返回数据标准(后端反馈数据标准化)

本文介绍了一种统一的API响应规范设计方案,包括响应状态码、消息提示及数据封装等核心内容,适用于前后端分离的开发模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

返回数据标准

        我们做了一个后台管理项目(lotteryCMS),为了解析时好解析,我们会对从db中拿到的数据进行封装,当前端接受到数据的时候根据反馈的code就可以决定自己是否要解析这次查询的数据了。

        我们定义一个基本的返回对象Response,我们的操作无非是两种情况,成功或者失败:

import java.io.Serializable;

public class Response implements Serializable {

	private static final long serialVersionUID = -1412088307616236078L;

	private String code = CodeDict.SUCCESS.getCode();

	private String msg = CodeDict.SUCCESS.getDesc();

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}	
}

当反馈的Response成功的时候提示成功,失败的时候提示失败,当处于未登录状态的时候让他去登陆,对应的响应码前对做出对应页面转换。

对应的依赖代码:

public enum CodeDict {
	SUCCESS("0","成功"),
	FAILED("1","失败"),
	EXCEPT("2","异常"),
	
	
	LOGIN_NEED("9","未登录"),
	NOAUTH("10","无权限"),
	NOT_PERMISSION_REQUEST("-1","不允许的操作");
	
	private String code;
	
	private String desc;
	
	private CodeDict(String code, String desc){
		this.code = code;
		this.desc = desc;
	}


	public String getCode() {
		return code;
	}


	public void setCode(String code) {
		this.code = code;
	}


	public String getDesc() {
		return desc;
	}


	public void setDesc(String desc) {
		this.desc = desc;
	}
} 

        上述代码只是反馈标准,没有反馈数据,只是我们的反馈约定,成功或者失败。如果说是查询的话,我们需要把数据给带到前端去的,所以到时候肯定就不止这些数据了,所以我们需要对数据进行更深一个层次的封装:

public class CommonRsp<T> extends Response {

	private static final long serialVersionUID = 460456776638649480L;

	private T data;

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

}

这样的话,当我们执行查询操作的时候我们就可以把我们的数据给塞进去传递到前端进行解析。

        如果说这样还不能满足你现在的项目需求的话那肯定就是说分页没有喽,如果说需要分页的话,那么我们就需要封装另一个Page对象,然后往CommonRsp中塞Page对象反馈到前端让其解析。

import java.util.List;

public class Page<T> {

	private Integer page;// 当前页
	private Integer totalPage;// 总页数
	private Integer totalRecords;// 总记录数
	private Integer rows;// 每页要显示的数据条目
	private List<T> result;

	public Integer getPage() {
		return page;
	}

	public void setPage(Integer page) {
		this.page = page;
	}

	public Integer getTotalRecords() {
		return totalRecords;
	}

	public void setTotalRecords(Integer totalRecords) {
		this.totalRecords = totalRecords;
	}

	public Integer getRows() {
		return rows;
	}

	public void setRows(Integer rows) {
		this.rows = rows;
	}



	public List<T> getResult() {
		return result;
	}

	public void setResult(List<T> result) {
		this.result = result;
	}

	public void setTotalPage(Integer totalPage) {
		this.totalPage = totalPage;
	}

	public int getTotalPage() {
		totalPage = totalRecords % rows == 0 ? totalRecords / rows : totalRecords / rows + 1;
		return totalPage;
	}

}
        上述代码基本上就是我么lotteryCMS的反馈标准,当然不是所有的请求都是这样反馈数据的,比如你前端使用的是第三方tree插件,而且你不能或者不方便指定tree的起始解析节点的情况下,那就只能按照当前插件给的api文档去编码,不要学死code,灵活一点。


上述代码是只有反馈的成功与否,没有数据,那该怎么办呢?先不要往下看,自己先想一下。
在Java Spring Boot应用程序中实现数据数据的国际化是一个复杂的过程,因为它不仅涉及到了静态文本资源文件的管理,还涉及到如何将这些本地化的信息映射到动态存储的数据上。以下是几种常见的做法来应对这个问题: ### 方案一:通过枚举或预定义常量集合作为桥梁 如果你的应用场景允许的话,可以预先确定好一部分关键字段的内容形式及其对应的多种语言解释,并把这些内容封装成枚举或者其他固定集合的形式存放在程序内部。每当访问某个具体的记录时,就根据当前环境下的Locale去匹配最合适的描述版本返回给客户端显示。 这种方法适用于那些业务规则相对稳定不变而且预期不会频繁变动的信息类别,如订单状态、支付方式等标准选项列表;然而对于个性化程度较高的非结构化数据则显得力不从心了。 ### 方案二:双表关联设计模式 另一个较为通用的设计思路是在原有实体模型的基础上新增一张或多张“翻译”性质的关系型表格专门用来承载多语言版本的具体表述。以文章为例,原本的一篇文章只对应一行主键ID+标题正文这样的简单关系,现在我们可以构造出一个额外的文章详情表,里面包含了诸如原文id、目标语种标识以及该条目在当地文化环境下应有的呈现形态等内容项。查询的时候依据请求方指定的目标language tag对两张表实施JOIN联接运获取最终结果集。 这种方案的好处是可以灵活适应未来可能出现的新需求点同时保持良好的扩展性和维护性,但是缺点在于增加了系统的复杂度同时也可能导致一定的性能损耗尤其是在面对海量级规模的数据集时需要谨慎评估其影响范围。 ### 实现步骤详解 - 双表关联法 假定我们要为一篇博客帖子(Post)添加标题和摘要两个部分的支持多国字幕的功能,则可以根据下面流程逐步推进下去: #### 步骤 01. 数据建模 创建原始post实体及其相应的Repository接口用于CRUD基本操作。 ```java @Entity @Table(name = "posts") public class Post { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 其他属性略... } interface PostRepository extends JpaRepository<Post,Long>{} ``` 接着再建立第二个名为PostTranslation的POJO类表示每一种特定方言下所特有的那部分内容。 ```java @Entity @ToString(callSuper=true) @NoArgsConstructor(access= AccessLevel.PRIVATE)// Lombok插件生成无参构造器 @Getter @Setter(onMethod_=@NonNull)// 强制要求提供getter/setter方法的同时不允许为空值赋入 @Table(uniqueConstraints={@UniqueConstraint(columnNames={"postId", "locale"})}) public class PostTranslation { @EmbeddedId// 使用组合键代替单一列作为唯一识别码 protected PostTranslationKey pk=new PostTranslationKey(); /** * 组合关键字包括外键引用原生表primary key + 目标语言标记符 */ @Embeddable public static final class PostTranslationKey implements Serializable{ @Column(nullable=false) String locale;// e.g., zh_CN,en_US @ManyToOne(cascade=CascadeType.ALL ) @JoinColumn(name="postId") Post post; // equals 和hashCode 的定义... } private String title; private String summary; } ``` 然后相应地也要有配套的操作仓储层组件帮助我们更高效便捷地与之交互。 ```java @Repository public interface IPostTranslationDao extends CrudRepository<PostTranslation,PostTranslation.PostTranslationKey>{ Optional<List<PostTranslation>> findByPk_PostOrderByPk_LocaleAsc(Post target); } ``` #### 步骤 02. Service 层逻辑编写 接下来就是最重要的Service层了,在这里我们需要明确当接受到来自外界关于加载某篇blog article的需求信号后应该采取怎样的行动路线才能满足既定目的——即找到贴切于当下上下文境况的最佳诠释变体并反馈出去。一般而言我们会先判断是否存在精确吻合的translation entry存在,如果没有就退而求其次选用系统默认fallback value也就是英文版吧! ```java @Service @Transactional(readOnly=true) @AllArgsConstructor class BloggingServiceImpl implements IBloggingService { private final IPublicationGateway gateway; private final LocaleResolver resolver; @Override public Mono<BlogArticleDTO> getLocalizedContent(Long postId) { return this.gateway.findById(postId).map(it -> mapToTransferObject(resolver.resolveLocale(), it)); } private BlogArticleDTO mapToTransferObject(Locale preferredLanguageTag, Publication aggregateRoot) { var translations=gateway.findTranslationsByAggregateIdentifierAndOrdering(preferredLanguageTag.getISO3Language()); return translations.orElseGet(()-> new BlogArticleDTO( aggregateRoot.getId(), null, aggregateRoot.getTitle(), aggregateRoot.getDescription() )); } } ``` 请注意这里的`IBloggingService`, `IPublicationGateway`都是简化后的伪代码示意而已实际上还要结合实际情况做出适当调整修改哦~ 另外别忘了注册那个负责解析传入HTTP header里面的Accept-Language参数从而得到正确的RegionInfo的对象实例: ```properties # application.properties 配置示例 spring.mvc.locale=en_US spring.mvc.locales=zh_CN,en_US spring.messages.basename=i18n/messages ``` ```java @Bean public AcceptHeaderLocaleResolver acceptHeaderLocaleResolver(){ AcceptHeaderLocaleResolver result=new AcceptHeaderLocaleResolver(); result.setDefaultLocale(new Locale("en","US")); List<Locale> supportedLanguages = Arrays.asList( new Locale("zh","CN"), new Locale("en","US") ); result.setSupportedLocales(supportedLanguages); return result; } ``` --- 经过上面一系列改造之后我们就成功赋予了一个普通的SpringBoot RESTful API具备处理来自世界各地访客朋友发送过来的要求的能力啦!当然除了以上提到的技术手段之外还有很多其他的途径可以选择,比如直接把所有的localizable string都放进NoSQL store当中去托管或是干脆全部交给第三方云服务商打理等等…总之各有千秋取决于各自的特殊诉求咯。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值