2010-01-21 53 views
6

Tôi cần hiển thị thông báo tùy chỉnh trong ứng dụng Spring 3.0 của mình. Tôi có một cơ sở dữ liệu với Hibernate và có một số ràng buộc. Tôi có nghi ngờ về cách DataIntegrityViolationException nên được xử lý một cách tốt. Tôi tự hỏi nếu có một cách để ánh xạ các ngoại lệ với một thông điệp được đặt trong một tập tin thuộc tính, vì nó có thể trong xác nhận ràng buộc. Tôi có thể xử lý nó tự động trong bất kỳ cách nào hoặc tôi có để bắt ngoại lệ này trong mỗi bộ điều khiển?Làm thế nào để xử lý DataIntegrityViolationException trong mùa xuân?

Trả lời

7

Sự cố khi hiển thị thông báo thân thiện với người dùng trong trường hợp vi phạm ràng buộc là tên ràng buộc bị mất khi số ConstraintViolationException của Hibernate đang được dịch sang số DataIntegrityViolationException của Spring.

Tuy nhiên, bạn có thể tùy chỉnh logic dịch này. Nếu bạn sử dụng LocalSessionFactoryBean để truy cập Hibernate, bạn có thể cung cấp nó với một tùy chỉnh SQLExceptionTranslator (xem LocalSessionFactoryBean.jdbcExceptionTranslator). Trình dịch ngoại lệ này có thể dịch ConstraintViolationException vào lớp ngoại lệ của riêng bạn, giữ nguyên tên ràng buộc.

4

Mùa xuân 3 cung cấp hai cách để xử lý việc này - HandlerExceptionResolver trong beans.xml của bạn hoặc @ExceptionHandler trong bộ điều khiển của bạn. Cả hai đều làm điều tương tự - họ biến ngoại lệ thành dạng xem để hiển thị.

Cả hai đều được ghi thành tài liệu here.

2

tôi đối xử với DataIntegrityViolationException trong ExceptionInfoHandler, việc tìm kiếm khó khăn DB lần xuất hiện trong thông điệp nguyên nhân gốc rễ và chuyển đổi nó thành thông điệp i18n qua constraintCodeMap:

@ControllerAdvice(annotations = RestController.class) 
@Order(Ordered.HIGHEST_PRECEDENCE + 5) 
public class ExceptionInfoHandler { 

    @Autowired 
    private MessageSource messageSource; 

    private static Map<String, String> constraintCodeMap = new HashMap<String, String>() { 
    { 
     put("users_unique_email_idx", "exception.users.duplicate_email"); 
     put("meals_unique_user_datetime_idx", "exception.meals.duplicate_datetime"); 
    } 
    }; 

    @ResponseStatus(value = HttpStatus.CONFLICT) // 409 
    @ExceptionHandler(DataIntegrityViolationException.class) 
    @ResponseBody 
    public ErrorInfo conflict(HttpServletRequest req, DataIntegrityViolationException e) { 
    String rootMsg = ValidationUtil.getRootCause(e).getMessage(); 
    if (rootMsg != null) { 
     Optional<Map.Entry<String, String>> entry = constraintCodeMap.entrySet().stream() 
       .filter((it) -> rootMsg.contains(it.getKey())) 
       .findAny(); 
     if (entry.isPresent()) { 
      e=new DataIntegrityViolationException(
        messageSource.getMessage(entry.get().getValue(), null, LocaleContextHolder.getLocale()); 
     } 
    } 
    return new ErrorInfo(req, e); 
    } 
    ... 
} 

có thể được mô phỏng trong Java Enterprise training application của tôi bằng cách thêm/user chỉnh sửa với thư trùng lặp hoặc bữa ăn với ngày giờ trùng lặp.

CẬP NHẬT:

giải pháp khác: sử dụng Controller Based Exception Handling:

@RestController 
@RequestMapping("/ajax/admin/users") 
public class AdminAjaxController { 

    @ExceptionHandler(DataIntegrityViolationException.class) 
    public ResponseEntity<ErrorInfo> duplicateEmailException(HttpServletRequest req, DataIntegrityViolationException e) { 
     return exceptionInfoHandler.getErrorInfoResponseEntity(req, e, EXCEPTION_DUPLICATE_EMAIL, HttpStatus.CONFLICT); 
    } 
+0

Bạn đã có một cấu hình khác nhau để có được ràng buộc thân thiện? Ràng buộc của tôi là một cái gì đó như thế này 'UK_6DOTKOTT2KJSP8VW4D0M25FB7_INDEX_4' – LTroya

+0

Có một số cách để tạo ra các ràng buộc có thể đọc được: 1. Trong kịch bản lệnh SQL ban đầu. 2. Tự động tạo DB với tham số 'uniqueConstraints' trong chú thích' @ Table', ví dụ: '@Table (tên =" bữa ăn ", uniqueConstraints = {@UniqueConstraint (columnNames = {" user_id "," date_time "}, name =" meals_unique_user_datetime_idx ")})' – GKislin

Các vấn đề liên quan