一、统一处理返回结果和异常处理的原因:
1、在springboot项目里我们希望接口返回的数据包含至少三个属性:
a、code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功,code = "0000",查询结果为null,code = "0001";
b、msg:请求接口的描述,也就是对返回编码的描述,"0000":就表示请求成功,"0001":表示结果为null;
c、data:请求接口成功,返回的结果。
-
-
-
-
-
-
-
-
"createdDate":
"2018-10-08T05:45:49.000+0000",
-
"updatedDate":
"2018-10-09T03:15:33.000+0000"
-
-
-
-
2、在springboot项目里我们希望请求结果失败之后,通过返回码和返回描述来告诉前端接口请求异常。
-
-
-
-
二、案例
1、建一张学生信息表,包含学生的学号、姓名、年龄、家庭住址等
-
CREATE
TABLE student_info (
-
id
bigint(
20)
NOT
NULL AUTO_INCREMENT
COMMENT
'自增',
-
student_id
varchar(
20)
NOT
NULL
COMMENT
'学号',
-
name
varchar(
64)
NOT
NULL
COMMENT
'姓名',
-
age
int(
2)
NOT
NULL
COMMENT
'年龄',
-
familly_address
varchar(
256)
NOT
NULL
COMMENT
'家庭地址',
-
created_date datetime
NOT
NULL
DEFAULT
CURRENT_TIMESTAMP
COMMENT
'创建时间',
-
updated_date datetime
NOT
NULL
DEFAULT
CURRENT_TIMESTAMP
COMMENT
'更新时间',
-
PRIMARY
KEY (student_id),
-
-
)
ENGINE=
InnoDB
DEFAULT
CHARSET=utf8mb4
2、pom.xml
-
-
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-web
</artifactId>
-
-
-
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-test
</artifactId>
-
-
-
-
-
<groupId>org.springframework.boot
</groupId>
-
<artifactId>spring-boot-starter-data-redis
</artifactId>
-
-
-
-
<groupId>org.mybatis.spring.boot
</groupId>
-
<artifactId>mybatis-spring-boot-starter
</artifactId>
-
<version>1.3.1
</version>
-
-
-
-
<groupId>mysql
</groupId>
-
<artifactId>mysql-connector-java
</artifactId>
-
<version>5.1.46
</version>
-
-
-
-
<groupId>com.alibaba
</groupId>
-
<artifactId>druid
</artifactId>
-
<version>1.1.9
</version>
-
-
-
-
<groupId>org.projectlombok
</groupId>
-
<artifactId>lombok
</artifactId>
-
<version>1.16.22
</version>
-
-
-
-
<groupId>com.alibaba
</groupId>
-
<artifactId>fastjson
</artifactId>
-
<version>1.2.43
</version>
-
-
-
-
-
<groupId>com.squareup.okhttp3
</groupId>
-
<artifactId>okhttp
</artifactId>
-
<version>3.9.1
</version>
-
-
-
-
<groupId>org.glassfish
</groupId>
-
<artifactId>javax.json
</artifactId>
-
<version>1.0.4
</version>
-
-
-
-
<groupId>org.apache.tomcat.embed
</groupId>
-
<artifactId>tomcat-embed-jasper
</artifactId>
-
-
-
3、案例中使用redis进行缓存,可以不需要
Windows环境安装redis以及缓存应用
4、创建实体类:StudentInfo
-
package com.dl.cn.message.bean;
-
-
import lombok.AllArgsConstructor;
-
-
-
import lombok.NoArgsConstructor;
-
-
import java.io.Serializable;
-
-
-
-
-
-
-
-
-
-
public
class StudentInfo implements Serializable{
-
-
private
static
final
long serialVersionUID =
2597547944454691103L;
-
-
-
private String studentId;
-
-
-
private String famillyAddress;
-
private Date createdDate;
-
private Date updatedDate;
-
5、创建Mapper:StudentInfoMapper
-
package com.dl.cn.message.mapper;
-
-
import com.dl.cn.message.bean.StudentInfo;
-
import org.apache.ibatis.annotations.*;
-
-
-
-
-
-
public
interface StudentInfoMapper {
-
@Insert("insert into student_info(student_id,name,age,familly_address)" +
-
" values(#{studentId},#{name},#{age},#{famillyAddress})")
-
-
-
-
void saveStudentInfo(StudentInfo studentInfo);
-
-
-
@Select("select * from student_info where student_id = #{studentId}")
-
StudentInfo findByStudentId(
@Param("studentId") String studentId);
-
-
-
@Update("update student_info set familly_address = #{famillyAddress},updated_date = now() ")
-
void updateFamillyAddress(
@Param("studentId") String studentId,
@Param("famillyAddress") String famillyAddress);
-
6、创建service:StudentInfoService
-
package com.dl.cn.message.service;
-
-
import com.dl.cn.message.bean.StudentInfo;
-
import com.dl.cn.message.mapper.StudentInfoMapper;
-
import lombok.extern.slf4j.Slf4j;
-
import org.springframework.beans.factory.
annotation.Autowired;
-
import org.springframework.cache.
annotation.CacheConfig;
-
import org.springframework.cache.
annotation.CacheEvict;
-
import org.springframework.cache.
annotation.Cacheable;
-
import org.springframework.stereotype.Service;
-
-
-
-
-
-
@CacheConfig(cacheNames = "studentInfo")
-
-
public
class StudentInfoService {
-
-
-
StudentInfoMapper studentInfoMapper;
-
-
-
-
-
-
public void saveStudentInfo(StudentInfo studentInfo){
-
studentInfoMapper.saveStudentInfo(studentInfo);
-
-
-
-
-
-
-
-
@Cacheable(key = "#studentId",unless = "#result == null")
-
public StudentInfo findByStudentId(String studentId){
-
log.info(
"查找信息:{}",studentId);
-
return studentInfoMapper.findByStudentId(studentId);
-
-
-
-
-
-
-
-
-
@CacheEvict(key = "#studentId")
-
public void updateFamillyAddress(String studentId,String famillyAddress){
-
studentInfoMapper.updateFamillyAddress(studentId,famillyAddress);
-
-
7、创建统一返回结果类:Response
-
package com.dl.cn.message.response;
-
-
import com.fasterxml.jackson.databind.
annotation.JsonSerialize;
-
-
-
-
import java.io.Serializable;
-
-
-
-
-
-
-
-
@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
-
public
class Response<T> implements Serializable {
-
-
private static
final long serialVersionUID =
-4505655308965878999L;
-
-
-
private static
final String successCode =
"0000";
-
-
-
-
-
-
-
-
-
-
-
-
-
public Response(String code,String msg){
-
-
-
-
-
public Response(String code,String msg,T
data){
-
-
-
-
-
-
-
-
-
-
8、创建异常编码和描述类:ErrorCodeAndMsg
-
package com.dl.cn.message.enums;
-
-
-
-
-
public
enum ErrorCodeAndMsg {
-
-
Student_number_does_not_exist(
"0001",
"学号不存在"),
-
Insufficient_student_number(
"0002",
"学号长度不足"),
-
Student_number_is_empty(
"0003",
"学号为空"),
-
Network_error(
"9999",
"网络错误,待会重试"),
-
-
-
-
-
-
ErrorCodeAndMsg(String code, String msg) {
-
-
-
-
-
public String getCode() {
-
-
-
public void setCode(String code) {
-
-
-
-
-
-
public void setMsg(String msg) {
-
-
-
9、创建统一异常处理类:StudentException
-
package com.dl.cn.message.exception;
-
-
import com.dl.cn.message.enums.ErrorCodeAndMsg;
-
-
import java.io.Serializable;
-
-
-
-
-
-
public
class StudentException extends RuntimeException{
-
-
private
static
final
long serialVersionUID = -
6370612186038915645L;
-
-
private
final ErrorCodeAndMsg response;
-
-
public StudentException(ErrorCodeAndMsg response) {
-
this.response = response;
-
-
public ErrorCodeAndMsg getResponse() {
-
-
-
10、创建异常处理的全局配置类:ExceptionHandler
-
package com.dl.cn.message.exception;
-
-
import com.dl.cn.message.enums.ErrorCodeAndMsg;
-
import com.dl.cn.message.
response.
Response;
-
import lombok.extern.slf4j.Slf4j;
-
import org.springframework.web.bind.annotation.ControllerAdvice;
-
import org.springframework.web.bind.annotation.ResponseBody;
-
-
import javax.servlet.http.HttpServletRequest;
-
-
-
* Created by Tiger
on
2018/
10/
9.
-
-
-
-
public
class ExceptionHandler {
-
@org.springframework.web.bind.annotation.ExceptionHandler(StudentException.
class)
-
-
public
Response handleStudentException(HttpServletRequest
request, StudentException ex) {
-
-
log.
error(
"StudentException code:{},msg:{}",ex.getResponse().getCode(),ex.getResponse().getMsg());
-
response =
new
Response(ex.getResponse().getCode(),ex.getResponse().getMsg());
-
-
-
@org.springframework.web.bind.annotation.ExceptionHandler(Exception.
class)
-
-
public
Response handleException(HttpServletRequest
request, Exception ex) {
-
-
log.
error(
"exception error:{}",ex);
-
response =
new
Response(ErrorCodeAndMsg.Network_error.getCode(),
-
ErrorCodeAndMsg.Network_error.getMsg());
-
-
-
11、创建controler类:StudentInofController
-
package com.dl.cn.message.controller;
-
-
import com.dl.cn.message.enums.ErrorCodeAndMsg;
-
import com.dl.cn.message.exception.StudentException;
-
import com.dl.cn.message.response.Response;
-
import com.dl.cn.message.service.StudentInfoService;
-
import com.dl.cn.message.bean.StudentInfo;
-
import lombok.extern.slf4j.Slf4j;
-
import org.springframework.beans.factory.
annotation.Autowired;
-
import org.springframework.web.bind.
annotation.PostMapping;
-
import org.springframework.web.bind.
annotation.RequestMapping;
-
import org.springframework.web.bind.
annotation.RequestParam;
-
import org.springframework.web.bind.
annotation.RestController;
-
-
-
-
-
-
@RequestMapping("/student")
-
-
public
class StudentInofController {
-
-
StudentInfoService studentInfoService;
-
-
-
-
-
-
-
-
-
-
public void saveStudentInfo(
@RequestParam("student_id") String studentId,
-
@RequestParam("name") String name,
-
@RequestParam("age") Integer age,
-
@RequestParam("familly_address") String famillyAddress){
-
StudentInfo studentInfo = StudentInfo.builder()
-
-
-
-
.famillyAddress(famillyAddress)
-
-
studentInfoService.saveStudentInfo(studentInfo);
-
-
-
-
-
-
-
-
@PostMapping("/findByStudentId")
-
public Response findByStudentId(
@RequestParam("student_id") String studentId){
-
-
log.info(
"Get student information based on student number:{}",studentId);
-
-
throw new StudentException(ErrorCodeAndMsg.Student_number_is_empty);
-
-
-
if(studentId.length() !=
8){
-
throw new StudentException(ErrorCodeAndMsg.Insufficient_student_number);
-
-
StudentInfo studentInfo = studentInfoService.findByStudentId(studentId);
-
-
throw new StudentException(ErrorCodeAndMsg.Student_number_does_not_exist);
-
-
return new Response(studentInfo);
-
-
if(e instanceof StudentException){
-
-
-
log.error(
"findByStudentId error:",e);
-
throw new StudentException(ErrorCodeAndMsg.Network_error);
-
-
-
-
-
@PostMapping("/updateFamillyAddress")
-
public Response updateFamillyAddress(
@RequestParam("student_id") String studentId,
-
@RequestParam("familly_address") String famillyAddress){
-
studentInfoService.updateFamillyAddress(studentId,famillyAddress);
-
Response response = new Response();
-
System.
out.println(response.toString());
-
-
-
-
-
12、application.properties配置
-
-
spring.redis.host=
127.0
.0
.1
-
-
spring.redis.password=tiger
-
-
-
#开启mybatis驼峰命名,这样可以将mysql中带有下划线的映射成驼峰命名的字段
-
mybatis.configuration.map-underscore-to-camel-
case=
true
-
-
-
spring.datasource.url=jdbc:mysql:
-
spring.datasource.username=tiger
-
spring.datasource.password=tiger
-
spring.datasource.driver-
class-name=com.mysql.jdbc.Driver
-
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
-
spring.datasource.max-idle=
10
-
spring.datasource.max-wait=
60000
-
spring.datasource.min-idle=
5
-
spring.datasource.initial-size=
5
-
spring.datasource.validationQuery=select
'x'
三、说明
1、controller层使用注解@RestController,这样返回结果就是json格式,而@Controller返回结果是字符串
2、throw 异常
如果exception类型是自定义的异常StudentException,直接抛出,如果是其它异常统一抛出网络错误
-
-
-
-
if(e
instanceof StudentException){
-
-
-
log.error(
"findByStudentId error:",e);
-
throw
new StudentException(ErrorCodeAndMsg.Network_error);
-
-
3、在返回结果类添加了注解@JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL)
是因为更新或者删除操作,一般没有返回值,我只需要知道是否更新成功或者删除成功就OK了,如果不加这个注解
我们返回的结果中data为null!!!
-
-
-
-
-
加上注解再更新数据,返回结果:
-
-
-
-
因此这个注解的作用就是:返回结果中有null值,干掉它!
四、测试结果
mysql数据库中有一条学号为13240115的数据:
1、student_id = "13240115"时
-
-
-
-
-
-
-
-
"createdDate":
"2018-10-08T05:45:49.000+0000",
-
"updatedDate":
"2018-10-09T05:36:36.000+0000"
-
-
-
-
2、student_id = "13240114"时
-
-
-
-
3、student_id = "1324011",不足8位时
-
-
-
-
4、student_id = "13240115",然后在接口中加上一行代码,System.out.println(1/0);
返回结果:
-
-
-
-
控制台日志:
-
java.lang.
ArithmeticException: / by zero
-
at com.dl.cn.message.controller.
StudentInofController.findByStudentId(
StudentInofController.java:
54) ~[classes/:na]
-
at sun.
reflect.
NativeMethodAccessorImpl.invoke0(
Native
Method) ~[na:
1.8.
0_161]
-
at sun.
reflect.
NativeMethodAccessorImpl.invoke(
NativeMethodAccessorImpl.java:
62) ~[na:
1.8.
0_161]
-
at sun.
reflect.
DelegatingMethodAccessorImpl.invoke(
DelegatingMethodAccessorImpl.java:
43) ~[na:
1.8.
0_161]
-
at java.lang.
reflect.
Method.invoke(
Method.java:
498) ~[na:
1.8.
0_161]
-
at org.springframework.web.method.support.
InvocableHandlerMethod.doInvoke(
InvocableHandlerMethod.java:
209) [spring-web-
5.0.
8.
RELEASE.jar:
5.0.
8.
RELEASE]
-
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