SpringSecurity实战笔记之RESTful

发布时间 2023-08-18 10:35:03作者: 咔咔皮卡丘

=================================RESTful========================================
一、JsonPath
1、github:https://github.com/json-path/JsonPath
二、@JsonView使用步骤(用于解决同一个对象在不同的接口返回的字段不同的场景)
1、使用接口来声明多个视图
2、在值对象的get方法上指定视图
3、在Controller方法上指定视图
package com.imooc.dto;
import com.fasterxml.jackson.annotation.JsonView;
public class User {

//1、使用接口来声明多个视图
public interface UserSimpleView{};
public interface UserDetailView extends UserSimpleView{};

private String username;
private String password;

public User() {}

public User(String username, String password) {
this.username = username;
this.password = password;
}

//2、在值对象的get方法上指定视图
@JsonView(UserSimpleView.class)
public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
//2、在值对象的get方法上指定视图
@JsonView(UserDetailView.class)
public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

3、在Controller方法上指定视图
@JsonView(User.UserSimpleView.class)
返回对象为User或User的集合才有效

三、@RequestBody和@RequestParam区别
1、@RequestParam 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容。
2、@RequestBody 处理HttpEntity传递过来的数据,一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。
四、日期类型参数处理
1、以时间戳的形式保存并传输,具体显示格式由前台来控制
五、校验
1、类属性上使用@NotNull之类注解,NotBlank比NotEmpty更严格
2、controller方法上添加@Valid注解
3、参数中添加 BindingResult,请求就可以进行方法体中,错误信息会保存在BindingResult对象中,可以从中取出做日志记录
@PostMapping
public User create(@Valid @RequestBody User user, BindingResult errors){
if(errors.hasErrors()){
errors.getAllErrors().stream().forEach(error -> System.out.println(error.getDefaultMessage()));
}
System.out.println(ReflectionToStringBuilder.toString(user,ToStringStyle.MULTI_LINE_STYLE));
user.setId("1");
return user;
}
4、常用的验证注解Hibernate Validator
@NotNull //值不能为空
@Null //值必须为空
@Pattern(regex=) //字符串必须匹配正则表达式
@Size(min=,max=) //集合的元素数量必须在min与max之间
@CreditCarNumber(ignoreNinDigitCharacters=) //字符串必须是信用卡号(近美国的标准验证)
@Email //字符串必须是Email
@Length(min=,max=) //检查字符串的长度
@NotBlank //字符串去空格后,必须有字符
@NotEmpty //字符串不能为空,集合有元素
@Range(min=,max=) //数字必须大于等于min,小于等于max
@SafeHtml //字符串是安全的html
@URL //字符串是合法的URL
@AssertFalse //boolean必须是false
@AssertTrue //boolean必须是true
@DecimalMax(value=,inclusive=) //值必须小于等于(inclusive=true)/小于(inclusive=false)value属性指定的值。可以注解在字符串类型的属性上。
@DecimalMim(value=,inclusive=) //值必须大于等于(inclusive=true)/大于(inclusive=false)value属性指定的值。可以注解在字符串类型的属性上。
@Max(value=) //值必须小于等于value属性指定的值。只能注解在数字类型的属性上。
@Mim(value=) //值必须大于等于value属性指定的值。只能注解在数字类型的属性上。
@Digits(integer=,fraction=) //数字格式检查。integer指定整数部分的最大长度。fraction指定小数部分最大长度。
@Future //值必须是未来的日期
@Past //值必须是过去的日期
5、自定义验证注解
5.1、注解类
package com.imooc.validator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD}) //定义注解可以标注在方法及字段上面
@Retention(RetentionPolicy.RUNTIME) //运行时注解
@Constraint(validatedBy = MyConstraintValidator.class) //指定使用的类进行逻辑判断
public @interface MyConstraint {

String message() ;

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
5.2、实现类

package com.imooc.validator;

//import com.imooc.Service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class MyConstraintValidator implements ConstraintValidator<MyConstraint,Object>{

//可以注入spring容器中的bean
//@Autowired
//private HelloService helloService;

@Override
public void initialize(MyConstraint myConstraint) {
System.out.println("my validator init");
}


@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
//helloService.greeting("anquing");
System.out.println("value:"+value);
return false;
}
}
六、异常处理机制
1、spring boot 默认处理机制(BasicErrorController):网页中返回html,接口中返回json
<html>
<body>
<h1>Whitelabel Error Page</h1>
<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
<div id='created'>Wed Nov 08 18:18:37 CST 2017</div>
<div>There was an unexpected error (type=Not Found, status=404).</div>
<div>No message available</div>
</body>
</html>
{
"timestamp": 1510135862443,
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/userdd"
}
2、自定义html异常页面
在resources目录下创建resources/error两个文件夹,在error文件夹下创建404.html({status}.html)文件,当产生相应的异常时就会显示对应的页面。
3、自定义接口异常
3.1、创建异常类,继承RunTimeException
package com.imooc.exception;

import java.io.Serializable;

public class UserNotExistException extends RuntimeException{

private static final long serialVersionUID = -6112780192479692859L;

private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public UserNotExistException(String id){
super("user not exist");
this.id = id;
}
}

3.2、创建ControllerExceptionHandler类
package com.imooc.web.controller;

import com.imooc.exception.UserNotExistException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class ControllerExceptionHandler {

@ExceptionHandler(UserNotExistException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String,Object> handlerUserNotExistException(UserNotExistException ex){
Map<String,Object> result = new HashMap<>();
result.put("id",ex.getId());
result.put("message",ex.getMessage());
return result;
}
}
七、拦截(过滤器>拦截器>切片>controller>切片>ControllerAdvice(有异常再会经过)>拦截器>过滤器)
1、过滤器(Filter)优点:能拿到http请求request,http响应response;缺点:无法拿到被过滤的类、方法信息
1.1、自定义(可以直接添加注解 @Component)
package com.imooc.web.controller.filter;

import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
import java.util.Date;

@Component //将filter加入容器中,自动会添加到过滤器链上(对所有的请求起作用)
public class TimeFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {

System.out.println("time filter init");

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("time filter start");
Long start = new Date().getTime();
filterChain.doFilter(servletRequest,servletResponse);
Long finish = new Date().getTime();
System.out.println("time filter:"+(finish - start));
System.out.println("time filter finish");
}

@Override
public void destroy() {
System.out.println("time filter destroy");
}
}
1.2、通过Configuration将第三方没有@Component的filter加入到过滤器链上
package com.imooc.web.config;

import com.imooc.web.filter.TimeFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;

@Configuration
public class WebConfig {

@Bean
public FilterRegistrationBean timeFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
registrationBean.setFilter(timeFilter);
List<String> urls = new ArrayList<>();
urls.add("/*");//添加需要经过过滤器的url(自定义)
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}

 

2、拦截器(Interceptor)
spring有提供,如果发生异常,处理的优先级为@ControllerAdvice到afterCompletion再到spring boot 默认处理机制(BasicErrorController)
优点:能拿到http请求request,http响应response,被过滤的类、方法信息;缺点:无法拿到方法参数的值
2.1、定义拦截器
package com.imooc.web.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

@Component
public class TimeInterceptor implements HandlerInterceptor {
/**
* 控制器方法调用之前,这个方法被调用
* @param httpServletRequest
* @param httpServletResponse
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
System.out.println("time interceptor preHandle");
//将类名与方法名打印
System.out.println("className:"+((HandlerMethod)handler).getBean().getClass().getName());
System.out.println("methodName:"+((HandlerMethod)handler).getMethod().getName());
//保存开始时间
httpServletRequest.setAttribute("startTime",new Date().getTime());
//如果返回false,就不会调用Controller中的方法
return true;
}

/**
* 控制器方法顺利执行之后,这个方法被调用
* @param httpServletRequest
* @param httpServletResponse
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("time interceptor postHandle");

//总耗时
Long startTime = (Long)httpServletRequest.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+(new Date().getTime()-startTime));

}

/**
* 控制器方法执行(包括抛出异常)之后,这个方法被调用
* @param httpServletRequest
* @param httpServletResponse
* @param handler
* @param e
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) throws Exception {
System.out.println("time interceptor afterCompletion");

//总耗时
Long startTime = (Long)httpServletRequest.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+(new Date().getTime()-startTime));

System.out.println("time interceptor ex is:"+e);
}
}
2.2、通过Configuration注册
package com.imooc.web.config;

import com.imooc.web.interceptor.TimeInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{

@Autowired
private TimeInterceptor timeInterceptor;


/**
* 同步请求方法拦截器注册
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
// addPathPatterns 用于添加拦截规则
// excludePathPatterns 用户排除拦截
registry.addInterceptor(timeInterceptor).addPathPatterns("/**");
}

//以下是扩展内容
@Autowired
private TimeDeferredResultProcessingInterceptor timeDeferredResultProcessingInterceptor;

/**
* 异步请求方法拦截器注册
* @param configurer
*/
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.registerDeferredResultInterceptors(timeDeferredResultProcessingInterceptor);
}

}


3、切片(Aspect)
优点:可以拿到方法参数的值,但无法拿到http请求request,http响应response
3.1、execution表达式:https://docs.spring.io/spring/docs/4.3.12.RELEASE/spring-framework-reference/htmlsingle/#aop-pointcuts-examples
3.2、代码实现
package com.imooc.web.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
* 切片类(类下有切入点,增强)
*/
@Aspect
@Component
public class TimeAspect {

//切入点(注解):1、在哪些方法上起作用;
@Pointcut("execution(* com.imooc.web.controller.UserController.*(..))")
public void pointcut(){}

// 2、在什么时候起作用
// @Before("pointcut()")//执行方法之前,也可以不需要定义pointcut,直接将execution表达式写在括号中@Before("execution(* com.imooc.web.controller.UserController.*(..))")
// @After("pointcut()")//成功执行方法之后
// @AfterThrowing("pointcut()")//执行方法抛出异常之后
@Around("pointcut()")//包含了以上方法
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {//增强(方法):起作用时执行的业务逻辑

System.out.println("time aspect start");

//取得方法中的参数
Object[] args = pjp.getArgs();
for (Object arg : args){
System.out.println("arg is : "+arg);
}

Long start = new Date().getTime();
//执行被拦截了的方法,与过滤器 filterChain.doFilter(servletRequest,servletResponse);作用相似
Object object = pjp.proceed();//object就是方法的返回值
Long finish = new Date().getTime();
System.out.println("time aspect 耗时:"+(finish - start));

System.out.println("time aspect end");

return object;
}
}

八、文件上传与下载
1、文件上传流程(单个上传)
-前端上传文件到temp文件夹,服务端返回文件名给前端;
-前端确认保存时,将文件名提交上来,服务端根据文件名,将temp文件转移到正式文件夹;
-将文件名以","隔开,保存在数据库中;
2、代码实现
package com.imooc.web.controller;

import com.imooc.dto.FileInfo;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;

/**
* 文件上传下载用例
*/
@RestController
@RequestMapping("/file")
public class FileController {

String folder = "D:\\document\\ideagit\\imooc-security\\imooc-security-demo\\src\\main\\java\\com\\imooc\\web\\controller";
/**
* 文件上传
* @param file
* @return
* @throws IOException
*/
@PostMapping
public FileInfo upload(MultipartFile file)throws IOException{

System.out.println("name:"+file.getName());
System.out.println("OriginalFilename:"+file.getOriginalFilename());
System.out.println("Size:"+file.getSize());

String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

File localFile = new File(folder,new Date().getTime()+suffix);
file.transferTo(localFile);
return new FileInfo(localFile.getAbsolutePath());
}

/**
* 文件下载
* @param id 文件名,不包括后缀
* @param response
* @param request
*/
@GetMapping("/{id}")
public void download(@PathVariable(value = "id") String id, HttpServletResponse response, HttpServletRequest request){
System.out.println(id);
//将流的操作放在try()中,使用完后会自动关闭流
try(InputStream inputStream = new FileInputStream(new File(folder, id+".txt"));
OutputStream outputStream = response.getOutputStream();) {

response.setContentType("application/x-download");
response.addHeader("Content-Disposition","attachment;filename=test.txt");

IOUtils.copy(inputStream,outputStream);
outputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
九、异步处理Rest服务(好处:主线程会立马释放,提高服务的吞吐量)
1、使用Runnable异步处理Rest服务(不足:副线程必须由主线唤起的,并写在主线程代码当中,无法满足复杂的场景)
/**
* 异步的处理方式
* @return
* @throws InterruptedException
*/
@GetMapping("/asynch")
public Callable<String> orderAsynch() throws InterruptedException {
logger.info("主线程开始");
Callable<String> result = new Callable<String>(){
@Override
public String call() throws Exception {
logger.info("副线程开始");
Thread.sleep(3000); //睡眠了3秒,但主线程不受影响
logger.info("副线程返回");
return "success";
}
};
logger.info("主线程返回");
return result;
}
打印结果:
2017-11-09 14:56:32.660 INFO 3088 --- [nio-8080-exec-3] com.imooc.web.async.AsyncController : 主线程开始
2017-11-09 14:56:32.661 INFO 3088 --- [nio-8080-exec-3] com.imooc.web.async.AsyncController : 主线程返回
2017-11-09 14:56:32.666 INFO 3088 --- [ MvcAsync1] com.imooc.web.async.AsyncController : 副线程开始
2017-11-09 14:56:35.667 INFO 3088 --- [ MvcAsync1] com.imooc.web.async.AsyncController : 副线程返回
2、使用DeferredResult异步处理Rest服务
2.1、下单场景描述(有两个应用分别为A(与客户端通信)、B(处理订单业务),它们之间通过消息队列进行通讯):
Http通过线程1请求应用 A,A将业务放入消息队列,线程1释放;B监听到消息队列有新业务要处理,就进行处理(线程3),处理完成后将处理结果放入消息队列;应用A中的线程2监听到有结果了,就将结果返回结客户端。
2.2、DeferredResult的作用可以使线程2与线程1能够交互,从而正确的返回给客户端

2.3、模拟消息队列类
package com.imooc.web.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* 模拟消息队列类(线程3)
*/
@Component
public class MockQueue {
private Logger logger = LoggerFactory.getLogger(MockQueue.class);
/**
* 下单消息
*/
private String placeOrder;

/**
* 下单完成消息
*/
private String completeOrder;

public String getPlaceOrder() {
return placeOrder;
}

public void setPlaceOrder(String placeOrder){
//这里是由于要模拟是另外一个应用在处理,所以为单独线程
new Thread(()->{
logger.info("接到下单请求,"+placeOrder);
try {
Thread.sleep(3000); //假设要3秒时间
} catch (InterruptedException e) {
e.printStackTrace();
}
this.completeOrder = placeOrder;
logger.info("下单请求处理完毕,"+placeOrder);
}).start();

}

public String getCompleteOrder() {
return completeOrder;
}

public void setCompleteOrder(String completeOrder) {
this.completeOrder = completeOrder;
}
}


2.4、DeferredResultHolder类
package com.imooc.web.async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
import java.util.HashMap;
import java.util.Map;

@Component
public class DeferredResultHolder {

private Map<String,DeferredResult<String>> map = new HashMap<>();

public Map<String, DeferredResult<String>> getMap() {
return map;
}

public void setMap(Map<String, DeferredResult<String>> map) {
this.map = map;
}
}

2.5、队列的监听器
package com.imooc.web.async;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
* 队列监听器(线程3)
*/
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent>{

private Logger logger = LoggerFactory.getLogger(QueueListener.class);

@Autowired
private MockQueue mockQueue;

@Autowired
private DeferredResultHolder deferredResultHolder;

/**
* 容器启动事件
* @param contextRefreshedEvent
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
//当容器启动后,一直监听mockQueue中completeOrder是否有值,要使用单独线程来轮询
new Thread(()->{
while(true){
if(StringUtils.isNotBlank(mockQueue.getCompleteOrder())){
String orderNumber = mockQueue.getCompleteOrder();
logger.info("返回订单处理结果:"+orderNumber);
deferredResultHolder.getMap().get(orderNumber).setResult("place order success");
mockQueue.setCompleteOrder(null);
}else{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();

}
}
2.6、controller方法
package com.imooc.web.async;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

@RestController
@RequestMapping("/order")
public class AsyncController {

private Logger logger = LoggerFactory.getLogger(AsyncController.class);

@Autowired
private MockQueue mockQueue;

@Autowired
private DeferredResultHolder deferredResultHolder;

/**
* DeferredResult异步处理方式(线程1)
* @return
* @throws InterruptedException
*/
@GetMapping("/deferredResultAsynch")
public DeferredResult<String> deferredResultAsynch() throws InterruptedException {
logger.info("主线程开始");
String orderNumber = RandomStringUtils.randomNumeric(8);
mockQueue.setPlaceOrder(orderNumber);
//由于setPlaceOrder方法是启用新的线程进行处理,所以不用等待处理完成就可以往下执行
DeferredResult<String> result = new DeferredResult<>();
deferredResultHolder.getMap().put(orderNumber,result);
logger.info("主线程返回");
return result;
}
}
2.7、执行结果
2017-11-09 16:06:49.135 INFO 1836 --- [nio-8080-exec-5] com.imooc.web.async.AsyncController : 主线程开始(线程1)
2017-11-09 16:06:49.135 INFO 1836 --- [nio-8080-exec-5] com.imooc.web.async.AsyncController : 主线程返回(线程1)
2017-11-09 16:06:49.135 INFO 1836 --- [ Thread-30] com.imooc.web.async.MockQueue : 接到下单请求,25860084(线程3)
2017-11-09 16:06:52.136 INFO 1836 --- [ Thread-30] com.imooc.web.async.MockQueue : 下单请求处理完毕,25860084(线程3)
2017-11-09 16:06:52.214 INFO 1836 --- [ Thread-17] com.imooc.web.async.QueueListener : 返回订单处理结果:25860084(线程2)
十、使用Swagger自动生成html文档
1、依赖
<!-- 扫描程序生成文档数据 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 将文档数据生成最终可视化的界面 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
2、再启动类加注解@EnableSwagger2
3、访问页面:http://localhost:8080/swagger-ui.htm
4、常用注解
4.1、针对方法:@ApiOperation(value="用户查询服务")//方法描述
4.2、针对参数:
4.2.1、方法参数封装在对象中的,在对象中对应的属性上添加
@ApiModelProperty(value="用户名")//参数描述
4.2.2、方法参数直接在方法中的,在参数前添加
@ApiParam("用户id")

十一、使用WireMock快速伪造RESTful服务
1、下载启动
官网:http://wiremock.org/
在http://wiremock.org/docs/running-standalone/页面下载downloaded the standalone JAR
启动:$ java -jar wiremock-standalone-2.10.1.jar --port=8082
2、与spring boot 整合
2.1、依赖
<!-- 使用WireMock快速伪造RESTful服务 -->
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
2.2、客户端类
package com.imooc.wiremock;

import com.github.tomakehurst.wiremock.client.WireMock;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;

public class MockServer {
public static void main(String[] args) throws IOException {
WireMock.configureFor("localhost",8082);
WireMock.removeAllMappings();//每次启动时,将原来的配置清除

mock("/order/1","01");
mock("/order/2","02");

}

private static void mock(String url,String fileName)throws IOException{
//将返回内容写在txt文档中
String filePath = "mock/response/"+fileName+".txt";
ClassPathResource resource = new ClassPathResource(filePath);
String content = StringUtils.join(FileUtils.readLines(resource.getFile(), "UTF-8").toArray(), "\n");
WireMock.stubFor(
WireMock.get(WireMock.urlPathEqualTo(url))
.willReturn(WireMock.aResponse().withBody(content).withStatus(200))
);
}
}
2.3、接口地址 http://localhost:8082/order/1