news 2026/5/3 4:56:15

【Spring 统一功能处理】拦截器、统一数据返回、异常处理:动态搞定后端接口规范

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Spring 统一功能处理】拦截器、统一数据返回、异常处理:动态搞定后端接口规范

文章目录

    • 一、拦截器
      • 1.1 拦截器入门
        • 1.1.1 拦截器介绍
        • 1.1.2 自定义拦截器
        • 1.1.3 注册配置拦截器
      • 1.2 拦截器详解
        • 1.2.1 拦截路径
        • 1.2.2 拦截器执行流程
    • 二、统一数据返回格式
      • 2.1 实现方式
      • 2.2 可能出现的问题
    • 三、统一异常处理

一、拦截器

1.1 拦截器入门

1.1.1 拦截器介绍

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

在拦截器当中,开发人员可以在应用程序中做一些通用性的操作,比如通过拦截器来拦截前端发来的请求,判断Session中是否有登录用户的信息.。如果有就可以放行,如果没有就进行拦截。

拦截器的使用步骤分为两步:

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

实现HandlerInterceptor接口,并重写其所有方法

@Slf4j@ComponentpublicclassLoginInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{log.info("LoginInterceptor 目标方法执行前执行..");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{log.info("LoginInterceptor 目标方法执行后执行");}}
  • preHandle()方法:目标方法执行前执行。返回true:继续执行后续操作;返回false:中断后续操作。
  • postHandle()方法:目标方法执行后执行。
  • afterCompletion()方法:视图渲染完毕后执行,最后执行(后端开发现在几乎不涉及视图,可以忽略)。
1.1.3 注册配置拦截器

实现WebMvcConfigurer接口,并重写addInterceptors方法

@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{//自定义的拦截器对象@AutowiredprivateLoginInterceptorloginInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)}}

启动服务,试试访问任意请求,观察后端日志。

可以看到preHandle 方法执行之后就放行了,开始执行目标方法,目标方法执行完成之后执行 postHandle。

1.2 拦截器详解

1.2.1 拦截路径

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

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

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

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

@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{//自定义的拦截器对象@AutowiredprivateLoginInterceptorloginInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){//注册自定义拦截器对象registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");//设置拦截器拦截的请求路径 (/** 表示拦截所有请求)}}

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

拦截路径含义
/*一级路径
/**任意级路径
/book/*/book下的一级路径
/book/**/book下的任意级路径

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

1.2.2 拦截器执行流程

正常的调用顺序:
后端程序 -> Controller 控制器层 -> 服务层 Service -> 数据持久层 Mapper -> 调用数据库

有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下:
后端程序 -> 拦截器 -> 控制器层 Controller -> 服务层 Service -> 数据持久层 Mapper -> 数据库

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

二、统一数据返回格式

2.1 实现方式

统一的数据返回格式使用 @ControllerAdvice 和 ResponseBodyAdvice 的方式实现

@ControllerAdvice 表示控制器通知类

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

@ControllerAdvicepublicclassResponseAdviceimplementsResponseBodyAdvice{@Overridepublicbooleansupports(MethodParameterreturnType,ClassconverterType){returntrue;}@OverridepublicObjectbeforeBodyWrite(Objectbody,MethodParameterreturnType,MediaTypeselectedContentType,ClassselectedConverterType,ServerHttpRequestrequest,ServerHttpResponseresponse){returnResult.success(body);}}

supports方法:判断是否要执行beforeBodyWrite方法。true为执行,false不执行。通过该方法可以选择哪些类或哪些方法的response要进行处理,其他的不进行处理。

beforeBodyWrite方法:对response方法进行具体操作处理。

2.2 可能出现的问题

问题现象:

在测试修改图书的接口: http://127.0.0.1:8080/book/updateBook
结果显示,发生内部错误。查看日志,日志报错:java.lang.ClassCastException: com.example.demo.model.Result cannot be cast to java.lang.String

多测试几种不同的返回结果,发现只有返回结果为String类型时才有这种错误发生。

解决方案:将返回数据转换为String 类型返回。

@SneakyThrows@OverridepublicObjectbeforeBodyWrite(Objectbody,MethodParameterreturnType,MediaTypeselectedContentType,ClassselectedConverterType,ServerHttpRequestrequest,ServerHttpResponseresponse){//返回结果更加灵活if(bodyinstanceofResult){returnbody;}//如果返回结果为String类型, 使用SpringBoot内置提供的Jackson来实现信息的序列化if(bodyinstanceofString){returnmapper.writeValueAsString(Result.success(body));}returnResult.success(body);}

统一数据返回格式优点:

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

三、统一异常处理

统一异常处理使用的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执行某个通知,也就是执行某个方法事件。

具体代码如下:

@ControllerAdvice@ResponseBodypublicclassErrorAdvice{@ExceptionHandlerpublicObjecthandler(Exceptione){returnResult.fail(e.getMessage());}}

类名,方法名和返回值可以自定义,重要的是注解。
接口返回为数据时,需要加@ResponseBody 注解。

以上代码表示,如果代码出现Exception异常(包括Exception的子类),就返回一个 Result的对象,Result 对象的设置参考 Result.fail(e.getMessage())。

publicstaticResultfail(Stringmsg){Resultresult=newResult();result.setStatus(ResultStatus.FAIL);result.setErrorMessage(msg);result.setData("");returnresult;}

可以针对不同的异常,返回不同的结果。

@Slf4j@ResponseBody@ControllerAdvicepublicclassExceptionAdvice{@ExceptionHandlerprivateResulthandler(Exceptione){log.error("发生异常 e",e);returnResult.fail("内部错误请联系管理员");}@ExceptionHandlerprivateResulthandler(NullPointerExceptione){log.error("发生异常 e",e);returnResult.fail(-2,"发生空指针异常");}@ExceptionHandlerprivateResulthandler(ArithmeticExceptione){log.error("发生异常 e",e);returnResult.fail(-3,"发生算数异常");}@ExceptionHandlerprivateResulthandler(IndexOutOfBoundsExceptione){log.error("发生异常 e",e);returnResult.fail(-4,"发生数组越界异常");}}

模拟制造异常:

@RequestMapping("/test")@RestControllerpublicclassTestController{@RequestMapping("/t1")publicStringt1(){inta=10/0;return"t1";}@RequestMapping("/t2")publicStringt2(){Stringa=null;System.out.println(a.length());return"t2";}}

当有多个异常通知时,匹配顺序为当前类及其子类向上依次匹配。

/test/t1 抛出ArithmeticException, 运行结果如下:

/test/t2 抛出NullPointerException, 运行结果如下:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 12:59:45

ChatGLM3-6B应用场景详解:解锁AI助手的10种用法

ChatGLM3-6B应用场景详解:解锁AI助手的10种用法 1. 为什么你需要一个“本地化”的ChatGLM3-6B 你有没有遇到过这些情况? 在写技术文档时卡在某个专业术语的准确表达上,查资料花了20分钟; 给客户写一封商务邮件,反复修…

作者头像 李华
网站建设 2026/4/18 8:52:26

Qwen2.5-7B可以多卡训练吗?当前镜像适配情况

Qwen2.5-7B可以多卡训练吗?当前镜像适配情况 1. 核心问题直击:单卡是默认,多卡需重构 你刚拿到一台双4090D工作站,满心期待用两块24GB显卡加速Qwen2.5-7B的微调——结果发现镜像里所有命令都写着 CUDA_VISIBLE_DEVICES0。这不是…

作者头像 李华
网站建设 2026/4/30 17:15:06

Qwen-Image-Edit修图神器体验:不用PS,一句话搞定背景替换/加墨镜

Qwen-Image-Edit修图神器体验:不用PS,一句话搞定背景替换/加墨镜 1. 这不是PS,但比PS更“听话” 你有没有过这样的时刻: 想给客户发一张带雪景氛围的办公照,却卡在Photoshop的图层蒙版里; 想给产品图换上…

作者头像 李华
网站建设 2026/4/24 8:11:04

小白也能懂:GTE中文向量模型快速入门与实战指南

小白也能懂:GTE中文向量模型快速入门与实战指南 你有没有遇到过这些情况? 想从几百篇产品文档里快速找到和“售后流程优化”最相关的那几条,却只能靠关键词硬搜,结果一堆不相关的内容混在里面;做客服知识库时&#x…

作者头像 李华
网站建设 2026/5/1 9:07:34

DeepChat实战:用本地Llama3模型打造企业级智能客服系统

DeepChat实战:用本地Llama3模型打造企业级智能客服系统 在企业数字化转型加速的今天,客服系统正经历一场静默革命——不再满足于关键词匹配和预设话术,而是追求真正理解用户意图、自主调用知识库、持续优化服务体验的“有思考能力”的智能体…

作者头像 李华
网站建设 2026/5/3 4:25:50

零基础玩转RexUniNLU:手把手教你做法律文书分析

零基础玩转RexUniNLU:手把手教你做法律文书分析 1. 你不需要懂NLP,也能用好这个法律AI工具 你有没有遇到过这样的情况: 法务同事每天要翻几十份合同,眼睛看花也怕漏掉关键条款;律师助理刚入职,面对满屏“…

作者头像 李华