3. 内容模块管理 - 异常处理与校验

文章目录

  • 内容模块管理
  • 一、自定义异常
    • 1.1 全局异常处理器
    • 1.2 自定义异常
    • 1.3 异常统一响应类
    • 1.4 封装通用异常信息
  • 二、JSR303校验
    • 2.1 Maven坐标
    • 2.2 校验规则
    • 2.3 代码示例
    • 2.4 捕捉校验异常
    • 2.5 分组校验
    • 2.6 备注
  • 三、全局异常处理2
    • 3.1 全局异常处理器
    • 3.2 结果集
    • 3.3 常用注解
      • 3.3.1 @ControllerAdvice
      • 3.3.2 @ExceptionHandle

内容模块管理

一、自定义异常

之前也学过对异常的统一管理,既然现在又看到了,就再学学springboot——全局异常处理器及封装结果集

如果一致对异常进行try…catch…,代码也会很冗余,我们直接throw就行,然后可以对异常进行统一处理

不论是那一层,都会有异常的出现,我们遇到异常都是向上抛出,最后让框架对异常统一处理

假如dao出异常就会抛给service,service有异常就会抛给controller,controller会抛给spring框架

image-20231115212256176

1.1 全局异常处理器

  • @ExceptionHandler

    提供的标识在方法上或类上的注解,用来表明方法的处理异常类型

  • @ControllerAdvice

    控制器增强,在项目中来增强SpringMVC中的Controller。通常和@ExceptionHandler结合使用,来处理SpringMVC的异常信息。

  • @ResponseStatus

    提供的标识在方法上或类上的注解,用状态代码和应返回的原因标记方法或异常类。

    调用处理程序方法时,状态代码将应用于HTTP响应

/*** 统一异常处理类*/
@Slf4j
@ControllerAdvice
@ResponseBody//返回JSON数据
//@RestControllerAdvice = @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {/*** 针对自定义异常进行处理的*/@ResponseBody@ExceptionHandler(XueChengPlusException.class)//捕捉这个异常@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//状态码500public RestErrorResponse customException(XueChengPlusException e) {
//      捕捉到异常的信息后解析异常的信息log.error("【系统异常】{}", e.getErrMessage(), e);return new RestErrorResponse(e.getErrMessage());}/*** 捕捉除了自定义异常以外的其他异常*/@ResponseBody@ExceptionHandler(Exception.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//状态码500public RestErrorResponse exception(Exception e) {log.error("【系统异常】{}", e.getMessage(), e);return new RestErrorResponse(CommonError.UNKOWN_ERROR.getErrMessage());//执行过程异常,请重试}}

1.2 自定义异常

@EqualsAndHashCode(callSuper = true)
@Data
public class XueChengPlusException extends RuntimeException {private static final long serialVersionUID = -378480393877627738L;private String errMessage;public XueChengPlusException() {super();}public XueChengPlusException(String errMessage) {super(errMessage);this.errMessage = errMessage;}public static void cast(CommonError commonError) {throw new XueChengPlusException(commonError.getErrMessage());}public static void cast(String errMessage) {throw new XueChengPlusException(errMessage);}}

1.3 异常统一响应类

/*** 和前端约定返回的异常信息模型* 错误响应参数包装*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RestErrorResponse implements Serializable {private static final long serialVersionUID = 9026504397012666687L;private String errMessage;}

1.4 封装通用异常信息

/*** 通用异常信息*/
public enum CommonError {UNKOWN_ERROR("执行过程异常,请重试。"),PARAMS_ERROR("非法参数"),OBJECT_NULL("对象为空"),QUERY_NULL("查询结果为空"),REQUEST_NULL("请求参数为空");private String errMessage;public String getErrMessage() {return errMessage;}private CommonError( String errMessage) {this.errMessage = errMessage;}}

二、JSR303校验

SpringBoot提供了JSR-303的支持,它就是spring-boot-starter-validation,它的底层使用Hibernate Validator,Hibernate Validator是Bean Validation 的参考实现。

所以,我们准备在Controller层使用spring-boot-starter-validation完成对请求参数的基本合法性进行校验。

  • 前端请求后端接口传输参数,是在controller中校验还是在Service中校验

    答案是都需要校验,只是分工不同。因为某些Service不仅仅被一个Controller调用,如果Service中不写校验再被其他Controller或其他Service调用时也会发生问题

  • Controller里一般校验什么

    Contoller中校验请求参数的合法性,包括:必填项校验,数据格式校验,比如:是否是符合一定的日期格式,等。

  • Service里一般校验什么

    Service中要校验的是业务规则相关的内容,比如:课程已经审核通过所以提交失败。

    Service中根据业务规则去校验不方便写成通用代码,Controller中则可以将校验的代码写成通用代码

2.1 Maven坐标

首先在Base工程添加spring-boot-starter-validation的依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

在javax.validation.constraints包下有很多这样的校验注解,直接使用注解定义校验规则即可

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2 校验规则

image-20231115224419263

2.3 代码示例

现在准备对内容管理模块添加课程接口进行参数校验,如下接口

定义好校验规则还需要开启校验,在controller方法中添加@Validated注解,否则校验不会生效

    @ApiOperation("新增课程")@PostMapping("/course")public CourseBaseInfoDto createCourseBase(@Validated @RequestBody AddCourseDto addCourseDto) {
//      将来会集成SpringSecurity框架,用户登录之后就可以获取到用户所属机构的ID
//      先把机构ID写死return courseBaseInfoService.createCourseBase(10086L,addCourseDto);}

进入AddCourseDto类,在属性上添加校验规则

@NotEmpty表示属性不能为空

@Size表示限制属性内容的长短

/*** @description 添加课程dto*/
@Data
@ApiModel(value = "AddCourseDto", description = "新增课程基本信息")
public class AddCourseDto {@NotEmpty(message = "课程名称不能为空")@ApiModelProperty(value = "课程名称", required = true)private String name;@NotEmpty(message = "适用人群不能为空")@Size(message = "适用人群内容过少", min = 10)@ApiModelProperty(value = "适用人群", required = true)private String users;@ApiModelProperty(value = "课程标签")private String tags;@NotEmpty(message = "课程分类不能为空")@ApiModelProperty(value = "大分类", required = true)private String mt;@NotEmpty(message = "课程分类不能为空")@ApiModelProperty(value = "小分类", required = true)private String st;@NotEmpty(message = "课程等级不能为空")@ApiModelProperty(value = "课程等级", required = true)private String grade;@ApiModelProperty(value = "教学模式(普通,录播,直播等)", required = true)private String teachmode;@ApiModelProperty(value = "课程介绍")private String description;@ApiModelProperty(value = "课程图片", required = true)private String pic;@NotEmpty(message = "收费规则不能为空")@ApiModelProperty(value = "收费规则,对应数据字典", required = true)private String charge;@ApiModelProperty(value = "价格")private Float price;@ApiModelProperty(value = "原价")private Float originalPrice;@ApiModelProperty(value = "qq")private String qq;@ApiModelProperty(value = "微信")private String wechat;@ApiModelProperty(value = "电话")private String phone;@ApiModelProperty(value = "有效期")private Integer validDays;
}

2.4 捕捉校验异常

该异常表示在方法参数验证失败时抛出,其中验证失败的详细信息可以通过 BindingResult 对象获取

getBindingResult() 方法是 MethodArgumentNotValidException 类的一个方法,用于获取包含验证错误详细信息的 BindingResult 对象。BindingResult 包含了验证结果,包括错误对象、错误代码、默认错误消息等。

    @ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public RestErrorResponse methodArgumentNotValidException(MethodArgumentNotValidException e) {
//      这个异常对象有一个方法getBindingResultBindingResult bindingResult = e.getBindingResult();List<String> msgList = new ArrayList<>();//将错误信息放在msgList//因为校验的时候可能多个字段都会出现问题,所以使用了一个list集合存放有问题的消息,我们后面会将他们一块拼接起来的bindingResult.getFieldErrors().stream().forEach(item -> msgList.add(item.getDefaultMessage()));//拼接错误信息String msg = StringUtils.join(msgList, ",");log.error("【系统异常】{}", msg);return new RestErrorResponse(msg);}

比如下面的这一次请求中就是两个字段不合格,都会放到List集合中,最后由StringUtils.join将其拼接起来

image-20231115231654132

2.5 分组校验

假如修改课程的Dto和增加课程的Dto是一个样子的,但是校验规则不一样,怎么办呢

方法1:定义两个Dto来分别校验

方法2:分组校验

分组校验:将Dto中的校验规则分组,新增课程使用一个检验规则组,修改课程使用一个校验规则组,但是都还是同一个Dto

定义分组

/*** 用于分组校验,定义一些常用的组*/
public class ValidationGroups {public interface Insert{};public interface Update{};public interface Delete{};}

划分组别

//    @NotEmpty(message = "课程名称不能为空")
//  这个地方就说明了下面@NotEmpty校验属于ValidationGroups.Insert.class组别@NotEmpty(message = "新增课程名称不能为空",groups = {ValidationGroups.Insert.class})
//  这个地方就说明了下面@NotEmpty校验属于ValidationGroups.Update.class组别@NotEmpty(message = "修改课程名称不能为空",groups = {ValidationGroups.Update.class})@ApiModelProperty(value = "课程名称", required = true)private String name;

此时Controller中也需要修改

    @ApiOperation("新增课程")@PostMapping("/course")public CourseBaseInfoDto createCourseBase(@Validated(ValidationGroups.Insert.class) @RequestBody AddCourseDto addCourseDto) {
//      将来会集成SpringSecurity框架,用户登录之后就可以获取到用户所属机构的ID
//      先把机构ID写死return courseBaseInfoService.createCourseBase(10086L,addCourseDto);}

image-20231115232957202

假如说是修改的话,如下所示

 public CourseBaseInfoDto  updateCourseBase(@Validated(ValidationGroups.Update.class) @RequestBody AddCourseDto addCourseDto) {...
}

2.6 备注

如果javax.validation.constraints包下的校验规则满足不了需求怎么办?

1、手写校验代码 。

2、自定义校验规则注解。

三、全局异常处理2

上面的异常处理是在看学成在线的时候做的笔记,但是怎么看怎么别扭,特别是封装的响应结果集,很别扭,然后就再整理一份

系统如何处理异常

  1. 我们自定义一个统一的异常处理器去捕获并处理异常

  2. 使用控制器增加注解@ControllerAdvice和异常处理注解@ExceptionHandler来实现

  3. 处理自定义异常

    程序在编写代码时根据校验结果主动抛出自定义异常类对象,抛出异常时指定详细的异常信息,异常处理器捕获异常信息记录异常日志并响应给用户

  4. 处理自定义异常

    接口执行过程中的一些运行时异常也会由异常处理器统一捕获,记录异常日志,统一响应给用户500错误(状态码由前后端协定)

  5. 在异常处理中还可以针对某个异常类型进行单独处理

3.1 全局异常处理器

/*** 全局异常处理* 底层是通过代理,代理controller,通过AOP把我们的一些方法拦截到,如果有异常,就在这个类统一进行处理* 下面就是只要带有RestController.class, Controller.class,Service.class的注解的类或方法出现异常,我们都会进行统一处理*/
@ControllerAdvice(annotations = {RestController.class, Controller.class, Service.class})  // 通知
@ResponseBody  //我们需要返回JSON数据
@Slf4j
public class GlobalExceptionHandler {//  表示处理SQL异常@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
//      打印日志信息log.error(ex.getMessage());//Duplicate entry 'zhangjingqi' for key 'employee.idx_username'//      在这里也可以判断异常的具体信息,比如:if(ex.getMessage().contains("Duplicate entry")){String[] s = ex.getMessage().split(" ");String username = s[2];String msg =s[2]+"已经存在";return   R.error(msg);}
//      其他情况下可以直接输出return R.error("未知错误:"+ex.getMessage());}
}

3.2 结果集

不论是成功响应还是异常响应,都使用下面这个结果集

/*** 通用返回结果类,服务端响应的数据都会封装成此对象* @param <T>  这个类会接受多种类型,可能是普通对象,可能是数组、集合等等等等,所以我们要将这个加个泛型<T>,表示可以接收任何参数*/
//  为什么不用Object,而用<T>?  如果用object需要强转类型 而T不用
@Data
public class R<T> {private Integer code; //编码:1成功,0和其它数字为失败private String msg; //错误信息private T data; //数据private Map map = new HashMap(); //动态数据//  方法的返回值及参数中的T属于泛型public static <T> R<T> success(T object) {R<T> r = new R<T>();r.data = object;r.code = 1;   //成功return r;}public static <T> R<T> error(String msg) {R r = new R();r.msg = msg;r.code = 0;   //失败return r;}public R<T> add(String key, Object value) {this.map.put(key, value);return this;}}

3.3 常用注解

3.3.1 @ControllerAdvice

SpringMVC 中 @ControllerAdvice 注解的三种使用场景! - 江南一点雨 - 博客园 (cnblogs.com)

  • basePackages/basePackageClasses属性

    指定扫描哪个包

@ControllerAdvice(basePackages = "com.zhangjingqi.controller")
public class GlobalExceptionHandler {// ...
}
  • annotations属性

    指定注解类型,限定只有被特定注解标记的控制器才会受到 @ControllerAdvice 类的影响

@ControllerAdvice(annotations = {RestController.class, Controller.class, Service.class})  // 通知
@ResponseBody  //我们需要返回JSON数据
@Slf4j
public class GlobalExceptionHandler {.......
}
  • assignableTypes属性

    通过指定类类型,限定只有继承自特定类的控制器才会受到 @ControllerAdvice 类的影响

@ControllerAdvice(assignableTypes = MyController.class)
public class GlobalExceptionHandler {// ...
}
  • value

    basePackages 属性类似,用于指定扫描的包。在很多情况下,value 属性可以替代 basePackages

@ControllerAdvice(value = "com.zhangjingqi.controllers")
public class GlobalExceptionHandler {// ...
}
  • useDefaultResponseAdvice

    默认为 true。当设置为 false 时,禁用默认的 ResponseEntityExceptionHandler,这样你就可以完全掌控异常处理的行为

@ControllerAdvice(useDefaultResponseAdvice = false)
public class CustomExceptionHandler {// ...
}

3.3.2 @ExceptionHandle

可以捕获到controller中抛出的一些自定义异常,统一进行处理,一般用于进行一些特定的异常处理

可以根据需要定义多个 @ExceptionHandler 方法,每个方法处理一种特定类型的异常

//  表示处理SQL异常@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {......}
  • value

    指定要处理的异常类型。可以是单个异常类或一组异常类

@ExceptionHandler(value = {NullPointerException.class, IllegalArgumentException.class})
public String handleSpecificExceptions(Exception e) {// 处理特定类型的异常return "处理特定类型的异常";
}
  • exceptions

    value 属性类似,用于指定要处理的异常类型

@ExceptionHandler(exceptions = NullPointerException.class)
public String handleCustomException(Exception e) {// 处理自定义异常return "处理自定义异常";
}
  • basePackages/basePackageClasses

    限定 @ExceptionHandler 方法的扫描范围,类似于 @ControllerAdvice 的属性

@ExceptionHandler(basePackages = "com.zhangjingqi.controllers")
public String handleExceptionsInControllerPackage(Exception e) {// 处理指定包中的异常return "packageError";
}

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

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

相关文章

【漏洞复现】捷诚管理信息系统 SQL注入漏洞

漏洞描述 捷诚管理信息系统是一款功能全面,可以支持自营、联营到外柜租赁的管理,其自身带工作流管理工具,能够帮助企业有效的开展内部审批工作。 该系统CWSFinanceCommon.asmx接口存在SQL注入漏洞。未经身份认证的攻击者可以通过该漏洞获取数据库敏感信息,深入利用可获取…

Redis设计与实现之整数集合

目录 一、内存映射数据结构 二、整数集合 1、整数集合的应用 2、数据结构和主要操作 3、intset运行实例 创建新intset 添加新元素到 intset 添加新元素到 intset&#xff08;不需要升级&#xff09; 添加新元素到 intset (需要升级) 4、升级 升级实例 5、关于升级 …

GZ015 机器人系统集成应用技术样题4-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题4 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

Flutter在Android Studio上创建项目与构建模式

一、安装插件 1、前提条件&#xff0c;安装配置好Android Studio环境 2、安装Flutter和Dart插件 Linux或者Windows平台&#xff1a; 1&#xff09;、打开File > Settings。 2&#xff09;、在左侧列表中&#xff0c;选择"Plugins"右侧上方面板选中 "Market…

vue-element-admin如何把mock换成使用真实后台接口

1&#xff09;修改vue.config.js文件 use strict const path require(path) const defaultSettings require(./src/settings.js)function resolve(dir) {return path.join(__dirname, dir) }const name defaultSettings.title || vue Element Admin // page title// If you…

Vue3-16-【v-model】 表单数据绑定

作用描述 v-model 指令&#xff0c;实现了 表单输入组件的值 与 js 中的变量的值的绑定关系。 当我们在页面上执行输入动作时&#xff0c;js中变量的值也会同步发生变化。表单不仅仅局限于输入框&#xff0c;其他的如 &#xff1a; 单选按钮&#xff0c;复选框&#xff0c;下拉…

数据结构面试题和题目解析

以下是一些数据结构的面试题和解析&#xff1a; 1. 什么是链表&#xff1f; 链表是一种线性数据结构&#xff0c;由一系列节点组成&#xff0c;每个节点包含数据部分和指向下一个节点的指针。链表的主要优点是插入和删除操作比较方便&#xff0c;但访问链表中的元素不如访问数组…

【INTEL(ALTERA)】 quartus SignalTap 逻辑分析器 – Nios® II 插件 无法检测 Nios® II/f 处理器内核

说明 使用 Nios II 插件将 Nios II/f 处理器内核节点添加到 SignalTap 逻辑分析器时&#xff0c;在 英特尔 Quartus Prime Pro Edition 软件 23.3 版中可能会出现此问题。 错误消息&#xff1a; 无法完成“添加带插件的节点”命令&#xff0c;因为在当前设计中找不到所选 IP。…

IDEA之设置项目包的结构层级为eclipse默认样式

idea默认项目包的结构层级如下: 想修改成eclipse默认的那种样式&#xff0c;设置步骤如下: 1.点击下图中红框图标进行设置 2.选择 Tree Appearance&#xff0c;取消勾选 Compact Middle Packages 3.勾选红框里的两个选项&#xff0c;Flatten Packages 和 Hide Empty Middle Pa…

DL Homework 11

由于好多同学问我要代码&#xff0c;但这两天光顾着考四六级了&#xff0c;所以只能今天熬夜先给赶出来&#xff0c;第一题先搁置&#xff0c;晚点补上&#xff0c;先写第二题 习题6-4 推导LSTM网络中参数的梯度&#xff0c; 并分析其避免梯度消失的效果 习题6-3P 编程实现…

KMP算法, 什么是KMP算法 ,暴力匹配 ,KMP算法实现

文章目录 KMP算法什么是KMP算法暴力匹配KMP算法实现 KMP算法 什么是KMP算法 KMP是Knuth、Morris和Pratt首字母的缩写&#xff0c;KMP也是由这三位学者发明&#xff08;1977年联合发表论文&#xff09;。 KMP主要应用在字符串的匹配&#xff0c;是一个解决模式串在文本串是否…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《耦合碳-绿证-消纳量市场的日前电量市场交易交互式优化》

这个标题描述了一种优化模型或算法&#xff0c;用于在日前电量市场中耦合碳排放权市场、可再生能源绿色证书市场和消纳量市场进行交易的交互式优化。我将解析标题的关键词和概念&#xff1a; 日前电量市场&#xff1a;指的是电力市场中进行短期调度和交易的市场&#xff0c;其…

Idea maven打包时 报错 illegalArgumentException: Malformed \uxxxx encoding 解决方法

1 改变打包命令重新打包 在maven打包命令上加入 -e -X 2 找到报错类和方法 可以看到是 java.util.Properties#loadConvert类方法中有个throw new IllegalArgumentException( "Malformed \\uxxxx encoding.")&#xff0c;在此打断点 3 以Debug方式重新运行maven…

SLAM算法与工程实践——相机篇:传统相机使用(1)

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址&#xff1a; SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

死锁的预防、避免、检测和消除

一、预防死锁 1. 破坏互斥条件 2. 破坏不剥夺条件 3.破坏请求和保持条件 4.破坏循环等待条件 二、避免死锁 避免死锁的一种方法是使用银行家算法&#xff0c;它涉及到安全序列的概念。银行家算法是一种资源分配和死锁避免的算法&#xff0c;它确保系统能够分配资源而不会导致死…

STM32迪文屏图标控件保姆级教程

要主图的去末尾&#xff0c;末尾福利图在等着你~~~ 文章目录 前言 开发环境 二、使用步骤 1.添加图标控件 2.设置图标属性 3.图标库ICL文件生成 4.单片机程序编写 容易踩得坑 一、前言 本篇文章主要介绍了在DGBUS平台上使用图标变量的步骤。首先需要在DGBUS中添加一个图标变量控…

linux(centos7)mysql8.0主从集群搭建(两台机器)

docker安装:&#xff08;转载&#xff09;centos7安装Docker详细步骤&#xff08;无坑版教程&#xff09;-CSDN博客 环境信息 主数据库服务器&#xff1a;192.168.1.10 从数据库服务器&#xff1a;192.168.1.11 1. mysql8.0镜像下载 docker pull mysql:8.0.23 2.创建docke…

瑞萨单片机学习:RA4M3单片机 BOOTloader升级 跳转到主程序 主程序无法执行问题

背景&#xff1a; 使用瑞萨的RA4M3单片机编写BOOT引导程序进行测试&#xff0c;在BOOT程序跳转到主程序时&#xff0c;主程序无法执行。本文介绍了问题的定位和解决方法。 运行开发环境介绍 硬件环境 RA4M3 官方开发板 J-LINK V11 开发板自带 软件开发环境 e2 studio VSCODE…

oracle怎么导入dmp文件??????

目录 oracle怎么导入dmp文件&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f; 先看&#xff1a; 方法一&#xff1a;【推荐】 winR输入 输入&#xff1a; 检验&#xff1a; 导入成功&#xff01; 方法二&#xff1a; 直接在 PLSQL Developer…

插入排序:直接插入排序 希尔排序

插入排序&#xff1a; 假设红竖线前的元素全部排好序&#xff0c;红线后面的数即为要插入的数据&#xff0c;红线依次往后移&#xff0c;假设end为排好序的最后一个数字&#xff0c;end1即为要插入的数字&#xff0c;一次插入时&#xff0c;end与要插入的数字依次比较&#xf…