spring MVC @ExceptionHandler метод получить тот же вид

моя проблема в том, что я хочу создать метод @ExceptionHandler, который будет захватывать все необработанные исключения. После захвата я хотел бы перенаправить на текущую страницу вместо указания отдельной страницы только для отображения ошибки.

в основном, как мне получить значение someview возвращено что-то вроде и установить его динамически в методе unhandledExceptionHandler ниже.

@ExceptionHandler(Exception.class)
protected ModelAndView unhandledExceptionHandler(Exception ex){
    System.out.println("unhandle exception here!!!");
    ModelAndView mv = new ModelAndView();
    mv.setViewName("currentview");
    mv.addObject("UNHANDLED_ERROR", "UNHANDLED ERROR. PLEASE CONTACT SUPPORT. "+ex.getMessage());
    return mv;
}



@RequestMapping(value = "/somepage", method = RequestMethod.GET)
public String somemethod(HttpSession session) throws Exception {
    String abc = null;
    abc.length();
    return "someview";
}

поэтому в JSP я могу визуализировать это сообщение об ошибке возвращается на текущую страницу что-то вроде этого.

<c:if test="${not empty UNHANDLED_ERROR}">
    <div class="messageError"> ${UNHANDLED_ERROR}</div>
</c:if>

5 ответов


Я не думаю, что есть способ сделать то, что вы просите, потому что в методе обработчика исключений unhandledExceptionHandler нет способа узнать, какое имя представления имеет метод обработчика somemethod вернули бы.

единственный способ-ввести какую-то схему метаданных, чтобы, когда вы окажетесь в обработчике исключений, вы могли выяснить, к какому виду его сопоставить. Но я думаю, что эта схема метаданных будет довольно сложной. Вы можете реализовать такую схему с помощью чтобы узнать, какой исходный url-адрес был доступен при возникновении исключения, это можно сделать с помощью фрагмента кода ниже.

(ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()

как только вы узнаете, какой исходный URL-адрес запроса вы можете перенаправить на него, возможно, используя атрибут flash, чтобы сохранить тот факт, что было исключение и какая ошибка.

основная проблема с метаданными будет возникать, когда у вас есть метод обработчика, который выбирает между различными представлениями что-то как.

@RequestMapping(value = "/somepage", method = RequestMethod.GET)
public String somemethod(HttpSession session) throws Exception {
    String abc = null;
    if(someCondition) {
        abc.length();
        return "someview";
    } else {
        // do some stuff here.
        return "someOtherView";
    }
}

даже зная, что somemethod был источником ошибки, вы не знаете, какая ветвь в операторе if вызвала исключение.


Я не думаю, что вы можете сделать это без изменения всех методов обработчика. Однако вы можете попытаться сделать это "красивым" способом:

1) Вы можете определить свою собственную аннотацию, которая будет принимать имя целевого вида в качестве параметра (например,@ExceptionView)

2) Следующее, что нужно сделать, это пометить ваши методы обработчика, например:

@ExceptionView("someview")
@RequestMapping(value = "/somepage", method = RequestMethod.GET)
    public String somemethod(HttpSession session) throws Exception {
    String abc = null;
    abc.length();
    return "someview";
}

3) После этого вы можете сделать что-то вроде этого в обработчик исключений:

@ExceptionHandler(Exception.class)
protected ModelAndView unhandledExceptionHandler(Exception ex, HandlerMethod hm) {
    String targetView;
    if (hm != null && hm.hasMethodAnnotation(ExceptionView.class)) {
        targetView = hm.getMethodAnnotation(ExceptionView.class).getValue();
    } else {
        targetView = "someRedirectView"; // kind of a fallback
    }
    ModelAndView mv = new ModelAndView();
    mv.setViewName(targetView);
    mv.addObject("UNHANDLED_ERROR", "UNHANDLED ERROR. PLEASE CONTACT SUPPORT. "+ex.getMessage());
    return mv;
}

вместо отправки ошибки на отдельной странице вы можете просто поместить ошибку в объект ModelAndView. В вашем случае вы можете просто поместить try/catch в свой метод контроллера и вернуть тот же вид, что и так:

@RequestMapping(value = "/somepage", method = RequestMethod.GET)
public String somemethod(ModelAndView mv,HttpSession session) throws Exception {
   mv.setViewName("someview");
   try{ 
      String abc = null;
      abc.length();
    } catch(Exception e) {
      mv.addObject("UNHANDLED_ERROR", "UNHANDLED ERROR. PLEASE CONTACT SUPPORT.  "+ex.getMessage());
   }
   return mv;
}

поэтому добавьте ModelAndView в свой метод и верните его.


Я не пробовал это, но на основе документации здесь, мы можем получить объект запроса в обработчик исключений. Возможно, мы не сможем получить представление, связанное с URL-адресом. Получение представления из URL-адреса и состояние/модель представления будут сложной частью.

  @ExceptionHandler(Exception.class)
  public ModelAndView handleError(HttpServletRequest req, Exception ex) {
    logger.error("Request: " + req.getRequestURL() + " raised " + ex);

    ModelAndView mav = new ModelAndView();
    mav.addObject("exception", ex);
    mav.addObject("url", req.getRequestURL());
    mav.setViewName("error");
    return mav;
  }

  1. создать метод контроллера с аннотацией @RequestMethod("/server-error")
  2. создать метод контроллера с аннотацией @ExceptionHandler что будет return "forward:/server-error";