Skip to content

Commit 2d08748

Browse files
committed
Server:优化数组查询性能并简化getArray逻辑;Client:解决未登录点击+查看所有用户崩溃
1 parent 9b1d33a commit 2d08748

4 files changed

Lines changed: 99 additions & 110 deletions

File tree

APIJSON(Android)/APIJSON(ADT)/APIJSONApp/APIJSONApp/src/apijson/demo/client/activity_fragment/MomentActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ private void deleteComment(CommentItem commentItem) {
358358
@Override
359359
public void getListAsync(final int page) {
360360
if (loadHead && page <= HttpManager.PAGE_NUM_0) {
361-
HttpRequest.getMoment(momentId, HTTP_GET_MOMENT, MomentActivity.this);
361+
// HttpRequest.getMoment(momentId, HTTP_GET_MOMENT, MomentActivity.this);
362362
}
363363
HttpRequest.getCommentList(momentId, 0, page, -page, this);
364364
}

APIJSON(Android)/APIJSON(ADT)/APIJSONApp/APIJSONApp/src/apijson/demo/client/util/HttpRequest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ public static void getUserList(int range, long id, com.alibaba.fastjson.JSONObje
320320
userItem.put(ID_IN, idList);
321321
} else {
322322
apijson.demo.client.model.User currentUser = APIJSONApplication.getInstance().getCurrentUser();
323+
if (currentUser == null) {
324+
currentUser = new apijson.demo.client.model.User();
325+
}
323326
switch (range) {
324327
case RANGE_ALL://1.首推注册时间长的(也可以是级别高的);2.给男性用户首推女性用户
325328
userItem.setOrder(DATE_UP, (currentUser.getSex() == 0 ? "sex-" : ""));
@@ -334,7 +337,7 @@ public static void getUserList(int range, long id, com.alibaba.fastjson.JSONObje
334337
Log.e(TAG, "只允许查看当前用户的!");
335338
return;
336339
}
337-
List<Long> list = currentUser == null ? null : currentUser.getFriendIdList();
340+
List<Long> list = currentUser.getFriendIdList();
338341
if (list == null) {//不能放在range == RANGE_USER_CIRCLE里面,为null不会当成查询条件!
339342
list = new ArrayList<Long>();
340343
}
@@ -420,7 +423,10 @@ public static void getMomentList(int range, long id, com.alibaba.fastjson.JSONOb
420423
return;
421424
}
422425
apijson.demo.client.model.User currentUser = APIJSONApplication.getInstance().getCurrentUser();
423-
List<Long> list = currentUser == null ? null : currentUser.getFriendIdList();
426+
if (currentUser == null) {
427+
currentUser = new apijson.demo.client.model.User();
428+
}
429+
List<Long> list = currentUser.getFriendIdList();
424430
if (list == null) {
425431
list = new ArrayList<Long>();
426432
}

APIJSON(Android)/APIJSON(ADT)/APIJSONApp/APIJSONApp/src/apijson/demo/client/view/MomentView.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,11 @@ public boolean getShowComment() {
232232
*/
233233
public void setComment(List<CommentItem> list) {
234234
// ivMomentViewComment.setImageResource(joined ? R.drawable.commented : R.drawable.comment);
235-
llMomentViewCommentContainer.setVisibility(list == null || list.isEmpty() ? View.GONE : View.VISIBLE);
235+
llMomentViewCommentContainer.setVisibility(showComment == false || list == null || list.isEmpty()
236+
? View.GONE : View.VISIBLE);
236237

237-
if (showComment == false) {
238-
Log.i(TAG, "setComment showComment == false >> return;");
238+
if (llMomentViewCommentContainer.getVisibility() != View.VISIBLE) {
239+
Log.i(TAG, "setComment llMomentViewCommentContainer.getVisibility() != View.VISIBLE >> return;");
239240
return;
240241
}
241242

APIJSON(Server)/APIJSON(Eclipse_JEE)/src/main/java/zuo/biao/apijson/server/Parser.java

Lines changed: 86 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ public static boolean isContainKeyInArray(String key, String[] array) {
475475

476476
/**获取单个对象,该对象处于parentObject内
477477
* @param parentPath parentObject的路径
478-
* @param parentConfig
478+
* @param parentConfig 对子object的SQL查询配置,需要传两个层级
479479
* @param name parentObject的key
480480
* @param request parentObject的value
481481
* @return
@@ -494,15 +494,13 @@ private JSONObject getObject(String parentPath, final QueryConfig parentConfig,
494494
&& isInRelationMap(path) == false) {
495495
return request;
496496
}
497-
//优化查询性能并避免"[]":{"0":{"1":{}}}这种导致第3层当成[]的直接子Object
497+
//为第二遍parseRelation = true服务,优化查询性能并避免"[]":{"0":{"1":{}}}这种导致第3层当成[]的直接子Object
498498
final boolean isArrayChild = parentConfig != null && StringUtil.isNumer(name) && ("" + parentConfig.getPosition()).equals(name);
499+
final String table = isArrayChild ? null : Pair.parseEntry(name, true).getKey();
500+
final boolean isTableKey = isArrayChild == false && isTableKey(table);
501+
Log.d(TAG, "getObject table = " + table + "; isTableKey = " + isTableKey);
499502

500-
String table = Pair.parseEntry(name, true).getKey();
501-
Log.d(TAG, "getObject table = " + table);
502503

503-
504-
505-
506504
boolean containRelation = false;
507505

508506
JSONObject transferredRequest = new JSONObject(true);//must init
@@ -527,8 +525,16 @@ && isInRelationMap(path) == false) {
527525
if (isArrayKey(key)) {//APIJSON Array
528526
result = getArray(path, parentConfig, key, (JSONObject) value);
529527
} else {//APIJSON Object
530-
result = getObject(path, isArrayChild == false || isFirst == false //以第0个JSONObject为准
531-
? null : parentConfig, key, (JSONObject) value);
528+
result = getObject(path, isFirst && isArrayChild //以第0个JSONObject为准
529+
? parentConfig : null, key, (JSONObject) value);
530+
531+
//如果第0个都为空,那后面的也都无意义了。
532+
if (isFirst && isArrayChild && (result == null || result.isEmpty())) {
533+
Log.d(TAG, "getObject isFirst && isArrayChild"
534+
+ " && (result == null || result.isEmpty()) >> return null;");
535+
return null;
536+
}
537+
532538
isFirst = false;//[]里第一个不能为[]
533539
}
534540
Log.i(TAG, "getObject key = " + key + "; result = " + result);
@@ -554,7 +560,6 @@ && isInRelationMap(path) == false) {
554560
//GET <<<<<<<<<<<<<<<<<<<<<<<<<
555561
JSONObject arrayRequest = new JSONObject();
556562
arrayRequest.put(QueryConfig.ID, request.get(QueryConfig.ID));
557-
// arrayRequest.setColumn(realKey);//put请求会对id添加功能符?
558563
arrayRequest.put(JSONRequest.KEY_COLUMN, realKey);
559564
JSONRequest getRequest = new JSONRequest(table, arrayRequest);
560565
JSONObject response = new Parser().parseResponse(getRequest);
@@ -596,46 +601,45 @@ && isInRelationMap(path) == false) {
596601
throw new IllegalArgumentException("\"key@\": 后面必须为依赖路径String!");
597602
}
598603
System.out.println("getObject key.endsWith(@) >> parseRelation = " + parseRelation);
599-
String replaceKey = key.substring(0, key.length() - 1);//key{}@ getRealKey(requestMethod, key, false, false);
604+
String replaceKey = key.substring(0, key.length() - 1);//key{}@ getRealKey
600605
String keyPath = getAbsPath(path, replaceKey);
601-
String valuePath;// = new String((String) value);
602-
603-
if (parseRelation) {
604-
//不是能直接获取到valuePath吗?因为更新?
605-
valuePath = getRelationValuePath(keyPath);
606-
Object target = getValueByPath(valuePath, true);
607-
Log.d(TAG, "getObject valuePath = " + valuePath + "; target = " + target);
608-
if (valuePath.equals(target) && isTableKey(table)) {
609-
Log.e(TAG, "getObject ((String) value).equals(target) && isTableKey(table) >> return null;");
610-
return null;//parseRelation时还获取不到就不用再做无效的query了。不考虑 Table:{Table:{}}嵌套
611-
}
612-
//还要isInRelationMap(path)判断 removeRelation(keyPath);
613-
// updateRelation(getAbsPath(path, key), keyPath);//request结构已改变,需要更新依赖关系
606+
String valuePath = parseRelation ? getRelationValuePath(keyPath) : new String((String) value);
614607

608+
if (valuePath.startsWith(SEPARATOR)) {
609+
valuePath = getAbsPath(parentPath, valuePath);
610+
}
611+
//先尝试获取,尽量保留缺省依赖路径,这样就不需要担心路径改变
612+
Object target = getValueByPath(valuePath, true);
613+
Log.i(TAG, "getObject valuePath = " + valuePath + "; target = " + target);
614+
615+
if (valuePath.equals(target)) {//必须valuePath和保证getValueByPath传进去的一致!
616+
Log.i(TAG, "getObject target != null && target instanceof String"
617+
+ " && ((String) target).startsWith(valuePath) >> ");
618+
if (parseRelation) {
619+
if (isTableKey) {
620+
Log.e(TAG, "getObject parseRelation >> isTableKey(table) >> return null;");
621+
return null;//parseRelation时还获取不到就不用再做无效的query了。不考虑 Table:{Table:{}}嵌套
622+
} else {
623+
Log.d(TAG, "getObject parseRelation >> isTableKey(table) == false >> continue;");
624+
continue;//舍去,对Table无影响
625+
}
626+
} else {//标记并存放依赖关系
627+
Log.i(TAG, "getObject parseRelation == false"
628+
+ " >> containRelation = true; putRelation(keyPath, valuePath);");
629+
containRelation = true;
630+
putRelation(keyPath, valuePath);
631+
}
632+
} else {//直接替换原来的key@:path为key:target
633+
Log.i(TAG, "getObject >> key = replaceKey; value = target;");
615634
key = replaceKey;
616635
value = target;
617-
} else {
618-
//尽量保留缺省依赖路径,这样就不需要担心路径改变
619-
valuePath = new String((String) value);
620-
//先尝试获取
621-
if (valuePath.startsWith(SEPARATOR)) {
622-
valuePath = getAbsPath(parentPath, valuePath);
623-
}
624-
// Object target = getValueByPath((String) value);
625-
// Log.d(TAG, "getObject value = " + value + "; target = " + target);
626-
// if (target == null || ((String) value).equals(target)) {//标记并存放依赖关系
627-
containRelation = true;
628-
putRelation(keyPath, valuePath);
629-
// } else {//直接替换原来的key@:path为key:target
630-
// transferredRequest.remove(key);
631-
// transferredRequest.put(replaceKey, target);
632-
// }
633636
}
637+
Log.d(TAG, "getObject key = " + key + "; value = " + value);
634638
}
635639

636640
if (key.endsWith("()")) {
637641
if (value instanceof String == false) {
638-
throw new IllegalArgumentException("\"key()\": 后面必须为函数String!");
642+
throw new IllegalArgumentException(path + "/" + key + "():function() 后面必须为函数String!");
639643
}
640644
functionMap.put(key, (String) value);
641645
} else if (key.startsWith("@") && QueryConfig.TABLE_KEY_LIST.contains(key) == false) {
@@ -650,10 +654,11 @@ && isInRelationMap(path) == false) {
650654

651655
boolean query = false;
652656
//执行SQL操作数据库
653-
if (containRelation == false && isTableKey(table)) {//提高性能
657+
if (containRelation == false && isTableKey) {//提高性能
654658
if (parseRelation == false || isInRelationMap(path)) {//避免覆盖原来已经获取的
655659
query = true;
656660
// keyValuePathMap.remove(path);
661+
//移除所有startswith path的keyPath?
657662
QueryConfig config = newQueryConfig(table, transferredRequest);
658663

659664
if (parentConfig == null) {//导致全部都是第0个 || isArrayChild == false) {
@@ -714,7 +719,7 @@ && isInRelationMap(path) == false) {
714719

715720
/**获取对象数组,该对象数组处于parentObject内
716721
* @param parentPath parentObject的路径
717-
* @param parentConfig parentObject对子object的SQL查询配置,需要传两个层级
722+
* @param parentConfig 对子object的SQL查询配置,需要传两个层级
718723
* @param name parentObject的key
719724
* @param request parentObject的value
720725
* @return 转为JSONArray不可行,因为会和被当成条件的key:JSONArray冲突。好像一般也就key{}:JSONArray用到??
@@ -733,18 +738,16 @@ private JSONObject getArray(String parentPath, QueryConfig parentConfig, String
733738
String path = getAbsPath(parentPath, name);
734739

735740
int page = 0, count = 0, total = 0;
736-
try {
737-
page = request.getIntValue(JSONRequest.KEY_PAGE);
738-
count = request.getIntValue(JSONRequest.KEY_COUNT);
739-
} catch (Exception e) {
740-
Log.i(TAG, "getArray try { page = arrayObject.getIntValue(page); ..." +
741-
" >> } catch (Exception e) {\n" + e.getMessage());
742-
}
741+
742+
count = request.getIntValue(JSONRequest.KEY_COUNT);
743+
page = request.getIntValue(JSONRequest.KEY_PAGE);
744+
request.remove(JSONRequest.KEY_COUNT);
745+
request.remove(JSONRequest.KEY_PAGE);
746+
743747
if (count <= 0 || count > 100) {//count最大为100
744748
count = 100;
745749
}
746750

747-
String firstTableKey = null;
748751
//最好先获取第一个table的所有项(where条件),填充一个列表?
749752
Set<String> set = new LinkedHashSet<>(request.keySet());
750753
if (count <= 0 || count > 5) {//5以下不优化长度
@@ -755,13 +758,6 @@ private JSONObject getArray(String parentPath, QueryConfig parentConfig, String
755758
table = Pair.parseEntry(key, true).getKey();
756759
value = isTableKey(table) ? request.get(key) : null;
757760
if (value != null && value instanceof JSONObject) {// && value.isEmpty() == false) {
758-
// totalCount = QueryHelper.getInstance().getCount(key);
759-
firstTableKey = key;
760-
// JSONObject response = new Parser(HEAD)
761-
// .parseResponse(new JSONRequest(key, object));
762-
// JSONObject target = response == null ? null : response.getJSONObject(key);
763-
// total = target == null ? 0 : target.getIntValue(JSONResponse.KEY_COUNT);
764-
765761
total = estimateMaxCount(path, table, (JSONObject) value);
766762
break;
767763
}
@@ -772,64 +768,55 @@ private JSONObject getArray(String parentPath, QueryConfig parentConfig, String
772768
}
773769
if (count > total) {
774770
count = total;
775-
request.put(JSONRequest.KEY_COUNT, count);
776-
// set = request.keySet();
777771
}
778772
}
779773
}
780-
781-
782774
Log.i(TAG, "getArray page = " + page + "; count = " + count);
783775

784776
QueryConfig config = new QueryConfig(requestMethod, count, page);
785777

778+
786779
JSONObject transferredRequest = new JSONObject(true);
780+
787781
JSONObject parent = null;
788782
Object value;
789783
JSONObject result;
784+
Log.d(TAG, "getArray parseRelation = " + parseRelation);
790785
if (parseRelation == false) {
791786
//生成count个
792787
for (int i = 0; i < count; i++) {
793-
parent = new JSONObject(true);
794-
for (String key : set) {
795-
value = request.get(key);
796-
if (value instanceof JSONObject) {//JSONObject
797-
config.setPosition(i);
798-
if (isArrayKey(key)) {//json array
799-
result = getArray(getAbsPath(path, "" + i), config, key, (JSONObject) value);
800-
} else {//json object
801-
result = getObject(getAbsPath(path, "" + i), config, key, (JSONObject) value);
802-
}
803-
Log.i(TAG, "getArray parseRelation == false"
804-
+ " >> i = " + i + "result = " + result);
805-
if (result != null && result.isEmpty() == false) {//只添加!=null的值,可能数据库返回数据不够count
806-
parent.put(key, result);
807-
808-
updateRelation(path, getAbsPath(path, "" + i));//request结构已改变,需要更新依赖关系
809-
}
810-
} else {//JSONArray或其它Object,直接填充
811-
transferredRequest.put(key, value);//array里不允许关联,只能在object中关联
812-
}
813-
}
814-
if (parent.isEmpty() == false) {//可能数据库返回数据不够count
815-
transferredRequest.put("" + i, parent);
788+
parent = getObject(path, config.setPosition(i), "" + i, request);
789+
if (parent == null || parent.isEmpty()) {
790+
break;//数据库返回数量不够count,后面没有了。有依赖不为空,无依赖直接查询数据库。
816791
}
792+
transferredRequest.put("" + i, parent);
793+
updateRelation(path, getAbsPath(path, "" + i));//request结构已改变,需要更新依赖关系
794+
}
795+
796+
if (isInRelationMap(path)) {
797+
transferredRequest.put(JSONRequest.KEY_COUNT, count);
798+
transferredRequest.put(JSONRequest.KEY_PAGE, page);
817799
}
818800
} else {
801+
boolean isArrayKey;
819802
for (String key : set) {//0:{},1:{}...
820803
value = request.get(key);
821804
if (value instanceof JSONObject) {//JSONObject,往下一级提取
822805
config.setPosition(Integer.valueOf(0 + StringUtil.getNumber(key, true)));
823-
if (isArrayKey(key)) {//json array
806+
isArrayKey = isArrayKey(key);
807+
if (isArrayKey) {//json array
824808
result = getArray(path, config, key, (JSONObject) value);
825809
} else {//json object
826810
result = getObject(path, config, key, (JSONObject) value);
827811
}
828-
if (result != null && result.isEmpty() == false) {//只添加!=null的值,可能数据库返回数据不够count
829-
//先实现功能,后续再优化 if (result.containsKey(firstTableKey)) {//第一个Table都没有,后面的也无效
830-
transferredRequest.put(key, result);
831-
// }
812+
if (result == null || result.isEmpty()) {
813+
if (isArrayKey) {
814+
continue;
815+
} else {
816+
break;//数据库返回数量不够count,后面没有了。有依赖不为空,无依赖直接查询数据库。
817+
}
832818
}
819+
transferredRequest.put(key, result);
833820
} else {//JSONArray或其它Object
834821
//array里不允许关联,只能在object中关联
835822
}
@@ -838,12 +825,6 @@ private JSONObject getArray(String parentPath, QueryConfig parentConfig, String
838825

839826
Log.i(TAG, "getArray return " + JSON.toJSONString(transferredRequest) + "\n>>>>>>>>>>>>>>>\n\n\n");
840827

841-
//可能部分情况下还是会返回,应该在getObject内解析了relation后 keyValuePathMap.remove(path + SEPARATOR + key);
842-
if (parseRelation == false && isInRelationMap(path) == false) {//parseRelation == true时不会添加进去
843-
transferredRequest.remove(JSONRequest.KEY_PAGE);
844-
transferredRequest.remove(JSONRequest.KEY_COUNT);
845-
}
846-
847828
return transferredRequest;
848829
}
849830

@@ -934,18 +915,18 @@ private String getAbsPath(String path, String name) {
934915
//依赖引用关系 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
935916

936917
/**有关联代码的object的关联key在relationMap里
937-
* @param path
918+
* @param keyPath
938919
* @return
939920
*/
940-
private boolean isInRelationMap(String path) {
941-
if (path == null) {
921+
private boolean isInRelationMap(String keyPath) {
922+
if (keyPath == null) {
942923
return false;
943924
}
944925
// return keyValuePathMap == null ? false : keyValuePathMap.containsKey(path);
945926
Set<String> set = keyValuePathMap == null ? null : keyValuePathMap.keySet();
946927
if (set != null) {
947928
for (String key : set) {
948-
if (path.equals(key) || key.startsWith(path + "/")) {//解决相同字符导致的错误) {//key.contains(path)) {//
929+
if (keyPath.equals(key) || key.startsWith(keyPath + "/")) {//解决相同字符导致的错误) {//key.contains(path)) {//
949930
return true;
950931
}
951932
}
@@ -1133,7 +1114,8 @@ public static boolean isWord(String key) {
11331114
*
11341115
* 方法2:在所有用到key的地方用getRealKey(key)代替key
11351116
* 优点:修改代码集中
1136-
* 缺点:完成查询后key没有替换为客户端所需的,要么不解决,要么最后增加一次遍历来替换key;需要在getValueByPath和putValueByPath中遍历keySet找到映射key
1117+
* 缺点:完成查询后key没有替换为客户端所需的,要么不解决,要么最后增加一次遍历来替换key;
1118+
* 需要在getValueByPath和putValueByPath中遍历keySet找到映射key
11371119
*
11381120
* 方法3:方法1,2结合。增加一个keyMap<origin, real>,
11391121
* getValueByPath和putValueByPath中path中的realKey如果有映射就替换为originKey,
@@ -1146,10 +1128,10 @@ public static boolean isWord(String key) {
11461128
*/
11471129

11481130
/**获取客户端实际需要的key
1149-
* <br> "userId@":"/User/id" //@根据路径依赖,@始终在最后。value是'/'分隔的字符串。
1131+
* <br> "userId@":"/User/id" //@根据路径依赖,@始终在最后。value是'/'分隔的字符串。
11501132
* <br> "isPraised()":"isContain(Collection:idList,long:id)" //()使用方法,value是方法表达式。不能与@并用。
1151-
* <br> "content$":"%searchKey%" //$搜索,右边紧跟key。value是搜索表达式。
1152-
* <br> "@columns":"id,sex,name" //关键字,左边紧跟key。暂时不用,因为目前关键字很少,几乎不会发生冲突。value是','分隔的字符串。
1133+
* <br> "content$":"%searchKey%" //$搜索,右边紧跟key。value是搜索表达式。
1134+
* <br> "@columns":"id,sex,name" //关键字,左边紧跟key。暂时不用,因为目前关键字很少,几乎不会发生冲突。value是','分隔的字符串。
11531135
*
11541136
* @param method
11551137
* @param originKey

0 commit comments

Comments
 (0)