java spring spring-mvc freemarker

java - ¿Cómo manejar las excepciones lanzadas al renderizar una vista en Spring MVC?



spring-mvc freemarker (3)

No estoy seguro si mi solución funciona con el problema que está teniendo. Solo publicaré la forma en que capturo mis excepciones para asegurarme de que no se muestre ningún rastro de pila dentro del navegador:

Hice una clase AbstractController con un método que manejará un conflicto específico como este:

public class AbstractController { @ResponseStatus(HttpStatus.CONFLICT) @ExceptionHandler({OptimisticLockingFailureException.class}) @ResponseBody public void handleConflict() { //Do something extra if you want } }

De esta forma, cada vez que se produce una excepción, el usuario verá un estado HTTPResponse predeterminado. (por ejemplo, 404 no encontrado, etc.)

Extiendo esta clase en todas mis clases de controladores para asegurarme de que los errores sean redirigidos a AbstractController. De esta forma, no necesito usar ExceptionHandler en un controlador específico, pero puedo agregarlo globalmente a todos mis controladores. (extendiendo la clase AbstractController).

Editar: Después de otra respuesta a su pregunta, noté que está obteniendo errores en su vista. No estoy seguro si de esta manera detectará ese error.

¡¡Espero que esto ayude!!

Tengo una aplicación Spring MVC que usa FreeMarker como tecnología View (pero tal vez la tecnología de visualización realmente no importa para mi pregunta). Necesito interceptar todas las excepciones que puedan lanzarse durante una solicitud.

He implementado un HandlerExceptionResolver pero este resolver solo se ejecuta cuando la excepción se produce dentro de un controlador. Pero cuando un controlador devuelve un ModelAndView y se produce la excepción al representar la vista (debido a que no se encontró una variable o algo así), entonces no se llama a la resolución de excepciones y en su lugar obtengo un seguimiento de la pila en la ventana del navegador.

También intenté usar un método de controlador de excepción dentro del controlador que devuelve la vista y lo anoté con @ExceptionHandler, pero tampoco funciona (lo más probable es que se deba a que la excepción no se emite en el controlador, sino en la vista).

Entonces, ¿hay algún mecanismo Spring en el que pueda registrar un manejador de excepciones que capture errores de visualización?


Podría extender el DispatcherServlet.

En su web.xml reemplace el DispatcherServlet genérico para su propia clase.

<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>com.controller.generic.DispatcherServletHandler</servlet-class> <load-on-startup>1</load-on-startup> </servlet>

Más tarde crea tu propia clase DispatcherServletHandler y se extiende desde DispatcherServlet:

public class DispatcherServletHandler extends DispatcherServlet { private static final String ERROR = "error"; private static final String VIEW_ERROR_PAGE = "/WEB-INF/views/error/view-error.jsp"; @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { try{ super.doService(request, response); } catch(Exception ex) { request.setAttribute(ERROR, ex); request.getRequestDispatcher(VIEW_ERROR_PAGE).forward(request, response); } } }

Y en esa página solo tenemos que mostrar un mensaje al usuario.


Una palabra por adelantado: si solo necesita una página de error "estática" sin mucha lógica y preparación del modelo, bastará con poner una <error-page> -Tag en su web.xml (ver más abajo un ejemplo).

De lo contrario, podría haber mejores formas de hacerlo, pero esto funciona para nosotros:

Usamos un servlet <filter> en el web.xml que capta todas las excepciones y llama a nuestro ErrorHandler personalizado, el mismo que usamos dentro del Spring HandlerExceptionResolver.

<filter> <filter-name>errorHandlerFilter</filter-name> <filter-class>org.example.filter.ErrorHandlerFilter</filter-class> </filter> <filter-mapping> <filter-name>errorHandlerFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

La implementación se ve esencialmente así:

public class ErrorHandlerFilter implements Filter { ErrorHandler errorHandler; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { try { filterChain.doFilter(request, response); } catch (Exception ex) { // call ErrorHandler and dispatch to error jsp String errorMessage = errorHandler.handle(request, response, ex); request.setAttribute("errorMessage", errorMessage); request.getRequestDispatcher("/WEB-INF/jsp/error/dispatch-error.jsp").forward(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { errorHandler = (ErrorHandler) WebApplicationContextUtils .getRequiredWebApplicationContext(filterConfig.getServletContext()) .getBean("defaultErrorHandler"); } // ... }

Creo que esto debería funcionar más o menos igual para las plantillas de FreeMarker. Por supuesto, si su vista de error arroja un error, estará más o menos sin opciones.

Para detectar también errores como 404 y preparar el modelo para él, utilizamos un filtro que se asigna al despachador ERROR :

<filter> <filter-name>errorDispatcherFilter</filter-name> <filter-class>org.example.filter.ErrorDispatcherFilter</filter-class> </filter> <filter-mapping> <filter-name>errorDispatcherFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>ERROR</dispatcher> </filter-mapping> <error-page> <error-code>404</error-code> <location>/WEB-INF/jsp/error/dispatch-error.jsp</location> </error-page> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/WEB-INF/jsp/error/dispatch-error.jsp</location> </error-page>

La implementación de doFilter se ve así:

@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; // handle code(s) final int code = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (code == 404) { final String uri = (String) request.getAttribute("javax.servlet.error.request_uri"); request.setAttribute("errorMessage", "The requested page ''" + uri + "'' could not be found."); } // notify chain filterChain.doFilter(servletRequest, servletResponse); }