SpringBoot统一功能处理

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

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

1. 自定义拦截器

//自定义拦截器
public class LoginInterceptor implements HandlerInterceptor {
    
    
    //调用目标方法之前执行的方法
    //此方法返回 boolean 类型的值:
    // 如果返回的是true 表示(拦截器)验证成功,继续走后续的流程,执行目标方法;
    // 如果返回false,表示拦截器执行失败,验证未通过,后续的流程和目标方法不要执行了
    @Override
    public 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;

@Configuration
public class MyConfig implements WebMvcConfigurer {
    
    
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public 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. 创建一个异常处理类
@ControllerAdvice
public class MyExceptionAdvice {
    
    
}
  1. 创建异常检测的类和处理业务方法
@ControllerAdvice
@ResponseBody
public 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. 方便前端程序员和后端程序员写公共的代码

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


//统一数据格式处理
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    
    
    //实现 ResponseBodyAdvice 接口 必须重写 supports 和 beforeBodyWrite 方法

    //内容是否需要重写
    /**
     * 是否执行 beforeBodyWrite 方法,true执行,重写返回结果
     * @param returnType
     * @param converterType
     */
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
    
    
        return true;
    }

    /**
     * 返回数据之前进行数据重写
     * @param body  原始返回值
     * @param returnType
     *
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    
    

        // 先定义:标准返回格式为 HashMap<String, Object>  ->  code,msg,data
        if (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格式

 @Override
    public 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<String, Object>  ->  code,msg,data
        if (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

    @Autowired
    private ObjectMapper objectMapper;

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    
    
        // 先定义:标准返回格式为 HashMap<String, Object>  ->  code,msg,data
        if (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;

@Configuration
public class MyConfig implements WebMvcConfigurer {
    
    
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    
    
        converters.removeIf(converter -> converter instanceof StringHttpMessageConverter);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44431128/article/details/130699444