首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >SpringBoot统一功能处理

SpringBoot统一功能处理

作者头像
趙卋傑
发布2026-01-12 15:19:46
发布2026-01-12 15:19:46
830
举报

1.拦截器

为了处理强制登陆问题,我们使用了session机制存储登陆状态

这里我们学习更简单的拦截方法拦截器,统⼀拦截所有的请求,并进行Session校验

拦截器是Spring框架提供的核心功能之一,主要用来拦截用户的请求,在指定方法前后,根据业务需要执行预先设定的代码

也就是说,允许开发人员提前预定义一些逻辑,在用户的请求响应前后执行,也可以在用户请求前阻止 其执行. 在拦截器当中,开发人员可以在应用程序中做一些通用性的操作,比如通过拦截器来拦截前端发来的 请求,判断Session中是否有登录用户的信息,如果有就可以放行,如果没有就进行拦截

比如我们去银行办理业务,在办理业务前后,就可以加一些拦截操作 办理业务之前,先取号,如果带身份证了就取号成功 业务办理结束,给业务办理人员的服务进行评价。 这些就是”拦截器”做的工作。

2.基本使用

使用步骤:

  1. 定义拦截器
  2. 注册配置拦截器

自定义拦截器:实现Handlerlnterceptor接口,并重写其所有方法

代码语言:javascript
复制
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("LoginInterceptor 目标方法执行前执行..");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("执行postHandle");
}
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("执行afterCompletion");
}
  • preHandle()方法:目标方法执行前执行.返回true:继续执行后续操作;返回false:中断后续操作.
  • postHandle()方法:目标方法执行后执行
  • afterCompletion(方法:视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,暂不了解)

注册配置拦截器:实现WebMvcConfigurer接口,并重写addInterceptors方法

可以注入loginInterceptor,也可以创建对象

代码语言:javascript
复制
//配置信息
@Configuration
public class WebConfig implements WebMvcConfigurer {

//    @Autowired
//    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")//对那些路径生效
                .excludePathPatterns("/user/login");//排除掉哪些路径
    }
}

3.拦截器详解

3.1 拦截路径

拦截路径是指我们定义的这个拦截器,对哪些请求生效

我们在注册配置拦截器的时候,通过addPathPatterns()方法指定要拦截哪些请求.也可以通过excludePathPatterns()指定不拦截哪些请求.

上述代码中,我们配置的是/**,表示拦截所有的请求。

比如用户登录校验,我们希望可以对除了登录之外所有的路径生效。

代码语言:javascript
复制
//配置信息
@Configuration
public class WebConfig implements WebMvcConfigurer {

      @Autowired
      private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")//对哪些路径生效
                .excludePathPatterns("/user/login");//排除掉哪些路径
    }
}

在拦截器中除了可以设置/**拦截所有资源外,还有一些常见拦截路径设置:

拦截路径

含义

举例

/*

一级路径

能匹配/user,/book,/login,不能匹配 /user/login

/**

任意级路径

能匹配/user,/user/login,/user/reg

/book/*

/book下的一级路径

能匹配/book/addBook,不能匹配/book/addBook/1,/book

/book/**

/book下的任意级路径

能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login

以上拦截规则可以拦截此项目中的使用URL,包括静态文件(图片文件,JS和CSS等文件)

3.2 拦截器执行流程

  1. 添加拦截器后,执行Controller的方法之前,请求会先被拦截器拦截住.执行preHandle方法, 这个方法需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,继续访问controller中的方法. 如果返回false,则不会放行(controller中的方法也不会执行).
  2. controller当中的方法执行完毕后,再回过来执行postHandle()这个方法以及afterCompletion()方法,执行完毕之后,最终给浏览器响应数据.

4.图书管理登录校验

4.1 定义拦截器

从session中获取用户信息,如果session中不存在,则返回false,并设置http状态码为401,否则返回true.

代码语言:javascript
复制
@Slf4j
//@Component
public class LoginInterceptor implements HandlerInterceptor {
    //@Autowired
    private ObjectMapper objectMapper = new ObjectMapper() ;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("登录拦截");
        // 获取当前会话(不创建新会话)
        HttpSession session = request.getSession(false);
        if (session == null || session.getAttribute(Constants.SESSION_USER_KEY) == null ||
                !StringUtils.hasLength((String) session.getAttribute(Constants.SESSION_USER_KEY))) {
            //用户未登录
            log.error("用户未登录,进行拦截");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            Result result = Result.unlogin();
            // 将响应体转为 JSON 并写入输出流
            response.getOutputStream().write(objectMapper.writeValueAsString(result).getBytes());
            response.setContentType("application/json;charset=utf-8");
            return false;// 拦截请求,不进入 Controller
        }
        log.info("用户校验通过");
        return true;// 放行请求,继续执行 Controller 方法
    }
}

登陆失败进行拦截:

登陆成功放行:

4.2 注册配置拦截器

代码语言:javascript
复制
//配置信息
@Configuration
public class WebConfig implements WebMvcConfigurer {

      @Autowired
      private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")//对那些路径生效
                .excludePathPatterns("/user/login");//排除掉哪些路径
    }
}

5.统一数据返回格式

统一的数据返回格式使用@ControllerAdviceResponseBodyAdvice的方式实现

@ControllerAdvice表示控制器通知类

添加类ResponseAdvice实现ResponseBodyAdvice接口,并在类上添加@ControllerAdvice注解

将所有接口返回值统一包装为 Result 格式

统一所有接口的返回格式,将任意类型的返回值(如实体对象、集合、字符串等)包装为 Result 类型(包含状态码、消息、数据的标准化结构),同时兼容已手动包装的 Result 对象和特殊的 String 类型,避免格式混乱或类型转换异常。

代码语言:javascript
复制
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result) {
            return body;
        }
        if (body instanceof String) {
            return objectMapper.writeValueAsString(Result.sucess(body));
        }
        return Result.sucess(body);
    }
}
  • supports方法:判断是否要执行beforeBodyWrite方法.true为执行,false不执行.通过该方法可以选择哪些类或哪些方法的response要进行处理,其他的不进行处理
  • beforeBodyWrite方法:对response方法进行具体操作处理 在响应体写入客户端前执行,对返回值 body 进行统一包装: 添加统一数据返回格式前后对比
    • body 已是 Result 类型(手动包装的响应),直接返回,避免重复包装;
    • bodyString 类型:因 Spring 对 String 默认使用 StringHttpMessageConverter 处理,直接返回 Result 会导致类型不匹配,故通过 objectMapperResult 序列化为 JSON 字符串;
    • 其他类型(如 UserList<User> 等):统一用 Result.success(body) 包装为标准化格式(包含状态码、消息、数据)。

6.统一异常处理

统一异常处理使用的是@ControllerAdvice+@ExceptionHandler来实现的,

@ControllerAdvice表示控制器通知类,@ExceptionHandler是异常处理器,

两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件

通过 @ControllerAdvice@ExceptionHandler 注解捕获应用中抛出的各类异常,统一返回标准化响应

代码语言:javascript
复制
@Slf4j
@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    @ExceptionHandler
    public Object handler(Exception e){
        log.error("发生异常, e: ", e);
        return Result.fail();
    }

    //    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler
    public Object handler(ArrayIndexOutOfBoundsException e){
        log.error("发生异常, e:{} ", e.getMessage());
        return Result.fail("发生数组越界异常");
    }
    @ExceptionHandler
    public Object handler(NullPointerException e){
        log.error("发生异常, e: ", e);
        return Result.fail("发生NullPointerException 异常");
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler
    public Object handler(NoResourceFoundException e){
        log.error("发生异常, e: {}, path:{}", e.getDetailMessageCode(), e.getResourcePath());
        return Result.fail("发生NoResourceFoundException 异常");
    }
}

类名,方法名和返回值可以自定义

接口返回为数据时,需要加@ResponseBody注解

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.拦截器
  • 2.基本使用
  • 3.拦截器详解
    • 3.1 拦截路径
    • 3.2 拦截器执行流程
  • 4.图书管理登录校验
    • 4.1 定义拦截器
    • 4.2 注册配置拦截器
  • 5.统一数据返回格式
  • 6.统一异常处理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档