xiaochan před 1 rokem
rodič
revize
31b3051bab

+ 54 - 4
src/main/java/thyyxxk/webserver/controller/database/DataMiddleOfficeController.java

@@ -2,18 +2,26 @@ package thyyxxk.webserver.controller.database;
 
 import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.web.bind.annotation.*;
 import thyyxxk.webserver.config.auth.PassToken;
+import thyyxxk.webserver.config.exception.BizException;
 import thyyxxk.webserver.config.exception.ExceptionEnum;
 import thyyxxk.webserver.entity.ResultVo;
+import thyyxxk.webserver.entity.database.DataParams;
+import thyyxxk.webserver.entity.database.DataSqlParamConfig;
 import thyyxxk.webserver.entity.database.TDataBaseSqlApi;
 import thyyxxk.webserver.entity.database.TDataBaseSqlApiTest;
 import thyyxxk.webserver.service.database.DataMiddleOfficeServer;
 import thyyxxk.webserver.utils.ResultVoUtil;
+import thyyxxk.webserver.utils.StringUtil;
 
 import javax.servlet.http.HttpServletRequest;
 import java.sql.SQLException;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
 
 @RequestMapping("/dataBase/api")
 @Slf4j
@@ -26,16 +34,58 @@ public class DataMiddleOfficeController {
         this.server = server;
     }
 
-    @RequestMapping(value = "/data/{id}")
+    @RequestMapping(value = "/{dataSource}/{id}")
     @PassToken
-    public ResultVo<JSONObject> getData(@PathVariable String id,
+    public ResultVo<JSONObject> getData(@PathVariable String dataSource,
+                                        @PathVariable String id,
                                         HttpServletRequest request) throws SQLException {
 
         if (id == null || id.isEmpty()) {
-            return ResultVoUtil.fail(ExceptionEnum.ERROR_MESSAGE, "id,不能为空");
+            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "id,不能为空");
         }
 
-        return server.getData(id, request);
+        TDataBaseSqlApi api = server.getSqlApi(id);
+
+        if (api == null) {
+            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "接口未开放或未启用。");
+        }
+        if (!request.getMethod().equals(api.getRequestMapping())) {
+            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请求方式错误,应使用" + api.getRequestMapping() + "请求");
+        }
+
+
+        Map<String, Object> map = new HashMap<>();
+        DataSqlParamConfig config = api.getConfigJson();
+
+        if (!config.getDataSources().contains(dataSource)) {
+            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请求地址错误请检查。");
+        }
+
+        api.setCurrentDataSource(dataSource);
+
+
+        if (config.getParams() != null && !config.getParams().isEmpty()) {
+            for (DataParams param : config.getParams()) {
+                Object value = request.getParameter(param.getKey());
+                Object v = value == null ? param.getDefaultValue() : value;
+                if (param.getRequired() && v == null) {
+                    throw new BizException(ExceptionEnum.SUCCESS, "请求参数:【" + param.getKey() + "】不能为空");
+                }
+                map.put(param.getKey(), v);
+            }
+
+            if (config.getPageInfo().getPage()) {
+                String currentPage = request.getParameter("currentPage");
+                if (StringUtil.isBlank(currentPage)) {
+                    throw new BizException(ExceptionEnum.SUCCESS, "请求参数:【currentPage】不能为空。");
+                }
+                map.put("currentPage", currentPage);
+            }
+        }
+
+//        return CompletableFuture.supplyAsync(() -> server.getData(api, map, false));
+
+        return server.getData(api, map, false);
     }
 
     @PostMapping("/getDataBaseSqlApiList")

+ 2 - 2
src/main/java/thyyxxk/webserver/dao/his/database/DataMiddleOfficeDao.java

@@ -11,10 +11,10 @@ import java.util.List;
 @Mapper
 public interface DataMiddleOfficeDao extends BaseMapper<TDataBaseSqlApi> {
 
-    @Select("select id, name, sql, data_base_id, request_mapping, config, enable, parent_id, type from t_data_base_sql_api")
+    @Select("select id, name, sql,  request_mapping, config, enable, parent_id, type from t_data_base_sql_api")
     List<TDataBaseSqlApi> selectAll();
 
-    @Select("select id, name, sql, data_base_id, request_mapping, config, enable, parent_id, type from t_data_base_sql_api where id = #{id} and enable = 1")
+    @Select("select id, name, sql,  request_mapping, config, enable, parent_id, type from t_data_base_sql_api where id = #{id} and enable = 1")
     TDataBaseSqlApi activationApiById(String id);
 
 

+ 0 - 15
src/main/java/thyyxxk/webserver/entity/database/CyPage.java

@@ -1,15 +0,0 @@
-package thyyxxk.webserver.entity.database;
-
-import lombok.Data;
-
-import java.util.List;
-import java.util.Map;
-
-@Data
-public class CyPage {
-    private long currentPage;
-    private long pageSize;
-    private long total;
-
-    private List<Map<String, Object>> data;
-}

+ 58 - 0
src/main/java/thyyxxk/webserver/entity/database/CyPageParam.java

@@ -0,0 +1,58 @@
+package thyyxxk.webserver.entity.database;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.druid.pool.DruidPooledConnection;
+import lombok.Data;
+import thyyxxk.webserver.utils.StringUtil;
+import thyyxxk.webserver.utils.sqlParser.SqlMeta;
+
+@Data
+public class CyPageParam {
+
+    public CyPageParam(SqlMeta sqlMeta, long currentPage, long pageSize) {
+        this.sqlMeta = sqlMeta;
+        int orderIndex = sqlMeta.getSql().indexOf("order by");
+        this.currentPage = currentPage;
+        this.pageSize = pageSize;
+
+        sql = sqlMeta.getSql().replace("select", "SELECT").replace("from", "FROM");
+
+        if (orderIndex > -1) {
+            sql = sqlMeta.getSql().substring(0, orderIndex);
+            orderBy = String.format(orderBy, sqlMeta.getSql().substring(orderIndex));
+        } else {
+            orderBy = String.format(orderBy, "order by current_timestamp");
+        }
+        long start = ((currentPage - 1) * pageSize) + 1;
+        long end = (currentPage) * pageSize;
+
+        help(start, end);
+    }
+
+    private SqlMeta sqlMeta;
+    private DruidPooledConnection coon;
+    private long currentPage;
+    private long pageSize;
+    private Boolean removeSpaces;
+    private Boolean printSql;
+
+    private String countSql;
+    private String pageSql;
+
+    private String orderBy = "ROW_NUMBER() OVER (%s) AS _row_index_";
+    private String sql;
+
+    private void help(long start, long end) {
+        if (StringUtil.isBlank(this.sqlMeta.getPageStr())) {
+            countSql = String.format("select count(1) from (%s) as t", sql);
+            pageSql = String.format("with selectTemp as (select  %s ,* from (%s) temp) select * from selectTemp where _row_index_ between %d and %d " +
+                    "order by _row_index_", orderBy, sql, start, end);
+        } else {
+            countSql = sql.replace("_cy_page_", " count(1) ");
+            String cyPage = sql.replace("_cy_page_", StrUtil.format(" {}, {}", orderBy, sqlMeta.getPageStr()));
+            pageSql = StrUtil.format("with selectTemp as ({}) select * from selectTemp where _row_index_ between {} and {} " +
+                    "order by _row_index_", cyPage, start, end);
+        }
+    }
+
+}

+ 2 - 0
src/main/java/thyyxxk/webserver/entity/database/DataSqlParamConfig.java

@@ -18,4 +18,6 @@ public class DataSqlParamConfig {
     private PageInfo pageInfo;
 
     private Boolean removeSpaces;
+
+    private List<String> dataSources;
 }

+ 3 - 6
src/main/java/thyyxxk/webserver/entity/database/TDataBaseSqlApi.java

@@ -33,12 +33,6 @@ public class TDataBaseSqlApi implements Serializable {
     @TableField(value = "sql")
     private String sql;
 
-    /**
-     * 数据源id
-     */
-    @TableField(value = "data_base_id")
-    private Integer dataBaseId;
-
     /**
      * get | post
      */
@@ -69,6 +63,9 @@ public class TDataBaseSqlApi implements Serializable {
     @TableField(value = "type")
     private Integer type;
 
+    @TableField(exist = false)
+    private String currentDataSource;
+
 
     public DataSqlParamConfig getConfigJson() {
         if (config != null) {

+ 6 - 5
src/main/java/thyyxxk/webserver/service/database/DataBaseServer.java

@@ -24,7 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
 public class DataBaseServer {
     private final DataBaseDao dao;
     @Getter
-    private static final Map<Integer, DruidDataSource> DATA_SOURCE_MAP = new ConcurrentHashMap<>();
+    private static final Map<String, DruidDataSource> DATA_SOURCE_MAP = new ConcurrentHashMap<>();
     private static List<TDataBaseConfig> dataList = new LinkedList<>();
 
     public DataBaseServer(DataBaseDao dao) {
@@ -42,7 +42,7 @@ public class DataBaseServer {
     private void pushDataBase(TDataBaseConfig dataBaseConfig) {
         try {
             DruidDataSource dataSource = createConnect(dataBaseConfig);
-            DATA_SOURCE_MAP.put(dataBaseConfig.getId(), dataSource);
+            DATA_SOURCE_MAP.put(dataBaseConfig.getAlias(), dataSource);
             log.info("数据库启动:{}", dataBaseConfig.getName());
         } catch (Exception e) {
             log.error("数据库初始化失败:{}", e.getMessage());
@@ -117,13 +117,14 @@ public class DataBaseServer {
     }
 
     public ResultVo<Boolean> delById(Integer id) {
+
+        TDataBaseConfig config = dao.selectById(id);
         dao.deleteById(id);
-        DruidDataSource source = DATA_SOURCE_MAP.get(id);
+        DruidDataSource source = DATA_SOURCE_MAP.get(config.getAlias());
         source.close();
-        DATA_SOURCE_MAP.remove(id);
+        DATA_SOURCE_MAP.remove(config.getAlias());
         dataList = dao.selectAll();
         return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION, true);
     }
 
-
 }

+ 42 - 103
src/main/java/thyyxxk/webserver/service/database/DataMiddleOfficeServer.java

@@ -6,13 +6,14 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import thyyxxk.webserver.config.exception.BizException;
 import thyyxxk.webserver.config.exception.ExceptionEnum;
 import thyyxxk.webserver.dao.his.database.DataMiddleOfficeDao;
 import thyyxxk.webserver.entity.ResultVo;
 import thyyxxk.webserver.entity.database.*;
-import thyyxxk.webserver.utils.ListUtil;
 import thyyxxk.webserver.utils.ResultVoUtil;
 import thyyxxk.webserver.utils.SnowFlakeId;
 import thyyxxk.webserver.utils.StringUtil;
@@ -20,7 +21,6 @@ import thyyxxk.webserver.utils.sqlParser.SqlMeta;
 import thyyxxk.webserver.utils.sqlParser.SqlTemplate;
 import thyyxxk.webserver.utils.sqlParser.SqlTemplateEngin;
 
-import javax.servlet.http.HttpServletRequest;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
@@ -39,15 +39,6 @@ public class DataMiddleOfficeServer {
         this.dao = dao;
     }
 
-    @Data
-    public static class CyPageParam {
-        private SqlMeta sqlMeta;
-        private DruidPooledConnection coon;
-        private long currentPage;
-        private long pageSize;
-        private Boolean removeSpaces;
-        private Boolean printSql;
-    }
 
     private static String printRealSql(String sql, Object[] params) {
         if (params == null || params.length == 0) {
@@ -90,7 +81,7 @@ public class DataMiddleOfficeServer {
 
     public JSONObject pageHelper(CyPageParam param) throws SQLException {
         SqlMeta sqlMeta = param.getSqlMeta();
-        long currentPage = param.currentPage;
+        long currentPage = param.getCurrentPage();
         long pageSize = param.getPageSize();
         DruidPooledConnection coon = param.getCoon();
 
@@ -99,32 +90,15 @@ public class DataMiddleOfficeServer {
         js.put("currentPage", currentPage);
         js.put("pageSize", pageSize);
 
-        int index = sqlMeta.getSql().indexOf("order by");
-        String sql = sqlMeta.getSql().replace("select", "SELECT").replace("from", "FROM");
-
-        String orderBy = "ROW_NUMBER() OVER (%s) AS row_index";
-        if (index > 0) {
-            sql = sqlMeta.getSql().substring(0, index);
-            orderBy = String.format(orderBy, sqlMeta.getSql().substring(index));
-        } else {
-            orderBy = String.format(orderBy, "order by current_timestamp");
-        }
-
-        long start = ((currentPage - 1) * pageSize) + 1;
-        long end = (currentPage) * pageSize;
-
-        String countSql = String.format("select count(1) from (%s) as t", sql);
-        String pageSql = String.format("with selectTemp as (select  %s ,* from (%s) temp) select * from selectTemp where row_index between %d and %d " +
-                "order by row_index", orderBy, sql, start, end);
         long count = 0L;
 
         if (param.getPrintSql()) {
             Object[] values = sqlMeta.getParameter().toArray(new Object[0]);
-            js.put("countSql", printRealSql(countSql, values));
-            js.put("querySql", printRealSql(pageSql, values));
+            js.put("countSql", printRealSql(param.getCountSql(), values));
+            js.put("querySql", printRealSql(param.getPageSql(), values));
         }
 
-        try (PreparedStatement ps = coon.prepareStatement(countSql)) {
+        try (PreparedStatement ps = coon.prepareStatement(param.getCountSql())) {
             for (int i = 0; i < sqlMeta.getParameter().size(); i++) {
                 ps.setString(i + 1, (String) sqlMeta.getParameter().get(i));
             }
@@ -132,7 +106,7 @@ public class DataMiddleOfficeServer {
                 while (rs.next()) {
                     count = rs.getLong(1);
                 }
-                js.put("total", 0);
+                js.put("total", count);
                 if (count == 0) {
                     js.put("data", null);
                     return js;
@@ -142,7 +116,7 @@ public class DataMiddleOfficeServer {
 
         List<Map<String, Object>> data;
 
-        try (PreparedStatement ps = coon.prepareStatement(pageSql)) {
+        try (PreparedStatement ps = coon.prepareStatement(param.getPageSql())) {
 
             for (int i = 0; i < sqlMeta.getParameter().size(); i++) {
                 ps.setString(i + 1, (String) sqlMeta.getParameter().get(i));
@@ -160,33 +134,33 @@ public class DataMiddleOfficeServer {
 
     private static List<Map<String, Object>> convertList(ResultSet rs, boolean removeWhitespace) throws SQLException {
         List<Map<String, Object>> list = new LinkedList<>();
-        ResultSetMetaData md = rs.getMetaData();//获取键名
-        int columnCount = md.getColumnCount();//获取列的数量
+        ResultSetMetaData md = rs.getMetaData();
+        int columnCount = md.getColumnCount();
         while (rs.next()) {
-            Map<String, Object> rowData = new HashMap<>();//声明Map
+            Map<String, Object> rowData = new HashMap<>();
             for (int i = 1; i <= columnCount; i++) {
                 Object value = rs.getObject(i);
                 if (removeWhitespace && value instanceof String) {
                     value = ((String) value).trim();
                 }
-                rowData.put(md.getColumnName(i), value);//获取键名及值
+                String key = md.getColumnName(i);
+                if (!"_row_index_".equals(key)) {
+                    rowData.put(key, value);//获取键名及值
+                }
             }
             list.add(rowData);
         }
         return list;
     }
 
-    public ResultVo<JSONObject> getData(String id, HttpServletRequest request) throws SQLException {
-        TDataBaseSqlApi api = dao.activationApiById(id);
-        if (api == null) {
-            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "接口未开放或未启用。");
-        }
-
-        if (!request.getMethod().equals(api.getRequestMapping())) {
-            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请求方式错误,应使用" + api.getRequestMapping() + "请求");
-        }
+    public ResultVo<JSONObject> getData(@NotNull TDataBaseSqlApi api, Map<String, Object> map, boolean pringSql) throws SQLException {
+        DruidDataSource ds = DataBaseServer.getDATA_SOURCE_MAP().get(api.getCurrentDataSource());
+        // 匹配 -- 或 # 开头的注解
+        String pattern2 = "(--).*?(\r\n|\r|\n)";
+        Pattern p2 = Pattern.compile(pattern2, Pattern.DOTALL);
+        Matcher m2 = p2.matcher(api.getSql());
 
-        DruidDataSource ds = DataBaseServer.getDATA_SOURCE_MAP().get(api.getDataBaseId());
+        api.setSql(m2.replaceAll(""));
 
         if (ds == null) {
             return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "数据源错误");
@@ -194,19 +168,10 @@ public class DataMiddleOfficeServer {
 
         try (DruidPooledConnection coon = ds.getConnection()) {
             DataSqlParamConfig config = api.getConfigJson();
-            Map<String, Object> map = new HashMap<>();
-
-            if (config.getParams() != null && !config.getParams().isEmpty()) {
-                for (DataParams param : config.getParams()) {
-                    Object value = request.getParameter(param.getKey());
-                    map.put(param.getKey(), value == null ? param.getDefaultValue() : value);
-                }
-            }
-
             if (config.getPageInfo().getPage()) {
-                return page(api, map, coon, false);
+                return page(api, map, coon, pringSql);
             } else {
-                return notPage(api, map, coon, false);
+                return notPage(api, map, coon, pringSql);
             }
         } catch (Exception e) {
             log.error("发生错误:{}", e.getMessage());
@@ -214,7 +179,6 @@ public class DataMiddleOfficeServer {
         }
     }
 
-
     private ResultVo<JSONObject> page(TDataBaseSqlApi api, Map<String, Object> params, DruidPooledConnection coon, boolean printSql) throws SQLException {
         SqlTemplate sqlTemplate = sqlTemplateEngin.getSqlTemplate(api.getSql());
         SqlMeta sqlMeta = sqlTemplate.process(params);
@@ -224,11 +188,11 @@ public class DataMiddleOfficeServer {
             throw new BizException(ExceptionEnum.NULL_POINTER, "当前页码不能为空。");
         }
 
-        CyPageParam pageParam = new CyPageParam();
-        pageParam.setSqlMeta(sqlMeta);
+        CyPageParam pageParam = new CyPageParam(sqlMeta,
+                Long.parseLong(currentPage instanceof String ? (String) currentPage : String.valueOf(currentPage)),
+                api.getConfigJson().getPageInfo().getPageSize()
+        );
         pageParam.setCoon(coon);
-        pageParam.setCurrentPage(Long.parseLong(currentPage instanceof String ? (String) currentPage : String.valueOf(currentPage)));
-        pageParam.setPageSize(api.getConfigJson().getPageInfo().getPageSize());
         pageParam.setRemoveSpaces(api.getConfigJson().getRemoveSpaces());
         pageParam.setPrintSql(printSql);
         return ResultVoUtil.success(pageHelper(pageParam));
@@ -237,19 +201,21 @@ public class DataMiddleOfficeServer {
     private ResultVo<JSONObject> notPage(TDataBaseSqlApi api, Map<String, Object> params, DruidPooledConnection coon, boolean printSql) throws SQLException {
         SqlTemplate sqlTemplate = sqlTemplateEngin.getSqlTemplate(api.getSql());
         SqlMeta sqlMeta = sqlTemplate.process(params);
-        try (PreparedStatement ps = coon.prepareStatement(sqlMeta.getSql())) {
+        String sql = sqlMeta.getSql().replace("_cy_page_", sqlMeta.getPageStr());
+        try (PreparedStatement ps = coon.prepareStatement(sql)) {
+
+            ps.setQueryTimeout(5);
 
             for (int i = 0; i < sqlMeta.getParameter().size(); i++) {
                 ps.setObject(i + 1, sqlMeta.getParameter().get(i));
             }
-            try (ResultSet res = ps.executeQuery()) {
 
+            try (ResultSet res = ps.executeQuery()) {
                 List<Map<String, Object>> data = convertList(res, api.getConfigJson().getRemoveSpaces());
-
                 JSONObject js = new JSONObject();
                 js.put("data", data);
                 if (printSql) {
-                    js.put("querySql", printRealSql(sqlMeta.getSql(), sqlMeta.getParameter().toArray(new Object[0])));
+                    js.put("querySql", printRealSql(sql, sqlMeta.getParameter().toArray(new Object[0])));
                 }
                 return ResultVoUtil.success(js);
             }
@@ -262,12 +228,6 @@ public class DataMiddleOfficeServer {
     }
 
     public ResultVo<JSONObject> testSqlApi(TDataBaseSqlApiTest api) {
-        DruidDataSource ds = DataBaseServer.getDATA_SOURCE_MAP().get(api.getDataBaseId());
-
-        if (ds == null) {
-            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "数据源错误");
-        }
-
         if (!api.getConfigJson().getPageInfo().getPage()) {
             String sql = api.getSql().replace("select", "SELECT");
             int selectIndex = sql.indexOf("SELECT") + 6;
@@ -275,28 +235,16 @@ public class DataMiddleOfficeServer {
             api.setSql(sql);
         }
 
-        try (DruidPooledConnection coon = ds.getConnection()) {
-            DataSqlParamConfig config = api.getConfigJson();
-            Map<String, Object> map = new HashMap<>();
-
-            if (ListUtil.notBlank(config.getParams())) {
-                for (DataParams param : config.getParams()) {
-                    Object value = api.getParams().getObject(param.getKey(), Object.class);
-                    map.put(param.getKey(), value == null ? param.getDefaultValue() : value);
-                }
-                map.put("currentPage", api.getParams().getObject("currentPage", Object.class));
-            }
+        if (!api.getConfigJson().getDataSources().contains(api.getCurrentDataSource())) {
+            return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "请求地址错误请检查。");
+        }
 
-            if (config.getPageInfo().getPage()) {
-                return page(api, map, coon, true);
-            } else {
-                return notPage(api, map, coon, true);
-            }
+        try {
+            return getData(api, api.getParams(), true);
         } catch (Exception e) {
-            e.printStackTrace();
-            log.error("发送错误:{}", e.getMessage());
             return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, e.getMessage());
         }
+
     }
 
     public ResultVo<Boolean> updateSqlApi(TDataBaseSqlApi param) {
@@ -341,17 +289,8 @@ public class DataMiddleOfficeServer {
         return ResultVoUtil.success(ExceptionEnum.SUCCESS_AND_NOTIFICATION);
     }
 
-
-    public static void main(String[] args) {
-        String sql = "select column1 from (select column2 from table1) as subquery";
-        String patternString = "\\((.*?)\\)";
-        Pattern pattern = Pattern.compile(patternString);
-        Matcher matcher = pattern.matcher(sql);
-
-        while (matcher.find()) {
-            String subquery = matcher.group(1);
-            System.out.println("子查询为:" + subquery);
-        }
+    public TDataBaseSqlApi getSqlApi(String id) {
+        return dao.activationApiById(id);
     }
 
 

+ 5 - 0
src/main/java/thyyxxk/webserver/utils/sqlParser/Context.java

@@ -1,6 +1,7 @@
 package thyyxxk.webserver.utils.sqlParser;
 
 import lombok.Getter;
+import lombok.Setter;
 import ognl.OgnlContext;
 import ognl.OgnlException;
 import ognl.OgnlRuntime;
@@ -27,6 +28,10 @@ public class Context {
     @Getter
     private final Map<String, Object> binding;
 
+    @Getter
+    @Setter
+    private String page;
+
     private StringBuilder sql = new StringBuilder();
 
     @Getter

+ 4 - 3
src/main/java/thyyxxk/webserver/utils/sqlParser/SqlMeta.java

@@ -9,16 +9,17 @@ import java.util.List;
  */
 @Getter
 public class SqlMeta {
-
-
     private String sql;
 
     private List<Object> parameter;
 
-    public SqlMeta(String sql, List<Object> parameter) {
+    private final String pageStr;
+
+    public SqlMeta(String sql, List<Object> parameter, String pageStr) {
         super();
         this.sql = sql;
         this.parameter = parameter;
+        this.pageStr = pageStr;
     }
 
     public void setSql(String sql) {

+ 10 - 1
src/main/java/thyyxxk/webserver/utils/sqlParser/SqlTemplate.java

@@ -47,7 +47,7 @@ public class SqlTemplate {
 
         parseParameter(context);
 
-        return new SqlMeta(context.getSql(), context.getParameter());
+        return new SqlMeta(context.getSql(), context.getParameter(), context.getPage());
     }
 
     private void parseParameter(final Context context) {
@@ -72,6 +72,15 @@ public class SqlTemplate {
 
         sql = parser1.parse(sql);
 
+
+        GenericTokenParser parser2 = new GenericTokenParser("@page{", "}",
+                content -> {
+                    context.setPage(content);
+                    return "_cy_page_";
+                });
+
+        sql = parser2.parse(sql);
+
         context.setSql(sql);
 
     }