使用最新版本的SpringBoot(1.1.3.RELEASE),我正在尝试一个非常简单的休息应用程序。我有一个异常处理程序来处理由输入错误引起的验证错误。如果我发出POST请求,则会触发异常处理程序。但是,如果我有补丁或放置请求,则不会触发。可能会发生什么?
异常处理程序类
@ControllerAdvice
public class DataValidationExceptionHandler {
@ExceptionHandler(value = {ConstraintViolationException.class})
public ResponseEntity handleBadInput(ConstraintViolationException ex) {
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
}
主要应用类
@Configuration
@ComponentScan
@EnableJpaRepositories
@Import(RepositoryRestMvcConfiguration.class)
@EnableTransactionManagement
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
域类
@Entity
public class Company {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Size(min=2, max=100)
@NotBlank
private String name;
@URL
private String website;
//Not including getters and setters...
}
存储库类
@RepositoryRestResource(collectionResourceRel = "companies", path = "companies")
public interface CompanyRepository extends PagingAndSortingRepository<Company, Long> {
}
正确处理此POST请求。该网站应该是一个URL,在此请求中它不是,因此,它正确地生成验证错误并由异常处理程序处理:curl -H "Content-Type:application/json" -X POST -i -d '{"name":"comp1", "website":"www.comp1.com"}' http://localhost:8080/companies
此PUT请求不由异常处理程序处理,尽管它生成与post请求相同的constraintviolationexception - curl -H "Content-Type:application/json" -X PUT -i -d '{"name":"comp1", "website":"www.comp1.com"}' http://localhost:8080/companies/1
发生了什么事?
更新。在POST请求的情况下,由于ExceptionHandler正在接管,因此没有生成堆栈跟踪。在PUT请求的情况下,这里是堆栈跟踪转储
javax.validation.ConstraintViolationException: Validation failed for classes [com.mycompany.domain.Company] during update time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must be a valid URL', propertyPath=website, rootBeanClass=class com.mycompany.domain.Company, messageTemplate='{org.hibernate.validator.constraints.URL.message}'}
]
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:160)
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreUpdate(BeanValidationEventListener.java:103)
at org.hibernate.action.internal.EntityUpdateAction.preUpdate(EntityUpdateAction.java:257)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:134)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
更新2 - 要进行故障排除,我还添加了一个catch-all异常处理程序。对于PUT请求,此catch-all将处理异常而不是我期望的异常(javax.validation.ConstraintViolationException的处理程序)。在查看异常的调试器时,调试器会显示 - org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
@ControllerAdvice
public class SystemExceptionHandler {
@ExceptionHandler(value = {Exception.class})
public ResponseEntity handleBadInput(Exception ex) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
所以看起来Spring将javax.validation.ConstraintViolationException的异常包装到另一个异常中。要查看是否正确处理了包装的异常,我还添加了此处理程序
@ControllerAdvice
public class TransactionExceptionHandler {
@ExceptionHandler(value = {TransactionSystemException.class})
public ResponseEntity handleTxException(TransactionSystemException ex) {
Throwable t = ex.getCause();
if(t instanceof ConstraintViolationException){
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}else {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
问题是即使是TransactionSystemException.class的处理程序也没有处理异常。它只有Exception.class才能处理它。神秘。
更新3 - 我现在在我的智慧结束。异常处理程序没有被正确调用。我的下一个测试是查看是否正确处理了数据库约束违规。在非常简单的公司模型中,数据库的设置对公司名称有唯一约束。因此,如果发生违规,则引发的异常是org.springframework.dao.DataIntegrityViolationException。无法捕获所有Exception.class处理程序以及为org.springframework.dao.DataIntegrityViolationException编写的特定处理程序。 Boot的json输出是这样的。 WHAT ???
{
"cause" : {
"cause" : {
"cause" : {
"cause" : null,
"message" : "Duplicate entry 'comp1' for key 'chk_comp_name_unique'"
},
"message" : "Duplicate entry 'comp1' for key 'chk_comp_name_unique'"
},
"message" : "could not execute statement"
},
"message" : "could not execute statement; SQL [n/a]; constraint [chk_comp_name_unique]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
}
答案 0 :(得分:0)
看起来这将在下一版本的Spring Data Rest中修复。 jira-ticket
我在github repo中看到了代码更改,因此SDR 2.3 RC1(Fowler)可以使用该修复程序。