Spring Boot 统一功能处理

本文介绍了如何在Spring MVC中实现统一用户登录权限验证、异常处理和数据格式封装。首先,通过自定义拦截器实现登录验证,将拦截器添加到系统配置并设置拦截规则。接着,利用@ControllerAdvice进行统一异常处理,提供友好的错误信息。最后,通过@ResponseBodyAdvice统一响应数据格式,提高前后端交互效率。
摘要由CSDN通过智能技术生成

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 将自定义拦截器添加系统配置中,并设置拦截的规则

在这里插入图片描述

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");

    }
}

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";
    }
}

在这里插入图片描述

在这里插入图片描述

响应码是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;
    }

}

在这里插入图片描述

@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.";
    }

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;
    }
}

3.2 测试

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

在这里插入图片描述

写个注册:

在这里插入图片描述

在这里插入图片描述

这样统一的好处:

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

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

粉色的志明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值