- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringBoot validator参数验证restful自定义错误码响应方式由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
关于spring web应用中关于如何使用 Bean Validation API和hibernate-validator的文章已经很多,本文就不再重复叙述,今天要介绍的重点是在SpringBoot restful服务中如何根据不同验证错误响应不同的自定义错误码。下面直接上代码.
阿里java开发手册中定义的一段参考【“对于公司外的 http/api 开放接口必须使用“错误码”; 而应用内部推荐异常抛出;跨应用间 RPC 调用优先考虑使用 Result 方式,封装 isSuccess()方法、 “错误码”、“错误简短信息”。】。因此这里也定义个返回结构.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
public
class
CommonResult<T>
implements
Serializable {
/**
* serialVersionUID:.
*/
private
static
final
long
serialVersionUID = -7268040542410707954L;
/**
* 是否成功
*/
private
boolean
success =
false
;
/**
* 返回信息
*/
private
String message;
/**
* 装在数据
*/
private
T data;
/**
* 错误代码
*/
private
String code;
/**
* 默认构造器
*/
public
CommonResult(){
}
/**
*
* @param success
* 是否成功
* @param message
* 返回的消息
*/
public
CommonResult(
boolean
success, String message){
this
.success = success;
this
.message = message;
}
/**
*
* @param success
* 是否成功
*/
public
CommonResult(
boolean
success){
this
.success = success;
}
/**
*
* @param code error code
* @param message success or error messages
*/
public
CommonResult(String code,String message){
this
.code = code;
this
.message = message;
}
/**
*
* @param success
* 是否成功
* @param message
* 消息
* @param data
* 数据
*/
public
CommonResult(
boolean
success, String message, T data){
this
.success = success;
this
.message = message;
this
.data = data;
}
//省略get set
}
|
在有需要国际化的项目,当然选择通过i18n来配置更好,此处为了简单直接采用枚举定义。这里定义的错误仅供参考,不同公司每个应用在实际情况下可能都不大一样.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/**
* 错误代码枚举类
*
*/
public
enum
ErrorCodeEnum {
SUCCESS(
"0000"
,
"success"
),
PARAM_EMPTY(
"1001"
,
"必选参数为空"
),
PARAM_ERROR(
"1002"
,
"参数格式错误"
),
UNKNOWN_ERROR(
"9999"
,
"系统繁忙,请稍后再试...."
);
private
String code;
private
String desc;
ErrorCodeEnum(String code, String desc) {
this
.code = code;
this
.desc = desc;
}
public
String getCode() {
return
this
.code;
}
public
String getDesc() {
return
desc;
}
@Override
public
String toString() {
return
"["
+
this
.code +
"]"
+
this
.desc;
}
}
|
静态封装CommonResult主要是方便在项目中快速根据逻辑写返回结果代码.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
/**
* 公共响应结果成功失败的静态方法调用
*
*/
public
class
ResultUtil {
/**
* return success
*
* @param data
* @return
*/
public
static
<T> CommonResult<T> returnSuccess(T data) {
CommonResult<T> result =
new
CommonResult();
result.setCode(ErrorCodeEnum.SUCCESS.getCode());
result.setSuccess(
true
);
result.setData(data);
result.setMessage(ErrorCodeEnum.SUCCESS.getDesc());
return
result;
}
/**
* return error
*
* @param code error code
* @param msg error message
* @return
*/
public
static
CommonResult returnError(String code, String msg) {
CommonResult result =
new
CommonResult();
result.setCode(code);
result.setData(
""
);
result.setMessage(msg);
return
result;
}
/**
* use enum
*
* @param status
* @return
*/
public
static
CommonResult returnError(ErrorCodeEnum status) {
return
returnError(status.getCode(), status.getDesc());
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/**
* BaseController
*
*/
public
abstract
class
BaseController {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(BaseController.
class
);
/**
* validate params
*
* @param bindingResult
* @return
*/
protected
CommonResult validParams(BindingResult bindingResult) {
if
(bindingResult.hasErrors()) {
FieldError fieldError = bindingResult.getFieldError();
return
processBindingError(fieldError);
}
return
ResultUtil.returnSuccess(
""
);
}
/**
* 根据spring binding 错误信息自定义返回错误码和错误信息
*
* @param fieldError
* @return
*/
private
CommonResult processBindingError(FieldError fieldError) {
String code = fieldError.getCode();
LOGGER.debug(
"validator error code: {}"
, code);
switch
(code) {
case
"NotEmpty"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
case
"NotBlank"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
case
"NotNull"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_EMPTY.getCode(), fieldError.getDefaultMessage());
case
"Pattern"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Min"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Max"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Length"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Range"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Email"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"DecimalMin"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"DecimalMax"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Size"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Digits"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Past"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
case
"Future"
:
return
ResultUtil.returnError(ErrorCodeEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
default
:
return
ResultUtil.returnError(ErrorCodeEnum.UNKNOWN_ERROR);
}
}
}
|
这里直接给出一个简单的参数验证例子.
Controller继承上面写的BaseController 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 关于Validator使用测试
*
*/
@RestController
@RequestMapping
(
"validator"
)
public
class
ValidatorTestController
extends
BaseController {
private
static
final
Logger LOGGER = LoggerFactory.getLogger(ValidatorTestController.
class
);
/**
* validate验证测试
*
* @param leader
* @param bindingResult
* @return
*/
@PostMapping
(
"/test"
)
public
CommonResult testSimpleValidate(
@Valid
@RequestBody
Leader leader, BindingResult bindingResult) {
LOGGER.debug(
"ReqParams:{}"
, JSON.toJSONString(leader));
CommonResult result = validParams(bindingResult);
if
(!result.isSuccess()) {
return
result;
}
return
ResultUtil.returnSuccess(
""
);
}
}
|
入参对象Leader代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public
class
Leader {
/**
* 姓名
*/
@NotEmpty
private
String name;
/**
* 生日
*/
@Pattern
(regexp =
"^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
, message =
"出生日期格式不正确"
)
private
String birthday;
/**
* 年龄
*/
@Min
(value =
0
)
private
Integer age;
//省略gettes and setters
}
|
这时项目已经已经完全可以根据验证错误来返回自定义的错误码和提示了.
本例所涉及源代码:https://github.com/shalousun/api-doc-test 。
在一些对外服务提供restful的应用中,根据不同的验证错误返回其实是避免不了。当然实现的方式可以有种,而本文所采用的方式相对来说简单易懂.
作为服务端开发,验证前端传入的参数的合法性是一个必不可少的步骤,但是验证参数是一个基本上是一个体力活,而且冗余代码繁多,也影响代码的可阅读性,所以有没有一个比较优雅的方式来解决这个问题?
这么简单的问题当然早就有大神遇到并且解决了,这一篇文章主要讲一下解决基于spring-boot的验证参数的比较好的方法:利用validator-api来进行验证参数.
在spring-boot-starter-web包里面有hibernate-validator包,它提供了一系列验证各种参数的方法,所以说spring-boot已经帮我们想好要怎么解决这个问题了.
这篇文章针对spring-boot里面的spring-mvc介绍三种方式来验证参数.
先假设我们的restful的接口接受一个GradeAndClassroomModel类型的对象,并且这个类被定义成 。
1
2
3
4
5
6
7
|
@Data
public
class
GradeAndClassroomModel {
@Range
(min =
1
, max =
9
, message =
"年级只能从1-9"
)
private
int
grade;
@Range
(min =
1
, max =
99
, message =
"班级只能从1-99"
)
private
int
classroomNumber;
}
|
利用validator提供的一系列注解,比如本例中的@Range,就可以表示参数的范围和出错时候的提示信息。还有很多其他注解,这里就不一一列出 。
然后我们的Controller层的代码为 。
1
2
3
4
5
6
7
8
|
@RequestMapping
(value =
"/paramErrorTest"
, method = RequestMethod.GET)
public
String paramErrorTest(
@Valid
@ModelAttribute
GradeAndClassroomModel gradeAndClassroomModel,
BindingResult result) {
return
classroomService.getTeacherName(gradeAndClassroomModel.getGrade(), gradeAndClassroomModel.getClassroomNumber());
}
|
其中如果验证出错,result对象里面就会有错误信息,然后可以自己进行处理.
会有人说,就两个参数,为什么要作为对象呢?会不会太麻烦?确实,如果只有少数对象,直接把参数写到Controller层,然后在Controller层进行验证就可以了.
1
2
3
4
5
6
7
8
9
10
11
|
@RequestMapping
(value =
"/teacherName"
, method = RequestMethod.GET)
public
String teacherName(
@Range
(min =
1
, max =
9
, message =
"年级只能从1-9"
)
@RequestParam
(name =
"grade"
, required =
true
)
int
grade,
@Min
(value =
1
, message =
"班级最小只能1"
)
@Max
(value =
99
, message =
"班级最大只能99"
)
@RequestParam
(name =
"classroom"
, required =
true
)
int
classroom) {
return
classroomService.getTeacherName(grade, classroom);
}
|
如果直接把validator提供的注解移除来写到请求参数上面的话是不是就可以了呢?答案是错,为什么这样不能成功的验证参数呢?具体原因大家可以参考官方文档:
上面的文档已经说的很清楚了,所以我们需要创建一个Bean 。
1
2
3
4
|
@Bean
public
MethodValidationPostProcessor methodValidationPostProcessor() {
return
new
MethodValidationPostProcessor();
}
|
然后在类方法上面加上注解@Validated 。
1
2
3
4
5
6
|
@RestController
@RequestMapping
(
"/spring-boot/classroom"
)
@Validated
public
class
ClassroomController {
...
}
|
然后之前没有生效的注解@Range、@Min、@Max等validator包里面提供的注解就可以生效了.
如果validator包里面注解不能满足我们的需求,我们是否可以自己定义参数验证的逻辑。答案是肯定的,我们可以利用 。
1
2
3
4
5
6
7
8
9
|
@Documented
@Retention
(RetentionPolicy.RUNTIME)
@Target
({ElementType.PARAMETER, ElementType.FIELD})
@Constraint
(validatedBy = {Validator.
class
})
public
@interface
ParamValidator {
String message()
default
"Parameter error!"
;
Class<?>[] groups()
default
{};
Class<?
extends
Payload>[] payload()
default
{};
}
|
和 。
1
2
3
|
public
class
Validator
implements
ConstraintValidator<ParamValidator, Object> {
...
}
|
组合进行自定义,具体的例子网上其他文章就很多了,这里就不进行详细的例子了,但是最终使用的时候就是 。
1
2
3
4
5
6
7
8
9
10
|
@RequestMapping
(value =
"/paramValidator"
, method = RequestMethod.GET)
public
String paramValidator(
@ParamValidator
(isRequired =
true
, desc =
"年级"
, range =
"int:1~9"
, message =
"年级只能从1-9"
)
@RequestParam
(name =
"grade"
, required =
true
)
int
grade,
@ParamValidator
(isRequired =
true
, desc =
"班级"
, range =
"int:1~99"
, message =
"班级只能从1-99"
)
@RequestParam
(name =
"classroom"
, required =
true
)
int
classroom) {
return
classroomService.getTeacherName(grade, classroom);
}
|
另外不要忘记方法二里面里面提到的MethodValidationPostProcessor这个bean,如果没有初始化这个bean,自定义的验证方法也不会执行。验证逻辑会失效.
是不是通过这样写注解的方式来验证进行请求的参数,代码逻辑更佳清晰和优雅?表达的含义也会更佳清楚?并且没有了大量重复的类似的验证代码.
Ps:这里的代码都是基于spring-mvc框架来试验的,如果有人并没有使用spring-mvc作为rest框架,而是使用jersey来作为rest框架的话,可能一些细节方面需要调整, 但是这三种方案应该都是可以兼容的.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/shalousun/article/details/80960835 。
最后此篇关于SpringBoot validator参数验证restful自定义错误码响应方式的文章就讲到这里了,如果你想了解更多关于SpringBoot validator参数验证restful自定义错误码响应方式的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
SpringBoot-Admin 服务监控 简单介绍 Spring Boot Actuator 是 Spring Boot 自带的一个功能模块, 提供了一组已经开箱即用的生产环境下常用
我想查找通过关键字匹配字段 nameEnglish 或 nameChinese 的模型列表。我花了一个多小时谷歌搜索但我做不到。请帮忙。 Springboot Mongo 入门示例 https://s
(请注意:在调查 this issue 时,我更好地发现了我在此处介绍的问题根源) 我对 Hibernate 和 SpringBoot 非常陌生。我的项目涉及一个搜索引擎,其中索引(javafx 客户
我最近有一个 Web 应用程序从 springboot 升级到 springboot 2。当我将其部署到 Tomcat 8 时,它似乎启动了,但没有完全启动。 在 localhost.2019-09-
我是 Spring boot 的新手...我在运行 Controller 时遇到问题, Description: Field todoService in com.springboot.todoCon
我有一个SpringBoot应用程序,它使用以下配置与PostgreSQL通信,通过AWS Beanstrik部署:。在我将AWS Aurora证书更新为rds-ca-ecc384-g1之前,一切都很
实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧 尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来 使用 智普AI 只能 在控制
一、介绍 在实际的软件系统开发过程中,由于业务的需求,在代码层面实现数据的脱敏还是远远不够的,往往还需要在数据库层面针对某些关键性的敏感信息,例如:身份证号、银行卡号、手机号、工资等信息进行加密存储
Selenium Selenium是一个用于Web应用程序自动化测试的开源工具套件。它主要用于以下目的: 浏览器自动化:Selenium能够模拟真实用户在不同浏览器(如Chrome、Fire
一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 Ja
SpringBoot:基于redis自定义注解实现后端接口防重复提交校验 一、添加依赖 org.springframework.boot spring
SpringBoot:使用Jackson完成全局序列化配置 一、测试准备 com.fasterxml.jackson.core jackson-cor
springboot:整合rocketmq 一、简易消息操作 生产者整合mq 导入依赖 org.springframework.boot
springboot:常用注解 一、spring常用注解 包扫描+组件标注注解 @Component:泛指各种组件 @Controller、@Service、@Repository都可以称为@Comp
我们经常需要在两个系统之间进行一些数据的交互,这时候我们就需要开发数据交互接口。 一般来说,遇到比较多的接口有HTTP接口、WebService接口、FTP文件传输。今天我要来学习一下在SpringB
背景 近期项目上线,甲方要求通过安全检测才能进行验收,故针对扫描结果对系统进行了一系列的安全加固,本文对一些常见的安全问题及防护策略进行介绍,提供对应的解决方案 跨站脚本攻击 XSS常发生于论坛评论等
1.排除 Spring-boot-starter 默认的日志配置 将原本的 spring-boot-starter 改为 org.springframework.boot
springboot:解决跨域问题 一、跨域简介 URL的组成: // 协议 + 域名(子域名 + 主域名) + 端口号 + 资源地址 http://www.baidu.com:8080/ 只要协
一、自定义Starter 的思路: 创建一个Maven工程,创建三个模块 一个模块为demo-app,一个模块为demo-module,一个模块为demo-module-springboot-star
1.pom.xml 4.0.0 org.springframework.boot spring-boot-starter-parent
我是一名优秀的程序员,十分优秀!