1.简介
我们可能已经在Spring中遇到了几种处理RESTful Web服务应用程序中异常的方法。 在本文中,我们将尝试探索可以采取的最佳方法来实现有效的异常处理。
2.问题陈述
让我们创建一个简单的应用程序,该应用程序将在REST URI中标识员工姓名。 如果请求中提供的员工名称是数字,则让我们的应用程序引发一个自定义异常,该异常将通过Exception Handlers处理 ,并相应地将JSON响应返回给客户端。 成功响应将是带有员工详细信息的JSON,而失败响应将是带有errorCode和正确的错误消息的错误JSON。
3.实施
首先让我们检查一下pom文件条目和web.xml的样子–
pom.xml
<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
<!-- Jackson JSON Processor -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>RESTWithSpringMVCException</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
现在让我们检查一下Web应用程序上下文 。
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.jcombat.controller" />
</beans>
现在是时候创建实体类了,一个用于Employee ,另一个用于ErrorResponse ,在我们应用程序中任何层出现任何异常的情况下,都将以JSON的形式返回。
Employee.java
package com.jcombat.bean;
public class Employee {
private String empId;
private String name;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ErrorResponse.java
package com.jcombat.bean;
public class ErrorResponse {
private int errorCode;
private String message;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
我们还需要拥有自己的自定义异常类。 我希望我们所有人都已经知道自定义异常。 让我们快速为我们的应用程序创建一个。
EmployeeException.java
package com.jcombat.exception;
public class EmployeeException extends Exception {
private static final long serialVersionUID = 1L;
private String errorMessage;
public String getErrorMessage() {
return errorMessage;
}
public EmployeeException(String errorMessage) {
super(errorMessage);
this.errorMessage = errorMessage;
}
public EmployeeException() {
super();
}
}
Spring为我们提供了@ExceptionHandler批注,以专门处理控制器中特定或常见类型的异常。
这里最重要的部分是为我们的应用程序编写rest控制器。
DemoController.java
package com.jcombat.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.jcombat.bean.Employee;
import com.jcombat.bean.ErrorResponse;
import com.jcombat.exception.EmployeeException;
@RestController
public class EmployeeController {
@RequestMapping(value = "/{firstName}", method = RequestMethod.GET)
public ResponseEntity<Employee> showMessage(
@PathVariable("firstName") String firstName,
@RequestParam(value = "empId", required = false, defaultValue = "00000") final String empId) throws EmployeeException {
Employee employee = new Employee();
employee.setEmpId(empId);
employee.setFirstName(firstName);
if (StringUtils.isNumeric(firstName)) {
throw new EmployeeException("Invalid employee name requested");
}
return new ResponseEntity<Employee>(employee, HttpStatus.OK);
}
@ExceptionHandler(EmployeeException.class)
public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex) {
ErrorResponse error = new ErrorResponse();
error.setErrorCode(HttpStatus.PRECONDITION_FAILED.value());
error.setMessage(ex.getMessage());
return new ResponseEntity<ErrorResponse>(error, HttpStatus.OK);
}
}
注意控制器中的@ExceptionHandler方法,该方法仅应处理在应用程序的任何层中引发的EmployeeException 。
但是,如果从任何地方抛出NullPointerException怎么办。 为了安全起见,我们必须在应用程序中具有通用的异常处理程序,该处理程序可以处理所有其他异常类型,例如IOException , NullPointerException等。 为此,Spring在版本3.2中引入了@ControllerAdvice ,可以在我们的应用程序中创建Controller Advice类,该类将能够处理所有全局异常情况。
用@ControllerAdvice注释的类将被注册为全局异常处理程序 。
让我们为我们的应用程序创建一个。
ExceptionControllerAdvice.java
package com.jcombat.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import com.jcombat.bean.ErrorResponse;
@ControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex) {
ErrorResponse error = new ErrorResponse();
error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
error.setMessage("Please contact your administrator");
return new ResponseEntity<ErrorResponse>(error, HttpStatus.OK);
}
}
这意味着,如果我们在应用程序中遇到了除自定义异常之外的意外异常,则将准备一个通用错误对象,其中包含通用错误代码和错误消息,并将它们作为错误JSON响应返回。
在早于3.2的Spring版本中,使用单个基本控制器创建,扩展所有单个控制器而不是@ControllerAdvice会是更好的选择。
这里有一些注意事项。 由于缺少Spring 3.0.x提供的支持,在Spring 3.0.x中无法通过ResponseEntity返回错误的JSON响应。 替代方法是将BeanNameViewResolver与ModelAndView一起用作返回类型。 我们将很快为此提供一个示例应用程序。
4.运行应用程序
是时候运行我们创建的应用程序了。
确保我们已将应用程序发布到服务器并启动了它。
现在,在浏览器中点击下面的URI – http:// localhost:8080 / RESTWithSpringMVCException / Ramesh?empId = 1234
让我们看看错误响应的样子。 请注意,我们在EmployeeController中添加了一个IF块,该块检查雇员名字的路径变量是否为数字。 如果是数字,则我们的应用程序将抛出EmployeeException 。 让我们点击下面的URI –
如果需要将电子邮件添加为路径变量之一,那么更好的方法是遍历在上一教程中创建的RESTful服务应用程序 。
5.下载源代码
翻译自: https://www.javacodegeeks.com/2016/01/exception-handling-spring-restful-web-service.html