spring拦截器 与统一格式
目录
- 前言
- 模拟拦截器
- 拦截器的实现原理
- 什么是动态代理? 什么是静态代理
- 静态代理与动态代理的区别
- 两种常用的动态代理方式
- 基于接口的动态代理
- 基于类的动态代理
- JDK Proxy 与 CGlib的区别
- 其他 统⼀访问前缀添加
- 统⼀异常处理
- 统⼀数据返回格式
前言
之前博客讲述了 , 关于SpringAOP如何实现, 但是在实际开发中, 我们大多数不会遇到SpringAOP, 而是使用Spring拦截器代替了SpringAOP的功能, 因为Spring拦截器 比起AOP来更简单, 更好上手
模拟拦截器
- 创建一个拦截器 - 定义一个类,实现HandlerInterceptor 接口, 并重写preHandle方法 , 在这个类中 ,写业务的判断方法, (注: 这个类只是一个普通类)
package com.example.demo.config;import com.example.demo.common.AppVariable;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class UserInterceptor implements HandlerInterceptor {/**** @param request* @param response* @param handler* @return 返回TRUE的时候, 表示拦截器验证成功, 返回FALSE 表示拦截器验证失败* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {// 业务方法HttpSession session = request.getSession(false); // 默认值是TRUE ,没有会自动创建一个session会话if (session != null && session.getAttribute(AppVariable.SESSION_KEY) != null){// 用户已登录return true;//如果是TRUE就继续执行后续方法}return false;// FALSE 不执行后续方法}
}
- 将拦截器配置到系统的配置文件中, 并配置拦截器的拦截规则
也就是, 定义一个全局类, 加上@Configuration 注解 , 然后实现WebMvcConfigurer接口, 重写addInterceptors 方法, 在方法中定义具体拦截那些资源
注: 一个项目中可以有多个拦截规则
package com.example.demo.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration //一定要加一个Configurationpublic class AppConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new UserInterceptor()) // 这儿也可以使用注解的方式来注入 , 表示具体拦截的类 .addPathPatterns("/**") // 一刀切, 拦截所有的请求.excludePathPatterns("/user/reg") // 配置不拦截的接口.excludePathPatterns("/user/login") // 不拦截的有更多的就写更多的方法;}
}
- 定义一个测试类, 来测试拦截的功能
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/getuser")public String getUser(){return "do getUser";}@RequestMapping("/reg")public String reg(){return "do reg";}@RequestMapping("/login")public String login(){return "do login";}}
拦截器的实现原理
之前的Spring调用流程
加入拦截器的调用流程
可以看出, 拦截器就是在访问控制层之前, 先将用户的请求处理一遍, 如果正确就给与后序层去调用, 如果不正确就拦截下来,让其实现对应的业务逻辑
拦截器也是通过动态代理的方式来实现的,
什么是动态代理? 什么是静态代理
代理: 就是将我们不愿意做的事情,交给别人去做
我们先来说什么是静态代理: 在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。简单来说静态代理就是在不改变源代码的基础上增加新的功能
比方说: 俩个类都实现了一个接口, 这样类A就可以通过类B 来加强一些自己说不具备的功能, 这种就可以说是静态代理, 因为你是根据代码提前写好去调用其他对象,这些对象在程序运行前就已经加载上了
有了静态代理的概念: 那么动态代理也就很清晰了
我们从上述可以看出静态代理受限于接口的实现。动态代理就是通过使用反射,动态地获取抽象接口的类型,从而获取相关特性进行代理
代理类在程序运行期间,创建的代理对象称之为动态代理对象。这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的“指示”,动态生成的
静态代理与动态代理的区别
静态代理需要自己写代理类并一一实现目标方法,且代理类必须实现与目标对象相同的接口。
动态代理不需要自己实现代理类,它是利用 JDK或CGLib,动态地在内存中构建代理对象(需要我们传入被代理类),并且默认实现所有目标方法。
两种常用的动态代理方式
基于接口的动态代理
是JDK提供的: 必须使用JDK官方的Proxy类创建代理对象,代理的目标对象必须实现接口
基于类的动态代理
是 CGLib提供的: 使用CGLib的Enhancer类创建代理对象
JDK Proxy 与 CGlib的区别
- 出生不同
- 实现不同 , JDK Proxy 要求代理类实现接口才能实现代理 , 而CGLib是实现代理类的子类完成动态代理
- 性能不同, JDK 7 Proxy 性能高于 CGLib , 而JDK 7 之前CGLib性能高于Proxy
其他 统⼀访问前缀添加
所有请求地址添加 api 前缀 , 在实现WebMvcConfigure 接口的类中 ,重写configurePathMatch方法 , 其中第⼆个参数是⼀个表达式,设置为 true 表示启动前缀
@Configuration
public class AppConfig implements WebMvcConfigurer {// 所有的接⼝添加 api 前缀@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("api", c -> true);}
}
统⼀异常处理
统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件,具体实现代码如下:
⽅法名和返回值可以⾃定义,其中最重要的是@ExceptionHandler(Exception.class) 注解 , 注解中放具体的异常类型, 也可以直接使用Exception来处理所有的异常,
调用流程如下: 定义了Exception异常的前提下, 如果找到对应异常就使用对应异常处理, 找不到就是用Exception异常处理
import java.util.HashMap;
@ControllerAdvice
public class ErrorAdive {@ExceptionHandler(Exception.class)@ResponseBodypublic Object handler(Exception e) {HashMap<String, Object> map = new HashMap<>();map.put("state", 0);map.put("data", null);map.put("msg", e.getMessage());return map;}
}
统⼀数据返回格式
统⼀的数据返回格式可以使⽤ @ControllerAdvice + ResponseBodyAdvice 的⽅式实现,具体实现代
码如下
如果想要使用统一数据的返回格式, 首先在类上加上@ControllerAdvice注解, 然后在类上实现 ResponseBodyAdvice 接口, 并重写俩个方法, support 与beforeBodywrite , 其中support 必须返回TRUE 否则不调用beforeBodywrite 方法, 在beforeBodywrite中写数据返回类型
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 {/*** 内容是否需要重写(通过此⽅法可以选择性部分控制器和⽅法进⾏重写)* 返回 true 表示重写*/@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<String, Object> result = new HashMap<>();result.put("state", 1);result.put("msg", "");result.put("data", body);return result;}
}
相关文章:

spring拦截器 与统一格式
目录 前言模拟拦截器拦截器的实现原理什么是动态代理? 什么是静态代理静态代理与动态代理的区别两种常用的动态代理方式基于接口的动态代理基于类的动态代理 JDK Proxy 与 CGlib的区别 其他 统⼀访问前缀添加统⼀异常处理统⼀数据返回格式 前言 之前博客讲述了 , 关于SpringA…...

leetcode 122. 买卖股票的最佳时机 II
2023.7.29 把整体利润拆分成每天的利润,将股票值想象成一个折线图,将所有上升的值相加即可。 代码: class Solution { public:int maxProfit(vector<int>& prices) {int ans 0;for(int i1; i<prices.size(); i){if(prices[i]-…...
代理模式:控制访问的设计模式
代理模式:控制访问的设计模式 什么是代理模式? 代理模式是一种常见的设计模式,它允许通过代理对象来控制对真实对象的访问。代理模式的主要目的是在不改变原始对象的情况下,提供额外的功能或控制访问。 为什么要使用代理模式&a…...
2020/7/30
Educational Codeforces Round 143 (Rated for Div. 2)\C_Tea_Tasting.cpp //题意:有n种茶,n个人,第i种茶有 a[i]的量,第i个人一次能喝 b[i], 第i个人从第i种茶开始往前喝,求每个人最多能喝多少茶。 //思路ÿ…...

图形编辑器开发:是否要像 Figma 一样上 wasm
大家好,我是前端西瓜哥。 wasm 拿来做 Web 端的图形编辑器貌似是不错的选择。 因为图形处理会有相当多无法利用到 WebGL GPU 加速的 CPU 密集的计算。比如对一条复杂贝塞尔曲线进行三角化,对多个图形进行复杂图形的布尔运算。 图形编辑器性能天花板 F…...

Linux学成之路(基础篇0(二十三)MySQL服务(主从MySQL服务和读写分离——补充)
目录 一、MySQL Replication概述 优点 异步复制(Asynchronous repication) 全同步复制(Fully synchronous replication) 半同步复制(Semisynchronous replication) 三、MySQL支持的复制 四、部署主从…...

spring启动流程 (6完结) springmvc启动流程
SpringMVC的启动入口在SpringServletContainerInitializer类,它是ServletContainerInitializer实现类(Servlet3.0新特性)。在实现方法中使用WebApplicationInitializer创建ApplicationContext、创建注册DispatcherServlet、初始化ApplicationContext等。 SpringMVC…...

设计模式-中介者模式在Java中使用示例-客户信息管理
场景 欲开发客户信息管理窗口界面,界面组件之间存在较为复杂的交互关系:如果删除一个客户, 要在客户列表(List)中删掉对应的项,客户选择组合框(ComboBox)中客户名称也将减少一个; 如果增加一个客户信息,…...
14443-1-doc
介绍 ISO/IEC 14443 是描述 ISO/IEC 7810 中定义的身份证参数以及此类卡在国际交换中的使用的一系列国际标准之一。 ISO/IEC 14443 的这一部分描述了感应卡的物理特性。 ISO/IEC 14443 的这一部分并不排除在卡上纳入其他标准技术,例如资料性附录 A 中引用的技术。非…...

SpringBoot的三层架构以及IOCDI
目录 一、IOC&DI入门 二、三层架构 数据库访问层 业务逻辑层 控制层 一、IOC&DI入门 在软件开发中,IOC(Inversion of Control)和DI(Dependency Injection)是密切相关的概念。 IOC(控制反转&a…...

RabbitMQ部署指南
RabbitMQ部署指南 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一:在线拉取 docker pull rabbitmq:3-management方式二:从本地加载 已经提供了镜像包: 上传到虚拟机中后,使用命令加载镜像即可&…...

【Golang】Golang进阶系列教程--Go 语言切片是如何扩容的?
文章目录 前言声明和初始化扩容时机源码分析go1.17go1.18内存对齐 总结 前言 在 Go 语言中,有一个很常用的数据结构,那就是切片(Slice)。 切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装…...

【数据结构】顺序表(SeqList)(增、删、查、改)详解
一、顺序表的概念和结构 1、顺序表的概念: 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 2、顺序表的结构: (1)静态顺序表:使…...

[golang gin框架] 42.Gin商城项目-微服务实战之后台Rbac微服务角色增删改查微服务
一.重构后台Rbac用户登录微服务功能 上一节讲解了后台Rbac微服务用户登录功能以及Gorm数据库配置单独抽离,Consul配置单独抽离,这一节讲解后台Rbac微服务角色增删改查微服务功能,Rbac微服务角色增删改查微服务和后台Rbac用户登录微服务是属于…...

项目篇:Echo论坛系统项目
一、登录注册模块 1、注册功能 1.1、注册流程图 1.2、注册代码 /*** 用户注册* param user* return Map<String, Object> 返回错误提示消息,如果返回的 map 为空,则说明注册成功*/public Map<String, Object> register(User user) {Map&l…...

数据可视化(2)
1.柱状图 #柱状图 #bar(x,height,width,*,aligncenter,**kwargs) #height柱子的高度,即y轴上的数据 #width数组的宽度,默认值0.8 #*表示后面的参数为匿名关键字,必须传入参数 #kwargs关键字参数x[1,2,3,4,5] height[random.randint(10,100)f…...

MD-MTSP:斑马优化算法ZOA求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)
一、斑马优化算法ZOA 斑马优化算法(Zebra Optimization Algorithm,ZOA)Eva Trojovsk等人于2022年提出,其模拟斑马的觅食和对捕食者攻击的防御行为。斑马优化算法(Zebra Optimization Algorithm,ZOA&#x…...

【笔试强训选择题】Day32.习题(错题)解析
作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:笔试强训选择题 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!! 文章目录 前言 一、Da…...

抖音seo账号矩阵系统源码如何开发布局?
目录 一、 抖音SEO账号矩阵系统源码的开发布局步骤如下: 二。 开发部署源码 三、 开发部署功能设计 1. 短视频AI智能创作 2. 托管式账号管理: 3. 数据分析 4. 智能营销获客 四。 抖音seo源码开发部署交付技术文档包含 五。 开发代码展示: 一、 抖…...
vue项目cdn打包优化
0.用vue ui可以查看项目打包后的情况。 1.定义包的排除 let externals {axios: axios,element-ui: ELEMENT,echarts: echarts,} configureWebpack: {externals: externals }2.配置cdn包资源 // 配置 let cdn {css: [// element-ui csshttps://unpkg.com/element-ui/lib/th…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...

Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...