spring拦截器 与统一格式

news2024/9/24 3:30:02

目录

  • 前言
  • 模拟拦截器
  • 拦截器的实现原理
    • 什么是动态代理? 什么是静态代理
      • 静态代理与动态代理的区别
      • 两种常用的动态代理方式
        • 基于接口的动态代理
        • 基于类的动态代理
      • JDK Proxy 与 CGlib的区别
  • 其他 统⼀访问前缀添加
    • 统⼀异常处理
    • 统⼀数据返回格式

前言

之前博客讲述了 , 关于SpringAOP如何实现, 但是在实际开发中, 我们大多数不会遇到SpringAOP, 而是使用Spring拦截器代替了SpringAOP的功能, 因为Spring拦截器 比起AOP来更简单, 更好上手

模拟拦截器

  1. 创建一个拦截器 - 定义一个类,实现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
     */
    @Override
    public 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 不执行后续方法
    }
}

  1. 将拦截器配置到系统的配置文件中, 并配置拦截器的拦截规则
    也就是, 定义一个全局类, 加上@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 //一定要加一个Configuration

public class AppConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserInterceptor()) // 这儿也可以使用注解的方式来注入 , 表示具体拦截的类 
                .addPathPatterns("/**") // 一刀切, 拦截所有的请求
                .excludePathPatterns("/user/reg") // 配置不拦截的接口
                .excludePathPatterns("/user/login") // 不拦截的有更多的就写更多的方法

        ;
    }
}

  1. 定义一个测试类, 来测试拦截的功能
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的区别

  1. 出生不同
  2. 实现不同 , JDK Proxy 要求代理类实现接口才能实现代理 , 而CGLib是实现代理类的子类完成动态代理
  3. 性能不同, JDK 7 Proxy 性能高于 CGLib , 而JDK 7 之前CGLib性能高于Proxy

其他 统⼀访问前缀添加

所有请求地址添加 api 前缀 , 在实现WebMvcConfigure 接口的类中 ,重写configurePathMatch方法 , 其中第⼆个参数是⼀个表达式,设置为 true 表示启动前缀

@Configuration
public class AppConfig implements WebMvcConfigurer {
 // 所有的接⼝添加 api 前缀
 @Override
 public 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)
	 @ResponseBody
	 public 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 表示重写
	 */
	 @Override
	 public boolean supports(MethodParameter returnType, Class converterTyp
	e) {
		 return true;
	 }
	 /**
	 * ⽅法返回之前调⽤此⽅法
	 */
	 @Override
	 public Object beforeBodyWrite(Object body, MethodParameter returnType,
	MediaType selectedContentType,
	 Class selectedConverterType, ServerHttpR
	equest request,
	 ServerHttpResponse response) {
		 // 构造统⼀返回对象
		 HashMap<String, Object> result = new HashMap<>();
		 result.put("state", 1);
		 result.put("msg", "");
		 result.put("data", body);
		 return result;
	 }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/810819.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kotlin~Memento备忘录模式

概念 备忘录模式是一种行为型设计模式&#xff0c;用于捕获和存储对象的内部状态&#xff0c;并在需要时将对象恢复到之前的状态。 备忘录模式允许在不暴露对象内部实现细节的情况下&#xff0c;对对象进行状态的保存和恢复。 角色介绍 Originator&#xff1a;原发器&#x…

7.事件类型

7.1鼠标事件 案例-轮播图点击切换 需求&#xff1a;当点击左右的按钮&#xff0c;可以切换轮播图 分析: ①右侧按钮点击&#xff0c;变量&#xff0c;如果大于等于8&#xff0c;则复原0 ②左侧按钮点击&#xff0c;变量–&#xff0c;如果小于0&#xff0c;则复原最后一张 ③鼠…

Zotero ubuntu2023安装 关联 ubuntu文献翻译

一、准备下载的软件&#xff1a; Zotero | Downloads 1. Zotero-6.0.26_linux-x86_64.tar.bz2 下面是插件 zotfile-5.1.2-fx.xpi zotero-pdf-translate.xpi jasminum-v0.2.6.xpi 2.2.5 Tampermonkey 4.11.crx 所准备的文件&#xff0c;都已经在这个链接的压缩包下面 …

【机器学习】Multiple Variable Linear Regression

Multiple Variable Linear Regression 1、问题描述1.1 包含样例的X矩阵1.2 参数向量 w, b 2、多变量的模型预测2.1 逐元素进行预测2.2 向量点积进行预测 3、多变量线性回归模型计算损失4、多变量线性回归模型梯度下降4.1 计算梯度4.2梯度下降 首先&#xff0c;导入所需的库 im…

【Maven】让maven更高效,优化maven构建项目速度

打开idea的setting&#xff0c;找到maven&#xff0c;设置它多线程数&#xff0c;重启后即可&#xff01; 我这里是8&#xff0c;你们可以随便设置。 如下图&#xff1a;

Android 之 使用 Camera 拍照

本节引言 本节给大家带来的是Android中Camera的使用&#xff0c;简单点说就是拍照咯&#xff0c;无非两种&#xff1a; 1.调用系统自带相机拍照&#xff0c;然后获取拍照后的图片 2.要么自己写个拍照页面 本节我们来写两个简单的例子体验下上面的这两种情况~ 1.调用系统自带…

《向量数据库指南》:向量数据库Pinecone如何集成LangChain(二)

目录 创建嵌入 向量数据库 索引 创建向量存储并查询 生成式问答 创建嵌入 使用LangChain的OpenAI嵌入功能构建嵌入非常简单。我们首先需要运行下一个单元格,以添加我们的OpenAI API密钥: Python from getpass import getpassOPENAI_API_KEY = getpass("OpenAI…

CleanMyMac X4.14.1中文版如何清理 Mac系统?CleanMyMac 真的能断网激活吗?

CleanMyMac X4.14.1中文版如何清理 Mac系统&#xff1f;Mac系统在使用过程中都会产生大量系统垃圾&#xff0c;如不需要的系统语言安装包&#xff0c;视频网站缓存文件&#xff0c;mac软件卸载残留的注册表等。 随着时间推移&#xff0c;mac系统垃圾就会越来越多&#xff0c;电…

Spring事务创建与使用

目录 前言Spring中事务的实现声明式事务Transactional 作⽤范围Transactional 参数说明对于事务不回滚的解决方案 前言 在数据库中我们提到了 事务, 事务的定义为, 将一系列操作封装成一个整体去调用 , 要么一起成功, 要么一起失败 Spring中事务的实现 在Spring中事务的操作…

LLaMA:开放和高效的基础语言模型

Part1前言 我们介绍了LLaMA&#xff0c;这是一个参数范围从7B到65B的基础语言模型集合。我们在数以万亿计的标记上训练我们的模型&#xff0c;并表明有可能完全使用公开可用的数据集来训练最先进的模型&#xff0c;而不必求助于专有的和不可获取的数据集。特别是&#xff0c;L…

快解析内网穿透和nginx端口映射的比较

众所周知&#xff0c;Nginx是一个高性能的Web服务器和反向代理服务器&#xff0c;快解析是一种内网穿透工具&#xff0c;使内部设备可以通过互联网进行访问。虽然它们都涉及到网络连接和端口使用&#xff0c;但在功能和用途上有一些区别。下面就来具体分析一下。 1.Nginx端口映…

Java中的锁分类

Java中有很多的锁&#xff0c;但是并不全指锁&#xff0c;有些指锁的特性&#xff0c;设计&#xff0c;状态。 1.乐观锁 乐观锁认为在更新数据时&#xff0c;乐观的认为并发时并不会出现问题&#xff0c;即不加锁。 2.悲观锁 悲观锁认为多线程对同一个数据进行操作时&#…

数据结构——复杂度

总有一天你要一个人&#xff0c;再暗夜中&#xff0c;向那座桥走过去 文章目录 一、算法的复杂度 考察形式范例 二、算法的时间复杂度 大O的渐进表示法 常见的复杂度对比 例题&#xff1a;消失的数字 题目的三种思路 1.排序遍历 2.减法 3.单身狗思想 三、空间复杂度…

UE5、CesiumForUnreal加载无高度地形

文章目录 1.实现目标2.实现过程3.参考资料1.实现目标 在UE5中,CesiumForUnreal插件默认的地形都是带高度的,这里加载没有高度的地形,即大地高程为0,GIF动图如下: 2.实现过程 参考官方的教程,下载无高度的DEM,再切片加载到UE中。 (1)下载无高度地形DEM0。 在官方帖子…

用合成数据训练托盘检测模型【机器学习】

想象一下&#xff0c;你是一名机器人或机器学习 (ML) 工程师&#xff0c;负责开发一个模型来检测托盘&#xff0c;以便叉车可以操纵它们。 ‌你熟悉传统的深度学习流程&#xff0c;已经整理了手动标注的数据集&#xff0c;并且已经训练了成功的模型。 推荐&#xff1a;用 NSDT设…

day58 单调栈

单调栈 使用场景&#xff1a;通常是一维数组&#xff0c;要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置 本质&#xff1a;空间换时间 三个判断条件&#xff1a; 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况 当前遍历的元素T[i]等于栈顶元素T[st.to…

tinkerCAD案例:24.Tinkercad 中的自定义字体

tinkerCAD案例&#xff1a;24.Tinkercad 中的自定义字体 原文 Tinkercad Projects Tinkercad has a fun shape in the Shape Generators section that allows you to upload your own font in SVG format and use it in your designs. I’ve used it for a variety of desi…

JavaSE第二次考试复盘

sleep是线程类&#xff08;Thread&#xff09;的方法&#xff0c;导致此线程暂停执行指定时间&#xff0c;给执行机会给其他线程&#xff0c;但是监控状态依然保持&#xff0c;到时候会自动恢复。调用sleep不会释放对象锁wait是Object类的方法&#xff0c;对此对象调用wait方法…

AI 能在哪些方面提高普通的程序员的效率

一、提高编码效率 1、起名字&#xff1a;变量名、函数名、类名、表名、数据库名(相信每个程序员都因为起名字掉了不少头发) 2、写简单的工具函数代码、结构转换代码&#xff1a;比如求2个数组的元素交集&#xff1b;把类转换成B类&#xff0c;原来需要一个字段一个字段的手动赋…

用LangChain开源框架实现知识机器人

前言 Large Language Models (LLMs)在2020年OpenAI 的 GPT-3 的发布而进入世界舞台 。从那时起&#xff0c;他们稳步增长进入公众视野。 众所周知 OpenAI 的 API 无法联网&#xff0c;所以大家如果想通过它的API实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频…