接上一篇最外层接口的匹配,我们继续深入开发内层规则的匹配。其中规则的匹配会涉及到较多的判断处理,以及重复重复内容,所以我们先创建个匹配工具类,来进行代码类化开发。
public class QMockRuleUtil {
// 规则匹配工具类
}
GET参数处理
实战项目为了简化处理,不论是GET参数还是POST BODY,不使用自带如之前讲到的getParameterMap
方法,而是自定义一个方法,专门处理URL中请求参数"a=a1&b=b1&c=c1"成为JSON。如下代码处理进行一次&
拆分,再进行一次=
拆分。在这里值得注意的是对应值可能没有或者有多个等号的,我做了一定的兼容,但在实际应用过程中还可能出现其他特殊值的兼容情况,请想想如果遇到要如何处理?
public static JSONObject getJsonObjcetByQueryUrl(String paramStr){
//String paramStr = "a=a1&b=b1&c=c1";
String[] params = paramStr.split("&");
JSONObject obj = new JSONObject();
for (int i = 0; i < params.length; i++) {
String[] param = params[i].split("=");
if (param.length >= 2) {
String key = param[0];
String value = param[1];
for (int j = 2; j < param.length; j++) {
value += "=" + param[j];
}
try {
obj.put(key,value);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
return obj;
}
在QMockInterceptor.java
类中preHandle
在匹配接口后,如果是GET请求,我们对其URL参数?
后的串获取并用自定义的处理工具类方法转换成统一的JSON数据。
if ("GET".equals(requestMethod.toUpperCase())){
try {
if (request.getParameterMap().size()!=0) {
// 获取GET请求参数
String paramsStr = URLDecoder.decode(request.getQueryString(),"utf-8");
// 通过自定义转换方法转换成通用的json数据
reqParamsOrBody = QMockRuleUtil.getJsonObjcetByQueryUrl(paramsStr);
}
// resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
}
catch (JSONException e){
log.error(e.toString());
}
}
这样先完成了GET参数的处理,注意这里有一行注释,将在最后一个核心公共方法实现后打开。
POST参数处理
GET的请求参数处理相对简单些,而对于POST一般对应的Body参数,当然也会可以同传Params参数。之前就讲过本套案例不做太复杂逻辑处理,如果有需要请在本系完成对应实战操作后,掌握了对应的技术能力后,根据项目需求进行扩展开发,如果真是对于Mock需求过滤有复杂的要求,一般就需要在产品需求交互上定义清楚,然后代码层面分层处理。
// 获取POST方法的中的Body数据
public static String getBodyString(HttpServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
// 逐行读取
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 返回JSON字符串
return sb.toString();
}
getBodyString
工具类方法字符流的处理方法是在一个POST请求的BODY本身就是要求JSON格式的前提下实现的逻辑。在得到这个JSON字符串后直接进行类型转换即可。其他非JSON格式请求很少见,如果需要请进行通过header传类型做响应匹配处理。
else if ("POST".equals(requestMethod.toUpperCase())){
try {
String strbody = QMockRuleUtil.getBodyString(request);
if (!strbody.isEmpty()) {
reqParamsOrBody = JSON.parseObject(strbody);
}
// resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
}
catch (JSONException e){
log.error(e.toString());
}
}
在最后我们进行获取规则,增加最后else处理,便可完成完整的逻辑匹配接口和规则的逻辑。
if(mockApiEntities.size() == 1) {
// 取得 Mock api 唯一值
QMockApiEntity mockApiEntity = mockApiEntities.get(0);
// 根据 api id 查询规则列表
List<QMockApiRuleEntity> mockApiRuleEntities = qMockService.selectApiRuleList(mockApiEntity.getId());
log.info("Mock规则个数:" + mockApiRuleEntities.size());
// 根据不同的方法做不同的处理,目前只支持常用的GET和POST
if ("GET".equals(requestMethod.toUpperCase())){
// GET参数处理部分
resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
} else if ("POST".equals(requestMethod.toUpperCase())){
// POST参数处理部分省略
resResult = QMockRuleUtil.matchFilter(mockApiEntity,mockApiRuleEntities,reqParamsOrBody);
} else {
resResult.put("code", 4008);
resResult.put("msg", "Mock暂未支持的请求方法");
}
} else if (mockApiEntities.size() > 1) {
resResult.put("code", 5000);
resResult.put("data", new JSONObject());
resResult.put("msg", "MOCK匹配多个URI请检查配置");
}
else {
resResult.put("code", 5000);
resResult.put("data", new JSONObject());
resResult.put("msg", "MOCK未匹配任何URI请先添加把");
}
上述代码中有“根据 api id 查询规则列表” 的查询,这个查库实现参考上一篇和最初几篇套路式自己我先实现,也当做是检验下自我脱稿编程的代码能力的检验了。学习是需要自我实战才能有效果的,多花点时间将学过的东西独立实践,而不是照着练一遍,你将收获更大的进步。当然如果不会也不用担心,我将在下篇给出代码详细。
简单规则匹配
通过上述的GET/POST的参数获取转换最终得到一个reqParamsOrBody
,然后还有上一篇中的得到mockApiEntity
和mockApiEntity
三个对象数据,这样我们就可以对其简单的匹配逻辑处理了,关键的解释放在代码注释里了。
// Mock Rule 匹配逻辑
public static JSONObject matchFilter(QMockApiEntity mockApiEntity, List<QMockApiRuleEntity> mockApiRuleEntities, JSONObject reqParamsOrBody){
JSONObject resResult = new JSONObject();
// 循环规则列表
for(QMockApiRuleEntity ruleEntity:mockApiRuleEntities){
// 如果规则没有配置个过滤条件跳过
if((ruleEntity.getReqFilter().isEmpty() || ruleEntity.getReqFilter() == null ) && reqParamsOrBody == null) {
resResult = ruleEntity.getResBody();
break;
}
// 如果有请求参数和配置条件都有进行匹配
if(!ruleEntity.getReqFilter().isEmpty() && reqParamsOrBody != null) {
// 规则大于请求参数认为不合理,不做此规则判定
if (ruleEntity.getReqFilter().size() > reqParamsOrBody.size()){
continue;
}
// 非合理条件均不存在进行key value的一一判定,这里同样简化只做一级过滤
JSONArray filters = ruleEntity.getReqFilter();
Boolean assertResult = false;
for(int i=0; i< filters.size(); i++) {
// 先看是否有匹配key+相等value
// 在页面添加规则的时候录入数据的固定格式为 [{"key":"job","value":"test"}]
String key = filters.getJSONObject(i).getString("key");
if(reqParamsOrBody.containsKey(key) && reqParamsOrBody.get(key).toString().equals(filters.getJSONObject(i).get("value"))) {
assertResult = true;
} else {
assertResult = false;
}
}
// 如果有获取规则返回值
if( assertResult ) {
resResult = ruleEntity.getResBody();
break;
}
}
}
// 全没有返回默认
if (resResult.isEmpty()) {
resResult = mockApiEntity.getResDefault();
}
return resResult;
}
我们最终做下联调运行测试:
-
GET接口规则命中
-
POST接口规则命中
至此,本篇教程实现到这里,在上一篇基础上我们进一步实现了接口规则的匹配。有了这个能力支持,我们就可以针对同一个接口不同数值的请求匹配返回对应的值了。
下一篇我们会给出接口规则的请求表和全过程,下下篇是一个扩展知识点,然后我们回归到页面的交互开发。