编辑
2020-03-27
编程
00

目录

1. 拦截 rest 服务
1.1 过滤器(Filter)
1.1.1 自定义过滤器
1.1.2 第三方过滤器
1.1.3 缺点
1.2 拦截器(Interceptor)
1.2.1 实现
1.2.2 缺点
1.2.3 要记得点
1.3 切片(Aspect)
1.3.1 实现方式
1.3.2 范围控制注解
1.3.3 范围控制表达式,execution
1.3.4 缺点
1.4 总结
2. 异步处理 rest 服务
2.1 Runnable 实现
2.2 DeferredResult 实现
2.3 异步拦截器
3. 前后端分离工具
3.1 Swagger自动生成html文档(springfox)
3.1.1 引入Swagger
3.1.2 常用注解
3.2 WireMock快速伪造RESTful服务

1. 拦截 rest 服务

1.1 过滤器(Filter)

1.1.1 自定义过滤器

自定义过滤器,只要实现Filter接口,并添加@Component注解即可

@Component public class TimeFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("time filter init"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("time filter start"); long startTime = System.currentTimeMillis(); chain.doFilter(request, response); System.out.printf("耗时:%d \r\n", System.currentTimeMillis() - startTime); System.out.println("time filter finish"); } @Override public void destroy() { System.out.println("time filter destroy"); } }

1.1.2 第三方过滤器

添加第三方过滤器,在配置类(@Configuration)中添加注入一个Bean(FilterRegistrationBea),指定生效路径

@Configuration public class WebConfig { @Bean public FilterRegistrationBean<TimeFilter> timeFilter(){ FilterRegistrationBean<TimeFilter> registrationBean = new FilterRegistrationBean<>(); // 设置过滤器 TimeFilter timeFilter = new TimeFilter(); registrationBean.setFilter(timeFilter); // 声明起作用的请求地址 List<String> urls = new ArrayList<>(16); urls.add("/user/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }

1.1.3 缺点

在过滤器中只能获取到http请求数据,不能识别那个控制器处理当前请求

1.2 拦截器(Interceptor)

1.2.1 实现

需要实现HandlerInterceptor接口,并在配置类中进行注册

a.创建类,实现HandlerInterceptor接口,注册为一个组件(@Component)

@Component public class TimeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 调用控制器之前 System.out.println("preHandle"); request.setAttribute("startTime", System.currentTimeMillis()); System.out.println(((HandlerMethod)handler).getBean().getClass().getName()); System.out.println(((HandlerMethod)handler).getMethod().getName()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 调用控制器正常返回之后(异常时不调用) System.out.println("postHandle"); Long startTime = (Long)request.getAttribute("startTime"); System.out.println("postHandle Interceptor 耗时:" + (System.currentTimeMillis() - startTime)); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 调用控制器返回之后 System.out.println("afterCompletion"); Long startTime = (Long)request.getAttribute("startTime"); System.out.println("afterCompletion Interceptor 耗时:" + (System.currentTimeMillis() - startTime)); } }

b.配置类(@Configuration) 继承 WebMvcConfigurer接口,覆盖addInterceptors方法,用registry.addInterceptor(timeInterceptor) 添加拦截器

@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private TimeInterceptor timeInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(timeInterceptor); } @Bean public FilterRegistrationBean<TimeFilter> timeFilter(){ FilterRegistrationBean<TimeFilter> registrationBean = new FilterRegistrationBean<>(); TimeFilter timeFilter = new TimeFilter(); registrationBean.setFilter(timeFilter); List<String> urls = new ArrayList<>(16); urls.add("/user/*"); registrationBean.setUrlPatterns(urls); return registrationBean; } }

控制台打印

time filter start preHandle com.yui.study.security.demo.controller.UserController getUserInfor postHandle postHandle Interceptor 耗时:435 afterCompletion afterCompletion Interceptor 耗时:440 time filter 耗时:466 time filter finish

1.2.2 缺点

无法获取到调用方法的参数

1.2.3 要记得点

handler可以获取访问的控制器的声明,为HandlerMethod实例 Exception ex 获取发生的异常

1.3 切片(Aspect)

1.3.1 实现方式

@Aspect 注解,声明作用范围(@Around)

@Aspect @Component public class TimeAspect { @Around("execution(* com.yui.study.security.demo.controller.UserController.*(..))") public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("aspect begin"); long start = System.currentTimeMillis(); // 获取参数 for (Object arg : pjp.getArgs()) { System.out.println("arg is " + arg); } Object o = pjp.proceed(); System.out.println("aspect end"); System.out.println("aspect 耗时:"+(System.currentTimeMillis() - start)); return o; } }

控制台打印

time filter start preHandle com.yui.study.security.demo.controller.UserController$$EnhancerBySpringCGLIB$$2b45dbcf getUserInfor aspect begin arg is 1 aspect end aspect 耗时:6 postHandle postHandle Interceptor 耗时:342 afterCompletion afterCompletion Interceptor 耗时:348 time filter 耗时:375 time filter finish

1.3.2 范围控制注解

@Before() 调用方法之前 @After() 调用方法之后 @AfterThrowing 异常时 @Around() 包含上述三种,一般使用这个

1.3.3 范围控制表达式,execution

详情可参考 spring-framework官方文档 例子说明

execution(* com.yui.study.security..*.*(..)) execution(): 表达式的主体asdFG 第一个“*”符号:表示返回值的类型任意 com.yui.study.security: AOP所切的服务的包名,即,需要进行横切的业务类 包名后面的“..”:表示当前包及子包 第二个“*”:表示类名,*即所有类 .*(..):表示任何方法名,括号表示参数,两个点表示任何参数类型

1.3.4 缺点

获取不到原始的http请求

1.4 总结

调用顺序 filter -> Interceptor -> ControllerAdvice -> Aspect -> controllermark text

2. 异步处理 rest 服务

2.1 Runnable 实现

controller

@RestController public class AsyncController { private Logger logger = LoggerFactory.getLogger(getClass()); @RequestMapping("/order") public String test() throws InterruptedException { logger.info("主线程开始"); Thread.sleep(10000); logger.info("主线程结束"); return "SUCCESS"; } @RequestMapping("/orderAsync") public Callable<String> test02() { logger.info("主线程开始"); Callable<String> result = () -> { logger.info("副线程开始"); Thread.sleep(10000); logger.info("副线程结束"); return "SUCCESS"; }; logger.info("主线程结束"); return result; } }

测试异步日志打印

2018-12-06 15:22:08.137 INFO 14540 --- [nio-8081-exec-2] c.y.s.s.demo.async.AsyncController : 主线程开始 2018-12-06 15:22:08.137 INFO 14540 --- [nio-8081-exec-2] c.y.s.s.demo.async.AsyncController : 主线程结束 2018-12-06 15:22:08.140 WARN 14540 --- [nio-8081-exec-2] o.s.w.c.request.async.WebAsyncManager : !!! An Executor is required to handle java.util.concurrent.Callable return values. Please, configure a TaskExecutor in the MVC config under "async support". The SimpleAsyncTaskExecutor currently in use is not suitable under load. ------------------------------- Request URI: '/orderAsync' !!! 2018-12-06 15:22:08.145 INFO 14540 --- [ MvcAsync1] c.y.s.s.demo.async.AsyncController : 副线程开始 2018-12-06 15:22:09.419 INFO 14540 --- [nio-8081-exec-4] c.y.s.s.demo.async.AsyncController : 主线程开始 2018-12-06 15:22:09.419 INFO 14540 --- [nio-8081-exec-4] c.y.s.s.demo.async.AsyncController : 主线程结束 2018-12-06 15:22:09.421 INFO 14540 --- [ MvcAsync2] c.y.s.s.demo.async.AsyncController : 副线程开始 2018-12-06 15:22:18.146 INFO 14540 --- [ MvcAsync1] c.y.s.s.demo.async.AsyncController : 副线程结束 2018-12-06 15:22:19.422 INFO 14540 --- [ MvcAsync2] c.y.s.s.demo.async.AsyncController : 副线程结束

警告内容是需要一个线程池来处理多线程

@Configuration public class WebConfig implements WebMvcConfigurer { private ThreadPoolTaskExecutor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(30); executor.setQueueCapacity(100); executor.setThreadNamePrefix("ronnie-task-"); executor.initialize(); return executor; } @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(getAsyncExecutor()); WebMvcConfigurer.super.configureAsyncSupport(configurer); } }

2.2 DeferredResult 实现

2.3 异步拦截器

@Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setTaskExecutor(getAsyncExecutor()); configurer.registerCallableInterceptors(); configurer.registerDeferredResultInterceptors(); WebMvcConfigurer.super.configureAsyncSupport(configurer); }

3. 前后端分离工具

3.1 Swagger自动生成html文档(springfox)

3.1.1 引入Swagger

pom.xml

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency>

程序入口添加 @EnableSwagger2 注解

@SpringBootApplication @EnableSwagger2 public class DemoApplication { /** * 启动入口 * @param args */ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

3.1.2 常用注解

@ApiModelProperty("用户id") : 参数为对象时使用,注解在对象的属性上 @ApiParam("用户id") : 参数为基本数据类型是使用,注解在参数前,如:

public User getUserInfor(@ApiParam("用户id") @PathVariable Long id){ ... }

@ApiOperation("用户信息查询服务") 注解在方法上,修改方法默认名称

3.2 WireMock快速伪造RESTful服务

本文作者:Yui_HTT

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!