springboot 单测加入参数_springboot 参数校验

http 接口开发过程中的常用场景为,根据提交的表单数据进行格式校验,包括字段长度、数据类型、范围等等。。如果每次都写一堆 if...else if... 太傻了,所以 Java 提供了一套标准化校验方案 JSR 303,而标准的最佳实践为 Hibernate Validator。

一句话为,通过注解对 bean 进行校验,并返回标准文案。

依赖

spring-boot-starter-web 已经集成了 hibernate-validator, 无需重复引用。

注解

JSR303 定义了一套,在 javax.validation.constraints 包目录下,hibernate-validator 扩展了一套,在 org.hibernate.validator.constraints 包下,下文会介绍如何自定义注解。

在 Bean 的字段中增加注解,代码如下:

public class User implements Serializable {

@Min(1)

private int id;

@Email

private String username;

@NotBlank

@Length(min = 6, max = 36)

private String password;

private Integer age;

public int getId() {

return id;

}

public void setId(int id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public Integer getAge() {

return age;

}

public void setAge(Integer age) {

this.age = age;

}

}

Controller

@Validated 声明对参数进行校验

MessageSource 用来分离错误提示,也可以实现国际化

BindingResult 绑定参数校验结果

@RestController

@RequestMapping("/user")

public class UserApi {

@Autowired

private MessageSource messageSource;

@GetMapping("/{id}")

public Object getInfo(@Validated User user, BindingResult bindingResult) {

Map result = new HashMap<>();

if (bindingResult.hasErrors()) {

List fieldErrors = bindingResult.getFieldErrors();

Locale locale = LocaleContextHolder.getLocale();

StringBuilder errorMessage = new StringBuilder();

fieldErrors.forEach(fieldError -> {

errorMessage.append(fieldError.getField())

.append(":")

.append(messageSource.getMessage(fieldError, locale))

.append(",");

});

result.put("code", 10001);

result.put("message", errorMessage);

} else {

result.put("code", 10000);

result.put("data", user);

}

return result;

}

}

自定义错误提示

框架本身做了错误提示,但是为了友好,通常会自定义提示。

硬编码

可以在 注解中硬编码提示语,如

@Email(message = "用户名必须是邮箱")

private String username;

ValidationMessages.properties

不过不够灵活。在使用 spring-boot 的过程中,我们都熟悉了约定大于配置。可以在 resources 目录下增加 ValidationMessages.properties 文件,并在其中复写

javax.validation.constraints.Min.message=参数最小为{1}

可以实现自定义提示,注意 properties 中文编码问题。@注 1 propertiesEditor

messages.properties

SpringBoot 提供的消息文件默认路径为 resources 下 messages.properties,可以把 ValidationMessages.properties 和 messages.properties 指定为自定义配置文件

在 application.properties 中配置属性

spring.messages.basename=valid

在 resources 目录下创建校验提示文件 valid.properties

org.hibernate.validator.constraints.NotBlank.message={0} can't be blank

user.id.error={0} error

配置 messageSource

@Configuration

public class ValidatorConf {

@Autowired

private MessageSource messageSource;

@Bean

@ConditionalOnClass(MessageSource.class)

public LocalValidatorFactoryBean localValidatorFactoryBean() {

LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();

bean.setProviderClass(HibernateValidator.class);

bean.setValidationMessageSource(messageSource);

return bean;

}

}

简化

需要的校验功能实现了,但是每个 RESTFul 接口都需要增加这些校验代码?每个参数后面都加一个 BindingResult? 显然不合理。懒惰是美德,试着做一次简化。

通过 @RestControllerAdvice 和 @ExceptionHandler 全局捕获 restapi 的 BindException 异常,在 controller 代码中,在需要校验的参数前增加 @Validated

@RestControllerAdvice

public class GlobalValidator {

@Autowired

private MessageSource messageSource;

@ExceptionHandler(BindException.class)

public Object bindError(BindException e) {

Map result = new HashMap<>();

List fieldErrors = e.getFieldErrors();

Locale locale = LocaleContextHolder.getLocale();

StringBuilder errorMessage = new StringBuilder();

fieldErrors.forEach(fieldError -> {

errorMessage.append(fieldError.getField())

.append(":")

.append(messageSource.getMessage(fieldError, locale))

.append(",");

});

result.put("code", 10001);

result.put("message", errorMessage);

return result;

}

}

@RestController

@RequestMapping("/simpleuser")

public class SimpleUserApi {

@GetMapping("/{uid}")

public Object getInfo(@Validated User user) {

Map result = new HashMap<>();

result.put("code", 10000);

result.put("data", user);

return result;

}

}

测试

mockMvc 请求 API 接口,判断返回值 code

@RunWith(SpringRunner.class)

@SpringBootTest

public class ValidatorApiTest {

private MockMvc mockMvc;

@Autowired

private WebApplicationContext context;

@Before

public void setup() {

mockMvc = MockMvcBuilders.webAppContextSetup(context).build();

}

private JSONObject requestApi(String path) throws Exception {

return new JSONObject(mockMvc.perform(MockMvcRequestBuilders.get(path))

.andExpect(MockMvcResultMatchers.status().isOk())

.andDo(MockMvcResultHandlers.print())

.andReturn()

.getResponse()

.getContentAsString());

}

@Test

public void test_user_param_valid() throws Exception {

String rightPath = "/user/" + "12?id=123" + "&password=123456";

assertTrue(10000 == requestApi(rightPath).getInt("code"));

String errorPath = "/user/" + "abc";

assertTrue(10001 == requestApi(errorPath).getInt("code"));

}

@Test

public void test_simpleuser_param_valid() throws Exception {

String rightPath = "/simpleuser/" + "12?id=123" + "&password=123456";

assertTrue(10000 == requestApi(rightPath).getInt("code"));

String errorPath = "/simpleuser/" + "abc";

assertTrue(10001 == requestApi(errorPath).getInt("code"));

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值