Open cloudAndMonkey opened 10 months ago
可以通过 @try + @catch + @finally 实现
@try: true,
@catch: "catchFun(id)" // 对应调用 DemoFunctionParser 中的 public Object catchFun(JSONObject curObj, Throwable e, String idKey)
@finally: "delRedisKey('User-82001')" // 对应调用 DemoFunctionParser 中的 public void delRedisKey(JSONObject curObj, String key) // String k = getArgVal(key) 自动根据单引号判断为值,根据 User/id 判断为路径来按路径取值等
目前仅有 @try 已实现,其它两个你试试 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/JSONObject.java#L132-L136
可以通过 @Try + @catch + @finally 实现
@try: true, @catch: "catchFun(id)" // 对应调用 DemoFunctionParser 中的 public Object catchFun(JSONObject curObj, Throwable e, String idKey) @finally: "delRedisKey('User-82001')" // 对应调用 DemoFunctionParser 中的 public void delRedisKey(JSONObject curObj, String key) // String k = getArgVal(key) 自动根据单引号判断为值,根据 User/id 判断为路径来按路径取值等
目前仅有 @Try 已实现,其它两个你试试 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/JSONObject.java#L132-L136
其他两个没有实现,哈哈
@TommyLemon 这里执行 @catch: "catchFun(id)" , 对吧? https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L299-L300
对,先提前 get 出来 @catch 和 @finally 的值 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L95-L105
然后在 AbstractObjectParser 这里 if tri 判断后调用 parseFunction https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L299-L304
@TommyLemon
} catch (Exception e) {
if (tri == false) {
if(StringUtil.isNotEmpty(isCatch)) {
String catchKey = JSONRequest.KEY_CATCH.substring(1);
onParse(catchKey + "()", isCatch);
parseFunction(catchKey + "()", catchKey, isCatch, parentPath, this.name, request, false);
}
throw CommonException.wrap(e, sqlConfig); // 不忽略错误,抛异常
}
invalidate(); // 忽略错误,还原request
}
onParse, parseFunction 两种方式调用执行流程是一样的,你认为那种方式合适呢?
https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L299-L304 @finally 考虑到一个问题 AbstractObjectParser catch 后添加 finally, 是无法获取执行结果(正确和异常). response执行结果需要在外层获取 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L540
parseFunction 更简单直接,应该放到 if (tri == false) {} 后面,只在 try 时生效。 或者只要 @catch/@finally 传了有效值,不需要传 @try: true 就生效?这样使用简单一些
@finally 需要在 catch (Exception e) 和 正常走完流程后都执行,最好找一个同时满足两者的地方,写一处代码就行,实在不行就只能分开写两处了
只要内部抛了异常,肯定不能拿到正常流程的结果,只能拿到 catch 异常后的结果,可以考虑 @default 返回默认值
parseFunction 更简单直接,应该放到 if (tri == false) {} 后面,只在 try 时生效。 或者只要 @catch/@finally 传了有效值,不需要传 @Try: true 就生效?这样使用简单一些
不需要传 @Try: true 就生效,这样简单.
} catch (Exception e) {
if (tri == false) {
throw CommonException.wrap(e, sqlConfig); // 不忽略错误,抛异常
}
if(StringUtil.isNotEmpty(isCatch)) {
String catchKey = JSONRequest.KEY_CATCH.substring(1);
parseFunction(catchKey + "()", catchKey, isCatch, parentPath, this.name, request, false);
}
invalidate(); // 忽略错误,还原request
}
@TommyLemon 场景: 查询数据,先从缓存查询,缓存存在直接返回.缓存不存在查询数据库. 可以控制某一步直接返回 请问有推荐的解决方案吗? 比如申明 "@block":true
@catch: "fun(args)" 调用的函数应该也支持返回值,也就是最后再返回 "@catch": 1
"@catch": { "id": 1, "content": "abc" }
这样的任意值,除非调用的远程函数返回类型是 void 或 return null 才不返回,这样功能更完善一些。 @finally 也一样。
加 Redis 等内存缓存,直接在 DemoSQLExecutor 重写 putCache, getCache, removeCache 就行了,没必要前端新增传参 https://github.com/APIJSON/APIJSON-Demo/blob/master/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java#L68-L130
控制某一步直接返回的目的是啥?
@catch: "fun(args)" 调用的函数应该也支持返回值,也就是最后再返回 "@catch": 1
"@catch": { "id": 1, "content": "abc" }
这样的任意值,除非调用的远程函数返回类型是 void 或 return null 才不返回,这样功能更完善一些。 @finally 也一样。
收到
@TommyLemon 分页支持从0, 1开始,添加一个开关即可,请问需要支持吗? https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L1295
if(AbstractParser.DEFAULT_QUERY_PAGE == false) {
page2 = page2 > 0 ? page2 -1 : page2;
}
这个需要的,DEFAULT_QUERY_PAGE 要改成更直观的名字,例如 IS_PAGE_START_FROM_ONE 这种
@TommyLemon 最近有点忙,不好意思 @catch 返回值已经支持
问题: 1、catch 是否放在 try 前面 ?
} catch (Exception e) {
if(isCatch != null) {
processCallFunction(KEY_CATCH, isCatch);
}
if (tri == false) {
throw CommonException.wrap(e, sqlConfig); // 不忽略错误,抛异常
}
invalidate(); // 忽略错误,还原request
} finally {
if(isFinally != null) {
processCallFunction(KEY_FINALLY, isFinally);
}
}
public void processCallFunction(String key, String value) throws Exception {
String funKey = key.substring(1);
parseFunction(funKey + "()", funKey, value, parentPath, this.name, request, false);
if(response.get(funKey) != null) {
this.parser.requestObject.put(key, response.get(funKey)); // 设置返回值
}
}
2、@finally 执行逻辑和 @catch保持一致吗? 3、分页变量名已经变更为: IS_PAGE_START_FROM_ONE
赞。
tri 已经不需要了,JSONObject.KEY_TRY 可以标记 @Deprecated,以上代码对应改为
if (catch_ == null) { // isCatch 看起来是 Boolean 类型,其实是 String 类型,前端传 @catch:"" 表示仅不抛异常,但不执行远程函数
throw CommonException.wrap(e, sqlConfig); // 不忽略错误,抛异常
}
if (StringUtil.isNotEmpty(catch_)) { // 这个判断移到 processCallFunction 更好,和 @finally 统一处理
processCallFunction(KEY_CATCH, catch_);
}
invalidate(); // 忽略错误,还原 request
同理 isFinally 命名改为 finally_ 或 finallyVal 之类的更好
@TommyLemon 代码已经调整,功能测试通过. 你再看看代码是否还有需要优化的点?
} catch (Exception e) {
if (catch_ == null) { // 前端传 @catch:"" 表示仅不抛异常,但不执行远程函数
throw CommonException.wrap(e, sqlConfig); // 不忽略错误,抛异常
}
processCallFunction(KEY_CATCH, catch_);
invalidate(); // 忽略错误,还原request
} finally {
processCallFunction(KEY_FINALLY, finally_);
}
public void processCallFunction(String key, String value) throws Exception {
if(StringUtil.isNotEmpty(value)) {
String funKey = key.substring(1);
parseFunction(funKey + "()", funKey, value, parentPath, this.name, request, false);
}
}
String warn = Log.DEBUG == false || error != null ? null : getWarnString();
processRequestObject(request, KEY_CATCH);
processRequestObject(request, KEY_FINALLY);
requestObject = error == null ? extendSuccessResult(requestObject, warn, isRoot) : extendErrorResult(requestObject, error, requestMethod, getRequestURL(), isRoot);
public void processRequestObject(JSONObject request, String key) {
if(request.containsKey(key)) {
String _key = key.substring(1);
requestObject = requestObject == null ? new JSONObject() : requestObject;
requestObject.put(_key, this.queryResultMap.get(_key));
}
}
测试脚本
{
"name": "jerry",
"@catch": "",
//"@catch": "sayHello(name)",
"@finally": "sayHello(name)",
"Document_copy2:data[]": {
"Document_copy2": {
"@column" : "id1"
},
"page": 0,
"count": 10
},
"@explain": true,
"format": true
}
{
"msg": "success",
"code": 200,
"finally": "Hello, jerry",
"debug:info|help": " \n提 bug 请发请求和响应的【完整截屏】,没图的自行解决! \n开发者有限的时间和精力主要放在【维护项目源码和文档】上! \n【描述不详细】 或 【文档/常见问题 已有答案】 的问题可能会被忽略!! \n【态度 不文明/不友善】的可能会被踢出群,问题也可能不予解答!!! \n\n **环境信息** \n系统: Mac OS X 12.4 \n数据库: DEFAULT_DATABASE = MYSQL \nJDK: 1.8.0_351 x86_64 \nAPIJSON: 6.3.0 \n \n【常见问题】:https://github.com/Tencent/APIJSON/issues/36 \n【通用文档】:https://github.com/Tencent/APIJSON/blob/master/Document.md \n【视频教程】:https://search.bilibili.com/all?keyword=APIJSON",
"ok": true,
"time": 1705460225810,
"sql:generate|cache|execute|maxExecute": "1|0|1|200",
"depth:count|max": "3|5",
"time:start|duration|end|parse|sql": "1705460225749|61|1705460225810|61|0"
}
{
"name": "jerry",
//"@catch": "",
"@catch": "sayHello(name)",
"@finally": "sayHello(name)",
"User_logback[]": [
{
"id": "0430f00c-a895-4f25-b096-40382bd85a11",
"name": "角色"
},
{
"id": "0430f00c-a895-4f25-b096-40382bd85a12",
"name": "角色3"
}
],
"tag": "User_logback[]",
"@explain": true,
"format": true
}
{
"msg": "success",
"code": 200,
"finally": "Hello, jerry",
"catch": "Hello, jerry",
"debug:info|help": " \n提 bug 请发请求和响应的【完整截屏】,没图的自行解决! \n开发者有限的时间和精力主要放在【维护项目源码和文档】上! \n【描述不详细】 或 【文档/常见问题 已有答案】 的问题可能会被忽略!! \n【态度 不文明/不友善】的可能会被踢出群,问题也可能不予解答!!! \n\n **环境信息** \n系统: Mac OS X 12.4 \n数据库: DEFAULT_DATABASE = MYSQL \nJDK: 1.8.0_351 x86_64 \nAPIJSON: 6.3.0 \n \n【常见问题】:https://github.com/Tencent/APIJSON/issues/36 \n【通用文档】:https://github.com/Tencent/APIJSON/blob/master/Document.md \n【视频教程】:https://search.bilibili.com/all?keyword=APIJSON",
"ok": true,
"time": 1705460325505,
"sql:generate|cache|execute|maxExecute": "2|0|2|200",
"depth:count|max": "2|5",
"time:start|duration|end|parse|sql": "1705460325418|87|1705460325505|57|30"
}
赞,关于返回结果统一处理,可以考虑移到 AbstractObjectParser 单独处理,因为这样 @catch 和 @finally 才能支持在多个不同对象中使用。
AbstractObjectParser.parseFunction 是有 response.put(key, returnVal) 的, https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L1015C14-L1055
应该 setSQLConfig, executeSQL, onFunctionResponse, onChildResponse, onComplete 最前面加上
if (isInvalidate()) {
return this; // 或对 void 方法 return;
}
就会自动写入最终结果了
目前看起来直接在 AbstractParser.onObjectParse 对 op 执行方法整体 try-catch-finally 实现简单很多 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L1125-L1131
只是要想想一个对象本身解析抛异常后,是否仍然继续解析它的内部子对象、剩下未执行的关键词、远程函数等?看起来没必要也不应该,避免继续错下去。 其实我当时想加 @try 的原因是: 有时需要同时查多个对象,它们之前没有依赖关系,有的甚至是次要的信息,没查到也没关系,希望报错不影响核心对象查询。
Description
try { crud(db,redis等) } catch(){ //TODO 删除redis key } finally{ }
请问实现上面的效果,有好的解决方案吗? 前置/后置函数,加一个异常执行函数?
如果是你的这个需求,那就需要在 @catch 和 @finally 解析过程或之后继续抛异常。 决定权可以给 catchFun 和 delKey 这两个函数,内部自己决定是否抛异常; 也可以把 @try 利用上,true 则不自动抛异常,false 则继续抛原来的异常,@catch 和 @finally 仅仅作为不同流程点的拦截处理,似乎这样更好些
@cloudAndMonkey 可以先发 PR 提交代码,我再看看怎么调整下
Description
请问实现上面的效果,有好的解决方案吗? 前置/后置函数,加一个异常执行函数?