公司需求如下:用户当前操作和上一次保存操作进行对比,然后显示到前端web弹窗,首先上一次操作毕竟是日志,包含了各种各样的操作,同事就用类外加整个对象来标识到底是对什么进行了操作,就才会有如下的className这个东西,同时要对当前的操作,也就是update的整个对象和之前存储日志的className这个东西进行对比,json的比较就是第一步!
JAVADEMO
package com.gisquest.tdcb.tdcbitem.utils;
import com.alibaba.fastjson.JSONObject;
import com.gisquest.realestate.utils.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import java.util.Iterator;
/**
* Created by Administrator on 2019/7/20.
*/
public class Demo {
public static void main(String[] args) {
String className = "yscdkData";
StringBuffer sb = new StringBuffer();
// String st1 = "{\"dmj\":1111.0}";
// String st1 = null;
// String st2 = "{\"yscdkData\":{\"dmj\":33.0,\"dswQksm\":\"22\"}}";
/* before */
String st1 = "{\"dmj\":1111.0,\"dswQksm\":\"22\",\"xmCj\":\"3\",\"cqMj\":0,\"sfyCbz\":\"1\",\"yxgmMj\":0,\"lmj\":1111.0,\"pcXzmj\":3,\"yxgmZc\":0,\"tdqqKfcb\":-1,\"qtfsqdMj\":0,\"pgFs\":\"2\",\"zjCb\":0,\"zyzyZc\":0,\"qtZc\":0,\"tdjb\":\"2\",\"sjCb\":-1,\"sgMj\":0,\"tdsgZc\":0,\"dwMc\":\"杭州市余杭区土地储备发展中心\",\"zdBh\":\"201901019\",\"nrCbLy\":\"4\",\"haveJzd\":0,\"sbSj\":1562169600000,\"sflyDxtd\":\"0\",\"sflyXztd\":\"1\",\"dswQk\":\"1\",\"xmZt\":\"13\",\"ghFs\":\"3\",\"zdZl\":\"临平新城核心区A-3-06拟招拍挂地块(东至星河南路、南至文正街、西至河道、北至东仁街)\",\"clMj\":0,\"lydxtdMj\":0,\"zszyMj\":1,\"xzqDm\":\"330110\",\"dkMc\":\"e\",\"pgj\":333,\"jzdjnh\":\"3\",\"qtCb\":0,\"qqKfqk\":\"222\",\"createDate\":1562169600000,\"zdMj\":1,\"dzBaBh\":\"3301102015S00635\",\"cqbcazZc\":0,\"nrCbSj\":1562169600000,\"tCbGhyt\":[{\"modifyDate\":1562169600000,\"ghytGuid\":\"c1be0530-a06e-fdf4-78a9-9839245c4e1a\",\"ghytMj\":1,\"tdYt\":\"6\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1562169600000}],\"cbjgGuid\":\"6b70a1e4-cb83-1e9f-9aca-c8a53f8a1b30\",\"sczGuid\":\"9d7dffc2-9c74-4671-82cd-d7a902112d65\",\"shMj\":0,\"tdshZc\":0,\"tdmqzt\":\"333\",\"rkDkbh\":\"1212\",\"tCbCbglpws\":[{\"zpcmj\":111,\"cbglpwGuid\":\"42f44bca-ab7f-66b8-84ec-f1b3dc882724\",\"xzMj\":3,\"cbdkGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"pzWh\":\"333\"}],\"tCbzs\":[{\"cbzBh\":\"3\",\"modifyDate\":1563465600000,\"zzMj\":3,\"qlrMc\":\"3\",\"cbzGuid\":\"cc616b0f-606f-887c-dcaa-6ee5527e8404\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1563465600000}],\"createUser\":\"yhcbjg\",\"tdQdCb\":0,\"isNdzcpg\":\"0\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"lyxztdMj\":0}";
/* after */
String st2 = "{\"yscdkData\":{\"dmj\":1111.0,\"dswQksm\":\"22\",\"xmCj\":\"3\",\"cqMj\":0,\"sfyCbz\":\"1\",\"yxgmMj\":0,\"lmj\":1111.0,\"pcXzmj\":3,\"yxgmZc\":0,\"tdqqKfcb\":-1,\"qtfsqdMj\":0,\"pgFs\":\"2\",\"zjCb\":0,\"zyzyZc\":0,\"qtZc\":0,\"tdjb\":\"2\",\"sjCb\":-1,\"sgMj\":0,\"tdsgZc\":0,\"dwMc\":\"杭州市余杭区土地储备发展中心\",\"zdBh\":\"201901019\",\"haveJzd\":0,\"sbSj\":1562169600000,\"sflyDxtd\":\"0\",\"sflyXztd\":\"1\",\"dswQk\":\"1\",\"xmZt\":\"13\",\"ghFs\":\"3\",\"zdZl\":\"临平新城核心区A-3-06拟招拍挂地块(东至星河南路、南至文正街、西至河道、北至东仁街)\",\"clMj\":0,\"lydxtdMj\":0,\"zszyMj\":1,\"xzqDm\":\"330110\",\"dkMc\":\"4445ABCD\",\"pgj\":333,\"jzdjnh\":\"3\",\"qtCb\":0,\"qqKfqk\":\"222\",\"createDate\":1562169600000,\"zdMj\":1,\"cqbcazZc\":0,\"nrCbSj\":1562169600000,\"tCbGhyt\":[{\"modifyDate\":1562169600000,\"ghytGuid\":\"c1be0530-a06e-fdf4-78a9-9839245c4e1a\",\"ghytMj\":1,\"tdYt\":\"6\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1562169600000}],\"cbjgGuid\":\"6b70a1e4-cb83-1e9f-9aca-c8a53f8a1b30\",\"sczGuid\":\"9d7dffc2-9c74-4671-82cd-d7a902112d65\",\"shMj\":0,\"tdshZc\":0,\"tdmqzt\":\"333\",\"rkDkbh\":\"1212\",\"tCbCbglpws\":[{\"zpcmj\":111,\"cbglpwGuid\":\"42f44bca-ab7f-66b8-84ec-f1b3dc882724\",\"xzMj\":3,\"cbdkGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"pzWh\":\"333\"}],\"tCbzs\":[{\"cbzBh\":\"3\",\"modifyDate\":1563465600000,\"zzMj\":3,\"qlrMc\":\"3\",\"cbzGuid\":\"cc616b0f-606f-887c-dcaa-6ee5527e8404\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1563465600000}],\"createUser\":\"yhcbjg\",\"isNdzcpg\":\"0\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"lyxztdMj\":0}}";
getCompareOpt(className, sb, st1, st2);
}
/**
* 旧数据和当前保存的数据进行比较,,返回比较的字符串,不是json
*
* @param className
* @param sb
* @param str1
* @param str2
* @return
* @date Xuhy, 2019-07-20 14:57
*/
public static String getCompareOpt(String className, StringBuffer sb, String str1, String str2) {
if (!StringUtils.isEmpty(str1)) {
// 取出st1属性数组
Iterator<String> st1keyArrs = JSONObject.parseObject(str1).keySet().iterator();
// 取出st2属性数组--当前是根据我公司的数据结构,可以按照情况自行修改
JSONObject jsonObject2 = JSONObject.parseObject(str2).getJSONObject(className);
// System.out.println(str1);
// System.out.println(jsonObject2);
// 取出st2属性数组
Iterator<String> st2keyArrs = jsonObject2.keySet().iterator();
// 将st1和st2转换成json进行json比较
JSONObject json1 = JSONObject.parseObject(str1);
JSONObject json2 = JSONObject.parseObject(JSONObject.parseObject(str2).get(className).toString());
// 前json和后json比较--返回是修改和删除
getCompareBA(st1keyArrs, json1, json2, sb);
// 后json和前json比较--返回是新增
getCompareAB(st2keyArrs, json1, json2, sb);
String compareOpt = "{\"className\":\"" + className + "\",\"changeContent\":[" + sb.substring(0, sb.length() - 1) + "]}";
System.out.println("--------------------compareOpt--------------------");
System.out.println(compareOpt);
System.out.println("--------------------compareOpt--------------------");
return compareOpt;
} else {
String compareOpt = "{\"className\":\"" + className + "\",\"changeContent\":[" + JSONObject.parseObject(str2).toString() + "]}";
System.out.println("--------------------compareOptOrg--------------------");
System.out.println(compareOpt);
System.out.println("--------------------compareOptOrg--------------------");
return compareOpt;
}
}
/**
* @Description: 前JSON和后JSON比较
* @Param: beforeKeySet
* @Param: afterJson
* @Return: 之前和之后的删除和修改操作
* @CreateDate: Xuhaiyan
*/
private static void getCompareBA(Iterator<String> beforeKeySet, JSONObject beforeJson, JSONObject afterJson, StringBuffer sb) {
while (beforeKeySet.hasNext()) {
// 上比下
String key = beforeKeySet.next();
if (afterJson.get(key) == null) {
sb.append("{\"" + key + "\": \"" + beforeJson.get(key) + "删除变成空\"},");
// System.out.println("有变化--删除操作 key:" + key + ",value:" + afterJson.get(key));
} else if (beforeJson.get(key) != null && afterJson.get(key) != null && !afterJson.get(key).equals(beforeJson.get(key))) {
// 字符串转义至关重要,对于多层次的必须如下处理
System.out.println();
sb.append("{\"" + key + "\": \"" + StringEscapeUtils.escapeJava(afterJson.get(key).toString()) + "修改成" + StringEscapeUtils.escapeJava(beforeJson.get(key).toString()) + "\"},");
// System.out.println("有变化--修改操作 key:" + key + ",value:" + afterJson.get(key));
}
}
}
/**
* @Description: 后JSON和钱JSON比较
* @Param: afterKeySet
* @Param: beforeJson
* @Return: 之后属性新增内容
* @CreateDate: Xuhaiyan
*/
private static void getCompareAB(Iterator<String> afterKeySet, JSONObject beforeJson, JSONObject afterJson, StringBuffer sb) {
while (afterKeySet.hasNext()) {
// 下比上
String key = afterKeySet.next();
if (beforeJson.get(key) == null) {
//删除操作
sb.append("{\"" + key + "\": \"新增" + beforeJson.get(afterJson.get(key).toString()) + "\"},");
}
}
}
}
字符串转义demo
public class demo3 { public static void main(String[] args) { String str = "{\\\"name\\\":\\\"spy\\\"}"; System.out.println("原始 str = " + str); String str1 = StringEscapeUtils.unescapeJava(str); String str2 = StringEscapeUtils.escapeJava(str); System.out.println("目标 str1 = " + str1); System.out.println("目标 str2 = " + str2); } }
原始 str = {\"name\":\"spy\"}
目标 str1 = {"name":"spy"}
目标 str2 = {\\\"name\\\":\\\"spy\\\"}
转义必须添加上,才会组成jsong格式的字符串!!效果如下所示,多层次加转义,如果不是则不转义!!!
{"className":"yscdkData","changeContent":[{"zdBh": "1212修改成201901020"},{"zdZl": "ddd修改成\u4E34\u5E73\u65B0\u57CE\u6838\u5FC3\u533A\u8FCE\u5BBE\u8DEF\u4EE5\u897F\u3001\u671B\u6885\u8DEF\u4EE5\u5317\u5730\u5757(\u4E1C\u81F3\u8FCE\u5BBE\u8DEF\u3001\u5357\u81F3\u671B\u6885\u8DEF\u3001\u897F\u81F3\u65B0\u4E30\u8DEF\u3001\u5317\u81F3\u6587\u95F2\u8857)"},{"tCbGhyt": "[{\"modifyDate\":1562169600000,\"ghytGuid\":\"c1be0530-a06e-fdf4-78a9-9839245c4e1a\",\"ghytMj\":1,\"tdYt\":\"2\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1562169600000}]修改成[{\"modifyDate\":1562169600000,\"ghytGuid\":\"c1be0530-a06e-fdf4-78a9-9839245c4e1a\",\"ghytMj\":1,\"tdYt\":\"8\",\"cbGuid\":\"31bb176e-7c28-01be-d245-1bc0617a6916\",\"createDate\":1562169600000}]"},{"sczGuid": "686db12d-c008-42ad-bc37-3bfea21b7c69修改成027dc564-5557-4546-b642-1d3d431a37b2"}]}
WEBDEMO-ANGULAR7
第二步骤就是对整个返回的日志list,进行type筛选,如果是操作更新,则单独处理,毕竟普通人又不是程序员需要变换成中文展示
数据结构List
getServe() { // 假数据-徐海燕 // this.operateLogDTO.ywGuid = 'f3fd665c-2427-7839-d647-474eb3cfadc0'; // this.operateLogDTO.ywLx = 'TDCB_NSCDK'; // 所有的未筛选数据 let orgArrs = []; this.operateService.listOperateLog(this.operateLogDTO).subscribe(res => { if (res.status === 200 && res.data != null) { orgArrs = res.data.list; // 筛选数据排除[自定义比较的JSON数据]--xuhaiyan[upd] this.operateLogList = res.data.list.filter(compareOpt => compareOpt.operation != '操作变更'); this._total = res.data.total; // 转换operateLogList, 把operateInfo转换为xx意见 this.transferXXyj(this.operateLogList); } this._loading = false; }, error1 => { }, () => { const validator = new Validator(); // 对于操作变更数据的操作--xuhaiyan[add] let compareOptArr = orgArrs.filter(compareOpt => compareOpt.operation === '操作变更'); compareOptArr.forEach(c => { // 解析数据库的字符串[变成之前中文xx之后中文] let compareText = this.getCompareOpt(JSON.parse(c.operateInfo)); // 覆盖原先的operateInfo 反转义unescape if (validator.isEmpty(compareText)) { c.operateInfo = '请补充完整配置信息'; } else { c.operateInfo = eval('\'' + compareText + '\''); } // 放回原先的数组 this.operateLogList.push(c); }); console.log('实际上办理日志-----------------------------------------?????看我看我!'); console.log(this.operateLogList); console.log('实际上办理日志-----------------------------------------?????看我看我!'); }); }
//--------------------------------------------compareOptStr---------------------------------------------------------
optionUpd = '修改成';
/*optionKV = [
// 拟收储
{'tCbSczDk': ['dwMc|储备机构名称', 'zdBh|收储地块编号', 'xzqDm|座落行政区', 'zdMj|宗地面积', 'zdZl|座落', 'tdYt|规划用途', 'dzBaBh|电子监管号', 'pzSj|批准日期', 'ncdLy|拟取得方式']},
//已收储【新增入库地块】
{'yscdkData': ['zdBh|拟收储地块编号', 'rkDkbh|入库地块编号', 'dkMc|地块名称', 'zdZl|地块座落', 'zdMj|入库地块面积', 'nscDkMj|拟收储地块面积', 'pcXzmj|农转征新增面积合计', 'clMj|国有存量建设用地', 'zdZl|地块座落', 'zszyMj|实际征收和转用的农用地面积', 'cqMj|实际征收、拆迁的建设用地面积', 'shMj|实际依法收回的面积', 'sgMj|实际依法收购的面积', 'yxgmMj|实际行使优先购买权的面积', 'qtfsqdMj|实际通过其他方式取得的面积', 'sflyXztd|是否来源于闲置土地', 'lyxztdMj|来源于闲置土地面积', 'sflyDxtd|是否来源于低效/“三旧”改造土地', 'lydxtdMj|来源于低效/“三旧”改造土地面积', 'nrCbLy|取得方式', 'tdQdCb|实际发生成本', 'dswQk|地上物情况', 'dswQksm|地上物情况说明', 'qqKfqk|前期开发情况', 'nrCbSj|入库时间', 'ghFs|管护方式', 'lslyFs|临时利用情况', 'tdjb|土地级别', 'lmj|楼面价', 'dmj|地面价', 'jzdjnh|基准地价内涵', 'pgj|资产评估价值', 'pgFs|资产价值评估方法', 'tdmqzt|土地目前情况', 'isNdzcpg|年度资产评估', 'sjCb|项目实际发生成本', 'zyzyZc|农用地征收和转用支出', 'cqbcazZc|拆迁补偿安置支出', 'tdshZc|土地收回支出', 'tdsgZc|土地收购支出', 'yxgmZc|优先购买支出', 'qtZc|其他有关支出', 'tdqqKfcb|土地前期开发成本', 'zjCb|资金成本', 'qtCb|其他成本']},
// {'yscdkData': ['tCbGhyt|土地规划情况']},
];*/
decorators = ['tCbSczDk', 'yscdkData'];
/**
* @description 根据operateInfo存储的字符串进行页面用户看得懂的中文翻译
* @param json
* @demo
* var json = {
'className': 'nccdk',
'changeContent': [{'dwMc': '宁波储备机构变成温州B储备机构'}, {'zdBh': '1110504135变成140104130124'}]
};
* @PS 注意数据有3种格式“修改成”/“删除变成空”/“新增”
* @author xuhy 2019/07/18 21:39
*/
private getCompareOpt(json: any): string {
const validator = new Validator();
// 最终返回的option_info
let text: string = '';
// JSON Reflect对象
let obj: any;
// JSON Reflect对象的英文名称如‘yscdkData’/‘tCbSczDk’
let className = json.className;
// 所有的中文处理首先放到这个数组里面
let optArr: any[] = [];
// 根据当前json的className值,去获取得到解析的对象,封装回到当前decorators数组[当前数组只会有一个符合条件的List]
this.decorators = this.decorators.filter(decorator => decorator === className);
if (validator.arrayNotEmpty(this.decorators)) {
let decorator = this.decorators[0];
if (decorator === 'yscdkData') {
// console.log(Reflect.getMetadata(`${eName}`, new Tdcbdk(), `${eName}`));
obj = new Tdcbdk();
}
json.changeContent.forEach(changeContentOne => {// [{zdBh: "201901020修改成1212"}]
for (var key in changeContentOne) {// 英文名称Key
let val = changeContentOne[key]; // 值
let reflectName = Reflect.getMetadata(`${key}`, obj, `${key}`); // 注释中文
let cName = validator.isEmpty(reflectName) ? `${key}` : reflectName;// 中文名称是否为空判断,如果注释中文为空,则默认显示英文属性名称,如果不为空则显示中文属性名称
// console.log(`---KV参数,Ekey:${key},Ckey:${cName},val:${val}---`);
// 修改JSON判断
if (validator.contains(val, this.optionUpd)) {
if (!validator.isJSON(val.split(this.optionUpd)[0])) {
// 201901020不是JSON 单层处理
let st1 = val.replace(`${key}`, `${cName}`);
optArr.push(JSON.parse('{"' + cName + '":"' + st1 + '"}'));
} else {
let updJSONArrs = this.notJSONCompare(validator, `${val}`, this.optionUpd, obj);
updJSONArrs.forEach(e => {
optArr.push(e);
});
}
}
}
});
}
optArr.forEach((o: any, i: number) => {
let o_text: string = JSON.stringify(o).substr(1, JSON.stringify(o).length - 2).replace('":"', '变更内容:');
// 按照右侧格式显示[储备机构名称变更内容:宁波储备机构变成温州B储备机构,收储地块编号变更内容:1110504135变成140104130124。]
if (i < optArr.length - 1) {
o_text = o_text.substring(1, o_text.length - 1) + ',';
} else {
o_text = o_text.substring(1, o_text.length - 1) + '。';
}
text = text + o_text;
});
return text;
}
// change:修改成
private notJSONCompare(validator, notJsonStr: string, change: string, obj: any) {
let arr = [];
if (validator.isNotEmpty(notJsonStr)) {
if (notJsonStr.indexOf(change) >= 0) {
let obj1 = notJsonStr.split(change)[0];
let obj2 = notJsonStr.split(change)[1];
for (var key in (JSON.parse(obj1))[0]) {
let beforeVal = (JSON.parse(obj1))[0][key];
let afterVal = (JSON.parse(obj2))[0][key];
if (beforeVal != afterVal) {
let reflectName = Reflect.getMetadata(`${key}`, obj, `${key}`); // 注释中文
let cName = validator.isEmpty(reflectName) ? `${key}` : reflectName;// 中文名称是否为空判断,如果注释中文为空,则默认显示英文属性名称,如果不为空则显示中文属性名称
console.log(`---参数,中文注释参数是否为空:${validator.isEmpty(reflectName)},中文注释:${reflectName},空则取原来的英文注释eName:${key}---`);
let str = '{"' + cName + '": "' + beforeVal + '修改成' + afterVal + '"}';
arr.push(str);
}
}
}
return arr;
}
}
//--------------------------------------------compareOptStr---------------------------------------------------------
最终前端效果
json在线比较工具:https://www.sojson.com/jsondiff.html
总结:之前json比较看了这篇文章https://blog.csdn.net/wangjin890620/article/details/81011461,用了一下确实可以自己也改了一下,但是场景发现如果比较的字段少还行,如果字段很多80多并且要输出这个stringbuffer的时候就会报内存溢出,当然作者的sout都是好使的,百思不得其解了,同伴们说死循环和空指针判断问题,于是自己修改了一下!有问题还会再改自己的代码,这个还是初版,思路就是上一个json和下一个json比较后,再反过来比较一次,一共比较两次,这样就知道新增、修改、删除三个点的内容。
-
class-validator
新知识点:https://angular.cn/tutorial/toh-pt2#style-the-heroes 用于是否为空 是否是xx的各种判断 email 【npm install class-validator --save】