广告位联系
返回顶部
分享到

Spring Boot统一接口返回及全局异常处理

java 来源:互联网 作者:秩名 发布时间:2022-04-20 21:35:45 人浏览
摘要

前言: 前段时间接手了一个老项目,现在需要在此项目中添加一些新的需求,同事在开发过程中遇到了一些问题? 1.成功的状态到底是200还是0啊,订单系统200代表成功,而会员系统却

前言:

前段时间接手了一个老项目,现在需要在此项目中添加一些新的需求,同事在开发过程中遇到了一些问题?

  • 1.成功的状态到底是200还是0啊,订单系统200代表成功,而会员系统却是0代表成功。
  • 2.接口返回的结果中,有些是用msg字段表示描述,有些又是用desc字段描述,前段处理起来比较麻烦能不能统一。
  • 3.错误提示信息需要支持国际化。

其实这些问题,归根究底还是代码规范问题,我们需要将接口定义和全局异常统一处理,历史项目10多个工程,难道每个工程都去实现一遍,答案可定是不可能的。

1、解决方案

定义公共模块,实现统一接口定义规范和异常处理,其他的系统进行依赖和扩展即可。

2、具体实现

2.1 定义状态码统一接口

1

2

3

4

5

6

7

8

9

10

11

12

13

public interface BaseResultCode

{

    /**

     * 状态码

     * @return

     */

    int getCode();

    /**

     * 提示信息

     * @return

     */

    String getMsg();

}

2.2 公共模块状态码枚举类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public enum ResultCode implements BaseResultCode

{

    OK(200, "成功"),

    ERROR(300,"系统异常"),

    NEED_AUTH(301, "非法请求,请重新登录"),

    PARAMTER_ERROR(302, "参数错误");

    //省略其他定义错误码

    private int code;

    private String msg;

    private ResultCode(int code, String msg)

    {

        this.code = code;

        this.msg = msg;

    }

    public static ResultCode getValue(int code)

    {

        for (ResultCode errorCode : values())

        {

            if (errorCode.getCode() == code)

            {

                return errorCode;

            }

        }

        return null;

    }

   //省略Get、Set方法

 }

2.3 定义全局自定义异常

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

public class SysException extends RuntimeException

{

    private static final long serialVersionUID = 5225171867523879342L;

    private int code;

    private String msg;

    private Object[] params;

    private BaseResultCode errorCode;

    public SysException()

    {

        super();

    }

    public SysException(String message)

    {

        super(message);

    }

    public SysException(Throwable cause)

    {

        super(cause);

    }

    public SysException(int code ,String message)

    {

        this.code = code;

        this.msg = message;

    }

    public SysException(int code ,String message,  Object[] params)

    {

        this(code, message);

        this.params= params;

    }

    public SysException(String message, Throwable cause)

    {

        super(message, cause);

    }

    public SysException(BaseResultCode errorCode)

    {

        this.errorCode = errorCode;

    }

    public SysException(String message, Object[] params)

    {

        super(message);

        this.params = params;

    }

    public SysException(BaseResultCode errorCode, String message, Object[] params)

    {

        this(message, params);

        this.errorCode = errorCode;

    }

     

    /**

     * Construct by default

     *

     * @param message

     *            message

     * @param parameters

     *            parameters

     * @param cause

     *            cause

     */

    public SysException(String message, Object[] params, Throwable cause)

    {

        super(message, cause);

        this.params = params;

    }

 

    public int getCode()

    {

        return code;

    }

    public void setCode(int code)

    {

        this.code = code;

    }

    public String getMsg()

    {

        return msg;

    }

    public void setMsg(String msg)

    {

        this.msg = msg;

    }

    /**

     * @return the params

     */

    public Object[] getParams()

    {

        return params;

    }

    /**

     * @param params

     *            the params to set

     */

    public void setParams(Object[] params)

    {

        this.params = params;

    }

    public BaseResultCode getErrorCode()

    {

        return errorCode;

    }

    public void setErrorCode(BaseResultCode errorCode)

    {

        this.errorCode = errorCode;

    }

     

}

2.4 定义统一接口格式输出类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

public class Result implements Serializable

{

    private static final long serialVersionUID = -1773941471021475043L;

    private Object data;

    private int code;

    private String msg;

    public Result()

    {

    }

    public Result(int code, Object data, String msg)

    {

        this.code = code;

        this.data = data;

        this.msg = msg;

    }

    public Result(int code, String desc)

    {

        this(code, null, desc);

    }

    public Result(BaseResultCode errorCode)

    {

        this(errorCode.getCode(), null, errorCode.getMsg());

    }

    public static Result success()

    {

        return success(null);

    }

    public static Result success(Object data)

    {

        Result result = new Result();

        result.setData(data);

        result.setCode(ResultCode.OK.getCode());

        return result;

    }

    public static Result error(String msg)

    {

        Result result = new Result();

        result.setCode(ResultCode.ERROR.getCode());

        result.setMsg(msg);

        return result;

    }

    public static Result error(BaseResultCode baseCode)

    {

        Result result = new Result();

        result.setCode(baseCode.getCode());

        result.setMsg(baseCode.getMsg());

        return result;

    }

}

个人建议:统一接口输出类不要定义为泛型类型

2.5 定义统一接口格式输出类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

@RestControllerAdvice

public class SysExceptionHandler

{

    public static Log logger = LogManager.getLogger(SysExceptionHandler.class);

    @ExceptionHandler(Exception.class)

    public Result handleException(HttpServletRequest request,

            Exception ex)

    {

        logger.error("Handle Exception Request Url:{},Exception:{}",request.getRequestURL(),ex);

        Result result = new Result();

        //系统异常

        if (ex instanceof SysException)

        {

            SysException se = (SysException) ex;

            BaseResultCode resultCode =se.getErrorCode();

            if(resultCode==null)

            {

                result = Result.error(se.getMessage());

            }

            else

            {

               result = new Result(resultCode.getCode(),

                                       StringUtil.isNotEmpty(se.getMessage())?se.getMessage():resultCode.getMsg());

            }

        }

        //参数错误

        else if (ex instanceof ConstraintViolationException)

        {

            ConstraintViolationException v = (ConstraintViolationException) ex;

            String message = v.getConstraintViolations().iterator().next()

                    .getMessage();

            result.setCode(ResultCode.PARAMTER_ERROR.getCode());

            result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

        }

        //参数错误

        else if (ex instanceof BindException)

        {

            BindException v = (BindException) ex;

            String message = v.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));

            result.setCode(ResultCode.PARAMTER_ERROR.getCode());

            result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

        }

        //参数错误

        else if (ex instanceof MethodArgumentNotValidException)

        {

            MethodArgumentNotValidException v = (MethodArgumentNotValidException) ex;

            String message = v.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));

            result.setCode(ResultCode.PARAMTER_ERROR.getCode());

            result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

        }

        else

        {

           result = new Result(ResultCode.ERROR.getCode(),ExceptionUtil.getErrorMsg(ex));

        }

        logger.info("exception handle reuslt:" + result);

        return result;

    }

}

上述定义已经可以实现全局接口和异常的统一处理,但是存在的如下问题

每个controller都需要返回Reesult类型,且每个方法都需要返回Result.success()或者Result.success(data)的结果,有点重复,需要进行优化。

1

2

3

4

5

6

7

8

9

10

11

12

13

@GetMapping("addUser")

public Result add()

{

   for(int i=0;i<10;i++)

   {

       TUser user = new TUser();

       //user.setOid(IdWorker.getId());

       user.setName("shareing_"+i);

       user.setAge(i);

       userService.addUser(user);

   }

   return Result.success();

}

2.6 接口统一输出优化

实现方式只需要实现ResponseBodyAdvice接口,重写beforeBodyWrite方法接口。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

@RestControllerAdvice

public class ResponseAdvice implements ResponseBodyAdvice<Object>

{

    private Logger logger = LoggerFactory.getLogger(ResponseAdvice.class);

    @Override

    public boolean supports(MethodParameter returnType,

            Class<? extends HttpMessageConverter<?>> converterType)

    {

        return true;

    }

    @Override

    public Object beforeBodyWrite(Object o, MethodParameter returnType,

            MediaType selectedContentType,

            Class<? extends HttpMessageConverter<?>> selectedConverterType,

            ServerHttpRequest request, ServerHttpResponse response)

    {

        logger.info("before body write param:{}",o);

        if(o instanceof String)

        {

           //序列化结果输出

           return FastJsonUtil.toJSONString(Result.success(o));

        }

        else if (o instanceof Result)

        {

             return o;

        }

        return Result.success(o);

    }

}

经过优化后,controller输出可以根据业务的需求定义输出对象。

1

2

3

4

5

6

@GetMapping("getUserByName")

   public TUser getUserByName1(@RequestParam String name)

   {

      logger.info("getUserByName paramter name:"+name);

      return userService.getUserByName(name);

   }

2.7 子系统如何实现

子系统引入common的jar包,

1

2

3

4

5

<dependency>

      <groupId>com.xx</groupId>

      <artifactId>xx-common</artifactId>

      <version>2.0</version>

  </dependency>

3、子系统定义状态码,实现BaseResultCode接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public enum OrderModelErrorCode implements BaseResultCode

{

    ORDER_STATUS_ERROR(1000, "订单状态不正确");

    private int code;

    private String msg;

    private UserModelErrorCode(int code, String msg)

    {

        this.code = code;

        this.msg = msg;

    }

    @Override

    public int getCode()

    {

        return code;

    }

    @Override

    public String getMsg()

    {

        return msg;

    }

}

定义异常处理类,继承公共异常处理类SysExceptionHandler

1

2

3

4

5

6

7

8

9

10

@RestControllerAdvice

public class OrderModalExceptionHandle extends SysExceptionHandler

{

     @Override

    public Result handleException(HttpServletRequest request, Exception ex)

    {

        return super.handleException(request, ex);

        //子系统可以扩展异常处理

    }

}

子系统使用示例:

1

2

3

4

5

6

7

8

9

10

11

@Override

public Order getOrder(String orderId)

{

    Order order =getOrder(orderId);

        //相关伪代码

    if(order.getStatus()>120)

    {

       throw new SysException(OrderModelErrorCode.ORDER_STATUS_ERROR);   

    }

    return order;

}

经过相关项目的重构,已经解决了第一个和第二问题,关于第三个国际化问题,将在后续的文章中讲解。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/7086031796755922981
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计