• Spring Boot 统一功能处理


    1. 统一用户登录权限验证

    之前我们在做的登录校验:

    1. 在每个方法里面获取 session 和 session 中的用户信息,如果存在用户,那么就认为登录成功,否则就登陆失败了.
    2. 提供了统一的方法,在每个需要验证的方法中调用统一的用户登录身份校验方法来判断.
    3. 使用 Spring AOP 来使用统一的用户登录校验.(没有办法得到 HttpSession 和 Request 对象,实际拦截规则很复杂,使用简单 aspectj 表达式无法满足拦截的需求).
    4. Spring 拦截器来实现用户的统一登录校验.

    针对第 4 点步骤:

    1. 实现自定义拦截器,实现 Spring 中的 HandlerInterceptor 接口中的 preHandle(执⾏具体⽅法之前的预处理) 方法.
    2. 将自定义拦截器加入到框架的配置中,并且设置拦截规则.

    a) 给当前的类添加 @Configuration 注解
    b) 实现WebMvcConfigurer 接口
    c) 重写 addInterceptors 方法

    1.1 自定义拦截

    在这里插入图片描述

    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;
    
    
    @Component
    public class LoginIntercept implements HandlerInterceptor {
    
        /**
         * 返回 true 表示拦截通过,可以访问后面的接口
         * 返回 false 表示拦截未通过,直接返回结果给前端
         * @param request
         * @param response
         * @param handler
         * @return
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                                 Object handler) throws Exception {
            // 1. 得到 httpsession对象
            HttpSession session = request.getSession(false);
            if(session != null && session.getAttribute("userinfo") != null){
                // 表示已经登录
                return true;
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    1.2 将自定义拦截器添加系统配置中,并设置拦截的规则

    在这里插入图片描述

    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.PathMatchConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    import javax.annotation.Resource;
    
    @Configuration
    public class AppConfig implements WebMvcConfigurer {
    
        @Resource
        private LoginIntercept loginIntercept;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    //        registry.addInterceptor(new LoginIntercept());
            registry.addInterceptor(loginIntercept).addPathPatterns("/**")  //拦截所有
                    .excludePathPatterns("/user1/login2") //不拦截登录接口
                    .excludePathPatterns("/user1/reg")
                    .excludePathPatterns("/login.html")
                    .excludePathPatterns("/reg.html")
                    .excludePathPatterns("/**/*.js")
                    .excludePathPatterns("/**/*.css")
                    .excludePathPatterns("/**/*.png")
                    .excludePathPatterns("/**/*.jpg");
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    addPathPatterns:表示需要拦截的 URL,“**”表示拦截任意⽅法(也就是所有⽅法)。
    excludePathPatterns:表示需要排除的 URL

    1.3 测试

    在这里插入图片描述

    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    @RestController
    @RequestMapping("/user1")
    public class UserController2 {
    
        @RequestMapping("/login2")
        public boolean login(HttpServletRequest request,String username, String password){
            boolean result = false;
            if(StringUtils.hasLength(username) && StringUtils.hasLength(password)){
                if(username.equals("admin") && password.equals("admin")){
                    HttpSession session = request.getSession();
                    session.setAttribute("userinfo","userinfo");
                    return true;
                }
            }
            return result;
        }
    
        @RequestMapping("/index")
        public String index() {
        return "Hello index";
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    在这里插入图片描述

    响应码是200,但并没有返回结果.

    我们在写两个前端页面验证一下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    测试:
    在这里插入图片描述
    在这里插入图片描述

    我们登录没有拦截:
    在这里插入图片描述

    在这里插入图片描述

    我们在进行登录是往往就是要进行校验,密码不对就要重新返回登录页面:
    加上这一段:
    在这里插入图片描述
    我们输入正确密码:
    在这里插入图片描述
    在这里插入图片描述

    登录成功后再访问其他页面:
    在这里插入图片描述

    在这里插入图片描述

    当登录成功写⼊ session 之后,拦截的⻚⾯可正常访问

    1.4 拦截器实现原理

    正常情况下的调⽤顺序:

    在这里插入图片描述

    然⽽有了拦截器之后,会在调⽤ Controller 之前进⾏相应的业务处理,执⾏的流程如下图所示:

    在这里插入图片描述

    大体流程:
    在这里插入图片描述

    1.5 扩展: 统一访问前缀添加

    所有请求地址添加 api 前缀:
    在这里插入图片描述

    其中第⼆个参数是⼀个表达式,设置为 true 表示启动前缀。
    在这里插入图片描述

    2. 统一异常处理

    1. 给当前的类加上 @ControllerAdvice/@RestControllerAdvice
    2. 给方法上添加 @ExceptionHandler(xxx.class),添加异常返回的业务代码

    2.1 代码

    编写测试代码:

    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.RestControllerAdvice;
    
    import java.util.HashMap;
    
    //@ControllerAdvice
    @RestControllerAdvice // 当前是针对 controller 的通知类(增强类)
    public class MyExceptionAdvice {
    
        @ExceptionHandler(ArithmeticException.class)
        public HashMap<String, Object> arithmeticExceptionAdvice(ArithmeticException e) {
            HashMap<String, Object> result = new HashMap<>();
            result.put("state", -1);
            result.put("data", null);
            result.put("msg", "算术异常:" + e.getMessage());
            return result;
        }
    
        @ExceptionHandler(NullPointerException.class)
        public HashMap<String, Object> nullPointerExceptionAdvice(NullPointerException e) {
            HashMap<String, Object> result = new HashMap<>();
            result.put("state", -1);
            result.put("data", null);
            result.put("msg", "空指针异常:" + e.getMessage());
            return result;
        }
    
        @ExceptionHandler(Exception.class)
        public HashMap<String, Object> exceptionAdvice(Exception e) {
            HashMap<String, Object> result = new HashMap<>();
            result.put("state", -1);
            result.put("data", null);
            result.put("msg", "异常:" + e.getMessage());
            return result;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    在这里插入图片描述

    @RequestMapping("/index")
        public String index() {
            int num = 10 / 0;
            return "Hello,Index.";
        }
    
    
        @RequestMapping("/index2")
        public String index2() {
            Object obj = null;
            System.out.println(obj.hashCode());
            return "Hello,Index.";
        }
    
        @RequestMapping("/index3")
        public String index3() {
            String str = "java";
            System.out.println(Integer.valueOf(str));
            return "Hello,Index.";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    2.2 测试

    测试结果:
    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    对前端就很友好了,他就不会报 500 的错误信息了,返回的是一个 200

    3. 统一数据格式封装

    1. 给当前类添加 @ControllerAdvice
    2. 实现 ResponseBodyAdvice 重写其方法

    3.1 代码

    在这里插入图片描述

    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;
    
    import java.util.HashMap;
    
    @ControllerAdvice
    public class MyResponseAdvice implements ResponseBodyAdvice {
    
        /**
         * 返回一个 boolean 值,true 表示返回数据之前对数据进行重写,也就是会进入 beforeBodyWrite 方法,再返回
         * 如果返回 false 表示对结果不进行任何处理,直接返回
         */
        @Override
        public boolean supports(MethodParameter returnType, Class converterType) {
            return true;
        }
    
        @Override
        public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
            HashMap<String, Object> result = new HashMap<>();
            result.put("state", 1);
            result.put("data", body);
            result.put("msg", "");
            return result;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3.2 测试

    在这里插入图片描述在这里插入图片描述

    在这里插入图片描述

    写个注册:

    在这里插入图片描述

    在这里插入图片描述

    这样统一的好处:

    1. ⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。
    2. 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就⾏了,因为所有接⼝都是这样返回的。
    3. 有利于项⽬统⼀数据的维护和修改。
    4. 有利于后端技术部⻔的统⼀规范的标准制定,不会出现稀奇古怪的返回内容

    缺点就是全统一了,格式就固定了,就不能返回自己想要的了.(相当于就是个性的牺牲)

  • 相关阅读:
    <C++>类和对象——引入
    Python常用的数据处理库有哪些?
    Python算法——树的镜像
    设计模式--适配器模式
    如何利用人工智能减少塑料垃圾?
    基于神经网络的车牌识别系统在matlab上如何实现
    python学习手册
    Java 字符串的数字校验:isNumeric,isNumericSpace和正则表达式,对比分析
    十大服装店收银系统有哪些 好用的服装收银软件推荐
    Gitea:开源世界的协作灵魂
  • 原文地址:https://blog.csdn.net/chenbaifan/article/details/126109307