SpringBoot项目必会技能——统一功能处理

目录

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

1.1、Spring拦截器

1.1.1、自定义拦截器

1.1.2、自定义拦截 

1.2、 拦截器实现原理

 1.3、扩展统一访问前缀添加

1.3.1、在系统的配置文件中设置:

1.3.2、在配置文件中配置

 2、统一数据格式返回

2.1、统一数据返回格式的实现

 2.2、统一数据返回格式的好处

3、统一异常处理


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

        为什么要进行用户登录权限验证呢?咱们想想如果不适用的话,例如博客系统,除了登录和注册页面不需要用户登录权限验证以外,其它的都需要,那就会导致有很多冗余代码~

        有伙伴想到了,可以使用AOP来解决,想法很不错,可现实是残酷的,例如,我们使用Spring AOP前置通知和环绕通知来实现,但我们会面临两个很难搞的问题:

  • 在切面类中,很难获取到HttpSession对象
  • 我们要对一部分方法进行拦截,另一部分不拦截,所以定义拦截规则很难

解决问题:使用Spring拦截器:HandlerInterceptor

1.1、Spring拦截器

        对于上述的问题,Spring提供了具体的实现拦截器:HandlerInterceptor,拦截器分为以下两个步骤:

  • 创建自定义拦截器,实现HandlerInterceptor接口的preHandle(执行具体方法之前的预处理)方法
  • 将自定义拦截器加入WebMvcConfigurer的addInterceptors方法中

1.1.1、自定义拦截器

实现一个用户登录权限校验,自定义拦截器是一个普通的类,具体实现如下:

  • 实现HandlerInterceptor接口
  • 重写preHeadler方法,在方法中编写自己的业务代码
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //用户登录业务判断
        HttpSession session = request.getSession(false);
        if(session !=null && session.getAttribute("userinfo") != null) {
            //用户已登录
            return  true;
        }
        //用户未登录
        //可以调整到登录页面,返回一个401/403没有权限码
        response.sendRedirect("login.html");
//        response.setStatus(401);
        return  false;
    }
}

1.1.2、自定义拦截 

将自定义拦截器加入WebMvcConfigurer的addInterceptors方法中,也就是将上一步中的自定义拦截器加入到系统配置信息中,并且设置拦截规则,具体实现如下:

@Configuration
public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")  //拦截所有请求
                .excludePathPatterns("/user/login")  //不拦截的url地址
                .excludePathPatterns("/**/*.html");  //不拦截html页面
    }
}

一个登录权限验证的拦截器就实现啦~

1.2、 拦截器实现原理

有了拦截器之后,会在调用Controller之前进行相应的业务处理,流程如下:

 1.3、扩展统一访问前缀添加

1.3.1、在系统的配置文件中设置:

在上述的自定义拦截的方法下面加一个重写的方法:

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("/user",c->true);
    }

第二个参数是一个表达式,设置为true表示启动前缀 

1.3.2、在配置文件中配置

如:我在yml配置文件中配置:

server:
  servlet:
    context-path: /user

 2、统一数据格式返回

2.1、统一数据返回格式的实现

两个步骤:

  • 创建一个类,并添加注解@ControllerAdvice
  • 实现ResponseBodyAdvice接口,并重写supports和beforeBodyWrite(统一对象就是此方法中实现)

代码实现:

package com.example.demo.config;

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;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:龙宝
 * Date:2023-03-29
 * Time:15:18
 */
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;//true为开启,执行beforeBodyWrite方法,否则不执行
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        HashMap<String,Object> ret = new HashMap<>();
        ret.put("code",200);//状态码
        ret.put("msg","");//报错信息,程序都执行到返回数据了,自然是没有报错~
        ret.put("data",body);
        return ret;
    }
}

写一个测试:

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:龙宝
 * Date:2023-03-29
 * Time:15:23
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/int")
    public Integer retInt() {
        return 2;
    }
}

结果: 

 但此时如果返回的是String类型,就会报错:

     @RequestMapping("/string")
    public String retInt() {
        return "222";
    }

        为什么呢?String是一个很特殊的类型,既不是基本类型,也不属于对象,并且在重写方法时,除String以外都是使用同一个格式化工具,而String用的是自己的一套格式化工具,因此在转换成HashMap时,还没有被加载好,而其他的转换器都已经加载好了,就引出上面的异常了。 

        因此当返回类型为String类型时,就要进行特殊处理,使用JSON的writeValueAsString方法将java对象转换成JSON格式再返回~

代码修改如下:

 2.2、统一数据返回格式的好处

  • 方便前端程序员更好地接收和解析后端数据接口返回的数据
  • 降低前端程序员和后端程序员的沟通成本,按照某个格式实现就行了,因为所有接口都是这样返回的
  • 有利于项目统一数据的维护和修改
  • 有利于后端技术部门的统一规范的标准制定,不会出现稀奇古怪的返回内容~

3、统一异常处理

两个步骤:

  • 创建一个类,并在类上标识@ControllerAdvice
  • 添加方法@ExceptionHandle来订阅异常

代码实现【举例】:

package com.example.demo.config;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User:龙宝
 * Date:2023-03-29
 * Time:15:44
 */
@ControllerAdvice
@ResponseBody
public class MyExHandle {
    @ExceptionHandler(NullPointerException.class)
    public HashMap<String,Object> nullEx(NullPointerException e) {
        HashMap<String,Object> ret = new HashMap<>();
        ret.put("code",-1);
        ret.put("msg","空指针异常"+e.getMessage());//错误码的描述信息
        ret.put("data",null);
        return  ret;
    }

    @ExceptionHandler(Exception.class)
    public HashMap<String, Object> exception(Exception e) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", "-1");
        result.put("msg", "异常:" + e.getMessage()); // 错误码的描述信息
        result.put("data", null);
        return result;
    }
}

好啦~本期到这里就结束了,下期见~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

龙洋静

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

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

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

打赏作者

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

抵扣说明:

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

余额充值