Spring MVC异常处理– @ ControllerAdvice,@ ExceptionHandler,HandlerExceptionResolver

Spring MVC Exception Handling is very important to make sure you are not sending server exceptions to client. Today we will look into Spring Exception Handling using @ExceptionHandler, @ControllerAdvice and HandlerExceptionResolver. Any web application requires good design for exception handling because we don’t want to serve container generated page when any unhandled exception is thrown by our application.

Spring MVC异常处理对于确保不向客户端发送服务器异常非常重要。 今天,我们将研究使用@ ExceptionHandler,@ ControllerAdvice和HandlerExceptionResolver的Spring异常处理。 任何Web应用程序都需要对异常处理进行良好的设计,因为当我们的应用程序抛出任何未处理的异常时,我们不想为容器生成的页面提供服务。

Spring异常处理 (Spring Exception Handling)

Having a well defined exception handling approach is a huge plus point for any web application framework, that being said Spring MVC framework delivers well when it comes to exception and error handling in our web applications.

对于任何Web应用程序框架而言,拥有定义良好的异常处理方法都是一个巨大的优点,也就是说, Spring MVC框架在处理Web应用程序中的异常和错误处理方面提供了很好的支持。

Spring MVC Framework provides following ways to help us achieving robust exception handling.

Spring MVC Framework提供了以下方法来帮助我们实现可靠的异常处理。

  1. Controller Based – We can define exception handler methods in our controller classes. All we need is to annotate these methods with @ExceptionHandler annotation. This annotation takes Exception class as argument. So if we have defined one of these for Exception class, then all the exceptions thrown by our request handler method will have handled.

    These exception handler methods are just like other request handler methods and we can build error response and respond with different error page. We can also send JSON error response, that we will look later on in our example.

    If there are multiple exception handler methods defined, then handler method that is closest to the Exception class is used. For example, if we have two handler methods defined for IOException and Exception and our request handler method throws IOException, then handler method for IOException will get executed.

    基于控制器 –我们可以在控制器类中定义异常处理程序方法。 我们需要的是使用@ExceptionHandler注释对这些方法进行注释。 此注释将Exception类作为参数。 因此,如果我们为Exception类定义了其中一种,那么请求处理程序方法抛出的所有异常都将得到处理。

    这些异常处理程序方法与其他请求处理程序方法一样,我们可以构建错误响应并使用不同的错误页面进行响应。 我们还可以发送JSON错误响应,稍后我们将在示例中进行查看。

    如果定义了多个异常处理程序方法,则使用最接近Exception类的处理程序方法。 例如,如果我们为IOException和Exception定义了两个处理程序方法,并且我们的请求处理程序方法抛出IOException,则将执行IOException的处理程序方法。

  2. Global Exception Handler – Exception Handling is a cross-cutting concern, it should be done for all the pointcuts in our application. We have already looked into Spring AOP and that’s why Spring provides @ControllerAdvice annotation that we can use with any class to define our global exception handler.

    The handler methods in Global Controller Advice is same as Controller based exception handler methods and used when controller class is not able to handle the exception.

    全局异常处理程序 –异常处理是一个跨领域的问题,应该对应用程序中的所有切入点进行处理。 我们已经研究过Spring AOP ,这就是Spring提供@ControllerAdvice批注的原因,我们可以将其与任何类一起使用来定义全局异常处理程序。

    Global Controller Advice中的处理程序方法与基于Controller的异常处理程序方法相同,并且在controller类无法处理异常时使用。

  3. HandlerExceptionResolver – For generic exceptions, most of the times we serve static pages. Spring Framework provides HandlerExceptionResolver interface that we can implement to create global exception handler. The reason behind this additional way to define global exception handler is that Spring framework also provides default implementation classes that we can define in our spring bean configuration file to get spring framework exception handling benefits.

    SimpleMappingExceptionResolver is the default implementation class, it allows us to configure exceptionMappings where we can specify which resource to use for a particular exception. We can also override it to create our own global handler with our application specific changes, such as logging of exception messages.

    HandlerExceptionResolver –对于一般异常,大多数时候我们提供静态页面。 Spring Framework提供了HandlerExceptionResolver接口,我们可以实现HandlerExceptionResolver接口来创建全局异常处理程序。 这种定义全局异常处理程序的其他方法背后的原因是,Spring框架还提供了默认实现类,我们可以在我们的Spring bean配置文件中定义这些默认实现类,以获得Spring框架异常处理的好处。

    SimpleMappingExceptionResolver是默认的实现类,它允许我们配置exceptionMappings,在其中可以指定用于特定异常的资源。 我们还可以覆盖它,以使用我们特定于应用程序的更改来创建自己的全局处理程序,例如记录异常消息。

Let’s create a Spring MVC project where we will look into the implementation of Controller based, AOP Based and Exception Resolver Based exception and error handling approaches. We will also write a exception handler method that will return JSON response. If you are new to JSON in Spring, read Spring Restful JSON Tutorial.

让我们创建一个Spring MVC项目,在其中我们将研究基于控制器,基于AOP和基于异常解析器的异常和错误处理方法的实现。 我们还将编写一个异常处理程序方法,该方法将返回JSON响应。 如果您不熟悉Spring中的JSON ,请阅读Spring Restful JSON Tutorial

Our final project will look like below image, we will look at all the components of our application one by one.

我们的最终项目将如下图所示,我们将逐一查看应用程序的所有组件。

Spring异常处理Maven依赖项 (Spring Exception Handling Maven Dependencies)

Apart from standard Spring MVC dependencies, we would also need Jackson JSON dependency for JSON support.

除了标准的Spring MVC依赖关系,我们还需要Jackson依赖关系来支持JSON。

Our final pom.xml file looks like below.

我们最终的pom.xml文件如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev.spring</groupId>
	<artifactId>SpringExceptionHandling</artifactId>
	<name>SpringExceptionHandling</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
		<org.aspectj-version>1.7.4</org.aspectj-version>
		<org.slf4j-version>1.7.5</org.slf4j-version>
		<jackson.databind-version>2.2.3</jackson.databind-version>
	</properties>
	<dependencies>
		<!-- Jackson -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.databind-version}</version>
		</dependency>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>

		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>

		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.9</version>
				<configuration>
					<additionalProjectnatures>
						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
					</additionalProjectnatures>
					<additionalBuildcommands>
						<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
					</additionalBuildcommands>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<compilerArgument>-Xlint:all</compilerArgument>
					<showWarnings>true</showWarnings>
					<showDeprecation>true</showDeprecation>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>1.2.1</version>
				<configuration>
					<mainClass>org.test.int1.Main</mainClass>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

I have updated Spring Framework, AspectJ, Jackson and slf4j versions to use the latest one.

我已经更新了Spring Framework,AspectJ,Jackson和slf4j版本,以使用最新版本。

Spring MVC异常处理部署描述符 (Spring MVC Exception Handling Deployment Descriptor)

Our web.xml file looks like below.

我们的web.xml文件如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/spring.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<error-page>
		<error-code>404</error-code>
		<location>/resources/404.jsp</location>
	</error-page>
</web-app>

Most of the part is for plugging in Spring Framework for our web application, except the error-page defined for 404 error. So when our application will throw 404 error, this page will be used as response. This configuration is used by container when our spring web application throws 404 error code.

除了为404错误定义的错误页面之外,大部分内容都是用于为我们的Web应用程序插入Spring Framework。 因此,当我们的应用程序抛出404错误时,此页面将用作响应。 当我们的Spring Web应用程序抛出404错误代码时,容器将使用此配置。

Spring异常处理–模型类 (Spring Exception Handling – Model Classes)

I have defined Employee bean as model class, however we will be using it in our application just to return valid response in specific scenario. We will be deliberately throwing different types of exceptions in most of the cases.

我已经将Employee bean定义为模型类,但是我们将在应用程序中使用它只是为了在特定情况下返回有效响应。 在大多数情况下,我们将故意抛出不同类型的异常。

package com.journaldev.spring.model;

public class Employee {

	private String name;
	private int id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}

Since we will be returning JSON response too, let’s create a java bean with exception details that will be sent as response.

因为我们也将返回JSON响应,所以我们创建一个带有异常详细信息的Java Bean,该异常详细信息将作为响应发送。

package com.journaldev.spring.model;

public class ExceptionJSONInfo {

	private String url;
	private String message;
	
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}

Spring异常处理–自定义异常类 (Spring Exception Handling – Custom Exception Class)

Let’s create a custom exception class to be used by our application.

让我们创建一个供我们的应用程序使用的自定义异常类。

package com.journaldev.spring.exceptions;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Employee Not Found") //404
public class EmployeeNotFoundException extends Exception {

	private static final long serialVersionUID = -3332292346834265371L;

	public EmployeeNotFoundException(int id){
		super("EmployeeNotFoundException with id="+id);
	}
}

Notice that we can use @ResponseStatus annotation with exception classes to define the HTTP code that will be sent by our application when this type of exception is thrown by our application and handled by our exception handling implementations.

注意,我们可以将@ResponseStatus批注与异常类一起使用,以定义当这种类型的异常由应用程序抛出并由异常处理实现处理时,由应用程序发送的HTTP代码。

As you can see that I am setting HTTP status as 404 and we have an error-page defined for this, so our application should use the error page for this type of exception if we are not returning any view.

如您所见,我将HTTP状态设置为404,并且为此定义了一个错误页面,因此,如果我们不返回任何视图,我们的应用程序应针对此类异常使用错误页面。

We can also override the status code in our exception handler method, think of it as default http status code when our exception handler method is not returning any view page as response.

我们还可以在异常处理程序方法中覆盖状态代码,当异常处理程序方法不返回任何视图页面作为响应时,将其视为默认的http状态代码。

Spring MVC异常处理控制器类异常处理程序 (Spring MVC Exception Handling Controller Class Exception Handler)

Let’s look at our controller class where we will throw different type of exceptions.

让我们看一下我们的控制器类,在该类中将引发不同类型的异常。

package com.journaldev.spring.controllers;

import java.io.IOException;
import java.sql.SQLException;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.journaldev.spring.exceptions.EmployeeNotFoundException;
import com.journaldev.spring.model.Employee;
import com.journaldev.spring.model.ExceptionJSONInfo;

@Controller
public class EmployeeController {
	
	private static final Logger logger = LoggerFactory.getLogger(EmployeeController.class);
	
	@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
	public String getEmployee(@PathVariable("id") int id, Model model) throws Exception{
		//deliberately throwing different types of exception
		if(id==1){
			throw new EmployeeNotFoundException(id);
		}else if(id==2){
			throw new SQLException("SQLException, id="+id);
		}else if(id==3){
			throw new IOException("IOException, id="+id);
		}else if(id==10){
			Employee emp = new Employee();
			emp.setName("Pankaj");
			emp.setId(id);
			model.addAttribute("employee", emp);
			return "home";
		}else {
			throw new Exception("Generic Exception, id="+id);
		}
		
	}
	
	@ExceptionHandler(EmployeeNotFoundException.class)
	public ModelAndView handleEmployeeNotFoundException(HttpServletRequest request, Exception ex){
		logger.error("Requested URL="+request.getRequestURL());
		logger.error("Exception Raised="+ex);
		
		ModelAndView modelAndView = new ModelAndView();
	    modelAndView.addObject("exception", ex);
	    modelAndView.addObject("url", request.getRequestURL());
	    
	    modelAndView.setViewName("error");
	    return modelAndView;
	}	
}

Notice that for EmployeeNotFoundException handler, I am returning ModelAndView and hence http status code will be sent as OK (200). If it would have been returning void, then http status code would have been sent as 404. We will look into this type of implementation in our global exception handler implementation.

请注意,对于EmployeeNotFoundException处理程序,我将返回ModelAndView,因此http状态代码将以OK的形式发送(200)。 如果返回的是void,那么HTTP状态代码将作为404发送。我们将在我们的全局异常处理程序实现中研究这种类型的实现。

Since I am handling only EmployeeNotFoundException in controller, all other exceptions thrown by our controller will be handled by global exception handler.

由于我仅在控制器中处理EmployeeNotFoundException,因此控制器抛出的所有其他异常将由全局异常处理程序处理。

@ControllerAdvice和@ExceptionHandler (@ControllerAdvice and @ExceptionHandler)

Here is our global exception handler controller class. Notice the class is annotated with @ControllerAdvice annotation. Also methods are annotated with @ExceptionHandler annotation.

这是我们的全局异常处理程序控制器类。 请注意,该类使用@ControllerAdvice注释进行了注释。 方法也使用@ExceptionHandler注释进行注释。

package com.journaldev.spring.controllers;

import java.io.IOException;
import java.sql.SQLException;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class GlobalExceptionHandler {

	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	@ExceptionHandler(SQLException.class)
	public String handleSQLException(HttpServletRequest request, Exception ex){
		logger.info("SQLException Occured:: URL="+request.getRequestURL());
		return "database_error";
	}
	
	@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
	@ExceptionHandler(IOException.class)
	public void handleIOException(){
		logger.error("IOException handler executed");
		//returning 404 error code
	}
}

Notice that for SQLException, I am returning database_error.jsp as response page with http status code as 200.

请注意,对于SQLException,我将返回http_状态代码为200的database_error.jsp作为响应页面。

For IOException, we are returning void with status code as 404, so our error-page will be used in this case.

对于IOException,我们返回的状态代码为404的void,因此在这种情况下将使用错误页面。

As you can see that I am not handling any other types of exception here, that part I have left for HandlerExceptionResolver implementation.

如您所见,我在这里不处理任何其他类型的异常,这部分我留给HandlerExceptionResolver实现。

HandlerExceptionResolver (HandlerExceptionResolver)

We are just extending SimpleMappingExceptionResolver and overriding one of the method, but we can override it’s most important method resolveException for logging and sending different types of view pages. But that is same as using ControllerAdvice implementation, so I am leaving it. We will be using it to configure view page for all the other exceptions not handled by us by responding with generic error page.

我们只是扩展SimpleMappingExceptionResolver并覆盖其中一种方法,但是我们可以覆盖它最重要的方法resolveException以记录和发送不同类型的视图页面。 但这与使用ControllerAdvice实现相同,因此我将其保留。 我们将使用它来配置视图页面,以通过响应通用错误页面来配置我们未处理的所有其他异常。

Spring异常处理配置文件 (Spring Exception Handling Configuration File)

Our spring bean configuration file looks like below.

我们的spring bean配置文件如下所示。

spring.xml code:

spring.xml代码:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="https://www.springframework.org/schema/beans"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	
	<beans:bean id="simpleMappingExceptionResolver" class="com.journaldev.spring.resolver.MySimpleMappingExceptionResolver">
		<beans:property name="exceptionMappings">
			<beans:map>
				<beans:entry key="Exception" value="generic_error"></beans:entry>
			</beans:map>
		</beans:property>
		<beans:property name="defaultErrorView" value="generic_error"/>
	</beans:bean>
	
	<!-- Configure to plugin JSON as request and response in method handler -->
	<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
		<beans:property name="messageConverters">
			<beans:list>
				<beans:ref bean="jsonMessageConverter"/>
			</beans:list>
		</beans:property>
	</beans:bean>
	
	<!-- Configure bean to convert JSON to POJO and vice versa -->
	<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
	</beans:bean>
	
	<context:component-scan base-package="com.journaldev.spring" />
	
</beans:beans>

Notice the beans configured for supporting JSON in our web application. The only part related to exception handling is the simpleMappingExceptionResolver bean definition where we are defining generic_error.jsp as the view page for Exception class. This make sure that any exception not handled by our application will not result in sending server generated error page as the response.

注意在我们的Web应用程序中配置为支持JSON的bean。 与异常处理有关的唯一部分是simpleMappingExceptionResolver bean定义,其中我们将generic_error.jsp定义为Exception类的视图页面。 这确保了我们的应用程序未处理的任何异常都不会导致发送服务器生成的错误页面作为响应。

Spring MVC异常处理JSP视图页面 (Spring MVC Exception Handling JSP View Pages)

It’s time to look into the last part of our application, our view pages that will be used in our application.

现在是时候研究应用程序的最后部分,即将在应用程序中使用的视图页面。

home.jsp code:

home.jsp代码:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Home</title>
</head>
<body>
	<h3>Hello ${employee.name}!</h3><br>
	<h4>Your ID is ${employee.id}</h4>  
</body>
</html>

home.jsp is used to respond with valid data, i.e when we get id as 10 in the client request.

home.jsp用于响应有效数据,即当我们在客户端请求中获得ID为10时。

404.jsp code:

404.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>404 Error Page</title>
</head>
<body>

<h2>Resource Not Found Error Occured, please contact support.</h2>

</body>
</html>

404.jsp is used for generating view for 404 http status code, for our implementation this should be the response when we get id as 3 in client request.

404.jsp用于生成404 http状态代码的视图,对于我们的实现,这应该是在客户端请求中将id设为3时的响应。

error.jsp code:

error.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Error Page</title>
</head>
<body>
<h2>Application Error, please contact support.</h2>

<h3>Debug Information:</h3>

Requested URL= ${url}<br><br>

Exception= ${exception.message}<br><br>

<strong>Exception Stack Trace</strong><br>
<c:forEach items="${exception.stackTrace}" var="ste">
	${ste}
</c:forEach>

</body>
</html>

error.jsp is used when our controller class request handler method is throwing EmployeeNotFoundException. We should get this page in response when id value is 1 in the client request.

当我们的控制器类请求处理程序方法抛出EmployeeNotFoundException时,将使用error.jsp。 当客户端请求中id值为1时,我们应该获得此页面作为响应。

database_error.jsp code:

database_error.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Database Error Page</title>
</head>
<body>

<h2>Database Error, please contact support.</h2>

</body>
</html>

database_error.jsp is used when our application is throwing SQLException, as configured in GlobalExceptionHandler class. We should get this page as response when id value is 2 in the client request.

当我们的应用程序抛出GlobalExceptionHandler类中配置SQLException时,将使用database_error.jsp。 当客户端请求中的id值为2时,我们应该获得此页面作为响应。

generic_error.jsp code:

generic_error.jsp代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Generic Error Page</title>
</head>
<body>

<h2>Unknown Error Occured, please contact support.</h2>

</body>
</html>

This should be the page as response when any exception occurs not handled by our application code and simpleMappingExceptionResolver bean takes care of that. We should get this page as response when id value in client request is anything other than 1,2,3 or 10.

当发生任何异常而我们的应用程序代码未处理时,这应该作为响应页面,而simpleMappingExceptionResolver bean会处理该页面。 当客户请求中的id值不是1,2,3或10时,我们应该将此页面作为响应。

运行Spring MVC异常处理应用程序 (Running the Spring MVC Exception Handling Application)

Just deploy the application in the servlet container you are using, I am using Apache Tomcat 7 for this example.

只需将应用程序部署在您正在使用的servlet容器中,本示例就使用Apache Tomcat 7。

Below images show the different response pages returned by our application based on the id value.

下图显示了我们的应用基于id值返回的不同响应页面。

ID=10, valid response.

ID = 10,有效的响应。

ID=1, controller based exception handler used

ID = 1,使用基于控制器的异常处理程序

ID=2, global exception handler used with view as response

ID = 2,全局异常处理程序,将视图用作响应

ID=3, 404 error page used

ID = 3,使用了404错误页面

ID=4, simpleMappingExceptionResolver used for response view

ID = 4,simpleMappingExceptionResolver用于响应视图

As you can see that we got the expected response in all the cases.

如您所见,在所有情况下我们都得到了预期的响应。

Spring异常处理程序JSON响应 (Spring Exception Handler JSON Response)

We are almost done with our tutorial, except the last bit where I will explain how to send JSON response from the exception handler methods.

我们的教程几乎完成,除了最后一部分,我将解释如何从异常处理程序方法发送JSON响应。

Our application has all the JSON dependencies and jsonMessageConverter is configured, all we need to implement the exception handler method.

我们的应用程序具有所有JSON依赖项,并且已配置jsonMessageConverter,这是实现异常处理程序方法所需的全部。

For simplicity, I will rewrite the EmployeeController handleEmployeeNotFoundException() method to return JSON response.

为简单起见,我将重写EmployeeController handleEmployeeNotFoundException()方法以返回JSON响应。

Just update EmployeeController exception handler method with below code and deploy the application again.

只需使用以下代码更新EmployeeController异常处理程序方法,然后再次部署应用程序。

@ExceptionHandler(EmployeeNotFoundException.class)
	public @ResponseBody ExceptionJSONInfo handleEmployeeNotFoundException(HttpServletRequest request, Exception ex){
		
		ExceptionJSONInfo response = new ExceptionJSONInfo();
		response.setUrl(request.getRequestURL().toString());
		response.setMessage(ex.getMessage());
		
		return response;
	}

Now when we use id as 1 in client request, we get following JSON response as shown in the below image.

现在,当我们在客户端请求中将id用作1时,我们将获得以下JSON响应,如下图所示。

That’s all for Spring Exception Handling and Spring MVC Exception Handling, please download the application from below URL and play around with it to learn more.

Spring Exception Handling和Spring MVC Exception Handling就是这样,请从下面的URL下载该应用程序并试用它以了解更多信息。

翻译自: https://www.journaldev.com/2651/spring-mvc-exception-handling-controlleradvice-exceptionhandler-handlerexceptionresolver

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值