干燥机配套车间生产管理系统/云平台服务端
baoshiwei
2023-03-10 58d42ccf875b120f40fddce63752298e916e0b0b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
package org.jeecg.common.desensitization.util;
 
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.desensitization.annotation.SensitiveField;
import org.jeecg.common.desensitization.enums.SensitiveEnum;
import org.jeecg.common.util.encryption.AesEncryptUtil;
import org.jeecg.common.util.oConvertUtils;
 
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Collections;
import java.util.List;
 
/**
 * 敏感信息处理工具类
 * @author taoYan
 * @date 2022/4/20 18:01
 **/
@Slf4j
public class SensitiveInfoUtil {
 
    /**
     * 处理嵌套对象
     * @param obj 方法返回值
     * @param entity 实体class
     * @param isEncode 是否加密(true: 加密操作 / false:解密操作)
     * @throws IllegalAccessException
     */
    public static void handleNestedObject(Object obj, Class entity, boolean isEncode) throws IllegalAccessException {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            if(field.getType().isPrimitive()){
                continue;
            }
            if(field.getType().equals(entity)){
                // 对象里面是实体
                field.setAccessible(true);
                Object nestedObject = field.get(obj);
                handlerObject(nestedObject, isEncode);
                break;
            }else{
                // 对象里面是List<实体>
                if(field.getGenericType() instanceof ParameterizedType){
                    ParameterizedType pt = (ParameterizedType)field.getGenericType();
                    if(pt.getRawType().equals(List.class)){
                        if(pt.getActualTypeArguments()[0].equals(entity)){
                            field.setAccessible(true);
                            Object nestedObject = field.get(obj);
                            handleList(nestedObject, entity, isEncode);
                            break;
                        }
                    }
                }
            }
        }
    }
 
    /**
     * 处理Object
     * @param obj 方法返回值
     * @param isEncode 是否加密(true: 加密操作 / false:解密操作)
     * @return
     * @throws IllegalAccessException
     */
    public static Object handlerObject(Object obj, boolean isEncode) throws IllegalAccessException {
        if (oConvertUtils.isEmpty(obj)) {
            return obj;
        }
        long startTime=System.currentTimeMillis();
        log.debug(" obj --> "+ obj.toString());
        
        // 判断是不是一个对象
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean isSensitiveField = field.isAnnotationPresent(SensitiveField.class);
            if(isSensitiveField){
                // 必须有SensitiveField注解 才作处理
                if(field.getType().isAssignableFrom(String.class)){
                    //必须是字符串类型 才作处理
                    field.setAccessible(true);
                    String realValue = (String) field.get(obj);
                    if(realValue==null || "".equals(realValue)){
                        continue;
                    }
                    SensitiveField sf = field.getAnnotation(SensitiveField.class);
                    if(isEncode==true){
                        //加密
                        String value = SensitiveInfoUtil.getEncodeData(realValue,  sf.type());
                        field.set(obj, value);
                    }else{
                        //解密只处理 encode类型的
                        if(sf.type().equals(SensitiveEnum.ENCODE)){
                            String value = SensitiveInfoUtil.getDecodeData(realValue);
                            field.set(obj, value);
                        }
                    }
                }
            }
        }
        //long endTime=System.currentTimeMillis();
        //log.info((isEncode ? "加密操作," : "解密操作,") + "当前程序耗时:" + (endTime - startTime) + "ms");
        return obj;
    }
 
    /**
     * 处理 List<实体>
     * @param obj
     * @param entity
     * @param isEncode(true: 加密操作 / false:解密操作)
     */
    public static void handleList(Object obj, Class entity, boolean isEncode){
        List list = (List)obj;
        if(list.size()>0){
            Object first = list.get(0);
            if(first.getClass().equals(entity)){
                for(int i=0; i<list.size(); i++){
                    Object temp = list.get(i);
                    try {
                        handlerObject(temp, isEncode);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
 
 
    /**
     * 处理数据 获取解密后的数据
     * @param data
     * @return
     */
    public static String getDecodeData(String data){
        String result = null;
        try {
            result = AesEncryptUtil.desEncrypt(data);
        } catch (Exception exception) {
            log.debug("数据解密错误,原数据:"+data);
        }
        //解决debug模式下,加解密失效导致中文被解密变成空的问题
        if(oConvertUtils.isEmpty(result) && oConvertUtils.isNotEmpty(data)){
            result = data;
        }
        return result;
    }
 
    /**
     * 处理数据 获取加密后的数据 或是格式化后的数据
     * @param data 字符串
     * @param sensitiveEnum 类型
     * @return 处理后的字符串
     */
    public static String getEncodeData(String data, SensitiveEnum sensitiveEnum){
        String result;
        switch (sensitiveEnum){
            case ENCODE:
                try {
                    result = AesEncryptUtil.encrypt(data);
                } catch (Exception exception) {
                    log.error("数据加密错误", exception.getMessage());
                    result = data;
                }
                break;
            case CHINESE_NAME:
                result = chineseName(data);
                break;
            case ID_CARD:
                result = idCardNum(data);
                break;
            case FIXED_PHONE:
                result = fixedPhone(data);
                break;
            case MOBILE_PHONE:
                result = mobilePhone(data);
                break;
            case ADDRESS:
                result = address(data, 3);
                break;
            case EMAIL:
                result = email(data);
                break;
            case BANK_CARD:
                result = bankCard(data);
                break;
            case CNAPS_CODE:
                result = cnapsCode(data);
                break;
            default:
                result = data;
        }
        return result;
    }
 
 
    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号
     * @param fullName 全名
     * @return <例子:李**>
     */
    private static String chineseName(String fullName) {
        if (oConvertUtils.isEmpty(fullName)) {
            return "";
        }
        return formatRight(fullName, 1);
    }
 
    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号
     * @param familyName 姓
     * @param firstName 名
     * @return <例子:李**>
     */
    private static String chineseName(String familyName, String firstName) {
        if (oConvertUtils.isEmpty(familyName) || oConvertUtils.isEmpty(firstName)) {
            return "";
        }
        return chineseName(familyName + firstName);
    }
 
    /**
     * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。
     * @param id 身份证号
     * @return <例子:*************5762>
     */
    private static String idCardNum(String id) {
        if (oConvertUtils.isEmpty(id)) {
            return "";
        }
        return formatLeft(id, 4);
 
    }
 
    /**
     * [固定电话] 后四位,其他隐藏
     * @param num 固定电话
     * @return <例子:****1234>
     */
    private static String fixedPhone(String num) {
        if (oConvertUtils.isEmpty(num)) {
            return "";
        }
        return formatLeft(num, 4);
    }
 
    /**
     * [手机号码] 前三位,后四位,其他隐藏
     * @param num 手机号码
     * @return <例子:138******1234>
     */
    private static String mobilePhone(String num) {
        if (oConvertUtils.isEmpty(num)) {
            return "";
        }
        int len = num.length();
        if(len<11){
            return num;
        }
        return formatBetween(num, 3, 4);
    }
 
    /**
     * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护
     * @param address 地址
     * @param sensitiveSize 敏感信息长度
     * @return <例子:北京市海淀区****>
     */
    private static String address(String address, int sensitiveSize) {
        if (oConvertUtils.isEmpty(address)) {
            return "";
        }
        int len = address.length();
        if(len<sensitiveSize){
            return address;
        }
        return formatRight(address, sensitiveSize);
    }
 
    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示
     * @param email 电子邮箱
     * @return <例子:g**@163.com>
     */
    private static String email(String email) {
        if (oConvertUtils.isEmpty(email)) {
            return "";
        }
        int index = email.indexOf("@");
        if (index <= 1){
            return email;
        }
        String begin = email.substring(0, 1);
        String end = email.substring(index);
        String stars = "**";
        return begin + stars + end;
    }
 
    /**
     * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号
     * @param cardNum 银行卡号
     * @return <例子:6222600**********1234>
     */
    private static String bankCard(String cardNum) {
        if (oConvertUtils.isEmpty(cardNum)) {
            return "";
        }
        return formatBetween(cardNum, 6, 4);
    }
 
    /**
     * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号
     * @param code 公司开户银行联号
     * @return <例子:12********>
     */
    private static String cnapsCode(String code) {
        if (oConvertUtils.isEmpty(code)) {
            return "";
        }
        return formatRight(code, 2);
    }
 
 
    /**
     * 将右边的格式化成*
     * @param str 字符串
     * @param reservedLength 保留长度
     * @return 格式化后的字符串
     */
    private static String formatRight(String str, int reservedLength){
        String name = str.substring(0, reservedLength);
        String stars = String.join("", Collections.nCopies(str.length()-reservedLength, "*"));
        return name + stars;
    }
 
    /**
     * 将左边的格式化成*
     * @param str 字符串
     * @param reservedLength 保留长度
     * @return 格式化后的字符串
     */
    private static String formatLeft(String str, int reservedLength){
        int len = str.length();
        String show = str.substring(len-reservedLength);
        String stars = String.join("", Collections.nCopies(len-reservedLength, "*"));
        return stars + show;
    }
 
    /**
     * 将中间的格式化成*
     * @param str 字符串
     * @param beginLen 开始保留长度
     * @param endLen 结尾保留长度
     * @return 格式化后的字符串
     */
    private static String formatBetween(String str, int beginLen, int endLen){
        int len = str.length();
        String begin = str.substring(0, beginLen);
        String end = str.substring(len-endLen);
        String stars = String.join("", Collections.nCopies(len-beginLen-endLen, "*"));
        return begin + stars + end;
    }
 
}