Spring boot Spring验证:@模式的ConstraintViolationException由于密码编码

Spring boot Spring验证:@模式的ConstraintViolationException由于密码编码,spring-boot,Spring Boot,我只是在实现一个基本的CRUD服务,其中可以在数据库中创建一个用户,用户的密码与某个正则表达式匹配,并使用BCryptPasswordEncoder进行编码 我的测试失败,因为密码上有一个ConstraintViolationException,表示它不满足regex要求: javax.validation.ConstraintViolationException:在组[javax.validation.groups.Default]的持久化时间内,类[com.hoaxify.hoaxify.u

我只是在实现一个基本的CRUD服务,其中可以在数据库中创建一个用户,用户的密码与某个正则表达式匹配,并使用
BCryptPasswordEncoder
进行编码

我的测试失败,因为密码上有一个
ConstraintViolationException
,表示它不满足regex要求:

javax.validation.ConstraintViolationException:在组[javax.validation.groups.Default]的持久化时间内,类[com.hoaxify.hoaxify.user.user]的验证失败,]
约束冲突列表:[
ConstraintViolationImpl{interpolatedMessage='必须匹配“^(?=.[a-z])(?=.*\d)(?=.[a-z])。{8,50}$”,propertyPath=password,rootBeanClass=class com.hoaxify.hoaxify.user.user,messageTemplate='{javax.validation.constraints.Pattern.message}}
它没有被我的
@ExceptionHandler
捕获,因为它抛出的是
ConstraintViolationException
,而不是
MethodArgumentNotValidException
。我调试发现,当它试图匹配给定的正则表达式时,密码本身的值显示为:
$2a$10$pmRUViwj3Ey4alK0eqT1Dulz4BpGSlSReHyBR28K6bIE4.LZ7nYWG

传入的密码为:
P4ssword

因此,验证似乎是在加密密码而不是原始密码上运行的。我认为验证应该在
createUser
方法中接收的对象上进行,然后再进行任何其他操作

任何关于为什么会发生这种情况以及如何修复的帮助都将不胜感激

注:
  • 验证适用于所有其他字段
用户控制器
@RestController
@请求映射(“{my/path}”)
类用户控制器{
@自动连线
lateinit var userService:userService
@邮戳
fun createUser(@Valid@RequestBody user:user):GenericResponse{
userService.save(用户)
返回GenericResponse(“已保存用户”)
}
@ExceptionHandler(MethodArgumentNotValidException::类)
@ResponseStatus(HttpStatus.BAD_请求)
fun handleValidationException(异常:MethodArgumentNotValidException,请求:HttpServletRequest):ApiError{
val error=APIRROR(400,“验证错误”,request.servletPath)
val bindingResult=异常。bindingResult
bindingResult.fieldErrors.forEach{
错误。validationErrors[it.field]=it.defaultMessage?:“无效”
}
返回错误
}
}
使用者
@实体
类用户(
@身份证
@生成值
val id:Long,
@字段:非空
@字段:大小(最小值=4,最大值=50)
var用户名:String,
@字段:非空
@字段:大小(最小值=4,最大值=50)
变量displayName:String,
@字段:非空
@字段:模式(regexp=“”^(?=.[a-z])(?=..*\d)(?=.[a-z])。{8,50}$“”)
var密码:String
)
用户服务
@服务
类用户服务(
私有val userRepository:userRepository,
私有val passwordEncoder:BCryptPasswordEncoder=BCryptPasswordEncoder()
) {
乐趣保存(用户:用户):用户{
user.password=passwordEncoder.encode(user.password)
返回userRepository.save(用户)
}
}
用户控制器测试 (相关测试)

@测试
有趣的姿势,当你接受时{
val user=user(
0,
“测试用户”,
“测试显示”,
“P4ssword”
)
val响应:ResponseEntity=testRestTemplate.postForEntity(API_USERS_BASE,user,Any::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
}

问题在于,您在控制器中使用的实体与在服务中使用的实体相同。因此,在控制器中,它可以按照您的预期工作。但是在服务中,您使用加密的密码更新未加密的密码并将其保存到数据库中。当您保存到数据库中时,还会检查验证注释,从而触发
常量raintViolationException


最好的选择是为控制器创建一个单独的对象。例如,创建一个类似于
User
实体的
CreateUserRequest
类,但只包含控制器需要的字段。您可以在其中添加验证注释。然后在服务中转换
CreateUserRequest
插件指向
用户
实体。在用户类上,删除
@模式
验证,因为您不想验证加密的密码。

我曾考虑过一个单独的请求DTO,但我下面的视频教程使用的是同一个对象,所有操作都正常,所以我一直在尝试解决这个问题。instructor使用的是Java,而我使用的是Kotlin,所以不确定在操作方式上是否有细微差别。谢谢你让我朝着正确的方向前进