2013-07-18 32 views
7

Tôi xử lý ngoại lệ vào mùa xuân bằng cách sử dụng @ExceptionHandler. Bất kỳ ngoại lệ nào được ném bởi bộ điều khiển đều bị bắt bằng cách sử dụng phương thức được chú thích bằng @ExceptionHandler và hành động được thực hiện tương ứng. Để tránh viết @exceptionHandler cho mọi bộ điều khiển tôi đang sử dụng chú thích @ControllerAdvice.xử lý ngoại lệ cho bộ lọc vào mùa xuân

Mọi thứ hoạt động tốt như mong đợi.

Bây giờ tôi có một bộ lọc (Có, không đánh chặn, để xử lý yêu cầu nhất định) được thực hiện bằng cách sử dụng DelegatingFilterProxy và ContextLoaderListener.

Khi tôi đang ném cùng một ngoại lệ từ bộ lọc trên, nó không bị bắt theo cách nó được thực hiện trong trường hợp bộ điều khiển. Nó được ném trực tiếp cho người dùng.

Có gì sai ở đây?

+0

Ngoài ra kiểm tra này http://stackoverflow.com/questions/34595605/how-to-manage-exceptions-thrown-in-filters-in-spring – kopelitsa

+0

Xem ở đây https://stackoverflow.com/questions/34595605/cách-to-quản lý-ngoại lệ-ném-trong-bộ lọc-in-spring/43242424, tôi đã làm việc đó để sử dụng '' '@ ExceptionHanlder''' cho một' '' ngoại lệ''' đã được được ném vào một '' 'Bộ lọc''' – Raf

Trả lời

15

Bộ lọc xảy ra trước khi bộ điều khiển được giải quyết, do đó, ngoại lệ được đưa ra khỏi bộ lọc không thể bị Bộ điều khiển tư vấn điều khiển phát hiện.

Bộ lọc là một phần của servlet và không thực sự là ngăn xếp MVC.

+3

Tôi cho là vậy. Có thể có được bất kỳ xung quanh cho điều này? Chúng tôi có thể autowire đậu mùa xuân trong bộ lọc, điều này có nghĩa là chúng ta có thể sử dụng mùa xuân DI, không phải là toàn bộ stack nhưng một số tính năng của nó. Một cách giải quyết khác (nên tránh mặc dù), trong trường hợp ngoại lệ, bộ lọc bắt chúng và ném vào bộ điều khiển mà lần lượt ném ngoại lệ. Đây chỉ là để duy trì tính nhất quán. –

+0

Có lẽ bạn có thể tạo một bộ lọc với chỉ mục 1 (bộ lọc đầu tiên) mà bắt tất cả các ngoại lệ một cách thủ công kích hoạt ngoại lệ mà bộ điều khiển sử dụng. –

+0

Bạn có thể ném thêm ánh sáng vào "thủ công gây ra ngoại lệ mà bộ điều khiển sử dụng" không? Nó có nghĩa là thực sự gọi một phương pháp điều khiển mà ném ngoại lệ cần thiết. –

2

Có lẽ, bạn muốn đặt mã Trạng thái HTTP là kết quả của ngoại lệ được đưa vào Bộ lọc? Nếu vậy, chỉ cần đặt trạng thái như sau:

HttpServletResponse response = (HttpServletResponse) res; response.setStatus (HttpServletResponse.SC_UNAUTHORIZED);

0

Kiểm tra đoạn mã bên dưới, nó hoạt động cho tôi.

final HttpServletResponseWrapper wrapper = new 
HttpServletResponseWrapper((HttpServletResponse) res);  
wrapper.sendError(HttpServletResponse.SC_UNAUTHORIZED, "<your error msg>");  
res = wrapper.getResponse(); 

Nếu bạn đang sử dụng bộ lọc này bên trong bộ lọc, hãy thêm tuyên bố trả lại khác chain.doFilter(req,res) sẽ ghi đè điều này.

+0

Xin chào, tôi đã chỉnh sửa mã này nhưng tên được hiển thị của người dùng khác. Trên thực tế tôi đã chỉnh sửa mã mà không cần đăng nhập. nhưng sau khi đăng nhập, nó hiển thị tên @Sumner Evans. –

+0

@vijayshegokar, tôi đã chấp nhận chỉnh sửa của bạn, nhưng thực hiện thêm một vài cải tiến. (Xem [toàn bộ lịch sử chỉnh sửa] (http://stackoverflow.com/posts/36138972/revisions)). –

+0

@SumnerEvans, Cảm ơn bạn đã trả lời nhanh và chấp nhận chỉnh sửa của tôi. Nhưng tôi vẫn nghĩ tên của tôi nên được hiển thị ở đây vì tôi đã chỉnh sửa câu trả lời. :) –

0

Nếu, giống như tôi, bạn đang mắc kẹt với mùa xuân 3.1 (chỉ 0,1 vesrsions sau @ControllerAdvice) bạn có thể thử giải pháp này tôi chỉ đưa ra.


Vì vậy, bạn đã từng nghe về giải pháp ngoại lệ, phải không? Nếu chưa, hãy đọc ở đây:

@Component 
public class RestExceptionResolver extends ExceptionHandlerExceptionResolver { 

    @Autowired 
    //If you have multiple handlers make this a list of handlers 
    private RestExceptionHandler restExceptionHandler; 
    /** 
    * This resolver needs to be injected because it is the easiest (maybe only) way of getting the configured MessageConverters 
    */ 
    @Resource 
    private ExceptionHandlerExceptionResolver defaultResolver; 

    @PostConstruct 
    public void afterPropertiesSet() { 
     setMessageConverters(defaultResolver.getMessageConverters()); 
     setOrder(2); // The annotation @Order(2) does not work for this type of component 
     super.afterPropertiesSet(); 
    } 

    @Override 
    protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { 
     ExceptionHandlerMethodResolver methodResolver = new ExceptionHandlerMethodResolver(restExceptionHandler.getClass()); 
     Method method = methodResolver.resolveMethod(exception); 
     if (method != null) { 
      return new ServletInvocableHandlerMethod(restExceptionHandler, method); 
     } 
     return null; 
    } 

    public void setRestExceptionHandler(RestExceptionHandler restExceptionHandler) { 
     this.restExceptionHandler = restExceptionHandler; 
    } 

    public void setDefaultResolver(ExceptionHandlerExceptionResolver defaultResolver) { 
     this.defaultResolver = defaultResolver; 
    } 
} 

Sau đó một handler dụ sẽ trông như thế này

@Component 
public class RestExceptionHandler { 

    @ExceptionHandler(ResourceNotFoundException.class) 
    @ResponseStatus(HttpStatus.NOT_FOUND) 
    @ResponseBody 
    public Map<String, Object> handleException(ResourceNotFoundException e, HttpServletResponse response) { 
     Map<String, Object> error = new HashMap<>(); 
     error.put("error", e.getMessage()); 
     error.put("resource", e.getResource()); 
     return error; 
    } 
} 

Tất nhiên bạn sẽ không quên đăng ký Beens bạn


Sau đó tạo một bộ lọc được gọi trước bộ lọc của bạn (tùy chọn tất cả 'em)

Sau đó, trong bộ lọc

try{ 
    chain.doFilter(request, response); 
catch(Exception e){ 
    exceptionResolver(request, response, exceptionHandler, e); 
    //Make the processing stop here... 
    return; //just in case 
} 
0

Đây là những gì tôi đã làm trong lớp lọc của tôi để ném lỗi:

@Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest req = (HttpServletRequest) request; 
     if (req.getHeader("Content-Type") == null) { 
      HttpServletResponse httpResponse = (HttpServletResponse) response;     
      httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Required headers not specified in the request");    
     } 
     chain.doFilter(request, response); 
    } 
0

Khi ngoại lệ không được huy động từ một bộ điều khiển nhưng một bộ lọc, @ControllerAdvice sẽ không bắt nó.

Vì vậy, giải pháp tốt nhất tôi tìm thấy sau khi tìm kiếm khắp mọi nơi là tạo ra một bộ lọc cho các lỗi nội bộ này:

Thêm nó vào cấu hình của bạn, tôi đang sử dụng một thực hiện WebSecurityConfigurerAdapter:

// Custom JWT based security filter 
httpSecurity 
     .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class); 

// Custom Exception Filter for filter 
httpSecurity 
     .addFilterBefore(exceptionHandlerFilterBean(), JwtAuthenticationTokenFilter.class); 

Lớp lỗi:

public class ApiError { 

    private HttpStatus status; 
    @JsonSerialize(using = LocalDateTimeSerializer.class) 
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss") 
    private LocalDateTime timestamp; 
    private String message; 
    private String debugMessage; 

    private ApiError() { 
     timestamp = LocalDateTime.now(); 
    } 
    public ApiError(HttpStatus status) { 
     this(); 
     this.status = status; 
    } 

    public ApiError(HttpStatus status, Throwable ex) { 
     this(); 
     this.status = status; 
     this.message = "Unexpected error"; 
     this.debugMessage = ex.getLocalizedMessage(); 
    } 

    public ApiError(HttpStatus status, String message, Throwable ex) { 
     this(); 
     this.status = status; 
     this.message = message; 
     this.debugMessage = ex.getLocalizedMessage(); 
    } 

    public String convertToJson() throws JsonProcessingException { 
     if (this == null) { 
      return null; 
     } 
     ObjectMapper mapper = new ObjectMapper(); 
     mapper.registerModule(new JavaTimeModule()); 
     mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 

     return mapper.writeValueAsString(this); 
    } 

    //Setters and getters 
} 
0

Tôi đã tạo ứng dụng của mình bằng r est api, vì vậy tôi giải quyết vấn đề này bằng cách bắt nó trong bộ lọc có thể ném một ngoại lệ và sau đó viết một cái gì đó trở lại. Hãy nhớ rằng phải bao gồm filterChain.doFilter(request, response);.

@Override 
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
    try { 
     // something may throw an exception 
     filterChain.doFilter(request, response); 
    } catch (Exception e) { 
     // ResponseWrapper is a customized class 
     ResponseWrapper responseWrapper = new ResponseWrapper().fail().msg(e.getMessage()); 
     response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); 
     response.getWriter().write(JSON.toJSONString(responseWrapper)); 
    } 
} 
Các vấn đề liên quan