Spring MVC例外処理 – @ControllerAdvice、@ExceptionHandler、HandlerExceptionResolver

Spring MVCの例外処理は、サーバーの例外をクライアントに送信しないようにするために非常に重要です。今日は、@ExceptionHandler@ControllerAdvice、およびHandlerExceptionResolverを使用したSpringの例外処理を見てみましょう。どんなWebアプリケーションも、アプリケーションで未処理の例外がスローされた場合に、コンテナが生成したページを提供したくないため、例外処理のための良い設計が必要です。

Springの例外処理

よく定義された例外処理アプローチを持つことは、どのWebアプリケーションフレームワークにとっても大きなプラスポイントです。それは言うまでもありませんが、Spring MVCフレームワークは、Webアプリケーションでの例外およびエラー処理を実現するための堅牢な方法を提供しています。Spring MVCフレームワークは、以下の方法を提供しています。

  1. Controller Based – コントローラークラスで例外処理メソッドを定義することができます。必要なのは、これらのメソッドに@ExceptionHandlerアノテーションを付けることだけです。このアノテーションは例外クラスを引数として受け取ります。したがって、Exceptionクラスの1つにこれを定義している場合、リクエストハンドラーメソッドによってスローされたすべての例外が処理されます。これらの例外ハンドラーメソッドは他のリクエストハンドラーメソッドと同じように、エラー応答を構築して異なるエラーページで応答することができます。後で例を見ていきますが、JSONエラー応答も送信することができます。複数の例外ハンドラーメソッドが定義されている場合、最も例外クラスに近いハンドラーメソッドが使用されます。例えば、IOExceptionとExceptionの2つのハンドラーメソッドが定義されており、リクエストハンドラーメソッドがIOExceptionをスローする場合、IOExceptionのハンドラーメソッドが実行されます。
  2. Global Exception Handler – 例外処理はクロスカットの関心事であり、アプリケーションのすべてのポイントカットに対して行う必要があります。すでにSpring AOPを見てきましたが、そのためSpringは@ControllerAdviceアノテーションを提供しており、これを使用してグローバルな例外ハンドラーを定義できます。グローバルコントローラーアドバイス内のハンドラーメソッドは、コントローラークラスが例外を処理できない場合に使用されます。
  3. HandlerExceptionResolver – 一般的な例外に対しては、ほとんどの場合、静的ページを提供します。Spring Frameworkは、グローバルな例外ハンドラを作成するために実装できるHandlerExceptionResolverインターフェースを提供しています。この追加のグローバル例外ハンドラの定義方法の背後にある理由は、Springフレームワークがデフォルトの実装クラスも提供しているためであり、これらのクラスをSpringビーンの設定ファイルで定義することで、Springフレームワークの例外処理の利点を得ることができます。SimpleMappingExceptionResolverは、デフォルトの実装クラスであり、exceptionMappingsを構成できるため、特定の例外に使用するリソースを指定できます。また、例外メッセージのログ記録など、アプリケーション固有の変更を含めた独自のグローバルハンドラを作成するために上書きすることもできます。

Spring MVCプロジェクトを作成しましょう。そこでは、Controllerベース、AOPベース、およびException Resolverベースの例外とエラー処理アプローチの実装を見ていきます。また、JSONレスポンスを返す例外ハンドラメソッドも作成します。SpringでJSONが初めての場合は、Spring Restful JSONチュートリアルを読んでください。最終的なプロジェクトは以下の画像のようになります。アプリケーションのすべてのコンポーネントを1つずつ見ていきます。

Springの例外処理Mavenの依存関係

標準のSpring MVCの依存関係に加えて、JSONサポートのためにJackson JSONの依存関係も必要です。最終的な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 MVCの例外処理のデプロイメントディスクリプタ

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>

ほとんどの部分は、WebアプリケーションにSpring Frameworkを接続するためのものですが、404エラーのために定義されたerror-pageを除きます。したがって、アプリケーションが404エラーをスローすると、このページが応答として使用されます。この設定は、Spring Webアプリケーションが404エラーコードをスローしたときにコンテナによって使用されます。

Springの例外処理 – モデルクラス

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.

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;
	}
}

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例外処理 – カスタム例外クラス

アプリケーションで使用するカスタム例外クラスを作成しましょう。

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);
	}
}

注目すべきは、例外クラスに@ResponseStatusアノテーションを使用して、この種類の例外がアプリケーションによってスローされ、例外処理の実装によって処理されたときにアプリケーションによって送信されるHTTPコードを定義できることです。 HTTPステータスを404として設定していることがわかりますが、これに対してエラーページが定義されていますので、ビューを返さない場合はこのタイプの例外に対してアプリケーションがエラーページを使用するはずです。 また、例外ハンドラーメソッドでステータスコードをオーバーライドすることもできます。これは、例外ハンドラーメソッドがビューページを返さない場合のデフォルトのHTTPステータスコードと考えてください。

Spring MVC例外処理コントローラークラスの例外ハンドラー

異なる種類の例外をスローするコントローラークラスを見てみましょう。

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;
	}	
}

EmployeeNotFoundException ハンドラーに注意してください。ModelAndView を返しているため、HTTP ステータスコードは OK (200) として送信されます。もし void を返していたら、HTTP ステータスコードは 404 として送信されていました。この種の実装については、グローバル例外ハンドラーの実装で検討します。コントローラーで EmployeeNotFoundException のみを処理しているため、コントローラーでスローされた他のすべての例外は、グローバル例外ハンドラーによって処理されます。

@ControllerAdvice および @ExceptionHandler

こちらが当社のグローバル例外ハンドラーコントローラークラスです。クラスが @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");
		//404 エラーコードを返します
	}
}

SQLExceptionの場合、httpステータスコード200でdatabase_error.jspをレスポンスページとして返します。IOExceptionの場合、ステータスコード404でvoidを返すため、この場合はerror-pageが使用されます。他の種類の例外はここでは処理していませんが、HandlerExceptionResolverの実装に任せています。

HandlerExceptionResolver

SimpleMappingExceptionResolverを拡張し、そのメソッドをオーバーライドしていますが、ログ記録と異なる種類のビューページを送信するためには、最も重要なメソッドであるresolveExceptionをオーバーライドすることができます。ただし、これはControllerAdviceの実装と同じですので、ここでは行っていません。私達は、私達が処理していない他の例外に対して汎用のエラーページをレスポンスとして返すために、この設定を使用します。

Springの例外処理の設定ファイル

私達のSpringのbean設定ファイルは以下のようになります。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>

私たちのWebアプリケーションでJSONをサポートするために設定されているビーンに注意してください。例外処理に関連する唯一の部分は、simpleMappingExceptionResolverビーンの定義であり、そこではExceptionクラスのビューページとしてgeneric_error.jspを定義しています。これにより、アプリケーションで処理されない任意の例外は、サーバーが生成したエラーページをレスポンスとして送信しないことが確実になります。

Spring MVCの例外処理JSPビューページ

最後の部分、アプリケーションで使用されるビューページを見てみましょう。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は、クライアントリクエストでidが10として渡された場合に有効なデータで応答するために使用されます。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は、我々の実装では、クライアントリクエストでidが3として渡された場合に404のhttpステータスコードのビューを生成するために使用されます。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は、私たちのコントローラクラスのリクエストハンドラメソッドがEmployeeNotFoundExceptionをスローする場合に使用されます。クライアントリクエストでidの値が1の場合には、このページをレスポンスとして取得するはずです。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は、私たちのアプリケーションがSQLExceptionをスローする場合に使用されます。クライアントリクエストでidの値が2の場合には、このページをレスポンスとして取得するはずです。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>

これは、私たちのアプリケーションコードで処理されていない例外が発生した場合に応答として表示されるページであり、simpleMappingExceptionResolverビーンがそれを処理します。クライアントのリクエストのid値が1、2、3、または10以外の場合、このページが応答として表示されるはずです。

Spring MVC例外処理アプリケーションの実行

使用しているサーブレットコンテナにアプリケーションを展開するだけです。この例では、Apache Tomcat 7を使用しています。以下の画像は、idの値に基づいてアプリケーションが返すさまざまな応答ページを示しています。 ID=10、有効な応答です。 ID=1、コントローラーベースの例外ハンドラーが使用されました ID=2、レスポンスとしてビューを使用するグローバル例外ハンドラーが使用されました ID=3、404エラーページが使用されました ID=4、応答ビューにsimpleMappingExceptionResolverが使用されました すべてのケースで期待どおりの応答を得ました。

Spring例外ハンドラJSONレスポンス

チュートリアルはほぼ完了していますが、最後に例外ハンドラメソッドからJSONレスポンスを送信する方法を説明します。アプリケーションにはすべてのJSON依存関係があり、jsonMessageConverterが構成されています。残すは例外ハンドラメソッドを実装するだけです。簡単にするために、EmployeeControllerのhandleEmployeeNotFoundException()メソッドを以下のコードで更新し、アプリケーションを再デプロイしてください。

	@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;
	}

これで、クライアントリクエストでidを1として使用すると、以下の画像に示すようなJSONレスポンスが得られます。これでSpring例外処理とSpring MVC例外処理についての説明は終わりです。アプリケーションは以下のURLからダウンロードして試してみてください。

Spring例外処理プロジェクトのダウンロード

Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-exception-handling-controlleradvice-exceptionhandler-handlerexceptionresolver