Commit c925b3d1e8967189542f467e12357d9526e5fa14
1 parent
940773b4
JeecgBoot 3.3.0 版本发布(发布日期:20220725)
Showing
40 changed files
with
1023 additions
and
200 deletions
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/dto/message/MessageDTO.java
... | ... | @@ -4,6 +4,7 @@ import lombok.Data; |
4 | 4 | import org.jeecg.common.constant.CommonConstant; |
5 | 5 | |
6 | 6 | import java.io.Serializable; |
7 | +import java.util.Map; | |
7 | 8 | |
8 | 9 | /** |
9 | 10 | * 普通消息 |
... | ... | @@ -72,4 +73,18 @@ public class MessageDTO implements Serializable { |
72 | 73 | this.category = category; |
73 | 74 | } |
74 | 75 | |
76 | + /** | |
77 | + * 模板消息对应的模板编码 | |
78 | + */ | |
79 | + protected String templateCode; | |
80 | + /** | |
81 | + * 消息类型:org.jeecg.common.constant.enums.MessageTypeEnum | |
82 | + */ | |
83 | + protected String type; | |
84 | + | |
85 | + /** | |
86 | + * 解析模板内容 对应的数据 | |
87 | + */ | |
88 | + protected Map<String, Object> data; | |
89 | + | |
75 | 90 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
... | ... | @@ -40,6 +40,8 @@ public class PermissionDataAspect { |
40 | 40 | @Autowired |
41 | 41 | private CommonAPI commonApi; |
42 | 42 | |
43 | + private static final String SPOT_DO = ".do"; | |
44 | + | |
43 | 45 | @Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionData)") |
44 | 46 | public void pointCut() { |
45 | 47 | |
... | ... | @@ -113,7 +115,7 @@ public class PermissionDataAspect { |
113 | 115 | requestPath = requestPath.substring(0, requestPath.indexOf("&")); |
114 | 116 | } |
115 | 117 | if(requestPath.indexOf(QueryRuleEnum.EQ.getValue())!=-1){ |
116 | - if(requestPath.indexOf(CommonConstant.SPOT_DO)!=-1){ | |
118 | + if(requestPath.indexOf(SPOT_DO)!=-1){ | |
117 | 119 | requestPath = requestPath.substring(0,requestPath.indexOf(".do")+3); |
118 | 120 | }else{ |
119 | 121 | requestPath = requestPath.substring(0,requestPath.indexOf("?")); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/DynamicTable.java
0 → 100644
1 | +package org.jeecg.common.aspect.annotation; | |
2 | + | |
3 | +import java.lang.annotation.*; | |
4 | + | |
5 | +/** | |
6 | + * 动态table切换 | |
7 | + * | |
8 | + * @author :zyf | |
9 | + * @date:2020-04-25 | |
10 | + */ | |
11 | +@Target(ElementType.METHOD) | |
12 | +@Retention(RetentionPolicy.RUNTIME) | |
13 | +@Documented | |
14 | +public @interface DynamicTable { | |
15 | + /** | |
16 | + * 需要动态解析的表名 | |
17 | + * @return | |
18 | + */ | |
19 | + String value(); | |
20 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
... | ... | @@ -9,320 +9,321 @@ public interface CommonConstant { |
9 | 9 | /** |
10 | 10 | * 正常状态 |
11 | 11 | */ |
12 | - public static final Integer STATUS_NORMAL = 0; | |
12 | + Integer STATUS_NORMAL = 0; | |
13 | 13 | |
14 | 14 | /** |
15 | 15 | * 禁用状态 |
16 | 16 | */ |
17 | - public static final Integer STATUS_DISABLE = -1; | |
17 | + Integer STATUS_DISABLE = -1; | |
18 | 18 | |
19 | 19 | /** |
20 | 20 | * 删除标志 |
21 | 21 | */ |
22 | - public static final Integer DEL_FLAG_1 = 1; | |
22 | + Integer DEL_FLAG_1 = 1; | |
23 | 23 | |
24 | 24 | /** |
25 | 25 | * 未删除 |
26 | 26 | */ |
27 | - public static final Integer DEL_FLAG_0 = 0; | |
27 | + Integer DEL_FLAG_0 = 0; | |
28 | 28 | |
29 | 29 | /** |
30 | 30 | * 系统日志类型: 登录 |
31 | 31 | */ |
32 | - public static final int LOG_TYPE_1 = 1; | |
32 | + int LOG_TYPE_1 = 1; | |
33 | 33 | |
34 | 34 | /** |
35 | 35 | * 系统日志类型: 操作 |
36 | 36 | */ |
37 | - public static final int LOG_TYPE_2 = 2; | |
37 | + int LOG_TYPE_2 = 2; | |
38 | 38 | |
39 | 39 | /** |
40 | 40 | * 操作日志类型: 查询 |
41 | 41 | */ |
42 | - public static final int OPERATE_TYPE_1 = 1; | |
42 | + int OPERATE_TYPE_1 = 1; | |
43 | 43 | |
44 | 44 | /** |
45 | 45 | * 操作日志类型: 添加 |
46 | 46 | */ |
47 | - public static final int OPERATE_TYPE_2 = 2; | |
47 | + int OPERATE_TYPE_2 = 2; | |
48 | 48 | |
49 | 49 | /** |
50 | 50 | * 操作日志类型: 更新 |
51 | 51 | */ |
52 | - public static final int OPERATE_TYPE_3 = 3; | |
52 | + int OPERATE_TYPE_3 = 3; | |
53 | 53 | |
54 | 54 | /** |
55 | 55 | * 操作日志类型: 删除 |
56 | 56 | */ |
57 | - public static final int OPERATE_TYPE_4 = 4; | |
57 | + int OPERATE_TYPE_4 = 4; | |
58 | 58 | |
59 | 59 | /** |
60 | 60 | * 操作日志类型: 倒入 |
61 | 61 | */ |
62 | - public static final int OPERATE_TYPE_5 = 5; | |
62 | + int OPERATE_TYPE_5 = 5; | |
63 | 63 | |
64 | 64 | /** |
65 | 65 | * 操作日志类型: 导出 |
66 | 66 | */ |
67 | - public static final int OPERATE_TYPE_6 = 6; | |
67 | + int OPERATE_TYPE_6 = 6; | |
68 | 68 | |
69 | 69 | |
70 | 70 | /** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */ |
71 | - public static final Integer SC_INTERNAL_SERVER_ERROR_500 = 500; | |
71 | + Integer SC_INTERNAL_SERVER_ERROR_500 = 500; | |
72 | 72 | /** {@code 200 OK} (HTTP/1.0 - RFC 1945) */ |
73 | - public static final Integer SC_OK_200 = 200; | |
73 | + Integer SC_OK_200 = 200; | |
74 | 74 | |
75 | 75 | /**访问权限认证未通过 510*/ |
76 | - public static final Integer SC_JEECG_NO_AUTHZ=510; | |
76 | + Integer SC_JEECG_NO_AUTHZ=510; | |
77 | 77 | |
78 | 78 | /** 登录用户Shiro权限缓存KEY前缀 */ |
79 | 79 | public static String PREFIX_USER_SHIRO_CACHE = "shiro:cache:org.jeecg.config.shiro.ShiroRealm.authorizationCache:"; |
80 | 80 | /** 登录用户Token令牌缓存KEY前缀 */ |
81 | - public static final String PREFIX_USER_TOKEN = "prefix_user_token_"; | |
81 | + String PREFIX_USER_TOKEN = "prefix_user_token_"; | |
82 | 82 | // /** Token缓存时间:3600秒即一小时 */ |
83 | -// public static final int TOKEN_EXPIRE_TIME = 3600; | |
83 | +// int TOKEN_EXPIRE_TIME = 3600; | |
84 | 84 | |
85 | 85 | /** 登录二维码 */ |
86 | - public static final String LOGIN_QRCODE_PRE = "QRCODELOGIN:"; | |
87 | - public static final String LOGIN_QRCODE = "LQ:"; | |
86 | + String LOGIN_QRCODE_PRE = "QRCODELOGIN:"; | |
87 | + String LOGIN_QRCODE = "LQ:"; | |
88 | 88 | /** 登录二维码token */ |
89 | - public static final String LOGIN_QRCODE_TOKEN = "LQT:"; | |
89 | + String LOGIN_QRCODE_TOKEN = "LQT:"; | |
90 | 90 | |
91 | 91 | |
92 | 92 | /** |
93 | 93 | * 0:一级菜单 |
94 | 94 | */ |
95 | - public static final Integer MENU_TYPE_0 = 0; | |
95 | + Integer MENU_TYPE_0 = 0; | |
96 | 96 | /** |
97 | 97 | * 1:子菜单 |
98 | 98 | */ |
99 | - public static final Integer MENU_TYPE_1 = 1; | |
99 | + Integer MENU_TYPE_1 = 1; | |
100 | 100 | /** |
101 | 101 | * 2:按钮权限 |
102 | 102 | */ |
103 | - public static final Integer MENU_TYPE_2 = 2; | |
103 | + Integer MENU_TYPE_2 = 2; | |
104 | 104 | |
105 | 105 | /**通告对象类型(USER:指定用户,ALL:全体用户)*/ |
106 | - public static final String MSG_TYPE_UESR = "USER"; | |
107 | - public static final String MSG_TYPE_ALL = "ALL"; | |
106 | + String MSG_TYPE_UESR = "USER"; | |
107 | + String MSG_TYPE_ALL = "ALL"; | |
108 | 108 | |
109 | 109 | /**发布状态(0未发布,1已发布,2已撤销)*/ |
110 | - public static final String NO_SEND = "0"; | |
111 | - public static final String HAS_SEND = "1"; | |
112 | - public static final String HAS_CANCLE = "2"; | |
110 | + String NO_SEND = "0"; | |
111 | + String HAS_SEND = "1"; | |
112 | + String HAS_CANCLE = "2"; | |
113 | 113 | |
114 | 114 | /**阅读状态(0未读,1已读)*/ |
115 | - public static final String HAS_READ_FLAG = "1"; | |
116 | - public static final String NO_READ_FLAG = "0"; | |
115 | + String HAS_READ_FLAG = "1"; | |
116 | + String NO_READ_FLAG = "0"; | |
117 | 117 | |
118 | 118 | /**优先级(L低,M中,H高)*/ |
119 | - public static final String PRIORITY_L = "L"; | |
120 | - public static final String PRIORITY_M = "M"; | |
121 | - public static final String PRIORITY_H = "H"; | |
119 | + String PRIORITY_L = "L"; | |
120 | + String PRIORITY_M = "M"; | |
121 | + String PRIORITY_H = "H"; | |
122 | 122 | |
123 | 123 | /** |
124 | 124 | * 短信模板方式 0 .登录模板、1.注册模板、2.忘记密码模板 |
125 | 125 | */ |
126 | - public static final String SMS_TPL_TYPE_0 = "0"; | |
127 | - public static final String SMS_TPL_TYPE_1 = "1"; | |
128 | - public static final String SMS_TPL_TYPE_2 = "2"; | |
126 | + String SMS_TPL_TYPE_0 = "0"; | |
127 | + String SMS_TPL_TYPE_1 = "1"; | |
128 | + String SMS_TPL_TYPE_2 = "2"; | |
129 | 129 | |
130 | 130 | /** |
131 | 131 | * 状态(0无效1有效) |
132 | 132 | */ |
133 | - public static final String STATUS_0 = "0"; | |
134 | - public static final String STATUS_1 = "1"; | |
133 | + String STATUS_0 = "0"; | |
134 | + String STATUS_1 = "1"; | |
135 | 135 | |
136 | 136 | /** |
137 | 137 | * 同步工作流引擎1同步0不同步 |
138 | 138 | */ |
139 | - public static final Integer ACT_SYNC_1 = 1; | |
140 | - public static final Integer ACT_SYNC_0 = 0; | |
139 | + Integer ACT_SYNC_1 = 1; | |
140 | + Integer ACT_SYNC_0 = 0; | |
141 | 141 | |
142 | 142 | /** |
143 | 143 | * 消息类型1:通知公告2:系统消息 |
144 | 144 | */ |
145 | - public static final String MSG_CATEGORY_1 = "1"; | |
146 | - public static final String MSG_CATEGORY_2 = "2"; | |
145 | + String MSG_CATEGORY_1 = "1"; | |
146 | + String MSG_CATEGORY_2 = "2"; | |
147 | 147 | |
148 | 148 | /** |
149 | 149 | * 是否配置菜单的数据权限 1是0否 |
150 | 150 | */ |
151 | - public static final Integer RULE_FLAG_0 = 0; | |
152 | - public static final Integer RULE_FLAG_1 = 1; | |
151 | + Integer RULE_FLAG_0 = 0; | |
152 | + Integer RULE_FLAG_1 = 1; | |
153 | 153 | |
154 | 154 | /** |
155 | 155 | * 是否用户已被冻结 1正常(解冻) 2冻结 |
156 | 156 | */ |
157 | - public static final Integer USER_UNFREEZE = 1; | |
158 | - public static final Integer USER_FREEZE = 2; | |
157 | + Integer USER_UNFREEZE = 1; | |
158 | + Integer USER_FREEZE = 2; | |
159 | 159 | |
160 | 160 | /**字典翻译文本后缀*/ |
161 | - public static final String DICT_TEXT_SUFFIX = "_dictText"; | |
161 | + String DICT_TEXT_SUFFIX = "_dictText"; | |
162 | 162 | |
163 | 163 | /** |
164 | 164 | * 表单设计器主表类型 |
165 | 165 | */ |
166 | - public static final Integer DESIGN_FORM_TYPE_MAIN = 1; | |
166 | + Integer DESIGN_FORM_TYPE_MAIN = 1; | |
167 | 167 | |
168 | 168 | /** |
169 | 169 | * 表单设计器子表表类型 |
170 | 170 | */ |
171 | - public static final Integer DESIGN_FORM_TYPE_SUB = 2; | |
171 | + Integer DESIGN_FORM_TYPE_SUB = 2; | |
172 | 172 | |
173 | 173 | /** |
174 | 174 | * 表单设计器URL授权通过 |
175 | 175 | */ |
176 | - public static final Integer DESIGN_FORM_URL_STATUS_PASSED = 1; | |
176 | + Integer DESIGN_FORM_URL_STATUS_PASSED = 1; | |
177 | 177 | |
178 | 178 | /** |
179 | 179 | * 表单设计器URL授权未通过 |
180 | 180 | */ |
181 | - public static final Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2; | |
181 | + Integer DESIGN_FORM_URL_STATUS_NOT_PASSED = 2; | |
182 | 182 | |
183 | 183 | /** |
184 | 184 | * 表单设计器新增 Flag |
185 | 185 | */ |
186 | - public static final String DESIGN_FORM_URL_TYPE_ADD = "add"; | |
186 | + String DESIGN_FORM_URL_TYPE_ADD = "add"; | |
187 | 187 | /** |
188 | 188 | * 表单设计器修改 Flag |
189 | 189 | */ |
190 | - public static final String DESIGN_FORM_URL_TYPE_EDIT = "edit"; | |
190 | + String DESIGN_FORM_URL_TYPE_EDIT = "edit"; | |
191 | 191 | /** |
192 | 192 | * 表单设计器详情 Flag |
193 | 193 | */ |
194 | - public static final String DESIGN_FORM_URL_TYPE_DETAIL = "detail"; | |
194 | + String DESIGN_FORM_URL_TYPE_DETAIL = "detail"; | |
195 | 195 | /** |
196 | 196 | * 表单设计器复用数据 Flag |
197 | 197 | */ |
198 | - public static final String DESIGN_FORM_URL_TYPE_REUSE = "reuse"; | |
198 | + String DESIGN_FORM_URL_TYPE_REUSE = "reuse"; | |
199 | 199 | /** |
200 | 200 | * 表单设计器编辑 Flag (已弃用) |
201 | 201 | */ |
202 | - public static final String DESIGN_FORM_URL_TYPE_VIEW = "view"; | |
202 | + String DESIGN_FORM_URL_TYPE_VIEW = "view"; | |
203 | 203 | |
204 | 204 | /** |
205 | 205 | * online参数值设置(是:Y, 否:N) |
206 | 206 | */ |
207 | - public static final String ONLINE_PARAM_VAL_IS_TURE = "Y"; | |
208 | - public static final String ONLINE_PARAM_VAL_IS_FALSE = "N"; | |
207 | + String ONLINE_PARAM_VAL_IS_TURE = "Y"; | |
208 | + String ONLINE_PARAM_VAL_IS_FALSE = "N"; | |
209 | 209 | |
210 | 210 | /** |
211 | 211 | * 文件上传类型(本地:local,Minio:minio,阿里云:alioss) |
212 | 212 | */ |
213 | - public static final String UPLOAD_TYPE_LOCAL = "local"; | |
214 | - public static final String UPLOAD_TYPE_MINIO = "minio"; | |
215 | - public static final String UPLOAD_TYPE_OSS = "alioss"; | |
213 | + String UPLOAD_TYPE_LOCAL = "local"; | |
214 | + String UPLOAD_TYPE_MINIO = "minio"; | |
215 | + String UPLOAD_TYPE_OSS = "alioss"; | |
216 | 216 | |
217 | 217 | /** |
218 | 218 | * 文档上传自定义桶名称 |
219 | 219 | */ |
220 | - public static final String UPLOAD_CUSTOM_BUCKET = "eoafile"; | |
220 | + String UPLOAD_CUSTOM_BUCKET = "eoafile"; | |
221 | 221 | /** |
222 | 222 | * 文档上传自定义路径 |
223 | 223 | */ |
224 | - public static final String UPLOAD_CUSTOM_PATH = "eoafile"; | |
224 | + String UPLOAD_CUSTOM_PATH = "eoafile"; | |
225 | 225 | /** |
226 | 226 | * 文件外链接有效天数 |
227 | 227 | */ |
228 | - public static final Integer UPLOAD_EFFECTIVE_DAYS = 1; | |
228 | + Integer UPLOAD_EFFECTIVE_DAYS = 1; | |
229 | 229 | |
230 | 230 | /** |
231 | 231 | * 员工身份 (1:普通员工 2:上级) |
232 | 232 | */ |
233 | - public static final Integer USER_IDENTITY_1 = 1; | |
234 | - public static final Integer USER_IDENTITY_2 = 2; | |
233 | + Integer USER_IDENTITY_1 = 1; | |
234 | + Integer USER_IDENTITY_2 = 2; | |
235 | 235 | |
236 | 236 | /** sys_user 表 username 唯一键索引 */ |
237 | - public static final String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username"; | |
237 | + String SQL_INDEX_UNIQ_SYS_USER_USERNAME = "uniq_sys_user_username"; | |
238 | 238 | /** sys_user 表 work_no 唯一键索引 */ |
239 | - public static final String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no"; | |
239 | + String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no"; | |
240 | 240 | /** sys_user 表 phone 唯一键索引 */ |
241 | - public static final String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone"; | |
241 | + String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone"; | |
242 | 242 | /** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */ |
243 | - public static final String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束"; | |
243 | + String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束"; | |
244 | 244 | |
245 | 245 | /** sys_user 表 email 唯一键索引 */ |
246 | - public static final String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email"; | |
246 | + String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email"; | |
247 | 247 | /** sys_quartz_job 表 job_class_name 唯一键索引 */ |
248 | - public static final String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name"; | |
248 | + String SQL_INDEX_UNIQ_JOB_CLASS_NAME = "uniq_job_class_name"; | |
249 | 249 | /** sys_position 表 code 唯一键索引 */ |
250 | - public static final String SQL_INDEX_UNIQ_CODE = "uniq_code"; | |
250 | + String SQL_INDEX_UNIQ_CODE = "uniq_code"; | |
251 | 251 | /** sys_role 表 code 唯一键索引 */ |
252 | - public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code"; | |
252 | + String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code"; | |
253 | 253 | /** sys_depart 表 code 唯一键索引 */ |
254 | - public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code"; | |
254 | + String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code"; | |
255 | 255 | /** sys_category 表 code 唯一键索引 */ |
256 | - public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code"; | |
256 | + String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code"; | |
257 | 257 | /** |
258 | 258 | * 在线聊天 是否为默认分组 |
259 | 259 | */ |
260 | - public static final String IM_DEFAULT_GROUP = "1"; | |
260 | + String IM_DEFAULT_GROUP = "1"; | |
261 | 261 | /** |
262 | 262 | * 在线聊天 图片文件保存路径 |
263 | 263 | */ |
264 | - public static final String IM_UPLOAD_CUSTOM_PATH = "imfile"; | |
264 | + String IM_UPLOAD_CUSTOM_PATH = "imfile"; | |
265 | 265 | /** |
266 | 266 | * 在线聊天 用户状态 |
267 | 267 | */ |
268 | - public static final String IM_STATUS_ONLINE = "online"; | |
268 | + String IM_STATUS_ONLINE = "online"; | |
269 | 269 | |
270 | 270 | /** |
271 | 271 | * 在线聊天 SOCKET消息类型 |
272 | 272 | */ |
273 | - public static final String IM_SOCKET_TYPE = "chatMessage"; | |
273 | + String IM_SOCKET_TYPE = "chatMessage"; | |
274 | 274 | |
275 | 275 | /** |
276 | 276 | * 在线聊天 是否开启默认添加好友 1是 0否 |
277 | 277 | */ |
278 | - public static final String IM_DEFAULT_ADD_FRIEND = "1"; | |
278 | + String IM_DEFAULT_ADD_FRIEND = "1"; | |
279 | 279 | |
280 | 280 | /** |
281 | 281 | * 在线聊天 用户好友缓存前缀 |
282 | 282 | */ |
283 | - public static final String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_"; | |
283 | + String IM_PREFIX_USER_FRIEND_CACHE = "sys:cache:im:im_prefix_user_friend_"; | |
284 | 284 | |
285 | 285 | /** |
286 | 286 | * 考勤补卡业务状态 (1:同意 2:不同意) |
287 | 287 | */ |
288 | - public static final String SIGN_PATCH_BIZ_STATUS_1 = "1"; | |
289 | - public static final String SIGN_PATCH_BIZ_STATUS_2 = "2"; | |
288 | + String SIGN_PATCH_BIZ_STATUS_1 = "1"; | |
289 | + String SIGN_PATCH_BIZ_STATUS_2 = "2"; | |
290 | 290 | |
291 | 291 | /** |
292 | 292 | * 公文文档上传自定义路径 |
293 | 293 | */ |
294 | - public static final String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc"; | |
294 | + String UPLOAD_CUSTOM_PATH_OFFICIAL = "officialdoc"; | |
295 | 295 | /** |
296 | 296 | * 公文文档下载自定义路径 |
297 | 297 | */ |
298 | - public static final String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown"; | |
298 | + String DOWNLOAD_CUSTOM_PATH_OFFICIAL = "officaldown"; | |
299 | 299 | |
300 | 300 | /** |
301 | 301 | * WPS存储值类别(1 code文号 2 text(WPS模板还是公文发文模板)) |
302 | 302 | */ |
303 | - public static final String WPS_TYPE_1="1"; | |
304 | - public static final String WPS_TYPE_2="2"; | |
303 | + String WPS_TYPE_1="1"; | |
304 | + String WPS_TYPE_2="2"; | |
305 | 305 | |
306 | 306 | |
307 | - public final static String X_ACCESS_TOKEN = "X-Access-Token"; | |
308 | - public final static String X_SIGN = "X-Sign"; | |
309 | - public final static String X_TIMESTAMP = "X-TIMESTAMP"; | |
310 | - public final static String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!"; | |
307 | + String X_ACCESS_TOKEN = "X-Access-Token"; | |
308 | + String X_SIGN = "X-Sign"; | |
309 | + String X_TIMESTAMP = "X-TIMESTAMP"; | |
310 | + String TOKEN_IS_INVALID_MSG = "Token失效,请重新登录!"; | |
311 | + String X_FORWARDED_SCHEME = "X-Forwarded-Scheme"; | |
311 | 312 | |
312 | 313 | /** |
313 | 314 | * 多租户 请求头 |
314 | 315 | */ |
315 | - public final static String TENANT_ID = "tenant-id"; | |
316 | + String TENANT_ID = "tenant-id"; | |
316 | 317 | |
317 | 318 | /** |
318 | 319 | * 微服务读取配置文件属性 服务地址 |
319 | 320 | */ |
320 | - public final static String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr"; | |
321 | + String CLOUD_SERVER_KEY = "spring.cloud.nacos.discovery.server-addr"; | |
321 | 322 | |
322 | 323 | /** |
323 | 324 | * 第三方登录 验证密码/创建用户 都需要设置一个操作码 防止被恶意调用 |
324 | 325 | */ |
325 | - public final static String THIRD_LOGIN_CODE = "third_login_code"; | |
326 | + String THIRD_LOGIN_CODE = "third_login_code"; | |
326 | 327 | |
327 | 328 | /** |
328 | 329 | * 第三方APP同步方向:本地 --> 第三方APP |
... | ... | @@ -361,16 +362,43 @@ public interface CommonConstant { |
361 | 362 | /**String 类型的空值*/ |
362 | 363 | String STRING_NULL = "null"; |
363 | 364 | |
364 | - /**java.util.Date 包*/ | |
365 | - String JAVA_UTIL_DATE = "java.util.Date"; | |
365 | + /**前端vue3版本Header参数名*/ | |
366 | + String VERSION="X-Version"; | |
366 | 367 | |
367 | - /**.do*/ | |
368 | - String SPOT_DO = ".do"; | |
368 | + /**存储在线程变量里的动态表名*/ | |
369 | + String DYNAMIC_TABLE_NAME="DYNAMIC_TABLE_NAME"; | |
370 | + /** | |
371 | + * http:// http协议 | |
372 | + */ | |
373 | + String HTTP_PROTOCOL = "http://"; | |
369 | 374 | |
375 | + /** | |
376 | + * https:// https协议 | |
377 | + */ | |
378 | + String HTTPS_PROTOCOL = "https://"; | |
379 | + | |
380 | + /** 部门表唯一key,id */ | |
381 | + String DEPART_KEY_ID = "id"; | |
382 | + /** 部门表唯一key,orgCode */ | |
383 | + String DEPART_KEY_ORG_CODE = "orgCode"; | |
370 | 384 | |
371 | - /**前端vue版本标识*/ | |
372 | - String VERSION="X-Version"; | |
385 | + /** | |
386 | + * 发消息 会传递一些信息到map | |
387 | + */ | |
388 | + String NOTICE_MSG_SUMMARY = "NOTICE_MSG_SUMMARY"; | |
373 | 389 | |
374 | - /**前端vue版本*/ | |
375 | - String VERSION_VUE3="vue3"; | |
390 | + /** | |
391 | + * 发消息 会传递一个业务ID到map | |
392 | + */ | |
393 | + String NOTICE_MSG_BUS_ID = "NOTICE_MSG_BUS_ID"; | |
394 | + | |
395 | + /** | |
396 | + * 邮箱消息中地址登录时地址后携带的token,需要替换成真实的token值 | |
397 | + */ | |
398 | + String LOGIN_TOKEN = "{LOGIN_TOKEN}"; | |
399 | + | |
400 | + /** | |
401 | + * 模板消息中 跳转地址的对应的key | |
402 | + */ | |
403 | + String MSG_HREF_URL = "url"; | |
376 | 404 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DataBaseConstant.java
... | ... | @@ -153,4 +153,14 @@ public interface DataBaseConstant { |
153 | 153 | * sql语句 where |
154 | 154 | */ |
155 | 155 | String SQL_WHERE = "where"; |
156 | + | |
157 | + /** | |
158 | + * sql语句 asc | |
159 | + */ | |
160 | + String SQL_ASC = "asc"; | |
161 | + | |
162 | + /** | |
163 | + * sqlserver数据库,中间有空格 | |
164 | + */ | |
165 | + String DB_TYPE_SQL_SERVER_BLANK = "sql server"; | |
156 | 166 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/DynamicTableConstant.java
0 → 100644
1 | +package org.jeecg.common.constant; | |
2 | + | |
3 | +/** | |
4 | + * 动态切换表配置常量 | |
5 | + * | |
6 | + * @author: scott | |
7 | + * @date: 2022年04月25日 22:30 | |
8 | + */ | |
9 | +public class DynamicTableConstant { | |
10 | + /** | |
11 | + * 角色首页配置表 | |
12 | + * vue2表名: sys_role_index | |
13 | + * vue3表名: sys_role_index_vue3 | |
14 | + */ | |
15 | + public static final String SYS_ROLE_INDEX = "sys_role_index"; | |
16 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
... | ... | @@ -35,9 +35,13 @@ public class ProvinceCityArea { |
35 | 35 | this.initAreaList(); |
36 | 36 | if(areaList!=null && areaList.size()>0){ |
37 | 37 | for(int i=areaList.size()-1;i>=0;i--){ |
38 | - if(text.indexOf(areaList.get(i).getText())>=0){ | |
38 | + //update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区 | |
39 | + String areaText = areaList.get(i).getText(); | |
40 | + String cityText = areaList.get(i).getAheadText(); | |
41 | + if(text.indexOf(areaText)>=0 && (cityText!=null && text.indexOf(cityText)>=0)){ | |
39 | 42 | return areaList.get(i).getId(); |
40 | 43 | } |
44 | + //update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区 | |
41 | 45 | } |
42 | 46 | } |
43 | 47 | return null; |
... | ... | @@ -145,6 +149,9 @@ public class ProvinceCityArea { |
145 | 149 | for(String areaKey:areaJson.keySet()){ |
146 | 150 | //System.out.println("········"+areaKey); |
147 | 151 | Area area = new Area(areaKey,areaJson.getString(areaKey),cityKey); |
152 | + //update-begin-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区 | |
153 | + area.setAheadText(cityJson.getString(cityKey)); | |
154 | + //update-end-author:taoyan date:2022-5-24 for:VUEN-1088 online 导入 省市区导入后 导入数据错乱 北京市/市辖区/西城区-->山西省/晋城市/城区 | |
148 | 155 | this.areaList.add(area); |
149 | 156 | } |
150 | 157 | } |
... | ... | @@ -180,6 +187,8 @@ public class ProvinceCityArea { |
180 | 187 | String id; |
181 | 188 | String text; |
182 | 189 | String pid; |
190 | + // 用于存储上级文本数据,区的上级文本 是市的数据 | |
191 | + String aheadText; | |
183 | 192 | |
184 | 193 | public Area(String id,String text,String pid){ |
185 | 194 | this.id = id; |
... | ... | @@ -198,5 +207,12 @@ public class ProvinceCityArea { |
198 | 207 | public String getPid() { |
199 | 208 | return pid; |
200 | 209 | } |
210 | + | |
211 | + public String getAheadText() { | |
212 | + return aheadText; | |
213 | + } | |
214 | + public void setAheadText(String aheadText) { | |
215 | + this.aheadText = aheadText; | |
216 | + } | |
201 | 217 | } |
202 | 218 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/SymbolConstant.java
... | ... | @@ -86,4 +86,34 @@ public class SymbolConstant { |
86 | 86 | * 符号:和 & |
87 | 87 | */ |
88 | 88 | public static final String AND = "&"; |
89 | + | |
90 | + /** | |
91 | + * 符号:../ | |
92 | + */ | |
93 | + public static final String SPOT_SINGLE_SLASH = "../"; | |
94 | + | |
95 | + /** | |
96 | + * 符号:..\\ | |
97 | + */ | |
98 | + public static final String SPOT_DOUBLE_BACKSLASH = "..\\"; | |
99 | + | |
100 | + /** | |
101 | + * 系统变量前缀 #{ | |
102 | + */ | |
103 | + public static final String SYS_VAR_PREFIX = "#{"; | |
104 | + | |
105 | + /** | |
106 | + * 符号 {{ | |
107 | + */ | |
108 | + public static final String DOUBLE_LEFT_CURLY_BRACKET = "{{"; | |
109 | + | |
110 | + /** | |
111 | + * 符号:[ | |
112 | + */ | |
113 | + public static final String SQUARE_BRACKETS_LEFT = "["; | |
114 | + /** | |
115 | + * 符号:] | |
116 | + */ | |
117 | + public static final String SQUARE_BRACKETS_RIGHT = "]"; | |
118 | + | |
89 | 119 | } |
90 | 120 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/CgformEnum.java
... | ... | @@ -20,13 +20,14 @@ public enum CgformEnum { |
20 | 20 | */ |
21 | 21 | MANY(2, "many", "/jeecg/code-template-online", "default.onetomany", "经典风格"), |
22 | 22 | /** |
23 | - * 多表 | |
24 | - */ | |
25 | - ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"), | |
26 | - /** | |
27 | 23 | * 多表(jvxe风格) |
28 | 24 | * */ |
29 | 25 | JVXE_TABLE(2, "jvxe", "/jeecg/code-template-online", "jvxe.onetomany", "JVXE风格"), |
26 | + | |
27 | + /** | |
28 | + * 多表 | |
29 | + */ | |
30 | + ERP(2, "erp", "/jeecg/code-template-online", "erp.onetomany", "ERP风格"), | |
30 | 31 | /** |
31 | 32 | * 多表(内嵌子表风格) |
32 | 33 | */ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/MessageTypeEnum.java
0 → 100644
1 | +package org.jeecg.common.constant.enums; | |
2 | + | |
3 | +import org.jeecg.common.system.annotation.EnumDict; | |
4 | +import org.jeecg.common.system.vo.DictModel; | |
5 | + | |
6 | +import java.util.ArrayList; | |
7 | +import java.util.List; | |
8 | + | |
9 | +/** | |
10 | + * 消息类型 | |
11 | + * @author: jeecg-boot | |
12 | + */ | |
13 | +@EnumDict("messageType") | |
14 | +public enum MessageTypeEnum { | |
15 | + | |
16 | + XT("system", "系统消息"), | |
17 | + YJ("email", "邮件消息"), | |
18 | + DD("dingtalk", "钉钉消息"), | |
19 | + QYWX("wechat_enterprise", "企业微信"); | |
20 | + | |
21 | + MessageTypeEnum(String type, String note){ | |
22 | + this.type = type; | |
23 | + this.note = note; | |
24 | + } | |
25 | + | |
26 | + /** | |
27 | + * 消息类型 | |
28 | + */ | |
29 | + String type; | |
30 | + | |
31 | + /** | |
32 | + * 类型说明 | |
33 | + */ | |
34 | + String note; | |
35 | + | |
36 | + public String getNote() { | |
37 | + return note; | |
38 | + } | |
39 | + | |
40 | + public void setNote(String note) { | |
41 | + this.note = note; | |
42 | + } | |
43 | + | |
44 | + public String getType() { | |
45 | + return type; | |
46 | + } | |
47 | + | |
48 | + public void setType(String type) { | |
49 | + this.type = type; | |
50 | + } | |
51 | + | |
52 | + | |
53 | + /** | |
54 | + * 获取字典数据 | |
55 | + * @return | |
56 | + */ | |
57 | + public static List<DictModel> getDictList(){ | |
58 | + List<DictModel> list = new ArrayList<>(); | |
59 | + DictModel dictModel = null; | |
60 | + for(MessageTypeEnum e: MessageTypeEnum.values()){ | |
61 | + dictModel = new DictModel(); | |
62 | + dictModel.setValue(e.getType()); | |
63 | + dictModel.setText(e.getNote()); | |
64 | + list.add(dictModel); | |
65 | + } | |
66 | + return list; | |
67 | + } | |
68 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/exception/JeecgBootExceptionHandler.java
... | ... | @@ -123,7 +123,8 @@ public class JeecgBootExceptionHandler { |
123 | 123 | @ExceptionHandler(DataIntegrityViolationException.class) |
124 | 124 | public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) { |
125 | 125 | log.error(e.getMessage(), e); |
126 | - return Result.error("字段太长,超出数据库字段的长度"); | |
126 | + //【issues/3624】数据库执行异常handleDataIntegrityViolationException提示有误 #3624 | |
127 | + return Result.error("执行数据库异常,违反了完整性例如:违反惟一约束、违反非空限制、字段内容超出长度等"); | |
127 | 128 | } |
128 | 129 | |
129 | 130 | @ExceptionHandler(PoolException.class) |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/annotation/EnumDict.java
0 → 100644
1 | +package org.jeecg.common.system.annotation; | |
2 | + | |
3 | +import java.lang.annotation.*; | |
4 | + | |
5 | +/** | |
6 | + * 将枚举类转化成字典数据 | |
7 | + * @Author taoYan | |
8 | + * @Date 2022/7/8 10:34 | |
9 | + **/ | |
10 | +@Target(ElementType.TYPE) | |
11 | +@Retention(RetentionPolicy.RUNTIME) | |
12 | +@Documented | |
13 | +public @interface EnumDict { | |
14 | + | |
15 | + /** | |
16 | + * 作为字典数据的唯一编码 | |
17 | + */ | |
18 | + String value() default ""; | |
19 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
... | ... | @@ -53,18 +53,14 @@ public class JeecgController<T, S extends IService<T>> { |
53 | 53 | QueryWrapper<T> queryWrapper = QueryGenerator.initQueryWrapper(object, request.getParameterMap()); |
54 | 54 | LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); |
55 | 55 | |
56 | - // Step.2 获取导出数据 | |
57 | - List<T> pageList = service.list(queryWrapper); | |
58 | - List<T> exportList = null; | |
59 | - | |
60 | 56 | // 过滤选中数据 |
61 | 57 | String selections = request.getParameter("selections"); |
62 | 58 | if (oConvertUtils.isNotEmpty(selections)) { |
63 | 59 | List<String> selectionList = Arrays.asList(selections.split(",")); |
64 | - exportList = pageList.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList()); | |
65 | - } else { | |
66 | - exportList = pageList; | |
60 | + queryWrapper.in("id",selectionList); | |
67 | 61 | } |
62 | + // Step.2 获取导出数据 | |
63 | + List<T> exportList = service.list(queryWrapper); | |
68 | 64 | |
69 | 65 | // Step.3 AutoPoi 导出Excel |
70 | 66 | ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); |
... | ... | @@ -97,21 +93,20 @@ public class JeecgController<T, S extends IService<T>> { |
97 | 93 | // Step.2 计算分页sheet数据 |
98 | 94 | double total = service.count(); |
99 | 95 | int count = (int)Math.ceil(total/pageNum); |
100 | - // Step.3 多sheet处理 | |
96 | + //update-begin-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 --- | |
97 | + // Step.3 过滤选中数据 | |
98 | + String selections = request.getParameter("selections"); | |
99 | + if (oConvertUtils.isNotEmpty(selections)) { | |
100 | + List<String> selectionList = Arrays.asList(selections.split(",")); | |
101 | + queryWrapper.in("id",selectionList); | |
102 | + } | |
103 | + //update-end-author:liusq---date:20220629--for: 多sheet导出根据选择导出写法调整 --- | |
104 | + // Step.4 多sheet处理 | |
101 | 105 | List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>(); |
102 | 106 | for (int i = 1; i <=count ; i++) { |
103 | 107 | Page<T> page = new Page<T>(i, pageNum); |
104 | 108 | IPage<T> pageList = service.page(page, queryWrapper); |
105 | - List<T> records = pageList.getRecords(); | |
106 | - List<T> exportList = null; | |
107 | - // 过滤选中数据 | |
108 | - String selections = request.getParameter("selections"); | |
109 | - if (oConvertUtils.isNotEmpty(selections)) { | |
110 | - List<String> selectionList = Arrays.asList(selections.split(",")); | |
111 | - exportList = records.stream().filter(item -> selectionList.contains(getId(item))).collect(Collectors.toList()); | |
112 | - } else { | |
113 | - exportList = records; | |
114 | - } | |
109 | + List<T> exportList = pageList.getRecords(); | |
115 | 110 | Map<String, Object> map = new HashMap<>(5); |
116 | 111 | ExportParams exportParams=new ExportParams(title + "报表", "导出人:" + sysUser.getRealname(), title+i,upLoadPath); |
117 | 112 | exportParams.setType(ExcelType.XSSF); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
... | ... | @@ -16,6 +16,7 @@ import org.apache.commons.beanutils.PropertyUtils; |
16 | 16 | import org.jeecg.common.constant.CommonConstant; |
17 | 17 | import org.jeecg.common.constant.DataBaseConstant; |
18 | 18 | import org.jeecg.common.constant.SymbolConstant; |
19 | +import org.jeecg.common.exception.JeecgBootException; | |
19 | 20 | import org.jeecg.common.system.util.JeecgDataAutorUtils; |
20 | 21 | import org.jeecg.common.system.util.JwtUtil; |
21 | 22 | import org.jeecg.common.system.vo.SysPermissionDataRuleModel; |
... | ... | @@ -191,8 +192,8 @@ public class QueryGenerator { |
191 | 192 | log.error(e.getMessage(), e); |
192 | 193 | } |
193 | 194 | } |
194 | - // 排序逻辑 处理 | |
195 | - doMultiFieldsOrder(queryWrapper, parameterMap); | |
195 | + // 排序逻辑 处理 | |
196 | + doMultiFieldsOrder(queryWrapper, parameterMap, fieldColumnMap.keySet()); | |
196 | 197 | |
197 | 198 | //高级查询 |
198 | 199 | doSuperQuery(queryWrapper, parameterMap, fieldColumnMap); |
... | ... | @@ -228,8 +229,7 @@ public class QueryGenerator { |
228 | 229 | } |
229 | 230 | } |
230 | 231 | |
231 | - /**多字段排序 TODO 需要修改前端*/ | |
232 | - private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) { | |
232 | + private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap, Set<String> allFields) { | |
233 | 233 | String column=null,order=null; |
234 | 234 | if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) { |
235 | 235 | column = parameterMap.get(ORDER_COLUMN)[0]; |
... | ... | @@ -243,6 +243,15 @@ public class QueryGenerator { |
243 | 243 | if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) { |
244 | 244 | column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX)); |
245 | 245 | } |
246 | + | |
247 | + //update-begin-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效 | |
248 | + //判断column是不是当前实体的 | |
249 | + log.info("当前字段有:"+ allFields); | |
250 | + if (!allColumnExist(column, allFields)) { | |
251 | + throw new JeecgBootException("请注意,将要排序的列字段不存在:" + column); | |
252 | + } | |
253 | + //update-end-author:taoyan date:2022-5-16 for: issues/3676 获取系统用户列表时,使用SQL注入生效 | |
254 | + | |
246 | 255 | //SQL注入check |
247 | 256 | SqlInjectionUtil.filterContent(column); |
248 | 257 | |
... | ... | @@ -264,6 +273,28 @@ public class QueryGenerator { |
264 | 273 | //update-end--Author:scott Date:20210531 for:36 多条件排序无效问题修正------- |
265 | 274 | } |
266 | 275 | } |
276 | + | |
277 | + //update-begin-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效 | |
278 | + /** | |
279 | + * 多字段排序 判断所传字段是否存在 | |
280 | + * @return | |
281 | + */ | |
282 | + private static boolean allColumnExist(String columnStr, Set<String> allFields){ | |
283 | + boolean exist = true; | |
284 | + if(columnStr.indexOf(COMMA)>=0){ | |
285 | + String[] arr = columnStr.split(COMMA); | |
286 | + for(String column: arr){ | |
287 | + if(!allFields.contains(column)){ | |
288 | + exist = false; | |
289 | + break; | |
290 | + } | |
291 | + } | |
292 | + }else{ | |
293 | + exist = allFields.contains(columnStr); | |
294 | + } | |
295 | + return exist; | |
296 | + } | |
297 | + //update-end-author:taoyan date:2022-5-23 for: issues/3676 获取系统用户列表时,使用SQL注入生效 | |
267 | 298 | |
268 | 299 | /** |
269 | 300 | * 高级查询 |
... | ... | @@ -825,13 +856,13 @@ public class QueryGenerator { |
825 | 856 | res = field + " in "+getInConditionValue(value, isString); |
826 | 857 | break; |
827 | 858 | case LIKE: |
828 | - res = field + " like "+getLikeConditionValue(value); | |
859 | + res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LIKE); | |
829 | 860 | break; |
830 | 861 | case LEFT_LIKE: |
831 | - res = field + " like "+getLikeConditionValue(value); | |
862 | + res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.LEFT_LIKE); | |
832 | 863 | break; |
833 | 864 | case RIGHT_LIKE: |
834 | - res = field + " like "+getLikeConditionValue(value); | |
865 | + res = field + " like "+getLikeConditionValue(value, QueryRuleEnum.RIGHT_LIKE); | |
835 | 866 | break; |
836 | 867 | default: |
837 | 868 | res = field+" = "+getFieldConditionValue(value, isString, dataBaseType); |
... | ... | @@ -914,8 +945,15 @@ public class QueryGenerator { |
914 | 945 | } |
915 | 946 | //update-end-author:taoyan date:20210628 for: 查询条件如果输入,导致sql报错 |
916 | 947 | } |
917 | - | |
918 | - private static String getLikeConditionValue(Object value) { | |
948 | + | |
949 | + /** | |
950 | + * 先根据值判断 走左模糊还是右模糊 | |
951 | + * 最后如果值不带任何标识(*或者%),则再根据ruleEnum判断 | |
952 | + * @param value | |
953 | + * @param ruleEnum | |
954 | + * @return | |
955 | + */ | |
956 | + private static String getLikeConditionValue(Object value, QueryRuleEnum ruleEnum) { | |
919 | 957 | String str = value.toString().trim(); |
920 | 958 | if(str.startsWith(SymbolConstant.ASTERISK) && str.endsWith(SymbolConstant.ASTERISK)) { |
921 | 959 | if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){ |
... | ... | @@ -951,11 +989,30 @@ public class QueryGenerator { |
951 | 989 | } |
952 | 990 | } |
953 | 991 | }else { |
954 | - if(DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())){ | |
955 | - return "N'%"+str+"%'"; | |
956 | - }else{ | |
957 | - return "'%"+str+"%'"; | |
992 | + | |
993 | + //update-begin-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题 | |
994 | + // 走到这里说明 value不带有任何模糊查询的标识(*或者%) | |
995 | + if (ruleEnum == QueryRuleEnum.LEFT_LIKE) { | |
996 | + if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) { | |
997 | + return "N'%" + str + "'"; | |
998 | + } else { | |
999 | + return "'%" + str + "'"; | |
1000 | + } | |
1001 | + } else if (ruleEnum == QueryRuleEnum.RIGHT_LIKE) { | |
1002 | + if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) { | |
1003 | + return "N'" + str + "%'"; | |
1004 | + } else { | |
1005 | + return "'" + str + "%'"; | |
1006 | + } | |
1007 | + } else { | |
1008 | + if (DataBaseConstant.DB_TYPE_SQLSERVER.equals(getDbType())) { | |
1009 | + return "N'%" + str + "%'"; | |
1010 | + } else { | |
1011 | + return "'%" + str + "%'"; | |
1012 | + } | |
958 | 1013 | } |
1014 | + //update-end-author:taoyan date:2022-6-30 for: issues/3810 数据权限规则问题 | |
1015 | + | |
959 | 1016 | } |
960 | 1017 | } |
961 | 1018 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
... | ... | @@ -54,7 +54,7 @@ public class JwtUtil { |
54 | 54 | try { |
55 | 55 | os = httpServletResponse.getOutputStream(); |
56 | 56 | httpServletResponse.setCharacterEncoding("UTF-8"); |
57 | - httpServletResponse.setStatus(401); | |
57 | + httpServletResponse.setStatus(code); | |
58 | 58 | os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8")); |
59 | 59 | os.flush(); |
60 | 60 | os.close(); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/ResourceUtil.java
0 → 100644
1 | +package org.jeecg.common.system.util; | |
2 | + | |
3 | +import lombok.extern.slf4j.Slf4j; | |
4 | +import org.jeecg.common.system.annotation.EnumDict; | |
5 | +import org.jeecg.common.system.vo.DictModel; | |
6 | +import org.jeecg.common.util.oConvertUtils; | |
7 | +import org.springframework.core.io.Resource; | |
8 | +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | |
9 | +import org.springframework.core.io.support.ResourcePatternResolver; | |
10 | +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; | |
11 | +import org.springframework.core.type.classreading.MetadataReader; | |
12 | +import org.springframework.core.type.classreading.MetadataReaderFactory; | |
13 | +import org.springframework.util.ClassUtils; | |
14 | + | |
15 | +import java.util.ArrayList; | |
16 | +import java.util.HashMap; | |
17 | +import java.util.List; | |
18 | +import java.util.Map; | |
19 | + | |
20 | +/** | |
21 | + * 资源加载工具类 | |
22 | + * @Author taoYan | |
23 | + * @Date 2022/7/8 10:40 | |
24 | + **/ | |
25 | +@Slf4j | |
26 | +public class ResourceUtil { | |
27 | + | |
28 | + | |
29 | + /** | |
30 | + * 枚举字典数据 | |
31 | + */ | |
32 | + private final static Map<String, List<DictModel>> enumDictData = new HashMap<>(5); | |
33 | + | |
34 | + /** | |
35 | + * 所有java类 | |
36 | + */ | |
37 | + private final static String CLASS_PATTERN="/**/*.class"; | |
38 | + | |
39 | + /** | |
40 | + * 包路径 org.jeecg | |
41 | + */ | |
42 | + private final static String BASE_PACKAGE = "org.jeecg"; | |
43 | + | |
44 | + /** | |
45 | + * 枚举类中获取字典数据的方法名 | |
46 | + */ | |
47 | + private final static String METHOD_NAME = "getDictList"; | |
48 | + | |
49 | + /** | |
50 | + * 获取枚举类对应的字典数据 SysDictServiceImpl#queryAllDictItems() | |
51 | + * @return | |
52 | + */ | |
53 | + public static Map<String, List<DictModel>> getEnumDictData(){ | |
54 | + if(enumDictData.keySet().size()>0){ | |
55 | + return enumDictData; | |
56 | + } | |
57 | + ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); | |
58 | + String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + CLASS_PATTERN; | |
59 | + try { | |
60 | + Resource[] resources = resourcePatternResolver.getResources(pattern); | |
61 | + MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver); | |
62 | + for (Resource resource : resources) { | |
63 | + MetadataReader reader = readerFactory.getMetadataReader(resource); | |
64 | + String classname = reader.getClassMetadata().getClassName(); | |
65 | + Class<?> clazz = Class.forName(classname); | |
66 | + EnumDict enumDict = clazz.getAnnotation(EnumDict.class); | |
67 | + if (enumDict != null) { | |
68 | + EnumDict annotation = clazz.getAnnotation(EnumDict.class); | |
69 | + String key = annotation.value(); | |
70 | + if(oConvertUtils.isNotEmpty(key)){ | |
71 | + List<DictModel> list = (List<DictModel>) clazz.getDeclaredMethod(METHOD_NAME).invoke(null); | |
72 | + enumDictData.put(key, list); | |
73 | + } | |
74 | + } | |
75 | + } | |
76 | + }catch (Exception e){ | |
77 | + log.error("获取枚举类字典数据异常", e.getMessage()); | |
78 | + // e.printStackTrace(); | |
79 | + } | |
80 | + return enumDictData; | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * 用于后端字典翻译 SysDictServiceImpl#queryManyDictByKeys(java.util.List, java.util.List) | |
85 | + * @param dictCodeList | |
86 | + * @param keys | |
87 | + * @return | |
88 | + */ | |
89 | + public static Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){ | |
90 | + if(enumDictData.keySet().size()==0){ | |
91 | + getEnumDictData(); | |
92 | + } | |
93 | + Map<String, List<DictModel>> map = new HashMap<>(); | |
94 | + for (String code : enumDictData.keySet()) { | |
95 | + if(dictCodeList.indexOf(code)>=0){ | |
96 | + List<DictModel> dictItemList = enumDictData.get(code); | |
97 | + for(DictModel dm: dictItemList){ | |
98 | + String value = dm.getValue(); | |
99 | + if(keys.indexOf(value)>=0){ | |
100 | + List<DictModel> list = new ArrayList<>(); | |
101 | + list.add(new DictModel(value, dm.getText())); | |
102 | + map.put(code,list); | |
103 | + break; | |
104 | + } | |
105 | + } | |
106 | + } | |
107 | + } | |
108 | + return map; | |
109 | + } | |
110 | + | |
111 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/LoginUser.java
... | ... | @@ -2,6 +2,7 @@ package org.jeecg.common.system.vo; |
2 | 2 | |
3 | 3 | import java.util.Date; |
4 | 4 | |
5 | +import org.jeecg.common.desensitization.annotation.SensitiveField; | |
5 | 6 | import org.springframework.format.annotation.DateTimeFormat; |
6 | 7 | |
7 | 8 | import com.fasterxml.jackson.annotation.JsonFormat; |
... | ... | @@ -26,21 +27,25 @@ public class LoginUser { |
26 | 27 | /** |
27 | 28 | * 登录人id |
28 | 29 | */ |
30 | + @SensitiveField | |
29 | 31 | private String id; |
30 | 32 | |
31 | 33 | /** |
32 | 34 | * 登录人账号 |
33 | 35 | */ |
36 | + @SensitiveField | |
34 | 37 | private String username; |
35 | 38 | |
36 | 39 | /** |
37 | 40 | * 登录人名字 |
38 | 41 | */ |
42 | + @SensitiveField | |
39 | 43 | private String realname; |
40 | 44 | |
41 | 45 | /** |
42 | 46 | * 登录人密码 |
43 | 47 | */ |
48 | + @SensitiveField | |
44 | 49 | private String password; |
45 | 50 | |
46 | 51 | /** |
... | ... | @@ -50,11 +55,13 @@ public class LoginUser { |
50 | 55 | /** |
51 | 56 | * 头像 |
52 | 57 | */ |
58 | + @SensitiveField | |
53 | 59 | private String avatar; |
54 | 60 | |
55 | 61 | /** |
56 | 62 | * 生日 |
57 | 63 | */ |
64 | + @SensitiveField | |
58 | 65 | @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") |
59 | 66 | @DateTimeFormat(pattern = "yyyy-MM-dd") |
60 | 67 | private Date birthday; |
... | ... | @@ -67,11 +74,13 @@ public class LoginUser { |
67 | 74 | /** |
68 | 75 | * 电子邮件 |
69 | 76 | */ |
77 | + @SensitiveField | |
70 | 78 | private String email; |
71 | 79 | |
72 | 80 | /** |
73 | 81 | * 电话 |
74 | 82 | */ |
83 | + @SensitiveField | |
75 | 84 | private String phone; |
76 | 85 | |
77 | 86 | /** |
... | ... | @@ -103,11 +112,13 @@ public class LoginUser { |
103 | 112 | /** |
104 | 113 | * 职务,关联职务表 |
105 | 114 | */ |
115 | + @SensitiveField | |
106 | 116 | private String post; |
107 | 117 | |
108 | 118 | /** |
109 | 119 | * 座机号 |
110 | 120 | */ |
121 | + @SensitiveField | |
111 | 122 | private String telephone; |
112 | 123 | |
113 | 124 | /**多租户id配置,编辑用户的时候设置*/ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
... | ... | @@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; |
7 | 7 | import lombok.extern.slf4j.Slf4j; |
8 | 8 | import org.jeecg.common.constant.CommonConstant; |
9 | 9 | import org.jeecg.common.constant.DataBaseConstant; |
10 | +import org.jeecg.common.constant.ServiceNameConstants; | |
10 | 11 | import org.jeecg.common.constant.SymbolConstant; |
11 | 12 | import org.jeecg.common.util.filter.FileTypeFilter; |
12 | 13 | import org.jeecg.common.util.oss.OssBootUtil; |
... | ... | @@ -314,14 +315,14 @@ public class CommonUtils { |
314 | 315 | */ |
315 | 316 | public static String getBaseUrl(HttpServletRequest request) { |
316 | 317 | //1.【兼容】兼容微服务下的 base path------- |
317 | - String xGatewayBasePath = request.getHeader("X_GATEWAY_BASE_PATH"); | |
318 | + String xGatewayBasePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH); | |
318 | 319 | if(oConvertUtils.isNotEmpty(xGatewayBasePath)){ |
319 | 320 | log.info("x_gateway_base_path = "+ xGatewayBasePath); |
320 | 321 | return xGatewayBasePath; |
321 | 322 | } |
322 | 323 | //2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题 |
323 | 324 | // https://blog.csdn.net/weixin_34376986/article/details/89767950 |
324 | - String scheme = request.getHeader("X-Forwarded-Scheme"); | |
325 | + String scheme = request.getHeader(CommonConstant.X_FORWARDED_SCHEME); | |
325 | 326 | if(oConvertUtils.isEmpty(scheme)){ |
326 | 327 | scheme = request.getScheme(); |
327 | 328 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
... | ... | @@ -4,6 +4,8 @@ import cn.hutool.crypto.SecureUtil; |
4 | 4 | import lombok.extern.slf4j.Slf4j; |
5 | 5 | import org.jeecg.common.exception.JeecgBootException; |
6 | 6 | import javax.servlet.http.HttpServletRequest; |
7 | +import java.lang.reflect.Field; | |
8 | +import java.util.Set; | |
7 | 9 | import java.util.regex.Pattern; |
8 | 10 | |
9 | 11 | /** |
... | ... | @@ -20,7 +22,11 @@ public class SqlInjectionUtil { |
20 | 22 | private final static String TABLE_DICT_SIGN_SALT = "20200501"; |
21 | 23 | private final static String XSS_STR = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()"; |
22 | 24 | |
23 | - /**show tables*/ | |
25 | + /** | |
26 | + * 正则 user() 匹配更严谨 | |
27 | + */ | |
28 | + private final static String REGULAR_EXPRE_USER = "user[\\s]*\\([\\s]*\\)"; | |
29 | + /**正则 show tables*/ | |
24 | 30 | private final static String SHOW_TABLES = "show\\s+tables"; |
25 | 31 | |
26 | 32 | /** |
... | ... | @@ -42,6 +48,13 @@ public class SqlInjectionUtil { |
42 | 48 | log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode); |
43 | 49 | } |
44 | 50 | |
51 | + /** | |
52 | + * sql注入过滤处理,遇到注入关键字抛异常 | |
53 | + * @param value | |
54 | + */ | |
55 | + public static void filterContent(String value) { | |
56 | + filterContent(value, null); | |
57 | + } | |
45 | 58 | |
46 | 59 | /** |
47 | 60 | * sql注入过滤处理,遇到注入关键字抛异常 |
... | ... | @@ -49,7 +62,7 @@ public class SqlInjectionUtil { |
49 | 62 | * @param value |
50 | 63 | * @return |
51 | 64 | */ |
52 | - public static void filterContent(String value) { | |
65 | + public static void filterContent(String value, String customXssString) { | |
53 | 66 | if (value == null || "".equals(value)) { |
54 | 67 | return; |
55 | 68 | } |
... | ... | @@ -66,7 +79,19 @@ public class SqlInjectionUtil { |
66 | 79 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
67 | 80 | } |
68 | 81 | } |
69 | - if(Pattern.matches(SHOW_TABLES, value)){ | |
82 | + //update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号 | |
83 | + if (customXssString != null) { | |
84 | + String[] xssArr2 = customXssString.split("\\|"); | |
85 | + for (int i = 0; i < xssArr2.length; i++) { | |
86 | + if (value.indexOf(xssArr2[i]) > -1) { | |
87 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]); | |
88 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | |
89 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | |
90 | + } | |
91 | + } | |
92 | + } | |
93 | + //update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号 | |
94 | + if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){ | |
70 | 95 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
71 | 96 | } |
72 | 97 | return; |
... | ... | @@ -74,11 +99,19 @@ public class SqlInjectionUtil { |
74 | 99 | |
75 | 100 | /** |
76 | 101 | * sql注入过滤处理,遇到注入关键字抛异常 |
102 | + * @param values | |
103 | + */ | |
104 | + public static void filterContent(String[] values) { | |
105 | + filterContent(values, null); | |
106 | + } | |
107 | + | |
108 | + /** | |
109 | + * sql注入过滤处理,遇到注入关键字抛异常 | |
77 | 110 | * |
78 | 111 | * @param values |
79 | 112 | * @return |
80 | 113 | */ |
81 | - public static void filterContent(String[] values) { | |
114 | + public static void filterContent(String[] values, String customXssString) { | |
82 | 115 | String[] xssArr = XSS_STR.split("\\|"); |
83 | 116 | for (String value : values) { |
84 | 117 | if (value == null || "".equals(value)) { |
... | ... | @@ -96,7 +129,19 @@ public class SqlInjectionUtil { |
96 | 129 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
97 | 130 | } |
98 | 131 | } |
99 | - if(Pattern.matches(SHOW_TABLES, value)){ | |
132 | + //update-begin-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号 | |
133 | + if (customXssString != null) { | |
134 | + String[] xssArr2 = customXssString.split("\\|"); | |
135 | + for (int i = 0; i < xssArr2.length; i++) { | |
136 | + if (value.indexOf(xssArr2[i]) > -1) { | |
137 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr2[i]); | |
138 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | |
139 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | |
140 | + } | |
141 | + } | |
142 | + } | |
143 | + //update-end-author:taoyan date:2022-7-13 for: 除了XSS_STR这些提前设置好的,还需要额外的校验比如 单引号 | |
144 | + if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){ | |
100 | 145 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
101 | 146 | } |
102 | 147 | } |
... | ... | @@ -111,8 +156,8 @@ public class SqlInjectionUtil { |
111 | 156 | * @return |
112 | 157 | */ |
113 | 158 | //@Deprecated |
114 | - public static void specialFilterContent(String value) { | |
115 | - String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|"; | |
159 | + public static void specialFilterContentForDictSql(String value) { | |
160 | + String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|user()"; | |
116 | 161 | String[] xssArr = specialXssStr.split("\\|"); |
117 | 162 | if (value == null || "".equals(value)) { |
118 | 163 | return; |
... | ... | @@ -129,7 +174,7 @@ public class SqlInjectionUtil { |
129 | 174 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
130 | 175 | } |
131 | 176 | } |
132 | - if(Pattern.matches(SHOW_TABLES, value)){ | |
177 | + if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){ | |
133 | 178 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
134 | 179 | } |
135 | 180 | return; |
... | ... | @@ -144,7 +189,7 @@ public class SqlInjectionUtil { |
144 | 189 | */ |
145 | 190 | //@Deprecated |
146 | 191 | public static void specialFilterContentForOnlineReport(String value) { |
147 | - String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |"; | |
192 | + String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |user()"; | |
148 | 193 | String[] xssArr = specialXssStr.split("\\|"); |
149 | 194 | if (value == null || "".equals(value)) { |
150 | 195 | return; |
... | ... | @@ -162,10 +207,53 @@ public class SqlInjectionUtil { |
162 | 207 | } |
163 | 208 | } |
164 | 209 | |
165 | - if(Pattern.matches(SHOW_TABLES, value)){ | |
210 | + if(Pattern.matches(SHOW_TABLES, value) || Pattern.matches(REGULAR_EXPRE_USER, value)){ | |
166 | 211 | throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); |
167 | 212 | } |
168 | 213 | return; |
169 | 214 | } |
170 | 215 | |
216 | + | |
217 | + /** | |
218 | + * 判断给定的字段是不是类中的属性 | |
219 | + * @param field 字段名 | |
220 | + * @param clazz 类对象 | |
221 | + * @return | |
222 | + */ | |
223 | + public static boolean isClassField(String field, Class clazz){ | |
224 | + Field[] fields = clazz.getDeclaredFields(); | |
225 | + for(int i=0;i<fields.length;i++){ | |
226 | + String fieldName = fields[i].getName(); | |
227 | + String tableColumnName = oConvertUtils.camelToUnderline(fieldName); | |
228 | + if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){ | |
229 | + return true; | |
230 | + } | |
231 | + } | |
232 | + return false; | |
233 | + } | |
234 | + | |
235 | + /** | |
236 | + * 判断给定的多个字段是不是类中的属性 | |
237 | + * @param fieldSet 字段名set | |
238 | + * @param clazz 类对象 | |
239 | + * @return | |
240 | + */ | |
241 | + public static boolean isClassField(Set<String> fieldSet, Class clazz){ | |
242 | + Field[] fields = clazz.getDeclaredFields(); | |
243 | + for(String field: fieldSet){ | |
244 | + boolean exist = false; | |
245 | + for(int i=0;i<fields.length;i++){ | |
246 | + String fieldName = fields[i].getName(); | |
247 | + String tableColumnName = oConvertUtils.camelToUnderline(fieldName); | |
248 | + if(fieldName.equalsIgnoreCase(field) || tableColumnName.equalsIgnoreCase(field)){ | |
249 | + exist = true; | |
250 | + break; | |
251 | + } | |
252 | + } | |
253 | + if(!exist){ | |
254 | + return false; | |
255 | + } | |
256 | + } | |
257 | + return true; | |
258 | + } | |
171 | 259 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
... | ... | @@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; |
5 | 5 | import org.jeecg.common.api.CommonAPI; |
6 | 6 | import org.jeecg.common.constant.CacheConstant; |
7 | 7 | import org.jeecg.common.constant.CommonConstant; |
8 | +import org.jeecg.common.desensitization.util.SensitiveInfoUtil; | |
8 | 9 | import org.jeecg.common.exception.JeecgBoot401Exception; |
9 | 10 | import org.jeecg.common.system.util.JwtUtil; |
10 | 11 | import org.jeecg.common.system.vo.LoginUser; |
... | ... | @@ -106,9 +107,16 @@ public class TokenUtils { |
106 | 107 | public static LoginUser getLoginUser(String username, CommonAPI commonApi, RedisUtil redisUtil) { |
107 | 108 | LoginUser loginUser = null; |
108 | 109 | String loginUserKey = CacheConstant.SYS_USERS_CACHE + "::" + username; |
109 | - if(redisUtil.hasKey(loginUserKey)){ | |
110 | - loginUser = (LoginUser) redisUtil.get(loginUserKey); | |
111 | - }else{ | |
110 | + //【重要】此处通过redis原生获取缓存用户,是为了解决微服务下system服务挂了,其他服务互调不通问题--- | |
111 | + if (redisUtil.hasKey(loginUserKey)) { | |
112 | + try { | |
113 | + loginUser = (LoginUser) redisUtil.get(loginUserKey); | |
114 | + //解密用户 | |
115 | + SensitiveInfoUtil.handlerObject(loginUser, false); | |
116 | + } catch (IllegalAccessException e) { | |
117 | + e.printStackTrace(); | |
118 | + } | |
119 | + } else { | |
112 | 120 | // 查询用户信息 |
113 | 121 | loginUser = commonApi.getUserByName(username); |
114 | 122 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java
... | ... | @@ -66,22 +66,20 @@ public class AesEncryptUtil { |
66 | 66 | * @throws Exception |
67 | 67 | */ |
68 | 68 | public static String desEncrypt(String data, String key, String iv) throws Exception { |
69 | - try { | |
70 | - byte[] encrypted1 = Base64.decode(data); | |
69 | + //update-begin-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理 | |
70 | + byte[] encrypted1 = Base64.decode(data); | |
71 | 71 | |
72 | - Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | |
73 | - SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); | |
74 | - IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); | |
72 | + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | |
73 | + SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); | |
74 | + IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); | |
75 | 75 | |
76 | - cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); | |
76 | + cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); | |
77 | 77 | |
78 | - byte[] original = cipher.doFinal(encrypted1); | |
79 | - String originalString = new String(original); | |
80 | - return originalString; | |
81 | - } catch (Exception e) { | |
82 | - e.printStackTrace(); | |
83 | - return null; | |
84 | - } | |
78 | + byte[] original = cipher.doFinal(encrypted1); | |
79 | + String originalString = new String(original); | |
80 | + //加密解码后的字符串会出现\u0000 | |
81 | + return originalString.replaceAll("\\u0000", ""); | |
82 | + //update-end-author:taoyan date:2022-5-23 for:VUEN-1084 【vue3】online表单测试发现的新问题 6、解密报错 ---解码失败应该把异常抛出去,在外面处理 | |
85 | 83 | } |
86 | 84 | |
87 | 85 | /** |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/AbstractQueryBlackListHandler.java
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java renamed to jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeecgBaseConfig.java
1 | 1 | package org.jeecg.config; |
2 | 2 | |
3 | +import org.jeecg.config.vo.DomainUrl; | |
4 | +import org.jeecg.config.vo.Path; | |
3 | 5 | import org.jeecg.config.vo.Shiro; |
4 | 6 | import org.springframework.boot.context.properties.ConfigurationProperties; |
5 | 7 | import org.springframework.stereotype.Component; |
... | ... | @@ -9,9 +11,15 @@ import org.springframework.stereotype.Component; |
9 | 11 | * 加载项目配置 |
10 | 12 | * @author: jeecg-boot |
11 | 13 | */ |
12 | -@Component("jeeccgBaseConfig") | |
14 | +@Component("jeecgBaseConfig") | |
13 | 15 | @ConfigurationProperties(prefix = "jeecg") |
14 | -public class JeeccgBaseConfig { | |
16 | +public class JeecgBaseConfig { | |
17 | + /** | |
18 | + * 签名密钥串(字典等敏感接口) | |
19 | + * @TODO 降低使用成本加的默认值,实际以 yml配置 为准 | |
20 | + */ | |
21 | + private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | |
22 | + | |
15 | 23 | /** |
16 | 24 | * 是否启用安全模式 |
17 | 25 | */ |
... | ... | @@ -21,10 +29,16 @@ public class JeeccgBaseConfig { |
21 | 29 | */ |
22 | 30 | private Shiro shiro; |
23 | 31 | /** |
24 | - * 签名密钥串(字典等敏感接口) | |
25 | - * @TODO 降低使用成本加的默认值,实际以 yml配置 为准 | |
32 | + * 上传文件配置 | |
26 | 33 | */ |
27 | - private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | |
34 | + private Path path; | |
35 | + | |
36 | + /** | |
37 | + * 前端页面访问地址 | |
38 | + * pc: http://localhost:3100 | |
39 | + * app: http://localhost:8051 | |
40 | + */ | |
41 | + private DomainUrl domainUrl; | |
28 | 42 | |
29 | 43 | public Boolean getSafeMode() { |
30 | 44 | return safeMode; |
... | ... | @@ -49,4 +63,20 @@ public class JeeccgBaseConfig { |
49 | 63 | public void setShiro(Shiro shiro) { |
50 | 64 | this.shiro = shiro; |
51 | 65 | } |
66 | + | |
67 | + public Path getPath() { | |
68 | + return path; | |
69 | + } | |
70 | + | |
71 | + public void setPath(Path path) { | |
72 | + this.path = path; | |
73 | + } | |
74 | + | |
75 | + public DomainUrl getDomainUrl() { | |
76 | + return domainUrl; | |
77 | + } | |
78 | + | |
79 | + public void setDomainUrl(DomainUrl domainUrl) { | |
80 | + this.domainUrl = domainUrl; | |
81 | + } | |
52 | 82 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
... | ... | @@ -145,4 +145,13 @@ public class WebMvcConfiguration implements WebMvcConfigurer { |
145 | 145 | return () -> meterRegistryPostProcessor.postProcessAfterInitialization(prometheusMeterRegistry, ""); |
146 | 146 | } |
147 | 147 | |
148 | +// /** | |
149 | +// * 注册拦截器【拦截器拦截参数,自动切换数据源——后期实现多租户切换数据源功能】 | |
150 | +// * @param registry | |
151 | +// */ | |
152 | +// @Override | |
153 | +// public void addInterceptors(InterceptorRegistry registry) { | |
154 | +// registry.addInterceptor(new DynamicDatasourceInterceptor()).addPathPatterns("/test/dynamic/**"); | |
155 | +// } | |
156 | + | |
148 | 157 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
... | ... | @@ -3,6 +3,9 @@ package org.jeecg.config.mybatis; |
3 | 3 | import java.util.ArrayList; |
4 | 4 | import java.util.List; |
5 | 5 | |
6 | +import cn.hutool.core.util.ObjectUtil; | |
7 | +import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor; | |
8 | +import org.jeecg.common.constant.CommonConstant; | |
6 | 9 | import org.jeecg.common.util.oConvertUtils; |
7 | 10 | import org.mybatis.spring.annotation.MapperScan; |
8 | 11 | import org.springframework.context.annotation.Bean; |
... | ... | @@ -71,9 +74,35 @@ public class MybatisPlusSaasConfig { |
71 | 74 | } |
72 | 75 | })); |
73 | 76 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); |
77 | + //update-begin-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题 | |
78 | + interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor()); | |
79 | + //update-end-author:zyf date:20220425 for:【VUEN-606】注入动态表名适配拦截器解决多表名问题 | |
74 | 80 | return interceptor; |
75 | 81 | } |
76 | 82 | |
83 | + /** | |
84 | + * 动态表名切换拦截器,用于适配vue2和vue3同一个表有多个的情况,如sys_role_index在vue3情况下表名为sys_role_index_v3 | |
85 | + * @return | |
86 | + */ | |
87 | + private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() { | |
88 | + DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor(); | |
89 | + dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> { | |
90 | + //获取需要动态解析的表名 | |
91 | + String dynamicTableName = ThreadLocalDataHelper.get(CommonConstant.DYNAMIC_TABLE_NAME); | |
92 | + //当dynamicTableName不为空时才走动态表名处理逻辑,否则返回原始表名 | |
93 | + if (ObjectUtil.isNotEmpty(dynamicTableName) && dynamicTableName.equals(tableName)) { | |
94 | + // 获取前端传递的版本号标识 | |
95 | + Object version = ThreadLocalDataHelper.get(CommonConstant.VERSION); | |
96 | + if (ObjectUtil.isNotEmpty(version)) { | |
97 | + //拼接表名规则(原始表名+下划线+前端传递的版本号) | |
98 | + return tableName + "_" + version; | |
99 | + } | |
100 | + } | |
101 | + return tableName; | |
102 | + }); | |
103 | + return dynamicTableNameInnerInterceptor; | |
104 | + } | |
105 | + | |
77 | 106 | // /** |
78 | 107 | // * 下个版本会删除,现在为了避免缓存出现问题不得不配置 |
79 | 108 | // * @return |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/ThreadLocalDataHelper.java
0 → 100644
1 | +package org.jeecg.config.mybatis; | |
2 | + | |
3 | +import cn.hutool.core.util.ObjectUtil; | |
4 | +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; | |
5 | +import java.util.concurrent.ConcurrentHashMap; | |
6 | + | |
7 | + | |
8 | +/** | |
9 | + * @Description: 本地线程变量存储工具类 | |
10 | + * @author: lsq | |
11 | + * @date: 2022年03月25日 11:42 | |
12 | + */ | |
13 | +public class ThreadLocalDataHelper { | |
14 | + /** | |
15 | + * 线程的本地变量 | |
16 | + */ | |
17 | + private static final ThreadLocal<ConcurrentHashMap> REQUEST_DATA = new ThreadLocal<>(); | |
18 | + | |
19 | + /** | |
20 | + * 存储本地参数 | |
21 | + */ | |
22 | + private static final ConcurrentHashMap DATA_MAP = new ConcurrentHashMap<>(); | |
23 | + | |
24 | + /** | |
25 | + * 设置请求参数 | |
26 | + * | |
27 | + * @param key 参数key | |
28 | + * @param value 参数值 | |
29 | + */ | |
30 | + public static void put(String key, Object value) { | |
31 | + if(ObjectUtil.isNotEmpty(value)) { | |
32 | + DATA_MAP.put(key, value); | |
33 | + REQUEST_DATA.set(DATA_MAP); | |
34 | + } | |
35 | + } | |
36 | + | |
37 | + /** | |
38 | + * 获取请求参数值 | |
39 | + * | |
40 | + * @param key 请求参数 | |
41 | + * @return | |
42 | + */ | |
43 | + public static <T> T get(String key) { | |
44 | + ConcurrentHashMap dataMap = REQUEST_DATA.get(); | |
45 | + if (CollectionUtils.isNotEmpty(dataMap)) { | |
46 | + return (T) dataMap.get(key); | |
47 | + } | |
48 | + return null; | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * 获取请求参数 | |
53 | + * | |
54 | + * @return 请求参数 MAP 对象 | |
55 | + */ | |
56 | + public static void clear() { | |
57 | + DATA_MAP.clear(); | |
58 | + REQUEST_DATA.remove(); | |
59 | + } | |
60 | + | |
61 | +} | |
62 | + | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/aspect/DynamicTableAspect.java
0 → 100644
1 | +package org.jeecg.config.mybatis.aspect; | |
2 | + | |
3 | +import org.aspectj.lang.ProceedingJoinPoint; | |
4 | +import org.aspectj.lang.annotation.Around; | |
5 | +import org.aspectj.lang.annotation.Aspect; | |
6 | +import org.aspectj.lang.annotation.Pointcut; | |
7 | +import org.aspectj.lang.reflect.MethodSignature; | |
8 | +import org.jeecg.common.aspect.annotation.DynamicTable; | |
9 | +import org.jeecg.common.constant.CommonConstant; | |
10 | +import org.jeecg.common.util.SpringContextUtils; | |
11 | +import org.jeecg.config.mybatis.ThreadLocalDataHelper; | |
12 | +import org.springframework.stereotype.Component; | |
13 | + | |
14 | +import javax.servlet.http.HttpServletRequest; | |
15 | +import java.lang.reflect.Method; | |
16 | + | |
17 | +/** | |
18 | + * 动态table切换 切面处理 | |
19 | + * | |
20 | + * @author :zyf | |
21 | + * @date:2020-04-25 | |
22 | + */ | |
23 | +@Aspect | |
24 | +@Component | |
25 | +public class DynamicTableAspect { | |
26 | + | |
27 | + | |
28 | + /** | |
29 | + * 定义切面拦截切入点 | |
30 | + */ | |
31 | + @Pointcut("@annotation(org.jeecg.common.aspect.annotation.DynamicTable)") | |
32 | + public void dynamicTable() { | |
33 | + } | |
34 | + | |
35 | + | |
36 | + @Around("dynamicTable()") | |
37 | + public Object around(ProceedingJoinPoint point) throws Throwable { | |
38 | + MethodSignature signature = (MethodSignature) point.getSignature(); | |
39 | + Method method = signature.getMethod(); | |
40 | + DynamicTable dynamicTable = method.getAnnotation(DynamicTable.class); | |
41 | + HttpServletRequest request = SpringContextUtils.getHttpServletRequest(); | |
42 | + //获取前端传递的版本标记 | |
43 | + String version = request.getHeader(CommonConstant.VERSION); | |
44 | + //存储版本号到本地线程变量 | |
45 | + ThreadLocalDataHelper.put(CommonConstant.VERSION, version); | |
46 | + //存储表名到本地线程变量 | |
47 | + ThreadLocalDataHelper.put(CommonConstant.DYNAMIC_TABLE_NAME, dynamicTable.value()); | |
48 | + //执行方法 | |
49 | + Object result = point.proceed(); | |
50 | + //清空本地变量 | |
51 | + ThreadLocalDataHelper.clear(); | |
52 | + return result; | |
53 | + } | |
54 | + | |
55 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/interceptor/DynamicDatasourceInterceptor.java
0 → 100644
1 | +package org.jeecg.config.mybatis.interceptor; | |
2 | + | |
3 | +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; | |
4 | +import lombok.extern.slf4j.Slf4j; | |
5 | +import org.apache.commons.lang3.StringUtils; | |
6 | +import org.springframework.web.servlet.HandlerInterceptor; | |
7 | +import org.springframework.web.servlet.ModelAndView; | |
8 | + | |
9 | +import javax.servlet.http.HttpServletRequest; | |
10 | +import javax.servlet.http.HttpServletResponse; | |
11 | + | |
12 | +/** | |
13 | + * 动态数据源切换拦截器 | |
14 | + * | |
15 | + * 测试:拦截参数,自动切换数据源 | |
16 | + * 未来规划:后面通过此机制,实现多租户切换数据源功能 | |
17 | + * @author zyf | |
18 | + */ | |
19 | +@Slf4j | |
20 | +public class DynamicDatasourceInterceptor implements HandlerInterceptor { | |
21 | + | |
22 | + /** | |
23 | + * 在请求处理之前进行调用(Controller方法调用之前) | |
24 | + */ | |
25 | + @Override | |
26 | + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { | |
27 | + String requestURI = request.getRequestURI(); | |
28 | + log.info("经过多数据源Interceptor,当前路径是{}", requestURI); | |
29 | + //获取动态数据源名称 | |
30 | + String dsName = request.getParameter("dsName"); | |
31 | + String dsKey = "master"; | |
32 | + if (StringUtils.isNotEmpty(dsName)) { | |
33 | + dsKey = dsName; | |
34 | + } | |
35 | + DynamicDataSourceContextHolder.push(dsKey); | |
36 | + return true; | |
37 | + } | |
38 | + | |
39 | + /** | |
40 | + * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后) | |
41 | + */ | |
42 | + @Override | |
43 | + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { | |
44 | + | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * 在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作) | |
49 | + */ | |
50 | + @Override | |
51 | + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { | |
52 | + DynamicDataSourceContextHolder.clear(); | |
53 | + } | |
54 | + | |
55 | +} | |
0 | 56 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
... | ... | @@ -15,7 +15,7 @@ import org.crazycake.shiro.RedisClusterManager; |
15 | 15 | import org.crazycake.shiro.RedisManager; |
16 | 16 | import org.jeecg.common.constant.CommonConstant; |
17 | 17 | import org.jeecg.common.util.oConvertUtils; |
18 | -import org.jeecg.config.JeeccgBaseConfig; | |
18 | +import org.jeecg.config.JeecgBaseConfig; | |
19 | 19 | import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean; |
20 | 20 | import org.jeecg.config.shiro.filters.JwtFilter; |
21 | 21 | import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; |
... | ... | @@ -45,11 +45,11 @@ import java.util.*; |
45 | 45 | public class ShiroConfig { |
46 | 46 | |
47 | 47 | @Resource |
48 | - LettuceConnectionFactory lettuceConnectionFactory; | |
48 | + private LettuceConnectionFactory lettuceConnectionFactory; | |
49 | 49 | @Autowired |
50 | 50 | private Environment env; |
51 | - @Autowired | |
52 | - JeeccgBaseConfig jeeccgBaseConfig; | |
51 | + @Resource | |
52 | + private JeecgBaseConfig jeecgBaseConfig; | |
53 | 53 | |
54 | 54 | /** |
55 | 55 | * Filter Chain定义说明 |
... | ... | @@ -64,11 +64,15 @@ public class ShiroConfig { |
64 | 64 | shiroFilterFactoryBean.setSecurityManager(securityManager); |
65 | 65 | // 拦截器 |
66 | 66 | Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); |
67 | - String shiroExcludeUrls = jeeccgBaseConfig.getShiro().getExcludeUrls(); | |
68 | - if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){ | |
69 | - String[] permissionUrl = shiroExcludeUrls.split(","); | |
70 | - for(String url : permissionUrl){ | |
71 | - filterChainDefinitionMap.put(url,"anon"); | |
67 | + | |
68 | + //支持yml方式,配置拦截排除 | |
69 | + if(jeecgBaseConfig.getShiro()!=null){ | |
70 | + String shiroExcludeUrls = jeecgBaseConfig.getShiro().getExcludeUrls(); | |
71 | + if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){ | |
72 | + String[] permissionUrl = shiroExcludeUrls.split(","); | |
73 | + for(String url : permissionUrl){ | |
74 | + filterChainDefinitionMap.put(url,"anon"); | |
75 | + } | |
72 | 76 | } |
73 | 77 | } |
74 | 78 | // 配置不会被拦截的链接 顺序判断 |
... | ... | @@ -125,9 +129,11 @@ public class ShiroConfig { |
125 | 129 | filterChainDefinitionMap.put("/jmreport/**", "anon"); |
126 | 130 | filterChainDefinitionMap.put("/**/*.js.map", "anon"); |
127 | 131 | filterChainDefinitionMap.put("/**/*.css.map", "anon"); |
128 | - | |
129 | - //测试示例 | |
130 | - filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子 | |
132 | + | |
133 | + //大屏模板例子 | |
134 | + filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); | |
135 | + filterChainDefinitionMap.put("/bigscreen/template1/**", "anon"); | |
136 | + filterChainDefinitionMap.put("/bigscreen/template1/**", "anon"); | |
131 | 137 | //filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试 |
132 | 138 | //filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面 |
133 | 139 | //filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试 |
... | ... | @@ -137,8 +143,6 @@ public class ShiroConfig { |
137 | 143 | filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块 |
138 | 144 | filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例 |
139 | 145 | |
140 | - //wps | |
141 | - filterChainDefinitionMap.put("/v1/**","anon"); | |
142 | 146 | |
143 | 147 | //性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有) |
144 | 148 | filterChainDefinitionMap.put("/actuator/**", "anon"); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
... | ... | @@ -69,13 +69,13 @@ public class ShiroRealm extends AuthorizingRealm { |
69 | 69 | |
70 | 70 | // 设置用户拥有的角色集合,比如“admin,test” |
71 | 71 | Set<String> roleSet = commonApi.queryUserRoles(username); |
72 | - System.out.println(roleSet.toString()); | |
72 | + //System.out.println(roleSet.toString()); | |
73 | 73 | info.setRoles(roleSet); |
74 | 74 | |
75 | 75 | // 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add” |
76 | 76 | Set<String> permissionSet = commonApi.queryUserAuths(username); |
77 | 77 | info.addStringPermissions(permissionSet); |
78 | - System.out.println(permissionSet); | |
78 | + //System.out.println(permissionSet); | |
79 | 79 | log.info("===============Shiro权限认证成功=============="); |
80 | 80 | return info; |
81 | 81 | } |
... | ... | @@ -123,7 +123,7 @@ public class ShiroRealm extends AuthorizingRealm { |
123 | 123 | |
124 | 124 | // 查询用户信息 |
125 | 125 | log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token); |
126 | - LoginUser loginUser = TokenUtils.getLoginUser(username,commonApi,redisUtil); | |
126 | + LoginUser loginUser = TokenUtils.getLoginUser(username, commonApi, redisUtil); | |
127 | 127 | //LoginUser loginUser = commonApi.getUserByName(username); |
128 | 128 | if (loginUser == null) { |
129 | 129 | throw new AuthenticationException("用户不存在!"); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
... | ... | @@ -107,4 +107,18 @@ public class JwtFilter extends BasicHttpAuthenticationFilter { |
107 | 107 | |
108 | 108 | return super.preHandle(request, response); |
109 | 109 | } |
110 | + | |
111 | + /** | |
112 | + * JwtFilter中ThreadLocal需要及时清除 #3634 | |
113 | + * | |
114 | + * @param request | |
115 | + * @param response | |
116 | + * @param exception | |
117 | + * @throws Exception | |
118 | + */ | |
119 | + @Override | |
120 | + public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception { | |
121 | + //log.info("------清空线程中多租户的ID={}------",TenantContext.getTenant()); | |
122 | + TenantContext.clear(); | |
123 | + } | |
110 | 124 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
1 | 1 | package org.jeecg.config.sign.interceptor; |
2 | 2 | |
3 | +import org.jeecg.config.filter.RequestBodyReserveFilter; | |
4 | +import org.springframework.boot.web.servlet.FilterRegistrationBean; | |
3 | 5 | import org.springframework.context.annotation.Bean; |
4 | 6 | import org.springframework.context.annotation.Configuration; |
5 | 7 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
... | ... | @@ -24,4 +26,22 @@ public class SignAuthConfiguration implements WebMvcConfigurer { |
24 | 26 | public void addInterceptors(InterceptorRegistry registry) { |
25 | 27 | registry.addInterceptor(signAuthInterceptor()).addPathPatterns(SIGN_URL_LIST); |
26 | 28 | } |
29 | + | |
30 | + //update-begin-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空 | |
31 | + @Bean | |
32 | + public RequestBodyReserveFilter requestBodyReserveFilter(){ | |
33 | + return new RequestBodyReserveFilter(); | |
34 | + } | |
35 | + | |
36 | + @Bean | |
37 | + public FilterRegistrationBean reqBodyFilterRegistrationBean(){ | |
38 | + FilterRegistrationBean registration = new FilterRegistrationBean(); | |
39 | + registration.setFilter(requestBodyReserveFilter()); | |
40 | + registration.setName("requestBodyReserveFilter"); | |
41 | + // 建议此处只添加post请求地址而不是所有的都需要走过滤器 | |
42 | + registration.addUrlPatterns(SIGN_URL_LIST); | |
43 | + return registration; | |
44 | + } | |
45 | + //update-end-author:taoyan date:20220427 for: issues/I53J5E post请求X_SIGN签名拦截校验后报错, request body 为空 | |
46 | + | |
27 | 47 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
... | ... | @@ -32,7 +32,7 @@ public class SignAuthInterceptor implements HandlerInterceptor { |
32 | 32 | |
33 | 33 | @Override |
34 | 34 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
35 | - log.info("request URI = " + request.getRequestURI()); | |
35 | + log.info("Sign Interceptor request URI = " + request.getRequestURI()); | |
36 | 36 | HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request); |
37 | 37 | //获取全部参数(包括URL和body上的) |
38 | 38 | SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
... | ... | @@ -6,7 +6,7 @@ import org.jeecg.common.constant.SymbolConstant; |
6 | 6 | import org.jeecg.common.exception.JeecgBootException; |
7 | 7 | import org.jeecg.common.util.SpringContextUtils; |
8 | 8 | import org.jeecg.common.util.oConvertUtils; |
9 | -import org.jeecg.config.JeeccgBaseConfig; | |
9 | +import org.jeecg.config.JeecgBaseConfig; | |
10 | 10 | import org.springframework.util.DigestUtils; |
11 | 11 | import org.springframework.util.StringUtils; |
12 | 12 | |
... | ... | @@ -48,8 +48,8 @@ public class SignUtil { |
48 | 48 | String paramsJsonStr = JSONObject.toJSONString(params); |
49 | 49 | log.info("Param paramsJsonStr : {}", paramsJsonStr); |
50 | 50 | //设置签名秘钥 |
51 | - JeeccgBaseConfig jeeccgBaseConfig = SpringContextUtils.getBean(JeeccgBaseConfig.class); | |
52 | - String signatureSecret = jeeccgBaseConfig.getSignatureSecret(); | |
51 | + JeecgBaseConfig jeecgBaseConfig = SpringContextUtils.getBean(JeecgBaseConfig.class); | |
52 | + String signatureSecret = jeecgBaseConfig.getSignatureSecret(); | |
53 | 53 | String curlyBracket = SymbolConstant.DOLLAR + SymbolConstant.LEFT_CURLY_BRACKET; |
54 | 54 | if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains(curlyBracket)){ |
55 | 55 | throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!"); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/DomainUrl.java
0 → 100644
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Path.java
0 → 100644
1 | +package org.jeecg.config.vo; | |
2 | + | |
3 | +import javax.print.DocFlavor; | |
4 | + | |
5 | +/** | |
6 | + * | |
7 | + * @author: scott | |
8 | + * @date: 2022年04月18日 20:35 | |
9 | + */ | |
10 | +public class Path { | |
11 | + private String upload; | |
12 | + private String webapp; | |
13 | + | |
14 | + public String getUpload() { | |
15 | + return upload; | |
16 | + } | |
17 | + | |
18 | + public void setUpload(String upload) { | |
19 | + this.upload = upload; | |
20 | + } | |
21 | + | |
22 | + public String getWebapp() { | |
23 | + return webapp; | |
24 | + } | |
25 | + | |
26 | + public void setWebapp(String webapp) { | |
27 | + this.webapp = webapp; | |
28 | + } | |
29 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
... | ... | @@ -4,19 +4,22 @@ |
4 | 4 | |
5 | 5 | <!-- 保存日志11 --> |
6 | 6 | <insert id="saveLog" parameterType="Object"> |
7 | - insert into sys_log (id, log_type, log_content, method, operate_type, request_param, ip, userid, username, cost_time, create_time) | |
7 | + insert into sys_log (id, log_type, log_content, method, operate_type, request_url, request_type, request_param, ip, userid, username, cost_time, create_time,create_by) | |
8 | 8 | values( |
9 | 9 | #{dto.id,jdbcType=VARCHAR}, |
10 | 10 | #{dto.logType,jdbcType=INTEGER}, |
11 | 11 | #{dto.logContent,jdbcType=VARCHAR}, |
12 | 12 | #{dto.method,jdbcType=VARCHAR}, |
13 | 13 | #{dto.operateType,jdbcType=INTEGER}, |
14 | + #{dto.requestUrl,jdbcType=VARCHAR}, | |
15 | + #{dto.requestType,jdbcType=VARCHAR}, | |
14 | 16 | #{dto.requestParam,jdbcType=VARCHAR}, |
15 | 17 | #{dto.ip,jdbcType=VARCHAR}, |
16 | 18 | #{dto.userid,jdbcType=VARCHAR}, |
17 | 19 | #{dto.username,jdbcType=VARCHAR}, |
18 | 20 | #{dto.costTime,jdbcType=BIGINT}, |
19 | - #{dto.createTime,jdbcType=TIMESTAMP} | |
21 | + #{dto.createTime,jdbcType=TIMESTAMP}, | |
22 | + #{dto.createBy,jdbcType=VARCHAR} | |
20 | 23 | ) |
21 | 24 | </insert> |
22 | 25 | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
... | ... | @@ -34,6 +34,7 @@ public class BaseCommonServiceImpl implements BaseCommonService { |
34 | 34 | } |
35 | 35 | //保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238 |
36 | 36 | try { |
37 | + logDTO.setCreateTime(new Date()); | |
37 | 38 | baseCommonMapper.saveLog(logDTO); |
38 | 39 | } catch (Exception e) { |
39 | 40 | log.warn(" LogContent length : "+logDTO.getLogContent().length()); |
... | ... |