寻找写代码感觉(十六)之 集成Validation做参数校验
写在前面
今天是大年初五了。。。
不知不觉,又要上班了,美好的假期只剩一天了,有点不舍呢!
也不知道为什么,总感觉像在做梦一样,像没睡醒一样,并不是因为眼睛小,更多应该是自寻烦恼,想得多罢了。
参数校验任务拆解
- 对保存接口和查询接口增加参数校验
- 校验不通过时,前端弹出错误提示
集成Validation做参数校验实现
1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2、对查询接口增加参数校验
2.1、给对应实体字段添加校验,示例代码如下:
package com.rongrong.wiki.req;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;
@Data
public class PageReq {
private int page;
@NotNull(message = "【每页条数】不能为空")
@Max(value = 100, message = "【每页条数】不能超过100")
private int size;
}
2.2、再给对应接口添加校验,示例代码如下:
/**
* 查询功能,支持按名字模糊查询
*
* @param eBookReq
* @return
*/
@GetMapping("/list")
public CommonResp list(@Valid EBookQueryReq eBookReq) {
CommonResp<PageResp<EBookResp>> resp = new CommonResp<>();
PageResp<EBookResp> list = eBookService.list(eBookReq);
resp.setMessage("执行查询成功!");
resp.setContent(list);
return resp;
}
2.3、测试接口是否有校验了
GET http://localhost:8888/ebook/list?page=1&size=1000
HTTP/1.1 400
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 05 Feb 2022 01:26:51 GMT
Connection: close
{
"timestamp": "2022-02-05T01:26:51.739+00:00",
"status": 400,
"error": "Bad Request",
"trace": "org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors\nField error in object 'EBookQueryReq' on field 'size': rejected value [1000]; codes [Max.EBookQueryReq.size,Max.size,Max.int,Max]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [EBookQueryReq.size,size]; arguments []; default message [size],100]; default message [【每页条数】不能超过100]\r\n\tat org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:170)\r\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:893)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:807)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1061)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:961)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:626)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n",
"message": "Validation failed for object='EBookQueryReq'. Error count: 1",
"errors": [
{
"codes": [
"Max.EBookQueryReq.size",
"Max.size",
"Max.int",
"Max"
],
"arguments": [
{
"codes": [
"EBookQueryReq.size",
"size"
],
"arguments": null,
"defaultMessage": "size",
"code": "size"
},
100
],
"defaultMessage": "【每页条数】不能超过100",
"objectName": "EBookQueryReq",
"field": "size",
"rejectedValue": 1000,
"bindingFailure": false,
"code": "Max"
}
],
"path": "/ebook/list"
}
Response code: 400; Time: 105ms; Content length: 5763 bytes
由上可知,已经触发了校验,但这样的提示,不是我们想要,需要对校验做进一步处理。
2.4、统一异常处理
加入后,将会对controller中的异常进行处理,示例代码如下:
package com.rongrong.wiki.controller;
import com.rongrong.wiki.exception.BusinessException;
import com.rongrong.wiki.resp.CommonResp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一异常处理、数据预处理等
*/
@ControllerAdvice
public class ControllerExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(ControllerExceptionHandler.class);
/**
* 校验异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = BindException.class)
@ResponseBody
public CommonResp validExceptionHandler(BindException e) {
CommonResp commonResp = new CommonResp();
LOG.warn("参数校验失败:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
commonResp.setSuccess(false);
commonResp.setMessage(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return commonResp;
}
/**
* 校验异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = BusinessException.class)
@ResponseBody
public CommonResp validExceptionHandler(BusinessException e) {
CommonResp commonResp = new CommonResp();
LOG.warn("业务异常:{}", e.getCode().getDesc());
commonResp.setSuccess(false);
commonResp.setMessage(e.getCode().getDesc());
return commonResp;
}
/**
* 校验异常统一处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public CommonResp validExceptionHandler(Exception e) {
CommonResp commonResp = new CommonResp();
LOG.error("系统异常:", e);
commonResp.setSuccess(false);
commonResp.setMessage("系统出现异常,请联系管理员");
return commonResp;
}
}
再次调用查询接口,测试结果如下:
3、对保存接口增加参数校验
和上面的查询接口一样,也是需要将需要校验字段加上注解校验,再对接口加上对应注解,即完成校验操作,示例代码如下:
@NotNull(message = "【名称】不能为空")
private String name;
/**
* 新增或编辑功能
*
* @param eBookSaveReq
* @return
*/
@PostMapping("/save")
public CommonResp save(@Valid @RequestBody EBookSaveReq eBookSaveReq) {
CommonResp resp = new CommonResp<>();
eBookService.save(eBookSaveReq);
return resp;
}
4、校验不通过时,前端弹出错误提示
在前段页面添加弹窗提示组件,示例代码如下:
import {message} from 'ant-design-vue';
if (data.success) {
modalVisible.value = false;
modalLoading.value = false;
//重新加载列表
handleQuery({
page: 1,
size: pagination.value.pageSize,
});
}else {
message.error(data.message);
}
})
编译运行,测试结果
1、查询接口铅酸验证结果
2、保存接口前端验证结果
写在最后
就一个功能来说的话,肯定是要有对应的校验规则,才是严谨的,从某种角度来说,也体现了程序的健壮性。
当然,也可能有的同学会说,写校验规则多麻烦,基本功能能用不就行了吗。
其实不然,因为用户的行为,是最不可控的,不能保证每个使用者(用户),都能按照开发者预设的想法去使用软件。
如果那样话,那所有程序,都会没有bug了,你说是不是?
寻找写代码感觉(十六)之 集成Validation做参数校验的更多相关文章
- 寻找写代码感觉(二)之 Spring Boot 项目属性配置
一.前言 写代码就和恋爱一样,有反馈就要趁热打铁,搞完了项目搭建,接下来就来搞搞项目配置. 二.IDEA设置 1.编码配置 这里所说的就是代码的编码格式,你可以不设置,但是可能要面临的是,很多未知的麻 ...
- 寻找写代码感觉(一)之使用 Spring Boot 快速搭建项目
写在前面 现在已经是八月份了,我已经荒废了半年居多,不得不说谈恋爱确实是个麻烦的事,谈好了皆大欢喜,分手了就是萎靡不振,需要很长一段时间才能缓过来. 人还是要有梦想的,至于实现只不过是一个契机,但凡不 ...
- 寻找写代码感觉(三)之使用 Spring Boot 编写接口
一.前言 项目配置完之后,接着就是写接口了,那咱们就开始吧. 二.项目配置补充知识点 上篇文章写的是关于项目属性配置的一些知识,这里针对上次遗忘内容进行补充如下: 2.1.获取配置文件的值 在appl ...
- 寻找写代码感觉(五)之Mybatis官方代码生成器的使用
一.Mybatis Generator生成器 见名知意,官方给出的代码生成器.好处就是不用自己写实体类.接口.xml文件了,应对简单增删改查是可以的.复杂的还是需要自己手写sql的. 二.Mybati ...
- 寻找写代码感觉(八)之SpringBoot过滤器的使用
一.什么是过滤器? 过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的, ...
- Java开发笔记(二十六)方法的输出参数
前面介绍了方法的输入参数,与输入参数相对应的则为输出参数,输出参数也被称作方法的返回值,意思是经过方法的处理最终得到的运算数值.这个返回值可能是整型数,也可能是双精度数,也可能是数组等其它类型,甚至允 ...
- ElasticSearch7.3学习(二十六)----搜索(Search)参数总结、结果跳跃(bouncing results)问题解析
1.preference 首先引入一个bouncing results问题,两个document排序,field值相同:不同的shard上,可能排序不同:每次请求轮询打到不同的replica shar ...
- 第十六篇 nginx主配置文件参数解释
# 指定拥有运行nginx权限的用户 #user nobody; # 指定开启的进程数,建议设置为CPU核心数 worker_processes ; # 指定全局错误日志级别,包括:debug/inf ...
- CTF---Web入门第十六题 天下武功唯快不破
天下武功唯快不破分值:10 来源: 北邮天枢战队 难度:易 参与人数:10787人 Get Flag:2264人 答题人数:3373人 解题通过率:67% 看看响应头 格式:CTF{ } 解题链接: ...
随机推荐
- 1742 开心的小Q
如果一个数字存在一个约数是完全平方数,那么小Q就认为这个数是有趣的. 小Q喜欢收集有趣的数字,每找到一个有趣的数,小Q就会变得很开心. 小Q发现12是有趣的,18也是有趣的,它们都是36的约数,而在3 ...
- 【剑指Offer】平衡二叉树 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 解题方法 日期 题目地址:https://www.nowcoder.co ...
- linux中网络存储与考试系统搭建(实现多用户可以共享文件)
上期内容回顾 1.数据备份的方式有哪些 全量和增量 2.数据备份的命令有哪些 都有哪些优点缺点 cp : 本地复制,全量复制 scp : 远程复制,全量复制 rsync : 远程复制,增量复制 3.r ...
- C++模拟python风格的print函数--打印vector,map,list等结构
// 最基本实现 template<typename T> static void print(T t) { std::cout << t; } // 处理 std::pair ...
- elementUI表单嵌套表格并对每行进行校验
elementUI表单嵌套表格并对每行进行校验 elementUI 表单嵌套表格并进行校验. 目录 效果展示 代码链接 关键代码 完整代码 效果展示 先看看这是不是需要的效果^_^ 如图,Elem ...
- html+css+JavaScript实现爱恩斯坦棋游戏
title: "html+css+JavaScript实现爱恩斯坦棋游戏" author: Sun-Wind date: December 30, 2021 背景:本贴将基于前端的 ...
- 搞一下vue生态,从vuex开始
Vuex vuex 是专门帮助vue管理的一个js库,利用了vue.js中细粒度数据响应机制来进行高效的状态更新. vuex核心就是store,store就是个仓库,这里采用了单一的store状态树, ...
- 每天学一点——python变量、常量与数字类型
python变量.常量与数字类型 常量 (一句话能概括先讲它) 严格来讲,python中除了π与N就没有不变的量 所以,在python中我们识别常量是看它是否全大写(如下图) 变量 变量,顾名思义,就 ...
- Drools的Eclipse_IDEA插件安装
1.说明 Drools使用时不是必须依赖插件的, 只是在安装了相应的插件之后, 在开发工具中能识别到对应的drools文件, 能够进行一些智能提示. 以及使用插件提供的便捷功能. 2.Eclipse插 ...
- centos6.5-DNS搭建
在RHEL6.5中,系统光盘自带了BIND服务的安装文件 安装步骤 准备工作: Service iptables stop #关闭防火墙 Setenforce 0 关闭selinux ...