关于validate:thinkphp-validate-unique-数据库字段唯一性校验

当咱们须要通过验证器 validate 来对数据库中的字段做唯一性校验时,能够通过 unique 规定实现,但 tp 并没有很具体的阐明如何应用。 这里联合我日常开发中的一些场景,给大家整顿一下: unique 语法规定// modelClassName 你须要关联校验的模型类名(间接写表名会比拟硬编码)// col1^col2 参加惟一校验的字段// [// ['col1', '=', $formData['col1']],// ['col2', '=', $formData['col2']],// ]// $pkId 「编辑」场景防他杀// [['id', '<>', $pkId]]protectd $rule = [ "colName" => "require|unique:modelClassName,col1[^col2][,$pkId]"]模型/** * @property int $id * @property string $name 惟一 * @property int $age * @property int $deleted 软删除class User extends Model{ protected $connection = "db_app";//多库链接配置}校验器基类依据表单数据中是否有 pkId 来动静的调整 unique 的校验规定 <?phpnamespace app\common\validate;use think\Validate;/** * Class MaterialTypeValidate * * @package app\prt\validate * @see \think\Validate::unique 解析器 */class BaseValidate extends Validate{ /** * 依据表单数据动静挂载 pkId * 编辑时的 unique 校验 应应用 pkId 来疏忽以后行 * 同时如果有软删除 那么还要退出 deleted=0 的条件来限度只校验无效记录 * formData ['col1' => xxx, 'col2' => xxx, 'deleted'=>0] * unique|modelName,col1^col2^deleted,pkId * unique多字段校验时验证器会查看表单数据有对应的字段 有才会生成查问条件 * 为了疏忽软删除要让表单数据中的 deleted=0 显示定义,排除已删除的数据 * BaseValidate constructor. * * @param int $pkId * @param array $rules * @param array $message * @param array $field */ public function __construct($pkId = 0, array $rules = [], array $message = [], array $field = []) { parent::__construct($rules, $message, $field); // 有 id 则为编辑,追加pkId条件 // 无 id 则为新增,全局惟一查看 array_walk($this->rule, function (&$row) use ($pkId) { $row = str_replace(",{pkId}", "," . $pkId ?? "", $row); }, $this->rule); }}新增时须要校验全局无效记录的字段唯一性,编辑 时须要校验 除以后记录外 的字段唯一性。 ...

June 10, 2022 · 2 min · jiezi

java-bean-属性验证框架-valid

项目介绍java 开发中,参数校验是非常常见的需求。 但是 hibernate-validator 在使用过程中,依然会存在一些问题。 特性支持 fluent-validation支持 jsr-303 注解支持 i18n支持用户自定义策略支持用户自定义注解开源地址valid创作目的hibernate-validator 无法满足的场景如今 java 最流行的 hibernate-validator 框架,但是有些场景是无法满足的。 比如: 验证新密码和确认密码是否相同。(同一对象下的不同属性之间关系)当一个属性值满足某个条件时,才进行其他值的参数校验。多个属性值,至少有一个不能为 null其实,在对于多个字段的关联关系处理时,hibernate-validator 就会比较弱。 本项目结合原有的优点,进行这一点的功能强化。 validation-api 过于复杂validation-api 提供了丰富的特性定义,也同时带来了一个问题。 实现起来,特别复杂。 然而我们实际使用中,常常不需要这么复杂的实现。 valid-api 提供了一套简化很多的 api,便于用户自行实现。 自定义缺乏灵活性hibernate-validator 在使用中,自定义约束实现是基于注解的,针对单个属性校验不够灵活。 本项目中,将属性校验约束和注解约束区分开,便于复用和拓展。 过程式编程 vs 注解式编程hibernate-validator 核心支持的是注解式编程,基于 bean 的校验。 一个问题是针对属性校验不灵活,有时候针对 bean 的校验,还是要自己写判断。 本项目支持 fluent-api 进行过程式编程,同时支持注解式编程。 尽可能兼顾灵活性与便利性。 项目模块说明模块名称说明valid-api核心 api 及注解定义valid-core针对 valid-api 的核心实现valid-jsr针对 JSR-303 标准注解的实现valid-test测试代码模块依赖说明valid-core 默认引入 valid-api valid-jsr 默认引入 valid-core 快速开始准备工作JDK1.7+ Maven 3.X+ maven 引入<dependency> <groupId>com.github.houbb</groupId> <artifactId>valid-jsr</artifactId> <version>0.1.2</version></dependency>例子我们直接利用 jsr 内置的约束类: ...

October 13, 2019 · 6 min · jiezi

yii2-在控制器中验证请求参数

写api接口时一般会在控制器中简单验证参数的正确性。 使用yii只带验证器(因为比较熟悉)实现有两种方式(效果都不佳)。 针对每个请求单独写个 Model, 定义验证规则并进行验证。 缺点:写好多参数验证的 Model 类。使用 独立验证器 中提到的 $validator->validateValue() 方法直接验证变量值。缺点:写实例化很多验证器对象。有么有“一劳永逸”的做法,像在 Model 中通过 rules 方法定义验证规则并实现快速验证的呢?有! 使用方法(实现效果)namespace frontend\controllers\api;use yii\web\Controller;use common\services\app\ParamsValidateService;class ArticleController extends Controller{ // 文章列表 public function actionList() { $PVS = new ParamsValidateService(); $valid = $PVS->validate(\Yii::$app->request->get(), [ ['category_id', 'required'], ['category_id', 'integer'], ['keyword', 'string'], ]); if (!$valid) { $this->apiError(1001, $PVS->getErrorSummary(true)); } //... } // 新增文章 public function actionPost() { $PVS = new ParamsValidateService(); $valid = $PVS->validate(\Yii::$app->request->get(), [ [['category_id', 'title', 'content'], 'required'], ['category_id', 'integer'], [['title'], 'string', 'max' => 64], [['content'], 'string'], ]); if (!$valid) { $this->apiError(1001, $PVS->getErrorSummary(true)); } //... } // 文章删除 public function actionDelete() { $PVS = new ParamsValidateService(); $valid = $PVS->validate(\Yii::$app->request->get(), [ ['article_id', 'required'], ['article_id', 'integer'], ]); if (!$valid) { $this->apiError(1001, $PVS->getErrorSummary(true)); } //... }}实现方法定义参数验证模型定义参数验证模型 ParamsValidateModel,继承 yii\db\ActiveRecord,重写 attributes() 方法,主要功能: ...

June 18, 2019 · 2 min · jiezi

开发函数计算的正确姿势-Fun-validate-语法校验排错指南

1. 前言首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考。Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考。 template.yml: template.yml 用于定义 serverless 应用的模型。无论是使用 fun local 还是 fun deploy 等功能,都是通过解析 tempalte.yml 的内容,构建出用户定义的云资源模型,进而实现本地云资源的运行调试以及发布等功能。template.yml 支持的规范文档可以参考。 template.yml 所描述的 Serverless 模型,是 Fun 所有功能的基石。template.yml 的正确性对后续能够顺利使用 Fun 的各项功能无疑是非常关键的。为了帮助用户更快速的修正 template.yml 中错误的描述,我们在 Fun 2.14.0 优化了语法校验的错误信息,可以达到更精准定位报错并修复的目的。 下面我们就通过一个示例,学习如何根据报错信息纠正 template.yml 中的错误语法描述。 备注:请确保 Fun 工具版本在 2.14.0+ 2. 错误的 template.yml 示例ROSTemplateFormatVersion: '2015-09-01'Transform: 'Aliyun::Serverless-2018-04-03'Resources: local-http-demo: Type: 'Aliyun::Serverless::InvalidService' Properties: Description: 'local invoke demo' nodejs8: Type: 'Aliyun::Serverless::InvalidFunction' Properties: Handler: index.handler CodeUri: nodejs8/ Description: 'http trigger demo with nodejs8!' Events: http-test: Type: HTTP Properties: AuthType: ANONYMOUS Method: ['GET', 'POST', 'PUT']在上面的示例中,我们原意是想要描述一个叫做 local-http-demo 的服务,并在服务下定义了一个名为 nodejs8 的函数,同时为该函数配置一个匿名的 HTTP 触发器,支持 GET、POST、PUT 的 HTTP 请求。 ...

May 22, 2019 · 3 min · jiezi

form 表单提交前验证 onsubmit

使用form表单的onsubmit方法,在提交表单之前,对表单或者网页中的数据进行检验。onsubmit指定的方法返回true,则提交数据;返回false不提交数据。在不使用JQuery的情况下(js原生),是提交表单前拦截的较好方法。js验证form表单,示例代码:<!DOCTYPE html><html><head> <meta charset=“utf-8”> <meta name=“viewport” content=“width=device-width”> <title>form validate</title> <script src=“https://code.jquery.com/jquery-1.9.1.js"></script> <script> function validate() { // 为了方便 使用了jq获取表单元素的值,可以使用js原生获取 if ($(’#input’).val() == 1) { return true } else { alert(‘validate error!’) return false } } </script></head><body> <form action=“http://www.baidu.com” onsubmit=“return validate()"> <input type=“text” id=“input”> <input type=“submit” id=“submit” value=“提交” /> </form></body></html>

April 18, 2019 · 1 min · jiezi

基于vee-validata封装的Vue验证插件 测试版

这个插件主要是为了解决vee-validata在使用中没有有验证的地方要单独去写很多验证样式的标签以及一些不方便实现的一些验证的样式 比如这样子:/插件源码*//create by fish at 20190321基于vee-validate封装的正则验证插件需要前端特殊样式的配合v0.0.1@beta;未解决 required的问题 只能在这个里面设置 还不支持参数传递/import zh from ‘vee-validate/dist/locale/zh_CN’; import { Validator } from ‘vee-validate’Validator.localize(‘zh’,zh);const isPhone = {getMessage:(field, params, data) => { return field + ‘格式错误’;},validate: value => { if(value==undefined){ value=’’ } return value.length == 11 && /^((13|14|15|17|18)[0-9]{1}\d{8})$/.test(value)}}const isPassword ={getMessage:(field, params, data) => { return field + ‘密码6-16位,不包含特殊字符,可以是数字或者字母’;},validate: value => { if(value==undefined){ value=’’ } return value == value && value.length > 5;}}const isEmail ={getMessage:(field, params, data) => { return field + ‘格式错误’;},validate: value => { if(value==undefined){ value=’’ } return value == value && /^(\w)+(.\w+)@(\w)+((.\w+)+)$/.test(value);}}Validator.extend(‘password’, isPassword);Validator.extend(‘phone’, isPhone);Validator.extend(’email’, isEmail);Validator.localize({zh: { messages: { required: function (name) { return name + ‘不能为空’ }, }, attributes: { phone: ‘手机号’, password:‘密码’, email:‘邮箱’ } }})const validator = new Validator({phone: ‘required|phone’,password: ‘required|password’,email:‘required|email’,});/*创建验证对象/const FishVer = function(){this.init = function(verArr,callback,id){ verArr.forEach((el,index)=>{ var inputDom = getElementByAttr(‘form-control’,’name’,el.name,id); inputDom.forEach((eldom,ind)=>{ eldom.addEventListener(‘input’,(event,e)=>{ regValue(el,eldom).then(res=>{ verArr[index].ver = res callback(checkVerAll(verArr)) }) }) }) })}}/*统一验证全部/FishVer.prototype.fishVerAll = function(verArr,callback,id){let promises = [];for(let i=0;i<verArr.length;i++){ var inputDom = getElementByAttr(‘form-control’,’name’,verArr[i].name,id); promises.push(regValue(verArr[i],inputDom[0]))}return Promise.all(promises).then(res=>{ callback(checkVerArrAll(res))})}/**检查 是否全部验证完(自动)@param {} value/function checkVerAll(value){let isAll = false;for(let i=0;i<value.length;i++){ if(value[i].ver){ isAll = true; continue; }else{ isAll = false; break; }}return isAll;}/**检查 是否全部验证完(手动)@param {} value/function checkVerArrAll(value){let isAll = false;for(let i=0;i<value.length;i++){ if(value[i]){ isAll = true; continue; }else{ isAll = false; break; }}return isAll;}/获取dom元素@param {} tag@param {} dataAttr@param {} reg/function getElementByAttr(tag, dataAttr, reg,id) {var idEle = document.getElementById(id);var aElements = idEle.getElementsByClassName(tag);var aEle = [];for(var i = 0; i < aElements.length; i++) { var ele = aElements[i].getAttribute(dataAttr); if(ele == reg) { aEle.push(aElements[i]); }}return aEle;}function regValue(el,inputDom){return new Promise((resolve,reject)=>{ validator.validate(el.name,inputDom.value).then((res)=>{ let inputDomFather = inputDom.parentNode; let hasError = inputDomFather.getElementsByClassName(‘ver_error’); if(validator.errors.has(el.name)){ //如果验证不通过 removeClass(inputDom,‘ver_success’); removeClass(inputDom,‘ver_fail’); addClass(inputDom,‘ver_fail’); removeClass(inputDomFather,‘ver_box_success’); removeClass(inputDomFather,‘ver_box_fail’) addClass(inputDomFather,‘ver_box_fail’); if(hasError.length){ hasError[0].innerHTML = validator.errors.first(el.name); }else{ let errorTemp = document.createElement(‘span’); errorTemp.className = ‘ver_error’; errorTemp.innerHTML = validator.errors.first(el.name); inputDomFather.append(errorTemp); } resolve(false) }else{ if(hasError.length){ inputDomFather.removeChild(hasError[0]); } removeClass(inputDom,‘ver_fail’); removeClass(inputDom,‘ver_success’); addClass(inputDom,‘ver_success’); removeClass(inputDomFather,‘ver_box_fail’); removeClass(inputDomFather,‘ver_box_success’); addClass(inputDomFather,‘ver_box_success’); resolve(true) } }).catch(err=>{ console.log(err) })})}function addClass(obj,cls) {var obj_class=obj.className,blank = ( obj_class != ’’ ) ? ’ ’ : ‘’;let added = obj_class + blank + cls;obj.className = added;}function removeClass(obj,classname){//如果原来有classif(obj.className!=""){ var arrClassName=obj.className.split(" “); var _index=arrIndexOf(arrClassName,classname); //如果有需要移除的class if(_index!=-1){ arrClassName.splice(_index,1); obj.className=arrClassName.join(” “); }}//如果原来没有class无操作}function arrIndexOf(arr,v){for(var i=0;i<arr.length;i++){ if(arr[i]==v){ return i; }}return -1;}const fishVer = new FishVer();export default fishVer;/插件源码//*调用插件/fishVer.init([{name:‘password’}],(res)=>{console.log(res)},’logver’)<input type=“password” name=“password” class=“form-control form-block” v-model=“login_pwd” placeholder=“密码”>需要输入框有form-control这个类 有对应的name logver 为包含这个input 这个DOM的外层盒子的id值 这个id 保证这个一个页面中相同的name值在不同的ID盒子里进行验证 自定义的样式可以在验证后审查元素 去定义自己的样式 ...

March 27, 2019 · 2 min · jiezi

SpringBoot 实战 (十五) | 服务端参数校验之一

前言估计很多朋友都认为参数校验是客户端的职责,不关服务端的事。其实这是错误的,学过 Web 安全的都知道,客户端的验证只是第一道关卡。它的参数验证并不是安全的,一旦被有心人抓到可乘之机,他就可以有各种方法来摸拟系统的 Http 请求,访问数据库的关键数据。轻则导致服务器宕机,重则泄露数据。所以,这时就需要设置第二道关卡,服务端验证了。老项目的服务端校验@RestController@RequestMapping("/student")public class ValidateOneController { @GetMapping("/id") public Student findStudentById(Integer id){ if(id == null){ logger.error(“id 不能为空!"); throw new NullPointerException(“id 不能为空”); } return studentService.findStudentById(id); }}看以上代码,就一个的校验就如此麻烦。那我们是否有好的统一校验方法呢?鉴于 SpringBoot 无所不能。答案当然是有的。其中,Bean Validator 和 Hibernate Validator 就是两套用于验证的框架,二者都遵循 JSR-303 ,可以混着用,鉴于二者的某些 Validator 注解有差别,例如 @Length 在 Bean Validator 中是没有的,所以这里我选择混合用。JSR-303JSR-303 是JAVA EE 6 中的一项子规范,叫做 Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现, Hibernate Validator 提供了 JSR 303 规范中所有内置 Constraint(约束) 的实现,除此之外还有一些附加的 Constraint 。这些 Constraint (约束) 全都通过注解的方式实现,请看下面两个表。Bean Validation 中内置的约束:注解作用@Null被注解参数必须为空@NotNull被注解参数不能为空@AssertTrue被注解参数必须为 True@AssertFalse被注解参数必须为 False@Min(value)被注解参数必须是数字,且其值必须大于等于 value@Max(value)被注解参数必须是数字,且其值必须小于等于 value@DecimaMin(value)被注解参数必须是数字,且其值必须大于等于 value@DecimaMax(value)被注解参数必须是数字,且其值必须小于等于 value@Size(max, min)被注解参数大小必须在指定范围内@Past被注解参数必须是一个过去的日期@Future被注解参数必须是一个将来的日期@Pattern(value)被注解参数必须符合指定的正则表达式@Digits(integer, fraction)被注解参数必须是数字,且其值必须在可接受范围内@NotBlank被注解参数的值不为空(不为 null、去除首位空格后长度为 0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的空格Hibernate Validator 附加的约束:注解作用@NotEmpty被注解参数的值不为 null 且不为空(字符串长度不为0、集合大小不为0)@Email被注解参数必须是电子邮箱地址@Length被注解的字符串长度必须在指定范围内@Range被注解的参数必须在指定范围内准备工作SpringBoot 2.1.3IDEAJDK8Pom 文件依赖<!– web 启动类 –><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><!– test 单元测试类 –><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope></dependency><!– lombok 依赖用于简化 bean –><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional></dependency>实体类用于测试,加入了参数校验规则。@Data@AllArgsConstructor@NoArgsConstructorpublic class Student { private Integer id; @NotBlank(message = “学生名字不能为空”) @Length(min = 2, max = 10, message = “name 长度必须在 {min} - {max} 之间”) private String name; @NotNull(message = “年龄不允许为空”) @Min(value = 0, message = “年龄不能低于 {value} 岁”) private Integer age;}Controller 层写了两个方法,一个用于校验普通参数,一个用于校验对象@Validated //开启数据校验,添加在类上用于校验方法,添加在方法参数中用于校验参数对象。(添加在方法上无效)@RestController@RequestMapping("/student”)public class ValidateOneController { /** * 普通参数校验 * @param name * @return / @GetMapping("/name") public String findStudentByName(@NotBlank(message = “学生名字不能为空”) @Length(min = 2, max = 10, message = “name 长度必须在 {min} - {max} 之间”)String name){ return “success”; } /* * 对象校验 * @param student * @return */ @PostMapping("/add") public String addStudent(@Validated @RequestBody Student student){ return “success”; }}Postman 测试校验普通参数测试结果:下图可以看见,我没有在 http://localhost:8080/student/name 地址后添加 name 参数,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。校验对象测试结果:结果有点长:下图可以看见,我访问 http://localhost:8080/student/add 传入了参数对象,但对象是不能通过校验规则的,比如 age 参数为负数,name 参数长度太大,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。完整代码https://github.com/turoDog/De…如果觉得对你有帮助,请给个 Star 再走呗,非常感谢。后语如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。另外,关注之后在发送 1024 可领取免费学习资料。资料详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享 ...

March 4, 2019 · 2 min · jiezi

Spring校验@RequestParams和@PathVariables参数

我们在写Rest API接口时候会用到很多的@RequestParam和@PathVariable进行参数的传递,但是在校验的时候,不像使用@RequestBody那样的直接写在实体类中,我们这篇文章讲解一下如何去校验这些参数。依赖配置要使用Java Validation API,我们必须添加validation-api依赖项:<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version></dependency>通过添加@Validated注解来启用控制器中的@RequestParams和@PathVariables的验证:@RestController@RequestMapping("/")@Validatedpublic class Controller { // …}校验@RequestParam我们将数字作为请求参数传递给控制器方法@GetMapping("/name-for-day")public String getNameOfDayByNumber(@RequestParam Integer dayOfWeek) { // …}我们保证dayOfWeek的值在1到7之间,我们使用@Min和@Max注解@GetMapping("/name-for-day")public String getNameOfDayByNumber(@RequestParam @Min(1) @Max(7) Integer dayOfWeek) { // …}任何与这些条件不匹配的请求都将返回HTTP状态500,并显示默认错误消息。如果我们尝试调用http://localhost:8080/name-for-day?dayOfWeek=24这将返回以下响应信息:There was an unexpected error (type=Internal Server Error, status=500).getNameOfDayByNumber.dayOfWeek: must be less than or equal to 7当然我们也可以在@Min和@Max注解后面加上message参数进行修改默认的返回信息。校验@PathVariable和校验@RequestParam一样,我们可以使用javax.validation.constraints包中的注解来验证@PathVariable。验证String参数不是空且长度小于或等于10@GetMapping("/valid-name/{name}")public void test(@PathVariable(“name”) @NotBlank @Size(max = 10) String username) { // …}任何名称参数超过10个字符的请求都会导致以下错误消息:There was an unexpected error (type=Internal Server Error, status=500).createUser.name:size must be between 0 and 10通过在@Size注解中设置message参数,可以覆盖默认消息。其实我们可以看到校验@RequestParam和@PathVariable参数和我们校验@RequestBody方式一致,只不过一个是写在了实体中,一个写在了外部,当然我们也可以将@RequestParam的参数写入到实体类中,进行使用@RequestParam注解进行引入,比如我们使用一个分页的实例分页实体类/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * “License”); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an “AS IS” BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. /package com.zhuanqb.param.page;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import lombok.ToString;import org.hibernate.validator.constraints.NotBlank;import org.hibernate.validator.constraints.NotEmpty;import javax.validation.constraints.Max;import javax.validation.constraints.Min;import javax.validation.constraints.NotNull;/* * PageParam <br/> * 描述 : PageParam <br/> * 作者 : qianmoQ <br/> * 版本 : 1.0 <br/> * 创建时间 : 2018-09-23 下午7:40 <br/> * 联系作者 : <a href=“mailTo:shichengoooo@163.com”>qianmoQ</a> */@Data@ToString@NoArgsConstructor@AllArgsConstructorpublic class PageParam { @NotNull(message = “每页数据显示数量不能为空”) @Min(value = 5) @Max(value = 100) private Integer size; // 每页数量 @NotNull(message = “当前页显示数量不能为空”) @Min(value = 1) @Max(value = Integer.MAX_VALUE) private Integer page; // 当前页数 private Boolean flag = true;}@RequestParam调用方式 @GetMapping(value = “list”) public CommonResponseModel findAll(@Validated PageParam param) { … }这样的话可以使我们的校验定制化更加简单。 ...

February 25, 2019 · 2 min · jiezi