第4章 Web开发
4.1 Web开发简介
4.2 URL映射
4.3 参数传递
4.4 数据验证
4.5 拦截器
4.6 过滤器
4.7 Web配置
4.8 实战:实现优雅的数据返回
4.8 实战:实现优雅的数据返回
本节介绍如何让前后台优雅地进行数据交互,正常的数据如何统一数据格式,以及异常情况如何统一处理并返回统一格式的数据。
4.8.1 为什么要统一返回值
在项目开发过程中经常会涉及服务端、客户端接口数据传输或前后台分离的系统架构下的数据交互问题。如何确保数据完整、清晰易懂是考验开发者的大难题。定义统一的数据返回格式有利于提高开发效率、降低沟通成本、降低调用方的开发成本。目前比较流行的是基于JSON格式的数据交互。但是JSON只是消息的格式,其中的数据内容还需要重新设计和定义。无论是HTTP接口还是RPC接口,保持返回值格式统一很重要。
在项目中,我们会将响应封装成JSON返回,一般会统一所有接口的数据格式,使前端(iOS、Android、Web)对数据的操作一致、轻松。一般情况下,统一返回数据格式没有固定的规范,只要能描述清楚返回的数据状态以及要返回的具体数据即可,但是一般会包含状态码
、消息提示语
、具体数据
这3部分内容。例如,一般的系统要求返回的基本数据格式如下:
{
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"id": "1",
"name": "zhangsan",
"intro": "备注"
}
]
}
}
通过上面的示例我们知道,定义的返回值包含4要素:响应结果、响应码、消息、返回数据。
4.8.2 统一数据返回
下面通过示例演示如何实现统一JSON数据返回。
1、定义数据格式
定义返回值的基本要素,确保后台无论执行成功还是失败都是返回这些字段,而不会出现其他字段。定义的返回值包括如下内容:
- Integer code: 成功时返回0,失败时返回具体错误吗。
- String message: 成功时返回null,失败时返回具体错误信息。
- T data: 成功时返回具体值,失败时返回null。
根据上面的返回数据格式的定义,实际返回的数据模板如下:
{
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"id": "1",
"name": "zhangsan",
"intro": "备注"
}
]
}
}
其中,data 字段为泛型字段,根据实际的业务返回前端需要的数据类型。
2、定义状态码
返回的数据中有一个非常重要的字段:状态码。状态码字段能够让服务端、客户端清楚知道操作的结果、业务是否处理成功,如果失败,失败的原因等信息。所以,定义清晰易懂的状态码非常重要。
状态码定义如下(以通用状态码
为例):
- 200:处理成功
- 400:处理失败
- 401:接口不存在
- 404:token未认证(签名错误)
- 500:服务器内部错误
以上定义的是通用状态码
,其他的业务相关状态码需要根据实际业务定义。
3、定义数据处理类
前面定义了返回数据的格式和处理结果的状态码,接下来定义通用的结果处理类。在实际使用时可以根据情况处理。本示例中简单定义如下:
JSONResult.java
package com.example.webproject.comm.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
/**
* 定义数据处理类
*
* @Title:: JSONResult.java
* @Package com.example.webproject.comm.utils
* @Description: 自定义响应数据结构
* 200: 表示成功
* 500: 表示错误,错误信息在 msg 字段中
* 501: bean 验证错误,无论多少个错误都以 map 形式返回
* 502: 拦截器拦截到用户 token 出错
* 555: 异常抛出信息
* Copyright: Copyright (c) 2023
*/
public class JSONResult {
// 定义 jackson 对象 (关于jackson的使用详解请参考:https://juejin.cn/post/6844904166809157639)
private static final ObjectMapper MAPPER = new ObjectMapper();
// 响应业务状态
private Integer code;
// 响应消息
private String msg;
// 响应中的数据
private Object data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public JSONResult() {
}
public JSONResult(Integer code,