@ExceptionHandler、HandlerExceptionResolver、@controlleradvice
https://blog.csdn.net/qq_40341361/article/details/79791011
app访问工程和浏览器访问工程不一样,如果想要返回给前端自定义的参数信息,就需要自己定义异常
两个服务之间的调用,如果想要返回另一个服务的错误信息。
public class UserNotExistException extends RuntimeException {
private static final long serialVersionUID = -6112780192479692859L;
private String id;
public UserNotExistException(String id) {
super("user not exist");
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
异常处理器:
@ControllerAdvice
public class ControllerExceptionHandler {
//现在我要我自定义异常返回的信息是一个Map
@ExceptionHandler(UserNotExistException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map handUserNotExistException(UserNotExistException ex) {
Map map = new HashMap();
map.put("id", ex.getId());
map.put("message", ex.getMessage());
return map;
}
}
过滤器:
@Component
public class TimeFilter implements Filter {
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
System.out.println("time filter destroy");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("time filter start");
long start = new Date().getTime();
chain.doFilter(request, response);
System.out.println("time filter 耗时:"+ (new Date().getTime() - start));
System.out.println("time filter finish");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("time filter init");
}
}
加了Compoment注解后,过滤器就自定加入到项目中去了,但是如果当我们使用第三方的框架可能用到第三方的过滤器,这个时候没有办法加@Compoment注解,如何使用过滤器呢?
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
filterRegistrationBean.setFilter(timeFilter);
//添加过滤器起作用的路径
List urls = new ArrayList();
urls.add("/user/*");
filterRegistrationBean.setUrlPatterns(urls);
return filterRegistrationBean;
}
}
拦截器:
过滤器只能获得原始的http请求和响应,而无法获得具体调用的哪个方法,要想获得就要使用过滤器,需要注意的事自己处理了的异常在最后的afterCompletion拿不到
@Component
public class TimeInterceptor implements HandlerInterceptor {
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
*/
//Controller方法执行之前调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
System.out.println(((HandlerMethod) handler).getBean().getClass().getName());
System.out.println(((HandlerMethod) handler).getMethod().getName());
request.setAttribute("startTime", new Date().getTime());
return true;
}
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
*/
//controller方法执行之后调用,如果Controller抛出异常,那么他就不会掉用了。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:" + (new Date().getTime() - start));
}
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
//一定会在Controller之后调用
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:" + (new Date().getTime() - start));
System.out.println("ex is " + ex);
}
}
注册拦截器:
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Autowired
private TimeInterceptor timeInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(timeInterceptor);
}
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
filterRegistrationBean.setFilter(timeFilter);
//添加过滤器起作用的路径
List urls = new ArrayList();
urls.add("/user/*");
filterRegistrationBean.setUrlPatterns(urls);
return filterRegistrationBean;
}
}
最后就是切面来实现,他拿不到原始的http请求和响应,但是能拿到执行方法的参数
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.wx.wxsecuritydemo.controller.UserController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
//可以获得方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("方法的参数:" + args[i]);
}
Long start = new Date().getTime();
//proceed即为方法的返回值
Object proceed = joinPoint.proceed();
System.out.println("time aspect 耗时:" + ((new Date().getTime()) - start));
return proceed;
}
}
执行顺序:
@RestController
@RequestMapping("/file")
public class FileController {
private String folder = "D:\\IDEA\\wx-security\\wx-security-demo\\src\\main\\java\\com\\wx\\wxsecuritydemo\\controller";
@PostMapping
public FileInfo upload(MultipartFile file) throws Exception {
System.out.println(file.getName());
System.out.println(file.getOriginalFilename());
System.out.println(file.getSize());
File localFile = new File(folder, new Date().getTime() + ".txt");
file.transferTo(localFile);
return new FileInfo(localFile.getAbsolutePath());
}
@GetMapping("/{id}")
public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
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();
}
}
}
模拟消息队列:
//模拟消息队列
@Component
public class MockQueue {
//模拟下单的消息
private String placeOrder;
//模拟订单完成的消息
private String completeOrder;
private Logger logger = LoggerFactory.getLogger(getClass());
public String getPlaceOrder() {
return placeOrder;
}
public void setPlaceOrder(String placeOrder) throws Exception {
new Thread(() -> {
logger.info("接到下单请求, " + placeOrder);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
this.completeOrder = placeOrder;
logger.info("下单请求处理完毕," + placeOrder);
}).start();
}
public String getCompleteOrder() {
return completeOrder;
}
public void setCompleteOrder(String completeOrder) {
this.completeOrder = completeOrder;
}
}
@RestController
public class AsyncController {
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
private Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/order")
public DeferredResult order() throws Exception {
logger.info("主线程开始");
String orderNumber = RandomStringUtils.randomNumeric(8);
mockQueue.setPlaceOrder(orderNumber);
DeferredResult result = new DeferredResult<>();
deferredResultHolder.getMap().put(orderNumber, result);
return result;
// Callable result = new Callable() {
// @Override
// public String call() throws Exception {
// logger.info("副线程开始");
// Thread.sleep(1000);
// logger.info("副线程返回");
// return "success";
// }
// };
}
}
处理的结果:
@Component
public class DeferredResultHolder {
private Map> map = new HashMap>();
public Map> getMap() {
return map;
}
public void setMap(Map> map) {
this.map = map;
}
}
监听消息队列,
@Component
public class QueueListener implements ApplicationListener {
@Autowired
private MockQueue mockQueue;
@Autowired
private DeferredResultHolder deferredResultHolder;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
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();
}
}
只需要注意的是,有拦截器,过滤器的时候需要这样配置才能访问swagger
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Autowired
private TimeInterceptor timeInterceptor;
//不访问swagger,拦截器可以这样配置
// @Override
// protected void addInterceptors(InterceptorRegistry registry) {
// super.addInterceptors(registry);
// registry.addInterceptor(timeInterceptor);
// }
/**
* 加了拦截器以后,想要访问swagger可以这样配置
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns添加需要拦截的命名空间;
// excludePathPatterns添加排除拦截命名空间
registry.addInterceptor(new TimeInterceptor()).addPathPatterns("/**").excludePathPatterns("/register").excludePathPatterns("/login").excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
}
@Bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
filterRegistrationBean.setFilter(timeFilter);
//添加过滤器起作用的路径
List urls = new ArrayList();
urls.add("/*");
filterRegistrationBean.setUrlPatterns(urls);
return filterRegistrationBean;
}
/**
* 解决添加过滤器后 SWAGGER 404报错
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
// 解决 SWAGGER 404报错
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}