【JavaEE】Spring Boot 统一功能处理

news2024/11/16 7:41:11

一.拦截器使用.

1.什么是拦截器?

  • 拦截器是Spring框架提供的核心功能之⼀, 主要用来拦截用户的请求, 在指定方法前后, 根据业务需要执行预先设定的代码
    • 也就是说, 允许开发人员提前预定义一些逻辑, 在用户的请求响应前后执行. 也可以在用户请求前阻止其执行. 在拦截器当中,开发人员可以在应用程序中做一些通用性的操作, 比如通过拦截器来拦截前端发来的请求, 判断Session中是否有登录用户的信息. 如果有就可以放行, 如果没有就进行拦截.也就是当前端请求发来的时候,不会直接执行,而是判断此时用户是否是处于登录状态,如果不是则进行拦截, 如果是则进行放行
    • 在这里插入图片描述
    • 比如我们去银行办理业务, 在办理业务前后, 就可以加一些拦截操作, 办理业务之前, 先取号, 如果带身份证了就取号成功, 业务办理结束, 给业务办理⼈员的服务进行评价.这些就是"拦截器"做的工作.

2.拦截器的入门程序.

1.定义拦截器.

  • 自定义用户登录的拦截器,实现HandlerInterceptor接口,并重写所有方法.
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
        //返回true表示不进行拦截
        log.info("执行了登录拦截器的preHandle方法");
        //获取session,判断session存储的userinfo信息是否为空
        //true表示如果有session就返回session,如果没有就创建
        HttpSession session = request.getSession(false);
        if (session == null) {
            return false;
        }
        UserInfo attribute = (UserInfo) session.getAttribute(Constants.USER_SESSION_KEY);
        if (attribute == null||attribute.getId()<=0) {
            response.setStatus(401);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("执行了登录拦截器的postHandle方法");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("执行了登录拦截器的afterCompletion方法");
    }
}
  • preHandle()方法: 目标方法执行前执行, 如果返回true则不进行拦截; 返回false, 进行拦截
  • postHandle()方法: 目标方法执行后执行.
  • afterCompletion()方法: 视图渲染完毕后执行, 最后执行(后端人员几乎不用管视图如何操作,交给前端即可,所以此处不做过多的介绍).

2.注册配置拦截器.

  • 实现WebMvcConfigurer接口,并重写addInterceptors()方法.
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册拦截器,并告诉他拦截路径
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/login")
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/js/**")
                .excludePathPatterns("/pic/**")
                .excludePathPatterns("/**/*.html")
        ;
    }
}
  • 启动服务, 试试访问任意请求, 观察后端日志:
    在这里插入图片描述

二.拦截器的使用细节.

1. 拦截器的拦截路径配置

  • 拦截路径是指我们定义的这个拦截器, 对哪些请求生效.
  • 我们在注册配置拦截器的时候, 通过 addPathPatterns() 方法指定要拦截哪些请求. 也可以通过excludePathPatterns() 指定不拦截哪些请求. 上述代码中, 我们配置的是 /** , 表示拦截所有的请求
  • 比如用户登录校验, 我们希望可以对除了登录之外所有的路径生效.
import org.springframework.beans.factory.annotation.Autowired;
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 WebConfig implements WebMvcConfigurer {
 	//⾃定义的拦截器对象
 	@Autowired
 	private LoginInterceptor loginInterceptor;
 	@Override
 	public void addInterceptors(InterceptorRegistry registry) {
 	//注册⾃定义拦截器对象
 	registry.addInterceptor(loginInterceptor)
 		.addPathPatterns("/**")
 		.excludePathPatterns("/user/login");//设置拦截器拦截的请求路径
		(/** 表⽰拦截所有请求)
 	}
 }
  • 在拦截器中除了可以设置 /** 拦截所有资源外,还有一些常见拦截路径设置:
拦截路径含义举例
/*一级路径能匹配/user,/book,/login,不能匹配 /user/login
/**任意级路径能匹配/user,/user/login,/user/reg
/book/*/book下的一级路径能匹配/book/addBook,不能匹配/book/addBook/1,/book
/book/**/book下的任意级路径能匹配/book,/book/addBook,/book/addBook/2,不能匹配/user/login
  • 以上拦截规则可以拦截此项目中的使用 URL,包括静态文件(图片文件, JS 和 CSS 等文件).

2. 拦截器执行流程

  • 正常的调用顺序: 在这里插入图片描述
  • 有了拦截器之后,会在调用 Controller 之前进行相应的业务处理,执行的流程如下图:在这里插入图片描述
  1. 添加拦截器后, 执行Controller的方法之前, 请求会先被拦截器拦截住. 执行preHandle() 方法, 这个方法需要返回⼀个布尔类型的值. 如果返回true, 就表示放行本次操作, 继续访问controller中的方法. 如果返回false,则不会放行(controller中的方法也不会执行).
  2. controller当中的方法执行完毕后,再回过来执行 postHandle() 这个方法以及
    afterCompletion() 方法,执行完毕之后,最终给浏览器响应数据

三.适配器模式

什么是适配器模式:
适配器模式, 也叫包装器模式. 将一个类的接口,转换成客户期望的另一个接口, 适配器让原本接口不兼容的类可以合作无间. 简单来说就是==目标类不能直接使用, 通过一个新类进行包装一下, 适配调用方使用. 把两个不兼容的接口通过一定的方式使之兼容.
在这里插入图片描述

  • 适配器模式角色:
    • Target: 目标接口 (可以是抽象类或接口), 客户希望直接用的接口
    • Adaptee: 适配者, 但是与Target不兼容
    • Adapter: 适配器类, 此模式的核心. 通过继承或者引用适配者的对象, 把适配者转为目标接口
    • client: 需要使用适配器的对象

举一个使用适配器模式的例子.

前面学习的slf4j 就使用了适配器模式, slf4j提供了一系列打印日志的api, 底层调用的是log4j 或者 logback来打日志, 我们作为调用者, 只需要调用slf4j的api就行了.

  • 基本结构:
    在这里插入图片描述
public interface Slf4jLog {
    void log(String msg);
}
public class Log4j {
    public void log(String msg) {
        System.out.println("我是Log4j,需要打印的信息为: "+msg);
    }
}

public class Log4jAdapter implements Slf4jLog{
    private Log4j log4j;
    public Log4jAdapter(Log4j log4j){
        this.log4j = log4j;
    }
    @Override
    public void log(String msg) {
        //使用Log4j进行打印
        log4j.log("我是适配器,打印的信息为: "+msg);
    }
}
public class Main {
    public static void main(String[] args) {
        Slf4jLog slf4jLog = new Log4jAdapter(new Log4j());
        slf4jLog.log("我是客户端");
    }
}

运行结果:
在这里插入图片描述

  • 可以看出, 我们不需要改变log4j的api,只需要通过适配器转换下, 就可以更换日志框架, 保障系统的平稳运行.
  • 适配器模式应用场景
    • 一般来说,适配器模式可以看作一种"补偿模式",用来补救设计上的缺陷. 应用这种模式算是"无奈之举", 如果在设计初期,我们就能协调规避接口不兼容的问题, 就不需要使用适配器模式了. 所以适配器模式更多的应用场景主要是对正在运行的代码进行改造, 并且希望可以复用原有代码实现新的功能. 比如版本升级等.

四. 统一数据返回格式.

  • 强制登录案例中, 我们共做了两部分工作
    • 通过Session来判断用户是否登录.
    • 对后端返回数据进行封装, 告知前端处理的结果.

快速入门:
统一的数据返回格式使用 @ControllerAdvice 和 ResponseBodyAdvice 的方式实现
@ControllerAdvice 表示控制器通知类, 添加类 ResponseAdvice , 实现ResponseBodyAdvice 接口, 并在类上添加@ControllerAdvice 注解.

@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    //序列化
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//        if(returnType.getMember().)
        //是否需要处理
        return true;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result) {
            return body;
        }
        if (body instanceof String) {
            //序列化String
            return objectMapper.writeValueAsString(Result.success(body));
        }
        return Result.success(body);
    }
}
  • supports方法: 判断是否要执行beforeBodyWrite方法. true为执行, false不执行. 通过该方法可以选择哪些类或哪些方法的response要进行处理, 其他的不进行处理.
  • beforeBodyWrite方法: 对response方法进行具体操作处理.

添加统一数据返回格式之前:

在这里插入图片描述

添加统一数据返回格式之后:

在这里插入图片描述

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

String问题.(源码分析)

五.统一异常处理

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

  • 代码实现:
@Slf4j
@ControllerAdvice
@ResponseBody
//如果不加会认为你返回的是一个视图,这个视图显然不存在,就会出现404的错误
public class ExceptionAdvice {
    @ExceptionHandler(value = Exception.class)
    public Result handleException(Exception e) {
        log.error("发生异常, e : "+ e);
        return Result.fail("内部错误");
    }
    @ExceptionHandler()
    public Result handleException(NullPointerException e) {
        log.error("发生空指针异常, e : "+ e);
        return Result.fail("内部错误");
    }
    @ExceptionHandler(ArithmeticException.class)
    public Result handleException(ArithmeticException e) {
        log.error("发生算术异常, e : "+ e);
        return Result.fail("内部错误");
    }
}

模拟制造异常:

@RequestMapping("/test")
@RestController
public class TestController {
    @RequestMapping("/t1")
    public String t1(){
        int result = 10/0;
        return "string";
    }

    @RequestMapping("/t2")
    public Integer t2(){
        String str = null;
        System.out.println(str.length());
        return 1;
    }

    @RequestMapping("/t3")
    public Boolean t3(){
        Integer[] integers = new Integer[]{1,2,3,4};
        System.out.println(integers[5]);
        return true;
    }

}
  • 当有多个异常通知时,匹配顺序为当前类及其子类向上依次匹配/test/t2 抛出ArithmeticException, 运行结果如下:
    在这里插入图片描述
  • /test/t3 抛出NullPointerException, 运行结果如下:
    在这里插入图片描述

@ControllerAdvice 源码分析

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

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

相关文章

Flutter 像素编辑器#05 | 缩放与平移

theme: cyanosis 本系列&#xff0c;将通过 Flutter 实现一个全平台的像素编辑器应用。源码见开源项目 【pix_editor】。在前三篇中&#xff0c;我们已经完成了一个简易的图像编辑器&#xff0c;并且简单引入了图层的概念&#xff0c;支持切换图层显示不同的像素画面。 《Flutt…

Web服务器与Apache(LAMP架构+搭建论坛)

一、Web基础 1.HTML概述 HTML&#xff08;Hypertext Markup Language&#xff09;是一种标记语音,用于创建和组织Web页面的结构和内容&#xff0c;HTML是构建Web页面的基础&#xff0c;定义了页面的结构和内容&#xff0c;通过标记和元素来实现 2.HTML文件结构 <html>…

抖音电商618国货数据:洗护、服饰等受欢迎,活力28环比增长40%

发布 | 大力财经 6月21日&#xff0c;抖音电商发布“抖音商城618好物节”消费数据报告&#xff08;下称“报告”&#xff09;&#xff0c;披露618期间平台全域经营情况及大众消费趋势&#xff0c;其中国货表现亮眼。 本次大促恰逢传统节日端午节&#xff0c;报告显示&#xf…

实验08 软件设计模式及应用

目录 实验目的实验内容一、能播放各种声音的软件产品Sound.javaDog.javaViolin.javaSimulator.javaApplication.java运行结果 二、简单工厂模式--女娲造人。Human.javaWhiteHuman.javaYellowHuman.javaBlackHuman.javaHumanFactory.javaNvWa.java运行结果 三、工厂方法模式--女…

React 扩展

文章目录 PureComponent1. 使用 React.Component&#xff0c;不会进行浅比较2. 使用 shouldComponentUpdate 生命周期钩子&#xff0c;手动比较3. 使用 React.PureComponent&#xff0c;自动进行浅比较 Render Props1. 使用 Children props&#xff08;通过组件标签体传入结构&…

nginx负载均衡案例,缓存知识----补充

负载均衡案例 ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near great all on wordpress.* to wp172.16.1.% indentified by 1 at line 1 MariaDB [(none)]>…

iptables(5)常用扩展模块iprange、string、time、connlimit、limit

简介 之前我们已经介绍过扩展模块的简单使用,比如使用-m tcp/udp ,-m multiport参数通过--dports,--sports可以设置连续和非连续的端口范围。那么我们如何匹配其他的一些参数呢,比如源地址范围,目的地址范围,时间范围等,这就是我们这篇文章介绍的内容。 iprange扩展模块…

Jmeter插件管理器,websocket协议,Jmeter连接数据库,测试报告的查看

目录 1、Jmeter插件管理器 1、Jmeter插件管理器用处&#xff1a;Jmeter发展并产生大量优秀的插件&#xff0c;比如取样器、性能监控的插件工具等。但要安装这些优秀的插件&#xff0c;需要先安装插件管理器。 2、插件的下载&#xff0c;从Availabale Plugins中选择&#xff…

服务器(Linux系统的使用)——自学习梳理

root表示用户名 后是机器的名字 ~表示文件夹&#xff0c;刚上来是默认的用户目录 ls -a 可以显示出隐藏的文件 蓝色的表示文件夹 白色的是文件 ll -a 查看详细信息 total表示所占磁盘总大小 一般以KB为单位 d开头表示文件夹 -代表文件 后面得三组rwx分别对应管理员用户-组…

VSCode创建并运行html页面(使用Live Server插件)

目录 一、参考博客二、安装Live Server插件三、新建html页面3.1 选择文件夹3.2 新建html文件3.3 快速生成html骨架 四、运行html页面 一、参考博客 https://blog.csdn.net/zhuiqiuzhuoyue583/article/details/126610162 https://blog.csdn.net/m0_74014525/article/details/13…

设计模式5-策略模式(Strategy)

设计模式5-策略模式 简介目的定义结构策略模式的结构要点 举例说明1. 策略接口2. 具体策略类3. 上下文类4. 客户端代码 策略模式的反例没有使用策略模式的代码 对比分析 简介 策略模式也是属于组件协作模式一种。现代软件专业分工之后的第一个结果是框架语音应用程序的划分。组…

MATLAB-振动问题:单自由度无阻尼振动系统受迫振动

一、基本理论 二、MATLAB实现 令式&#xff08;1.3&#xff09;中A0 2&#xff0c;omega0 30&#xff0c;omega 40&#xff0c;matlab程序如下&#xff1a; clear; clc; close all;A0 2; omega0 30; omega 40; t 0:0.02:5; y A0 * sin( (omega0 - omega) * t /2) .* s…

【源码+文档+调试讲解】牙科就诊管理系统

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本牙科就诊管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

计算机网络 访问控制列表以及NAT

一、理论知识 1. 单臂路由 单臂路由是一种在路由器上配置多个子接口的方法&#xff0c;每个子接口代表不同的 VLAN&#xff0c;用于在一个物理接口上支持多 VLAN 通信。此方法使得不同 VLAN 之间可以通过路由器进行通信。 2. NAT (网络地址转换) NAT 是一种在私有网络和公共…

vue+three.js渲染3D模型

安装three.js: npm install three 页面部分代码&#xff1a; <div style"width: 100%; height: 300px; position: relative;"><div style"height: 200px; background-color: white; width: 100%; position: absolute; top: 0;"><div id&…

小阿轩yx-MySQL数据库管理

小阿轩yx-MySQL数据库管理 使用 MySQL 数据库 在服务器运维工作中不可或缺的 SQL &#xff08;结构化查询语句&#xff09;的四种类型 数据定义语言&#xff08;DDL&#xff09;&#xff1a;DROP&#xff08;删除&#xff09;、CREATE&#xff08;创建&#xff09;、ALTER&…

帝国cms定时审核并更新的方法

比如你网站采集了成千上万篇文章&#xff0c;不可能一下子全部放出来的&#xff0c;所以为了模拟人工发布&#xff0c;那么就需要定时审核发布文章内容&#xff0c;本文内容核心解决了更加个性化的逼真模拟人工更新网站内容。 第一&#xff1a;首先要满足你的表中有未审核的数据…

JavaWeb——MySQL:DML

目录 DML&#xff1a;添加&#xff0c;修改&#xff0c;删除表的数据&#xff1b; 1. 添加表的数据 1.1 给所有列添加数据 1.2 给指定列添加数据 1.3 批量添加信息 总结&#xff1a; DML&#xff1a;添加&#xff0c;修改&#xff0c;删除表的数据&#xff1b; 1. 添加表的…

cube-studio开源一站式机器学习平台,在线ide,jupyter,vscode,matlab,rstudio,ssh远程连接,tensorboard

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; 一站式云原生机器学习平台 前言 开源地址&#xff1a;https://github.com/tencentmusic/cube-studio cube studio 腾讯开源的国内最热门的一站式机器学习mlops/大模型训练平台&#xff0c;支持多租户&…

微博默认按照最新时间排序

微博默认按照最新时间排序 目前微博会默认按照推荐顺序排序&#xff0c;如果你想要默认按照时间顺序排序的话&#xff0c;可以使用这个油猴脚本。 演示&#xff1a; 脚本安装地址 源代码地址 参考 本项目基于 vite-plugin-monkey 开发 菜单切换&#xff08;useOption&…