目录

  • springBoot拦截器 实现 统一用户登录权限验证
    • 1. 自定义拦截器
    • 2. 将自定义拦截器配置到系统配置项,并设置合理的拦截规则
    • 拦截器实现原理
  • 统一异常处理
  • 统一数据格式返回

统一用户登录权限验证
统一数据格式返回
统一异常处理

springBoot拦截器 实现 统一用户登录权限验证

1. 自定义拦截器

//自定义拦截器public class LoginInterceptor implements HandlerInterceptor {//调用目标方法之前执行的方法//此方法返回 boolean 类型的值:// 如果返回的是true 表示(拦截器)验证成功,继续走后续的流程,执行目标方法;// 如果返回false,表示拦截器执行失败,验证未通过,后续的流程和目标方法不要执行了@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//用户登录的判断业务HttpSession session = request.getSession(false);if (session != null && session.getAttribute("session_userinfo") != null) {//用户已经登陆return true;}//response.sendRedirect("https://www.baidu.com");response.setStatus(401);return false;}}

2. 将自定义拦截器配置到系统配置项,并设置合理的拦截规则

package com.example.demo.config;import com.example.demo.common.LoginInterceptor;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 MyConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {//registry.addInterceptor(new LoginInterceptor());// 都可以,推荐使用注入的方式registry.addInterceptor(loginInterceptor).addPathPatterns("/**") ///** 拦截所有的url,/* 一级/** 多级.excludePathPatterns("/user/login")// 排除url/user/login 不拦截该路径.excludePathPatterns("/user/reg").excludePathPatterns("/image/**");//排除 image 文件夹下的所有文件}}

拦截器实现原理

统一异常处理

  1. 创建一个异常处理类
@ControllerAdvicepublic class MyExceptionAdvice {}
  1. 创建异常检测的类和处理业务方法
@ControllerAdvice@ResponseBodypublic class MyExceptionAdvice {///处理空指针异常@ExceptionHandler(NullPointerException.class)public HashMap<String, Object> doNullPointerException(NullPointerException e) {HashMap<String, Object> result = new HashMap<>();result.put("code", -1);result.put("msg", "空指针:" + e.getMessage());result.put("data", null);return result;}}
//默认异常处理//当具体的异常匹配不到时,会执行此方法@ExceptionHandler(Exception.class)public HashMap<String, Object> doException(Exception e) {HashMap<String, Object> result = new HashMap<>();result.put("code", -1);result.put("msg", "Exception:" + e.getMessage());result.put("data", null);return result;}

统一数据格式返回

统一数据格式返回的优点:

  1. 降低前端和后端沟通的成本
  2. 方便前端程序员和后端程序员写公共的代码

统一数据格式返回(强制性统一数据返回)【在返回数据之前进行数据重写】:

//统一数据格式处理@ControllerAdvicepublic class ResponseAdvice implements ResponseBodyAdvice {//实现 ResponseBodyAdvice 接口 必须重写 supports 和 beforeBodyWrite 方法//内容是否需要重写/** * 是否执行 beforeBodyWrite 方法,true执行,重写返回结果 * @param returnType * @param converterType */@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}/** * 返回数据之前进行数据重写 * @param body原始返回值 * @param returnType * */@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 先定义:标准返回格式为 HashMap->code,msg,dataif (body instanceof HashMap) {return body;}//重写返回结果,让其返回一个统一的数据格式HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg", "");result.put("data", body);return result;}}

统一数据格式返回在遇到String类型返回时会报错:

@RequestMapping("/sayHi")public String sayHi() {return "say hiiii";}
@ExceptionHandler(Exception.class)public HashMap<String, Object> doException(Exception e) {HashMap<String, Object> result = new HashMap<>();result.put("code", -300);result.put("msg", "Exception:" + e.getMessage());result.put("data", null);return result;}


执行流程:

  1. 方法返回的是String类型
  2. 统一数据返回之前的处理,会将String转成HashMap
  3. 将HashMap转换成 application / json 字符串给前端(接口)

报错发生在第三步。
判断原body的类型:

  1. 如果是string,使用StringHttpMessageConverter进行类型转换 – 出错
  2. 不是string,使用HttpMessageConverter进行类型转换

解决方案:

  1. 将 StringHttpMessageConverter 通过项目的配置文件,从项目当中去除掉
  2. 在统一数据重写时,单独处理String类型,让其返回一个String 字符串,而非HashMap。【常用】

解决方案2的两种写法
一、 在最开始先判断是否为string类型,手动写成json格式

 @Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {//先判断是不是 string 类型if (body instanceof String) {// 返回一个 String 字符串return "{\"code\":200,\"msg\": \"\", \"data\":\"" + body + "\"}";}// 先定义:标准返回格式为 HashMap->code,msg,dataif (body instanceof HashMap) {return body;}//重写返回结果,让其返回一个统一的数据格式HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg", "");result.put("data", body);return result;}

二、使用ObjectMapper ,objectMapper.writeValueAsString(result),将对象转化成string

@Autowiredprivate ObjectMapper objectMapper;@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {// 先定义:标准返回格式为 HashMap->code,msg,dataif (body instanceof HashMap) {return body;}HashMap<String, Object> result = new HashMap<>();result.put("code", 200);result.put("msg", "");result.put("data", body);if (body instanceof String) {return objectMapper.writeValueAsString(result);//将对象转化成string}return result;}

解决方案1:移除StringHttpMessageConverter

package com.example.demo.config;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.StringHttpMessageConverter;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configurationpublic class MyConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<" />>> converters) {converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);}}