在公司已经实习一段时间了,最近分到了一个任务是将php转java的重构项目,导师让我做稳定性检测,输入原来和现在的接口,检测两个是否一致,之前了解过postMan软件,但是特定的需求可能还有问题。感觉这个项目让我重新学习了FastJson,下面写一下工具的整理架构
- 前端--Vue
- 后端--Springboot+IDEA软件
- 后端:
输入--两个除了IP不同其余相同的接口
输出--标准的Json
1、Controller-控制层
@RequestMapping("/check2")
@ResponseBody
public Result byJsonMethod(
@RequestParam("requestUrl") String requestUrl,
@RequestParam("requestUrl2") String requestUrl2) {
Date date = new Date();
JSONObject result = new JSONObject();
String json_string1 = diffService.getJson_String(requestUrl);
JSONObject jsonObject1 = JSONObject.parseObject(json_string1);
String json_string2 = diffService.getJson_String(requestUrl2);
JSONObject jsonObject2 = JSONObject.parseObject(json_string2);
// JSONObject jsonObject = new JSONObject();
//将检查结果封装到map集合中
JSONObject resultByJson = diffService.getResultByJson(jsonObject1, jsonObject2);
// 将两个url结果返回到前端
if(resultByJson.getJSONObject("diff").size()>=1){
return ResultGenerator.genOkResult(resultByJson,"两个接口返回值不一致");
}else {
return ResultGenerator.genOkResult(resultByJson);
}
}
(1)调用service层获取两个接口的返回结果以string返回
(2)调用service层getResultByJson检测方法,得到结果检测
(3)判断检测内容是否为空,若为空返回正确Json,否则返回具体信息。
2、Service业务层
<1>方法1:根据传入的接口去请求,获得请求结果
/**
* 通用方法抽取-将url请求的结果变为String字符串返回
* @param Url
* @return
*/
@Override
public String getJson_String(String Url) {
//返回结果
String res="";
StringBuffer buffer = new StringBuffer();
try{
//创建url,此处可以动态扩展,拼接
URL url = new URL(Url);
HttpURLConnection urlCon= (HttpURLConnection)url.openConnection();
if(200==urlCon.getResponseCode()){
InputStream is = urlCon.getInputStream();
InputStreamReader isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr);
String str = null;
while((str = br.readLine())!=null){
buffer.append(str);
}
br.close();
isr.close();
is.close();
res = buffer.toString();
}
}catch(IOException e){
System.out.println("访问不成功");
}
return res;
}
在这个方法后期可以根据参数自己进行拼接-接口请求,此方法对应Controller层第一层。
<2>根据传入的结果,进行检查,以下为第一次使用的将json封装到Map、list集合等
/**
* 将请求的URL变成Json格式传入,输出<错误1:具体位置>这种map集合的格式
* @param json
* @return map
*/
@Override
public Map<String, String> getResultByJson(String json,String json2) {
// 0.方法返回结果
Map<String, String> resultMap = new HashMap<String, String>();
// 1、分解第一层
int i = 1;
Map<String, Object> map1 = JSONObject.parseObject(json, Map.class);
Object ss = JSONObject.parseObject(json);
Map<String, Object> map2 = JSONObject.parseObject(json2, Map.class);
for (String key : map1.keySet()) {
// 根据每次得到的map1集合中的key,map2.contains()方法判断是否含有key,
if (map2.keySet().contains(key)) {
// 如果含有则利用equals方法判断value的值是否相等
// 如果有相同的key,判断是否有嵌套情况或者再次复杂的情况
// (1)key对应的为数组,数组中嵌套json。
// (2)key对应的为json。
// (3)key对应的为json,json再次嵌套数组-json
resultMap = generalMethod(map1.get(key), map2.get(key), i,resultMap);
/*
int status = diffTools.verificationBykey(map1.get(key));
int status2 = diffTools.verificationBykey(map2.get(key));
// 两种URL虽然key相等,但是对应的value类型不想等,例如一个是数组,另一个是json
if(status!= status2){
resultMap.put("第"+i+"处error","key对应的value类型不一致");
continue;
}
// 两种URL类型相等,都是嵌套了一个数组,需要继续进行解析
if (status==1){
// JSONArray jsonArray1 = JSONArray.parseArray(map1.get(key).toString());
// JSONArray jsonArray2 = JSONArray.parseArray(map1.get(key).toString());
// 将数组结果封装到list<String>集合中
List<Object> listString1 = JSONArray.parseArray(map1.get(key).toString(), Object.class);
List<Object> listString2 = JSONArray.parseArray(map2.get(key).toString(), Object.class);
for (Object arrString1:listString1) {
}
}
// 两种URL类型相等,都是嵌套了一个json,需要继续进行解析
if(status==2){
Map<String, Object> map12 = JSONObject.parseObject(map1.get(key).toString(), Map.class);
Map<String, Object> map13 = JSONObject.parseObject(map2.get(key).toString(), Map.class);
}
// 两种URL类型相等,都是普通的键值对,可以直接判断
if (status==3){
boolean result_value = map1.get(key).equals(map2.get(key));
if(result_value==false){
resultMap.put("第"+i+"错误","key:"+key+"对应的value不同");
}
}
/*
// try {
// map1.get(key).toString();
// } catch (Exception e) {
//
// }
// if (map1.get(key).equals(map2.get(key))) {
// 两个json对应的key-value都相等
// System.out.println("");
//
// } else {//添加错误的返回值
//
// String s1 = "url1中的key:" + key + "对应的值:" + map1.get(key) + "和在url2不相等!";
//
// System.out.println("不相同的地方为值不想等:url1中的key:" + key + "对应的值:" + map1.get(key) + "和在url2返回结果不想等!");
// }*/
} else {
String s2 = "url1中的key:" + key + "在url2不存在";
resultMap.put(key+"出现错误", s2);
}
}
return resultMap;
}
/**
* 迭代判断公用方法
* @param o1
* @param o2
* @param i
* @param resultMap
* @return
*/
public Map<String,String> generalMethod(Object o1,Object o2,int i,Map resultMap) {
int status = diffTools.verificationBykey(o1);
int status2 = diffTools.verificationBykey(o2);
// 两种URL虽然key相等,但是对应的value类型不想等,例如一个是数组,另一个是json
if (status != status2) {
resultMap.put("第" + i + "层error", "key对应的value类型不一致");
}
// 两种URL类型相等,都是嵌套了一个数组,需要继续进行解析
if (status == 1) {
// JSONArray jsonArray1 = JSONArray.parseArray(map1.get(key).toString());
// JSONArray jsonArray2 = JSONArray.parseArray(map1.get(key).toString());
// 将数组结果封装到list<String>集合中
List<Object> listString1 = JSONArray.parseArray(o1.toString(), Object.class);
List<Object> listString2 = JSONArray.parseArray(o2.toString(), Object.class);
if (listString1.size() != listString2.size()) {
resultMap.put("第" + i + "层error", "长度不一致");
return resultMap;
}
for (int j = 0; j < listString1.size(); j++) {
resultMap=generalMethod(listString1.get(j), listString2.get(j), i+1,resultMap);
}
}
// 两种URL类型相等,都是嵌套了一个json,需要继续进行解析
if (status == 2) {
Map<String, Object> map12 = JSONObject.parseObject(o1.toString(), Map.class);
Map<String, Object> map13 = JSONObject.parseObject(o2.toString(), Map.class);
if (map12.size() != map13.size()) {
resultMap.put("第" + i + "层error", "长度不一致");
return resultMap;
}
for (String key : map12.keySet()) {
// 根据每次得到的map1集合中的key,map2.contains()方法判断是否含有key,
i++;
if (map13.keySet().contains(key)) {
resultMap = generalMethod(map12.get(key), map13.get(key), i+1,resultMap);
} else {
resultMap.put("", "key不包含");
}
}
}
// 两种URL类型相等,都是普通的键值对,可以直接判断
if (status == 3) {
boolean result_value = o1.equals(o2);
if (result_value == false) {
resultMap.put("第" + i + "错误", "key对应的value不同");
}
}
return resultMap;
}
后期对以上处理方式进行了修改,采用了直接使用Json判断,省去了转成map等集合的开销,但是Json转成map等集合仍有值得学习的地方,这里进行保留。
<3>由于Json中嵌套的类型多种多样,包括null、jsonArray、JsonObject等,所以需要判断key对应的value所属的数据类型。抽取为utils工具类
public int verificationBykey(Object value){
//获取第一个字符
if(value==null){
return 0;
}
String ac = value==null?"null":value.toString();
char a = ac.charAt(0);
switch (a){
// 开头[,表示嵌套了一个数组
case '[':
return 1;
// 开头为{,表示嵌套的是一个JsonObject对象
case '{':
return 2;
// 开头为",表示普通值并没有嵌套过程
default:
return 3;
}
}
通过以上判断可以处理时采用迭代递归的方法判断Json中是否有嵌套的类型,以及嵌套了什么类型,然后在判断。所以这一步很重要。
<4>封装集合提升为使用JsonObject直接处理方法
/**
* 使用json方法,不使用map--通用属性的抽取
* @param o1
* @param o2
* @param i
* @param resultJson
* @return
*/
@Override
public JSONObject generalMethod(Object o1, Object o2, int i, int j,JSONObject resultJson,String original_key) {
int status = diffTools.verificationBykey(o1);
int status2 = diffTools.verificationBykey(o2);
// 两种URL虽然key相等,但是对应的value类型不想等,例如一个是数组,另一个是json
if (status != status2) {
resultJson.put(++j+"", "在" + i + "层错误,"+original_key+"对应的值类型不一致。value1:"+o1+";value2:"+o2);
}
// 两种URL类型相等,都是嵌套了一个数组,需要继续进行解析
if (status == 1) {
JSONArray jsonArray1 = JSONArray.parseArray(o1.toString());
JSONArray jsonArray2 = JSONArray.parseArray(o2.toString());
if (jsonArray1.size() != jsonArray2.size()) {
resultJson.put(++j+"", "在"+i+"层错误,结构不一致");
return resultJson;
}
for (int k = 0; k < jsonArray1.size(); k++) {
//数组不当做嵌套关系,平级关系,所以这里i不在+1。所以key也不需要传入复合状态。
resultJson=generalMethod(jsonArray1.get(k), jsonArray2.get(k), i,j,resultJson,original_key);
}
}
// 两种URL类型相等,都是嵌套了一个json,需要继续进行解析
if (status == 2) {
JSONObject jsonObject1 = JSONObject.parseObject(o1.toString());
JSONObject jsonObject2 = JSONObject.parseObject(o2.toString());
if (jsonObject1.size() != jsonObject2.size()) {
resultJson.put(++j+"", "在" + i + "层错误,结构不一致");
return resultJson;
}
for (String key : jsonObject1.keySet()) {
// 根据每次得到的map1集合中的key,map2.contains()方法判断是否含有key,
if (jsonObject2.keySet().contains(key)) {
resultJson = generalMethod(jsonObject1.get(key), jsonObject2.get(key), i+1,j,resultJson,original_key+":"+key);
} else {
resultJson.put(++j+"", "第" + i + "层错误,接口1中的key:" + key + " 在接口2结果中不存在");
}
}
}
// 两种URL类型相等,都是普通的键值对,可以直接判断
if (status == 3) {
boolean result_value = o1.equals(o2);
if (result_value == false) {
//考虑如何更友好的显示到前端
resultJson.put(++j+"-"+original_key,"在" + i + "层错误,"+original_key+"对应的value不同。value1:"+o1+"。value2:"+o2);
//resultJson.put(original_key,"对应的值不一致");
}
}
return resultJson;
}
/**
* Json方式-----遍历第一层
* @param json1
* @param json2
* @return
*/
@Override
public JSONObject getResultByJson(JSONObject json1, JSONObject json2) {
// 0.方法返回结果
JSONObject resultJson = new JSONObject();
JSONObject resultJson_final = new JSONObject();
resultJson_final.put("data_api_1",json1);
resultJson_final.put("data_api_2",json2);
// 1、分解第一层
int i = 0;
int j = 1;
if(json1.size()!=json2.size()){
resultJson.put(j+"","在"+i+"层错误,二者体系结构不同");
resultJson_final.put("diff",resultJson);
return resultJson_final;
}
for (String key : json1.keySet()) {
// 根据每次得到的key,map2.contains()方法判断是否含有key,
if (json2.keySet().contains(key)) {
resultJson = generalMethod(json1.get(key), json2.get(key), i+1,j,resultJson,key);
} else {
resultJson.put(j+"", "在"+i+"层错误,接口1中的key:" + key + "在接口2不存在");
}
}
resultJson_final.put("diff",resultJson);
return resultJson_final;
}
(1)首先判断体系结构是否相同。
(2)若体系结构相同,判断Json格式是哪一种类型:
key:value || key:jsonArray || key:JsonObject
如果是第一种普通键值对形式则直接判断value是否相等,若是后两者需要递归进行判断,直到遇到普通键值对,然后向上返回逐步判断。
3、标准化返回结果
最后将数据标准化输出,创建了两个类
(1)返回的实体类
package com.web.response;
import com.alibaba.fastjson.JSON;
public class Result {
/**
* 状态码
*/
private final Integer code;
/**
* 消息
*/
private final String msg;
/**
* 数据内容,比如列表,实体
*/
private final Object data;
// private final Object data_api;
//private final Object data_api2;
private Result(final Builder builder) {
this.code = builder.code;
this.msg = builder.msg;
this.data = builder.data;
// this.data_api = builder.data_api;
//this.data_api2 = builder.data_api2;
}
public static class Builder {
private final Integer code;
private String msg;
private Object data;
private Object data_api;
private Object data_api2;
public Builder(final Integer code) {
this.code = code;
}
public Builder msg(final String msg) {
this.msg = msg;
return this;
}
public Builder data(final Object data) {
this.data = data;
return this;
}
public Builder data_api(final Object data_api) {
this.data_api = data_api;
return this;
}
public Builder data_api2(final Object data_api2) {
this.data_api2 = data_api2;
return this;
}
public Result build() {
return new Result(this);
}
}
public Integer getCode() {
return this.code;
}
public String getMsg() {
return this.msg;
}
public Object getData() {
return this.data;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
(2)根据各种情况,封装对应的Result返回对象
package com.web.response;
import org.springframework.http.HttpStatus;
public class ResultGenerator {private static final String DEFAULT_OK_MESSAGE = "OK";
private static final String DEFAULT_UNAUTHORIZED_MESSAGE = "Need authorized";
private static final String DEFAULT_METHOD_NOT_ALLOWED_MESSAGE = "Request method incorrect";
public static Result genOkResult() {
return new Result.Builder(HttpStatus.OK.value()).msg(DEFAULT_OK_MESSAGE).build();
}
public static Result genOkResult(final Object data) {
return new Result
.Builder(HttpStatus.OK.value())
.msg(DEFAULT_OK_MESSAGE)
.data(data)
.build();
}
public static Result genOkResult(final Object data,String msg) {
return new Result
.Builder(HttpStatus.OK.value())
.msg(msg)
.data(data)
.build();
}
public static Result genOkResult(final Object data,final Object data_api1,Object data_api2) {
return new Result
.Builder(HttpStatus.OK.value())
.msg(DEFAULT_OK_MESSAGE)
.data(data)
.data_api(data_api1)
.data_api2(data_api2)
.build();
}
public static Result genFailedResult(final String msg) {
return new Result
.Builder(HttpStatus.BAD_REQUEST.value())
.msg(msg)
.build();
}
public static Result genMethodErrorResult() {
return new Result
.Builder(HttpStatus.METHOD_NOT_ALLOWED.value())
.msg(DEFAULT_METHOD_NOT_ALLOWED_MESSAGE)
.build();
}
public static Result genUnauthorizedResult() {
return new Result
.Builder(HttpStatus.UNAUTHORIZED.value())
.msg(DEFAULT_UNAUTHORIZED_MESSAGE)
.build();
}
public static Result genUnauthorizedResult(final String msg) {
return new Result
.Builder(HttpStatus.UNAUTHORIZED.value())
.msg(msg)
.build();
}
public static Result genInternalServerErrorResult(final String url) {
return new Result
.Builder(HttpStatus.INTERNAL_SERVER_ERROR.value())
.msg("API [" + url + "] internal server error. Please call engineer to debug.")
.build();
}
}