1. 业务场景介绍
功能描述:数据接口如何实现字典表的快速转换
举例:如一张人员表的性别(SEX)字段这样定义 1代表男 2代表女
返回人员接口信息如下
{"SEX":1,"NAME":"张三"}
但是业务需要转换为如下信息(字段1转化为了男)
{"SEX":"男","NAME":"张三"}
2. 开发实战
这里快速梳理下集成步骤
1)定义相关字典表
规则:1代表男 2代表女 即对应码表编号和码表名称
特别说明:key为性别的规范定义字段如SEX代表性别,也就是key和码表编号 查询 可以确定一条记录
2)Java实体类标明需要转换的字段(人员表举例)
字段转换标识:字段@JSONField标识 name:显示字段+转换前缀+字典Key
@JSONField(name="rc3"+ Constant.CODE_TRANS_PRE+"SEX")
rc3需要字典转换,对应转换为码表中SEX性别的字典值
public class UserInfo extends AbstractModel implements Serializable {
private String id;
private String account;
private String name;
/**
* 性别标识-需要码表转换的字段:举例 用@JSONField标识
* name:显示字段+转换前缀+字典Key
* 即是:name="rc3"+ Constant.CODE_TRANS_PRE+"SEX"
*/
@JSONField(name="rc3"+ Constant.CODE_TRANS_PRE+"SEX")
private Integer rc3;
}
3.码表转换开关
Controller注入核心Servce
@Autowired
CoreService coreService;
返回Json数据开启码表转换getJson(coreService)
Result.getInstance(...).getJson(coreService);
@RequestMapping(value = "/loginUserInfo",method= RequestMethod.GET)
public String loginUserInfo() {
UserInfo user=ApplicationContext.getLoginUser();
UserInfo userInfo=userInfoService.get(user.getId());
return Result.getInstance(ResultCode.SUCCESS.toString(), ResultMsg.SUCCESS,userInfo,"").getJson(coreService);
}
4.效果展示
3.源码剖析
设计原则:最小改动、不影响其他接口业务、符合常规码表定义规则
核心技术点:fastJson的JSONField功能、正则字符串替换、Result类的封装
部分代如下
Result返回类
package com.limp.framework.core.bean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
//import com.limp.framework.boss.service.CommonService;
import com.limp.framework.core.constant.ExceptionEnum;
import com.limp.framework.core.constant.ResultMsg;
import com.limp.framework.core.service.CoreService;
import com.limp.framework.utils.StrUtils;
import com.limp.framework.utils.TextUtils;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* @author: zzh
* Date: 16-6-12
* Time: 下午11:55
* To change this template use File | Settings | File Templates.
*/
public class Result implements Serializable {
private static Logger log= Logger.getLogger(Result.class);
/**
* 字符串
*/
private static final String EMPTY_STRING="";
/**
* 返回状态码 : 如 200
*/
private static final String CODE="code";
/**
* 返回提示信息:如 更新成功
*/
private static final String MSG="msg";
/**
* 返回数据集合:如list对象等
*/
private static final String RESULT="result";
/**
* 额外参数:如Map个格式的其他数据
*/
private static final String EXT="ext";
/**
* 返回状态代码
*/
private String code;
/**
* 提示信息
*/
private String msg;
/**
* 返回数据
*/
private Object data;
/**
* 返回结果map
*/
private Map resultMap;
/**
* 格式化数据字符串
*/
private String formatJsonStr;
/**
* 返回结果
* @param code 状态码
* @param msg 提示信息
* @param data 结果集合
* @param param 额外参数
*/
public Result(String code,String msg,Object data,Object param){
this.code=code;
this.msg=msg;
this.data=data;
resultMap=new HashMap();
resultMap.put(CODE,code);
resultMap.put(MSG,this.msg);
if(!StrUtils.isBlank(data)){
resultMap.put(RESULT,this.data);
}
if(!StrUtils.isBlank(param)){
resultMap.put(EXT,param);
}
this.resultMap=resultMap;
}
/**
* 正确的返回结果
* @param data
*/
public Result(Object data){
this.msg=msg;
this.data=data;
resultMap=new HashMap();
resultMap.put(CODE,200);
resultMap.put(MSG,"success");
if(!StrUtils.isBlank(data)){
resultMap.put(RESULT,this.data);
}
this.resultMap=resultMap;
}
/**
* 返回异常信息
* @param exceptionEnum
* @return
*/
public final static Result getException(ExceptionEnum exceptionEnum) {
String arr[]= exceptionEnum.getKey().split("_");
return new Result(arr.length>1?arr[0]:ResultCode.ERROR.toString(),arr.length>1?arr[1]: ResultMsg.ERROR.toString(),exceptionEnum.getValue(),"");
}
/**
* 返回异常信息
* @param exceptionStr
* @return
*/
public final static Result getException(String exceptionStr) {
return new Result(ResultCode.ERROR.toString(),exceptionStr,"","");
}
/**
* 返回结果格式化
* @param code 状态值 200成功 500错误
* @param msg 提示信息
* @param data 返回数据
* @param param ext其他参数
* @return 调用Result.getJson()返回json数据
*/
public final static Result getInstance(String code,String msg,Object data,Object param) {
return new Result(code,msg,data,param);
}
/**
* 正确返回结果
* @return
*/
public final static Result Success() {
return new Result(ResultCode.SUCCESS.toString(),ResultMsg.SUCCESS,"","");
}
/**
* 错误返回结果
* @return
*/
public final static Result Error() {
return new Result(ResultCode.ERROR.toString(),ResultMsg.ERROR,"","");
}
/**
* 错误返回结果
* @param msg 返回信息
* @return
*/
public final static Result Error(String msg) {
return new Result(ResultCode.ERROR.toString(),msg,"","");
}
/**
* FASTjson【obj】转化为【json】
* @param obj
* @return
*/
public static String toJSONString(Object obj) {
if (StrUtils.isBlank(obj)) {
return EMPTY_STRING;
}
return JSON.toJSONString(obj);
}
public final static String transCodeZN(CoreService commonService, Object obj){
//定义返回JSON字符串
String returnJson = "";
SerializeConfig ser = new SerializeConfig();
/* *
* 注意:有些json字符串返回的不是如下时间格式,校验方式:检查该字段是否是Date类型(其他Object类型无效)
*/
ser.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
try {
/* 1、格式化时间
2、禁止循环
3、fastjson将bean转成字符串时首字母变小写问题:方案在bean的属性get方法上加注解 @JSONField(name = "RC2") public String getRC2() return RC2;
*/
returnJson = JSON.toJSONString(obj, ser, SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.DisableCircularReferenceDetect);
} catch (Exception e) {
}
//格式化数据字符串使用
//转码方法
Long start=System.currentTimeMillis();
returnJson= commonService.transCodeZN(returnJson);
Long end=System.currentTimeMillis();
log.info(TextUtils.format("码表转换解析需要时间为:{0}毫秒",end-start));
return returnJson;
}
/**
*第一个参数为转码service
* 格式JSON数据( resultMap的json格式数据)
* @return 转换后的json字符串
*/
public String getJson(CoreService... commonServices) {
// public String getJson() {
if (StrUtils.isBlank(this.resultMap)) {
return null;
}
//定义返回JSON字符串
String returnJson = "";
SerializeConfig ser = new SerializeConfig();
ser.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
try {
/*
1、格式化时间
2、禁止循环
3、fastjson将bean转成字符串时首字母变小写问题:方案在bean的属性get方法上加注解 @JSONField(name = "RC2") public String getRC2() return RC2;
*/
returnJson = JSON.toJSONString(this.resultMap, ser, SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.DisableCircularReferenceDetect);
} catch (Exception e) {
log.error("-----JSON转换异常【实体类Timestamp类型请定义为Date类型接收】-----");
Gson gson2 = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").enableComplexMapKeySerialization()
.registerTypeAdapter(Timestamp.class, new TimestampTypeAdapter()).create();
log.error(e);
returnJson= gson2.toJson(this.resultMap);
this.formatJsonStr = returnJson;
return returnJson;
}
//格式化数据字符串使用
this.formatJsonStr=returnJson;
//转码方法
if (commonServices.length>0) {
Long start=System.currentTimeMillis();
log.debug(TextUtils.format("-----码表转换开始-----"));
log.debug(returnJson);
returnJson= commonServices[0].transCodeZN(returnJson);
Long end=System.currentTimeMillis();
log.debug(TextUtils.format("-----码表转换结束-----"));
log.debug(TextUtils.format("码表转换解析需要时间为:{0}毫秒", end - start));
}
return returnJson;
}
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;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Map getResultMap() {
return resultMap;
}
public void setResultMap(Map resultMap) {
this.resultMap = resultMap;
}
}
字典表转换类
package com.limp.framework.boss.service.impl;
import com.limp.framework.boss.domain.DicCode;
import com.limp.framework.boss.domain.PageLog;
import com.limp.framework.boss.mapper.oracle.PageLogMapper;
import com.limp.framework.boss.service.CacheService;
import com.limp.framework.boss.service.CommonService;
import com.limp.framework.boss.service.SysService;
import com.limp.framework.core.bean.Pager;
import com.limp.framework.core.constant.Constant;
import com.limp.framework.utils.StrUtils;
import com.limp.framework.utils.TextUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
/**
* @Description: 通用类实现方法
* @Author: zzh
* @Modified By:
* @Date: 2018/10/17 16:54
*/
@Service
public class CommonServiceImpl implements CommonService {
private static Logger log= Logger.getLogger(CommonServiceImpl.class);
@Resource
private PageLogMapper pageLogMapper;
@Resource
private CacheService cacheService;
/**
*字典码表
*/
@Autowired
private SysService dictCodesService;
@Override
public void insertPageLog(PageLog pageLog) {
try{
if (StrUtils.isBlank(pageLog.getId())) {
pageLog.setId(StrUtils.randomUUID());
}
if (StrUtils.isBlank(pageLog.getState())) {
pageLog.setState(Constant.STATE_EFFECTIVE);
}
if (StrUtils.isBlank(pageLog.getIdt())) {
pageLog.setIdt(new Date());
}
pageLogMapper.insert(pageLog);
}catch (Exception e){
log.debug("/****日志记录异常************/");
e.printStackTrace();
}
}
@Override
public String transCodeZN(String jsonStr) {
//lp_code_ }或者]结尾【定义需要替换CODE的正则匹配规则】
final String pattern= Constant.CODE_TRANS_PRE+"(.*?)[,|\\}|\\]]";
//key 的集合 (唯一;去重)
List listUnKsy=new ArrayList();
//需要转化的码表 key 和value对应集合
List<Map<String,String>> listMapMath=new ArrayList<Map<String,String>>();
//匹配List得到的Group分组
List<String> groups= StrUtils.getRegGroupList(jsonStr, pattern);
Long start=System.currentTimeMillis();
log.debug(TextUtils.format("-----获取key-value值-----"));
for(String group:groups){
// String []groupArr=group.split(":");
//需要转换Key:value
String codeMath=group.replaceAll("\'|\"", "");
if(codeMath.indexOf(Constant.CODE_SUF)>-1){
// String pre=groupArr[0].substring(0,groupArr[0].indexOf(Constant.CODE_SUF)+1);
// String codeMath=pre+groupArr[1].replaceAll("\'|\"", "");
//如果该value值已经获取相应的码值,则不再进行查询
if(!StrUtils.isBlank(codeMath)&&!listUnKsy.contains(codeMath)){
listUnKsy.add(codeMath);
Map<String,String> code=new HashMap<String,String>();
String value=getCacheCodeValue(codeMath);//commonService.getCacheCodeValue(codeMath);
//只有value不为空,才进行转化
if(!StrUtils.isBlank(value)){
code.put("key",Constant.CODE_TRANS_PRE+group);
code.put("value", value);
code.put("pre",group.indexOf("\"")>-1?"\"":"\'" );
listMapMath.add(code);
}
}
}
}
Long end=System.currentTimeMillis();
log.debug(TextUtils.format("----->获取key-value值需要时间{0}[key-value]-----",(end-start)));
//循环转换字典表
for(Map<String,String> mapF:listMapMath){
//获取需要转换的key
final String reg=mapF.get("key");
// final String reg="('"+mapF.get("key")+"':|\""+mapF.get("key")+"\":|"+mapF.get("key")+":)";
// String reg=":"+key+"|:'"+key+"'|:\""+key+"\"";
//转换后的信息 ":"男" 注意,转后的应该带上引号,是描述信息
final String replaceVal=mapF.get("pre")+":"+mapF.get("pre")+mapF.get("value")+mapF.get("pre");
try {
jsonStr=jsonStr.replaceAll(reg,replaceVal);
}catch (Exception e){
log.error("-->正则转化异常");
e.printStackTrace();
}
}
// jsonStr=jsonStr.replaceAll(Constant.CODE_TRANS_PRE+"(.*?)#","");
return jsonStr;
}
@Override
public String getCacheCodeValue(String key) {
log.debug(TextUtils.format("-->getCacheCodeValue方法调用;Key值:{0}",key));
String val= cacheService.get(key);
if(StrUtils.isBlank(val)){
log.debug(TextUtils.format("-->无此key({0})值得缓存,开始添加到缓存池<--",key));
DicCode dicCodes=new DicCode();
String dictKey[]=key.split(Constant.CODE_SUF);
dicCodes.setDictKey(dictKey[0]);
dicCodes.setDictValue(dictKey[1]);
Pager<DicCode> list=dictCodesService.getDicPageList(dicCodes,new Pager(1,1));
for(DicCode codes:list
.getDataList()){
cacheService.set(key,codes.getDictName());
log.debug(TextUtils.format("添加缓存数据 set key:{0} value:{1}",
key, codes.getDictName()));
}
val=cacheService.get(key);
log.debug("reload cache key----> "+val);
}
return val;
}
}
主要是这两个类,其它的有需要深入了解 的可以下方留言
在保证正常业务的流程下,码表转化该方法还是比较方便的,有其它方法也欢迎留言