diff --git a/APIJSON-Java-Server/APIJSONBoot-BigData/src/main/java/apijson/demo/DemoSQLExecutor.java b/APIJSON-Java-Server/APIJSONBoot-BigData/src/main/java/apijson/demo/DemoSQLExecutor.java index 0983685..1d48c5f 100644 --- a/APIJSON-Java-Server/APIJSONBoot-BigData/src/main/java/apijson/demo/DemoSQLExecutor.java +++ b/APIJSON-Java-Server/APIJSONBoot-BigData/src/main/java/apijson/demo/DemoSQLExecutor.java @@ -49,13 +49,13 @@ public class DemoSQLExecutor extends APIJSONSQLExecutor { @Override public Connection getConnection(SQLConfig config) throws Exception { Log.d(TAG, "getConnection config.getDatasource() = " + config.getDatasource()); - - Connection c = connectionMap.get(config.getDatabase()); + String connectionKey = config.getDatasource() + "-" + config.getDatabase(); + Connection c = connectionMap.get(connectionKey); if (c == null || c.isClosed()) { try { DataSource ds = DemoApplication.getApplicationContext().getBean(DataSource.class); // 另一种方式是 DruidConfig 初始化获取到 Datasource 后给静态变量 DATA_SOURCE 赋值: ds = DruidConfig.DATA_SOURCE.getConnection(); - connectionMap.put(config.getDatabase(), ds == null ? null : ds.getConnection()); + connectionMap.put(connectionKey, ds == null ? null : ds.getConnection()); } catch (Exception e) { Log.e(TAG, "getConnection try { " + "DataSource ds = DemoApplication.getApplicationContext().getBean(DataSource.class); .." diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/APIJSON-8.0.0.1.jar b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/APIJSON-8.0.0.1.jar new file mode 100644 index 0000000..85819c3 Binary files /dev/null and b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/APIJSON-8.0.0.1.jar differ diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-framework-7.2.0.1.jar b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-framework-7.2.0.1.jar new file mode 100644 index 0000000..5897cfc Binary files /dev/null and b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-framework-7.2.0.1.jar differ diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-router-2.2.0.1.jar b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-router-2.2.0.1.jar new file mode 100644 index 0000000..b84407e Binary files /dev/null and b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/libs/apijson-router-2.2.0.1.jar differ diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/pom.xml b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/pom.xml index 148bbe2..e3b04eb 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/pom.xml +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/pom.xml @@ -5,7 +5,7 @@ apijson.boot apijson-boot-multi-datasource - 7.1.0 + 7.2.0 jar APIJSONBoot-MultiDataSource @@ -23,10 +23,15 @@ + + + + + - com.alibaba - fastjson - 1.2.83 + com.alibaba.fastjson2 + fastjson2 + 2.0.57 @@ -59,23 +64,31 @@ com.github.Tencent APIJSON - 7.1.0 + 8.0.0 com.github.APIJSON apijson-framework - 7.1.0 - - - com.github.APIJSON - apijson-column - 2.1.0 + 7.2.1 com.github.APIJSON - apijson-router - 2.1.0 + apijson-fastjson2 + 1.0.1 + + + + + + + + + + + + + @@ -167,7 +180,7 @@ com.mysql mysql-connector-j - 8.4.0 + 9.2.0 org.postgresql @@ -219,6 +232,18 @@ mongodb-jdbc 2.0.3 + + + + + + + + + + + + @@ -286,6 +311,14 @@ + + + + + + + + diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoApplication.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoApplication.java index 910e62f..e83bbd3 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoApplication.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoApplication.java @@ -14,11 +14,12 @@ package apijson.boot; -import apijson.framework.APIJSONSQLConfig; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.alibaba.fastjson.serializer.PropertyFilter; - +import apijson.fastjson2.APIJSONApplication; +import apijson.fastjson2.APIJSONCreator; +import apijson.fastjson2.APIJSONVerifier; +import apijson.fastjson2.APIJSONSQLConfig; +import apijson.orm.AbstractParser; +import apijson.orm.AbstractVerifier; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -29,8 +30,6 @@ import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import java.lang.reflect.Modifier; -import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -44,21 +43,12 @@ import apijson.demo.DemoSQLConfig; import apijson.demo.DemoSQLExecutor; import apijson.demo.DemoVerifier; -import apijson.framework.APIJSONApplication; -import apijson.framework.APIJSONCreator; -import apijson.framework.APIJSONParser; -import apijson.orm.AbstractVerifier; -import apijson.orm.FunctionParser; -import apijson.orm.Parser; -import apijson.orm.SQLConfig; -import apijson.orm.SQLExecutor; import apijson.orm.Verifier; -import apijson.router.APIJSONRouterApplication; -import unitauto.MethodUtil; -import unitauto.MethodUtil.Argument; -import unitauto.MethodUtil.InstanceGetter; -import unitauto.MethodUtil.JSONCallback; -import unitauto.jar.UnitAutoApp; +//import unitauto.MethodUtil; +//import unitauto.MethodUtil.Argument; +//import unitauto.MethodUtil.InstanceGetter; +//import unitauto.MethodUtil.JSONCallback; +//import unitauto.jar.UnitAutoApp; /** @@ -91,12 +81,13 @@ public static void main(String[] args) throws Exception { // FIXME 不要开放给项目组后端之外的任何人使用 UnitAuto(强制登录鉴权)!!!如果不需要单元测试则移除相关代码或 unitauto.Log.DEBUG = false; // 上线生产环境前改为 false,可不输出 APIJSONORM 的日志 以及 SQLException 的原始(敏感)信息 - unitauto.Log.DEBUG = Log.DEBUG = true; // 是否开启调试模式(打印详细日志、返回详细调试信息等) - APIJSONParser.IS_PRINT_BIG_LOG = true; // 是否打印大日志 -// APIJSONParser.IS_START_FROM_1 = true; // 分页页码是否从 1 开始,true - 从 1 开始;false - 从 0 开始 -// APIJSONSQLConfig.ENABLE_COLUMN_CONFIG = true; // apijson-framework 已集成字段插件 apijson-column,支持 !key 反选字段 和 字段名映射 + //unitauto.Log.DEBUG = true; + Log.DEBUG = true; // 是否开启调试模式(打印详细日志、返回详细调试信息等) + AbstractParser.IS_PRINT_BIG_LOG = true; // 是否打印大日志 + APIJSONVerifier.ENABLE_APIJSON_ROUTER = true; // apijson-framework 已集成字段插件 apijson-router,是否开启 接口路由 模式,支持简单接口转为 APIJSON JSON + //APIJSONParser.IS_START_FROM_1 = true; // 分页页码是否从 1 开始,true - 从 1 开始;false - 从 0 开始 + APIJSONSQLConfig.ENABLE_COLUMN_CONFIG = false; // apijson-framework 已集成字段插件 apijson-column,支持 !key 反选字段 和 字段名映射 APIJSONApplication.init(); - APIJSONRouterApplication.init(); System.out.println("\n\n<<<<<<<<< 本 Demo 在 resources/static 内置了 APIAuto,Chrome/Firefox 打开 http://localhost:8080 即可调试(端口号根据项目配置而定) ^_^ >>>>>>>>>\n"); } @@ -223,6 +214,15 @@ public void addCorsMappings(CorsRegistry registry) { // Log.e(TAG, "加载 TDengine 驱动失败,请检查 pom.xml 中 com.taosdata.jdbc 版本是否存在以及可用 !!!"); // } + // try { //加载驱动程序 + // Log.d(TAG, "尝试加载 openGauss 驱动 <<<<<<<<<<<<<<<<<<<<< "); + // Class.forName("org.opengauss.Driver"); + // Log.d(TAG, "成功加载 openGauss 驱动!>>>>>>>>>>>>>>>>>>>>> "); + // } catch (ClassNotFoundException e) { + // e.printStackTrace(); + // Log.e(TAG, "加载 openGauss 驱动失败,请检查 pom.xml 中 org.opengauss 版本是否存在以及可用 !!!"); + // } + // APIJSON 配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Map COMPILE_MAP = AbstractVerifier.COMPILE_MAP; @@ -234,27 +234,27 @@ public void addCorsMappings(CorsRegistry registry) { APIJSONApplication.DEFAULT_APIJSON_CREATOR = new APIJSONCreator() { @Override - public Parser createParser() { + public DemoParser createParser() { return new DemoParser(); } @Override - public FunctionParser createFunctionParser() { + public DemoFunctionParser createFunctionParser() { return new DemoFunctionParser(); } @Override - public Verifier createVerifier() { + public DemoVerifier createVerifier() { return new DemoVerifier(); } @Override - public SQLConfig createSQLConfig() { + public DemoSQLConfig createSQLConfig() { return new DemoSQLConfig(); } @Override - public SQLExecutor createSQLExecutor() { + public DemoSQLExecutor createSQLExecutor() { return new DemoSQLExecutor(); } @@ -265,96 +265,96 @@ public SQLExecutor createSQLExecutor() { // UnitAuto 单元测试配置 https://github.com/TommyLemon/UnitAuto <<<<<<<<<<<<<<<<<<<<<<<<<<< // FIXME 不要开放给项目组后端之外的任何人使用 UnitAuto(强制登录鉴权)!!!如果不需要单元测试则移除相关代码或 unitauto.Log.DEBUG = false; - UnitAutoApp.init(); + //UnitAutoApp.init(); // 适配 Spring 注入的类及 Context 等环境相关的类 - final InstanceGetter ig = MethodUtil.INSTANCE_GETTER; - MethodUtil.INSTANCE_GETTER = new InstanceGetter() { - - @Override - public Object getInstance(@NotNull Class clazz, List classArgs, Boolean reuse) throws Exception { - if (APPLICATION_CONTEXT != null && ApplicationContext.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(APPLICATION_CONTEXT.getClass())) { - return APPLICATION_CONTEXT; - } - - if (reuse != null && reuse && (classArgs == null || classArgs.isEmpty())) { - return APPLICATION_CONTEXT.getBean(clazz); - } - - return ig.getInstance(clazz, classArgs, reuse); - } - }; - - // 排除转换 JSON 异常的类,一般是 Context 等环境相关的类 - final JSONCallback jc = MethodUtil.JSON_CALLBACK; - MethodUtil.JSON_CALLBACK = new JSONCallback() { - - @Override - public JSONObject newSuccessResult() { - return jc.newSuccessResult(); - } - - @Override - public JSONObject newErrorResult(Throwable e) { - return jc.newErrorResult(e); - } - - @Override - public JSONObject parseJSON(String type, Object value) { - if (value == null || unitauto.JSON.isBooleanOrNumberOrString(value) || value instanceof JSON || value instanceof Enum) { - return jc.parseJSON(type, value); - } - - if (value instanceof ApplicationContext - || value instanceof Context - || value instanceof org.apache.catalina.Context - // SpringBoot 2.6.7 已移除 || value instanceof ch.qos.logback.core.Context - ) { - value = value.toString(); - } else { - try { - value = JSON.parse(JSON.toJSONString(value, new PropertyFilter() { - @Override - public boolean apply(Object object, String name, Object value) { - if (value == null) { - return true; - } - - if (value instanceof ApplicationContext - || value instanceof Context - || value instanceof org.apache.catalina.Context - // SpringBoot 2.6.7 已移除 || value instanceof ch.qos.logback.core.Context - ) { - return false; - } - - // 防止通过 UnitAuto 远程执行 getDBPassword 等方法来查到敏感信息,但如果直接调用 public String getDBUri 这里没法拦截,仍然会返回敏感信息 - // if (object instanceof SQLConfig) { - // // 这个类部分方法不序列化返回 - // if ("dBUri".equalsIgnoreCase(name) || "dBPassword".equalsIgnoreCase(name) || "dBAccount".equalsIgnoreCase(name)) { - // return false; - // } - // return false; // 这个类所有方法都不序列化返回 - // } - - // 所有类中的方法只要包含关键词就不序列化返回 - String n = StringUtil.toLowerCase(name); - if (n.contains("database") || n.contains("schema") || n.contains("dburi") || n.contains("password") || n.contains("account")) { - return false; - } - - return Modifier.isPublic(value.getClass().getModifiers()); - } - })); - } catch (Exception e) { - Log.e(TAG, "toJSONString catch \n" + e.getMessage()); - } - } - - return jc.parseJSON(type, value); - } - - }; + //final InstanceGetter ig = MethodUtil.INSTANCE_GETTER; + //MethodUtil.INSTANCE_GETTER = new InstanceGetter() { + // + // @Override + // public Object getInstance(@NotNull Class clazz, List classArgs, Boolean reuse) throws Exception { + // if (APPLICATION_CONTEXT != null && ApplicationContext.class.isAssignableFrom(clazz) && clazz.isAssignableFrom(APPLICATION_CONTEXT.getClass())) { + // return APPLICATION_CONTEXT; + // } + // + // if (reuse != null && reuse && (classArgs == null || classArgs.isEmpty())) { + // return APPLICATION_CONTEXT.getBean(clazz); + // } + // + // return ig.getInstance(clazz, classArgs, reuse); + // } + //}; + // + //// 排除转换 JSON 异常的类,一般是 Context 等环境相关的类 + //final JSONCallback jc = MethodUtil.JSON_CALLBACK; + //MethodUtil.JSON_CALLBACK = new JSONCallback() { + // + // @Override + // public JSONObject newSuccessResult() { + // return jc.newSuccessResult(); + // } + // + // @Override + // public JSONObject newErrorResult(Throwable e) { + // return jc.newErrorResult(e); + // } + // + // @Override + // public JSONObject parseJSON(String type, Object value) { + // if (value == null || unitauto.JSON.isBooleanOrNumberOrString(value) || value instanceof JSON || value instanceof Enum) { + // return jc.parseJSON(type, value); + // } + // + // if (value instanceof ApplicationContext + // || value instanceof Context + // || value instanceof org.apache.catalina.Context + // // SpringBoot 2.6.7 已移除 || value instanceof ch.qos.logback.core.Context + // ) { + // value = value.toString(); + // } else { + // try { + // value = parseJSON(JSON.toJSONString(value, new PropertyFilter() { + // @Override + // public boolean apply(Object object, String name, Object value) { + // if (value == null) { + // return true; + // } + // + // if (value instanceof ApplicationContext + // || value instanceof Context + // || value instanceof org.apache.catalina.Context + // // SpringBoot 2.6.7 已移除 || value instanceof ch.qos.logback.core.Context + // ) { + // return false; + // } + // + // // 防止通过 UnitAuto 远程执行 getDBPassword 等方法来查到敏感信息,但如果直接调用 public String getDBUri 这里没法拦截,仍然会返回敏感信息 + // // if (object instanceof SQLConfig) { + // // // 这个类部分方法不序列化返回 + // // if ("dBUri".equalsIgnoreCase(name) || "dBPassword".equalsIgnoreCase(name) || "dBAccount".equalsIgnoreCase(name)) { + // // return false; + // // } + // // return false; // 这个类所有方法都不序列化返回 + // // } + // + // // 所有类中的方法只要包含关键词就不序列化返回 + // String n = StringUtil.toLowerCase(name); + // if (n.contains("database") || n.contains("schema") || n.contains("dburi") || n.contains("password") || n.contains("account")) { + // return false; + // } + // + // return Modifier.isPublic(value.getClass().getModifiers()); + // } + // })); + // } catch (Exception e) { + // Log.e(TAG, "toJSONString catch \n" + e.getMessage()); + // } + // } + // + // return jc.parseJSON(type, value); + // } + // + //}; // UnitAuto 单元测试配置 https://github.com/TommyLemon/UnitAuto >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoController.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoController.java index bf3f44f..19455c2 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoController.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/DemoController.java @@ -14,30 +14,22 @@ package apijson.boot; -import apijson.orm.AbstractParser; -import apijson.orm.Parser; +import apijson.fastjson2.APIJSONController; +import apijson.fastjson2.APIJSONParser; +import apijson.fastjson2.JSONRequest; import apijson.orm.exception.*; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; -import com.alibaba.fastjson.serializer.SerializerFeature; -import com.alibaba.fastjson.serializer.ValueFilter; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.databind.util.LRUMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestClientResponseException; import org.springframework.web.client.RestTemplate; -import java.io.IOException; import java.lang.reflect.Array; import java.net.URLDecoder; import java.net.URLEncoder; @@ -54,8 +46,8 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; -import apijson.JSON; -import apijson.JSONResponse; +import apijson.fastjson2.JSON; +import apijson.fastjson2.JSONResponse; import apijson.Log; import apijson.RequestMethod; import apijson.StringUtil; @@ -68,12 +60,9 @@ import apijson.demo.model.User; import apijson.demo.model.Verify; import apijson.framework.BaseModel; -import apijson.orm.JSONRequest; -import apijson.orm.model.TestRecord; -import apijson.router.APIJSONRouterController; -import org.springframework.web.servlet.ModelAndView; import unitauto.MethodUtil; +import static apijson.JSON.getString; import static apijson.RequestMethod.DELETE; import static apijson.RequestMethod.GET; import static apijson.RequestMethod.GETS; @@ -87,14 +76,13 @@ import static apijson.framework.APIJSONConstant.FUNCTION_; import static apijson.framework.APIJSONConstant.ID; import static apijson.framework.APIJSONConstant.REQUEST_; -import static apijson.framework.APIJSONConstant.TEST_RECORD_; import static apijson.framework.APIJSONConstant.USER_ID; import static apijson.framework.APIJSONConstant.VERSION; import static org.springframework.http.HttpHeaders.COOKIE; import static org.springframework.http.HttpHeaders.SET_COOKIE; -/**请求路由入口控制器,包括通用增删改查接口等,转交给 APIJSON 的 Parser 来处理 +/**请求路由入口控制器,包括通用增删改查接口等,转交给 APIJSON 的 Parser 来处理 * 具体见 SpringBoot 文档 * https://www.springcloud.cc/spring-boot.html#boot-features-spring-mvc * 以及 APIJSON 通用文档 3.设计规范 3.1 操作方法 @@ -108,7 +96,7 @@ @Service @RestController @RequestMapping("") -public class DemoController extends APIJSONRouterController { // APIJSONController { +public class DemoController extends APIJSONController { private static final String TAG = "DemoController"; public String getRequestBaseURL() { @@ -142,10 +130,11 @@ public String getRequestURL() { } @Override - public Parser newParser(HttpSession session, RequestMethod method) { - return super.newParser(session, method).setNeedVerify(false); + public APIJSONParser newParser(HttpSession session, RequestMethod method) { + return super.newParser(session, method); // .setNeedVerify(false); } + /**增删改查统一的类 RESTful API 入口,牺牲一点路由解析性能来提升一些开发效率 * @param method * @param tag @@ -172,7 +161,7 @@ public String router(@PathVariable("method") String method, @PathVariable("tag") @PostMapping(value = "crud") // 直接 {method} 或 apijson/{method} 会和内置网页的路由有冲突 // @Override public String crudAll(@RequestBody String request, HttpSession session) { - return newParser(session, RequestMethod.CRUD).parse(request); + return super.crudAll(request, session); } /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一点路由解析性能来提升一些开发效率 * @param method @@ -390,7 +379,7 @@ public String openGet(@PathVariable("request") String request, HttpSession sessi try { request = URLDecoder.decode(request, StringUtil.UTF_8); } catch (Exception e) { - // Parser 会报错 + // Parser 会报错 } if (! Log.DEBUG) { // 一般情况这样简单使用 @@ -402,7 +391,7 @@ public String openGet(@PathVariable("request") String request, HttpSession sessi try { String url = getRequestURL(); - String query = StringUtil.getTrimedString(httpServletRequest.getQueryString()); + String query = StringUtil.trim(httpServletRequest.getQueryString()); if (StringUtil.isNotEmpty(query)) { try { query = "?" + URLEncoder.encode(query, StringUtil.UTF_8); @@ -548,16 +537,16 @@ public JSONObject reload(@RequestBody String request) { phone = requestObject.getString(PHONE); verify = requestObject.getString(VERIFY); } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } JSONResponse response = new JSONResponse(headVerify(Verify.TYPE_RELOAD, phone, verify)); response = response.getJSONResponse(VERIFY_); if (JSONResponse.isExist(response) == false) { - return DemoParser.extendErrorResult(requestObject, new ConditionErrorException("手机号或验证码错误")); + return extendErrorResult(requestObject, new ConditionErrorException("手机号或验证码错误")); } - JSONObject result = DemoParser.newSuccessResult(); + JSONObject result = newSuccessResult(); boolean reloadAll = StringUtil.isEmpty(type, true) || "ALL".equals(type); @@ -566,7 +555,7 @@ public JSONObject reload(@RequestBody String request) { result.put(ACCESS_, DemoVerifier.initAccess(false, null, value)); } catch (ServerException e) { e.printStackTrace(); - result.put(ACCESS_, DemoParser.newErrorResult(e)); + result.put(ACCESS_, newErrorResult(e)); } } @@ -575,7 +564,7 @@ public JSONObject reload(@RequestBody String request) { result.put(FUNCTION_, DemoFunctionParser.init(false, null, value)); } catch (ServerException e) { e.printStackTrace(); - result.put(FUNCTION_, DemoParser.newErrorResult(e)); + result.put(FUNCTION_, newErrorResult(e)); } } @@ -584,7 +573,7 @@ public JSONObject reload(@RequestBody String request) { result.put(REQUEST_, DemoVerifier.initRequest(false, null, value)); } catch (ServerException e) { e.printStackTrace(); - result.put(REQUEST_, DemoParser.newErrorResult(e)); + result.put(REQUEST_, newErrorResult(e)); } } @@ -611,10 +600,10 @@ public JSONObject postVerify(@RequestBody String request) { type = requestObject.getIntValue(TYPE); phone = requestObject.getString(PHONE); } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } - new DemoParser(DELETE, false).parse(newVerifyRequest(type, phone, null)); + new DemoParser(DELETE, false).parse(newVerifyRequest(type, phone)); JSONObject response = new DemoParser(POST, false).parseResponse( newVerifyRequest(type, phone, "" + (new Random().nextInt(9999) + 1000)) @@ -622,7 +611,7 @@ public JSONObject postVerify(@RequestBody String request) { if (JSONResponse.isSuccess(response) == false) { - new DemoParser(DELETE, false).parseResponse(new JSONRequest(new Verify(type, phone))); + new DemoParser(DELETE, false).parseResponse(newVerifyRequest(type, phone)); return response; } @@ -653,9 +642,9 @@ public JSONObject getVerify(@RequestBody String request) { type = requestObject.getIntValue(TYPE); phone = requestObject.getString(PHONE); } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } - return new DemoParser(GETS, false).parseResponse(newVerifyRequest(type, phone, null)); + return new DemoParser(GETS, false).parseResponse(newVerifyRequest(type, phone)); } /**校验验证码 @@ -681,7 +670,7 @@ public JSONObject headVerify(@RequestBody String request) { phone = requestObject.getString(PHONE); verify = requestObject.getString(VERIFY); } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } return headVerify(type, phone, verify); } @@ -696,15 +685,12 @@ public JSONObject headVerify(@RequestBody String request) { public JSONObject headVerify(int type, String phone, String code) { JSONResponse response = new JSONResponse( new DemoParser(GETS, false).parseResponse( - new JSONRequest( - new Verify(type, phone) - .setVerify(code) - ).setTag(VERIFY_) + newVerifyRequest(type, phone, code) ) ); Verify verify = response.getObject(Verify.class); if (verify == null) { - return DemoParser.newErrorResult(StringUtil.isEmpty(code, true) + return newErrorResult(StringUtil.isEmpty(code, true) ? new NotExistException("验证码不存在!") : new ConditionErrorException("手机号或验证码错误!")); } @@ -713,27 +699,36 @@ public JSONObject headVerify(int type, String phone, String code) { long now = System.currentTimeMillis(); if (now > 60*1000 + time) { new DemoParser(DELETE, false).parseResponse( - new JSONRequest(new Verify(type, phone)).setTag(VERIFY_) + newVerifyRequest(type, phone) ); - return DemoParser.newErrorResult(new TimeoutException("验证码已过期!")); + return newErrorResult(new TimeoutException("验证码已过期!")); } - return new JSONResponse( - new DemoParser(HEADS, false).parseResponse( - new JSONRequest(new Verify(type, phone).setVerify(code)).setFormat(true) - ) + return new DemoParser(HEADS, false).parseResponse( + newVerifyRequest(type, phone, code) ); } /**新建一个验证码请求 + * @param phone + * @param phone + * @return + */ + public static JSONObject newVerifyRequest(int type, String phone) { + return newVerifyRequest(type, phone, null); + } + /**新建一个验证码请求 + * @param type * @param phone * @param verify * @return */ - private apijson.JSONRequest newVerifyRequest(int type, String phone, String verify) { - return new JSONRequest(new Verify(type, phone).setVerify(verify)).setTag(VERIFY_).setFormat(true); + public static JSONObject newVerifyRequest(int type, String phone, String verify) { + return new JSONRequest( + new Verify(type, phone).setVerify(verify) + ).setTag(VERIFY_).setFormat(true); } @@ -757,7 +752,7 @@ private apijson.JSONRequest newVerifyRequest(int type, String phone, String veri } * */ - @PostMapping(LOGIN) //TODO 改 SQLConfig 里的 dbAccount, dbPassword,直接用数据库鉴权 + @PostMapping(LOGIN) //TODO 改 SQLConfig 里的 dbAccount, dbPassword,直接用数据库鉴权 public JSONObject login(@RequestBody String request, HttpSession session) { JSONObject requestObject = null; boolean isPassword; @@ -799,22 +794,20 @@ public JSONObject login(@RequestBody String request, HttpSession session) { requestObject.remove(REMEMBER); requestObject.remove(DEFAULTS); } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } //手机号是否已注册 JSONObject phoneResponse = new DemoParser(HEADS, false).parseResponse( - new JSONRequest( - new Privacy().setPhone(phone) - ) + new JSONRequest(new Privacy().setPhone(phone)) ); if (JSONResponse.isSuccess(phoneResponse) == false) { - return DemoParser.newResult(phoneResponse.getIntValue(JSONResponse.KEY_CODE), phoneResponse.getString(JSONResponse.KEY_MSG)); + return newResult(phoneResponse.getIntValue(JSONResponse.KEY_CODE), getString(phoneResponse, JSONResponse.KEY_MSG)); } JSONResponse response = new JSONResponse(phoneResponse).getJSONResponse(PRIVACY_); if(JSONResponse.isExist(response) == false) { - return DemoParser.newErrorResult(new NotExistException("手机号未注册")); + return newErrorResult(new NotExistException("手机号未注册")); } //根据phone获取User @@ -842,26 +835,25 @@ public JSONObject login(@RequestBody String request, HttpSession session) { response = new JSONResponse(headVerify(Verify.TYPE_LOGIN, phone, password)); } if (JSONResponse.isSuccess(response) == false) { - return response; + return response.toObject(JSONObject.class); } response = response.getJSONResponse(isPassword ? PRIVACY_ : VERIFY_); if (JSONResponse.isExist(response) == false) { - return DemoParser.newErrorResult(new ConditionErrorException("账号或密码错误")); + return newErrorResult(new ConditionErrorException("账号或密码错误")); } response = new JSONResponse( new DemoParser(GETS, false).parseResponse( - new JSONRequest( // 兼容 MySQL 5.6 及以下等不支持 json 类型的数据库 - USER_, // User 里在 setContactIdList(List) 后加 setContactIdList(String) 没用 - new apijson.JSONObject( // fastjson 查到一个就不继续了,所以只能加到前面或者只有这一个,但这样反过来不兼容 5.7+ - new User(userId) // 所以就用 @json 来强制转为 JSONArray,保证有效 - ).setJson("contactIdList,pictureList") - ).setFormat(true) + new JSONRequest( // 兼容 MySQL 5.6 及以下等不支持 json 类型的数据库 + USER_, // User 里在 setContactIdList(List) 后加 setContactIdList(String) 没用 + JSONRequest.setJson(JSON.parseObject(new User(userId)),"contactIdList,pictureList") + ) + .setFormat(true) ) ); User user = response.getObject(User.class); if (user == null || BaseModel.value(user.getId()) != userId) { - return DemoParser.newErrorResult(new NullPointerException("服务器内部错误")); + return newErrorResult(new NullPointerException("服务器内部错误")); } //登录状态保存至session @@ -886,7 +878,9 @@ public JSONObject login(@RequestBody String request, HttpSession session) { @PostMapping("logout") @Override public JSONObject logout(HttpSession session) { - SESSION_MAP.remove(session.getId()); + if (session != null) { + SESSION_MAP.remove(session.getId()); + } Long userId; try { @@ -894,11 +888,11 @@ public JSONObject logout(HttpSession session) { Log.d(TAG, "logout userId = " + userId + "; session.getId() = " + (session == null ? null : session.getId())); super.logout(session); } catch (Exception e) { - return DemoParser.newErrorResult(e); + return newErrorResult(e); } - JSONObject result = DemoParser.newSuccessResult(); - JSONObject user = DemoParser.newSuccessResult(); + JSONObject result = newSuccessResult(); + JSONObject user = newSuccessResult(); user.put(ID, userId); user.put(COUNT, 1); result.put(StringUtil.firstCase(USER_), user); @@ -938,7 +932,7 @@ public JSONObject register(@RequestBody String request) { requestObject = DemoParser.parseRequest(request); privacyObj = requestObject.getJSONObject(PRIVACY_); - phone = StringUtil.getString(privacyObj.getString(PHONE)); + phone = StringUtil.get(privacyObj.getString(PHONE)); verify = requestObject.getString(VERIFY); password = privacyObj.getString(_PASSWORD); @@ -952,7 +946,7 @@ public JSONObject register(@RequestBody String request) { return newIllegalArgumentResult(requestObject, VERIFY); } } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } @@ -962,11 +956,9 @@ public JSONObject register(@RequestBody String request) { } //手机号或验证码错误 if (JSONResponse.isExist(response.getJSONResponse(VERIFY_)) == false) { - return DemoParser.extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!")); + return extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!")); } - - //生成User和Privacy if (StringUtil.isEmpty(requestObject.getString(JSONRequest.KEY_TAG), true)) { requestObject.put(JSONRequest.KEY_TAG, REGISTER); @@ -1014,8 +1006,8 @@ public static JSONObject newIllegalArgumentResult(JSONObject requestObject, Stri * @return */ public static JSONObject newIllegalArgumentResult(JSONObject requestObject, String key, String msg) { - return DemoParser.extendErrorResult(requestObject - , new IllegalArgumentException(key + ":value 中value不合法!" + StringUtil.getString(msg))); + return new DemoParser().extendErrorResult(requestObject + , new IllegalArgumentException(key + ":value 中value不合法!" + StringUtil.get(msg))); } @@ -1056,8 +1048,8 @@ public JSONObject putPassword(@RequestBody String request){ String password; try { requestObject = DemoParser.parseRequest(request); - oldPassword = StringUtil.getString(requestObject.getString(OLD_PASSWORD)); - verify = StringUtil.getString(requestObject.getString(VERIFY)); + oldPassword = StringUtil.get(requestObject.getString(OLD_PASSWORD)); + verify = StringUtil.get(requestObject.getString(VERIFY)); requestObject.remove(OLD_PASSWORD); requestObject.remove(VERIFY); @@ -1082,16 +1074,16 @@ public JSONObject putPassword(@RequestBody String request){ } } } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } if (StringUtil.isPassword(oldPassword)) { if (userId <= 0) { //手机号+验证码不需要userId - return DemoParser.extendErrorResult(requestObject, new IllegalArgumentException(ID + ":value 中value不合法!")); + return extendErrorResult(requestObject, new IllegalArgumentException(ID + ":value 中value不合法!")); } if (oldPassword.equals(password)) { - return DemoParser.extendErrorResult(requestObject, new ConflictException("新旧密码不能一样!")); + return extendErrorResult(requestObject, new ConflictException("新旧密码不能一样!")); } //验证旧密码 @@ -1107,7 +1099,7 @@ public JSONObject putPassword(@RequestBody String request){ ) ); if (JSONResponse.isExist(response.getJSONResponse(PRIVACY_)) == false) { - return DemoParser.extendErrorResult(requestObject, new ConditionErrorException("账号或原密码错误,请重新输入!")); + return extendErrorResult(requestObject, new ConditionErrorException("账号或原密码错误,请重新输入!")); } } else if (StringUtil.isPhone(phone) && StringUtil.isVerify(verify)) { @@ -1116,7 +1108,7 @@ else if (StringUtil.isPhone(phone) && StringUtil.isVerify(verify)) { return response; } if (JSONResponse.isExist(response.getJSONResponse(VERIFY_)) == false) { - return DemoParser.extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!")); + return extendErrorResult(response, new ConditionErrorException("手机号或验证码错误!")); } response = new JSONResponse( new DemoParser(GET, false).parseResponse( @@ -1132,7 +1124,7 @@ else if (StringUtil.isPhone(phone) && StringUtil.isVerify(verify)) { requestObject.put(PRIVACY_, privacyObj); } else { - return DemoParser.extendErrorResult(requestObject, new IllegalArgumentException("请输入合法的 旧密码 或 手机号+验证码 !")); + return extendErrorResult(requestObject, new IllegalArgumentException("请输入合法的 旧密码 或 手机号+验证码 !")); } //TODO 上线版加上 password = MD5Util.MD5(password); @@ -1186,7 +1178,7 @@ public JSONObject putBalance(@RequestBody String request, HttpSession session) { throw new IllegalArgumentException(PRIVACY_ + "." + _PAY_PASSWORD + ":value 中value不合法!"); } } catch (Exception e) { - return DemoParser.extendErrorResult(requestObject, e); + return extendErrorResult(requestObject, e); } //验证密码<<<<<<<<<<<<<<<<<<<<<<< @@ -1199,7 +1191,7 @@ public JSONObject putBalance(@RequestBody String request, HttpSession session) { ); response = response.getJSONResponse(PRIVACY_); if (JSONResponse.isExist(response) == false) { - return DemoParser.extendErrorResult(requestObject, new ConditionErrorException("支付密码错误!")); + return extendErrorResult(requestObject, new ConditionErrorException("支付密码错误!")); } //验证密码>>>>>>>>>>>>>>>>>>>>>>>> @@ -1208,10 +1200,10 @@ public JSONObject putBalance(@RequestBody String request, HttpSession session) { //验证金额范围<<<<<<<<<<<<<<<<<<<<<<< if (change == 0) { - return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("balance+的值不能为0!")); + return extendErrorResult(requestObject, new OutOfRangeException("balance+的值不能为0!")); } if (Math.abs(change) > 10000) { - return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("单次 充值/提现 的金额不能超过10000元!")); + return extendErrorResult(requestObject, new OutOfRangeException("单次 充值/提现 的金额不能超过10000元!")); } //验证金额范围>>>>>>>>>>>>>>>>>>>>>>>> @@ -1219,19 +1211,17 @@ public JSONObject putBalance(@RequestBody String request, HttpSession session) { if (change < 0) {//提现 response = new JSONResponse( new DemoParser(GETS, false).parseResponse( - new JSONRequest( - new Privacy(userId) - ) + new JSONRequest(new Privacy(userId)) ) ); - Privacy privacy = response == null ? null : response.getObject(Privacy.class); + Privacy privacy = response.getObject(Privacy.class); long id = privacy == null ? 0 : BaseModel.value(privacy.getId()); if (id != userId) { - return DemoParser.extendErrorResult(requestObject, new Exception("服务器内部错误!")); + return extendErrorResult(requestObject, new Exception("服务器内部错误!")); } if (BaseModel.value(privacy.getBalance()) < -change) { - return DemoParser.extendErrorResult(requestObject, new OutOfRangeException("余额不足!")); + return extendErrorResult(requestObject, new OutOfRangeException("余额不足!")); } } @@ -1309,7 +1299,7 @@ public String delegate( HttpMethod method, HttpSession session ) { if (Log.DEBUG == false) { - return DemoParser.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用服务器代理!")).toJSONString(); + return JSON.toJSONString(newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许使用服务器代理!"))); } int recordType = record != null ? record : (REQUEST_RECORD_TYPE != null ? REQUEST_RECORD_TYPE : 0); @@ -1328,7 +1318,7 @@ public String delegate( JSONObject obj = JSON.parseObject(body); if (obj == null) { - obj = new JSONObject(true); + obj = JSON.newJSONObject(); } if (obj.get("endpoint") == null) { endpoint = index < 0 ? endpoint : endpoint.substring(0, index); @@ -1429,10 +1419,10 @@ else if (body != null && "DATA".equals(type)) { // if (StringUtil.isNotEmpty(bod hm.put(name, h); try { - com.alibaba.fastjson.JSON.parse(h); + JSON.parse(h); } catch (Throwable e) { Log.e(TAG, "delegate try {\n" + - " JSON.parse(h);\n" + + " parseJSON(h);\n" + " } catch (Throwable e) = " + e.getMessage()); hs += "\n" + name + ": " + "\"" + h.replaceAll("\"", "\\\"") + "\""; continue; @@ -1471,11 +1461,11 @@ else if (names != null) { hm.put(name, h); try { - com.alibaba.fastjson.JSON.parse(h); + JSON.parse(h); } catch (Throwable e) { Log.e(TAG, "delegate try {\n" + - " JSON.parse(h);\n" + + " parseJSON(h);\n" + " } catch (Throwable e) = " + e.getMessage()); hs += "\n" + name + ": " + "\"" + h.replaceAll("\"", "\\\"") + "\""; continue; @@ -1542,7 +1532,7 @@ else if (names != null) { for (Entry e : set) { if (e != null) { String[] vals = e.getValue(); - url += ((first ? "" : "&") + e.getKey() + "=" + ( vals == null || vals.length <= 0 ? "" : StringUtil.getString(vals[0]) )); + url += ((first ? "" : "&") + e.getKey() + "=" + ( vals == null || vals.length <= 0 ? "" : StringUtil.get(vals[0]) )); first = false; } } @@ -1577,12 +1567,12 @@ else if (names != null) { : (MediaType.MULTIPART_FORM_DATA.equals(contentType) ? "DATA" : "JSON"))) // FIXME 考虑 XML, PNG 等格式? ) : "JSON"; - String sql = isSQL ? StringUtil.getTrimedString(req.getString("sql")) : null; + String sql = isSQL ? StringUtil.trim(req.getString("sql")) : null; String newSql = ""; // String[] lines = sql.split(" \\? "); // StringUtil.split(sql, " \\? ", false); // int len = lines == null ? 0 : lines.length; // if (len > 0) { -// JSONArray args = req.getJSONArray("args"); +// JSONList args = req.getJSONArray("args"); // Set set = hm.keySet(); // Iterator iterator = set.iterator(); // @@ -1642,11 +1632,11 @@ else if (names != null) { sql = newSql.trim(); } - JSONRequest existReq = new JSONRequest(); + JSONObject existReq = JSON.newJSONObject(); if (isUnit) { if (req != null) { // Method <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - apijson.JSONRequest mthd = new apijson.JSONRequest(); + JSONRequest mthd = new JSONRequest(); if (recordType > 0) { mthd.setColumn("id"); } @@ -1667,7 +1657,7 @@ else if (names != null) { } else { // Document <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - apijson.JSONRequest document = new apijson.JSONRequest(); + JSONRequest document = new JSONRequest(); if (recordType > 0) { document.setColumn("id"); } @@ -1687,13 +1677,13 @@ else if (names != null) { long documentId = existRsp2 == null ? 0 : existRsp2.getId(); JSONRequest request = new JSONRequest(); - apijson.JSONRequest testRecord = new apijson.JSONRequest(); + JSONRequest testRecord = new JSONRequest(); if (documentId <= 0) { if (isUnit) { request.setTag("Method"); // Method <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - apijson.JSONRequest mthd = new apijson.JSONRequest(); + JSONRequest mthd = new JSONRequest(); mthd.put("from", 2); // 0-测试工具,1-CI/CD,2-流量录制 mthd.put("language", req.getString("language")); mthd.put(MethodUtil.KEY_UI, req.getInteger(MethodUtil.KEY_UI)); @@ -1714,7 +1704,7 @@ else if (names != null) { else if (recordType > 0) { request.setTag("Document"); // Document <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - JSONObject document = new JSONObject(true); + JSONObject document = JSON.newJSONObject(); document.put("from", 2); // 0-测试工具,1-CI/CD,2-流量录制 document.put("name", "[Record] " + new java.util.Date().toLocaleString()); document.put("type", reqType); @@ -1723,7 +1713,7 @@ else if (recordType > 0) { document.put("request", isSQL ? "{}" : (isBodyEmpty ? JSON.toJSONString(map) : body)); if (isSQL) { // 没有名称,除非 args 传对象而不是数组 - // JSONArray args = req.getJSONArray("args"); + // JSONList args = req.getJSONArray("args"); // String argStr = ""; // if (args != null) { // for (int i = 0; i < args.size(); i++) { @@ -1747,7 +1737,7 @@ else if (recordType > 0) { Map m = isSQL ? null : (isBodyEmpty ? map : JSON.parseObject(body)); String config = isSQL ? hs : parseRandomConfig("", m); - JSONObject random = new JSONObject(true); + JSONObject random = JSON.newJSONObject(); random.put("count", 1); random.put("documentId", documentId); random.put("config", config.trim()); @@ -1774,7 +1764,7 @@ else if (recordType > 0) { isDefault = Objects.equals(reqObj, req); } catch (Throwable e) { - Log.w(TAG, "delegate try { Object reqObj = JSON.parse(reqStr); ..." + + Log.w(TAG, "delegate try { Object reqObj = parseJSON(reqStr); ..." + " } catch (Throwable e) = " + e.getMessage()); } } @@ -1785,7 +1775,7 @@ else if (recordType > 0) { else { long randomId = 0; try { - apijson.JSONRequest randomReq = new apijson.JSONRequest(); + JSONObject randomReq = JSON.newJSONObject(); randomReq.put("Random", random); JSONObject rsp = newParser(session, GET).parseResponse(randomReq); @@ -1793,7 +1783,7 @@ else if (recordType > 0) { randomId = rsp2 == null ? 0 : rsp2.getLongValue("id"); } catch (Throwable e) { - Log.w(TAG, "delegate try { apijson.JSONRequest randomReq = new apijson.JSONRequest(); ..." + + Log.w(TAG, "delegate try { JSONMap randomReq = JSON.newJSONObject(); ..." + " } catch (Throwable e) = " + e.getMessage()); } @@ -1812,7 +1802,7 @@ else if (recordType > 0) { else { // TestRecord <<<<<<<<<<<<<<<<<<<<<<<<<<<<< testRecord.put("from", 2); // 0-接口工具,1-CI/CD,2-流量录制 testRecord.put("host", host); - testRecord.put("response", rspBody); // 用 JSONRequest.put 会转为 JSONObject + testRecord.put("response", rspBody); // 用 JSONRequest.put 会转为 JSONMap } // TestRecord >>>>>>>>>>>>>>>>>>>>>>>>>>>>> request.put("TestRecord", testRecord); @@ -1822,7 +1812,7 @@ else if (recordType > 0) { String response = rsp2 == null ? null : rsp2.getString("response"); if (StringUtil.isNotEmpty(response, true)) { String header = rsp2.getString("header"); - String[] lines = StringUtil.split(StringUtil.getTrimedString(header), "\n"); + String[] lines = StringUtil.split(StringUtil.trim(header), "\n"); if (lines != null) { for (String line : lines) { @@ -1869,6 +1859,14 @@ protected String sendRequest(HttpSession session, HttpMethod method, String url, String rspBody = null; try { RestTemplate client = new RestTemplate(); + try { // 支持 PATCH 方法,需要 Maven 依赖 org.apache.httpcomponents.client5:httpclient5 + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + client.setRequestFactory(requestFactory); + } + catch (Throwable e) { + e.printStackTrace(); + } + HttpEntity requestEntity = new HttpEntity<>(method == HttpMethod.GET ? null : body, headers); ResponseEntity entity = client.exchange(url, method, requestEntity, String.class); @@ -1929,7 +1927,7 @@ private String parseRandomConfig(String path, Object obj) { Map m = (Map) obj; Set> s = m == null ? null : m.entrySet(); if (s != null) { - // TODO APIAuto 得先支持空 key config += "\n" + path + ": {}"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONArray + // TODO APIAuto 得先支持空 key config += "\n" + path + ": {}"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONList for (Entry e : s) { Object k = e == null ? null : e.getKey(); @@ -1947,7 +1945,7 @@ private String parseRandomConfig(String path, Object obj) { if (obj instanceof Collection) { Collection c = (Collection) obj; if (c != null) { - config += "\n" + path + ": []"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONObject + config += "\n" + path + ": []"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONMap int i = -1; for (Object v : c) { @@ -1962,7 +1960,7 @@ private String parseRandomConfig(String path, Object obj) { if (obj instanceof Array) { Array a = (Array) obj; if (a != null) { - config += "\n" + path + ": []"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONObject + config += "\n" + path + ": []"; // 避免默认 JSON 中这个数组为 null 导致后面生成的是 JSONMap int len = Array.getLength(a); for (int i = 0; i < len; i++) { @@ -1997,7 +1995,7 @@ private String parseRandomConfig(String path, Object obj) { public String execute(@RequestBody String request, HttpSession session) { try { if (Log.DEBUG == false) { - return DemoParser.newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许调用 /sql/execute !")).toJSONString(); + return JSON.toJSONString(newErrorResult(new IllegalAccessException("非 DEBUG 模式下不允许调用 /sql/execute !"))); } // DemoVerifier.verifyLogin(session); @@ -2137,7 +2135,7 @@ public String execute(@RequestBody String request, HttpSession session) { while (rs != null && rs.next()) { cursorDuration += System.currentTimeMillis() - cursorStartTime; - JSONObject obj = new JSONObject(true); + JSONObject obj = JSON.newJSONObject(); for (int i = 1; i <= length; i++) { long sqlStartTime = System.currentTimeMillis(); String name = rsmd.getColumnName(i); // rsmd.getColumnLable(i); @@ -2157,7 +2155,7 @@ public String execute(@RequestBody String request, HttpSession session) { // } } - JSONObject result = DemoParser.newSuccessResult(); + JSONObject result = newSuccessResult(); result.put("sql", sql); result.put("args", arg); if (isWrite) { @@ -2175,7 +2173,7 @@ public String execute(@RequestBody String request, HttpSession session) { return result.toJSONString(); } catch (Exception e) { - JSONObject result = DemoParser.newErrorResult(e); + JSONObject result = newErrorResult(e); result.put("throw", e.getClass().getName()); result.put("trace:stack", e.getStackTrace()); @@ -2186,7 +2184,7 @@ public String execute(@RequestBody String request, HttpSession session) { return result.toJSONString(); } } catch (Exception e) { - JSONObject result = DemoParser.newErrorResult(e); + JSONObject result = newErrorResult(e); result.put("throw", e.getClass().getName()); result.put("trace:stack", e.getStackTrace()); return result.toJSONString(); @@ -2661,15 +2659,15 @@ public String ui() { // 为 UnitAuto 提供的单元测试接口 https://github.com/TommyLemon/UnitAuto <<<<<<<<<<<<<<<<<<<<<<<<<<< - @PostMapping("method/list") - public JSONObject listMethod(@RequestBody String request) { - return super.listMethod(request); - } - - @PostMapping("method/invoke") - public void invokeMethod(@RequestBody String request, HttpServletRequest servletRequest) { - super.invokeMethod(request, servletRequest); - } + //@PostMapping("method/list") + //public JSONMap listMethod(@RequestBody String request) { + // return super.listMethod(request); + //} + // + //@PostMapping("method/invoke") + //public void invokeMethod(@RequestBody String request, HttpServletRequest servletRequest) { + // super.invokeMethod(request, servletRequest); + //} // 为 UnitAuto 提供的单元测试接口 https://github.com/TommyLemon/UnitAuto >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/FileController.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/FileController.java index 7687633..9894870 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/FileController.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/boot/FileController.java @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONObject; import apijson.demo.DemoParser; @@ -78,7 +78,7 @@ public void initFileRepository(){ public JSONObject files() { JSONObject res = new JSONObject(); res.put("data", fileRepository); - return DemoParser.extendSuccessResult(res); + return new DemoParser().extendSuccessResult(res); } @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -96,11 +96,11 @@ public JSONObject upload(@RequestParam("file") MultipartFile file) { JSONObject res = new JSONObject(); res.put("path", file.getOriginalFilename()); res.put("size", file.getBytes().length); - return DemoParser.extendSuccessResult(res); + return new DemoParser().extendSuccessResult(res); } catch (Exception e) { e.printStackTrace(); - return DemoParser.newErrorResult(e); + return new DemoParser().newErrorResult(e); } } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoFunctionParser.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoFunctionParser.java index 0f58395..b026215 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoFunctionParser.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoFunctionParser.java @@ -16,20 +16,20 @@ import java.util.*; +import apijson.NotNull; +import apijson.RequestMethod; +import apijson.StringUtil; +import apijson.fastjson2.JSON; +import apijson.fastjson2.JSONRequest; +import apijson.fastjson2.JSONResponse; import jakarta.servlet.http.HttpSession; import apijson.orm.script.JavaScriptExecutor; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; -import apijson.JSONResponse; -import apijson.NotNull; -import apijson.RequestMethod; -import apijson.StringUtil; -import apijson.framework.APIJSONFunctionParser; +import apijson.fastjson2.APIJSONFunctionParser; import apijson.orm.AbstractVerifier; -import apijson.orm.JSONRequest; import apijson.orm.Visitor; @@ -41,7 +41,7 @@ public class DemoFunctionParser extends APIJSONFunctionParser { public static final String TAG = "DemoFunctionParser"; static { - SCRIPT_EXECUTOR_MAP.put("js", new JavaScriptExecutor()); + SCRIPT_EXECUTOR_MAP.put("js", new JavaScriptExecutor()); } public DemoFunctionParser() { @@ -100,13 +100,6 @@ public void verifyIdList(@NotNull JSONObject curObj, @NotNull String idList) thr } } - @Override - public boolean isContain(JSONObject curObj, String array, String value) { - List list = apijson.JSON.parseArray(getArgStr(array), String.class); - Object val = getArgVal(value); - return list != null && list.contains(val == null ? null : String.valueOf(val)); - } - /** * @param curObj * @param urlList @@ -148,10 +141,10 @@ public int deleteCommentOfMoment(@NotNull JSONObject curObj, @NotNull String mom return 0; } - JSONRequest request = new JSONRequest(); + JSONObject request = JSON.newJSONObject(); //Comment<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - JSONRequest comment = new JSONRequest(); + JSONObject comment = JSON.newJSONObject(); comment.put("momentId", mid); request.put("Comment", comment); @@ -177,10 +170,10 @@ public int deleteChildComment(@NotNull JSONObject curObj, @NotNull String toId) //递归获取到全部子评论id - JSONRequest request = new JSONRequest(); + JSONObject request = JSON.newJSONObject(); //Comment<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - JSONRequest comment = new JSONRequest(); + JSONObject comment = JSON.newJSONObject();; comment.put("id{}", getChildCommentIdList(tid)); request.put("Comment", comment); @@ -196,7 +189,7 @@ public int deleteChildComment(@NotNull JSONObject curObj, @NotNull String toId) private JSONArray getChildCommentIdList(long tid) { JSONArray arr = new JSONArray(); - JSONRequest request = new JSONRequest(); + JSONObject request = JSON.newJSONObject(); //Comment-id[]<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< JSONRequest idItem = new JSONRequest(); @@ -205,10 +198,10 @@ private JSONArray getChildCommentIdList(long tid) { JSONRequest comment = new JSONRequest(); comment.put("toId", tid); comment.setColumn("id"); - idItem.put("Comment", comment); + idItem.put("Comment", JSON.newJSONObject(comment)); //Comment>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - request.putAll(idItem.toArray(0, 0, "Comment-id")); + request.putAll(JSON.newJSONObject(idItem.toArray(0, 0, "Comment-id"))); //Comment-id[]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> JSONObject rp = new DemoParser().setNeedVerify(false).parseResponse(request); @@ -217,10 +210,9 @@ private JSONArray getChildCommentIdList(long tid) { if (a != null) { arr.addAll(a); - JSONArray a2; for (int i = 0; i < a.size(); i++) { - a2 = getChildCommentIdList(a.getLongValue(i)); + JSONArray a2 = getChildCommentIdList(a.getLongValue(i)); if (a2 != null) { arr.addAll(a2); } @@ -233,8 +225,7 @@ private JSONArray getChildCommentIdList(long tid) { /**TODO 仅用来测试 "key-()":"getIdList()" 和 "key()":"getIdList()" * @param curObj - * @return JSONArray 只能用JSONArray,用long[]会在SQLConfig解析崩溃 - * @throws Exception + * @return JSONList 只能用JSONArray,用long[]会在SQLConfig解析崩溃 */ public JSONArray getIdList(@NotNull JSONObject curObj) { return new JSONArray(new ArrayList(Arrays.asList(12, 15, 301, 82001, 82002, 38710))); @@ -256,10 +247,10 @@ public Object verifyAccess(@NotNull JSONObject curObj) throws Exception { } // apijson-framework 5.4.0 以下取消注释,兼容 Function 表中 name = getMethodDefinition 的记录(或者删除这条记录,如果使用 UnitAuto,则版本要在 2.7.2 以下) - // public String getMethodDefinition(JSONObject request) throws IllegalArgumentException, ClassNotFoundException, IOException { + // public String getMethodDefinition(JSONMap request) throws IllegalArgumentException, ClassNotFoundException, IOException { // return super.getMethodDefination(request); // } - // public String getMethodDefinition(JSONObject request, String method, String arguments, String type, String exceptions, String language) throws IllegalArgumentException, ClassNotFoundException, IOException { + // public String getMethodDefinition(JSONMap request, String method, String arguments, String type, String exceptions, String language) throws IllegalArgumentException, ClassNotFoundException, IOException { // return super.getMethodDefination(request, method, arguments, type, exceptions, language); // } @@ -280,4 +271,5 @@ public void verifyGroupUrlLike(@NotNull JSONObject curObj, String urlLike) throw throw new IllegalArgumentException(urlLike + "必须以包含有效 URL 字符!"); } } + } \ No newline at end of file diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoObjectParser.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoObjectParser.java index b4ef70f..960cfba 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoObjectParser.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoObjectParser.java @@ -14,7 +14,8 @@ package apijson.demo; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import java.util.List; @@ -22,7 +23,7 @@ import apijson.NotNull; import apijson.RequestMethod; -import apijson.framework.APIJSONObjectParser; +import apijson.fastjson2.APIJSONObjectParser; import apijson.orm.Join; import apijson.orm.SQLConfig; @@ -32,13 +33,15 @@ */ public class DemoObjectParser extends APIJSONObjectParser { - public DemoObjectParser(HttpSession session, @NotNull JSONObject request, String parentPath, SQLConfig arrayConfig + public DemoObjectParser(HttpSession session, @NotNull JSONObject request, String parentPath + , SQLConfig arrayConfig , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { super(session, request, parentPath, arrayConfig, isSubquery, isTable, isArrayMainTable); } @Override - public SQLConfig newSQLConfig(RequestMethod method, String table, String alias, JSONObject request, List joinList, boolean isProcedure) throws Exception { + public SQLConfig newSQLConfig(RequestMethod method, String table, String alias + , JSONObject request, List> joinList, boolean isProcedure) throws Exception { return DemoSQLConfig.newSQLConfig(method, table, alias, request, joinList, isProcedure); } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoParser.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoParser.java index c0a3e34..3cfd27e 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoParser.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoParser.java @@ -14,7 +14,9 @@ package apijson.demo; -import com.alibaba.fastjson.JSONObject; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import java.util.HashMap; import java.util.Map; @@ -25,10 +27,8 @@ import apijson.StringUtil; import apijson.boot.DemoController; import apijson.demo.model.Privacy; -import apijson.demo.model.User; -import apijson.framework.APIJSONObjectParser; -import apijson.framework.APIJSONParser; -import apijson.framework.APIJSONVerifier; +import apijson.fastjson2.APIJSONObjectParser; +import apijson.fastjson2.APIJSONParser; import apijson.orm.SQLConfig; @@ -53,34 +53,40 @@ public DemoParser(RequestMethod method, boolean needVerify) { super(method, needVerify); } -// // 可重写来设置分页页码是否从 1 开始,true - 从 1 开始;false - 从 0 开始 + + @Override + public DemoParser setNeedVerify(boolean needVerify) { + super.setNeedVerify(needVerify); + return this; + } + + // // 可重写来设置分页页码是否从 1 开始,true - 从 1 开始;false - 从 0 开始 // @Override // public boolean isStartFrom1() { // return true; // } private int maxQueryCount = 2000; -// // 可重写来设置最大查询数量 -// @Override -// public int getMaxQueryCount() { -// return maxQueryCount; -// } -// -// @Override -// public int getMaxUpdateCount() { -// return 2000; -// } -// -// @Override -// public int getMaxObjectCount() { -// return getMaxUpdateCount(); -// } -// -// @Override -// public int getMaxSQLCount() { -// return getMaxUpdateCount(); -// } + // 可重写来设置最大查询数量 + @Override + public int getMaxQueryCount() { + return maxQueryCount; + } + + @Override + public int getMaxUpdateCount() { + return 2000; + } + @Override + public int getMaxObjectCount() { + return getMaxUpdateCount(); + } + + @Override + public int getMaxSQLCount() { + return getMaxUpdateCount(); + } @Override public JSONObject parseResponse(JSONObject request) { @@ -96,8 +102,10 @@ public JSONObject parseResponse(JSONObject request) { return super.parseResponse(request); } + @Override - public APIJSONObjectParser createObjectParser(JSONObject request, String parentPath, SQLConfig arrayConfig + public APIJSONObjectParser createObjectParser(JSONObject request, String parentPath + , SQLConfig arrayConfig , boolean isSubquery, boolean isTable, boolean isArrayMainTable) throws Exception { return new DemoObjectParser(getSession(), request, parentPath, arrayConfig , isSubquery, isTable, isArrayMainTable).setMethod(getMethod()).setParser(this); @@ -109,12 +117,12 @@ public APIJSONObjectParser createObjectParser(JSONObject request, String p private String dbPassword; @Override public APIJSONParser setSession(HttpSession session) { - Boolean asDBAccount = (Boolean) session.getAttribute(DemoController.AS_DB_ACCOUNT); + Boolean asDBAccount = session == null ? null : (Boolean) session.getAttribute(DemoController.AS_DB_ACCOUNT); this.asDBAccount = asDBAccount != null && asDBAccount; if (this.asDBAccount) { // User user = (User) session.getAttribute(DemoController.USER_); // this.dbAccount = user.getName(); - Privacy privacy = (Privacy) session.getAttribute(DemoController.PRIVACY_); + Privacy privacy = session == null ? null : (Privacy) session.getAttribute(DemoController.PRIVACY_); this.dbAccount = privacy.getPhone(); this.dbPassword = privacy.get__password(); } @@ -123,13 +131,13 @@ public APIJSONParser setSession(HttpSession session) { } @Override - public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception { + public JSONObject executeSQL(SQLConfig config, boolean isSubquery) throws Exception { if (asDBAccount && config instanceof DemoSQLConfig) { DemoSQLConfig cfg = (DemoSQLConfig) config; - if (StringUtil.isEmpty(cfg.getDBAccount())) { + if (StringUtil.isEmpty(cfg.gainDBAccount())) { cfg.setDBAccount(dbAccount); } - if (StringUtil.isEmpty(cfg.getDBPassword())) { + if (StringUtil.isEmpty(cfg.gainDBPassword())) { cfg.setDBPassword(dbPassword); } } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLConfig.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLConfig.java index 82918ad..ad09e0e 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLConfig.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLConfig.java @@ -22,17 +22,20 @@ import java.text.SimpleDateFormat; import java.util.*; -import apijson.*; //import apijson.influxdb.InfluxDBUtil; //import apijson.iotdb.IoTDBUtil; +import apijson.RequestMethod; +import apijson.StringUtil; import apijson.orm.AbstractParser; import apijson.orm.AbstractSQLConfig; import apijson.orm.Parser; //import apijson.surrealdb.SurrealDBUtil; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson.annotation.JSONField; -import apijson.column.ColumnUtil; -import apijson.framework.APIJSONSQLConfig; +import apijson.framework.ColumnUtil; +import apijson.fastjson2.APIJSONSQLConfig; import apijson.orm.Join; import apijson.orm.Join.On; //import org.influxdb.InfluxDB; @@ -55,8 +58,9 @@ public DemoSQLConfig(RequestMethod method, String table) { static { DEFAULT_DATABASE = DATABASE_MYSQL; //TODO 默认数据库类型,改成你自己的。TiDB, MariaDB, OceanBase 这类兼容 MySQL 的可当做 MySQL 使用 - // DEFAULT_NAMESPACE = "root"; //TODO 默认数据库名/模式,改成你自己的,仅对 PostgreSQL: posgres, SurrealDB: root 等数据库有效 - DEFAULT_SCHEMA = "sys"; // "apijson"; //TODO 默认数据库名/模式,改成你自己的,默认情况是 MySQL: sys, PostgreSQL: sys, SQL Server: dbo, Oracle: + // DEFAULT_NAMESPACE = "root"; //TODO 默认数据库名/模式,改成你自己的,仅对 SurrealDB: root 等数据库有效 + // DEFAULT_CATALOG = "postgres"; //TODO 默认数据库名/模式,改成你自己的,仅对 PostgreSQL: posgres 等数据库有效 + DEFAULT_SCHEMA = "sys"; // "apijson"; //TODO 默认数据库名/模式,改成你自己的,默认情况是 MySQL: sys, PostgreSQL: sys, SQL Server: dbo, Manticore: Manticore, Oracle: // 表名和数据库不一致的,需要配置映射关系。只使用 APIJSONORM 时才需要; // 这个 Demo 用了 apijson-framework 且调用了 APIJSONApplication.init 则不需要 @@ -72,7 +76,8 @@ public DemoSQLConfig(RequestMethod method, String table) { SIMPLE_CALLBACK = new SimpleCallback() { @Override - public AbstractSQLConfig getSQLConfig(RequestMethod method, String database, String schema, String datasource, String table) { + public AbstractSQLConfig getSQLConfig( + RequestMethod method, String database, String schema, String datasource, String table) { return new DemoSQLConfig(method, table); } @@ -97,7 +102,7 @@ public String getUserIdKey(String database, String schema, String datasource, St // } // @Override - // public void onMissingKey4Combine(String name, JSONObject request, String combine, String item, String key) throws Exception { + // public void onMissingKey4Combine(String name, JSONMap request, String combine, String item, String key) throws Exception { //// super.onMissingKey4Combine(name, request, combine, item, key); // } }; @@ -140,13 +145,39 @@ public String getUserIdKey(String database, String schema, String datasource, St RAW_MAP.put("(CASE WHEN package LIKE '*%' THEN substr(package,2) ELSE package END) `url`", ""); // UnitAuto 获取分组 RAW_MAP.put("(CASE WHEN package LIKE '*%' THEN substr(package,2) ELSE package END) `groupUrl`", ""); // UnitAuto 获取分组 RAW_MAP.put("(CASE WHEN package LIKE '*%' THEN substr(package,2) ELSE package END):groupUrl", "(CASE WHEN package LIKE '*%' THEN substr(package,2) ELSE package END) `groupUrl`"); // UnitAuto 获取分组 + + // 反选字段配置 + Map> tableColumnMap = new HashMap<>(); + tableColumnMap.put("User", Arrays.asList(StringUtil.split("id,sex,name,tag,head,contactIdList,pictureList,date"))); + // 需要对应方法传参也是这样拼接才行,例如 ColumnUtil.compatInputColumn(column, getSQLDatabase() + "-" + getSQLSchema() + "-" + getTable(), getMethod()); + tableColumnMap.put("MYSQL-sys-Privacy", Arrays.asList(StringUtil.split("id,certified,phone,balance,_password,_payPassword"))); + ColumnUtil.VERSIONED_TABLE_COLUMN_MAP.put(null, tableColumnMap); + + // 字段名映射配置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + Map> tableKeyColumnMap = new HashMap<>(); + + Map userKeyColumnMap = new HashMap<>(); + userKeyColumnMap.put("gender", "sex"); + userKeyColumnMap.put("createTime", "date"); + tableKeyColumnMap.put("User", userKeyColumnMap); + + Map privacyKeyColumnMap = new HashMap<>(); + privacyKeyColumnMap.put("rest", "balance"); + // 需要对应方法传参也是这样拼接才行,例如 ColumnUtil.compatInputKey(super.getKey(key), getSQLDatabase() + "-" + getSQLSchema() + "-" + getTable(), getMethod()); + tableKeyColumnMap.put("MYSQL-sys-Privacy", privacyKeyColumnMap); + + ColumnUtil.VERSIONED_KEY_COLUMN_MAP.put(null, tableKeyColumnMap); + // 字段名映射配置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + ColumnUtil.init(); + } // 如果 DemoSQLExecutor.getConnection 能拿到连接池的有效 Connection,则这里不需要配置 dbVersion, dbUri, dbAccount, dbPassword @Override - public String getDBVersion() { + public String gainDBVersion() { if (isMySQL()) { // return "5.7.22"; // return "8.0.11"; //TODO 改成你自己的 MySQL 或 PostgreSQL 数据库版本号 //MYSQL 8 和 7 使用的 JDBC 配置不一样 @@ -163,9 +194,9 @@ public String getDBVersion() { if (isDb2()) { return "11.5"; //TODO 改成你自己的 } - // if (isSQLite()) { - // return "3.39.3"; //TODO 改成你自己的 - // } + // if (isSQLite()) { + // return "3.39.3"; //TODO 改成你自己的 + // } if (isDameng()) { return "8.1.2.141"; //TODO 改成你自己的 } @@ -190,6 +221,9 @@ public String getDBVersion() { // if (isSurrealDB()) { // return "2.0.0"; //TODO 改成你自己的 // } + // if (isOpenGauss()) { + // return "5.0.0"; //TODO 改成你自己的 + // } return null; } @@ -199,22 +233,25 @@ public DemoSQLConfig setDBUri(String dbUri) { this.dbUri = dbUri; return this; } - @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 @Override - public String getDBUri() { + public String gainDBUri() { if (StringUtil.isNotEmpty(dbUri)) { return dbUri; } if (isMySQL()) { // 这个是 MySQL 8.0 及以上,要加 userSSL=false -// return "jdbc:mysql://47.122.25.116:3306?userSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8"; + // return "jdbc:mysql://47.122.25.116:3306?userSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8"; // 以下是 MySQL 5.7 及以下 return "jdbc:mysql://localhost:3306?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8"; //TODO 改成你自己的,TiDB 可以当成 MySQL 使用,默认端口为 4000 } - if (isPostgreSQL()) { + if (isPostgreSQL()) { // PG JDBC 必须在 URI 传 catalog return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 } + //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog + // return "jdbc:postgresql://localhost:26257/movr?sslmode=require"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach && cockroach demo + // // return "jdbc:postgresql://localhost:26258/postgres?sslmode=disable"; //TODO 改成你自己的 brew install cockroachdb/tap/cockroach # && start 3 nodes and init cluster + //} if (isSQLServer()) { return "jdbc:jtds:sqlserver://localhost:1433/pubs;instance=SQLEXPRESS"; //TODO 改成你自己的 } @@ -224,9 +261,9 @@ public String getDBUri() { if (isDb2()) { return "jdbc:db2://localhost:50000/BLUDB"; //TODO 改成你自己的 } - //if (isSQLite()) { - // return "jdbc:sqlite:sample.db"; //TODO 改成你自己的 - //} + // if (isSQLite()) { + // return "jdbc:sqlite:sample.db"; //TODO 改成你自己的 + // } if (isDameng()) { return "jdbc:dm://localhost:5236"; //TODO 改成你自己的 } @@ -234,31 +271,46 @@ public String getDBUri() { // return "jdbc:TAOS://localhost:6030"; //TODO 改成你自己的 return "jdbc:TAOS-RS://localhost:6041"; //TODO 改成你自己的 } + if (isTimescaleDB()) { // PG JDBC 必须在 URI 传 catalog + return "jdbc:postgresql://localhost:5432/postgres?stringtype=unspecified"; //TODO 改成你自己的 + } + if (isQuestDB()) { // PG JDBC 必须在 URI 传 catalog + return "jdbc:postgresql://localhost:8812/qdb"; //TODO 改成你自己的 + } if (isInfluxDB()) { return "http://203.189.6.3:8086"; //TODO 改成你自己的 } if (isMilvus()) { return "http://localhost:19530"; //TODO 改成你自己的 } - // if (isIoTDB()) { - // return "jdbc:iotdb://localhost:6667"; // ?charset=GB18030 加参数会报错 URI 格式错误 //TODO 改成你自己的 - // } + //if (isManticore()) { + // return "jdbc:mysql://localhost:9306?characterEncoding=utf8&maxAllowedPacket=512000"; //TODO 改成你自己的 + //} + //if (isIoTDB()) { + // return "jdbc:iotdb://localhost:6667"; // ?charset=GB18030 加参数会报错 URI 格式错误 //TODO 改成你自己的 + //} if (isMongoDB()) { return "jdbc:mongodb://atlas-sql-6593c65c296c5865121e6ebe-xxskv.a.query.mongodb.net/myVirtualDatabase?ssl=true&authSource=admin"; //TODO 改成你自己的 } if (isCassandra()) { return "http://localhost:7001"; //TODO 改成你自己的 } - // if (isDuckDB()) { - // return "jdbc:duckdb:/Users/tommylemon/my_database.duckdb"; //TODO 改成你自己的 - // } - // if (isSurrealDB()) { - // // return "memory"; //TODO 改成你自己的 - // // return "surrealkv://localhost:8000"; //TODO 改成你自己的 - // return "ws://localhost:8000"; //TODO 改成你自己的 - // } - - return null; + //if (isDuckDB()) { + // return "jdbc:duckdb:/Users/tommylemon/my_database.duckdb"; //TODO 改成你自己的 + //} + //if (isSurrealDB()) { + // // return "memory"; //TODO 改成你自己的 + // // return "surrealkv://localhost:8000"; //TODO 改成你自己的 + // return "ws://localhost:8000"; //TODO 改成你自己的 + //} + //if (isOpenGauss()) { + // return "jdbc:opengauss://127.0.0.1:5432/postgres?currentSchema=" + DEFAULT_SCHEMA; //TODO 改成你自己的 + //} + //if (isDoris()) { + // return "jdbc:mysql://localhost:9030"; //TODO 改成你自己的,TiDB 可以当成 MySQL 使用,默认端口为 4000 + //} + + return super.gainDBUri(); } private String dbAccount; @@ -266,9 +318,8 @@ public DemoSQLConfig setDBAccount(String dbAccount) { this.dbAccount = dbAccount; return this; } - @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 @Override - public String getDBAccount() { + public String gainDBAccount() { if (StringUtil.isNotEmpty(dbAccount)) { return dbAccount; } @@ -279,6 +330,10 @@ public String getDBAccount() { if (isPostgreSQL()) { return "postgres"; //TODO 改成你自己的 } + //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog + // return "demo"; //TODO 改成你自己的 + // //return "postgres"; //TODO 改成你自己的 + //} if (isSQLServer()) { return "sa"; //TODO 改成你自己的 } @@ -288,38 +343,54 @@ public String getDBAccount() { if (isDb2()) { return "db2admin"; //TODO 改成你自己的 } - //if (isSQLite()) { - // return "root"; //TODO 改成你自己的 - //} + // if (isSQLite()) { + // return "root"; //TODO 改成你自己的 + // } if (isDameng()) { return "SYSDBA"; } if (isTDengine()) { return "root"; //TODO 改成你自己的 } + //if (isTimescaleDB()) { + // return "postgres"; //TODO 改成你自己的 + //} + if (isQuestDB()) { + return "admin"; //TODO 改成你自己的 + } if (isInfluxDB()) { return "iotos"; } if (isMilvus()) { return "root"; } - // if (isIoTDB()) { - // return "root"; - // } + //if (isManticore()) { + // return null; // "root"; + //} + //if (isIoTDB()) { + // return "root"; + //} if (isMongoDB()) { return "root"; //TODO 改成你自己的 } if (isCassandra()) { return "root"; //TODO 改成你自己的 } - // if (isDuckDB()) { - // return "root"; //TODO 改成你自己的 - // } - // if (isSurrealDB()) { - // return "root"; //TODO 改成你自己的 - // } - - return null; + //if (isDuckDB()) { + // return "root"; //TODO 改成你自己的 + //} + //if (isSurrealDB()) { + // return "root"; //TODO 改成你自己的 + //} + //if (isOpenGauss()) { + // return "postgres"; //TODO 改成你自己的 + // // 不允许用初始账号,需要 CREATE USER 创建新账号并 GRANT 授权 return "opengauss"; //TODO 改成你自己的 + //} + //if (isDoris()) { + // return "root"; + //} + + return super.gainDBAccount(); } private String dbPassword; @@ -327,9 +398,8 @@ public DemoSQLConfig setDBPassword(String dbPassword) { this.dbPassword = dbPassword; return this; } - @JSONField(serialize = false) // 不在日志打印 账号/密码 等敏感信息,用了 UnitAuto 则一定要加 @Override - public String getDBPassword() { + public String gainDBPassword() { if (StringUtil.isNotEmpty(dbPassword)) { return dbPassword; } @@ -340,6 +410,10 @@ public String getDBPassword() { if (isPostgreSQL()) { return null; //TODO 改成你自己的 } + //if (isCockroachDB()) { // PG JDBC 必须在 URI 传 catalog + // return "demo39865"; //TODO 改成你自己的 + // // return null; //TODO 改成你自己的 + //} if (isSQLServer()) { return "apijson@123"; //TODO 改成你自己的 } @@ -349,50 +423,65 @@ public String getDBPassword() { if (isDb2()) { return "123"; //TODO 改成你自己的 } - // if (isSQLite()) { - // return "apijson"; //TODO 改成你自己的 - // } + // if (isSQLite()) { + // return "apijson"; //TODO 改成你自己的 + // } if (isDameng()) { return "SYSDBA"; } if (isTDengine()) { return "taosdata"; //TODO 改成你自己的 } + if (isTimescaleDB()) { + return "password"; //TODO 改成你自己的 + } + if (isQuestDB()) { + return "quest"; //TODO 改成你自己的 + } if (isInfluxDB()) { return "apijson@123"; //TODO 改成你自己的 } if (isMilvus()) { return "apijson"; //TODO 改成你自己的 } - // if (isIoTDB()) { - // return "root"; - // } + //if (isManticore()) { + // return null; + //} + //if (isIoTDB()) { + // return "root"; + //} if (isMongoDB()) { return "apijson"; //TODO 改成你自己的 } if (isCassandra()) { return "apijson"; //TODO 改成你自己的 } - // if (isDuckDB()) { - // return ""; //TODO 改成你自己的 - // } - // if (isSurrealDB()) { - // return "root"; //TODO 改成你自己的 - // } - - return null; + //if (isDuckDB()) { + // return ""; //TODO 改成你自己的 + //} + //if (isSurrealDB()) { + // return "root"; //TODO 改成你自己的 + //} + //if (isOpenGauss()) { + // return "openGauss@123"; //TODO 改成你自己的 + //} + //if (isDoris()) { + // return "apijson"; + //} + + return super.gainDBPassword(); } private String sql; - public String getSQL() throws Exception { - return getSQL(isPrepared()); + public String gainSQL() throws Exception { + return gainSQL(isPrepared()); } @Override - public String getSQL(boolean prepared) throws Exception { + public String gainSQL(boolean prepared) throws Exception { if (StringUtil.isNotEmpty(sql)) { return sql; } - return super.getSQL(prepared); + return super.gainSQL(prepared); } public void setSql(String sql) { @@ -464,15 +553,15 @@ public void setSql(String sql) { @Override - protected void onGetCrossJoinString(Join join) throws UnsupportedOperationException { + protected void onGainCrossJoinString(Join join) throws UnsupportedOperationException { // 开启 CROSS JOIN 笛卡尔积联表 super.onGetCrossJoinString(join); } @Override - protected void onJoinNotRelation(String sql, String quote, Join join, String table, List onList, On on) { + protected void onJoinNotRelation(String sql, String quote, Join join, String table, List onList, On on) { // 开启 JOIN ON t1.c1 != t2.c2 等不等式关联 super.onJoinNotRelation(sql, quote, join, table, onList, on); } @Override - protected void onJoinComplexRelation(String sql, String quote, Join join, String table, List onList, On on) { + protected void onJoinComplexRelation(String sql, String quote, Join join, String table, List onList, On on) { // 开启 JOIN ON t1.c1 LIKE concat('%', t2.c2, '%') 等复杂关联 super.onJoinComplexRelation(sql, quote, join, table, onList, on); } @@ -501,15 +590,17 @@ protected int getMaxCombineCount() { // // @Override // public String getSQLSchema() { - // return SurrealDBUtil.getSQLSchema(super.getSQLSchema(), isSurrealDB()); + // return isOpenGauss() ? "public" : super.getSQLSchema(); + // // return SurrealDBUtil.getSQLSchema(super.getSQLSchema(), isSurrealDB()); //// return InfluxDBUtil.getSQLSchema(super.getSQLSchema(), isIoTDB()); //// return IoTDBUtil.getSQLSchema(super.getSQLSchema().replaceAll("-", "."), isIoTDB()); // } @Override - public String getSQLTable() { - String t = super.getSQLTable(); + public String gainSQLTable() { + String t = super.gainSQLTable(); return isInfluxDB() ? t.toLowerCase() : t; + //return isInfluxDB() || isManticore() ? t.toLowerCase() : t; // return isInfluxDB() || isIoTDB() ? t.toLowerCase() : t; // return isInfluxDB() ? t.toLowerCase() : StringUtil.firstCase(JSONRequest.recoverUnderline(t, false), false); } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java index afd939f..3fcd765 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoSQLExecutor.java @@ -17,7 +17,7 @@ import apijson.*; import apijson.boot.DemoApplication; //import apijson.cassandra.CassandraUtil; -import apijson.framework.APIJSONSQLExecutor; +import apijson.fastjson2.APIJSONSQLExecutor; //import apijson.influxdb.InfluxDBUtil; //import apijson.milvus.MilvusUtil; //import apijson.mongodb.MongoUtil; @@ -25,7 +25,8 @@ import apijson.orm.SQLConfig; //import apijson.surrealdb.SurrealDBUtil; import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.JSONArray; //import org.duckdb.JsonNode; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; @@ -67,7 +68,7 @@ public class DemoSQLExecutor extends APIJSONSQLExecutor { REDIS_TEMPLATE.setKeySerializer(new StringRedisSerializer()); REDIS_TEMPLATE.setHashValueSerializer(new GenericToStringSerializer<>(Serializable.class)); REDIS_TEMPLATE.setValueSerializer(new GenericToStringSerializer<>(Serializable.class)); - // REDIS_TEMPLATE.setValueSerializer(new FastJsonRedisSerializer>(List.class)); + // REDIS_TEMPLATE.setValueSerializer(new FastJsonRedisSerializer>(List.class)); REDIS_TEMPLATE.afterPropertiesSet(); } catch (Throwable e) { e.printStackTrace(); @@ -76,7 +77,7 @@ public class DemoSQLExecutor extends APIJSONSQLExecutor { // 可重写以下方法,支持 Redis 等单机全局缓存或分布式缓存 @Override - public List getCache(String sql, SQLConfig config) { + public List getCache(String sql, SQLConfig config) { List list = super.getCache(sql, config); if (list == null) { try { @@ -89,7 +90,7 @@ public List getCache(String sql, SQLConfig config) { } @Override - public synchronized void putCache(String sql, List list, SQLConfig config) { + public synchronized void putCache(String sql, List list, SQLConfig config) { super.putCache(sql, list, config); String table = config != null && config.isMain() ? config.getTable() : null; @@ -107,7 +108,7 @@ public synchronized void putCache(String sql, List list, SQLConfig config) { + public synchronized void removeCache(String sql, SQLConfig config) { super.removeCache(sql, config); try { if (config.getMethod() == RequestMethod.DELETE) { // 避免缓存击穿 @@ -123,14 +124,14 @@ public synchronized void removeCache(String sql, SQLConfig config) { // Redis 缓存 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - // 适配连接池,如果这里能拿到连接池的有效 Connection,则 SQLConfig 不需要配置 dbVersion, dbUri, dbAccount, dbPassword + // 适配连接池,如果这里能拿到连接池的有效 Connection,则 SQLConfig 不需要配置 dbVersion, dbUri, dbAccount, dbPassword @Override - public Connection getConnection(SQLConfig config) throws Exception { + public Connection getConnection(SQLConfig config) throws Exception { String datasource = config.getDatasource(); Log.d(TAG, "getConnection config.getDatasource() = " + datasource); String key = datasource + "-" + config.getDatabase(); - Connection c = connectionMap.get(key); + Connection c = getConnection(key); if (datasource != null && (c == null || c.isClosed())) { try { DataSource ds; @@ -159,7 +160,7 @@ public Connection getConnection(SQLConfig config) throws Exception { break; } - connectionMap.put(key, ds == null ? null : ds.getConnection()); + putConnection(key, ds == null ? null : ds.getConnection()); } catch (Exception e) { Log.e(TAG, "getConnection try { " + "DataSource ds = DemoApplication.getApplicationContext().getBean(DataSource.class); .." @@ -173,7 +174,7 @@ public Connection getConnection(SQLConfig config) throws Exception { } @Override - public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception { + public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) throws Exception { boolean isMilvus = config.isMilvus(); // DATABASE_MILVUS.equals(config.getDatabase()); // APIJSON 6.4.0+ 可用 config.isMilvus(); boolean isCassandra = config.isCassandra(); // DemoSQLConfig.DATABASE_CASSANDRA.equals(config.getDatabase()); boolean isInfluxDB = config.isInfluxDB(); // DemoSQLConfig.DATABASE_INFLUXDB.equals(config.getDatabase()); @@ -182,7 +183,7 @@ public JSONObject execute(@NotNull SQLConfig config, boolean unknownType) if (isMilvus || isCassandra || isInfluxDB) { // || isIoTDB || isSurrealDB) { // TODO 把 execute 内与缓存无关只与数据库读写逻辑相关的代码抽取到 executeSQL 函数 - String sql = config.getSQL(false); // config.isPrepared()); + String sql = config.gainSQL(false); // config.isPrepared()); if (sql != null && config.getMethod() == null) { String trimmedSQL = sql.trim(); String sqlPrefix = trimmedSQL.length() < 7 ? "" : trimmedSQL.substring(0, 7).toUpperCase(); @@ -273,14 +274,14 @@ public void close() { // 不需要隐藏字段这个功能时,取消注释来提升性能 // @Override - // protected boolean isHideColumn(SQLConfig config, java.sql.ResultSet rs, ResultSetMetaData rsmd, int tablePosition, - // JSONObject table, int columnIndex, Map childMap) throws SQLException { + // protected boolean isHideColumn(SQLConfig config, java.sql.ResultSet rs, ResultSetMetaData rsmd, int tablePosition, + // JSONMap table, int columnIndex, Map childMap) throws SQLException { // return false; // } // 取消注释可将前端传参驼峰命名转为蛇形命名 aBCdEfg => upper ? A_B_CD_EFG : a_b_cd_efg // @Override - // protected String getKey(SQLConfig config, java.sql.ResultSet rs, ResultSetMetaData rsmd, int tablePosition, JSONObject table, int columnIndex, Map childMap) throws Exception { + // protected String getKey(SQLConfig config, java.sql.ResultSet rs, ResultSetMetaData rsmd, int tablePosition, JSONMap table, int columnIndex, Map childMap) throws Exception { // String key = super.getKey(config, rs, rsmd, tablePosition, table, columnIndex, childMap); // String tbl = StringUtil.firstCase(JSONResponse.formatUnderline(rsmd.getTableName(columnIndex), true), true); // if (DemoVerifier.SYSTEM_ACCESS_MAP.containsKey(tbl)) { @@ -290,13 +291,15 @@ public void close() { // } -// @Override -// protected Object getValue(SQLConfig config, ResultSet rs, ResultSetMetaData rsmd, int tablePosition, JSONObject table, int columnIndex, String lable, Map childMap) throws Exception { -// Object v = super.getValue(config, rs, rsmd, tablePosition, table, columnIndex, lable, childMap); -//// if (v instanceof JsonNode) { // DuckDB json 类型需要转换 -//// JsonNode jn = (JsonNode) v; -//// v = jn.isNull() ? null : JSON.parse(jn.toString()); -//// } -// return v; // MongoUtil.getValue(v); -// } + @Override + protected Object getValue( + SQLConfig config, ResultSet rs, ResultSetMetaData rsmd, int row, JSONObject table, int columnIndex + , String label, Map childMap, Map keyMap) throws Exception { + Object v = super.getValue(config, rs, rsmd, row, table, columnIndex, label, childMap, keyMap); +// if (v instanceof JsonNode) { // DuckDB json 类型需要转换 +// JsonNode jn = (JsonNode) v; +// v = jn.isNull() ? null : parseJSON(jn.toString()); +// } + return v; // MongoUtil.getValue(v); + } } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoVerifier.java b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoVerifier.java index afc3a7b..60d3fbf 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoVerifier.java +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/java/apijson/demo/DemoVerifier.java @@ -14,7 +14,7 @@ package apijson.demo; -import apijson.router.APIJSONRouterVerifier; +import apijson.fastjson2.APIJSONVerifier; import java.util.regex.Pattern; @@ -23,7 +23,7 @@ * 具体见 https://github.com/Tencent/APIJSON/issues/12 * @author Lemon */ -public class DemoVerifier extends APIJSONRouterVerifier { // APIJSONVerifier { +public class DemoVerifier extends APIJSONVerifier { public static final String TAG = "DemoVerifier"; static { @@ -39,7 +39,7 @@ public class DemoVerifier extends APIJSONRouterVerifier { // APIJSONVerif // 重写方法来自定义字段名等 // @Override - // public String getVisitorIdKey(SQLConfig config) { + // public String getVisitorIdKey(SQLConfig config) { // return super.getVisitorIdKey(config); // return "userid"; // return "uid" 等自定义的字段名 // } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/README.md b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/README.md index 530f2d6..1523203 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/README.md +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/README.md @@ -16,13 +16,14 @@ --- 敏捷开发最强大易用的 HTTP 接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释。
-集 文档、测试、Mock、调试、管理 于一体的一站式体验,还有一键 格式化、注释/取消注释 等高效易用的快捷键。
+集合 文档、测试、Mock、调试、管理 的一站式体验,还有 **AI 问答** 和一键 格式化、注释/取消注释 等高效快捷键。
在常用功能上远超 Postman, Swagger, YApi 等各种 开源、商业 的 API 文档/测试 工具,并能一键导入用例和文档。
支持 GET, POST, PUT, PATCH, DELETE, HEAD 等各种 HTTP Method 及 Content-Type, URL /{Path}/{Variable}。
不仅适用于 RESTful、类 RESTful、GRPC 的 API,还是腾讯 [APIJSON](https://github.com/Tencent/APIJSON) 官方建议的文档与测试工具。
腾讯内部用户包括 IEG 互动娱乐事业群、TEG 技术工程事业群、CSIG 云与智慧事业群 的多个部门及团队,
外部用户包含 华为、工商银行某地分行、500 强上市公司传音、跨境电商巨头 SHEIN、行业领头羊社保科技 等。 +![image](https://github.com/user-attachments/assets/24460af3-0001-46e7-aa2a-df28b711a8cf) ![](https://user-images.githubusercontent.com/5738175/145665502-94231804-5ea8-4784-b30d-d5558aad0f8d.jpeg)

@@ -115,7 +116,9 @@ Bilibili:https://search.bilibili.com/all?keyword=APIAuto ### 相关推荐 -[别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg) +[别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg)
+[APIAuto: 最先进的HTTP接口工具](https://blog.csdn.net/Nifc666/article/details/141966487) + ### 百度、搜狗、抖音公网接口调用演示
因为这些接口不支持 CORS 跨域,所以需要开启托管服务代理。
@@ -252,6 +255,24 @@ https://github.com/TommyLemon/APIAuto/issues
+### Roadmap 路线图 +1.Translate document to English/Italian/Franch/Spanish...
+ +2.新增功能
+1) 断言结果 新增按钮 变-\{原因},点击后右侧展示 JSON diff view;
+2) 右下角列表展示具体每个断言有问题的字段,点击后 JSON view 只显示该字段对应值
+其他待补充...
+
+3.完善自动断言,支持更多格式的匹配
+
+4.解决 bug
+
+5.提升性能
+
+6.其他待补充...
+ +
+ ### 感谢开源 * jsonon * editor.md diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/CodeUtil.js b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/CodeUtil.js index 8a66958..3190bab 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/CodeUtil.js +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/CodeUtil.js @@ -266,7 +266,7 @@ var CodeUtil = { } else { try { - value = JSON.parse(value) + value = parseJSON(value) } catch (e) { console.log(e) @@ -1846,7 +1846,7 @@ var CodeUtil = { return CodeUtil.parseCode(name, resObj, { onParseParentStart: function () { - return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ' = JSON.parse(resultJson) \n'; + return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ' = parseJSON(resultJson) \n'; }, onParseParentEnd: function () { @@ -2695,7 +2695,7 @@ res_data = rep.json() else if (format instanceof Array == false && format instanceof Object) { s += prefix2 + varName + '_json = json.loads(' + varName + ')' try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var cs = CodeUtil.parsePythonResponseByStandard(varName + '_json', key, format, realObj, depth, isSmart, true, funDefs, funNames); if (StringUtil.isNotEmpty(cs, true)) { s += '\n' + padding + cs.trim(); @@ -2759,7 +2759,7 @@ res_data = rep.json() return CodeUtil.parseCode(name, resObj, { onParseParentStart: function () { - return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ': object = JSON.parse(resultJson); \n'; + return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ': object = parseJSON(resultJson); \n'; }, onParseParentEnd: function () { @@ -6783,7 +6783,7 @@ res_data = rep.json() var typeOfValue = CodeUtil.getType4Request(value); var isValueNotArray = typeOfValue != 'array'; var isValueNotObject = typeOfValue != 'object'; - + if (standardObj != null) { var parentObj = pathKeys == null || pathKeys.length <= 0 ? null : JSONResponse.getStandardByPath(standardObj, pathKeys.slice(0, pathKeys.length - 1)); var targetValues = parentObj == null ? null : parentObj.values; @@ -7294,7 +7294,7 @@ res_data = rep.json() }, getType4Request: function (value) { - // return t != 'string' ? t : typeof JSON.parse(value); + // return t != 'string' ? t : typeof parseJSON(value); if (value instanceof Array) { return 'array' } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONRequest.js b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONRequest.js index 20b97ba..927403f 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONRequest.js +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONRequest.js @@ -215,7 +215,7 @@ function format(json) { } try { - return JSON.stringify(JSON.parse(json), null, "\t"); + return JSON.stringify(parseJSON(json), null, "\t"); } catch(e) { log(TAG_REQUEST_UTIL, 'format try { ... } catch (err) { \n ' + e); return json; @@ -234,9 +234,9 @@ function format(json) { // var jsonObj; // if (typeof json == 'string'){ // try { - // jsonObj = JSON.parse(json); + // jsonObj = parseJSON(json); // } catch (err) { - // console.log('format try { jsonObj = JSON.parse(json); } catch (err) { \n ' + err); + // console.log('format try { jsonObj = parseJSON(json); } catch (err) { \n ' + err); // return json; // } // } diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONResponse.js b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONResponse.js index 21a4321..065396f 100644 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONResponse.js +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/apijson/JSONResponse.js @@ -829,7 +829,7 @@ var JSONResponse = { } if (right instanceof Object) { - var m = JSON.parse(JSON.stringify(left)); + var m = parseJSON(JSON.stringify(left)); for (var k in right) { m[k] = JSONResponse.deepMerge(m[k], right[k]); } @@ -1036,7 +1036,7 @@ var JSONResponse = { } else if (format instanceof Array == false && format instanceof Object) { try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var result = JSONResponse.compareWithStandard(format, realObj, folder, exceptKeys, ignoreTrend); if (guess == true) { result.code -= 1; @@ -1601,7 +1601,7 @@ var JSONResponse = { } catch (e) { log(e) try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var format2 = JSONResponse.updateStandard(target.format, realObj, exceptKeys, ignoreTrend, key); if (format2 != null) { target.format = format2; diff --git a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/index.html b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/index.html index 17d4e56..ead8ad0 100755 --- a/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/index.html +++ b/APIJSON-Java-Server/APIJSONBoot-MultiDataSource/src/main/resources/static/api/index.html @@ -203,7 +203,7 @@
  • - +
    • - {{ isCaseGroupEditable ? '' : item.Chain.groupName }}{{' (' + (item.Chain.count - 1) + ') '}} + {{ isCaseGroupEditable ? '' : item.Chain.groupName }}{{' (' + (item.Chain.count - 1) + ') '}} @@ -256,7 +256,7 @@
      - +
      • @@ -743,14 +743,20 @@
        -
        - - - - - 每页 - - +
        + + + + + + 每页 + + + +
        + + +