zoukankan      html  css  js  c++  java
  • springboot2.0-统一处理返回结果和异常情况

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

    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

  • 相关阅读:
    HTML DOM prompt() 方法
    Zen cart前台英文后台中文(Zen cart后台取消多语言输入的方法)
    Zencart模板结构和设计详解
    给zencart添加一个fckeditor编辑器
    mssql重置表
    Guid与id区别
    zencart五款是必备的插件
    C#使用HTTP头检测网络资源是否有效
    OA系统权限管理设计方案
    C#获取网页http头的方法(附代码)
  • 原文地址:https://www.cnblogs.com/jpfss/p/11591806.html
Copyright © 2011-2022 走看看