1414
1515package apijson .boot ;
1616
17- import static apijson .RequestMethod .DELETE ;
18- import static apijson .RequestMethod .GET ;
19- import static apijson .RequestMethod .GETS ;
20- import static apijson .RequestMethod .HEAD ;
21- import static apijson .RequestMethod .HEADS ;
22- import static apijson .RequestMethod .POST ;
23- import static apijson .RequestMethod .PUT ;
24- import static apijson .framework .APIJSONConstant .ACCESS_ ;
25- import static apijson .framework .APIJSONConstant .COUNT ;
26- import static apijson .framework .APIJSONConstant .FORMAT ;
27- import static apijson .framework .APIJSONConstant .FUNCTION_ ;
28- import static apijson .framework .APIJSONConstant .ID ;
29- import static apijson .framework .APIJSONConstant .REQUEST_ ;
30- import static apijson .framework .APIJSONConstant .USER_ID ;
31- import static apijson .framework .APIJSONConstant .VERSION ;
32- import static org .springframework .http .HttpHeaders .COOKIE ;
33- import static org .springframework .http .HttpHeaders .SET_COOKIE ;
17+ import com .alibaba .fastjson .JSONArray ;
18+ import com .alibaba .fastjson .JSONObject ;
19+ import com .fasterxml .jackson .databind .util .LRUMap ;
20+
21+ import org .springframework .beans .factory .annotation .Autowired ;
22+ import org .springframework .http .HttpEntity ;
23+ import org .springframework .http .HttpHeaders ;
24+ import org .springframework .http .HttpMethod ;
25+ import org .springframework .http .ResponseEntity ;
26+ import org .springframework .stereotype .Service ;
27+ import org .springframework .web .bind .annotation .GetMapping ;
28+ import org .springframework .web .bind .annotation .PathVariable ;
29+ import org .springframework .web .bind .annotation .PostMapping ;
30+ import org .springframework .web .bind .annotation .RequestBody ;
31+ import org .springframework .web .bind .annotation .RequestMapping ;
32+ import org .springframework .web .bind .annotation .RequestParam ;
33+ import org .springframework .web .bind .annotation .RestController ;
34+ import org .springframework .web .client .RestTemplate ;
3435
3536import java .net .URLDecoder ;
3637import java .rmi .ServerException ;
38+ import java .sql .PreparedStatement ;
39+ import java .sql .ResultSet ;
40+ import java .sql .ResultSetMetaData ;
41+ import java .sql .Statement ;
3742import java .util .ArrayList ;
3843import java .util .Arrays ;
3944import java .util .Enumeration ;
4954import javax .servlet .http .HttpServletResponse ;
5055import javax .servlet .http .HttpSession ;
5156
52- import org .springframework .beans .factory .annotation .Autowired ;
53- import org .springframework .http .HttpEntity ;
54- import org .springframework .http .HttpHeaders ;
55- import org .springframework .http .HttpMethod ;
56- import org .springframework .http .ResponseEntity ;
57- import org .springframework .stereotype .Service ;
58- import org .springframework .web .bind .annotation .GetMapping ;
59- import org .springframework .web .bind .annotation .PathVariable ;
60- import org .springframework .web .bind .annotation .PostMapping ;
61- import org .springframework .web .bind .annotation .RequestBody ;
62- import org .springframework .web .bind .annotation .RequestMapping ;
63- import org .springframework .web .bind .annotation .RequestParam ;
64- import org .springframework .web .bind .annotation .RestController ;
65- import org .springframework .web .client .RestTemplate ;
66-
67- import com .alibaba .fastjson .JSONObject ;
68- import com .fasterxml .jackson .databind .util .LRUMap ;
69-
7057import apijson .JSON ;
7158import apijson .JSONResponse ;
7259import apijson .Log ;
7360import apijson .RequestMethod ;
7461import apijson .StringUtil ;
7562import apijson .demo .DemoFunctionParser ;
7663import apijson .demo .DemoParser ;
64+ import apijson .demo .DemoSQLConfig ;
65+ import apijson .demo .DemoSQLExecutor ;
7766import apijson .demo .DemoVerifier ;
7867import apijson .demo .model .Privacy ;
7968import apijson .demo .model .User ;
8675import apijson .orm .exception .OutOfRangeException ;
8776import apijson .router .APIJSONRouterController ;
8877
78+ import static apijson .RequestMethod .DELETE ;
79+ import static apijson .RequestMethod .GET ;
80+ import static apijson .RequestMethod .GETS ;
81+ import static apijson .RequestMethod .HEAD ;
82+ import static apijson .RequestMethod .HEADS ;
83+ import static apijson .RequestMethod .POST ;
84+ import static apijson .RequestMethod .PUT ;
85+ import static apijson .framework .APIJSONConstant .ACCESS_ ;
86+ import static apijson .framework .APIJSONConstant .COUNT ;
87+ import static apijson .framework .APIJSONConstant .FORMAT ;
88+ import static apijson .framework .APIJSONConstant .FUNCTION_ ;
89+ import static apijson .framework .APIJSONConstant .ID ;
90+ import static apijson .framework .APIJSONConstant .REQUEST_ ;
91+ import static apijson .framework .APIJSONConstant .USER_ID ;
92+ import static apijson .framework .APIJSONConstant .VERSION ;
93+ import static org .springframework .http .HttpHeaders .COOKIE ;
94+ import static org .springframework .http .HttpHeaders .SET_COOKIE ;
95+
8996
9097/**请求路由入口控制器,包括通用增删改查接口等,转交给 APIJSON 的 Parser 来处理
9198 * 具体见 SpringBoot 文档
9299 * https://www.springcloud.cc/spring-boot.html#boot-features-spring-mvc
93- * 以及 APIJSON 通用文档 3.设计规范 3.1 操作方法
100+ * 以及 APIJSON 通用文档 3.设计规范 3.1 操作方法
94101 * https://github.com/Tencent/APIJSON/blob/master/Document.md#3.1
95102 * <br > 建议全通过HTTP POST来请求:
96103 * <br > 1.减少代码 - 客户端无需写HTTP GET,PUT等各种方式的请求代码
@@ -123,7 +130,7 @@ public String getRequestURL() {
123130 public String router (@ PathVariable String method , @ PathVariable String tag , @ RequestParam Map <String , String > params , @ RequestBody String request , HttpSession session ) {
124131 return super .router (method , tag , params , request , session );
125132 }
126-
133+
127134 // 通用接口,非事务型操作 和 简单事务型操作 都可通过这些接口自动化实现 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
128135
129136 /**增删改查统一入口,这个一个方法可替代以下 7 个方法,牺牲一些路由解析性能来提升一点开发效率
@@ -713,7 +720,7 @@ public JSONObject login(@RequestBody String request, HttpSession session) {
713720 return privacyResponse ;
714721 }
715722
716- //校验凭证
723+ //校验凭证
717724 if (isPassword ) {//password密码登录
718725 response = new JSONResponse (
719726 new DemoParser (HEADS , false ).parseResponse (
@@ -853,7 +860,7 @@ public JSONObject register(@RequestBody String request) {
853860 requestObject .put (JSONRequest .KEY_TAG , REGISTER );
854861 }
855862 requestObject .put (JSONRequest .KEY_FORMAT , true );
856- response = new JSONResponse (
863+ response = new JSONResponse (
857864 new DemoParser (POST ).setNeedVerifyLogin (false ).parseResponse (requestObject )
858865 );
859866
@@ -982,7 +989,7 @@ public JSONObject putPassword(@RequestBody String request){
982989 } else {
983990 privacy .setPayPassword (oldPassword );
984991 }
985- JSONResponse response = new JSONResponse (
992+ JSONResponse response = new JSONResponse (
986993 new DemoParser (HEAD , false ).parseResponse (
987994 new JSONRequest (privacy ).setFormat (true )
988995 )
@@ -1169,11 +1176,11 @@ public void remove(String key) {
11691176 @ SuppressWarnings ("unchecked" )
11701177 @ RequestMapping (value = "delegate" )
11711178 public String delegate (
1172- @ RequestParam ("$_delegate_url" ) String url ,
1179+ @ RequestParam ("$_delegate_url" ) String url ,
11731180 @ RequestParam (value = "$_type" , required = false ) String type ,
11741181 @ RequestParam (value = "$_except_headers" , required = false ) String exceptHeaders ,
1175- @ RequestParam (value = "$_delegate_id" , required = false ) String sessionId ,
1176- @ RequestBody (required = false ) String body ,
1182+ @ RequestParam (value = "$_delegate_id" , required = false ) String sessionId ,
1183+ @ RequestBody (required = false ) String body ,
11771184 HttpMethod method , HttpSession session
11781185 ) {
11791186
@@ -1210,7 +1217,7 @@ public String delegate(
12101217 if (names != null ) {
12111218 headers = new HttpHeaders ();
12121219 //Arrays.asList(null) 抛异常,可以排除不存在的头来替代 exceptHeaders == null //空字符串表示不排除任何头
1213- List <String > exceptHeaderList = StringUtil .isEmpty (exceptHeaders , true )
1220+ List <String > exceptHeaderList = StringUtil .isEmpty (exceptHeaders , true )
12141221 ? EXCEPT_HEADER_LIST : Arrays .asList (StringUtil .split (exceptHeaders ));
12151222
12161223
@@ -1221,7 +1228,7 @@ public String delegate(
12211228 while (names .hasMoreElements ()) {
12221229 name = names .nextElement ();
12231230 if (name != null && exceptHeaderList .contains (name .toLowerCase ()) == false ) {
1224- //APIAuto 是一定精准发送 Set-Cookie 名称过来的,预留其它命名可实现覆盖原 Cookie Header 等更多可能
1231+ //APIAuto 是一定精准发送 Set-Cookie 名称过来的,预留其它命名可实现覆盖原 Cookie Header 等更多可能
12251232 if (SET_COOKIE .toLowerCase ().equals (name .toLowerCase ())) { //接收到时就已经被强制小写
12261233 setCookie = Arrays .asList (httpServletRequest .getHeader (name )); // JSON.parseArray(request.getHeader(name), String.class);
12271234 }
@@ -1317,6 +1324,96 @@ else if (APIJSON_DELEGATE_ID.toLowerCase().equals(name.toLowerCase())) {
13171324 return entity .getBody ();
13181325 }
13191326
1327+ /**执行 SQL 语句,支持 SQLAuto,注意仅仅不要开放给后端组外的任何人,更不要暴露到公司外的公网!
1328+ * @param request 只用String,避免encode后未decode
1329+ * @return
1330+ * @see
1331+ * <pre>
1332+ {
1333+ "sql": "SELECT * FROM sys.Access LIMIT ${limit}", // SQL 语句,可以带占位符
1334+ "arg": {
1335+ "limit": 5
1336+ }
1337+ }
1338+ * </pre>
1339+ */
1340+ @ PostMapping ("execute" )
1341+ public String execute (@ RequestBody String request , HttpSession session ) {
1342+ try {
1343+ if (Log .DEBUG == false ) {
1344+ return DemoParser .newErrorResult (new IllegalAccessException ("非 DEBUG 模式下不允许调用 /execute !" )).toJSONString ();
1345+ }
1346+
1347+ DemoVerifier .verifyLogin (session );
1348+
1349+ long startTime = System .currentTimeMillis ();
1350+
1351+ JSONObject req = JSON .parseObject (request );
1352+ String uri = req .getString ("uri" );
1353+ String sql = req .getString ("sql" );
1354+ List <Object > valueList = req .getJSONArray ("arg" );
1355+
1356+ DemoSQLExecutor executor = new DemoSQLExecutor ();
1357+ DemoSQLConfig config = new DemoSQLConfig ();
1358+
1359+ if (StringUtil .isNotEmpty (uri )) {
1360+ config .setDBUri (uri );
1361+ }
1362+ config .setPrepared (true );
1363+ config .setPreparedValueList (valueList );
1364+
1365+ Statement statement = executor .getStatement (config , sql );
1366+ if (statement instanceof PreparedStatement ) {
1367+ ((PreparedStatement ) statement ).execute ();
1368+ } else {
1369+ statement .execute (sql );
1370+ }
1371+
1372+ ResultSet rs = statement .getResultSet ();
1373+ ResultSetMetaData rsmd = rs .getMetaData ();
1374+ int length = rsmd .getColumnCount ();
1375+
1376+ JSONArray arr = new JSONArray ();
1377+
1378+ long cursorDuration = 0 ;
1379+ long rsDuration = 0 ;
1380+
1381+ long cursorStartTime = System .currentTimeMillis ();
1382+ while (rs .next ()) {
1383+ cursorDuration += System .currentTimeMillis () - cursorStartTime ;
1384+
1385+ JSONObject obj = new JSONObject (true );
1386+ for (int i = 1 ; i <= length ; i ++) {
1387+ long sqlStartTime = System .currentTimeMillis ();
1388+ String label = rsmd .getColumnLabel (i );
1389+ Object value = rs .getObject (i );
1390+ rsDuration += System .currentTimeMillis () - sqlStartTime ;
1391+
1392+ obj .put (label , value );
1393+ }
1394+
1395+ arr .add (obj );
1396+ }
1397+
1398+ JSONObject result = DemoParser .newSuccessResult ();
1399+ result .put ("count" , statement .getUpdateCount ());
1400+ result .put ("list" , arr );
1401+
1402+ long endTime = System .currentTimeMillis ();
1403+ long duration = endTime - startTime ;
1404+
1405+ long sqlDuration = cursorDuration + rsDuration ;
1406+ long parseDuration = duration - sqlDuration ;
1407+
1408+ result .put ("time:start|duration|end|parse|sql" , startTime + "|" + duration + "|" + endTime + "|" + parseDuration + "|" + sqlDuration );
1409+
1410+ return result .toJSONString ();
1411+ } catch (Exception e ) {
1412+ return DemoParser .newErrorResult (e ).toJSONString ();
1413+ }
1414+
1415+ }
1416+
13201417
13211418 /**Swagger 文档 Demo,供 APIAuto 测试导入 Swagger 文档到数据库用
13221419 * @return
0 commit comments