一、统一处理返回结果和异常处理的原因:

1、在springboot项目里我们希望接口返回的数据包含至少三个属性:

a、code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功,code = "0000",查询结果为null,code = "0001";

b、msg:请求接口的描述,也就是对返回编码的描述,"0000":就表示请求成功,"0001":表示结果为null;

c、data:请求接口成功,返回的结果。


  1. {
  2. "data": {
  3. "id": 1,
  4. "studentId": "13240115",
  5. "name": "Tiger",
  6. "age": 25,
  7. "famillyAddress": "北京",
  8. "createdDate": "2018-10-08T05:45:49.000+0000",
  9. "updatedDate": "2018-10-09T03:15:33.000+0000"
  10. },
  11. "code": "0000",
  12. "msg": "请求成功"
  13. }

2、在springboot项目里我们希望请求结果失败之后,通过返回码和返回描述来告诉前端接口请求异常。


  1. {
  2. "code": "0001",
  3. "msg": "学号不存在"
  4. }

二、案例

1、建一张学生信息表,包含学生的学号、姓名、年龄、家庭住址等


  1. CREATE TABLE student_info (
  2. id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增',
  3. student_id varchar(20) NOT NULL COMMENT '学号',
  4. name varchar(64) NOT NULL COMMENT '姓名',
  5. age int(2) NOT NULL COMMENT '年龄',
  6. familly_address varchar(256) NOT NULL COMMENT '家庭地址',
  7. created_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  8. updated_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  9. PRIMARY KEY (student_id),
  10. KEY id (id)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

2、pom.xml


  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-test</artifactId>
  9. <scope>test</scope>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-data-redis</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.mybatis.spring.boot</groupId>
  17. <artifactId>mybatis-spring-boot-starter</artifactId>
  18. <version>1.3.1</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>mysql</groupId>
  22. <artifactId>mysql-connector-java</artifactId>
  23. <version>5.1.46</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>com.alibaba</groupId>
  27. <artifactId>druid</artifactId>
  28. <version>1.1.9</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.projectlombok</groupId>
  32. <artifactId>lombok</artifactId>
  33. <version>1.16.22</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>com.alibaba</groupId>
  37. <artifactId>fastjson</artifactId>
  38. <version>1.2.43</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>com.squareup.okhttp3</groupId>
  42. <artifactId>okhttp</artifactId>
  43. <version>3.9.1</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.glassfish</groupId>
  47. <artifactId>javax.json</artifactId>
  48. <version>1.0.4</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>org.apache.tomcat.embed</groupId>
  52. <artifactId>tomcat-embed-jasper</artifactId>
  53. </dependency>
  54. </dependencies>

3、案例中使用redis进行缓存,可以不需要

Windows环境安装redis以及缓存应用

4、创建实体类:StudentInfo


  1. package com.dl.cn.message.bean;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Builder;
  4. import lombok.Data;
  5. import lombok.NoArgsConstructor;
  6. import java.io.Serializable;
  7. import java.util.Date;
  8. /**
  9. * Created by Tiger on 2018/10/8.
  10. */
  11. @Data
  12. @Builder
  13. @AllArgsConstructor
  14. @NoArgsConstructor
  15. public class StudentInfo implements Serializable{
  16. private static final long serialVersionUID = 2597547944454691103L;
  17. private Long id;
  18. private String studentId;
  19. private String name;
  20. private Integer age;
  21. private String famillyAddress;
  22. private Date createdDate;
  23. private Date updatedDate;
  24. }

5、创建Mapper:StudentInfoMapper


  1. package com.dl.cn.message.mapper;
  2. import com.dl.cn.message.bean.StudentInfo;
  3. import org.apache.ibatis.annotations.*;
  4. /**
  5. * Created by Tiger on 2018/10/8.
  6. */
  7. @Mapper
  8. public interface StudentInfoMapper {
  9. @Insert("insert into student_info(student_id,name,age,familly_address)" +
  10. " values(#{studentId},#{name},#{age},#{famillyAddress})")
  11. /**
  12. * 通过bean保存实体类是,建议不要通过@Param注解,负责实体类的属性都在@Param中找
  13. * */
  14. void saveStudentInfo(StudentInfo studentInfo);
  15. @Select("select * from student_info where student_id = #{studentId}")
  16. StudentInfo findByStudentId(@Param("studentId") String studentId);
  17. @Update("update student_info set familly_address = #{famillyAddress},updated_date = now() ")
  18. void updateFamillyAddress(@Param("studentId") String studentId,@Param("famillyAddress") String famillyAddress);
  19. }

6、创建service:StudentInfoService


  1. package com.dl.cn.message.service;
  2. import com.dl.cn.message.bean.StudentInfo;
  3. import com.dl.cn.message.mapper.StudentInfoMapper;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheConfig;
  7. import org.springframework.cache.annotation.CacheEvict;
  8. import org.springframework.cache.annotation.Cacheable;
  9. import org.springframework.stereotype.Service;
  10. /**
  11. * Created by Tiger on 2018/10/8.
  12. */
  13. @Service
  14. @CacheConfig(cacheNames = "studentInfo")
  15. @Slf4j
  16. public class StudentInfoService {
  17. @Autowired
  18. StudentInfoMapper studentInfoMapper;
  19. /**
  20. * 保存学生信息
  21. * @param studentInfo
  22. * */
  23. public void saveStudentInfo(StudentInfo studentInfo){
  24. studentInfoMapper.saveStudentInfo(studentInfo);
  25. }
  26. /**
  27. * 根据学号查学生信息
  28. * @param studentId
  29. * @return
  30. * */
  31. @Cacheable(key = "#studentId",unless = "#result == null")
  32. public StudentInfo findByStudentId(String studentId){
  33. log.info("查找信息:{}",studentId);
  34. return studentInfoMapper.findByStudentId(studentId);
  35. }
  36. /**
  37. * 根据学号更新家庭地址
  38. * @param studentId
  39. * @param famillyAddress
  40. * */
  41. //删除对应key的缓存
  42. @CacheEvict(key = "#studentId")
  43. public void updateFamillyAddress(String studentId,String famillyAddress){
  44. studentInfoMapper.updateFamillyAddress(studentId,famillyAddress);
  45. }
  46. }

7、创建统一返回结果类:Response


  1. package com.dl.cn.message.response;
  2. import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  3. import lombok.Getter;
  4. import lombok.Setter;
  5. import java.io.Serializable;
  6. /**
  7. * 请求返回类
  8. * Created by Tiger on 2018/10/9.
  9. */
  10. @Getter
  11. @Setter
  12. @JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
  13. public class Response<T> implements Serializable {
  14. private static final long serialVersionUID = -4505655308965878999L;
  15. //请求成功返回码为:0000
  16. private static final String successCode = "0000";
  17. //返回数据
  18. private T data;
  19. //返回码
  20. private String code;
  21. //返回描述
  22. private String msg;
  23. public Response(){
  24. this.code = successCode;
  25. this.msg = "请求成功";
  26. }
  27. public Response(String code,String msg){
  28. this();
  29. this.code = code;
  30. this.msg = msg;
  31. }
  32. public Response(String code,String msg,T data){
  33. this();
  34. this.code = code;
  35. this.msg = msg;
  36. this.data = data;
  37. }
  38. public Response(T data){
  39. this();
  40. this.data = data;
  41. }
  42. }

8、创建异常编码和描述类:ErrorCodeAndMsg


  1. package com.dl.cn.message.enums;
  2. /**
  3. * Created by Tiger on 2018/10/9.
  4. */
  5. public enum ErrorCodeAndMsg {
  6. Student_number_does_not_exist("0001","学号不存在"),
  7. Insufficient_student_number("0002","学号长度不足"),
  8. Student_number_is_empty("0003","学号为空"),
  9. Network_error("9999","网络错误,待会重试"),
  10. ;
  11. private String code;
  12. private String msg;
  13. ErrorCodeAndMsg(String code, String msg) {
  14. this.code = code;
  15. this.msg = msg;
  16. }
  17. public String getCode() {
  18. return code;
  19. }
  20. public void setCode(String code) {
  21. this.code = code;
  22. }
  23. public String getMsg() {
  24. return msg;
  25. }
  26. public void setMsg(String msg) {
  27. this.msg = msg;
  28. }
  29. }

9、创建统一异常处理类:StudentException


  1. package com.dl.cn.message.exception;
  2. import com.dl.cn.message.enums.ErrorCodeAndMsg;
  3. import java.io.Serializable;
  4. /**
  5. * 统一异常捕获类
  6. * Created by Tiger on 2018/10/9.
  7. */
  8. public class StudentException extends RuntimeException{
  9. private static final long serialVersionUID = -6370612186038915645L;
  10. private final ErrorCodeAndMsg response;
  11. public StudentException(ErrorCodeAndMsg response) {
  12. this.response = response;
  13. }
  14. public ErrorCodeAndMsg getResponse() {
  15. return response;
  16. }
  17. }

10、创建异常处理的全局配置类:ExceptionHandler


  1. package com.dl.cn.message.exception;
  2. import com.dl.cn.message.enums.ErrorCodeAndMsg;
  3. import com.dl.cn.message.response.Response;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.web.bind.annotation.ControllerAdvice;
  6. import org.springframework.web.bind.annotation.ResponseBody;
  7. import javax.servlet.http.HttpServletRequest;
  8. /**
  9. * Created by Tiger on 2018/10/9.
  10. */
  11. @ControllerAdvice
  12. @Slf4j
  13. public class ExceptionHandler {
  14. @org.springframework.web.bind.annotation.ExceptionHandler(StudentException.class)
  15. @ResponseBody
  16. public Response handleStudentException(HttpServletRequest request, StudentException ex) {
  17. Response response;
  18. log.error("StudentException code:{},msg:{}",ex.getResponse().getCode(),ex.getResponse().getMsg());
  19. response = new Response(ex.getResponse().getCode(),ex.getResponse().getMsg());
  20. return response;
  21. }
  22. @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
  23. @ResponseBody
  24. public Response handleException(HttpServletRequest request, Exception ex) {
  25. Response response;
  26. log.error("exception error:{}",ex);
  27. response = new Response(ErrorCodeAndMsg.Network_error.getCode(),
  28. ErrorCodeAndMsg.Network_error.getMsg());
  29. return response;
  30. }
  31. }

11、创建controler类:StudentInofController


  1. package com.dl.cn.message.controller;
  2. import com.dl.cn.message.enums.ErrorCodeAndMsg;
  3. import com.dl.cn.message.exception.StudentException;
  4. import com.dl.cn.message.response.Response;
  5. import com.dl.cn.message.service.StudentInfoService;
  6. import com.dl.cn.message.bean.StudentInfo;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.web.bind.annotation.PostMapping;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RequestParam;
  12. import org.springframework.web.bind.annotation.RestController;
  13. /**
  14. * Created by Tiger on 2018/10/8.
  15. */
  16. @RestController
  17. @RequestMapping("/student")
  18. @Slf4j
  19. public class StudentInofController {
  20. @Autowired
  21. StudentInfoService studentInfoService;
  22. /**
  23. * 保存学生信息
  24. * @param studentId
  25. * @param name
  26. * @param age
  27. * @param famillyAddress
  28. * */
  29. @PostMapping("/save")
  30. public void saveStudentInfo(@RequestParam("student_id") String studentId,
  31. @RequestParam("name") String name,
  32. @RequestParam("age") Integer age,
  33. @RequestParam("familly_address") String famillyAddress){
  34. StudentInfo studentInfo = StudentInfo.builder()
  35. .studentId(studentId)
  36. .name(name)
  37. .age(age)
  38. .famillyAddress(famillyAddress)
  39. .build();
  40. studentInfoService.saveStudentInfo(studentInfo);
  41. }
  42. /**
  43. * 根据学号查学生信息
  44. * @param studentId
  45. * @return
  46. * */
  47. @PostMapping("/findByStudentId")
  48. public Response findByStudentId(@RequestParam("student_id") String studentId){
  49. try{
  50. log.info("Get student information based on student number:{}",studentId);
  51. if(studentId == null){
  52. throw new StudentException(ErrorCodeAndMsg.Student_number_is_empty);
  53. }
  54. //学号固定为8位
  55. if(studentId.length() != 8){
  56. throw new StudentException(ErrorCodeAndMsg.Insufficient_student_number);
  57. }
  58. StudentInfo studentInfo = studentInfoService.findByStudentId(studentId);
  59. if(studentInfo == null){
  60. throw new StudentException(ErrorCodeAndMsg.Student_number_does_not_exist);
  61. }
  62. return new Response(studentInfo);
  63. }catch (Exception e){
  64. if(e instanceof StudentException){
  65. throw e;
  66. }else {
  67. log.error("findByStudentId error:",e);
  68. throw new StudentException(ErrorCodeAndMsg.Network_error);
  69. }
  70. }
  71. }
  72. @PostMapping("/updateFamillyAddress")
  73. public Response updateFamillyAddress(@RequestParam("student_id") String studentId,
  74. @RequestParam("familly_address") String famillyAddress){
  75. studentInfoService.updateFamillyAddress(studentId,famillyAddress);
  76. Response response = new Response();
  77. System.out.println(response.toString());
  78. return response;
  79. }
  80. }

12、application.properties配置


  1. #redis
  2. spring.redis.host=127.0.0.1
  3. spring.redis.port=6379
  4. spring.redis.password=tiger
  5. #mybatis
  6. #开启mybatis驼峰命名,这样可以将mysql中带有下划线的映射成驼峰命名的字段
  7. mybatis.configuration.map-underscore-to-camel-case=true
  8. #datasource
  9. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tiger?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&generateSimpleParameterMetadata=true
  10. spring.datasource.username=tiger
  11. spring.datasource.password=tiger
  12. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  13. spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
  14. spring.datasource.max-idle=10
  15. spring.datasource.max-wait=60000
  16. spring.datasource.min-idle=5
  17. spring.datasource.initial-size=5
  18. spring.datasource.validationQuery=select 'x'

三、说明

1、controller层使用注解@RestController,这样返回结果就是json格式,而@Controller返回结果是字符串

2、throw 异常

如果exception类型是自定义的异常StudentException,直接抛出,如果是其它异常统一抛出网络错误


  1. try{
  2. }catch (Exception e){
  3. if(e instanceof StudentException){
  4. throw e;
  5. }else {
  6. log.error("findByStudentId error:",e);
  7. throw new StudentException(ErrorCodeAndMsg.Network_error);
  8. }
  9. }

3、在返回结果类添加了注解@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)

是因为更新或者删除操作,一般没有返回值,我只需要知道是否更新成功或者删除成功就OK了,如果不加这个注解

我们返回的结果中data为null!!!


  1. {
  2. "data": null,
  3. "code": "0000",
  4. "msg": "请求成功"
  5. }

加上注解再更新数据,返回结果:


  1. {
  2. "code": "0000",
  3. "msg": "请求成功"
  4. }

因此这个注解的作用就是:返回结果中有null值,干掉它!

四、测试结果

mysql数据库中有一条学号为13240115的数据:

1、student_id = "13240115"时


  1. {
  2. "data": {
  3. "id": 1,
  4. "studentId": "13240115",
  5. "name": "Tiger",
  6. "age": 25,
  7. "famillyAddress": "北京",
  8. "createdDate": "2018-10-08T05:45:49.000+0000",
  9. "updatedDate": "2018-10-09T05:36:36.000+0000"
  10. },
  11. "code": "0000",
  12. "msg": "请求成功"
  13. }

2、student_id = "13240114"时


  1. {
  2. "code": "0001",
  3. "msg": "学号不存在"
  4. }

3、student_id = "1324011",不足8位时


  1. {
  2. "code": "0002",
  3. "msg": "学号长度不足"
  4. }

4、student_id = "13240115",然后在接口中加上一行代码,System.out.println(1/0);

返回结果:


  1. {
  2. "code": "9999",
  3. "msg": "网络错误,待会重试"
  4. }

控制台日志:


  1. java.lang.ArithmeticException: / by zero
  2. at com.dl.cn.message.controller.StudentInofController.findByStudentId(StudentInofController.java:54) ~[classes/:na]
  3. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161]
  4. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161]
  5. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161]
  6. at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]
  7. at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) [spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
  8. at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) [spring-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]

通过测试,发现这个小案例满足刚开始我们提出的需求,一定还有很多其它问题,暂时没有发现,我会及时修改,不知道有人是否看我的博客?我只是想把自己的学习成果总结记录下来。人可以成长为芳草,也可以长成杂莠!!!

原文地址:https://blog.csdn.net/qq_31289187/article/details/82980714

springboot2.0-统一处理返回结果和异常情况的更多相关文章

  1. SpringBoot统一处理返回结果和异常情况

    如果文章有帮助到你,还请点个赞或留下评论 原因 在springboot项目里我们希望接口返回的数据包含至少三个属性: code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功. messa ...

  2. ASP.NET Core搭建多层网站架构【11-WebApi统一处理返回值、异常】

    2020/02/01, ASP.NET Core 3.1, VS2019 摘要:基于ASP.NET Core 3.1 WebApi搭建后端多层网站架构[11-WebApi统一处理返回值.异常] 使用I ...

  3. asp.net core webapi 统一处理返回值、异常和请求参数验证

    现在的开发模式很少用asp.net mvc一个项目直接操作界面和数据库了.大部分都使用前后端分离,更多的是为了让API支持移动端. 后端写webapi的时候必然需要和前端约定请求值和返回值的格式,如果 ...

  4. SpringBoot入门教程(六)SpringBoot2.0统一处理404,500等http错误跳转页

    在做web项目的时候,大家对404.500等http状态码肯定并不陌生.然而无论是哪种"非正常"状态码,都不是我们想遇到的.尤其像一些500这种服务器内部错误,不愿意展示给用户的, ...

  5. SpringBoot2.0针对请求参数@RequestBody验证统一拦截

    title: "SpringBoot2.0针对请求参数@RequestBody验证的统一拦截"categories: SpringBoot2.0 Shirotags: Spring ...

  6. springBoot2.0 配置@ControllerAdvice 捕获异常统一处理

    一.前言 基于上一篇 springBoot2.0 配置shiro实现权限管理 这一篇配置 异常统一处理 二.新建文件夹:common,param 三.返回结果集对象 1.ResultData.java ...

  7. SpringBoot2.0 基础案例(03):配置系统全局异常映射处理

    一.异常分类 这里的异常分类从系统处理异常的角度看,主要分类两类:业务异常和系统异常. 1.业务异常 业务异常主要是一些可预见性异常,处理业务异常,用来提示用户的操作,提高系统的可操作性. 常见的业务 ...

  8. C语言保证,0永远不是有效的数据地址,因此,返回址0可用来表示发生的异常事件

    C语言保证,0永远不是有效的数据地址,因此,返回址0可用来表示发生的异常事件

  9. SpringBoot2.0小程序支付功能实现weixin-java-pay

    SpringBoot2.0小程序支付功能实现weixin-java-pay WxJava - 微信开发 Java SDK(开发工具包); 支持包括微信支付.开放平台.公众号.企业微信/企业号.小程序等 ...

随机推荐

  1. springboot(11)使用SpringBoot validator进行数据验证

    简介: 数据验证是作为一个企业级项目架构上设计的最基础的模块,前辈们曾说过:界面上传递到后台的数据没有百分之百值得相信的!为什么这么说呢?往往我们在编写程序的时候都会感觉后台的验证无关紧要,这样就会给 ...

  2. jquery header选择器 语法

    jquery header选择器 语法 作用::header 选择器选取所有标题元素(h1 - h6).广州大理石机械构件 语法:$(":header") jquery heade ...

  3. Min_25筛初级应用:求$[1,n]$内质数个数

    代码 #include <bits/stdc++.h> #define rin(i,a,b) for(int i=(a);i<=(b);++i) #define irin(i,a,b ...

  4. EF 视图查询坑

    EF 视图在查询的时候如果主键一样则默认的数据都是第一条查询的数据

  5. linux 简单命令说明

    1.df -h 查看磁盘占用及挂载情况 挂载磁盘 如下: mount /dev/sda1 /boot 取消挂载的磁盘 umount /boot 2.dh -sh 查看当前目录占用文件大小 dh -sh ...

  6. legend3---用Homestead配置后报错“No input file specified.”

    legend3---用Homestead配置后报错“No input file specified.” 一.总结 一句话总结: 自己项目上传到github的时候多增加了一层legend3的github ...

  7. Sqlserver 创建账号

    下面是通过脚本创建账号,创建一个appuser 的账号,密码:123456,可操作的DB:TEST 赋予权限,增删改查,操作视图,存储过程.当然当前的账号要有足够的权限. create login a ...

  8. webpack安装低于4版本(没有配置webpack.config.js)

    webpack安装低于4版本(没有配置webpack.config.js) webpack 无需配置输出参数-o 低版本  1.初始化项目 npm init -y 初始化项目 2.安装webpack@ ...

  9. leetcode-mid-dynamic programming- Longest Increasing Subsequence-NO

    不会... 参考: 思路类似于coin那个题,for循环中在满足条件时就及时更新当下位置的信息 def lengthOfLIS(nums): """ :type nums ...

  10. 如何进行EDM邮件内容的撰写

    近两个月没有来博客园更新一下博客文章了,实在惭愧,最近忙于工作,经常加班.下面来说说EDM邮件内容的撰写技巧吧,本文就跟大家交流一下自己一直以来的心得体会. EDM中很重要的一个步骤,就是邮件内容的撰 ...