1.自定义拦截器
package com.example.demo.config;import com.example.demo.common.AppVar;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;/*** 自定义拦截器*/@Componentpublic class UserInterceptor implements HandlerInterceptor {/*** 返回 true -> 拦截器验证成功,继续执行后续方法* false -> 拦截器验证失败,不会执行后续的目标方法** @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {// 业务方法HttpSession session = request.getSession(false);if (session != null &&session.getAttribute(AppVar.SESSION_KEY) != null) {// 用户已经登录return true;}return false;}}2.将自定义拦截器配置到系统设置中,并设置拦截规则
package com.example.demo.config;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.WebMvcConfigurer;@Configurationpublic class AppConfig implements WebMvcConfigurer {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// registry.addInterceptor(new UserInterceptor());registry.addInterceptor(userInterceptor).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/reg").excludePathPatterns("/user/login");}} 排除所有静态资源 // 拦截器@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 拦截所有接⼝.excludePathPatterns("/**/*.js").excludePathPatterns("/**/*.css").excludePathPatterns("/**/*.jpg").excludePathPatterns("/login.html").excludePathPatterns("/**/login"); // 排除接⼝} 练习:登录拦截器 登录、注册⻚⾯不拦截,其他⻚⾯都拦截。当登录成功写⼊ session 之后,拦截的⻚⾯可正常访问。 package com.example.demo.config;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.WebMvcConfigurer;@Configurationpublic class AppConfig implements WebMvcConfigurer {@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// registry.addInterceptor(new UserInterceptor());registry.addInterceptor(userInterceptor).addPathPatterns("/**") // 拦截所有请求.excludePathPatterns("/user/reg").excludePathPatterns("/reg.html").excludePathPatterns("/login.html").excludePathPatterns("/css/**").excludePathPatterns("/editor.md/**").excludePathPatterns("/img/**").excludePathPatterns("/js/**");}} package com.example.demo.config;import com.example.demo.common.AppVar;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;/*** 自定义拦截器*/@Componentpublic class UserInterceptor implements HandlerInterceptor {/*** 返回 true -> 拦截器验证成功,继续执行后续方法* false -> 拦截器验证失败,不会执行后续的目标方法** @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {System.out.println("do UserInterceptor");// 业务方法HttpSession session = request.getSession(false);if (session != null &&session.getAttribute(AppVar.SESSION_KEY) != null) {// 用户已经登录return true;}response.sendRedirect("https://www.baidu.com");return false;}} 拦截器实现原理然⽽有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图所示:
统一异常处理统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件。
1.@ControllerAdvice/@RestControllerAdvice 2.@ExceptionHandler(Exception.class)统一返回的对象
package com.example.demo.config;import com.example.demo.common.ResultAjax;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvicepublic class ExceptionAdvice {@ExceptionHandler(NullPointerException.class)public ResultAjax doNullPointerException(NullPointerException e) {ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(-1);resultAjax.setMsg("空指针异常:"+ e.getMessage());resultAjax.setData(null);return resultAjax;}@ExceptionHandler(Exception.class)public ResultAjax doException(Exception e) {ResultAjax resultAjax = new ResultAjax();resultAjax.setCode(-1);resultAjax.setMsg("异常:"+ e.getMessage());resultAjax.setData(null);return resultAjax;}} 统一数据返回格式 为什么需要统⼀数据返回格式?统⼀数据返回格式的优点有很多,⽐如以下⼏个:
⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回 的。有利于项⽬统⼀数据的维护和修改。有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容。 统⼀数据返回格式的实现统⼀的数据返回格式可以使⽤ @ControllerAdvice + ResponseBodyAdvice 的⽅式实现。
@ControllerAdvice实现ResponseBodyAdvice接口,并重写它的两个方法:supports方法必须返回true,beforeBodyWrit方法中进行重新判断和重写操作。 package com.example.demo.config;import com.example.demo.common.ResultAjax;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;/*** 统一返回值的保底实现类*/@ControllerAdvicepublic class ResponseAdvice implements ResponseBodyAdvice {/*** true -> 才会调用 beforeBodyWrite 方法,* 反之则永远不会调用* @param returnType* @param converterType* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 已经包装好的对象if (body instanceof ResultAjax) {return body;}return ResultAjax.succ(body);}}