商城类网站建设方案,免费百度seo引流,品牌设计 品牌标志设计,个人主页免费网站文章目录 前言1. 拦截器1.1 什么是拦截器1.2 拦截器的使用1.2.1 自定义拦截器1.2.2 注册配置拦截器 1.3 拦截器详解1.3.1 拦截路径1.3.2 拦截器执行流程1.3.3 适配器模式 2. 统一数据返回格式3. 统一异常处理 前言
在日常使用 Spring 框架进行开发的时候#xff0c;对于一些板… 文章目录 前言1. 拦截器1.1 什么是拦截器1.2 拦截器的使用1.2.1 自定义拦截器1.2.2 注册配置拦截器 1.3 拦截器详解1.3.1 拦截路径1.3.2 拦截器执行流程1.3.3 适配器模式 2. 统一数据返回格式3. 统一异常处理 前言
在日常使用 Spring 框架进行开发的时候对于一些板块来说可能需要实现一个相同的功能这个功能可以是验证你的登录信息也可以是其他的但是由于各个板块实现这个功能的代码逻辑都是相同的如果一个板块一个板块进行添加的话开发效率就会很低所以 Spring 也想到了这点为我们程序员提供了 SpringBoot 统一功能处理的方法实现我们是可以直接使用的。这篇文章我将带大家一起学习 SpringBoot 统一功能的处理。
1. 拦截器
正常的判断用户是否登录的逻辑就是通过 session 来判断对于一些网站来说很多的功能都是需要用户进行登录之后才可以使用的如果此时通过 session 判断出来用户处于未登录状态的话咱们的服务器会强制用户进行登录通过代码来显示就是这样的
//检验用户是否登录
HttpSession session request.getSession(false);
if (session null || session.getAttribute(userInfo) null) {return 您未登录请登录后再试试该功能吧;
}我们想要在哪个功能前判断用户的登录信息就需要在该功能的模块中添加上面这些代码如果需要添加的功能较少还好如果很多那么就需要花费很多的时间那么有人就说了我是否可以将这些代码封装成函数然后哪个模块需要使用只需要调用这些函数就可以了呢可以是可以但是使用函数封装代码还是需要在原代码的基础上调用这个函数并且显得也不是那么优雅。那么是否有方法既不需要更改原代码也可以使得我们写的代码很优雅呢SpringBoot 为我们提供了一种功能——拦截器。
1.1 什么是拦截器
在 Spring Boot 中拦截器是一种用于在处理请求之前或之后执行特定操作的组件。拦截器通常用于实现一些通用的功能比如权限验证、日志记录等。拦截器可以拦截通过Controller的请求并在请求处理前后执行特定的操作。
拦截器的思想正好符合我们执行其他功能之前进行身份验证验证并且不仅在方法执行之前拦截器可以起作用方法执行之后。我们的拦截器也可以起到作用。 1.2 拦截器的使用
拦截器的使用分为两个步骤
定义拦截器注册配置拦截器
1.2.1 自定义拦截器
我们自定义的拦截器需要实现 HandlerInterceptor 接口并且重写这个接口中的方法。
package com.example.springbootbook2.interceptor;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;Component
Slf4j
public class LoginInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {log.info(目标方法执行前执行...);HttpSession session request.getSession(false);if (session null || session.getAttribute(userInfo) null) {response.setStatus(401);return false;}return true;}Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info(目标方法执行后执行...);}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info(视图渲染完毕之后执行最后执行...);}
}
preHandle() 方法是在目标方法执行之前执行的返回 true继续执行后面的代码返回 false中断后续的操作postHandle() 方法是在目标方法执行之后执行的afterCompletion() 方法是在视图渲染之后才执行的它还在 postHandle() 方法之后执行并且现在因为前后端分离我们后端基本上接触不到视图的渲染所以这个方法使用的较少
1.2.2 注册配置拦截器
注册配置拦截器需要实现 WebMvcConfiguer 接口并实现 addInterceptors 方法。
package com.example.springbootbook2.config;import com.example.springbootbook2.interceptor.LoginInterceptor;
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 {Autowiredprivate LoginInterceptor loginInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**) //指定路径配置拦截器.excludePathPatterns(/user/login); //指定路径不配置拦截器}
}在添加拦截器进行身份校验之前我们可以直接通过对应的 url 访问到指定功能页面。 而在我们添加拦截器之后再看是否能直接访问某些功能。 我们启动添加了拦截器之后的代码之后点击刷新就发现不能够直接访问到某些功能了再搭配着前端我们就可以实现强制登录的功能了。
1.3 拦截器详解
拦截器的⼊⻔程序完成之后接下来我们来介绍拦截器的使⽤细节。拦截器的使⽤细节我们主要介绍两个部分
拦截器的拦截路径配置拦截器实现原理
1.3.1 拦截路径
拦截路径是指我们定义的这个拦截器对哪些请求生效我们在注册配置拦截器的时候通过 addPathPatterns() 方法指定要拦截哪些 HTTP 请求也可以通过 excludePathPatterns() 方法指定不拦截哪些请求上面我们的 /** 表示拦截所有的 HTTP 请求除了可以设置拦截所有请求外还有一些其他的拦截设置
拦截路径含义举例/*⼀级路径能匹配/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 等⽂件)。
知道了如何配置拦截路径之后我们就可以解决网页上身份验证的问题了。因为 /** 会拦截所有的请求包括前端页面请求所以我们需要将前端页面请求排除在拦截之外。
如果我们不讲前端页面请求在外的话机会出现这种情况 然后我们将前端页面请求不添加拦截器的话就可以实现完整的身份校验强制登录功能了。
Configuration
public class WebConfig implements WebMvcConfigurer {Autowiredprivate LoginInterceptor loginInterceptor;private ListString excludePath Arrays.asList(/user/login,/css/**,/js/**,/pic/**,/**/*.html); // /**/*html中的/**表示所有路径下的所有以html结尾的文件 * 表示通配符Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**).excludePathPatterns(excludePath);}
}
当我们未登录然后访问其他功能的话就会强制跳转到登录页面 1.3.2 拦截器执行流程
正常的调用顺序是这样的 有了拦截器之后会在调⽤ Controller 之前进⾏相应的业务处理执⾏的流程如下图 当我们添加拦截器之后在执行 Controller 方法之前请求会先被拦截器拦截执行 preHandle() 方法这个方法会返回一个布尔类型的值如果返回的是 true那么会继续执行后面的操作如果返回的是 false则不会执行后面的操作Controller 当中的方法执行完毕之后会继续执行 postHandle() 方法以及 afterHandle() 方法执行完毕之后返回给浏览器响应数据。
在源码中的 DispatcherServlet 类中的 doDispatch 方法中可以看到这三个方法的执行流程 1.3.3 适配器模式
在拦截器执行的过程中还使用了适配器模式 适配器模式Adapter Pattern在计算机编程中是一种常用的设计模式主要用于解决两个不兼容的类之间的接口匹配问题。通过将一个类的接口转换成客户端所期望的另一种接口原本因为接口不匹配而无法一起工作的两个类现在可以一起工作。
适配器模式的优点在于它能够使原本由于接口不兼容而无法一起工作的类一起工作提高了系统的灵活性和可扩展性。同时它也能够减少代码的重复性因为多个源可以共享同一个适配器。
HandlerAdapter 主要⽤于⽀持不同类型的处理器如 Controller、HttpRequestHandler 或者 Servlet 等让它们能够适配统⼀的请求处理流程。这样SpringMVC可以通过⼀个统⼀的接⼝ 来处理来⾃各种处理器的请求。 本来 target 和 adaptee 是两个无法正常对接的事物但是通过适配器 adapter这两者之间就可以进行对接也就类似于下面这个情况 适配器模式⻆⾊
Target⽬标接口可以是抽象类或接口客户希望直接⽤的接口Adaptee适配者但是与Target不兼容Adapter适配器类此模式的核⼼。通过继承或者引⽤适配者的对象把适配者转为⽬标接⼝client需要使⽤适配器的对象
前⾯学习的 slf4j 就使⽤了适配器模式slf4j 提供了⼀系列打印⽇志的 api底层调⽤的是 log4j 或者logback 来打⽇志我们作为调⽤者只需要调⽤ slf4j 的 api 就⾏了。
/**
* slf4j接⼝
*/
interface Slf4jApi{void log(String message);
}/**
* log4j 接⼝
*/
class Log4j{void log4jLog(String message){System.out.println(Log4j打印:message);}
}/**
* slf4j和log4j适配器
*/
class Slf4jLog4JAdapter implements Slf4jApi{private Log4j log4j;public Slf4jLog4JAdapter(Log4j log4j) {this.log4j log4j;}Overridepublic void log(String message) {log4j.log4jLog(message);}
}/**
* 客⼾端调⽤
*/
public class Slf4jDemo {public static void main(String[] args) {Slf4jApi slf4jApi new Slf4jLog4JAdapter(new Log4j());slf4jApi.log(使⽤slf4j打印⽇志);}
}可以看出我们不需要改变 log4j 的api只需要通过适配器转换下就可以更换⽇志框架保障系统的平稳运行。
⼀般来说适配器模式可以看作⼀种补偿模式⽤来补救设计上的缺陷。应⽤这种模式算是⽆奈之举如果在设计初期我们就能协调规避接⼝不兼容的问题就不需要使⽤适配器模式了。
所以适配器模式更多的应⽤场景主要是对正在运⾏的代码进⾏改造并且希望可以复⽤原有代码实现新的功能.。⽐如版本升级等。
2. 统一数据返回格式
如果我们完成了一个项目的开发但是这时候我们突然觉得后端的各个功能的返回值返回的信息不够全面我们需要补充一些返回信息那么这时候就意味着所有方法的返回值都需要做出修改这也是一个不小的工作量。这时 SpringBot 又为我们提供了解决方法——统一数据返回格式。
SpringBoot 统一数据返回格式会在各个方法进行 return 返回值之前插入一些代码逻辑从而达到改变返回值的功能。
统一的数据返回格式使用 ControllerAdvice 和 ResponseBodyAdvice 的方式实现。ControllerAdvice 表示控制器通知类。
我们先定义一个统一的返回类型
public enum ResultCode {SUCCESS(0),FAIL(-1),UNLOGIN(-2);//0-成功 -1 失败 -2 未登录private int code;ResultCode(int code) {this.code code;}public int getCode() {return code;}public void setCode(int code) {this.code code;}
}Data
public class ResultT {/*** 业务状态码*/private ResultCode code; //0-成功 -1 失败 -2 未登录/*** 错误信息*/private String errMsg;/*** 数据*/private T data;public static T ResultT success(T data){Result result new Result();result.setCode(ResultCode.SUCCESS);result.setErrMsg();result.setData(data);return result;}public static T ResultT fail(String errMsg){Result result new Result();result.setCode(ResultCode.FAIL);result.setErrMsg(errMsg);result.setData(null);return result;}public static T ResultT fail(String errMsg,Object data){Result result new Result();result.setCode(ResultCode.FAIL);result.setErrMsg(errMsg);result.setData(data);return result;}public static T ResultT unlogin(){Result result new Result();result.setCode(ResultCode.UNLOGIN);result.setErrMsg(用户未登录);result.setData(null);return result;}}package com.example.springbootbook2.config;import com.example.springbootbook2.model.Result;
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;ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {return Result.success(body);}
}继承 ResponseBodyAdvice 接口后需要实现该接口下的 supports 方法和 beforeBodyWrite 方法supports 方法只需要更改返回值为 true 就可以了表示是否要执行 beforeBodyWrite 方法返回 true 表示执行false 表示不执行beforeBodyWrite 方法中的 body 参数就是我们原方法的返回值。
当我们关闭拦截器访问图书列表页之后就发现我们的返回类型发生了变化 但是这个统一数据返回格式也存在问题当我们的返回值为 String 类型的话机会出现错误 这是为什么呢SpringMVC默认会注册⼀些⾃带的 HttpMessageConverter (从先后顺序排列分别为 ByteArrayHttpMessageConverter StringHttpMessageConverter , SourceHttpMessageConverter AllEncompassingFormHttpMessageConverter ) 其中 AllEncompassingFormHttpMessageConverter 会根据项⽬依赖情况添加对应的 HttpMessageConverter 在依赖中引⼊jackson包后容器会把 MappingJackson2HttpMessageConverter ⾃动注册到 messageConverters 链的末尾。Spring会根据返回的数据类型从 messageConverters 链选择合适的 HttpMessageConverter。当返回的数据是⾮字符串时使⽤的MappingJackson2HttpMessageConverter 写⼊返回对象。当返回的数据是字符串时 StringHttpMessageConverter 会先被遍历到这时会认为 StringHttpMessageConverter 可以使用。 然⽽⼦类 StringHttpMessageConverter 的addDefaultHeaders⽅法定义接收参数为String此 时t为Result类型所以出现类型不匹配Result cannot be cast to java.lang.String的异常。
那么如何解决返回类型为 String 类型的问题呢如果返回结果为String类型, 使⽤SpringBoot内置提供的Jackson来实现信息的序列化。
ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {Autowiredprivate ObjectMapper objectMapper;Overridepublic boolean supports(MethodParameter returnType, Class converterType) {return true;}SneakyThrowsOverridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (body instanceof String) {return objectMapper.writeValueAsString(Result.success(body));}else if (body instanceof Result) {return body;}else {return Result.success(body);}}
}SneakyThrows 的主要目的是解决 Java 的异常处理问题。当我们在代码中抛出一个异常时如果这个异常被包裹在一个方法中并且这个方法没有 throws 关键字来声明会抛出这个异常那么编译器会报错。通过使用 SneakyThrows你可以告诉编译器“我知道这个方法可能会抛出异常但我保证在 catch 块中处理它。” 这样编译器就不会报错了。
通过这个处理当返回的数据类型为 String 的时候就不会出现错误了。 统一数据返回格式的优点
⽅便前端程序员更好的接收和解析后端数据接口返回的数据降低前端程序员和后端程序员的沟通成本按照某个格式实现就可以了因为所有接口都是这样返回的有利于项目统⼀数据的维护和修改有利于后端技术部⻔的统⼀规范的标准制定不会出现稀奇古怪的返回内容
3. 统一异常处理
当我们的程序中出现异常的时候我们需要解决这些异常因为前面做了统一数据返回格式的处理所以这里的异常也可以进行统一的处理。
统⼀异常处理使⽤的是 ControllerAdvice ExceptionHandler 来实现的ControllerAdvice 表⽰控制器通知类 ExceptionHandler 是异常处理器两个结合表示当出现异常的时候执行某个通知也就是执⾏某个⽅法事件。
package com.example.springbootbook2.config;import com.example.springbootbook2.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;ControllerAdvice
Slf4j
ResponseBody //因为返回的数据都不是视图类型所以加上这个注解防止出现问题
public class ErrorHandler {ExceptionHandlerpublic ResultString exception(Exception e) {log.error(发生异常:e{},e);return Result.fail(内部异常);}ExceptionHandlerpublic ResultString exception(NullPointerException e) {log.error(发生异常:e{},e);return Result.fail(NullPointerException异常请联系管理员);}ExceptionHandlerpublic ResultString exception(ArithmeticException e) {log.error(发生异常:e{},e);return Result.fail(ArithmeticException异常请联系管理员);}
}
Controller
RequestMapping(/test)
public class TestController {RequestMapping(/t1)public Integer test1() {return 10/0;}
}这个 Exception 和 ArithmeticException 的先后顺序可以不考虑这个不会因为 Exception 在前面捕获就报的 Exception 异常而是会根据自己出现的最接近的异常来捕获。 文章转载自: http://www.morning.nhrkl.cn.gov.cn.nhrkl.cn http://www.morning.zpyxl.cn.gov.cn.zpyxl.cn http://www.morning.czxrg.cn.gov.cn.czxrg.cn http://www.morning.jgcrr.cn.gov.cn.jgcrr.cn http://www.morning.wdykx.cn.gov.cn.wdykx.cn http://www.morning.lxfdh.cn.gov.cn.lxfdh.cn http://www.morning.slmbg.cn.gov.cn.slmbg.cn http://www.morning.jjtwh.cn.gov.cn.jjtwh.cn http://www.morning.cxsdl.cn.gov.cn.cxsdl.cn http://www.morning.mfcbk.cn.gov.cn.mfcbk.cn http://www.morning.jfnbh.cn.gov.cn.jfnbh.cn http://www.morning.phwmj.cn.gov.cn.phwmj.cn http://www.morning.ggmls.cn.gov.cn.ggmls.cn http://www.morning.lmmyl.cn.gov.cn.lmmyl.cn http://www.morning.tqxtx.cn.gov.cn.tqxtx.cn http://www.morning.zbhfs.cn.gov.cn.zbhfs.cn http://www.morning.lbssg.cn.gov.cn.lbssg.cn http://www.morning.kstgt.cn.gov.cn.kstgt.cn http://www.morning.sacxbs.cn.gov.cn.sacxbs.cn http://www.morning.nftzn.cn.gov.cn.nftzn.cn http://www.morning.rxtxf.cn.gov.cn.rxtxf.cn http://www.morning.elsemon.com.gov.cn.elsemon.com http://www.morning.tdgwg.cn.gov.cn.tdgwg.cn http://www.morning.tqfnf.cn.gov.cn.tqfnf.cn http://www.morning.kpzbf.cn.gov.cn.kpzbf.cn http://www.morning.txmkx.cn.gov.cn.txmkx.cn http://www.morning.qhydkj.com.gov.cn.qhydkj.com http://www.morning.xgchm.cn.gov.cn.xgchm.cn http://www.morning.bmyrl.cn.gov.cn.bmyrl.cn http://www.morning.gwsfq.cn.gov.cn.gwsfq.cn http://www.morning.iuibhkd.cn.gov.cn.iuibhkd.cn http://www.morning.hmwjk.cn.gov.cn.hmwjk.cn http://www.morning.rlwcs.cn.gov.cn.rlwcs.cn http://www.morning.jyzxt.cn.gov.cn.jyzxt.cn http://www.morning.qtyfb.cn.gov.cn.qtyfb.cn http://www.morning.mkyny.cn.gov.cn.mkyny.cn http://www.morning.qwpdl.cn.gov.cn.qwpdl.cn http://www.morning.xnltz.cn.gov.cn.xnltz.cn http://www.morning.nlryq.cn.gov.cn.nlryq.cn http://www.morning.fglyb.cn.gov.cn.fglyb.cn http://www.morning.dxzcr.cn.gov.cn.dxzcr.cn http://www.morning.kgxyd.cn.gov.cn.kgxyd.cn http://www.morning.cbpkr.cn.gov.cn.cbpkr.cn http://www.morning.wmqrn.cn.gov.cn.wmqrn.cn http://www.morning.rjjjk.cn.gov.cn.rjjjk.cn http://www.morning.yqjjn.cn.gov.cn.yqjjn.cn http://www.morning.mftdq.cn.gov.cn.mftdq.cn http://www.morning.xlxmy.cn.gov.cn.xlxmy.cn http://www.morning.frpm.cn.gov.cn.frpm.cn http://www.morning.dqgbx.cn.gov.cn.dqgbx.cn http://www.morning.qxwrd.cn.gov.cn.qxwrd.cn http://www.morning.kxgn.cn.gov.cn.kxgn.cn http://www.morning.clwhf.cn.gov.cn.clwhf.cn http://www.morning.xfncq.cn.gov.cn.xfncq.cn http://www.morning.bqts.cn.gov.cn.bqts.cn http://www.morning.rfjmy.cn.gov.cn.rfjmy.cn http://www.morning.kflzy.cn.gov.cn.kflzy.cn http://www.morning.srxhd.cn.gov.cn.srxhd.cn http://www.morning.httpm.cn.gov.cn.httpm.cn http://www.morning.prgnp.cn.gov.cn.prgnp.cn http://www.morning.kxwsn.cn.gov.cn.kxwsn.cn http://www.morning.trtxt.cn.gov.cn.trtxt.cn http://www.morning.easiuse.com.gov.cn.easiuse.com http://www.morning.jbxfm.cn.gov.cn.jbxfm.cn http://www.morning.dhrbj.cn.gov.cn.dhrbj.cn http://www.morning.ktskc.cn.gov.cn.ktskc.cn http://www.morning.qsy38.cn.gov.cn.qsy38.cn http://www.morning.srkwf.cn.gov.cn.srkwf.cn http://www.morning.xjkr.cn.gov.cn.xjkr.cn http://www.morning.rcrnw.cn.gov.cn.rcrnw.cn http://www.morning.kybyf.cn.gov.cn.kybyf.cn http://www.morning.bpmtz.cn.gov.cn.bpmtz.cn http://www.morning.nlbhj.cn.gov.cn.nlbhj.cn http://www.morning.gbljq.cn.gov.cn.gbljq.cn http://www.morning.dgwrz.cn.gov.cn.dgwrz.cn http://www.morning.mnyzz.cn.gov.cn.mnyzz.cn http://www.morning.hdrrk.cn.gov.cn.hdrrk.cn http://www.morning.kaylyea.com.gov.cn.kaylyea.com http://www.morning.qbwyd.cn.gov.cn.qbwyd.cn http://www.morning.prgnp.cn.gov.cn.prgnp.cn