zhouxiang
2022-03-24 db287aac9eb5032b1158b405a9b4807301467ed3
提交 | 用户 | age
c64e12 1 package com.hx.mybatis.aes.springbean;
e29546 2
c64e12 3 import com.gitee.sunchenbin.mybatis.actable.annotation.Table;
e29546 4 import com.hx.common.annotations.MysqlHexAes;
C 5 import com.hx.util.StringUtils;
346eb2 6 import org.slf4j.Logger;
C 7 import org.slf4j.LoggerFactory;
e29546 8 import org.springframework.stereotype.Component;
C 9
10 import javax.annotation.PostConstruct;
11 import javax.annotation.Resource;
12 import java.io.File;
13 import java.io.FileFilter;
14 import java.io.IOException;
15 import java.lang.reflect.Field;
346eb2 16 import java.net.JarURLConnection;
e29546 17 import java.net.URL;
C 18 import java.net.URLDecoder;
19 import java.util.*;
346eb2 20 import java.util.jar.JarEntry;
C 21 import java.util.jar.JarFile;
e29546 22
C 23 /**
24  * 获取指定包里面的AES秘钥
25  */
26 @Component
27 public class VariableAesKey {
346eb2 28
C 29     //log4j日志
30     private static Logger logger = LoggerFactory.getLogger(VariableAesKey.class.getName());
e29546 31
C 32     @Resource
33     private ConstantBean constantBean;
34
c64e12 35     /**是否已经启动完*/
C 36     public static int isRun = 0;
37
38     /**存储所有AES的秘钥*/
e29546 39     public static Map<String,String> aesKeys = new HashMap<>();
c64e12 40     /**根据表明来存储AES秘钥*/
C 41     public static Map<String,Map<String,String>> aesKeysTable = new HashMap<>();
42
43     /**固定的aes秘钥*/
44     public static String AES_KEY = null;
b1097d 45     /**数据库加密字段初始化版本号*/
C 46     public static String INIT_VERSION = null;
47
48
e29546 49
C 50     /**存储AES秘钥*/
51     public static void setAesKey(String aesKeyFild,String aesKey){
52         aesKeys.put(aesKeyFild,aesKey);
53     }
54     /**获取AES秘钥*/
55     public static String getAesKey(String aesKeyFild){
c64e12 56         if(aesKeyFild == null){
C 57             return AES_KEY;
58         }
59         if(StringUtils.isEmpty(aesKeys.get(aesKeyFild))){
60             return AES_KEY;
61         }else {
62             return  aesKeys.get(aesKeyFild);
63         }
e29546 64     }
C 65
66     /**
67      * 项目启动就执行后就执行该方法
68      */
69     @PostConstruct
70     public void VariableAesKey(){
c64e12 71
C 72         isRun = 1;
e29546 73         //项目启动的时候填入
346eb2 74         logger.info("扫描获取AES的包:" + constantBean.getPackPath());
c64e12 75         AES_KEY = constantBean.getFixedAesKey();
b1097d 76         INIT_VERSION = constantBean.getInitVersion();
af1eee 77         if(!StringUtils.isEmpty(constantBean.getPackPath())){
e29546 78             Set<Class<?>> classes = classData(constantBean.getPackPath());
346eb2 79             logger.info("扫描获取AES的包classes:" + classes.size());
c64e12 80             Map<String,String> aesKeysFild = new HashMap<>();
C 81             boolean isAes = false;
82             String tableName = null;
83
e29546 84             for(Class<?> cl:classes){
c64e12 85                 //表名称
346eb2 86                 boolean hasAnnotation = cl.isAnnotationPresent(Table.class);
C 87                 if(!hasAnnotation){
c64e12 88                     continue;
C 89                 }
346eb2 90                 Table table = cl.getAnnotation(Table.class);
c64e12 91                 tableName = table.name();
C 92
93                 aesKeysFild = new HashMap<>();
94                 isAes = false;
95
e29546 96                 // 取得本类的全部属性
C 97                 Field[] fields = cl.getDeclaredFields();
98                 fields = getPatentFields(fields,cl);
99                 for (Field field:fields) {
100                     // 判断方法中是否有指定注解类型的注解
346eb2 101                     hasAnnotation = field.isAnnotationPresent(MysqlHexAes.class);
e29546 102                     if (hasAnnotation) {
C 103                         // 根据注解类型返回方法的指定类型注解
104                         MysqlHexAes mysqlHexAes = field.getAnnotation(MysqlHexAes.class);
105
c64e12 106                         //String aesKeyField = mysqlHexAes.aesKeyField();
e29546 107                         String aesKey = mysqlHexAes.aesKey();
C 108
109                         if(StringUtils.isEmpty(aesKey)){
c64e12 110                             aesKey = constantBean.getFixedAesKey();
C 111                             if(StringUtils.isEmpty(aesKey)){
112                                 throw new RuntimeException("mysql的AES秘钥不能为空:"+field.getName());
e29546 113                             }
c64e12 114                         }
C 115                         String key = aesKeys.get(field.getName());
116                         if(StringUtils.isEmpty(key)){
117                             aesKeys.put(field.getName(),aesKey);
118                             aesKeysFild.put(field.getName(),aesKey);
119                             isAes = true;
e29546 120                         }else{
c64e12 121                             isAes = true;
C 122                             aesKeysFild.put(field.getName(),aesKey);
123                             if(!aesKey.equals(key)){
124                                 throw new RuntimeException("字段/定义的AES秘钥字段【"+field.getName()+"】多个一样,但是AES秘钥不一样");
e29546 125                             }
C 126                         }
127                     }
c64e12 128                 }
C 129                 if(isAes){
130                     aesKeysTable.put(tableName,aesKeysFild);
e29546 131                 }
C 132             }
133         }
134     }
135
136     /**获取包下面的所有文件*/
137     public static Set<Class<?>> classData(String packPath){
346eb2 138         Set<Class<?>> classes = new LinkedHashSet();
C 139         String[] split = packPath.split(",|;");
140         String[] var3 = split;
141         int var4 = split.length;
c64e12 142
346eb2 143         label82:
C 144         for(int var5 = 0; var5 < var4; ++var5) {
145             String pack = var3[var5];
c64e12 146             boolean recursive = true;
346eb2 147             String packageName = pack;
C 148             String packageDirName = pack.replace('.', '/');
149
150             try {
151                 Enumeration dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
152
153                 while(true) {
154                     label75:
155                     while(true) {
156                         if (!dirs.hasMoreElements()) {
157                             continue label82;
158                         }
159
160                         URL url = (URL)dirs.nextElement();
161                         String protocol = url.getProtocol();
162                         if ("file".equals(protocol)) {
163                             System.err.println("file类型的扫描:" + pack);
164                             String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
165                             findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);
166                         } else if ("jar".equals(protocol)) {
167                             System.err.println("jar类型的扫描");
168
169                             try {
170                                 JarFile jar = ((JarURLConnection)url.openConnection()).getJarFile();
171                                 Enumeration entries = jar.entries();
172
173                                 while(true) {
174                                     JarEntry entry;
175                                     String name;
176                                     int idx;
177                                     do {
178                                         do {
179                                             if (!entries.hasMoreElements()) {
180                                                 continue label75;
181                                             }
182
183                                             entry = (JarEntry)entries.nextElement();
184                                             name = entry.getName();
185                                             if (name.charAt(0) == '/') {
186                                                 name = name.substring(1);
187                                             }
188                                         } while(!name.startsWith(packageDirName));
189
190                                         idx = name.lastIndexOf(47);
191                                         if (idx != -1) {
192                                             packageName = name.substring(0, idx).replace('/', '.');
193                                         }
194                                     } while(idx == -1 && !recursive);
195
196                                     if (name.endsWith(".class") && !entry.isDirectory()) {
197                                         String className = name.substring(packageName.length() + 1, name.length() - 6);
198
199                                         try {
200                                             classes.add(Class.forName(packageName + '.' + className));
201                                         } catch (ClassNotFoundException var20) {
202                                             var20.printStackTrace();
203                                         }
204                                     }
205                                 }
206                             } catch (IOException var21) {
207                                 var21.printStackTrace();
208                             }
209                         }
c64e12 210                     }
e29546 211                 }
346eb2 212             } catch (IOException var22) {
C 213                 var22.printStackTrace();
e29546 214             }
C 215         }
346eb2 216
e29546 217         return classes;
C 218     }
219
220     /**
221      * 以文件的形式来获取包下的所有Class
222      *
223      * @param packageName
224      * @param packagePath
225      * @param recursive
226      * @param classes
227      */
228     public static void findAndAddClassesInPackageByFile(
229             String packageName,
230             String packagePath,
231             final boolean recursive,
232             Set<Class<?>> classes){
233         // 获取此包的目录 建立一个File
234         File dir = new File(packagePath);
235         // 如果不存在或者 也不是目录就直接返回
236         if (!dir.exists() || !dir.isDirectory()) {
237             // log.warn("用户定义包名 " + packageName + " 下没有任何文件");
238             return;
239         }
240         // 如果存在 就获取包下的所有文件 包括目录
241         File[] dirfiles = dir.listFiles(new FileFilter(){
242             // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
243             @Override
244             public boolean accept(File file){
245                 return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
246             }
247         });
248         // 循环所有文件
249         for (File file : dirfiles){
250             // 如果是目录 则继续扫描
251             if (file.isDirectory()) {
252                 findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
253             }else{
254                 // 如果是java类文件 去掉后面的.class 只留下类名
255                 String className = file.getName().substring(0, file.getName().length() - 6);
256                 try{
257                     // 添加到集合中去
258                     // classes.add(Class.forName(packageName + '.' +
259                     // className));
260                     // 经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净
261                     classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
262                 }catch (ClassNotFoundException e){
263                     // log.error("添加用户自定义视图类错误 找不到此类的.class文件");
264                     e.printStackTrace();
265                 }
266             }
267         }
268     }
269
270     /**
271      * 获取父类的字段
272      * @param fields
273      * @param clas
274      * @return
275      */
276     public static Field[] getPatentFields(Field[] fields,Class<?> clas){
277         if (clas.getSuperclass() != null) {
278             Class clsSup = clas.getSuperclass();
279             List<Field> fieldList = new ArrayList<Field>();
280             fieldList.addAll(Arrays.asList(fields));
281             fieldList.addAll(Arrays.asList(clsSup.getDeclaredFields()));
282             fields = new Field[fieldList.size()];
283             int i = 0;
284             for (Object field : fieldList.toArray()) {
285                 fields[i] = (Field) field;
286                 i++;
287             }
288             fields = getPatentFields(fields,clsSup);
289         }
290         return  fields;
291     }
292
293
294 }