Spring Boot에서는 org.hibernate는 처리되지 않습니다.예외.제약 위반예외.
엔티티 클래스에서 이메일을 검증하기 위한 패턴을 정의했습니다.검증 예외 핸들러 클래스에서 ConstraintViolation 핸들러를 추가했습니다.예외.어플리케이션에서는 Spring Boot 1.4.5를 사용하고 있습니다.
Profile.java
@Entity
@EntityListeners(AuditingEntityListener.class)
@Table(name = "profile")
public class Profile extends AuditableEntity {
private static final long serialVersionUID = 8744243251433626827L;
@Column(name = "email", nullable = true, length = 250)
@NotNull
@Pattern(regexp = "^([^ @])+@([^ \\.@]+\\.)+([^ \\.@])+$")
@Size(max = 250)
private String email;
....
}
확인Exception Handler.java
@ControllerAdvice
public class ValidationExceptionHandler extends ResponseEntityExceptionHandler {
private MessageSource messageSource;
@Autowired
public ValidationExceptionHandler(MessageSource messageSource) {
this.messageSource = messageSource;
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex,
WebRequest request) {
List<String> errors = new ArrayList<String>();
....
}
}
코드를 실행하고 유효하지 않은 이메일 주소를 전달하면 다음과 같은 예외가 발생합니다.handleConstraintViolation의 코드는 실행되지 않습니다.예외로 반환된 http 상태는 500이지만 400을 반환하고 싶습니다.내가 어떻게 그걸 할 수 있는지 알기나?
2017-07-12 22:15:07.078 ERROR 55627 --- [nio-9000-exec-2] o.h.c.s.u.c.UserProfileController : Validation failed for classes [org.xxxx.common.service.user.domain.Profile] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must match "^([^ @])+@([^ \.@]+\.)+([^ \.@])+$"', propertyPath=email, rootBeanClass=class org.xxxx.common.service.user.domain.Profile, messageTemplate='{javax.validation.constraints.Pattern.message}'}]
javax.validation.ConstraintViolationException: Validation failed for classes [org.xxxx.common.service.user.domain.Profile] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must match "^([^ @])+@([^ \.@]+\.)+([^ \.@])+$"', propertyPath=email, rootBeanClass=class org.xxxx.common.service.user.domain.Profile, messageTemplate='{javax.validation.constraints.Pattern.message}'}]
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:138)
at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:78)
않다ConstraintViolationException.class
코드 레이어에 전파되지 않기 때문에 하위 레이어에 의해 포착되어 다른 타입으로 래핑 및 재배열됩니다. 웹 는 ""가 .ConstraintViolationException
.
경우에는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.TransactionSystemException
쓰고 @Transactional
과 JpaTransactionManager
때 예외는 트랜잭션에서 " " "로 됩니다."TransactionSystemException
JpaTransactionManager
.
다음과 같은 작업을 수행할 수 있습니다.
@ExceptionHandler({ TransactionSystemException.class })
public ResponseEntity<RestResponseErrorMessage> handleConstraintViolation(Exception ex, WebRequest request) {
Throwable cause = ((TransactionSystemException) ex).getRootCause();
if (cause instanceof ConstraintViolationException) {
Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) cause).getConstraintViolations();
// do something here
}
}
뭔가 덧붙이고 싶은 게 있어요.저도 같은 일을 하려고 했어요 실체를 확인하려고요그리고 컨트롤러의 입력을 확인해주면 스프링은 이미 모든 것을 즉시 사용할 수 있다는 것을 깨달았습니다.
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public ProfileDto createProfile(@Valid ProfileDto profile){
...
}
@Valid
.validation javax.validation annotations를 .
프로파일 사용자 이름에 공백 공간을 허용하지 않는 regexp가 있는 패턴 주석이 있다고 가정합니다.
Spring은 상태 400(부정 요청)과 다음과 같은 바디로 응답을 작성합니다.
{
"timestamp": 1544453370570,
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"Pattern.ProfileDto.username",
"Pattern.username",
"Pattern.java.lang.String",
"Pattern"
],
"arguments": [
{
"codes": [
"profileDto.username",
"username"
],
"arguments": null,
"defaultMessage": "username",
"code": "username"
},
[],
{
"defaultMessage": "^[A-Za-z0-9_\\-.]+$",
"arguments": null,
"codes": [
"^[A-Za-z0-9_\\-.]+$"
]
}
],
"defaultMessage": "must match \"^[A-Za-z0-9_\\-.]+$\"",
"objectName": "profileDto",
"field": "username",
"rejectedValue": "Wr Ong",
"bindingFailure": false,
"code": "Pattern"
}
],
"message": "Validation failed for object='profileDto'. Error count: 1",
"path": "/profile"
}
다음 솔루션은 Spring Boot 2.1.2를 기반으로 합니다.
분명히 말씀드리면...nimai가 이미 올바르게 언급했듯이:
ConstraintViolation을 잡을 수 없습니다.Exception.class는 코드의 해당 계층에 전파되지 않기 때문에 하위 계층에 의해 포착되어 다른 유형으로 래핑 및 재배열됩니다. 따라서 웹 계층에 영향을 미치는 예외가 ConstraintViolation이 아닙니다.예외입니다.
, ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」DataIntegrityViolationException
이는 지속성 레이어의 문제를 지적합니다.하지만 그렇게 멀리 가게 놔두면 안 돼
솔루션
도 이렇게 하세요.@Valid
Ena가 언급한 방법 매개 변수로 지정된 엔티티에 대한 주석.내 버전에서는 이 버전이 누락되었습니다.org.springframework.web.bind.annotation.RequestBody
주석(없음)@RequestBody
에 주석을 달다ProfileDto
에 올바르게 해석할 수 없습니다.ProfileDto
엔티티와 속성으로 인해null
예를 들어, 값입니다.NullPointerException
.):
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public ProfileDto createProfile(@Valid @RequestBody ProfileDto profile){
...
}
그러면 원하는 상태 코드 400과 기본 응답 본문이 함께 반환됩니다.org.springframework.web.bind.MethodArgumentNotValidException
지속성 층에 도달하기도 전에 말이죠.의 처리MethodArgumentNotValidException
에 정의되어 있습니다.org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler
.
이것은 다른 토픽입니다만, 그 후, 그 동작을 덮어쓰기 할 수 있는 옵션이 있습니다.@ControllerAdvice
와 함께@ExceptionHandler(MethodArgumentNotValidException.class)
ErrorMvcAutoConfiguration을 제외할 경우 기본 오류 응답 본문이 최적이 아니며 존재하지도 않으므로 필요에 따라 응답 본문을 맞춤화할 수 있습니다.
주의:의 소재지@ExceptionHandler(MethodArgumentNotValidException.class)
내부@ControllerAdvice
를 확장하다ResponseEntityExceptionHandler
결과물이 되다IllegalStateException
왜냐하면ResponseEntityExceptionHandler
이미 정의되어 있는 예외 핸들러MethodArgumentNotValidException
그래서 그냥 다른 것에 넣으세요.@ControllerAdvice
아무 것도 연장하지 않고 수업할 수 있습니다.
대체 수동 접근법
전자 메일 패턴의 유효성 검사를 수동으로 트리거할 수도 있습니다(수동으로 스프링 주석 유효성 검사 호출 참조).직접 테스트해 본 적은 없지만 개인적으로 이 방식은 컨트롤러 코드를 부풀리기만 할 뿐 현재 필요한 사용 사례가 떠오르지 않기 때문에 좋아하지 않습니다.
나는 그것이 비슷한 문제를 겪고 있는 다른 사람들에게 도움이 되기를 바란다.
ConstraintViolation을 잡을 수 없습니다.Exception.class는 코드의 해당 계층에 전파되지 않기 때문에 하위 계층에 의해 포착되어 다른 유형으로 래핑 및 재배열됩니다.따라서 웹 계층에 영향을 미치는 예외가 ConstraintViolation이 아닙니다.예외.다음과 같은 작업을 수행할 수 있습니다.
@ExceptionHandler({TransactionSystemException.class})
protected ResponseEntity<Object> handlePersistenceException(final Exception ex, final WebRequest request) {
logger.info(ex.getClass().getName());
//
Throwable cause = ((TransactionSystemException) ex).getRootCause();
if (cause instanceof ConstraintViolationException) {
ConstraintViolationException consEx= (ConstraintViolationException) cause;
final List<String> errors = new ArrayList<String>();
for (final ConstraintViolation<?> violation : consEx.getConstraintViolations()) {
errors.add(violation.getPropertyPath() + ": " + violation.getMessage());
}
final ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, consEx.getLocalizedMessage(), errors);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
final ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getLocalizedMessage(), "error occurred");
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
다시 한 번 확인해 보겠습니다만,ConstraintViolationException
당신이 원하는 건org.hibernate.exception.ConstraintViolationException
패키지.를 Import한 경우javax.validation.ConstraintViolationException
경험하신 대로 건너뜁니다.
import org.hibernate.exception.ConstraintViolationException;
@RestController
public class FeatureToggleController {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, WebRequest request) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
}
}
이것은 예상대로 호출됩니다.
모든 예외를 선택하고 필요한 예외를 선택합니다.
원인을 특정할 필요가 있다:
while ((cause = resultCause.getCause()) != null && resultCause != cause) { resultCause = cause; }
인스턴스 사용
@ExceptionHandler(Exception.class) protected ResponseEntity<MyException> handleExceptions(Exception e) { String message; Throwable cause, resultCause = e; while ((cause = resultCause.getCause()) != null && resultCause != cause) { resultCause = cause; } if (resultCause instanceof ConstraintViolationException) { message = (((ConstraintViolationException) resultCause).getConstraintViolations()).iterator().next().getMessage(); } else { resultCause.printStackTrace(); message = "Unknown error"; } return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(new MyException(message)); }
그게 내 해결책이야
@ExceptionHandler({DataIntegrityViolationException.class})
protected ResponseEntity<Object> handlePersistenceException(final DataIntegrityViolationException ex) {
Throwable cause = ex.getRootCause();
if (cause instanceof SQLIntegrityConstraintViolationException) {
SQLIntegrityConstraintViolationException consEx = (SQLIntegrityConstraintViolationException) cause;
final ApiErrorResponse apiError = ApiErrorResponse.newBuilder()
.message(consEx.getLocalizedMessage())
.status(HttpStatus.BAD_REQUEST)
.build();
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
}
final ApiErrorResponse apiError = ApiErrorResponse.newBuilder()
.message(ex.getLocalizedMessage())
.status(HttpStatus.NOT_ACCEPTABLE)
.build();
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
}
@ExceptionHandler(RollbackException.class)
public ResponseEntity<ApiErrorsListResponse> handleNotValidException(RollbackException ex){
String errMessage = ex.getCause().getMessage();
List<String> listErrMessage = getListErrMessage(errMessage);
ApiErrorsListResponse response = ApiErrorsListResponse.newBuilder()
.status(HttpStatus.NOT_ACCEPTABLE)
.errorMessage(listErrMessage)
.build();
return new ResponseEntity<>(response, HttpStatus.NOT_ACCEPTABLE);
}
public static List<String> getListErrMessage(String msg){
Stream<String> stream = Arrays.stream(msg.split("\n"))
.filter(s -> s.contains("\t"))
.map(s -> s.replaceAll("^([^\\{]+)\\{", ""))
.map(s -> s.replaceAll("[\"]", ""))
.map(s -> s.replaceAll("=", ":"))
.map(s -> s.replaceAll("interpolatedMessage", "message"))
.map(s -> s.replaceAll("\\{|\\}(, *)?", ""));
return stream.collect(Collectors.toList());
}
- 콩
public class ApiErrorsListResponse {
private HttpStatus status;
private List<String> errorMessage;
public ApiErrorsListResponse() {
}
...
}
이렇게 해보세요.
@ControllerAdvice
public class ControllerAdvisor extends ResponseEntityExceptionHandler {
@Autowired
BaseResponse baseResponse;
@ExceptionHandler(javax.validation.ConstraintViolationException.class)
public ResponseEntity<BaseResponse> inputValidationException(Exception e) {
baseResponse.setMessage("Invalid Input : " + e.getMessage());
return new ResponseEntity<BaseResponse>(baseResponse, HttpStatus.BAD_REQUEST);
}
}
더해야 할 것 같아요.@ResponseStatus(HttpStatus.BAD_REQUEST)
고객님께@ExceptionHandler
:
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<String>();
....
}
@ResponseBody
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
@ExceptionHandler(DataIntegrityViolationException.class)
public Map errorHandler(DataIntegrityViolationException ex) {
Map map = new HashMap();
map.put("rs_code", 422);
map.put("rs_msg", "data existed !");
return map;
}
그냥 잡는다org.springframework.dao.DataIntegrityViolationException
.
org.hibernate를 처리할 수 있습니다.예외.제약 위반@controllerAdvice에 추가함으로써 예외입니다.
@ExceptionHandler(DataIntegrityViolation)Exception.class) public ResponseEntity handleConstraintViolation예외(예외){
String errorMessage = ex.getMessage();
errorMessage = (null == errorMessage) ? "Internal Server Error" : errorMessage;
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
return new ResponseEntity<ErrorResponseDTO>(
new ErrorResponseDTO( errorMessage ,details), HttpStatus.INTERNAL_SERVER_ERROR);
}
Constraint Violation Constraint Violation 을 잡을 . 및 (「」를 포함)@ResponseStatus
따위를 써서 @ExceptionHandler(YourCustomException.class)
Jpa Repository 。할 때는 .saveAndFlush
methods 에 、 DB 、 block block block block block블럭을 시도합니다.필요에 따라서, 다음과 같이 범용적으로 실시할 수 있습니다.
imports
...
public class ErrorHandler {
public static <T> T execute(Supplier<T> repositorySaveFunction) {
try {
return repositorySaveFunction.get();
} catch (DataIntegrityViolationException e) {
if (e.getCause() instanceof org.hibernate.exception.ConstraintViolationException) {
throw new CustomObjectAlreadyExistException();
}
if (e.getCause() instanceof PropertyValueException) {
var fieldName = ((PropertyValueException) e.getCause()).getPropertyName();
throw new CustomNotNullException(fieldName);
}
throw e;
} catch (javax.validation.ConstraintViolationException e) {
e.getConstraintViolations().forEach(constraintViolation -> {
throw new CustomNotNullException(constraintViolation.getPropertyPath());
});
throw e;
}
}
}
서비스:
imports
...
@Service
@Transactional
public class Service {
private final YourRepository yourRepository;
... constructor
public ObjectToSave save(ObjectToSave objectToSave) {
return execute(() -> yourRepository.saveAndFlush(objectToSave));
}
}
언급URL : https://stackoverflow.com/questions/45070642/springboot-doesnt-handle-org-hibernate-exception-constraintviolationexception
'programing' 카테고리의 다른 글
React Js에서 CSS/Jquery calc 함수 사용 (0) | 2023.03.27 |
---|---|
Sonar 탐지 보고서에서 롬복 클래스 제외 (0) | 2023.03.27 |
Angular의 .$on()이란JS (0) | 2023.03.27 |
Spring Boot에서 파일 업로드를 위한 임시 디렉토리를 지정하는 방법은 무엇입니까? (0) | 2023.03.22 |
최소화 없이 React의 실제 버전을 구축하는 방법은 무엇입니까? (0) | 2023.03.22 |