【Spring AOP】如何统一“拦截器校验、数据格式返回、异常返回”处理?
创始人
2024-05-30 18:41:31
0

目录

一、Spring  拦截器

1.1、背景

1.2、实现步骤

1.3、拦截原理

二、 统一url前缀路径

2.1、方法一:在系统的配置文件中设置

2.2、方法二:在 application.properies 中配置

三、统一异常处理

四、统一返回数据返回格式处理

4.1、背景

4.2、具体实现


一、Spring  拦截器


1.1、背景

在原生的 Spring AOP 中实现统一的拦截的难点在于:1.定义拦截规则(表达式)很难,2.在切面类中拿到 HttpSession 比较难;如何解决这两个难点呢?使用拦截器!

1.2、实现步骤

实现一个普通的拦截器关键在于以下两步:

  1. 实现 HandlerInterceptor 接口,重写 preHeadler 方法,在方法中编写自己的业务代码。
  2. 将拦截器添加到配置文件中,设置拦截规则。

具体的,首先步骤一,例如要实现一个用户登录判断,就需要创建一个类,这里起名叫LoginInterceptor 类,实现 HandlerInterceptor 接口,重写 preHeadler 方法(此方法返回的是以个 boolean 类型,如果为 true 表示验证成功,可以继续执行后面的流程,若是 false 表示验证失败,后面的流程就不执行了),通过是否可以获取到 Session 信息判断用户是否已经登陆,来返回 true 或 false。

a)实现 HandlerInterceptor 接口,重写 preHeadler 方法,如下代码:

import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;//登录拦截器
public class LoginInterceptor implements HandlerInterceptor {/*** 此方法返回一个 boolean,若为 true 表示验证成功,否则验证失败,后面的流程不能执行了* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic 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");return false;}
}

b)将拦截器添加到配置文件中,设置拦截规则

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class AppConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") //连接所有请求,值得注意的是,这里不能只写一个 *,一个 * 表示一级路径.excludePathPatterns("/user/login") //不拦截的 url.excludePathPatterns("/user/reg").excludePathPatterns("/**/*.html"); //不拦截所有的页面}
}

注意:

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

说明:以上拦截规则可以拦截此项⽬中的使⽤ URL,包括静态⽂件(图⽚⽂件、JS 和 CSS 等⽂件)

1.3、拦截原理

二、 统一url前缀路径


2.1、方法一:在系统的配置文件中设置

具体的,重写 WebMvcConfigurer 接口下的 configurePathMatch 方法,例如修改所有请求url添加前缀 /zhangsan ,如下代码:

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;@Configuration
public class AppConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/zhangsan", c -> true);}}

2.2、方法二:在 application.properies 中配置

例如修改所有请求url添加前缀 /zhangsan,如下代码:

server.servlet.context-path=/zhangsan

三、统一异常处理


统一异常处理是通过如下两个注解结合实现的:

  • @ControllerAdvice:表示控制器通知类。
  • @ExceptionHandler:表示异常处理器。

两个结合表示出现异常的时候执行某个通知方法,具体的步骤如下:

  1. 创建一个类,标识上 @ControllerAdvice;
  2. 在方法上添加 @ExceptionHandler;

如下代码:

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;@ControllerAdvice
@ResponseBody
public class MyExHandler {/*** 拦截所有的空指针异常,进行统一的数据返回* @param e* @return*/@ExceptionHandler(Exception.class) //这里也可以根据实际情况,填写不同的异常public HashMap nullException(NullPointerException e) {HashMap reslut = new HashMap<>();reslut.put("code", "-1");reslut.put("msg", "空指针异常" + e.getMessage());reslut.put("data", null);//这里返回 HashMap ,就相当于项前端返回了一个 JSON 格式的数据return reslut;}}

四、统一返回数据返回格式处理


4.1、背景

为什么要统一数据返回格式处理?例如以下几个原因:

  • 方便前端程序员更好的接收和解析后端返回的数据;
  • 降低约定前后端交互接口的成本,按照某种格式实现即可,因为所有的接口都是这样返回的。
  • 有利于项目的统一数据的维护和修改。

4.2、具体实现

统一数据格式返回的实现需要以下两个步骤:

  1. 创建一个类,并添加 @ControllerAdvice。
  2. 实现 ResponseBodyAdvice 接口,重写 supports 和  beforeBodyWrite。

Ps:

1、 supports 方法不用编写业务逻辑,而是像一个控制器一样,返回 true 则执行 beforeBodyWrite 方法,反之则不执行。

2、beforeBodyWrite 方法就是用来实现统一对象的。

具体的如下:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
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 ResponseAdvice implements ResponseBodyAdvice {//将 java 对象转化成 JSON 格式@Autowiredprivate ObjectMapper objectMapper;/*** 此方法返回 true 则执行下面的 beforeBodyWrite 方法,反之则不执行* @param returnType* @param converterType* @return*/@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {HashMap result = new HashMap<>();result.put("code", 200);result.put("msg", "");result.put("data",body);// 这里需要进行特殊处理,因为 String 在转换的时候报错if(body instanceof String) {try {return objectMapper.writeValueAsString(result);} catch (JsonProcessingException e) {e.printStackTrace();}}return result;}
}

代码中为什么要进行特殊处理?(最易出错!)

在 java 程序中, String 是一个最特殊的类型(既不是基础类型也不是对象),并且在重写方法时也很特殊,除了 String 其他的都是用一个格式化工具,而 String 用的是自己的一套格式化工具,因此在转换成 HashMap 的时候还没有被加载好,而其他的转换器已经加载好了,最后就会引发如下异常:

因此就要判断 body 是否为 String ,若为 String 类型,就要进行特殊处理,使用 JSON 的writeValueAsString 方法将 Java 对象转换成 JSON 格式再返回。

 

 

相关内容

热门资讯

大同云冈石窟导游词 大同云冈石窟导游词  云冈石窟佛教艺术按石窟形制、造像内容和样式的发展,小编收集了大同云冈石窟导游词...
明孝陵导游词 明孝陵导游词10篇  作为一名默默奉献的导游,可能需要进行导游词编写工作,导游词具有注重口语化、精简...
无锡九龙灌浴导游词 无锡九龙灌浴导游词  作为一名专门为游客提供优质服务的导游人员,可能需要进行导游词编写工作,导游词由...
灯塔风景区优秀导游词 灯塔风景区优秀导游词  你知道日照吗?日照,取自太阳照耀,就是这样一个太阳照耀下的城市,这里的灯塔风...
金寨红军广场导游词 金寨红军广场导游词  你知道金寨红军广场的来历吗?你知道金寨红军广场的导游词应该怎么写嘛。下面就由小...
山东地下大峡谷景点讲解导游词 山东地下大峡谷景点讲解导游词  各位**游客朋友,你们好!欢迎大家光临山东地下大峡谷旅游区观光游览。...
苏州简介及特色导游词 苏州简介及特色导游词  玄妙观是一座有着1300年历史的恢宏道教建筑群,主殿是九开间的重檐歇山顶的三...
苏州导游词 苏州导游词范文(精选5篇)  作为一名旅游从业人员,时常会需要准备好导游词,导游词是我们引导游览时使...
鸳鸯溪导游词 鸳鸯溪导游词  作为一位兢兢业业的旅游从业人员,就难以避免地要准备导游词,借助导游词可以更好地宣传景...
大理导游词 大理导游词范文(精选8篇)  作为一位不辞辛劳的导游,就难以避免地要准备导游词,导游词可以加深游客对...
四川导游词节选 四川导游词节选  四川,简称为“蜀”,历史悠久。在古代称为巴蜀,是古代巴人和蜀人的发祥地,这片土地孕...
鸟的天堂导游词 鸟的天堂导游词精选15篇  作为一名专门为游客提供优质服务的导游人员,编写导游词是必不可少的,导游词...
韶关南雄梅关古道导游词 韶关南雄梅关古道导游词  各位游客,大家好!我是**旅行社的导游,大家可以叫我**,韶关南雄梅关古道...
上海宋庆龄故居导游词 上海宋庆龄故居导游词  作为一名优秀的旅游从业人员,就不得不需要编写导游词,导游词具有极强的实用性,...
白果树瀑布导游词 白果树瀑布导游词3篇  作为一名优秀的旅游从业人员,常常要写一份好的导游词,导游词是导游员进行实地口...
沈阳张氏帅府导游词 沈阳张氏帅府导游词  作为一名具备丰富知识的导游,就有可能用到导游词,导游词是我们引导游览时使用的讲...
永安桃源洞的导游词 永安桃源洞的导游词各位远道而来的朋友:  一路辛苦了,欢迎你们!我来自三明市明运旅行社,姓张名红鹰,...
青山地质公园的导游词 青山地质公园的导游词  导语:青山之景实在数不胜数,青山之美也实在美不胜收。以下是小编为大家整理分享...
三峡大坝导游词 三峡大坝导游词(精选7篇)  作为一名具备丰富知识的导游,通常会被要求编写导游词,导游词不是以一代百...
游苏州导游词 游苏州导游词  夜读苏州诗,襟怀尽冰雪。下面是小编整理的游苏州导游词,希望对你有所帮助!  篇一:游...