本篇博文仅记录该学习过程。
测试url请求的controller方法
package com.lwj.securitydemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@GetMapping("/hello/{id}")
public String hello(@PathVariable int id) {
return "hello";
}
}
(1)在Springboot项目中通过@Component注解的方式添加一个过滤器来拦截URL请求。
package com.lwj.securitydemo.filter;
import javax.servlet.*;
import java.io.IOException;
import java.util.Date;
//将TimeFilter添加到Spring容器中
@Component
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("TimeFilter init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("TimeFilter doFilter");
System.out.println("start do something..." + new Date());
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("something is done" + new Date());
}
@Override
public void destroy() {
System.out.println("TimeFilter destroy");
}
}
(2)使用Springboot的config配置的方式
新建WebConfig类,并添加@Configuration注解,将该类配置为一个配置类。
package com.lwj.securitydemo.config;
import com.lwj.securitydemo.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 {
/**
* 配置过滤器
* @return
*/
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
// new一個自定義的filter出來
TimeFilter timeFilter = new TimeFilter();
// 將自定義的filter放入到registrationBean
registrationBean.setFilter(timeFilter);
// 設置需要被攔截的親求類型
List<String> filterUrls = new ArrayList<>();
filterUrls.add("/*");
registrationBean.setUrlPatterns(filterUrls);
return registrationBean;
}
}
(1)创建TimeInterceptor类
package com.lwj.securitydemo.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
@Component
public class TimeInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
Map map = request.getParameterMap();
System.out.println(handler.getClass().getName());
System.out.println("param "+ map.toString());
return true;
}
/**
* 该方法如果调用的方法抛出异常就不会再被调用了
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
/**
* 该方法最终都会执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
PS:此处的handler中虽然不能获取到请求中的参数,但是通过request对象中的方法也可以获取到param参数!
(2)将自定义的Interceptor添加到配置中
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 注入自定义的TimeInterceptor
*/
@Autowired
private TimeInterceptor timeInterceptor;
/**
* 配置自定义的Interceptor
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
/**
* 配置过滤器
* @return
*/
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
// new一個自定義的filter出來
TimeFilter timeFilter = new TimeFilter();
// 將自定義的filter放入到registrationBean
registrationBean.setFilter(timeFilter);
// 設置需要被攔截的親求類型
List<String> filterUrls = new ArrayList<>();
filterUrls.add("/*");
registrationBean.setUrlPatterns(filterUrls);
return registrationBean;
}
}
package com.lwj.securitydemo.web.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.lwj.securitydemo.controller.UserController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("time aspect 方法被调用!");
long start = System.currentTimeMillis();
// 获取切片方法的参数
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("args : " + arg);
}
// 执行切片的方法
Object obj = pjp.proceed();
System.out.println("time aspect 耗时: " + (System.currentTimeMillis() - start));
System.out.println("time aspect 方法结束!");
return obj;
}
}
package com.lwj.securitydemo.web.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Callable;
@RestController
public class AsyncController {
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/order")
public Callable<String> order() {
logger.info("主线程开始!");
Callable<String> result = () -> {
logger.info("副线程开始!");
Thread.sleep(1000);
logger.info("副线程结束!");
return "success";
};
logger.info("主线程结束!");
return result;
}
}
param org.apache.catalina.util.ParameterMap@16e52a1
2019-03-20 11:47:36.206 INFO 15556 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController : 主线程开始!
2019-03-20 11:47:36.207 INFO 15556 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController : 主线程结束!
2019-03-20 11:47:36.215 INFO 15556 --- [ task-1] c.l.s.web.async.AsyncController : 副线程开始!
2019-03-20 11:47:37.216 INFO 15556 --- [ task-1] c.l.s.web.async.AsyncController : 副线程结束!
可以看到日志信息中,在主线程结束后副线程立马开始了
1.创建MockQueue
package com.lwj.securitydemo.web.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MockQueue {
private Logger logger = LoggerFactory.getLogger(getClass());
private String placeOrder;
private String completeOrder;
public String getPlaceOrder() {
return placeOrder;
}
public void setPlaceOrder(String placeOrder) throws Exception {
new Thread(() -> {
logger.info("接到下单请求:" + placeOrder);
try {
Thread.sleep(1000);
} 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.创建DeferredResultHolder类
package com.lwj.securitydemo.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;
}
}
3.创建QueueListener
package com.lwj.securitydemo.web.async;
import cn.hutool.core.util.StrUtil;
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;
/**
* ContextRefreshedEvent 為spring容器初始化完畢事件
*/
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
new Thread(()->{
while (true) {
if (StrUtil.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();
}
}
4.修改AsyncController中的方法
package com.lwj.securitydemo.web.async;
import cn.hutool.core.util.RandomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.concurrent.Callable;
@RestController
public class AsyncController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
@RequestMapping("/order")
public DeferredResult<String> order() throws Exception {
logger.info("主线程开始!");
String orderNumber = RandomUtil.randomNumbers(8);
mockQueue.setPlaceOrder(orderNumber);
DeferredResult<String> result = new DeferredResult<>();
deferredResultHolder.getMap().put(orderNumber, result);
// Callable result = () -> {
// logger.info("副线程开始!");
// Thread.sleep(1000);
// logger.info("副线程结束!");
// return "success";
// };
logger.info("主线程结束!");
return result;
}
}
console日志
2019-03-20 14:21:12.700 INFO 6508 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController : 主线程开始!
2019-03-20 14:21:12.701 INFO 6508 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController : 主线程结束!
2019-03-20 14:21:12.701 INFO 6508 --- [ Thread-10] c.lwj.securitydemo.web.async.MockQueue : 接到下单请求:89428880
2019-03-20 14:21:13.702 INFO 6508 --- [ Thread-10] c.lwj.securitydemo.web.async.MockQueue : 下单请求处理完毕:89428880
2019-03-20 14:21:13.703 INFO 6508 --- [ Thread-7] c.l.s.web.async.QueueListener : 返回订单处理结果:89428880