From 0d18e536f02cac386c5eec05f4ba790a1bbf57e5 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Tue, 29 Apr 2025 16:14:51 +0800 Subject: [PATCH 01/12] =?UTF-8?q?=E8=A7=A3=E5=86=B3swagger=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=87=E6=A1=A3=EF=BC=8C=E5=8F=82=E6=95=B0=E4=B9=B1?= =?UTF-8?q?=E7=A0=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/config/default-spring-doc.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties b/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties index 91f214b50..002250c54 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties +++ b/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties @@ -1,2 +1,3 @@ springdoc.auto-tag-classes: false -springdoc.packages-to-scan: org.jeecg \ No newline at end of file +springdoc.packages-to-scan: org.jeecg +springdoc.default-flat-param-object: true \ No newline at end of file From d1589acc4123f24d1aa0dbab4513449e05e09ce8 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Sat, 3 May 2025 17:14:18 +0800 Subject: [PATCH 02/12] =?UTF-8?q?=E5=9B=9E=E6=BB=9Aswagger=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/config/default-spring-doc.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties b/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties index 002250c54..91f214b50 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties +++ b/jeecg-boot/jeecg-boot-base-core/src/main/resources/config/default-spring-doc.properties @@ -1,3 +1,2 @@ springdoc.auto-tag-classes: false -springdoc.packages-to-scan: org.jeecg -springdoc.default-flat-param-object: true \ No newline at end of file +springdoc.packages-to-scan: org.jeecg \ No newline at end of file From cffba084fc4cb2d49c3da4d21215a4d14d75f499 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Sun, 4 May 2025 16:27:28 +0800 Subject: [PATCH 03/12] =?UTF-8?q?=E3=80=90issues/8178=E3=80=91=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=8E=9F=E7=94=9Fvxe-table=E7=BB=84=E4=BB=B6=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=A8=A1=E5=BC=8F=E4=B8=8B=E5=A4=B1=E5=8E=BB=E7=84=A6?= =?UTF-8?q?=E7=82=B9=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/jeecg/JVxeTable/src/install.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/install.ts b/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/install.ts index 9b85eb311..a8ba5e2e6 100644 --- a/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/install.ts +++ b/jeecgboot-vue3/src/components/jeecg/JVxeTable/src/install.ts @@ -39,6 +39,12 @@ export function registerJVxeTable(app: App) { function preventClosingPopUp(this: any, params) { // 获取组件增强 let col = params.column.params; + // update-begin--author:liaozhiyang---date:20250429---for:【issues/8178】使用原生vxe-table组件编辑模式下失去焦点报错 + if (col === undefined) { + // 说明使用的是纯原生的vxe-table + return; + } + // update-end--author:liaozhiyang---date:20250429---for:【issues/8178】使用原生vxe-table组件编辑模式下失去焦点报错 let { $event } = params; const interceptor = getEnhanced(col.type).interceptor; // 执行增强 From 3b34276cf81ea691dc4da1fd89ab6f5b9e483684 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Sun, 4 May 2025 16:34:12 +0800 Subject: [PATCH 04/12] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=80=E4=B8=AAUI?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E9=80=89=E4=BA=BA=EF=BC=8C=E6=9B=B4=E5=8A=A0?= =?UTF-8?q?=E4=BE=BF=E6=8D=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jeecgboot-vue3/src/components/Form/index.ts | 1 + .../src/components/Form/src/componentMap.ts | 2 + .../components/JSelectUserByDepartment.vue | 176 ++++ .../modal/JSelectUserByDepartmentModal.vue | 833 ++++++++++++++++++ .../src/components/Form/src/types/index.ts | 1 + .../views/demo/jeecg/jeecgComponents.data.ts | 14 + .../src/views/system/notice/notice.data.ts | 2 +- 7 files changed, 1028 insertions(+), 1 deletion(-) create mode 100644 jeecgboot-vue3/src/components/Form/src/jeecg/components/JSelectUserByDepartment.vue create mode 100644 jeecgboot-vue3/src/components/Form/src/jeecg/components/modal/JSelectUserByDepartmentModal.vue diff --git a/jeecgboot-vue3/src/components/Form/index.ts b/jeecgboot-vue3/src/components/Form/index.ts index b18d36d05..f9f47b4d4 100644 --- a/jeecgboot-vue3/src/components/Form/index.ts +++ b/jeecgboot-vue3/src/components/Form/index.ts @@ -27,6 +27,7 @@ export { default as JDictSelectTag } from './src/jeecg/components/JDictSelectTag export { default as JTreeSelect } from './src/jeecg/components/JTreeSelect.vue'; export { default as JSearchSelect } from './src/jeecg/components/JSearchSelect.vue'; export { default as JSelectUserByDept } from './src/jeecg/components/JSelectUserByDept.vue'; +export { default as JSelectUserByDepartment } from './src/jeecg/components/JSelectUserByDepartment.vue'; export { default as JEditor } from './src/jeecg/components/JEditor.vue'; export { default as JImageUpload } from './src/jeecg/components/JImageUpload.vue'; // Jeecg自定义校验 diff --git a/jeecgboot-vue3/src/components/Form/src/componentMap.ts b/jeecgboot-vue3/src/components/Form/src/componentMap.ts index 2e17b624c..dc098c48a 100644 --- a/jeecgboot-vue3/src/components/Form/src/componentMap.ts +++ b/jeecgboot-vue3/src/components/Form/src/componentMap.ts @@ -64,6 +64,7 @@ import JInput from './jeecg/components/JInput.vue'; import JTreeSelect from './jeecg/components/JTreeSelect.vue'; import JEllipsis from './jeecg/components/JEllipsis.vue'; import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue'; +import JSelectUserByDepartment from './jeecg/components/JSelectUserByDepartment.vue'; import JUpload from './jeecg/components/JUpload/JUpload.vue'; import JSearchSelect from './jeecg/components/JSearchSelect.vue'; import JAddInput from './jeecg/components/JAddInput.vue'; @@ -159,6 +160,7 @@ componentMap.set('JInput', JInput); componentMap.set('JTreeSelect', JTreeSelect); componentMap.set('JEllipsis', JEllipsis); componentMap.set('JSelectUserByDept', JSelectUserByDept); +componentMap.set('JSelectUserByDepartment', JSelectUserByDepartment); componentMap.set('JUpload', JUpload); componentMap.set('JSearchSelect', JSearchSelect); componentMap.set('JAddInput', JAddInput); diff --git a/jeecgboot-vue3/src/components/Form/src/jeecg/components/JSelectUserByDepartment.vue b/jeecgboot-vue3/src/components/Form/src/jeecg/components/JSelectUserByDepartment.vue new file mode 100644 index 000000000..1fdd5d3a7 --- /dev/null +++ b/jeecgboot-vue3/src/components/Form/src/jeecg/components/JSelectUserByDepartment.vue @@ -0,0 +1,176 @@ + + + + diff --git a/jeecgboot-vue3/src/components/Form/src/jeecg/components/modal/JSelectUserByDepartmentModal.vue b/jeecgboot-vue3/src/components/Form/src/jeecg/components/modal/JSelectUserByDepartmentModal.vue new file mode 100644 index 000000000..1e533f5a6 --- /dev/null +++ b/jeecgboot-vue3/src/components/Form/src/jeecg/components/modal/JSelectUserByDepartmentModal.vue @@ -0,0 +1,833 @@ + + + + + diff --git a/jeecgboot-vue3/src/components/Form/src/types/index.ts b/jeecgboot-vue3/src/components/Form/src/types/index.ts index 560c949c4..286cbd886 100644 --- a/jeecgboot-vue3/src/components/Form/src/types/index.ts +++ b/jeecgboot-vue3/src/components/Form/src/types/index.ts @@ -139,6 +139,7 @@ export type ComponentType = | 'JTreeSelect' | 'JEllipsis' | 'JSelectUserByDept' + | 'JSelectUserByDepartment' | 'JUpload' | 'JSearchSelect' | 'JAddInput' diff --git a/jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts b/jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts index 9f5a133a5..a8dc6a030 100644 --- a/jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts +++ b/jeecgboot-vue3/src/views/demo/jeecg/jeecgComponents.data.ts @@ -258,6 +258,20 @@ export const schemas: FormSchema[] = [ label: '选中用户', colProps: { span: 12 }, }, + { + field: 'user4', + component: 'JSelectUserByDepartment', + label: '部门选择用户', + helpMessage: ['component模式'], + defaultValue: '', + componentProps: { + labelKey: 'realname', + rowKey: 'username', + }, + colProps: { + span: 12, + }, + }, { field: 'role2', component: 'JSelectRole', diff --git a/jeecgboot-vue3/src/views/system/notice/notice.data.ts b/jeecgboot-vue3/src/views/system/notice/notice.data.ts index 64ce2756d..7b4a498db 100644 --- a/jeecgboot-vue3/src/views/system/notice/notice.data.ts +++ b/jeecgboot-vue3/src/views/system/notice/notice.data.ts @@ -144,7 +144,7 @@ export const formSchema: FormSchema[] = [ { field: 'userIds', label: '指定用户', - component: 'JSelectUser', + component: 'JSelectUserByDepartment', required: true, componentProps: { rowKey: 'id', From 77ae25b86ac13a5cc44b58b2c8afa046460eee38 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Sun, 4 May 2025 17:28:30 +0800 Subject: [PATCH 05/12] =?UTF-8?q?=E8=A7=A3=E5=86=B3jeecg-boot-V3.8.0?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E4=B8=8B=E6=8B=89=E6=A0=91=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=97=B6=E9=AB=98=E9=A2=91=E7=8E=87=E6=8A=A5=E9=94=99UT005071:?= =?UTF-8?q?=20Undertow=20request=20failed=20HttpServerExchange{=20GET=20/s?= =?UTF-8?q?ys/dict/loadTreeData}=20#8217?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actuator/undertow/CustomUndertowMetricsHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java index b60432b3d..f80e20a79 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/monitor/actuator/undertow/CustomUndertowMetricsHandler.java @@ -78,7 +78,9 @@ public class CustomUndertowMetricsHandler { // 获取当前 session,如果不存在则创建 Session session = sessionManager.getSession(exchange, sessionConfig); if (session == null) { - sessionManager.createSession(exchange, sessionConfig); + try { + sessionManager.createSession(exchange, sessionConfig); + } catch (Exception e) {} } // 执行下一个 Handler From fe9630d15c26ef4ad5e3263a88ff6820681de9d9 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Tue, 6 May 2025 09:24:20 +0800 Subject: [PATCH 06/12] =?UTF-8?q?=E3=80=90issues/8211=E3=80=91=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E9=80=BB=E8=BE=91=E5=86=99=E7=9A=84=E6=9C=89=E9=97=AE?= =?UTF-8?q?=E9=A2=98--=20org/jeecg/config/firewall/interceptor/LowCodeMode?= =?UTF-8?q?Interceptor.java?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/firewall/interceptor/LowCodeModeInterceptor.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java index 7b03a657d..9bdcbd643 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/firewall/interceptor/LowCodeModeInterceptor.java @@ -6,15 +6,12 @@ import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.vo.Result; import org.jeecg.common.constant.CommonConstant; -import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.util.CommonUtils; import org.jeecg.common.util.SpringContextUtils; import org.jeecg.config.JeecgBaseConfig; -import org.jeecg.config.firewall.interceptor.enums.LowCodeUrlsEnum; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.AntPathMatcher; import org.springframework.web.servlet.HandlerInterceptor; import javax.annotation.Resource; @@ -70,6 +67,9 @@ public class LowCodeModeInterceptor implements HandlerInterceptor { Set hasRoles = null; if (loginUser == null) { loginUser = commonAPI.getUserByName(JwtUtil.getUserNameByToken(SpringContextUtils.getHttpServletRequest())); + } + + if (loginUser != null) { //当前登录人拥有的角色 hasRoles = commonAPI.queryUserRolesById(loginUser.getId()); } From 590d73dfe3521765fd1a04b34034a6948887b3fb Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Tue, 6 May 2025 16:01:31 +0800 Subject: [PATCH 07/12] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jeecg/modules/openapi/controller/OpenApiController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java index 7bbc9b8e7..63059bc33 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java @@ -353,7 +353,7 @@ public class OpenApiController extends JeecgController SwaggerInfo info = new SwaggerInfo(); info.setDescription("OpenAPI 接口列表"); - info.setVersion("3.7.1"); + info.setVersion("3.8.0"); info.setTitle("OpenAPI 接口列表"); info.setTermsOfService("https://jeecg.com"); From 94bff11eb1cec69cff610f16587ce0642cac04d1 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Wed, 7 May 2025 13:37:54 +0800 Subject: [PATCH 08/12] =?UTF-8?q?=E7=A7=BB=E9=99=A4sqlparse=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=94=B9=E8=B0=83minidao=E6=96=B9=E6=B3=95=E3=80=81?= =?UTF-8?q?=E5=8D=87=E7=BA=A7fastjson=E7=89=88=E6=9C=AC=E5=8F=B7=E5=88=B02?= =?UTF-8?q?.0.57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jeecg-boot/jeecg-boot-base-core/pom.xml | 5 + .../sqlparse/JSqlParserAllTableManager.java | 510 +++++++++--------- .../common/util/sqlparse/JSqlParserUtils.java | 380 ++++++------- .../util/sqlparse/vo/SelectSqlInfo.java | 202 +++---- .../impl/DictTableWhiteListHandlerImpl.java | 8 +- jeecg-boot/pom.xml | 29 +- 6 files changed, 578 insertions(+), 556 deletions(-) diff --git a/jeecg-boot/jeecg-boot-base-core/pom.xml b/jeecg-boot/jeecg-boot-base-core/pom.xml index 1f62b586f..9ad9b1ee9 100644 --- a/jeecg-boot/jeecg-boot-base-core/pom.xml +++ b/jeecg-boot/jeecg-boot-base-core/pom.xml @@ -314,5 +314,10 @@ org.jeecgframework.boot jeecg-boot-starter-chatgpt + + + org.jeecgframework + minidao-spring-boot-starter + \ No newline at end of file diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserAllTableManager.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserAllTableManager.java index 1482a0412..ce6eefd26 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserAllTableManager.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserAllTableManager.java @@ -1,255 +1,255 @@ -package org.jeecg.common.util.sqlparse; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.*; -import net.sf.jsqlparser.parser.CCJSqlParserManager; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.select.*; -import org.jeecg.common.exception.JeecgBootException; -import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; - -import java.io.StringReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * 解析所有表名和字段的类 - */ -@Slf4j -public class JSqlParserAllTableManager { - - private final String sql; - private final Map allTableMap = new HashMap<>(); - /** - * 别名对应实际表名 - */ - private final Map tableAliasMap = new HashMap<>(); - - /** - * 解析后的sql - */ - private String parsedSql = null; - - JSqlParserAllTableManager(String selectSql) { - this.sql = selectSql; - } - - /** - * 开始解析 - * - * @return - * @throws JSQLParserException - */ - public Map parse() throws JSQLParserException { - // 1. 创建解析器 - CCJSqlParserManager mgr = new CCJSqlParserManager(); - // 2. 使用解析器解析sql生成具有层次结构的java类 - Statement stmt = mgr.parse(new StringReader(this.sql)); - if (stmt instanceof Select) { - Select selectStatement = (Select) stmt; - SelectBody selectBody = selectStatement.getSelectBody(); - this.parsedSql = selectBody.toString(); - // 3. 解析select查询sql的信息 - if (selectBody instanceof PlainSelect) { - PlainSelect plainSelect = (PlainSelect) selectBody; - // 4. 合并 fromItems - List fromItems = new ArrayList<>(); - fromItems.add(plainSelect.getFromItem()); - // 4.1 处理join的表 - List joins = plainSelect.getJoins(); - if (joins != null) { - joins.forEach(join -> fromItems.add(join.getRightItem())); - } - // 5. 处理 fromItems - for (FromItem fromItem : fromItems) { - // 5.1 通过表名的方式from - if (fromItem instanceof Table) { - this.addSqlInfoByTable((Table) fromItem); - } - // 5.2 通过子查询的方式from - else if (fromItem instanceof SubSelect) { - this.handleSubSelect((SubSelect) fromItem); - } - } - // 6. 解析 selectFields - List selectItems = plainSelect.getSelectItems(); - for (SelectItem selectItem : selectItems) { - // 6.1 查询的是全部字段 - if (selectItem instanceof AllColumns) { - // 当 selectItem 为 AllColumns 时,fromItem 必定为 Table - String tableName = plainSelect.getFromItem(Table.class).getName(); - // 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中 - SelectSqlInfo sqlInfo = this.allTableMap.get(tableName); - assert sqlInfo != null; - // 设置为查询全部字段 - sqlInfo.setSelectAll(true); - sqlInfo.setSelectFields(null); - sqlInfo.setRealSelectFields(null); - } - // 6.2 查询的是带表别名( u.* )的全部字段 - else if (selectItem instanceof AllTableColumns) { - AllTableColumns allTableColumns = (AllTableColumns) selectItem; - String aliasName = allTableColumns.getTable().getName(); - // 通过别名获取表名 - String tableName = this.tableAliasMap.get(aliasName); - if (tableName == null) { - tableName = aliasName; - } - SelectSqlInfo sqlInfo = this.allTableMap.get(tableName); - // 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理 - if (sqlInfo != null) { - // 设置为查询全部字段 - sqlInfo.setSelectAll(true); - sqlInfo.setSelectFields(null); - sqlInfo.setRealSelectFields(null); - } - } - // 6.3 各种字段表达式处理 - else if (selectItem instanceof SelectExpressionItem) { - SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; - Expression expression = selectExpressionItem.getExpression(); - Alias alias = selectExpressionItem.getAlias(); - this.handleExpression(expression, alias, plainSelect.getFromItem()); - } - } - } else { - log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName()); - throw new JeecgBootException("暂时尚未处理该类型的 SelectBody"); - } - } else { - // 非 select 查询sql,不做处理 - throw new JeecgBootException("非 select 查询sql,不做处理"); - } - return this.allTableMap; - } - - /** - * 处理子查询 - * - * @param subSelect - */ - private void handleSubSelect(SubSelect subSelect) { - try { - String subSelectSql = subSelect.getSelectBody().toString(); - // 递归调用解析 - Map map = JSqlParserUtils.parseAllSelectTable(subSelectSql); - if (map != null) { - this.assignMap(map); - } - } catch (Exception e) { - log.error("解析子查询出错", e); - } - } - - /** - * 处理查询字段表达式 - * - * @param expression - */ - private void handleExpression(Expression expression, Alias alias, FromItem fromItem) { - // 处理函数式字段 CONCAT(name,'(',age,')') - if (expression instanceof Function) { - Function functionExp = (Function) expression; - List expressions = functionExp.getParameters().getExpressions(); - for (Expression expItem : expressions) { - this.handleExpression(expItem, null, fromItem); - } - return; - } - // 处理字段上的子查询 - if (expression instanceof SubSelect) { - this.handleSubSelect((SubSelect) expression); - return; - } - // 不处理字面量 - if (expression instanceof StringValue || - expression instanceof NullValue || - expression instanceof LongValue || - expression instanceof DoubleValue || - expression instanceof HexValue || - expression instanceof DateValue || - expression instanceof TimestampValue || - expression instanceof TimeValue - ) { - return; - } - - // 处理字段 - if (expression instanceof Column) { - Column column = (Column) expression; - // 查询字段名 - String fieldName = column.getColumnName(); - String aliasName = fieldName; - if (alias != null) { - aliasName = alias.getName(); - } - String tableName; - if (column.getTable() != null) { - // 通过列的表名获取 sqlInfo - // 例如 user.name,这里的 tableName 就是 user - tableName = column.getTable().getName(); - // 有可能是别名,需要转换为真实表名 - if (this.tableAliasMap.get(tableName) != null) { - tableName = this.tableAliasMap.get(tableName); - } - } else { - // 当column的table为空时,说明是 fromItem 中的字段 - tableName = ((Table) fromItem).getName(); - } - SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName); - if ($sqlInfo != null) { - $sqlInfo.addSelectField(aliasName, fieldName); - } else { - log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName); - } - } - } - - /** - * 根据表名添加sqlInfo - * - * @param table - */ - private void addSqlInfoByTable(Table table) { - String tableName = table.getName(); - // 解析 aliasName - if (table.getAlias() != null) { - this.tableAliasMap.put(table.getAlias().getName(), tableName); - } - SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql); - sqlInfo.setFromTableName(table.getName()); - this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo); - } - - /** - * 合并map - * - * @param source - */ - private void assignMap(Map source) { - for (Map.Entry entry : source.entrySet()) { - SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey()); - if (sqlInfo == null) { - this.allTableMap.put(entry.getKey(), entry.getValue()); - } else { - // 合并 - if (sqlInfo.getSelectFields() == null) { - sqlInfo.setSelectFields(entry.getValue().getSelectFields()); - } else { - sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields()); - } - if (sqlInfo.getRealSelectFields() == null) { - sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields()); - } else { - sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields()); - } - } - } - } - -} +//package org.jeecg.common.util.sqlparse; +// +//import lombok.extern.slf4j.Slf4j; +//import net.sf.jsqlparser.JSQLParserException; +//import net.sf.jsqlparser.expression.*; +//import net.sf.jsqlparser.parser.CCJSqlParserManager; +//import net.sf.jsqlparser.schema.Column; +//import net.sf.jsqlparser.schema.Table; +//import net.sf.jsqlparser.statement.Statement; +//import net.sf.jsqlparser.statement.select.*; +//import org.jeecg.common.exception.JeecgBootException; +//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; +// +//import java.io.StringReader; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.List; +//import java.util.Map; +// +///** +// * 解析所有表名和字段的类 +// */ +//@Slf4j +//public class JSqlParserAllTableManager { +// +// private final String sql; +// private final Map allTableMap = new HashMap<>(); +// /** +// * 别名对应实际表名 +// */ +// private final Map tableAliasMap = new HashMap<>(); +// +// /** +// * 解析后的sql +// */ +// private String parsedSql = null; +// +// JSqlParserAllTableManager(String selectSql) { +// this.sql = selectSql; +// } +// +// /** +// * 开始解析 +// * +// * @return +// * @throws JSQLParserException +// */ +// public Map parse() throws JSQLParserException { +// // 1. 创建解析器 +// CCJSqlParserManager mgr = new CCJSqlParserManager(); +// // 2. 使用解析器解析sql生成具有层次结构的java类 +// Statement stmt = mgr.parse(new StringReader(this.sql)); +// if (stmt instanceof Select) { +// Select selectStatement = (Select) stmt; +// SelectBody selectBody = selectStatement.getSelectBody(); +// this.parsedSql = selectBody.toString(); +// // 3. 解析select查询sql的信息 +// if (selectBody instanceof PlainSelect) { +// PlainSelect plainSelect = (PlainSelect) selectBody; +// // 4. 合并 fromItems +// List fromItems = new ArrayList<>(); +// fromItems.add(plainSelect.getFromItem()); +// // 4.1 处理join的表 +// List joins = plainSelect.getJoins(); +// if (joins != null) { +// joins.forEach(join -> fromItems.add(join.getRightItem())); +// } +// // 5. 处理 fromItems +// for (FromItem fromItem : fromItems) { +// // 5.1 通过表名的方式from +// if (fromItem instanceof Table) { +// this.addSqlInfoByTable((Table) fromItem); +// } +// // 5.2 通过子查询的方式from +// else if (fromItem instanceof SubSelect) { +// this.handleSubSelect((SubSelect) fromItem); +// } +// } +// // 6. 解析 selectFields +// List selectItems = plainSelect.getSelectItems(); +// for (SelectItem selectItem : selectItems) { +// // 6.1 查询的是全部字段 +// if (selectItem instanceof AllColumns) { +// // 当 selectItem 为 AllColumns 时,fromItem 必定为 Table +// String tableName = plainSelect.getFromItem(Table.class).getName(); +// // 此处必定不为空,因为在解析 fromItem 时,已经将表名添加到 allTableMap 中 +// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName); +// assert sqlInfo != null; +// // 设置为查询全部字段 +// sqlInfo.setSelectAll(true); +// sqlInfo.setSelectFields(null); +// sqlInfo.setRealSelectFields(null); +// } +// // 6.2 查询的是带表别名( u.* )的全部字段 +// else if (selectItem instanceof AllTableColumns) { +// AllTableColumns allTableColumns = (AllTableColumns) selectItem; +// String aliasName = allTableColumns.getTable().getName(); +// // 通过别名获取表名 +// String tableName = this.tableAliasMap.get(aliasName); +// if (tableName == null) { +// tableName = aliasName; +// } +// SelectSqlInfo sqlInfo = this.allTableMap.get(tableName); +// // 如果此处为空,则说明该字段是通过子查询获取的,所以可以不处理,只有实际表才需要处理 +// if (sqlInfo != null) { +// // 设置为查询全部字段 +// sqlInfo.setSelectAll(true); +// sqlInfo.setSelectFields(null); +// sqlInfo.setRealSelectFields(null); +// } +// } +// // 6.3 各种字段表达式处理 +// else if (selectItem instanceof SelectExpressionItem) { +// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; +// Expression expression = selectExpressionItem.getExpression(); +// Alias alias = selectExpressionItem.getAlias(); +// this.handleExpression(expression, alias, plainSelect.getFromItem()); +// } +// } +// } else { +// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName()); +// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody"); +// } +// } else { +// // 非 select 查询sql,不做处理 +// throw new JeecgBootException("非 select 查询sql,不做处理"); +// } +// return this.allTableMap; +// } +// +// /** +// * 处理子查询 +// * +// * @param subSelect +// */ +// private void handleSubSelect(SubSelect subSelect) { +// try { +// String subSelectSql = subSelect.getSelectBody().toString(); +// // 递归调用解析 +// Map map = JSqlParserUtils.parseAllSelectTable(subSelectSql); +// if (map != null) { +// this.assignMap(map); +// } +// } catch (Exception e) { +// log.error("解析子查询出错", e); +// } +// } +// +// /** +// * 处理查询字段表达式 +// * +// * @param expression +// */ +// private void handleExpression(Expression expression, Alias alias, FromItem fromItem) { +// // 处理函数式字段 CONCAT(name,'(',age,')') +// if (expression instanceof Function) { +// Function functionExp = (Function) expression; +// List expressions = functionExp.getParameters().getExpressions(); +// for (Expression expItem : expressions) { +// this.handleExpression(expItem, null, fromItem); +// } +// return; +// } +// // 处理字段上的子查询 +// if (expression instanceof SubSelect) { +// this.handleSubSelect((SubSelect) expression); +// return; +// } +// // 不处理字面量 +// if (expression instanceof StringValue || +// expression instanceof NullValue || +// expression instanceof LongValue || +// expression instanceof DoubleValue || +// expression instanceof HexValue || +// expression instanceof DateValue || +// expression instanceof TimestampValue || +// expression instanceof TimeValue +// ) { +// return; +// } +// +// // 处理字段 +// if (expression instanceof Column) { +// Column column = (Column) expression; +// // 查询字段名 +// String fieldName = column.getColumnName(); +// String aliasName = fieldName; +// if (alias != null) { +// aliasName = alias.getName(); +// } +// String tableName; +// if (column.getTable() != null) { +// // 通过列的表名获取 sqlInfo +// // 例如 user.name,这里的 tableName 就是 user +// tableName = column.getTable().getName(); +// // 有可能是别名,需要转换为真实表名 +// if (this.tableAliasMap.get(tableName) != null) { +// tableName = this.tableAliasMap.get(tableName); +// } +// } else { +// // 当column的table为空时,说明是 fromItem 中的字段 +// tableName = ((Table) fromItem).getName(); +// } +// SelectSqlInfo $sqlInfo = this.allTableMap.get(tableName); +// if ($sqlInfo != null) { +// $sqlInfo.addSelectField(aliasName, fieldName); +// } else { +// log.warn("发生意外情况,未找到表名为 {} 的 SelectSqlInfo", tableName); +// } +// } +// } +// +// /** +// * 根据表名添加sqlInfo +// * +// * @param table +// */ +// private void addSqlInfoByTable(Table table) { +// String tableName = table.getName(); +// // 解析 aliasName +// if (table.getAlias() != null) { +// this.tableAliasMap.put(table.getAlias().getName(), tableName); +// } +// SelectSqlInfo sqlInfo = new SelectSqlInfo(this.parsedSql); +// sqlInfo.setFromTableName(table.getName()); +// this.allTableMap.put(sqlInfo.getFromTableName(), sqlInfo); +// } +// +// /** +// * 合并map +// * +// * @param source +// */ +// private void assignMap(Map source) { +// for (Map.Entry entry : source.entrySet()) { +// SelectSqlInfo sqlInfo = this.allTableMap.get(entry.getKey()); +// if (sqlInfo == null) { +// this.allTableMap.put(entry.getKey(), entry.getValue()); +// } else { +// // 合并 +// if (sqlInfo.getSelectFields() == null) { +// sqlInfo.setSelectFields(entry.getValue().getSelectFields()); +// } else { +// sqlInfo.getSelectFields().addAll(entry.getValue().getSelectFields()); +// } +// if (sqlInfo.getRealSelectFields() == null) { +// sqlInfo.setRealSelectFields(entry.getValue().getRealSelectFields()); +// } else { +// sqlInfo.getRealSelectFields().addAll(entry.getValue().getRealSelectFields()); +// } +// } +// } +// } +// +//} diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserUtils.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserUtils.java index 01373e4ff..e8788b718 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserUtils.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/JSqlParserUtils.java @@ -1,190 +1,190 @@ -package org.jeecg.common.util.sqlparse; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import net.sf.jsqlparser.expression.*; -import net.sf.jsqlparser.parser.CCJSqlParserManager; -import net.sf.jsqlparser.schema.Column; -import net.sf.jsqlparser.schema.Table; -import net.sf.jsqlparser.statement.Statement; -import net.sf.jsqlparser.statement.select.*; -import org.jeecg.common.exception.JeecgBootException; -import org.jeecg.common.util.oConvertUtils; -import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; - -import java.io.StringReader; -import java.util.List; -import java.util.Map; - -@Slf4j -public class JSqlParserUtils { - - /** - * 解析 查询(select)sql的信息, - * 此方法会展开所有子查询到一个map里, - * key只存真实的表名,如果查询的没有真实的表名,则会被忽略。 - * value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。 - *

- * 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d - * 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]} - * - * @param selectSql - * @return - */ - public static Map parseAllSelectTable(String selectSql) throws JSQLParserException { - if (oConvertUtils.isEmpty(selectSql)) { - return null; - } - // log.info("解析查询Sql:{}", selectSql); - JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql); - return allTableManager.parse(); - } - - /** - * 解析 查询(select)sql的信息,子查询嵌套 - * - * @param selectSql - * @return - */ - public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException { - if (oConvertUtils.isEmpty(selectSql)) { - return null; - } - // log.info("解析查询Sql:{}", selectSql); - // 使用 JSqlParer 解析sql - // 1、创建解析器 - CCJSqlParserManager mgr = new CCJSqlParserManager(); - // 2、使用解析器解析sql生成具有层次结构的java类 - Statement stmt = mgr.parse(new StringReader(selectSql)); - if (stmt instanceof Select) { - Select selectStatement = (Select) stmt; - // 3、解析select查询sql的信息 - return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody()); - } else { - // 非 select 查询sql,不做处理 - throw new JeecgBootException("非 select 查询sql,不做处理"); - } - } - - /** - * 解析 select 查询sql的信息 - * - * @param selectBody - * @return - */ - private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) { - // 判断是否使用了union等操作 - if (selectBody instanceof SetOperationList) { - // 如果使用了union等操作,则只解析第一个查询 - List selectBodyList = ((SetOperationList) selectBody).getSelects(); - return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0)); - } - // 简单的select查询 - if (selectBody instanceof PlainSelect) { - SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody); - PlainSelect plainSelect = (PlainSelect) selectBody; - FromItem fromItem = plainSelect.getFromItem(); - // 解析 aliasName - if (fromItem.getAlias() != null) { - sqlInfo.setFromTableAliasName(fromItem.getAlias().getName()); - } - // 解析 表名 - if (fromItem instanceof Table) { - // 通过表名的方式from - Table fromTable = (Table) fromItem; - sqlInfo.setFromTableName(fromTable.getName()); - } else if (fromItem instanceof SubSelect) { - // 通过子查询的方式from - SubSelect fromSubSelect = (SubSelect) fromItem; - SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody()); - sqlInfo.setFromSubSelect(subSqlInfo); - } - // 解析 selectFields - List selectItems = plainSelect.getSelectItems(); - for (SelectItem selectItem : selectItems) { - if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) { - // 全部字段 - sqlInfo.setSelectAll(true); - sqlInfo.setSelectFields(null); - sqlInfo.setRealSelectFields(null); - break; - } else if (selectItem instanceof SelectExpressionItem) { - // 获取单个查询字段名 - SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; - Expression expression = selectExpressionItem.getExpression(); - Alias alias = selectExpressionItem.getAlias(); - JSqlParserUtils.handleExpression(sqlInfo, expression, alias); - } - } - return sqlInfo; - } else { - log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName()); - throw new JeecgBootException("暂时尚未处理该类型的 SelectBody"); - } - } - - /** - * 处理查询字段表达式 - * - * @param sqlInfo - * @param expression - * @param alias 是否有别名,无传null - */ - private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) { - // 处理函数式字段 CONCAT(name,'(',age,')') - if (expression instanceof Function) { - JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo); - return; - } - // 处理字段上的子查询 - if (expression instanceof SubSelect) { - SubSelect subSelect = (SubSelect) expression; - SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody()); - // 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并 - sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields()); - sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields()); - return; - } - // 不处理字面量 - if (expression instanceof StringValue || - expression instanceof NullValue || - expression instanceof LongValue || - expression instanceof DoubleValue || - expression instanceof HexValue || - expression instanceof DateValue || - expression instanceof TimestampValue || - expression instanceof TimeValue - ) { - return; - } - - // 查询字段名 - String selectField = expression.toString(); - // 实际查询字段名 - String realSelectField = selectField; - // 判断是否有别名 - if (alias != null) { - selectField = alias.getName(); - } - // 获取真实字段名 - if (expression instanceof Column) { - Column column = (Column) expression; - realSelectField = column.getColumnName(); - } - sqlInfo.addSelectField(selectField, realSelectField); - } - - /** - * 处理函数式字段 - * - * @param functionExp - * @param sqlInfo - */ - private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) { - List expressions = functionExp.getParameters().getExpressions(); - for (Expression expression : expressions) { - JSqlParserUtils.handleExpression(sqlInfo, expression, null); - } - } - -} +//package org.jeecg.common.util.sqlparse; +// +//import lombok.extern.slf4j.Slf4j; +//import net.sf.jsqlparser.JSQLParserException; +//import net.sf.jsqlparser.expression.*; +//import net.sf.jsqlparser.parser.CCJSqlParserManager; +//import net.sf.jsqlparser.schema.Column; +//import net.sf.jsqlparser.schema.Table; +//import net.sf.jsqlparser.statement.Statement; +//import net.sf.jsqlparser.statement.select.*; +//import org.jeecg.common.exception.JeecgBootException; +//import org.jeecg.common.util.oConvertUtils; +//import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; +// +//import java.io.StringReader; +//import java.util.List; +//import java.util.Map; +// +//@Slf4j +//public class JSqlParserUtils { +// +// /** +// * 解析 查询(select)sql的信息, +// * 此方法会展开所有子查询到一个map里, +// * key只存真实的表名,如果查询的没有真实的表名,则会被忽略。 +// * value只存真实的字段名,如果查询的没有真实的字段名,则会被忽略。 +// *

+// * 例如:SELECT a.*,d.age,(SELECT count(1) FROM sys_depart) AS count FROM (SELECT username AS foo, realname FROM sys_user) a, demo d +// * 解析后的结果为:{sys_user=[username, realname], demo=[age], sys_depart=[]} +// * +// * @param selectSql +// * @return +// */ +// public static Map parseAllSelectTable(String selectSql) throws JSQLParserException { +// if (oConvertUtils.isEmpty(selectSql)) { +// return null; +// } +// // log.info("解析查询Sql:{}", selectSql); +// JSqlParserAllTableManager allTableManager = new JSqlParserAllTableManager(selectSql); +// return allTableManager.parse(); +// } +// +// /** +// * 解析 查询(select)sql的信息,子查询嵌套 +// * +// * @param selectSql +// * @return +// */ +// public static SelectSqlInfo parseSelectSqlInfo(String selectSql) throws JSQLParserException { +// if (oConvertUtils.isEmpty(selectSql)) { +// return null; +// } +// // log.info("解析查询Sql:{}", selectSql); +// // 使用 JSqlParer 解析sql +// // 1、创建解析器 +// CCJSqlParserManager mgr = new CCJSqlParserManager(); +// // 2、使用解析器解析sql生成具有层次结构的java类 +// Statement stmt = mgr.parse(new StringReader(selectSql)); +// if (stmt instanceof Select) { +// Select selectStatement = (Select) stmt; +// // 3、解析select查询sql的信息 +// return JSqlParserUtils.parseBySelectBody(selectStatement.getSelectBody()); +// } else { +// // 非 select 查询sql,不做处理 +// throw new JeecgBootException("非 select 查询sql,不做处理"); +// } +// } +// +// /** +// * 解析 select 查询sql的信息 +// * +// * @param selectBody +// * @return +// */ +// private static SelectSqlInfo parseBySelectBody(SelectBody selectBody) { +// // 判断是否使用了union等操作 +// if (selectBody instanceof SetOperationList) { +// // 如果使用了union等操作,则只解析第一个查询 +// List selectBodyList = ((SetOperationList) selectBody).getSelects(); +// return JSqlParserUtils.parseBySelectBody(selectBodyList.get(0)); +// } +// // 简单的select查询 +// if (selectBody instanceof PlainSelect) { +// SelectSqlInfo sqlInfo = new SelectSqlInfo(selectBody); +// PlainSelect plainSelect = (PlainSelect) selectBody; +// FromItem fromItem = plainSelect.getFromItem(); +// // 解析 aliasName +// if (fromItem.getAlias() != null) { +// sqlInfo.setFromTableAliasName(fromItem.getAlias().getName()); +// } +// // 解析 表名 +// if (fromItem instanceof Table) { +// // 通过表名的方式from +// Table fromTable = (Table) fromItem; +// sqlInfo.setFromTableName(fromTable.getName()); +// } else if (fromItem instanceof SubSelect) { +// // 通过子查询的方式from +// SubSelect fromSubSelect = (SubSelect) fromItem; +// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(fromSubSelect.getSelectBody()); +// sqlInfo.setFromSubSelect(subSqlInfo); +// } +// // 解析 selectFields +// List selectItems = plainSelect.getSelectItems(); +// for (SelectItem selectItem : selectItems) { +// if (selectItem instanceof AllColumns || selectItem instanceof AllTableColumns) { +// // 全部字段 +// sqlInfo.setSelectAll(true); +// sqlInfo.setSelectFields(null); +// sqlInfo.setRealSelectFields(null); +// break; +// } else if (selectItem instanceof SelectExpressionItem) { +// // 获取单个查询字段名 +// SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; +// Expression expression = selectExpressionItem.getExpression(); +// Alias alias = selectExpressionItem.getAlias(); +// JSqlParserUtils.handleExpression(sqlInfo, expression, alias); +// } +// } +// return sqlInfo; +// } else { +// log.warn("暂时尚未处理该类型的 SelectBody: {}", selectBody.getClass().getName()); +// throw new JeecgBootException("暂时尚未处理该类型的 SelectBody"); +// } +// } +// +// /** +// * 处理查询字段表达式 +// * +// * @param sqlInfo +// * @param expression +// * @param alias 是否有别名,无传null +// */ +// private static void handleExpression(SelectSqlInfo sqlInfo, Expression expression, Alias alias) { +// // 处理函数式字段 CONCAT(name,'(',age,')') +// if (expression instanceof Function) { +// JSqlParserUtils.handleFunctionExpression((Function) expression, sqlInfo); +// return; +// } +// // 处理字段上的子查询 +// if (expression instanceof SubSelect) { +// SubSelect subSelect = (SubSelect) expression; +// SelectSqlInfo subSqlInfo = JSqlParserUtils.parseBySelectBody(subSelect.getSelectBody()); +// // 注:字段上的子查询,必须只查询一个字段,否则会报错,所以可以放心合并 +// sqlInfo.getSelectFields().addAll(subSqlInfo.getSelectFields()); +// sqlInfo.getRealSelectFields().addAll(subSqlInfo.getAllRealSelectFields()); +// return; +// } +// // 不处理字面量 +// if (expression instanceof StringValue || +// expression instanceof NullValue || +// expression instanceof LongValue || +// expression instanceof DoubleValue || +// expression instanceof HexValue || +// expression instanceof DateValue || +// expression instanceof TimestampValue || +// expression instanceof TimeValue +// ) { +// return; +// } +// +// // 查询字段名 +// String selectField = expression.toString(); +// // 实际查询字段名 +// String realSelectField = selectField; +// // 判断是否有别名 +// if (alias != null) { +// selectField = alias.getName(); +// } +// // 获取真实字段名 +// if (expression instanceof Column) { +// Column column = (Column) expression; +// realSelectField = column.getColumnName(); +// } +// sqlInfo.addSelectField(selectField, realSelectField); +// } +// +// /** +// * 处理函数式字段 +// * +// * @param functionExp +// * @param sqlInfo +// */ +// private static void handleFunctionExpression(Function functionExp, SelectSqlInfo sqlInfo) { +// List expressions = functionExp.getParameters().getExpressions(); +// for (Expression expression : expressions) { +// JSqlParserUtils.handleExpression(sqlInfo, expression, null); +// } +// } +// +//} diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/vo/SelectSqlInfo.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/vo/SelectSqlInfo.java index 1a3d4dd1b..8d0e1325b 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/vo/SelectSqlInfo.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/sqlparse/vo/SelectSqlInfo.java @@ -1,101 +1,101 @@ -package org.jeecg.common.util.sqlparse.vo; - -import lombok.Data; -import net.sf.jsqlparser.statement.select.SelectBody; - -import java.util.HashSet; -import java.util.Set; - -/** - * select 查询 sql 的信息 - */ -@Data -public class SelectSqlInfo { - - /** - * 查询的表名,如果是子查询,则此处为null - */ - private String fromTableName; - /** - * 表别名 - */ - private String fromTableAliasName; - /** - * 通过子查询获取的表信息,例如:select name from (select * from user) u - * 如果不是子查询,则为null - */ - private SelectSqlInfo fromSubSelect; - /** - * 查询的字段集合,如果是 * 则为null,如果设了别名则为别名 - */ - private Set selectFields; - /** - * 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名 - */ - private Set realSelectFields; - /** - * 是否是查询所有字段 - */ - private boolean selectAll; - - /** - * 解析之后的 SQL (关键字都是大写) - */ - private final String parsedSql; - - public SelectSqlInfo(String parsedSql) { - this.parsedSql = parsedSql; - } - - public SelectSqlInfo(SelectBody selectBody) { - this.parsedSql = selectBody.toString(); - } - - public void addSelectField(String selectField, String realSelectField) { - if (this.selectFields == null) { - this.selectFields = new HashSet<>(); - } - if (this.realSelectFields == null) { - this.realSelectFields = new HashSet<>(); - } - this.selectFields.add(selectField); - this.realSelectFields.add(realSelectField); - } - - /** - * 获取所有字段,包括子查询里的。 - * - * @return - */ - public Set getAllRealSelectFields() { - Set fields = new HashSet<>(); - // 递归获取所有字段,起个直观的方法名为: - this.recursiveGetAllFields(this, fields); - return fields; - } - - /** - * 递归获取所有字段 - */ - private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set fields) { - if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) { - fields.addAll(sqlInfo.getRealSelectFields()); - } - if (sqlInfo.getFromSubSelect() != null) { - recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields); - } - } - - @Override - public String toString() { - return "SelectSqlInfo{" + - "fromTableName='" + fromTableName + '\'' + - ", fromSubSelect=" + fromSubSelect + - ", aliasName='" + fromTableAliasName + '\'' + - ", selectFields=" + selectFields + - ", realSelectFields=" + realSelectFields + - ", selectAll=" + selectAll + - "}"; - } - -} +//package org.jeecg.common.util.sqlparse.vo; +// +//import lombok.Data; +//import net.sf.jsqlparser.statement.select.SelectBody; +// +//import java.util.HashSet; +//import java.util.Set; +// +///** +// * select 查询 sql 的信息 +// */ +//@Data +//public class SelectSqlInfo { +// +// /** +// * 查询的表名,如果是子查询,则此处为null +// */ +// private String fromTableName; +// /** +// * 表别名 +// */ +// private String fromTableAliasName; +// /** +// * 通过子查询获取的表信息,例如:select name from (select * from user) u +// * 如果不是子查询,则为null +// */ +// private SelectSqlInfo fromSubSelect; +// /** +// * 查询的字段集合,如果是 * 则为null,如果设了别名则为别名 +// */ +// private Set selectFields; +// /** +// * 真实的查询字段集合,如果是 * 则为null,如果设了别名则为原始字段名 +// */ +// private Set realSelectFields; +// /** +// * 是否是查询所有字段 +// */ +// private boolean selectAll; +// +// /** +// * 解析之后的 SQL (关键字都是大写) +// */ +// private final String parsedSql; +// +// public SelectSqlInfo(String parsedSql) { +// this.parsedSql = parsedSql; +// } +// +// public SelectSqlInfo(SelectBody selectBody) { +// this.parsedSql = selectBody.toString(); +// } +// +// public void addSelectField(String selectField, String realSelectField) { +// if (this.selectFields == null) { +// this.selectFields = new HashSet<>(); +// } +// if (this.realSelectFields == null) { +// this.realSelectFields = new HashSet<>(); +// } +// this.selectFields.add(selectField); +// this.realSelectFields.add(realSelectField); +// } +// +// /** +// * 获取所有字段,包括子查询里的。 +// * +// * @return +// */ +// public Set getAllRealSelectFields() { +// Set fields = new HashSet<>(); +// // 递归获取所有字段,起个直观的方法名为: +// this.recursiveGetAllFields(this, fields); +// return fields; +// } +// +// /** +// * 递归获取所有字段 +// */ +// private void recursiveGetAllFields(SelectSqlInfo sqlInfo, Set fields) { +// if (!sqlInfo.isSelectAll() && sqlInfo.getRealSelectFields() != null) { +// fields.addAll(sqlInfo.getRealSelectFields()); +// } +// if (sqlInfo.getFromSubSelect() != null) { +// recursiveGetAllFields(sqlInfo.getFromSubSelect(), fields); +// } +// } +// +// @Override +// public String toString() { +// return "SelectSqlInfo{" + +// "fromTableName='" + fromTableName + '\'' + +// ", fromSubSelect=" + fromSubSelect + +// ", aliasName='" + fromTableAliasName + '\'' + +// ", selectFields=" + selectFields + +// ", realSelectFields=" + realSelectFields + +// ", selectAll=" + selectAll + +// "}"; +// } +// +//} diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/firewall/SqlInjection/impl/DictTableWhiteListHandlerImpl.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/firewall/SqlInjection/impl/DictTableWhiteListHandlerImpl.java index 81f74fd9a..f4cf29c68 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/firewall/SqlInjection/impl/DictTableWhiteListHandlerImpl.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/config/firewall/SqlInjection/impl/DictTableWhiteListHandlerImpl.java @@ -4,14 +4,14 @@ import lombok.extern.slf4j.Slf4j; import org.jeecg.common.constant.SymbolConstant; import org.jeecg.common.exception.JeecgSqlInjectionException; import org.jeecg.common.util.oConvertUtils; -import org.jeecg.common.util.sqlparse.JSqlParserUtils; -import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; import org.jeecg.config.JeecgBaseConfig; import org.jeecg.config.firewall.SqlInjection.IDictTableWhiteListHandler; import org.jeecg.config.firewall.interceptor.LowCodeModeInterceptor; import org.jeecg.modules.system.entity.SysTableWhiteList; import org.jeecg.modules.system.security.DictQueryBlackListHandler; import org.jeecg.modules.system.service.ISysTableWhiteListService; +import org.jeecgframework.minidao.sqlparser.impl.vo.SelectSqlInfo; +import org.jeecgframework.minidao.util.MiniDaoUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -65,7 +65,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler public boolean isPassBySql(String sql) { Map parsedMap = null; try { - parsedMap = JSqlParserUtils.parseAllSelectTable(sql); + parsedMap = MiniDaoUtil.parseAllSelectTable(sql); } catch (Exception e) { log.warn("校验sql语句,解析报错:{}", e.getMessage()); } @@ -127,7 +127,7 @@ public class DictTableWhiteListHandlerImpl implements IDictTableWhiteListHandler log.info("字典拼接的查询SQL:{}", sql); try { // 进行SQL解析 - JSqlParserUtils.parseSelectSqlInfo(sql); + MiniDaoUtil.parseSelectSqlInfo(sql); } catch (Exception e) { // 如果SQL解析失败,则通过字段名和表名进行校验 return checkWhiteList(tableName, new HashSet<>(Arrays.asList(fields))); diff --git a/jeecg-boot/pom.xml b/jeecg-boot/pom.xml index 56492188a..8498c278d 100644 --- a/jeecg-boot/pom.xml +++ b/jeecg-boot/pom.xml @@ -40,7 +40,7 @@ 1.5.2 2.4.1 - 2.0.56 + 2.0.57 5.2.6 1.6.0 0.17.0 @@ -56,7 +56,8 @@ 8.1.1.49 - 1.9.5 + 1.9.5.1 + 1.10.7 3.5.3.2 4.1.3 @@ -254,7 +255,7 @@ org.jeecgframework.boot hibernate-re - 3.8.0-GA + 3.8.0.1 @@ -359,7 +360,7 @@ org.jeecgframework weixin4j - 2.0.2 + 2.0.4 commons-beanutils @@ -383,6 +384,22 @@ + + + org.jeecgframework + minidao-spring-boot-starter + ${minidao.version} + + + druid + com.alibaba + + + jsqlparser + com.github.jsqlparser + + + org.jeecgframework.jimureport @@ -418,7 +435,7 @@ org.jeecgframework.jimureport jimureport-nosql-starter - ${jimureport-spring-boot-starter.version} + 1.9.5.2 org.apache.calcite @@ -430,7 +447,7 @@ org.jeecgframework.jimureport jimubi-spring-boot-starter - 1.9.4 + 1.9.5 From 86a3ed9daeafb4ecaf26ad5745705942305b0546 Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Fri, 9 May 2025 10:11:33 +0800 Subject: [PATCH 09/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0OpenApiController?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=88=9B=E5=BB=BA=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=94=9F=E6=88=90token=E7=AD=BE=E5=90=8D=EF=BC=8C=E7=AE=80?= =?UTF-8?q?=E5=8C=96=E7=94=A8=E6=88=B7=E5=85=B3=E8=81=94=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeecg/modules/openapi/controller/OpenApiController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java index 63059bc33..7e14d796c 100644 --- a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/openapi/controller/OpenApiController.java @@ -182,7 +182,8 @@ public class OpenApiController extends JeecgController String appkey = request.getHeader("appkey"); OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey); - SysUser systemUser = sysUserService.getById(openApiAuth.getSystemUserId()); + //TODO 使用创建用户生成token签名,这样无需关联用户 + SysUser systemUser = sysUserService.getById(openApiAuth.getCreateBy()); String token = JwtUtil.sign(systemUser.getUsername(), systemUser.getPassword()); httpHeaders.put("X-Access-Token", Lists.newArrayList(token)); From 0e184eaa64966c6be5e8aabb32490136520c420b Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Fri, 9 May 2025 10:17:14 +0800 Subject: [PATCH 10/12] =?UTF-8?q?=E5=8D=87=E7=BA=A7shiro=E5=88=B02.0.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jeecg/common/util/encryption/AesEncryptUtil.java | 2 +- jeecg-boot/pom.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java index 670f3ebd6..6a4db4215 100644 --- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java +++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java @@ -1,6 +1,6 @@ package org.jeecg.common.util.encryption; -import org.apache.shiro.codec.Base64; +import org.apache.shiro.lang.codec.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; diff --git a/jeecg-boot/pom.xml b/jeecg-boot/pom.xml index 8498c278d..17dc0fd02 100644 --- a/jeecg-boot/pom.xml +++ b/jeecg-boot/pom.xml @@ -68,9 +68,9 @@ 2.1.0 3.11.2 - 1.13.0 - 4.5.0 + 2.0.4 3.2.3 + 4.5.0 1.4.9 1.4.11 8.0.3 @@ -255,7 +255,7 @@ org.jeecgframework.boot hibernate-re - 3.8.0.1 + 3.8.0.2 From 37c593e1d47987b922b50d15cb9d9cbe0521f19d Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Wed, 14 May 2025 15:04:57 +0800 Subject: [PATCH 11/12] =?UTF-8?q?=E5=88=A0=E9=99=A4jsqlparse=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sqlinjection/TestInjectWithSqlParser.java | 75 ------------ .../sqlinjection/TestSqlInjectForDict.java | 50 -------- .../TestSqlInjectForOnlineReport.java | 60 ---------- .../test/sqlinjection/TestSqlInjection.java | 103 ----------------- .../test/sqlparse/JSqlParserUtilsTest.java | 109 ------------------ 5 files changed, 397 deletions(-) delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestInjectWithSqlParser.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForDict.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForOnlineReport.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjection.java delete mode 100644 jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/JSqlParserUtilsTest.java diff --git a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestInjectWithSqlParser.java b/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestInjectWithSqlParser.java deleted file mode 100644 index e02311bf0..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestInjectWithSqlParser.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.jeecg.test.sqlinjection; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import org.jeecg.common.util.SqlInjectionUtil; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -/** - * SQL注入攻击检查测试 - * @author: liusq - * @date: 2023年09月08日 - */ -@Slf4j -public class TestInjectWithSqlParser { - /** - * 注入测试 - * - * @param sql - * @return - */ - private boolean isExistSqlInject(String sql) { - try { - SqlInjectionUtil.specialFilterContentForOnlineReport(sql); - return false; - } catch (Exception e) { - log.info("==================================================="); - return true; - } - } - - - @Test - public void test() throws JSQLParserException { - //不存在sql注入 - assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time")); - assertFalse(isExistSqlInject("select * from test")); - assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")")); - assertFalse(isExistSqlInject("WITH SUB1 AS (SELECT user FROM t1) SELECT * FROM T2 WHERE id > 123 ")); - - //存在sql注入 - assertTrue(isExistSqlInject("or 1= 1 --")); - assertTrue(isExistSqlInject("select * from test where sleep(%23)")); - assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));")); - assertTrue(isExistSqlInject("select * from users;show databases;")); - assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13")); - assertTrue(isExistSqlInject("update user set name = '123'")); - assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--")); - assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23")); - assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23")); - assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)")); - assertTrue(isExistSqlInject("select * from dc_device where id in (select id from other)")); - assertTrue(isExistSqlInject("select * from dc_device where 2=2.0 or 2 != 4")); - assertTrue(isExistSqlInject("select * from dc_device where 1!=2.0")); - assertTrue(isExistSqlInject("select * from dc_device where id=floor(2.0)")); - assertTrue(isExistSqlInject("select * from dc_device where not true")); - assertTrue(isExistSqlInject("select * from dc_device where 1 or id > 0")); - assertTrue(isExistSqlInject("select * from dc_device where 'tom' or id > 0")); - assertTrue(isExistSqlInject("select * from dc_device where '-2.3' ")); - assertTrue(isExistSqlInject("select * from dc_device where 2 ")); - assertTrue(isExistSqlInject("select * from dc_device where (3+2) ")); - assertTrue(isExistSqlInject("select * from dc_device where -1 IS TRUE")); - assertTrue(isExistSqlInject("select * from dc_device where 'hello' is null ")); - assertTrue(isExistSqlInject("select * from dc_device where '2022-10-31' and id > 0")); - assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1!=2.0 ")); - assertTrue(isExistSqlInject("select * from dc_device where id > 0 or 1 in (1,3,4) ")); - assertTrue(isExistSqlInject("select * from dc_device UNION select name from other")); - assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)")); - } - -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForDict.java b/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForDict.java deleted file mode 100644 index 75719ef2c..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForDict.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.jeecg.test.sqlinjection; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import org.jeecg.common.util.SqlInjectionUtil; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -/** - * SQL注入攻击检查测试 - * @author: liusq - * @date: 2023年09月08日 - */ -@Slf4j -public class TestSqlInjectForDict { - /** - * 注入测试 - * - * @param sql - * @return - */ - private boolean isExistSqlInject(String sql) { - try { - SqlInjectionUtil.specialFilterContentForDictSql(sql); - return false; - } catch (Exception e) { - log.info("==================================================="); - return true; - } - } - - - @Test - public void test() throws JSQLParserException { - //不存在sql注入 - assertFalse(isExistSqlInject("sys_user,realname,id")); - assertFalse(isExistSqlInject("oa_officialdoc_organcode,organ_name,id")); - assertFalse(isExistSqlInject("onl_cgform_head where table_type!=3 and copy_type=0,table_txt,table_name")); - assertFalse(isExistSqlInject("onl_cgform_head where copy_type = 0,table_txt,table_name")); - - //存在sql注入 - assertTrue(isExistSqlInject("or 1= 1 --")); - assertTrue(isExistSqlInject("select * from test where sleep(%23)")); - } - -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForOnlineReport.java b/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForOnlineReport.java deleted file mode 100644 index 537bd12a8..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjectForOnlineReport.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.jeecg.test.sqlinjection; - -import lombok.extern.slf4j.Slf4j; -import net.sf.jsqlparser.JSQLParserException; -import org.jeecg.common.util.SqlInjectionUtil; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -/** - * SQL注入攻击检查测试 - * @author: liusq - * @date: 2023年09月08日 - */ -@Slf4j -public class TestSqlInjectForOnlineReport { - /** - * 注入测试 - * - * @param sql - * @return - */ - private boolean isExistSqlInject(String sql) { - try { - SqlInjectionUtil.specialFilterContentForOnlineReport(sql); - return false; - } catch (Exception e) { - log.info("==================================================="); - return true; - } - } - - - @Test - public void test() throws JSQLParserException { - //不存在sql注入 - assertFalse(isExistSqlInject("select * from fm_time where dept_id=:sqlparamsmap.id and time=:sqlparamsmap.time")); - assertFalse(isExistSqlInject("select * from test")); - assertFalse(isExistSqlInject("select load_file(\"C:\\\\benben.txt\")")); - assertFalse(isExistSqlInject("select * from dc_device where id in (select id from other)")); - assertFalse(isExistSqlInject("select * from dc_device UNION select name from other")); - - //存在sql注入 - assertTrue(isExistSqlInject("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)")); - assertTrue(isExistSqlInject("or 1= 1 --")); - assertTrue(isExistSqlInject("select * from test where sleep(%23)")); - assertTrue(isExistSqlInject("select * from test where SLEEP(3)")); - assertTrue(isExistSqlInject("select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));")); - assertTrue(isExistSqlInject("select * from users;show databases;")); - assertTrue(isExistSqlInject("select * from dc_device where id=1 and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13")); - assertTrue(isExistSqlInject("update user set name = '123'")); - assertTrue(isExistSqlInject("SELECT * FROM users WHERE username = 'admin' AND password = '123456' OR 1=1;--")); - assertTrue(isExistSqlInject("select * from users where id=1 and (select count(*) from information_schema.tables where table_schema='数据库名')>4 %23")); - assertTrue(isExistSqlInject("select * from dc_device where sleep(5) %23")); - } - -} - diff --git a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjection.java b/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjection.java deleted file mode 100644 index f86ed04e4..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlinjection/TestSqlInjection.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.jeecg.test.sqlinjection; - -import com.baomidou.mybatisplus.core.toolkit.sql.SqlInjectionUtils; -import org.jeecg.common.util.SqlInjectionUtil; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -/** - * @Description: SQL注入测试类 - * @author: scott - * @date: 2023年08月14日 9:55 - */ -public class TestSqlInjection { - - - /** - * 表名带别名,同时有html编码字符 - */ - @Test - public void testSpecialSQL() { - String tableName = "sys_user t"; - //解决使用参数tableName=sys_user t&复测,漏洞仍然存在 - if (tableName.contains(" ")) { - tableName = tableName.substring(0, tableName.indexOf(" ")); - } - //【issues/4393】 sys_user , (sys_user), sys_user%20, %60sys_user%60 - String reg = "\\s+|\\(|\\)|`"; - tableName = tableName.replaceAll(reg, ""); - System.out.println(tableName); - } - - - /** - * 测试sql是否含sql注入风险 - *

- * mybatis plus的方法 - */ - @Test - public void sqlInjectionCheck() { - String sql = "select * from sys_user"; - System.out.println(SqlInjectionUtils.check(sql)); - } - - - /** - * 测试sql是否有SLEEP风险 - *

- * mybatisPlus的方法 - */ - @Test - public void sqlSleepCheck() { - SqlInjectionUtil.checkSqlAnnotation("(SELECT 6240 FROM (SELECT(SLEEP(5))and 1=2)vidl)"); - } - - /** - * 测试sql是否含sql注入风险 - *

- * 自定义方法 - */ - @Test - public void sqlInjectionCheck2() { - String sql = "select * from sys_user"; - SqlInjectionUtil.specialFilterContentForOnlineReport(sql); - } - - /** - * 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等) - *

- * 判断字段名是否符合规范 - */ - @Test - public void testFieldSpecification() { - List list = new ArrayList(); - list.add("Hello World!"); - list.add("Hello%20World!"); - list.add("HelloWorld!"); - list.add("Hello World"); - list.add("age"); - list.add("user_name"); - list.add("user_name%20"); - list.add("user_name%20 "); - - for (String input : list) { - boolean containsSpecialChars = isValidString(input); - System.out.println("input:" + input + " ,包含空格和特殊字符: " + containsSpecialChars); - } - } - - /** - * 字段定义只能是是字母 数字 下划线的组合(不允许有空格、转义字符串等) - * - * @param input - * @return - */ - private static boolean isValidString(String input) { - Pattern pattern = Pattern.compile("^[a-zA-Z0-9_]+$"); - return pattern.matcher(input).matches(); - } - -} diff --git a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/JSqlParserUtilsTest.java b/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/JSqlParserUtilsTest.java deleted file mode 100644 index 1efc9ee3f..000000000 --- a/jeecg-boot/jeecg-boot-base-core/src/test/java/org/jeecg/test/sqlparse/JSqlParserUtilsTest.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jeecg.test.sqlparse; - -import net.sf.jsqlparser.JSQLParserException; -import org.jeecg.common.util.oConvertUtils; -import org.jeecg.common.util.sqlparse.JSqlParserUtils; -import org.jeecg.common.util.sqlparse.vo.SelectSqlInfo; -import org.junit.jupiter.api.Test; - -import java.util.Map; - -/** - * 针对 JSqlParserUtils 的单元测试 - */ -public class JSqlParserUtilsTest { - - private static final String[] sqlList = new String[]{ - "select * from sys_user", - "select u.* from sys_user u", - "select u.*, c.name from sys_user u, demo c", - "select u.age, c.name from sys_user u, demo c", - "select sex, age, c.name from sys_user, demo c", - // 别名测试 - "select username as realname from sys_user", - "select username as realname, u.realname as aaa, u.id bbb from sys_user u", - // 不存在真实地查询字段 - "select count(1) from sys_user", - // 函数式字段 - "select max(sex), id from sys_user", - // 复杂嵌套函数式字段 - "select CONCAT(CONCAT(' _ ', sex), ' - ' , birthday) as info, id from sys_user", - // 更复杂的嵌套函数式字段 - "select CONCAT(CONCAT(101,'_',NULL, DATE(create_time),'_',sex),' - ',birthday) as info, id from sys_user", - // 子查询SQL - "select u.name1 as name2 from (select username as name1 from sys_user) u", - // 多层嵌套子查询SQL - "select u2.name2 as name3 from (select u1.name1 as name2 from (select username as name1 from sys_user) u1) u2", - // 字段子查询SQL - "select id, (select username as name1 from sys_user u2 where u1.id = u2.id) as name2 from sys_user u1", - // 带条件的SQL(不解析where条件里的字段,但不影响解析查询字段) - "select username as name1 from sys_user where realname LIKE '%张%'", - // 多重复杂关联表查询解析,包含的表为:sys_user, sys_depart, sys_dict_item, demo - "" + - "SELECT " + - " u.*, d.age, sd.item_text AS sex, (SELECT count(sd.id) FROM sys_depart sd) AS count " + - "FROM " + - " (SELECT sd.username AS foo, sd.realname FROM sys_user sd) u, " + - " demo d " + - "LEFT JOIN sys_dict_item AS sd ON d.sex = sd.item_value " + - "WHERE sd.dict_id = '3d9a351be3436fbefb1307d4cfb49bf2'", - }; - - @Test - public void testParseSelectSql() { - System.out.println("-----------------------------------------"); - for (String sql : sqlList) { - System.out.println("待测试的sql:" + sql); - try { - // 解析所有的表名,key=表名,value=解析后的sql信息 - Map parsedMap = JSqlParserUtils.parseAllSelectTable(sql); - assert parsedMap != null; - for (Map.Entry entry : parsedMap.entrySet()) { - System.out.println("表名:" + entry.getKey()); - this.printSqlInfo(entry.getValue(), 1); - } - } catch (JSQLParserException e) { - System.out.println("SQL解析出现异常:" + e.getMessage()); - } - System.out.println("-----------------------------------------"); - } - } - - private void printSqlInfo(SelectSqlInfo sqlInfo, int level) { - String beforeStr = this.getBeforeStr(level); - if (sqlInfo.getFromTableName() == null) { - // 子查询 - System.out.println(beforeStr + "子查询:" + sqlInfo.getFromSubSelect().getParsedSql()); - this.printSqlInfo(sqlInfo.getFromSubSelect(), level + 1); - } else { - // 非子查询 - System.out.println(beforeStr + "查询的表名:" + sqlInfo.getFromTableName()); - } - if (oConvertUtils.isNotEmpty(sqlInfo.getFromTableAliasName())) { - System.out.println(beforeStr + "查询的表别名:" + sqlInfo.getFromTableAliasName()); - } - if (sqlInfo.isSelectAll()) { - System.out.println(beforeStr + "查询的字段:*"); - } else { - System.out.println(beforeStr + "查询的字段:" + sqlInfo.getSelectFields()); - System.out.println(beforeStr + "真实的字段:" + sqlInfo.getRealSelectFields()); - if (sqlInfo.getFromTableName() == null) { - System.out.println(beforeStr + "所有的字段(包括子查询):" + sqlInfo.getAllRealSelectFields()); - } - } - } - - // 打印前缀,根据层级来打印 - private String getBeforeStr(int level) { - if (level == 0) { - return ""; - } - StringBuilder beforeStr = new StringBuilder(); - for (int i = 0; i < level; i++) { - beforeStr.append(" "); - } - beforeStr.append("- "); - return beforeStr.toString(); - } - -} From 9cf3328ea4d75d4c32fef9d184f1452fa17ee12f Mon Sep 17 00:00:00 2001 From: JEECG <445654970@qq.com> Date: Wed, 14 May 2025 18:33:15 +0800 Subject: [PATCH 12/12] =?UTF-8?q?uniapp3=E4=BB=A3=E7=A0=81=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=99=A8=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../uniapp3/${entityName}Data.tsi | 49 ++ .../uniapp3/${entityName}Form.vuei | 512 ++++++++++++++++++ .../uniapp3/${entityName}List.vuei | 148 +++++ 3 files changed, 709 insertions(+) create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Data.tsi create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei create mode 100644 jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}List.vuei diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Data.tsi b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Data.tsi new file mode 100644 index 000000000..da81ef377 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Data.tsi @@ -0,0 +1,49 @@ +import { render } from '@/common/renderUtils'; +//列表数据 +export const columns = [ + <#list columns as po> + <#if po.isShowList =='Y' && po.fieldName !='id' && po.fieldName !='delFlag'> + { + title: '${po.filedComment}', + align:"center", + <#if po.sort=='Y'> + sorter: true, + + <#if po.classType=='date'> + dataIndex: '${po.fieldName}', + <#elseif po.fieldDbType=='Blob'> + dataIndex: '${po.fieldName}String' + <#elseif po.classType=='umeditor'> + dataIndex: '${po.fieldName}', + <#elseif po.classType=='pca'> + dataIndex: '${po.fieldName}', + <#elseif po.classType=='file'> + dataIndex: '${po.fieldName}', + <#elseif po.classType=='image'> + dataIndex: '${po.fieldName}', + customRender:render.renderImage, + <#elseif po.classType=='switch'> + dataIndex: '${po.fieldName}', + <#assign switch_extend_arr=['Y','N']> + <#if po.dictField?default("")?contains("[")> + <#assign switch_extend_arr=po.dictField?eval> + + <#list switch_extend_arr as a> + <#if a_index == 0> + <#assign switch_extend_arr1=a> + <#else> + <#assign switch_extend_arr2=a> + + + customRender:({text}) => { + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) + }, + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user' || po.classType=='popup_dict'> + dataIndex: '${po.fieldName}_dictText' + <#else> + dataIndex: '${po.fieldName}' + + }, + + +]; \ No newline at end of file diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei new file mode 100644 index 000000000..b6332ab9d --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}Form.vuei @@ -0,0 +1,512 @@ +<#include "/common/utils.ftl"> + +{ +layout: 'default', +style: { +navigationStyle: 'custom', +navigationBarTitleText: '${tableVo.ftlDescription}', +}, +} + + + + + + + diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}List.vuei b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}List.vuei new file mode 100644 index 000000000..fae339fa6 --- /dev/null +++ b/jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/uniapp3/${entityName}List.vuei @@ -0,0 +1,148 @@ + +{ +layout: 'default', +style: { +navigationBarTitleText: '${tableVo.ftlDescription}', +navigationStyle: 'custom', +}, +} + + + + + +