java - 验证是否不适用于 Spring Boot 中的 put 请求?
问题描述
我是 spring boot 的新手,正在开发一个简单的 crud 应用程序。我创建了一个学生模型,对少数字段进行了很少的验证,以测试验证是否有效。post
在使用对 的请求创建新学生时/students
,验证正在工作。现在,我希望在更新学生时也可以应用相同的验证,因为创建/更新的字段需要保持一致。我已经配置了一个put
请求以/students/{id}
根据 id 更新学生。但验证不起作用,如果我put
将post
{message:"name should have atleast 4 characters"}
{ "timestamp": "2021-06-29T10:06:52.866+00:00", "status": 500, "error": "Internal Server Error", "trace": "org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:571)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743)\r\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)\r\n\tat com.sun.proxy.$Proxy93.save(Unknown Source)\r\n\tat com.demo.service.Studentservice.updateStudent(Studentservice.java:42)\r\n\tat com.demo.controller.StudentController.updateStudent(StudentController.java:47)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:566)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)\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:894)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\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:1063)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:920)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:684)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:764)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:228)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\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:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\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:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\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:190)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)\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:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1723)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)\r\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:834)\r\nCaused by: javax.persistence.RollbackException: Error while committing the transaction\r\n\tat org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81)\r\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104)\r\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562)\r\n\t... 66 more\r\nCaused by: javax.validation.ConstraintViolationException: Validation failed for classes [com.demo.model.Student] during persist time for groups [javax.validation.groups.Default, ]\nList of constraint violations:[\n\tConstraintViolationImpl{interpolatedMessage='name should have min of 4 characters', propertyPath=name, rootBeanClass=class com.demo.model.Student, messageTemplate='name should have min of 4 characters'}\n]\r\n\tat org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140)\r\n\tat org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80)\r\n\tat org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:214)\r\n\tat org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:100)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)\r\n\tat org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)\r\n\tat java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)\r\n\tat org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)\r\n\tat org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:344)\r\n\tat org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)\r\n\tat org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)\r\n\tat org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362)\r\n\tat org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453)\r\n\tat org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3212)\r\n\tat org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2380)\r\n\tat org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:448)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)\r\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)\r\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)\r\n\t... 67 more\r\n", "message": "Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction", "path": "/students/3" }
在我的邮递员...
这是代码的结构:
Student.java
package com.demo.model;
import javax.persistence.*;
import javax.validation.constraints.*;
@Entity
@Table(name="Students")
public class Student {
@Id
private int id;
@Size(min=4,message = "name should have min of 4 characters")
@NotEmpty(message="name should not be null")
private String name;
private int age;
@Email
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
StudentRepository.java
package com.demo.repository;
import com.demo.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends CrudRepository<Student,Integer> {
}
Studentservice.java
package com.demo.service;
import com.demo.errors.StudentNotFoundException;
import com.demo.model.Student;
import com.demo.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class Studentservice {
@Autowired
StudentRepository studentRepository;
//getting all students
public List<Student> getStudents(){
ArrayList<Student> students = new ArrayList<>();
studentRepository.findAll().forEach(students::add);
return students;
}
//find student
public Student getStudent(int id){
return studentRepository.findById(id).orElseThrow(() -> new StudentNotFoundException(id));
}
//create a student
public Student createStudent(Student student){
return studentRepository.save(student);
}
//delete a student
public void deleteStudent(int id){
getStudent(id);
studentRepository.deleteById(id);
}
//update student
public void updateStudent(int id,Student student ){
if(getStudent(id)!=null){
studentRepository.save(student);
}
}
}
StudentController.java
package com.demo.controller;
import com.demo.model.Student;
import com.demo.service.Studentservice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.*;
@RestController
public class StudentController {
@Autowired
Studentservice studentservice;
//get students
@GetMapping("/students")
private List<Student> fetchStudents(){
return studentservice.getStudents();
}
//get student
@GetMapping("/students/{id}")
private ResponseEntity<Object> fetchStudent(@PathVariable("id") int id){
Student found= studentservice.getStudent(id);
return new ResponseEntity<Object>(found,HttpStatus.OK);
}
//create student
@PostMapping("/students")
private ResponseEntity<Object> createStudent(@Valid @RequestBody Student student) {
Student s = studentservice.createStudent(student);
return new ResponseEntity<Object>(s, HttpStatus.CREATED);
}
//delete student
@DeleteMapping("/students/{id}")
private ResponseEntity<Object> deleteStudent(@PathVariable("id") int id){
studentservice.deleteStudent(id);
return new ResponseEntity<Object>("deleted student",HttpStatus.OK);
}
//update student
@PutMapping("/students/{id}")
private ResponseEntity<Object> updateStudent(@Valid @PathVariable("id") int id, @RequestBody Student student){
studentservice.updateStudent(id,student);
return new ResponseEntity<Object>("updated succesfully",HttpStatus.OK);
}
}
StudentNotFoundException.java
package com.demo.errors;
public class StudentNotFoundException extends RuntimeException{
public StudentNotFoundException(int id){
super("Student not found at:"+ id);
}
}
InputValidationHandler.java
package com.demo.errors;
import org.springframework.http.*;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import java.util.*;
@ControllerAdvice
public class InputValidationHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String,String>errors=new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error)->{
String fieldName=((FieldError) error).getField();
String message=error.getDefaultMessage();
errors.put(fieldName,message);
});
return new ResponseEntity<Object>(errors,HttpStatus.BAD_REQUEST);
}
}
解决方案
您必须将 @Valid 注释放在请求正文参数之前,在您的放置端点中,您已将其放在 id 之前,因此验证不起作用
推荐阅读
- cross-compiling - 如何解决mingw-w64不支持参数:-undefined dynamic_lookup
- php - 用 PHP 从 JSON 中提取数据?
- java - 在自定义对象上使用优先级队列的更好方法
- android - 如何在 kotlin 的 android studio 中制作折线图
- r - RStudio 会话在运行 nloptr 时崩溃
- python - 使用带有小数点的`pandas.to_timedelta`
- r - 如何将不带双引号的表/数据框中的字符数据保存为 R 中的 csv 或 txt 文件?
- c# - DynamoDB - 如何使用 ServiceStack.Aws 实现乐观锁定
- c++ - += 运算符后 std::string::begin() 迭代器是否无效?
- python - 循环遍历数据框只返回一列