Jersey Rest 异常统一处理机制

59 篇文章 0 订阅
55 篇文章 0 订阅

前言:

        异常分为运行时异常和非运行时异常,所谓的运行时异常是指那些不需要异常捕获的异常,总是交由虚拟机接管,如:ArrayIndexOutOfBoundsException,我们在写程序时,并没有使用try..catch来捕获它。

    以前,我们进行项目开发时,习惯性的喜欢使用大量的try...catch...finally方法来进行异常处理,并且,只是将异常信息保存到log日志中即可,并没有将一些异常信息以可读性的方式返回给前端用户。而在一些比较大的项目中,进行异常统一处理是架构师或项目经理必须考虑的问题之一。

    Jersey 提供了统一异常处理机制,使得在发生运行时异常时,自动跳转到相应的异常处理资源中,并将处理结果返回给前端用户。对于程序开发人员而言,不需要编写太多的try...catch块,只需要使用throw关键字将自定义的异常抛出即可。

一、Jersey异常处理统一机制

1、演示项目结构及技术

 

             (1)技术:Spring4.1.4+Jersey2.21+JPA+PostMan,使用Spring Data JPA技术,其中PostMan是测试工具,可以在chrome浏览器中安装该插件,模拟前端向服务端发送请求。

(2)演示案例构建采用Maven

(3)案例结构如下:

 

 

(4)案例异常处理结构图

 

2、业务场景说明

        本项目中,只是 以分页查询中的page页码不能为负数为例,来演示Jersey的统一异常处理机制。当page页码为负数时,抛出UserException运行时异常,交由Jersey统一异常处理资源类ExceptionMappingResource处理,该类解析抛出的异常信息,解析ExceptionKeys定义的常量key,读取配置文件messages_zh_CN.properties定义的中文异常Unicode码,并能够实现参数配置。

 

 

3、代码片段说明

A、messages_zh_CN.properties异常配置内容

 

11110=\u67E5\u8BE2\u8BF7\u6C42\u8D77\u59CB\u9875 {0} \u662F\u8D1F\u6570
其中,{0},表示需要传递一个参数值来为其赋值,“11110”为key,等于号后面的unicode码为返回给前端用户显示的中文异常提示信息

 

B、ExceptionKeys异常key常量定义内容

 

 
  1. package com.spring.jersy.jpa.hibernate.constants;

  2.  
  3. public class ExceptionKeys {

  4.  
  5. // 所有的异常key字符串开头都加了E标识,在后面的解析过程中会截取掉E字符,取E字符后面的编号

  6. // 如下:“E11110”,变成“11110”,才能与messages_zh_CN.properties中的key一一对应

  7. public final static String page_number_greater_zero = "E11110";

  8. }

C、MessageUtil异常信息解析工具类

 

 
  1. package com.spring.jersy.jpa.hibernate.util;

  2.  
  3. import java.text.MessageFormat;

  4. import java.util.PropertyResourceBundle;

  5. import java.util.ResourceBundle;

  6.  
  7. import com.spring.jersy.jpa.hibernate.exception.BaseException;

  8.  
  9. public final class MessageUtil {

  10.  
  11. private static MessageUtil instance = new MessageUtil();

  12.  
  13. // 用于读取资源属性文件(properties)

  14. private ResourceBundle resourceBoudle = null;

  15.  
  16. public static MessageUtil getInstance() {

  17. return instance;

  18. }

  19.  
  20. /**

  21. * 根据异常key获取对应的异常信息

  22. *

  23. * @param exceptionId

  24. * @return

  25. */

  26. public String getMessage(String exceptionId) {

  27. String message = resourceBoudle.getString(getErrorID(exceptionId));

  28. return message;

  29. }

  30.  
  31. /**

  32. * 根据异常获取对应的中文异常

  33. *

  34. * @param e

  35. * @return

  36. */

  37. public String getMessage(BaseException e) {

  38. String message = resourceBoudle.getString(getErrorID(e.getMessage()));

  39. Object[] arguments = e.getValues();

  40. if (arguments != null) {

  41. message = MessageFormat.format(message, arguments);

  42. }

  43. return message;

  44. }

  45.  
  46. private MessageUtil() {

  47. init();

  48. }

  49.  
  50. /**

  51. * 读取、加载存放key/value形式,并被Unicode编码的properties配置信息

  52. */

  53. private void init() {

  54. try {

  55. resourceBoudle = new PropertyResourceBundle(

  56. getClass()

  57. .getClassLoader()

  58. .getResourceAsStream(

  59. "com/spring/jersy/jpa/hibernate/message/messages_zh_CN.properties"));

  60. } catch (Exception ex) {

  61. // LOGGER.error("Error loading messages properties", ex);

  62. }

  63. }

  64.  
  65. /**

  66. * 根据抛出的异常编号截取与配置文件对应的异常编号 编号E11110——>变成11110

  67. *

  68. * @param exceptionID

  69. * :example 编号E11110

  70. * @return:变成11110

  71. */

  72. private String getErrorID(String exceptionID) {

  73. exceptionID = exceptionID.substring(1);

  74. return exceptionID;

  75. }

  76. }

        其中,使用java.util. ResourceBundle类来读取、解析properties文件,使用java.text. MessageFormat类来格式化消息,即将配置文件中的{0}参数自动替换为传递过来的值。

 

D、BaseException异常基类,继承RuntimeException

 
  1. package com.spring.jersy.jpa.hibernate.exception;

  2.  
  3. public class BaseException extends RuntimeException {

  4.  
  5. /**

  6. *

  7. */

  8. private static final long serialVersionUID = 1L;

  9. private Object[] values;

  10.  
  11. private int code = 500;

  12.  
  13. public BaseException() {

  14.  
  15. }

  16.  
  17. public BaseException(String msg) {

  18. super(msg);

  19. }

  20.  
  21. public BaseException(String msg, String... params) {

  22. super(msg);

  23. if (null != params) {

  24. values = new Object[params.length];

  25. for (int i = 0; i < params.length; i++) {

  26. values[i] = params[i];

  27. }

  28. }

  29. }

  30.  
  31. public BaseException(String msg, int code, String... params) {

  32. this(msg, params);

  33. this.code = code;

  34. }

  35.  
  36. public BaseException(String msg, int code) {

  37. super(msg);

  38. this.code = code;

  39. }

  40.  
  41. public BaseException(String message, Throwable cause, String... params) {

  42. super(message, cause);

  43. if (null != params) {

  44. values = new Object[params.length];

  45. for (int i = 0; i < params.length; i++) {

  46. values[i] = params[i];

  47. }

  48. }

  49. }

  50.  
  51. public BaseException(int code, String message, Throwable cause,

  52. String... params) {

  53. this(message, cause, params);

  54. this.code = code;

  55. }

  56.  
  57. public Object[] getValues() {

  58. return values;

  59. }

  60.  
  61. public void setValues(Object[] values) {

  62. this.values = values;

  63. }

  64.  
  65. public int getCode() {

  66. return code;

  67. }

  68.  
  69. public void setCode(int code) {

  70. this.code = code;

  71. }

  72. }

E、用户异常处理类UserException
 
  1. package com.spring.jersy.jpa.hibernate.exception;

  2.  
  3. import com.spring.jersy.jpa.hibernate.constants.ExceptionKeys;

  4.  
  5. public class UserException extends BaseException{

  6.  
  7. /**

  8. *

  9. */

  10. private static final long serialVersionUID = 1L;

  11.  
  12. public UserException(){

  13.  
  14. }

  15.  
  16. public UserException(String... params){

  17. super(ExceptionKeys.page_number_greater_zero,params);

  18. }

  19. }

F、异常统一处理类ExceptionMappingResource

 

 

 
  1. package com.spring.jersy.jpa.hibernate.resource;

  2.  
  3. import javax.ws.rs.core.Response;

  4. import javax.ws.rs.core.Response.ResponseBuilder;

  5. import javax.ws.rs.ext.ExceptionMapper;

  6. import javax.ws.rs.ext.Provider;

  7.  
  8. import com.spring.jersy.jpa.hibernate.bean.ExceptionResponse;

  9. import com.spring.jersy.jpa.hibernate.exception.BaseException;

  10. import com.spring.jersy.jpa.hibernate.util.MessageUtil;

  11.  
  12. /**

  13. * 必须添加该注解使得在程序的任何地方发生运行时异常时,自动的进行异常统一处理

  14. * 同时该类要能够被Jersey扫描到

  15. */

  16. @Provider

  17. public class ExceptionMappingResource implements ExceptionMapper<Exception> {

  18.  
  19. @Override

  20. public Response toResponse(Exception exception) {

  21. ResponseBuilder responseBuilder = null;

  22.  
  23. // 用户自定义的运行时异常处理

  24. if (exception instanceof BaseException) {

  25.  
  26. //获取用户抛出的异常信息

  27. String code = exception.getMessage();

  28.  
  29. //根据异常key获取对应的中文异常信息

  30. String message = MessageUtil.getInstance().getMessage(

  31. (BaseException) exception);

  32. Throwable cause = exception.getCause();

  33. if (cause != null) {

  34. String realReason = cause.getMessage();

  35. message += " 可能的原因是:" + realReason + "";

  36. }

  37.  
  38. //自定义异常返回实体bean类

  39. ExceptionResponse error = new ExceptionResponse();

  40. error.setCode(code);

  41. error.setMessage(message);

  42. error.setStatus("error");

  43.  
  44. responseBuilder = Response.ok(error).status(

  45. ((BaseException) exception).getCode());

  46. }

  47. // 其他异常

  48. else {

  49. ExceptionResponse error = new ExceptionResponse();

  50. error.setCode("E000000");

  51. error.setMessage(exception.getMessage());

  52. error.setStatus("error ");

  53. responseBuilder = Response.ok(error).status(

  54. Response.Status.INTERNAL_SERVER_ERROR);

  55. }

  56. return responseBuilder.build();

  57. }

  58. }

         注意:该类必须被 @Provider注解,且要实现JAX-RS提供的 ExceptionMapper才能时刻跟踪处理项目中抛出的运行时异常,同时,该类需要被放在能够被JPA扫描器扫描到的包中。
G、用户资源类UserResource中的分页查询测试方法

 

 
  1. // 分页查询

  2. @GET

  3. @Path("/findByPage")

  4. @Produces(MediaType.APPLICATION_JSON)

  5. @Consumes(MediaType.APPLICATION_JSON)

  6. public Response findByPage(

  7. @DefaultValue("0") @QueryParam(value = "page") Integer page,

  8. @DefaultValue("10") @QueryParam(value = "pageSize") Integer pageSize) {

  9.  
  10. if (page >= 0) {

  11. List<User> listUser = userSpringDataJpaService.findUserByPage(page,

  12. pageSize);

  13. ResponseBuilder rb = null;

  14. if (listUser == null) {

  15. rb = Response.serverError().status(500);

  16. } else {

  17. rb = Response.ok(listUser).status(200);

  18. }

  19. return rb.build();

  20. } else {

  21. //如果page为负数,则抛出该异常

  22. throw new UserException(page.toString());

  23. }

  24. }

        其中,“page.toString”参数值是用来为messages_zh_CN.properties中的{0}参数赋值的,提示该值是负数。

二、PostMan测试

postman是一个很好的模拟前端发送请求,测试后端代码正确性的测试工具,可以通过chrome浏览器安装插件,界面如下:

 

接下来,我们准备测试Jersey rest统一异常处理机制是否搭建成功,发送如下请求连接:

 

附:

           测试源码:Spring Data JPA+Jersey+TestNG用户CRUD操作案例

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值