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…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
