Поиск по сайту:

Spring Обработка исключений MVC — @ControllerAdvice, @ExceptionHandler, HandlerExceptionResolver


Обработка исключений Spring MVC очень важна, чтобы убедиться, что вы не отправляете исключения сервера клиенту. Сегодня мы рассмотрим Spring Exception Handling с использованием веб-приложения, требующего хорошего дизайна для обработки исключений, потому что мы не хотим обслуживать страницу, сгенерированную контейнером, когда любое необработанное исключение генерируется нашим приложением.

Обработка исключений Spring

Наличие четко определенного подхода к обработке исключений является огромным плюсом для любого фреймворка веб-приложений, который, как говорят, фреймворк Spring MVC хорошо работает, когда дело доходит до обработки исключений и ошибок в наших веб-приложениях. Spring MVC Framework предоставляет следующие способы, которые помогут нам добиться надежной обработки исключений.

  1. На основе контроллера. Мы можем определить методы обработки исключений в наших классах контроллеров. Все, что нам нужно, это аннотировать эти методы аннотацией @ExceptionHandler. Эта аннотация принимает класс Exception в качестве аргумента. Поэтому, если мы определили одно из них для класса Exception, то все исключения, созданные нашим методом обработчика запросов, будут обработаны. Эти методы обработчика исключений аналогичны другим методам обработки запросов, и мы можем создать ответ об ошибке и ответить другой страницей ошибки. Мы также можем отправить ответ об ошибке в формате JSON, который мы рассмотрим позже в нашем примере. Если определено несколько методов обработчика исключений, используется метод обработчика, ближайший к классу Exception. Например, если у нас есть два метода-обработчика, определенные для IOException и Exception, и наш метод-обработчик запросов выдает IOException, то будет выполнен метод-обработчик для IOException.
  2. Глобальный обработчик исключений. Обработка исключений является сквозной задачей, она должна выполняться для всех точек в нашем приложении. Мы уже рассмотрели Spring AOP, и поэтому Spring предоставляет аннотацию @ControllerAdvice, которую мы можем использовать с любым классом для определения нашего глобального обработчика исключений. Методы обработчика в Global Controller Advice аналогичны методам обработчика исключений на основе контроллера и используются, когда класс контроллера не может обработать исключение.
  3. HandlerExceptionResolver — для общих исключений в большинстве случаев мы обслуживаем статические страницы. Spring Framework предоставляет интерфейс HandlerExceptionResolver, который мы можем реализовать для создания глобального обработчика исключений. Причина этого дополнительного способа определения глобального обработчика исключений заключается в том, что среда Spring также предоставляет классы реализации по умолчанию, которые мы можем определить в нашем файле конфигурации bean-компонента Spring, чтобы получить преимущества обработки исключений среды Spring. SimpleMappingExceptionResolver — это класс реализации по умолчанию, он позволяет нам настраивать сопоставления исключений, где мы можем указать, какой ресурс использовать для конкретного исключения. Мы также можем переопределить его, чтобы создать собственный глобальный обработчик с изменениями, специфичными для нашего приложения, такими как регистрация сообщений об исключениях.

Spring Exception Обработка зависимостей Maven

Помимо стандартных зависимостей Spring MVC, нам также понадобится зависимость Jackson JSON для поддержки 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>

Я обновил версии Spring Framework, AspectJ, Jackson и slf4j, чтобы использовать последнюю версию.

Дескриптор развертывания обработки исключений 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>

Большая часть предназначена для подключения Spring Framework для нашего веб-приложения, за исключением страницы ошибок, определенной для ошибки 404. Поэтому, когда наше приложение выдаст ошибку 404, эта страница будет использоваться в качестве ответа. Эта конфигурация используется контейнером, когда наше весеннее веб-приложение выдает код ошибки 404.

Обработка исключений Spring — классы моделей

Я определил bean-компонент Employee как класс модели, однако мы будем использовать его в нашем приложении только для возврата действительного ответа в конкретном сценарии. В большинстве случаев мы будем намеренно генерировать различные типы исключений.

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-бин с подробностями об исключении, которые будут отправлены в качестве ответа.

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 Exception

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

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

Вот наш глобальный класс контроллера обработчика исключений. Обратите внимание, что класс помечен аннотацией @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
	}
}

Обратите внимание, что для SQLException я возвращаю database_error.jsp в качестве страницы ответа с кодом состояния http как 200. Для IOException мы возвращаем void с кодом состояния как 404, поэтому в этом случае будет использоваться наша страница ошибок. Как видите, здесь я не обрабатываю никаких других типов исключений, эту часть я оставил для реализации HandlerExceptionResolver.

HandlerExceptionResolver

Мы просто расширяем SimpleMappingExceptionResolver и переопределяем один из методов, но мы можем переопределить самый важный метод resolveException для регистрации и отправки различных типов страниц просмотра. Но это то же самое, что и использование ControllerAdvice, поэтому я его оставляю. Мы будем использовать его для настройки страницы просмотра для всех других исключений, которые мы не обрабатывали, отвечая общей страницей ошибки.

Файл конфигурации обработки исключений Spring

Наш файл конфигурации bean-компонента Spring выглядит следующим образом. код 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>

Обратите внимание на bean-компоненты, настроенные для поддержки JSON в нашем веб-приложении. Единственная часть, связанная с обработкой исключений, — это определение bean-компонента simpleMappingExceptionResolver, где мы определяем generic_error.jsp как страницу просмотра для класса Exception. Это гарантирует, что любое исключение, не обработанное нашим приложением, не приведет к отправке сгенерированной сервером страницы ошибки в качестве ответа.

Spring MVC Exception Handling JSP View Pages

Пришло время взглянуть на последнюю часть нашего приложения, наши страницы просмотра, которые будут использоваться в нашем приложении. код 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 используется для ответа действительными данными, т.е. когда мы получаем идентификатор 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 используется для создания представления для кода состояния http 404, для нашей реализации это должен быть ответ, когда мы получаем идентификатор 3 в клиентском запросе. Код 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 в клиентском запросе. Код базы данных_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, как настроено в классе GlobalExceptionHandler. Мы должны получить эту страницу в качестве ответа, когда значение 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>

Это должна быть страница в качестве ответа, когда возникает какое-либо исключение, не обработанное нашим кодом приложения, и bean-компонент simpleMappingExceptionResolver позаботится об этом. Мы должны получить эту страницу в качестве ответа, когда значение id в клиентском запросе отличается от 1,2,3 или 10.

Запуск приложения обработки исключений Spring MVC

Ответ JSON обработчика исключений Spring

Мы почти закончили наше руководство, за исключением последней части, где я объясню, как отправить ответ JSON из методов обработчика исключений. В нашем приложении есть все зависимости JSON и настроен jsonMessageConverter — все, что нам нужно для реализации метода обработчика исключений. Для простоты я перепишу метод handleEmployeeNotFoundException() EmployeeController, чтобы он возвращал ответ JSON. Просто обновите метод обработчика исключений 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;
	}

Скачать проект обработки исключений Spring