SpringBoot doesn't handle org.hibernate.exception.ConstraintViolationException

后端 未结 11 931
没有蜡笔的小新
没有蜡笔的小新 2020-12-10 01:37

I have defined a pattern for validating email in my Entity class. In my validation exception handler class, I have added handler for ConstraintViolationException. My appli

相关标签:
11条回答
  • 2020-12-10 02:05
    @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;
    }
    

    just catch org.springframework.dao.DataIntegrityViolationException.

    0 讨论(0)
  • 2020-12-10 02:06

    You can handle org.hibernate.exception.ConstraintViolationException by adding this in your @controllerAdvice

    @ExceptionHandler(DataIntegrityViolationException.class) public ResponseEntity handleConstraintViolationException(Exception ex){

        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);
    
    }
    
    0 讨论(0)
  • 2020-12-10 02:09

    Just want to add something. I was trying to do the same thing, validating the entity. Then I realized Spring has already everything out of the box if you validate the controller's input.

    @RequestMapping(value = "/profile", method = RequestMethod.POST)
    public ProfileDto createProfile(@Valid ProfileDto profile){
    ...    
    }
    

    The @Valid annotation will trigger the validation with the javax.validation annotations.

    Suppose you have a Pattern annotation on your profile username with a regexp not allowing whitespaces.

    Spring will build a response with status 400 (bad request) and a body like this one:

    {
        "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"
    }
    
    0 讨论(0)
  • 2020-12-10 02:09

    Just check all Exceptions and select the one you need

    1. Need to determine the cause:

      while ((cause = resultCause.getCause()) != null && resultCause != cause) {
          resultCause = cause;
      }
      
    2. Use instanceof

      @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));
      }
      
    0 讨论(0)
  • 2020-12-10 02:10

    That is my solution...

    @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());
        }
    
    • bean
    
    public class ApiErrorsListResponse {
    
        private HttpStatus status;
    
     private List<String> errorMessage;
    
        public ApiErrorsListResponse() {
        }
    ...
    }
    
    
    0 讨论(0)
  • 2020-12-10 02:11

    I would double check you've imported the right ConstraintViolationException

    The one you want is from the org.hibernate.exception.ConstraintViolationException package. If you've imported the javax.validation.ConstraintViolationException it will be skipped as you've experienced.

    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);
        }
    }
    

    This will be called as expected.

    0 讨论(0)
提交回复
热议问题