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.xsdhttp://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