Commit 6c6376411cccdd1dd1fdc0f5861661bda4e1f332
1 parent
b7c29a22
no message
Showing
1744 changed files
with
570595 additions
and
0 deletions
Too many changes.
To preserve performance only 100 of 1744 files are displayed.
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/IPUtils.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import javax.servlet.http.HttpServletRequest; | ||
| 4 | + | ||
| 5 | +import org.apache.commons.lang3.StringUtils; | ||
| 6 | +import org.slf4j.Logger; | ||
| 7 | +import org.slf4j.LoggerFactory; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IP地址 | ||
| 11 | + * | ||
| 12 | + * @Author scott | ||
| 13 | + * @email jeecgos@163.com | ||
| 14 | + * @Date 2019年01月14日 | ||
| 15 | + */ | ||
| 16 | +public class IPUtils { | ||
| 17 | + private static Logger logger = LoggerFactory.getLogger(IPUtils.class); | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 获取IP地址 | ||
| 21 | + * | ||
| 22 | + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 | ||
| 23 | + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 | ||
| 24 | + */ | ||
| 25 | + public static String getIpAddr(HttpServletRequest request) { | ||
| 26 | + String ip = null; | ||
| 27 | + try { | ||
| 28 | + ip = request.getHeader("x-forwarded-for"); | ||
| 29 | + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { | ||
| 30 | + ip = request.getHeader("Proxy-Client-IP"); | ||
| 31 | + } | ||
| 32 | + if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | ||
| 33 | + ip = request.getHeader("WL-Proxy-Client-IP"); | ||
| 34 | + } | ||
| 35 | + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { | ||
| 36 | + ip = request.getHeader("HTTP_CLIENT_IP"); | ||
| 37 | + } | ||
| 38 | + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { | ||
| 39 | + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); | ||
| 40 | + } | ||
| 41 | + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { | ||
| 42 | + ip = request.getRemoteAddr(); | ||
| 43 | + } | ||
| 44 | + } catch (Exception e) { | ||
| 45 | + logger.error("IPUtils ERROR ", e); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | +// //使用代理,则获取第一个IP地址 | ||
| 49 | +// if(StringUtils.isEmpty(ip) && ip.length() > 15) { | ||
| 50 | +// if(ip.indexOf(",") > 0) { | ||
| 51 | +// ip = ip.substring(0, ip.indexOf(",")); | ||
| 52 | +// } | ||
| 53 | +// } | ||
| 54 | + | ||
| 55 | + return ip; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ImportExcelUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson.JSONObject; | ||
| 4 | +import com.baomidou.mybatisplus.extension.service.IService; | ||
| 5 | +import lombok.extern.slf4j.Slf4j; | ||
| 6 | +import org.jeecg.common.api.vo.Result; | ||
| 7 | +import org.jeecg.common.constant.CommonConstant; | ||
| 8 | + | ||
| 9 | +import java.io.File; | ||
| 10 | +import java.io.IOException; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * 导出返回信息 | ||
| 15 | + */ | ||
| 16 | +@Slf4j | ||
| 17 | +public class ImportExcelUtil { | ||
| 18 | + | ||
| 19 | + public static Result<?> imporReturnRes(int errorLines,int successLines,List<String> errorMessage) throws IOException { | ||
| 20 | + if (errorLines == 0) { | ||
| 21 | + return Result.ok("共" + successLines + "行数据全部导入成功!"); | ||
| 22 | + } else { | ||
| 23 | + JSONObject result = new JSONObject(5); | ||
| 24 | + int totalCount = successLines + errorLines; | ||
| 25 | + result.put("totalCount", totalCount); | ||
| 26 | + result.put("errorCount", errorLines); | ||
| 27 | + result.put("successCount", successLines); | ||
| 28 | + result.put("msg", "总上传行数:" + totalCount + ",已导入行数:" + successLines + ",错误行数:" + errorLines); | ||
| 29 | + String fileUrl = PmsUtil.saveErrorTxtByList(errorMessage, "userImportExcelErrorLog"); | ||
| 30 | + int lastIndex = fileUrl.lastIndexOf(File.separator); | ||
| 31 | + String fileName = fileUrl.substring(lastIndex + 1); | ||
| 32 | + result.put("fileUrl", "/sys/common/static/" + fileUrl); | ||
| 33 | + result.put("fileName", fileName); | ||
| 34 | + Result res = Result.ok(result); | ||
| 35 | + res.setCode(201); | ||
| 36 | + res.setMessage("文件导入成功,但有错误。"); | ||
| 37 | + return res; | ||
| 38 | + } | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public static List<String> importDateSave(List<Object> list, Class serviceClass,List<String> errorMessage,String errorFlag) { | ||
| 42 | + IService bean =(IService) SpringContextUtils.getBean(serviceClass); | ||
| 43 | + for (int i = 0; i < list.size(); i++) { | ||
| 44 | + try { | ||
| 45 | + boolean save = bean.save(list.get(i)); | ||
| 46 | + if(!save){ | ||
| 47 | + throw new Exception(errorFlag); | ||
| 48 | + } | ||
| 49 | + } catch (Exception e) { | ||
| 50 | + String message = e.getMessage().toLowerCase(); | ||
| 51 | + int lineNumber = i + 1; | ||
| 52 | + // 通过索引名判断出错信息 | ||
| 53 | + if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_ROLE_CODE)) { | ||
| 54 | + errorMessage.add("第 " + lineNumber + " 行:角色编码已经存在,忽略导入。"); | ||
| 55 | + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME)) { | ||
| 56 | + errorMessage.add("第 " + lineNumber + " 行:任务类名已经存在,忽略导入。"); | ||
| 57 | + }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CODE)) { | ||
| 58 | + errorMessage.add("第 " + lineNumber + " 行:职务编码已经存在,忽略导入。"); | ||
| 59 | + }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE)) { | ||
| 60 | + errorMessage.add("第 " + lineNumber + " 行:部门编码已经存在,忽略导入。"); | ||
| 61 | + }else { | ||
| 62 | + errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); | ||
| 63 | + log.error(e.getMessage(), e); | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + return errorMessage; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + public static List<String> importDateSaveOne(Object obj, Class serviceClass,List<String> errorMessage,int i,String errorFlag) { | ||
| 71 | + IService bean =(IService) SpringContextUtils.getBean(serviceClass); | ||
| 72 | + try { | ||
| 73 | + boolean save = bean.save(obj); | ||
| 74 | + if(!save){ | ||
| 75 | + throw new Exception(errorFlag); | ||
| 76 | + } | ||
| 77 | + } catch (Exception e) { | ||
| 78 | + String message = e.getMessage().toLowerCase(); | ||
| 79 | + int lineNumber = i + 1; | ||
| 80 | + // 通过索引名判断出错信息 | ||
| 81 | + if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_ROLE_CODE)) { | ||
| 82 | + errorMessage.add("第 " + lineNumber + " 行:角色编码已经存在,忽略导入。"); | ||
| 83 | + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME)) { | ||
| 84 | + errorMessage.add("第 " + lineNumber + " 行:任务类名已经存在,忽略导入。"); | ||
| 85 | + }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CODE)) { | ||
| 86 | + errorMessage.add("第 " + lineNumber + " 行:职务编码已经存在,忽略导入。"); | ||
| 87 | + }else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE)) { | ||
| 88 | + errorMessage.add("第 " + lineNumber + " 行:部门编码已经存在,忽略导入。"); | ||
| 89 | + }else { | ||
| 90 | + errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); | ||
| 91 | + log.error(e.getMessage(), e); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + return errorMessage; | ||
| 95 | + } | ||
| 96 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MD5Util.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import java.security.MessageDigest; | ||
| 4 | + | ||
| 5 | +public class MD5Util { | ||
| 6 | + | ||
| 7 | + public static String byteArrayToHexString(byte b[]) { | ||
| 8 | + StringBuffer resultSb = new StringBuffer(); | ||
| 9 | + for (int i = 0; i < b.length; i++){ | ||
| 10 | + resultSb.append(byteToHexString(b[i])); | ||
| 11 | + } | ||
| 12 | + return resultSb.toString(); | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + private static String byteToHexString(byte b) { | ||
| 16 | + int n = b; | ||
| 17 | + if (n < 0) { | ||
| 18 | + n += 256; | ||
| 19 | + } | ||
| 20 | + int d1 = n / 16; | ||
| 21 | + int d2 = n % 16; | ||
| 22 | + return hexDigits[d1] + hexDigits[d2]; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public static String MD5Encode(String origin, String charsetname) { | ||
| 26 | + String resultString = null; | ||
| 27 | + try { | ||
| 28 | + resultString = new String(origin); | ||
| 29 | + MessageDigest md = MessageDigest.getInstance("MD5"); | ||
| 30 | + if (charsetname == null || "".equals(charsetname)) { | ||
| 31 | + resultString = byteArrayToHexString(md.digest(resultString.getBytes())); | ||
| 32 | + } else { | ||
| 33 | + resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname))); | ||
| 34 | + } | ||
| 35 | + } catch (Exception exception) { | ||
| 36 | + } | ||
| 37 | + return resultString; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5", | ||
| 41 | + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; | ||
| 42 | + | ||
| 43 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import io.minio.*; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.jeecg.common.util.filter.StrAttackFilter; | ||
| 6 | +import org.springframework.web.multipart.MultipartFile; | ||
| 7 | + | ||
| 8 | +import java.io.InputStream; | ||
| 9 | +import java.net.URLDecoder; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * minio文件上传工具类 | ||
| 13 | + */ | ||
| 14 | +@Slf4j | ||
| 15 | +public class MinioUtil { | ||
| 16 | + private static String minioUrl; | ||
| 17 | + private static String minioName; | ||
| 18 | + private static String minioPass; | ||
| 19 | + private static String bucketName; | ||
| 20 | + | ||
| 21 | + public static void setMinioUrl(String minioUrl) { | ||
| 22 | + MinioUtil.minioUrl = minioUrl; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public static void setMinioName(String minioName) { | ||
| 26 | + MinioUtil.minioName = minioName; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public static void setMinioPass(String minioPass) { | ||
| 30 | + MinioUtil.minioPass = minioPass; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public static void setBucketName(String bucketName) { | ||
| 34 | + MinioUtil.bucketName = bucketName; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public static String getMinioUrl() { | ||
| 38 | + return minioUrl; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public static String getBucketName() { | ||
| 42 | + return bucketName; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + private static MinioClient minioClient = null; | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * 上传文件 | ||
| 49 | + * @param file | ||
| 50 | + * @return | ||
| 51 | + */ | ||
| 52 | + public static String upload(MultipartFile file, String bizPath, String customBucket) { | ||
| 53 | + String file_url = ""; | ||
| 54 | + //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击 | ||
| 55 | + bizPath=StrAttackFilter.filter(bizPath); | ||
| 56 | + //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击 | ||
| 57 | + String newBucket = bucketName; | ||
| 58 | + if(oConvertUtils.isNotEmpty(customBucket)){ | ||
| 59 | + newBucket = customBucket; | ||
| 60 | + } | ||
| 61 | + try { | ||
| 62 | + initMinio(minioUrl, minioName,minioPass); | ||
| 63 | + // 检查存储桶是否已经存在 | ||
| 64 | + if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) { | ||
| 65 | + log.info("Bucket already exists."); | ||
| 66 | + } else { | ||
| 67 | + // 创建一个名为ota的存储桶 | ||
| 68 | + minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build()); | ||
| 69 | + log.info("create a new bucket."); | ||
| 70 | + } | ||
| 71 | + InputStream stream = file.getInputStream(); | ||
| 72 | + // 获取文件名 | ||
| 73 | + String orgName = file.getOriginalFilename(); | ||
| 74 | + if("".equals(orgName)){ | ||
| 75 | + orgName=file.getName(); | ||
| 76 | + } | ||
| 77 | + orgName = CommonUtils.getFileName(orgName); | ||
| 78 | + String objectName = bizPath+"/" | ||
| 79 | + +( orgName.indexOf(".")==-1 | ||
| 80 | + ?orgName + "_" + System.currentTimeMillis() | ||
| 81 | + :orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf(".")) | ||
| 82 | + ); | ||
| 83 | + | ||
| 84 | + // 使用putObject上传一个本地文件到存储桶中。 | ||
| 85 | + if(objectName.startsWith("/")){ | ||
| 86 | + objectName = objectName.substring(1); | ||
| 87 | + } | ||
| 88 | + PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName) | ||
| 89 | + .bucket(newBucket) | ||
| 90 | + .contentType("application/octet-stream") | ||
| 91 | + .stream(stream,stream.available(),-1).build(); | ||
| 92 | + minioClient.putObject(objectArgs); | ||
| 93 | + stream.close(); | ||
| 94 | + file_url = minioUrl+newBucket+"/"+objectName; | ||
| 95 | + }catch (Exception e){ | ||
| 96 | + log.error(e.getMessage(), e); | ||
| 97 | + } | ||
| 98 | + return file_url; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + /** | ||
| 102 | + * 文件上传 | ||
| 103 | + * @param file | ||
| 104 | + * @param bizPath | ||
| 105 | + * @return | ||
| 106 | + */ | ||
| 107 | + public static String upload(MultipartFile file, String bizPath) { | ||
| 108 | + return upload(file,bizPath,null); | ||
| 109 | + } | ||
| 110 | + | ||
| 111 | + /** | ||
| 112 | + * 获取文件流 | ||
| 113 | + * @param bucketName | ||
| 114 | + * @param objectName | ||
| 115 | + * @return | ||
| 116 | + */ | ||
| 117 | + public static InputStream getMinioFile(String bucketName,String objectName){ | ||
| 118 | + InputStream inputStream = null; | ||
| 119 | + try { | ||
| 120 | + initMinio(minioUrl, minioName, minioPass); | ||
| 121 | + GetObjectArgs objectArgs = GetObjectArgs.builder().object(objectName) | ||
| 122 | + .bucket(bucketName).build(); | ||
| 123 | + inputStream = minioClient.getObject(objectArgs); | ||
| 124 | + } catch (Exception e) { | ||
| 125 | + log.info("文件获取失败" + e.getMessage()); | ||
| 126 | + } | ||
| 127 | + return inputStream; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * 删除文件 | ||
| 132 | + * @param bucketName | ||
| 133 | + * @param objectName | ||
| 134 | + * @throws Exception | ||
| 135 | + */ | ||
| 136 | + public static void removeObject(String bucketName, String objectName) { | ||
| 137 | + try { | ||
| 138 | + initMinio(minioUrl, minioName,minioPass); | ||
| 139 | + RemoveObjectArgs objectArgs = RemoveObjectArgs.builder().object(objectName) | ||
| 140 | + .bucket(bucketName).build(); | ||
| 141 | + minioClient.removeObject(objectArgs); | ||
| 142 | + }catch (Exception e){ | ||
| 143 | + log.info("文件删除失败" + e.getMessage()); | ||
| 144 | + } | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + /** | ||
| 148 | + * 获取文件外链 | ||
| 149 | + * @param bucketName | ||
| 150 | + * @param objectName | ||
| 151 | + * @param expires | ||
| 152 | + * @return | ||
| 153 | + */ | ||
| 154 | + public static String getObjectURL(String bucketName, String objectName, Integer expires) { | ||
| 155 | + initMinio(minioUrl, minioName,minioPass); | ||
| 156 | + try{ | ||
| 157 | + GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName) | ||
| 158 | + .bucket(bucketName) | ||
| 159 | + .expiry(expires).build(); | ||
| 160 | + String url = minioClient.getPresignedObjectUrl(objectArgs); | ||
| 161 | + return URLDecoder.decode(url,"UTF-8"); | ||
| 162 | + }catch (Exception e){ | ||
| 163 | + log.info("文件路径获取失败" + e.getMessage()); | ||
| 164 | + } | ||
| 165 | + return null; | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + /** | ||
| 169 | + * 初始化客户端 | ||
| 170 | + * @param minioUrl | ||
| 171 | + * @param minioName | ||
| 172 | + * @param minioPass | ||
| 173 | + * @return | ||
| 174 | + */ | ||
| 175 | + private static MinioClient initMinio(String minioUrl, String minioName,String minioPass) { | ||
| 176 | + if (minioClient == null) { | ||
| 177 | + try { | ||
| 178 | + minioClient = MinioClient.builder() | ||
| 179 | + .endpoint(minioUrl) | ||
| 180 | + .credentials(minioName, minioPass) | ||
| 181 | + .build(); | ||
| 182 | + } catch (Exception e) { | ||
| 183 | + e.printStackTrace(); | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | + return minioClient; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + /** | ||
| 190 | + * 上传文件到minio | ||
| 191 | + * @param stream | ||
| 192 | + * @param relativePath | ||
| 193 | + * @return | ||
| 194 | + */ | ||
| 195 | + public static String upload(InputStream stream,String relativePath) throws Exception { | ||
| 196 | + initMinio(minioUrl, minioName,minioPass); | ||
| 197 | + if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { | ||
| 198 | + log.info("Bucket already exists."); | ||
| 199 | + } else { | ||
| 200 | + // 创建一个名为ota的存储桶 | ||
| 201 | + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); | ||
| 202 | + log.info("create a new bucket."); | ||
| 203 | + } | ||
| 204 | + PutObjectArgs objectArgs = PutObjectArgs.builder().object(relativePath) | ||
| 205 | + .bucket(bucketName) | ||
| 206 | + .contentType("application/octet-stream") | ||
| 207 | + .stream(stream,stream.available(),-1).build(); | ||
| 208 | + minioClient.putObject(objectArgs); | ||
| 209 | + stream.close(); | ||
| 210 | + return minioUrl+bucketName+"/"+relativePath; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MyClassLoader.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * @Author 张代浩 | ||
| 5 | + */ | ||
| 6 | +public class MyClassLoader extends ClassLoader { | ||
| 7 | + public static Class getClassByScn(String className) { | ||
| 8 | + Class myclass = null; | ||
| 9 | + try { | ||
| 10 | + myclass = Class.forName(className); | ||
| 11 | + } catch (ClassNotFoundException e) { | ||
| 12 | + e.printStackTrace(); | ||
| 13 | + throw new RuntimeException(className+" not found!"); | ||
| 14 | + } | ||
| 15 | + return myclass; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + // 获得类的全名,包括包名 | ||
| 19 | + public static String getPackPath(Object object) { | ||
| 20 | + // 检查用户传入的参数是否为空 | ||
| 21 | + if (object == null) { | ||
| 22 | + throw new java.lang.IllegalArgumentException("参数不能为空!"); | ||
| 23 | + } | ||
| 24 | + // 获得类的全名,包括包名 | ||
| 25 | + String clsName = object.getClass().getName(); | ||
| 26 | + return clsName; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public static String getAppPath(Class cls) { | ||
| 30 | + // 检查用户传入的参数是否为空 | ||
| 31 | + if (cls == null) { | ||
| 32 | + throw new java.lang.IllegalArgumentException("参数不能为空!"); | ||
| 33 | + } | ||
| 34 | + ClassLoader loader = cls.getClassLoader(); | ||
| 35 | + // 获得类的全名,包括包名 | ||
| 36 | + String clsName = cls.getName() + ".class"; | ||
| 37 | + // 获得传入参数所在的包 | ||
| 38 | + Package pack = cls.getPackage(); | ||
| 39 | + String path = ""; | ||
| 40 | + // 如果不是匿名包,将包名转化为路径 | ||
| 41 | + if (pack != null) { | ||
| 42 | + String packName = pack.getName(); | ||
| 43 | + // 此处简单判定是否是Java基础类库,防止用户传入JDK内置的类库 | ||
| 44 | + if (packName.startsWith("java.") || packName.startsWith("javax.")) { | ||
| 45 | + throw new java.lang.IllegalArgumentException("不要传送系统类!"); | ||
| 46 | + } | ||
| 47 | + // 在类的名称中,去掉包名的部分,获得类的文件名 | ||
| 48 | + clsName = clsName.substring(packName.length() + 1); | ||
| 49 | + // 判定包名是否是简单包名,如果是,则直接将包名转换为路径, | ||
| 50 | + if (packName.indexOf(".") < 0) { | ||
| 51 | + path = packName + "/"; | ||
| 52 | + } else {// 否则按照包名的组成部分,将包名转换为路径 | ||
| 53 | + int start = 0, end = 0; | ||
| 54 | + end = packName.indexOf("."); | ||
| 55 | + while (end != -1) { | ||
| 56 | + path = path + packName.substring(start, end) + "/"; | ||
| 57 | + start = end + 1; | ||
| 58 | + end = packName.indexOf(".", start); | ||
| 59 | + } | ||
| 60 | + path = path + packName.substring(start) + "/"; | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + // 调用ClassLoader的getResource方法,传入包含路径信息的类文件名 | ||
| 64 | + java.net.URL url = loader.getResource(path + clsName); | ||
| 65 | + // 从URL对象中获取路径信息 | ||
| 66 | + String realPath = url.getPath(); | ||
| 67 | + // 去掉路径信息中的协议名"file:" | ||
| 68 | + int pos = realPath.indexOf("file:"); | ||
| 69 | + if (pos > -1) { | ||
| 70 | + realPath = realPath.substring(pos + 5); | ||
| 71 | + } | ||
| 72 | + // 去掉路径信息最后包含类文件信息的部分,得到类所在的路径 | ||
| 73 | + pos = realPath.indexOf(path + clsName); | ||
| 74 | + realPath = realPath.substring(0, pos - 1); | ||
| 75 | + // 如果类文件被打包到JAR等文件中时,去掉对应的JAR等打包文件名 | ||
| 76 | + if (realPath.endsWith("!")) { | ||
| 77 | + realPath = realPath.substring(0, realPath.lastIndexOf("/")); | ||
| 78 | + } | ||
| 79 | + /*------------------------------------------------------------ | ||
| 80 | + ClassLoader的getResource方法使用了utf-8对路径信息进行了编码,当路径 | ||
| 81 | + 中存在中文和空格时,他会对这些字符进行转换,这样,得到的往往不是我们想要 | ||
| 82 | + 的真实路径,在此,调用了URLDecoder的decode方法进行解码,以便得到原始的 | ||
| 83 | + 中文及空格路径 | ||
| 84 | + -------------------------------------------------------------*/ | ||
| 85 | + try { | ||
| 86 | + realPath = java.net.URLDecoder.decode(realPath, "utf-8"); | ||
| 87 | + } catch (Exception e) { | ||
| 88 | + throw new RuntimeException(e); | ||
| 89 | + } | ||
| 90 | + return realPath; | ||
| 91 | + }// getAppPath定义结束 | ||
| 92 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PasswordUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import java.security.Key; | ||
| 4 | +import java.security.SecureRandom; | ||
| 5 | +import javax.crypto.Cipher; | ||
| 6 | +import javax.crypto.SecretKey; | ||
| 7 | +import javax.crypto.SecretKeyFactory; | ||
| 8 | +import javax.crypto.spec.PBEKeySpec; | ||
| 9 | +import javax.crypto.spec.PBEParameterSpec; | ||
| 10 | +public class PasswordUtil { | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * JAVA6支持以下任意一种算法 PBEWITHMD5ANDDES PBEWITHMD5ANDTRIPLEDES | ||
| 14 | + * PBEWITHSHAANDDESEDE PBEWITHSHA1ANDRC2_40 PBKDF2WITHHMACSHA1 | ||
| 15 | + * */ | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 定义使用的算法为:PBEWITHMD5andDES算法 | ||
| 19 | + */ | ||
| 20 | + public static final String ALGORITHM = "PBEWithMD5AndDES";//加密算法 | ||
| 21 | + public static final String Salt = "63293188";//密钥 | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * 定义迭代次数为1000次 | ||
| 25 | + */ | ||
| 26 | + private static final int ITERATIONCOUNT = 1000; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 获取加密算法中使用的盐值,解密中使用的盐值必须与加密中使用的相同才能完成操作. 盐长度必须为8字节 | ||
| 30 | + * | ||
| 31 | + * @return byte[] 盐值 | ||
| 32 | + * */ | ||
| 33 | + public static byte[] getSalt() throws Exception { | ||
| 34 | + // 实例化安全随机数 | ||
| 35 | + SecureRandom random = new SecureRandom(); | ||
| 36 | + // 产出盐 | ||
| 37 | + return random.generateSeed(8); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public static byte[] getStaticSalt() { | ||
| 41 | + // 产出盐 | ||
| 42 | + return Salt.getBytes(); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 根据PBE密码生成一把密钥 | ||
| 47 | + * | ||
| 48 | + * @param password | ||
| 49 | + * 生成密钥时所使用的密码 | ||
| 50 | + * @return Key PBE算法密钥 | ||
| 51 | + * */ | ||
| 52 | + private static Key getPBEKey(String password) { | ||
| 53 | + // 实例化使用的算法 | ||
| 54 | + SecretKeyFactory keyFactory; | ||
| 55 | + SecretKey secretKey = null; | ||
| 56 | + try { | ||
| 57 | + keyFactory = SecretKeyFactory.getInstance(ALGORITHM); | ||
| 58 | + // 设置PBE密钥参数 | ||
| 59 | + PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray()); | ||
| 60 | + // 生成密钥 | ||
| 61 | + secretKey = keyFactory.generateSecret(keySpec); | ||
| 62 | + } catch (Exception e) { | ||
| 63 | + // TODO Auto-generated catch block | ||
| 64 | + e.printStackTrace(); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + return secretKey; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 加密明文字符串 | ||
| 72 | + * | ||
| 73 | + * @param plaintext | ||
| 74 | + * 待加密的明文字符串 | ||
| 75 | + * @param password | ||
| 76 | + * 生成密钥时所使用的密码 | ||
| 77 | + * @param salt | ||
| 78 | + * 盐值 | ||
| 79 | + * @return 加密后的密文字符串 | ||
| 80 | + * @throws Exception | ||
| 81 | + */ | ||
| 82 | + public static String encrypt(String plaintext, String password, String salt) { | ||
| 83 | + | ||
| 84 | + Key key = getPBEKey(password); | ||
| 85 | + byte[] encipheredData = null; | ||
| 86 | + PBEParameterSpec parameterSpec = new PBEParameterSpec(salt.getBytes(), ITERATIONCOUNT); | ||
| 87 | + try { | ||
| 88 | + Cipher cipher = Cipher.getInstance(ALGORITHM); | ||
| 89 | + | ||
| 90 | + cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec); | ||
| 91 | + //update-begin-author:sccott date:20180815 for:中文作为用户名时,加密的密码windows和linux会得到不同的结果 gitee/issues/IZUD7 | ||
| 92 | + encipheredData = cipher.doFinal(plaintext.getBytes("utf-8")); | ||
| 93 | + //update-end-author:sccott date:20180815 for:中文作为用户名时,加密的密码windows和linux会得到不同的结果 gitee/issues/IZUD7 | ||
| 94 | + } catch (Exception e) { | ||
| 95 | + } | ||
| 96 | + return bytesToHexString(encipheredData); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * 解密密文字符串 | ||
| 101 | + * | ||
| 102 | + * @param ciphertext | ||
| 103 | + * 待解密的密文字符串 | ||
| 104 | + * @param password | ||
| 105 | + * 生成密钥时所使用的密码(如需解密,该参数需要与加密时使用的一致) | ||
| 106 | + * @param salt | ||
| 107 | + * 盐值(如需解密,该参数需要与加密时使用的一致) | ||
| 108 | + * @return 解密后的明文字符串 | ||
| 109 | + * @throws Exception | ||
| 110 | + */ | ||
| 111 | + public static String decrypt(String ciphertext, String password, String salt) { | ||
| 112 | + | ||
| 113 | + Key key = getPBEKey(password); | ||
| 114 | + byte[] passDec = null; | ||
| 115 | + PBEParameterSpec parameterSpec = new PBEParameterSpec(salt.getBytes(), ITERATIONCOUNT); | ||
| 116 | + try { | ||
| 117 | + Cipher cipher = Cipher.getInstance(ALGORITHM); | ||
| 118 | + | ||
| 119 | + cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec); | ||
| 120 | + | ||
| 121 | + passDec = cipher.doFinal(hexStringToBytes(ciphertext)); | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + catch (Exception e) { | ||
| 125 | + // TODO: handle exception | ||
| 126 | + } | ||
| 127 | + return new String(passDec); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + /** | ||
| 131 | + * 将字节数组转换为十六进制字符串 | ||
| 132 | + * | ||
| 133 | + * @param src | ||
| 134 | + * 字节数组 | ||
| 135 | + * @return | ||
| 136 | + */ | ||
| 137 | + public static String bytesToHexString(byte[] src) { | ||
| 138 | + StringBuilder stringBuilder = new StringBuilder(""); | ||
| 139 | + if (src == null || src.length <= 0) { | ||
| 140 | + return null; | ||
| 141 | + } | ||
| 142 | + for (int i = 0; i < src.length; i++) { | ||
| 143 | + int v = src[i] & 0xFF; | ||
| 144 | + String hv = Integer.toHexString(v); | ||
| 145 | + if (hv.length() < 2) { | ||
| 146 | + stringBuilder.append(0); | ||
| 147 | + } | ||
| 148 | + stringBuilder.append(hv); | ||
| 149 | + } | ||
| 150 | + return stringBuilder.toString(); | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + /** | ||
| 154 | + * 将十六进制字符串转换为字节数组 | ||
| 155 | + * | ||
| 156 | + * @param hexString | ||
| 157 | + * 十六进制字符串 | ||
| 158 | + * @return | ||
| 159 | + */ | ||
| 160 | + public static byte[] hexStringToBytes(String hexString) { | ||
| 161 | + if (hexString == null || hexString.equals("")) { | ||
| 162 | + return null; | ||
| 163 | + } | ||
| 164 | + hexString = hexString.toUpperCase(); | ||
| 165 | + int length = hexString.length() / 2; | ||
| 166 | + char[] hexChars = hexString.toCharArray(); | ||
| 167 | + byte[] d = new byte[length]; | ||
| 168 | + for (int i = 0; i < length; i++) { | ||
| 169 | + int pos = i * 2; | ||
| 170 | + d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); | ||
| 171 | + } | ||
| 172 | + return d; | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + private static byte charToByte(char c) { | ||
| 176 | + return (byte) "0123456789ABCDEF".indexOf(c); | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + | ||
| 180 | +} | ||
| 0 | \ No newline at end of file | 181 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/PmsUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +import java.io.BufferedWriter; | ||
| 8 | +import java.io.File; | ||
| 9 | +import java.io.FileWriter; | ||
| 10 | +import java.util.Date; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +@Slf4j | ||
| 14 | +@Component | ||
| 15 | +public class PmsUtil { | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + private static String uploadPath; | ||
| 19 | + | ||
| 20 | + @Value("${jeecg.path.upload}") | ||
| 21 | + public void setUploadPath(String uploadPath) { | ||
| 22 | + PmsUtil.uploadPath = uploadPath; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public static String saveErrorTxtByList(List<String> msg, String name) { | ||
| 26 | + Date d = new Date(); | ||
| 27 | + String saveDir = "logs" + File.separator + DateUtils.yyyyMMdd.get().format(d) + File.separator; | ||
| 28 | + String saveFullDir = uploadPath + File.separator + saveDir; | ||
| 29 | + | ||
| 30 | + File saveFile = new File(saveFullDir); | ||
| 31 | + if (!saveFile.exists()) { | ||
| 32 | + saveFile.mkdirs(); | ||
| 33 | + } | ||
| 34 | + name += DateUtils.yyyymmddhhmmss.get().format(d) + Math.round(Math.random() * 10000); | ||
| 35 | + String saveFilePath = saveFullDir + name + ".txt"; | ||
| 36 | + | ||
| 37 | + try { | ||
| 38 | + //封装目的地 | ||
| 39 | + BufferedWriter bw = new BufferedWriter(new FileWriter(saveFilePath)); | ||
| 40 | + //遍历集合 | ||
| 41 | + for (String s : msg) { | ||
| 42 | + //写数据 | ||
| 43 | + if (s.indexOf("_") > 0) { | ||
| 44 | + String arr[] = s.split("_"); | ||
| 45 | + bw.write("第" + arr[0] + "行:" + arr[1]); | ||
| 46 | + } else { | ||
| 47 | + bw.write(s); | ||
| 48 | + } | ||
| 49 | + //bw.newLine(); | ||
| 50 | + bw.write("\r\n"); | ||
| 51 | + } | ||
| 52 | + //释放资源 | ||
| 53 | + bw.flush(); | ||
| 54 | + bw.close(); | ||
| 55 | + } catch (Exception e) { | ||
| 56 | + log.info("excel导入生成错误日志文件异常:" + e.getMessage()); | ||
| 57 | + } | ||
| 58 | + return saveDir + name + ".txt"; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/ReflectHelper.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | + | ||
| 5 | +import java.lang.reflect.Field; | ||
| 6 | +import java.lang.reflect.Method; | ||
| 7 | +import java.util.*; | ||
| 8 | +import java.util.Map.Entry; | ||
| 9 | +import java.util.regex.Pattern; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @author 张代浩 | ||
| 13 | + * @desc 通过反射来动态调用get 和 set 方法 | ||
| 14 | + */ | ||
| 15 | +@Slf4j | ||
| 16 | +public class ReflectHelper { | ||
| 17 | + | ||
| 18 | + private Class cls; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 传过来的对象 | ||
| 22 | + */ | ||
| 23 | + private Object obj; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 存放get方法 | ||
| 27 | + */ | ||
| 28 | + private Hashtable<String, Method> getMethods = null; | ||
| 29 | + /** | ||
| 30 | + * 存放set方法 | ||
| 31 | + */ | ||
| 32 | + private Hashtable<String, Method> setMethods = null; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 定义构造方法 -- 一般来说是个pojo | ||
| 36 | + * | ||
| 37 | + * @param o 目标对象 | ||
| 38 | + */ | ||
| 39 | + public ReflectHelper(Object o) { | ||
| 40 | + obj = o; | ||
| 41 | + initMethods(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * @desc 初始化 | ||
| 46 | + */ | ||
| 47 | + public void initMethods() { | ||
| 48 | + getMethods = new Hashtable<String, Method>(); | ||
| 49 | + setMethods = new Hashtable<String, Method>(); | ||
| 50 | + cls = obj.getClass(); | ||
| 51 | + Method[] methods = cls.getMethods(); | ||
| 52 | + // 定义正则表达式,从方法中过滤出getter / setter 函数. | ||
| 53 | + String gs = "get(\\w+)"; | ||
| 54 | + Pattern getM = Pattern.compile(gs); | ||
| 55 | + String ss = "set(\\w+)"; | ||
| 56 | + Pattern setM = Pattern.compile(ss); | ||
| 57 | + // 把方法中的"set" 或者 "get" 去掉 | ||
| 58 | + String rapl = "$1"; | ||
| 59 | + String param; | ||
| 60 | + for (int i = 0; i < methods.length; ++i) { | ||
| 61 | + Method m = methods[i]; | ||
| 62 | + String methodName = m.getName(); | ||
| 63 | + if (Pattern.matches(gs, methodName)) { | ||
| 64 | + param = getM.matcher(methodName).replaceAll(rapl).toLowerCase(); | ||
| 65 | + getMethods.put(param, m); | ||
| 66 | + } else if (Pattern.matches(ss, methodName)) { | ||
| 67 | + param = setM.matcher(methodName).replaceAll(rapl).toLowerCase(); | ||
| 68 | + setMethods.put(param, m); | ||
| 69 | + } else { | ||
| 70 | + // logger.info(methodName + " 不是getter,setter方法!"); | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * @desc 调用set方法 | ||
| 77 | + */ | ||
| 78 | + public boolean setMethodValue(String property, Object object) { | ||
| 79 | + Method m = setMethods.get(property.toLowerCase()); | ||
| 80 | + if (m != null) { | ||
| 81 | + try { | ||
| 82 | + // 调用目标类的setter函数 | ||
| 83 | + m.invoke(obj, object); | ||
| 84 | + return true; | ||
| 85 | + } catch (Exception ex) { | ||
| 86 | + log.info("invoke getter on " + property + " error: " + ex.toString()); | ||
| 87 | + return false; | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + return false; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * @desc 调用set方法 | ||
| 95 | + */ | ||
| 96 | + public Object getMethodValue(String property) { | ||
| 97 | + Object value = null; | ||
| 98 | + Method m = getMethods.get(property.toLowerCase()); | ||
| 99 | + if (m != null) { | ||
| 100 | + try { | ||
| 101 | + /* | ||
| 102 | + * 调用obj类的setter函数 | ||
| 103 | + */ | ||
| 104 | + value = m.invoke(obj, new Object[]{}); | ||
| 105 | + | ||
| 106 | + } catch (Exception ex) { | ||
| 107 | + log.info("invoke getter on " + property + " error: " + ex.toString()); | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + return value; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * 把map中的内容全部注入到obj中 | ||
| 115 | + * | ||
| 116 | + * @param data | ||
| 117 | + * @return | ||
| 118 | + */ | ||
| 119 | + public Object setAll(Map<String, Object> data) { | ||
| 120 | + if (data == null || data.keySet().size() <= 0) { | ||
| 121 | + return null; | ||
| 122 | + } | ||
| 123 | + for (Entry<String, Object> entry : data.entrySet()) { | ||
| 124 | + this.setMethodValue(entry.getKey(), entry.getValue()); | ||
| 125 | + } | ||
| 126 | + return obj; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 130 | + * 把map中的内容全部注入到obj中 | ||
| 131 | + * | ||
| 132 | + * @param o | ||
| 133 | + * @param data | ||
| 134 | + * @return | ||
| 135 | + */ | ||
| 136 | + public static Object setAll(Object o, Map<String, Object> data) { | ||
| 137 | + ReflectHelper reflectHelper = new ReflectHelper(o); | ||
| 138 | + reflectHelper.setAll(data); | ||
| 139 | + return o; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * 把map中的内容全部注入到新实例中 | ||
| 144 | + * | ||
| 145 | + * @param clazz | ||
| 146 | + * @param data | ||
| 147 | + * @return | ||
| 148 | + */ | ||
| 149 | + @SuppressWarnings("unchecked") | ||
| 150 | + public static <T> T setAll(Class<T> clazz, Map<String, Object> data) { | ||
| 151 | + T o = null; | ||
| 152 | + try { | ||
| 153 | + o = clazz.newInstance(); | ||
| 154 | + } catch (Exception e) { | ||
| 155 | + e.printStackTrace(); | ||
| 156 | + o = null; | ||
| 157 | + return o; | ||
| 158 | + } | ||
| 159 | + return (T) setAll(o, data); | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + /** | ||
| 163 | + * 根据传入的class将mapList转换为实体类list | ||
| 164 | + * | ||
| 165 | + * @param mapist | ||
| 166 | + * @param clazz | ||
| 167 | + * @return | ||
| 168 | + */ | ||
| 169 | + public static <T> List<T> transList2Entrys(List<Map<String, Object>> mapist, Class<T> clazz) { | ||
| 170 | + List<T> list = new ArrayList<T>(); | ||
| 171 | + if (mapist != null && mapist.size() > 0) { | ||
| 172 | + for (Map<String, Object> data : mapist) { | ||
| 173 | + list.add(ReflectHelper.setAll(clazz, data)); | ||
| 174 | + } | ||
| 175 | + } | ||
| 176 | + return list; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + /** | ||
| 180 | + * 根据属性名获取属性值 | ||
| 181 | + */ | ||
| 182 | + public static Object getFieldValueByName(String fieldName, Object o) { | ||
| 183 | + try { | ||
| 184 | + String firstLetter = fieldName.substring(0, 1).toUpperCase(); | ||
| 185 | + String getter = "get" + firstLetter + fieldName.substring(1); | ||
| 186 | + Method method = o.getClass().getMethod(getter, new Class[]{}); | ||
| 187 | + Object value = method.invoke(o, new Object[]{}); | ||
| 188 | + return value; | ||
| 189 | + } catch (Exception e) { | ||
| 190 | + e.printStackTrace(); | ||
| 191 | + return null; | ||
| 192 | + } | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + /** | ||
| 196 | + * 获取属性名数组 | ||
| 197 | + */ | ||
| 198 | + public static String[] getFiledName(Object o) { | ||
| 199 | + Field[] fields = o.getClass().getDeclaredFields(); | ||
| 200 | + String[] fieldNames = new String[fields.length]; | ||
| 201 | + for (int i = 0; i < fields.length; i++) { | ||
| 202 | + //log.info(fields[i].getType()); | ||
| 203 | + fieldNames[i] = fields[i].getName(); | ||
| 204 | + } | ||
| 205 | + return fieldNames; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + /** | ||
| 209 | + * 获取属性类型(type),属性名(name),属性值(value)的map组成的list | ||
| 210 | + */ | ||
| 211 | + public static List<Map> getFiledsInfo(Object o) { | ||
| 212 | + Field[] fields = o.getClass().getDeclaredFields(); | ||
| 213 | + String[] fieldNames = new String[fields.length]; | ||
| 214 | + List<Map> list = new ArrayList<Map>(); | ||
| 215 | + Map<String, Object> infoMap = null; | ||
| 216 | + for (int i = 0; i < fields.length; i++) { | ||
| 217 | + infoMap = new HashMap<String, Object>(); | ||
| 218 | + infoMap.put("type", fields[i].getType().toString()); | ||
| 219 | + infoMap.put("name", fields[i].getName()); | ||
| 220 | + infoMap.put("value", getFieldValueByName(fields[i].getName(), o)); | ||
| 221 | + list.add(infoMap); | ||
| 222 | + } | ||
| 223 | + return list; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + /** | ||
| 227 | + * 获取对象的所有属性值,返回一个对象数组 | ||
| 228 | + */ | ||
| 229 | + public static Object[] getFiledValues(Object o) { | ||
| 230 | + String[] fieldNames = getFiledName(o); | ||
| 231 | + Object[] value = new Object[fieldNames.length]; | ||
| 232 | + for (int i = 0; i < fieldNames.length; i++) { | ||
| 233 | + value[i] = getFieldValueByName(fieldNames[i], o); | ||
| 234 | + } | ||
| 235 | + return value; | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | +} | ||
| 0 | \ No newline at end of file | 239 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestDesformUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson.JSONObject; | ||
| 4 | +import org.jeecg.common.api.vo.Result; | ||
| 5 | +import org.springframework.http.HttpHeaders; | ||
| 6 | +import org.springframework.http.HttpMethod; | ||
| 7 | +import org.springframework.http.MediaType; | ||
| 8 | +import org.springframework.http.ResponseEntity; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 通过 RESTful 风格的接口操纵 desform 里的数据 | ||
| 12 | + * | ||
| 13 | + * @author sunjianlei | ||
| 14 | + */ | ||
| 15 | +public class RestDesformUtil { | ||
| 16 | + | ||
| 17 | + private static String domain = null; | ||
| 18 | + private static String path = null; | ||
| 19 | + | ||
| 20 | + static { | ||
| 21 | + domain = SpringContextUtils.getDomain(); | ||
| 22 | + path = oConvertUtils.getString(SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path")); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 查询数据 | ||
| 27 | + * | ||
| 28 | + * @param desformCode | ||
| 29 | + * @param dataId | ||
| 30 | + * @param token | ||
| 31 | + * @return | ||
| 32 | + */ | ||
| 33 | + public static Result queryOne(String desformCode, String dataId, String token) { | ||
| 34 | + String url = getBaseUrl(desformCode, dataId).toString(); | ||
| 35 | + HttpHeaders headers = getHeaders(token); | ||
| 36 | + ResponseEntity<JSONObject> result = RestUtil.request(url, HttpMethod.GET, headers, null, null, JSONObject.class); | ||
| 37 | + return packageReturn(result); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 新增数据 | ||
| 42 | + * | ||
| 43 | + * @param desformCode | ||
| 44 | + * @param formData | ||
| 45 | + * @param token | ||
| 46 | + * @return | ||
| 47 | + */ | ||
| 48 | + public static Result addOne(String desformCode, JSONObject formData, String token) { | ||
| 49 | + return addOrEditOne(desformCode, formData, token, HttpMethod.POST); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 修改数据 | ||
| 54 | + * | ||
| 55 | + * @param desformCode | ||
| 56 | + * @param formData | ||
| 57 | + * @param token | ||
| 58 | + * @return | ||
| 59 | + */ | ||
| 60 | + public static Result editOne(String desformCode, JSONObject formData, String token) { | ||
| 61 | + return addOrEditOne(desformCode, formData, token, HttpMethod.PUT); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + private static Result addOrEditOne(String desformCode, JSONObject formData, String token, HttpMethod method) { | ||
| 65 | + String url = getBaseUrl(desformCode).toString(); | ||
| 66 | + HttpHeaders headers = getHeaders(token); | ||
| 67 | + ResponseEntity<JSONObject> result = RestUtil.request(url, method, headers, null, formData, JSONObject.class); | ||
| 68 | + return packageReturn(result); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + /** | ||
| 72 | + * 删除数据 | ||
| 73 | + * | ||
| 74 | + * @param desformCode | ||
| 75 | + * @param dataId | ||
| 76 | + * @param token | ||
| 77 | + * @return | ||
| 78 | + */ | ||
| 79 | + public static Result removeOne(String desformCode, String dataId, String token) { | ||
| 80 | + String url = getBaseUrl(desformCode, dataId).toString(); | ||
| 81 | + HttpHeaders headers = getHeaders(token); | ||
| 82 | + ResponseEntity<JSONObject> result = RestUtil.request(url, HttpMethod.DELETE, headers, null, null, JSONObject.class); | ||
| 83 | + return packageReturn(result); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + private static Result packageReturn(ResponseEntity<JSONObject> result) { | ||
| 87 | + if (result.getBody() != null) { | ||
| 88 | + return result.getBody().toJavaObject(Result.class); | ||
| 89 | + } | ||
| 90 | + return Result.error("操作失败"); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + private static StringBuilder getBaseUrl() { | ||
| 94 | + StringBuilder builder = new StringBuilder(domain).append(path); | ||
| 95 | + builder.append("/desform/api"); | ||
| 96 | + return builder; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + private static StringBuilder getBaseUrl(String desformCode, String dataId) { | ||
| 100 | + StringBuilder builder = getBaseUrl(); | ||
| 101 | + builder.append("/").append(desformCode); | ||
| 102 | + if (dataId != null) { | ||
| 103 | + builder.append("/").append(dataId); | ||
| 104 | + } | ||
| 105 | + return builder; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + private static StringBuilder getBaseUrl(String desformCode) { | ||
| 109 | + return getBaseUrl(desformCode, null); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + private static HttpHeaders getHeaders(String token) { | ||
| 113 | + HttpHeaders headers = new HttpHeaders(); | ||
| 114 | + String mediaType = MediaType.APPLICATION_JSON_UTF8_VALUE; | ||
| 115 | + headers.setContentType(MediaType.parseMediaType(mediaType)); | ||
| 116 | + headers.set("Accept", mediaType); | ||
| 117 | + headers.set("X-Access-Token", token); | ||
| 118 | + return headers; | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | +} | ||
| 0 | \ No newline at end of file | 122 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/RestUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson.JSONObject; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.apache.commons.lang3.StringUtils; | ||
| 6 | +import org.springframework.http.*; | ||
| 7 | +import org.springframework.http.client.SimpleClientHttpRequestFactory; | ||
| 8 | +import org.springframework.http.converter.StringHttpMessageConverter; | ||
| 9 | +import org.springframework.web.client.RestTemplate; | ||
| 10 | + | ||
| 11 | +import java.nio.charset.StandardCharsets; | ||
| 12 | +import java.util.Iterator; | ||
| 13 | +import java.util.Map; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 调用 Restful 接口 Util | ||
| 17 | + * | ||
| 18 | + * @author sunjianlei | ||
| 19 | + */ | ||
| 20 | +@Slf4j | ||
| 21 | +public class RestUtil { | ||
| 22 | + | ||
| 23 | + private static String domain = null; | ||
| 24 | + | ||
| 25 | + public static String getDomain() { | ||
| 26 | + if (domain == null) { | ||
| 27 | + domain = SpringContextUtils.getDomain(); | ||
| 28 | + } | ||
| 29 | + return domain; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public static String path = null; | ||
| 33 | + | ||
| 34 | + public static String getPath() { | ||
| 35 | + if (path == null) { | ||
| 36 | + path = SpringContextUtils.getApplicationContext().getEnvironment().getProperty("server.servlet.context-path"); | ||
| 37 | + } | ||
| 38 | + return oConvertUtils.getString(path); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public static String getBaseUrl() { | ||
| 42 | + String basepath = getDomain() + getPath(); | ||
| 43 | + log.info(" RestUtil.getBaseUrl: " + basepath); | ||
| 44 | + return basepath; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * RestAPI 调用器 | ||
| 49 | + */ | ||
| 50 | + private final static RestTemplate RT; | ||
| 51 | + | ||
| 52 | + static { | ||
| 53 | + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); | ||
| 54 | + requestFactory.setConnectTimeout(3000); | ||
| 55 | + requestFactory.setReadTimeout(3000); | ||
| 56 | + RT = new RestTemplate(requestFactory); | ||
| 57 | + // 解决乱码问题 | ||
| 58 | + RT.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public static RestTemplate getRestTemplate() { | ||
| 62 | + return RT; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * 发送 get 请求 | ||
| 67 | + */ | ||
| 68 | + public static JSONObject get(String url) { | ||
| 69 | + return getNative(url, null, null).getBody(); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * 发送 get 请求 | ||
| 74 | + */ | ||
| 75 | + public static JSONObject get(String url, JSONObject variables) { | ||
| 76 | + return getNative(url, variables, null).getBody(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * 发送 get 请求 | ||
| 81 | + */ | ||
| 82 | + public static JSONObject get(String url, JSONObject variables, JSONObject params) { | ||
| 83 | + return getNative(url, variables, params).getBody(); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + /** | ||
| 87 | + * 发送 get 请求,返回原生 ResponseEntity 对象 | ||
| 88 | + */ | ||
| 89 | + public static ResponseEntity<JSONObject> getNative(String url, JSONObject variables, JSONObject params) { | ||
| 90 | + return request(url, HttpMethod.GET, variables, params); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 发送 Post 请求 | ||
| 95 | + */ | ||
| 96 | + public static JSONObject post(String url) { | ||
| 97 | + return postNative(url, null, null).getBody(); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + /** | ||
| 101 | + * 发送 Post 请求 | ||
| 102 | + */ | ||
| 103 | + public static JSONObject post(String url, JSONObject params) { | ||
| 104 | + return postNative(url, null, params).getBody(); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + /** | ||
| 108 | + * 发送 Post 请求 | ||
| 109 | + */ | ||
| 110 | + public static JSONObject post(String url, JSONObject variables, JSONObject params) { | ||
| 111 | + return postNative(url, variables, params).getBody(); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * 发送 POST 请求,返回原生 ResponseEntity 对象 | ||
| 116 | + */ | ||
| 117 | + public static ResponseEntity<JSONObject> postNative(String url, JSONObject variables, JSONObject params) { | ||
| 118 | + return request(url, HttpMethod.POST, variables, params); | ||
| 119 | + } | ||
| 120 | + | ||
| 121 | + /** | ||
| 122 | + * 发送 put 请求 | ||
| 123 | + */ | ||
| 124 | + public static JSONObject put(String url) { | ||
| 125 | + return putNative(url, null, null).getBody(); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + /** | ||
| 129 | + * 发送 put 请求 | ||
| 130 | + */ | ||
| 131 | + public static JSONObject put(String url, JSONObject params) { | ||
| 132 | + return putNative(url, null, params).getBody(); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + /** | ||
| 136 | + * 发送 put 请求 | ||
| 137 | + */ | ||
| 138 | + public static JSONObject put(String url, JSONObject variables, JSONObject params) { | ||
| 139 | + return putNative(url, variables, params).getBody(); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + /** | ||
| 143 | + * 发送 put 请求,返回原生 ResponseEntity 对象 | ||
| 144 | + */ | ||
| 145 | + public static ResponseEntity<JSONObject> putNative(String url, JSONObject variables, JSONObject params) { | ||
| 146 | + return request(url, HttpMethod.PUT, variables, params); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * 发送 delete 请求 | ||
| 151 | + */ | ||
| 152 | + public static JSONObject delete(String url) { | ||
| 153 | + return deleteNative(url, null, null).getBody(); | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * 发送 delete 请求 | ||
| 158 | + */ | ||
| 159 | + public static JSONObject delete(String url, JSONObject variables, JSONObject params) { | ||
| 160 | + return deleteNative(url, variables, params).getBody(); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * 发送 delete 请求,返回原生 ResponseEntity 对象 | ||
| 165 | + */ | ||
| 166 | + public static ResponseEntity<JSONObject> deleteNative(String url, JSONObject variables, JSONObject params) { | ||
| 167 | + return request(url, HttpMethod.DELETE, null, variables, params, JSONObject.class); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + /** | ||
| 171 | + * 发送请求 | ||
| 172 | + */ | ||
| 173 | + public static ResponseEntity<JSONObject> request(String url, HttpMethod method, JSONObject variables, JSONObject params) { | ||
| 174 | + return request(url, method, getHeaderApplicationJson(), variables, params, JSONObject.class); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + /** | ||
| 178 | + * 发送请求 | ||
| 179 | + * | ||
| 180 | + * @param url 请求地址 | ||
| 181 | + * @param method 请求方式 | ||
| 182 | + * @param headers 请求头 可空 | ||
| 183 | + * @param variables 请求url参数 可空 | ||
| 184 | + * @param params 请求body参数 可空 | ||
| 185 | + * @param responseType 返回类型 | ||
| 186 | + * @return ResponseEntity<responseType> | ||
| 187 | + */ | ||
| 188 | + public static <T> ResponseEntity<T> request(String url, HttpMethod method, HttpHeaders headers, JSONObject variables, Object params, Class<T> responseType) { | ||
| 189 | + log.info(" RestUtil --- request --- url = "+ url); | ||
| 190 | + if (StringUtils.isEmpty(url)) { | ||
| 191 | + throw new RuntimeException("url 不能为空"); | ||
| 192 | + } | ||
| 193 | + if (method == null) { | ||
| 194 | + throw new RuntimeException("method 不能为空"); | ||
| 195 | + } | ||
| 196 | + if (headers == null) { | ||
| 197 | + headers = new HttpHeaders(); | ||
| 198 | + } | ||
| 199 | + // 请求体 | ||
| 200 | + String body = ""; | ||
| 201 | + if (params != null) { | ||
| 202 | + if (params instanceof JSONObject) { | ||
| 203 | + body = ((JSONObject) params).toJSONString(); | ||
| 204 | + | ||
| 205 | + } else { | ||
| 206 | + body = params.toString(); | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + // 拼接 url 参数 | ||
| 210 | + if (variables != null) { | ||
| 211 | + url += ("?" + asUrlVariables(variables)); | ||
| 212 | + } | ||
| 213 | + // 发送请求 | ||
| 214 | + HttpEntity<String> request = new HttpEntity<>(body, headers); | ||
| 215 | + return RT.exchange(url, method, request, responseType); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + /** | ||
| 219 | + * 获取JSON请求头 | ||
| 220 | + */ | ||
| 221 | + public static HttpHeaders getHeaderApplicationJson() { | ||
| 222 | + return getHeader(MediaType.APPLICATION_JSON_UTF8_VALUE); | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + /** | ||
| 226 | + * 获取请求头 | ||
| 227 | + */ | ||
| 228 | + public static HttpHeaders getHeader(String mediaType) { | ||
| 229 | + HttpHeaders headers = new HttpHeaders(); | ||
| 230 | + headers.setContentType(MediaType.parseMediaType(mediaType)); | ||
| 231 | + headers.add("Accept", mediaType); | ||
| 232 | + return headers; | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + /** | ||
| 236 | + * 将 JSONObject 转为 a=1&b=2&c=3...&n=n 的形式 | ||
| 237 | + */ | ||
| 238 | + public static String asUrlVariables(JSONObject variables) { | ||
| 239 | + Map<String, Object> source = variables.getInnerMap(); | ||
| 240 | + Iterator<String> it = source.keySet().iterator(); | ||
| 241 | + StringBuilder urlVariables = new StringBuilder(); | ||
| 242 | + while (it.hasNext()) { | ||
| 243 | + String key = it.next(); | ||
| 244 | + String value = ""; | ||
| 245 | + Object object = source.get(key); | ||
| 246 | + if (object != null) { | ||
| 247 | + if (!StringUtils.isEmpty(object.toString())) { | ||
| 248 | + value = object.toString(); | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + urlVariables.append("&").append(key).append("=").append(value); | ||
| 252 | + } | ||
| 253 | + // 去掉第一个& | ||
| 254 | + return urlVariables.substring(1); | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SpringContextUtils.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import javax.servlet.http.HttpServletRequest; | ||
| 4 | + | ||
| 5 | +import org.jeecg.common.constant.ServiceNameConstants; | ||
| 6 | +import org.springframework.beans.BeansException; | ||
| 7 | +import org.springframework.context.ApplicationContext; | ||
| 8 | +import org.springframework.context.ApplicationContextAware; | ||
| 9 | +import org.springframework.stereotype.Component; | ||
| 10 | +import org.springframework.web.context.request.RequestContextHolder; | ||
| 11 | +import org.springframework.web.context.request.ServletRequestAttributes; | ||
| 12 | + | ||
| 13 | +@Component | ||
| 14 | +public class SpringContextUtils implements ApplicationContextAware { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 上下文对象实例 | ||
| 18 | + */ | ||
| 19 | + private static ApplicationContext applicationContext; | ||
| 20 | + | ||
| 21 | + @Override | ||
| 22 | + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | ||
| 23 | + SpringContextUtils.applicationContext = applicationContext; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 获取applicationContext | ||
| 28 | + * | ||
| 29 | + * @return | ||
| 30 | + */ | ||
| 31 | + public static ApplicationContext getApplicationContext() { | ||
| 32 | + return applicationContext; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 获取HttpServletRequest | ||
| 37 | + */ | ||
| 38 | + public static HttpServletRequest getHttpServletRequest() { | ||
| 39 | + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 获取项目根路径 basePath | ||
| 44 | + */ | ||
| 45 | + public static String getDomain(){ | ||
| 46 | + HttpServletRequest request = getHttpServletRequest(); | ||
| 47 | + StringBuffer url = request.getRequestURL(); | ||
| 48 | + //微服务情况下,获取gateway的basePath | ||
| 49 | + String basePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH); | ||
| 50 | + if(oConvertUtils.isNotEmpty(basePath)){ | ||
| 51 | + return basePath; | ||
| 52 | + }else{ | ||
| 53 | + return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString(); | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static String getOrigin(){ | ||
| 58 | + HttpServletRequest request = getHttpServletRequest(); | ||
| 59 | + return request.getHeader("Origin"); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * 通过name获取 Bean. | ||
| 64 | + * | ||
| 65 | + * @param name | ||
| 66 | + * @return | ||
| 67 | + */ | ||
| 68 | + public static Object getBean(String name) { | ||
| 69 | + return getApplicationContext().getBean(name); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + /** | ||
| 73 | + * 通过class获取Bean. | ||
| 74 | + * | ||
| 75 | + * @param clazz | ||
| 76 | + * @param <T> | ||
| 77 | + * @return | ||
| 78 | + */ | ||
| 79 | + public static <T> T getBean(Class<T> clazz) { | ||
| 80 | + return getApplicationContext().getBean(clazz); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * 通过name,以及Clazz返回指定的Bean | ||
| 85 | + * | ||
| 86 | + * @param name | ||
| 87 | + * @param clazz | ||
| 88 | + * @param <T> | ||
| 89 | + * @return | ||
| 90 | + */ | ||
| 91 | + public static <T> T getBean(String name, Class<T> clazz) { | ||
| 92 | + return getApplicationContext().getBean(name, clazz); | ||
| 93 | + } | ||
| 94 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import cn.hutool.crypto.SecureUtil; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.jeecg.common.exception.JeecgBootException; | ||
| 6 | +import javax.servlet.http.HttpServletRequest; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * sql注入处理工具类 | ||
| 10 | + * | ||
| 11 | + * @author zhoujf | ||
| 12 | + */ | ||
| 13 | +@Slf4j | ||
| 14 | +public class SqlInjectionUtil { | ||
| 15 | + /** | ||
| 16 | + * sign 用于表字典加签的盐值【SQL漏洞】 | ||
| 17 | + * (上线修改值 20200501,同步修改前端的盐值) | ||
| 18 | + */ | ||
| 19 | + private final static String TABLE_DICT_SIGN_SALT = "20200501"; | ||
| 20 | + private final static String xssStr = "'|and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+"; | ||
| 21 | + | ||
| 22 | + /* | ||
| 23 | + * 针对表字典进行额外的sign签名校验(增加安全机制) | ||
| 24 | + * @param dictCode: | ||
| 25 | + * @param sign: | ||
| 26 | + * @param request: | ||
| 27 | + * @Return: void | ||
| 28 | + */ | ||
| 29 | + public static void checkDictTableSign(String dictCode, String sign, HttpServletRequest request) { | ||
| 30 | + //表字典SQL注入漏洞,签名校验 | ||
| 31 | + String accessToken = request.getHeader("X-Access-Token"); | ||
| 32 | + String signStr = dictCode + SqlInjectionUtil.TABLE_DICT_SIGN_SALT + accessToken; | ||
| 33 | + String javaSign = SecureUtil.md5(signStr); | ||
| 34 | + if (!javaSign.equals(sign)) { | ||
| 35 | + log.error("表字典,SQL注入漏洞签名校验失败 :" + sign + "!=" + javaSign+ ",dictCode=" + dictCode); | ||
| 36 | + throw new JeecgBootException("无权限访问!"); | ||
| 37 | + } | ||
| 38 | + log.info(" 表字典,SQL注入漏洞签名校验成功!sign=" + sign + ",dictCode=" + dictCode); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * sql注入过滤处理,遇到注入关键字抛异常 | ||
| 44 | + * | ||
| 45 | + * @param value | ||
| 46 | + * @return | ||
| 47 | + */ | ||
| 48 | + public static void filterContent(String value) { | ||
| 49 | + if (value == null || "".equals(value)) { | ||
| 50 | + return; | ||
| 51 | + } | ||
| 52 | + // 统一转为小写 | ||
| 53 | + value = value.toLowerCase(); | ||
| 54 | + String[] xssArr = xssStr.split("\\|"); | ||
| 55 | + for (int i = 0; i < xssArr.length; i++) { | ||
| 56 | + if (value.indexOf(xssArr[i]) > -1) { | ||
| 57 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]); | ||
| 58 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | ||
| 59 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | + return; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * sql注入过滤处理,遇到注入关键字抛异常 | ||
| 67 | + * | ||
| 68 | + * @param values | ||
| 69 | + * @return | ||
| 70 | + */ | ||
| 71 | + public static void filterContent(String[] values) { | ||
| 72 | + String[] xssArr = xssStr.split("\\|"); | ||
| 73 | + for (String value : values) { | ||
| 74 | + if (value == null || "".equals(value)) { | ||
| 75 | + return; | ||
| 76 | + } | ||
| 77 | + // 统一转为小写 | ||
| 78 | + value = value.toLowerCase(); | ||
| 79 | + for (int i = 0; i < xssArr.length; i++) { | ||
| 80 | + if (value.indexOf(xssArr[i]) > -1) { | ||
| 81 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]); | ||
| 82 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | ||
| 83 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + return; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * @特殊方法(不通用) 仅用于字典条件SQL参数,注入过滤 | ||
| 92 | + * @param value | ||
| 93 | + * @return | ||
| 94 | + */ | ||
| 95 | + @Deprecated | ||
| 96 | + public static void specialFilterContent(String value) { | ||
| 97 | + String specialXssStr = " exec | insert | select | delete | update | drop | count | chr | mid | master | truncate | char | declare |;|+|"; | ||
| 98 | + String[] xssArr = specialXssStr.split("\\|"); | ||
| 99 | + if (value == null || "".equals(value)) { | ||
| 100 | + return; | ||
| 101 | + } | ||
| 102 | + // 统一转为小写 | ||
| 103 | + value = value.toLowerCase(); | ||
| 104 | + for (int i = 0; i < xssArr.length; i++) { | ||
| 105 | + if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) { | ||
| 106 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]); | ||
| 107 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | ||
| 108 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + return; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + | ||
| 115 | + /** | ||
| 116 | + * @特殊方法(不通用) 仅用于Online报表SQL解析,注入过滤 | ||
| 117 | + * @param value | ||
| 118 | + * @return | ||
| 119 | + */ | ||
| 120 | + @Deprecated | ||
| 121 | + public static void specialFilterContentForOnlineReport(String value) { | ||
| 122 | + String specialXssStr = " exec | insert | delete | update | drop | chr | mid | master | truncate | char | declare |"; | ||
| 123 | + String[] xssArr = specialXssStr.split("\\|"); | ||
| 124 | + if (value == null || "".equals(value)) { | ||
| 125 | + return; | ||
| 126 | + } | ||
| 127 | + // 统一转为小写 | ||
| 128 | + value = value.toLowerCase(); | ||
| 129 | + for (int i = 0; i < xssArr.length; i++) { | ||
| 130 | + if (value.indexOf(xssArr[i]) > -1 || value.startsWith(xssArr[i].trim())) { | ||
| 131 | + log.error("请注意,存在SQL注入关键词---> {}", xssArr[i]); | ||
| 132 | + log.error("请注意,值可能存在SQL注入风险!---> {}", value); | ||
| 133 | + throw new RuntimeException("请注意,值可能存在SQL注入风险!--->" + value); | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | + return; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SysAnnmentTypeEnum.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 系统公告自定义跳转方式 | ||
| 5 | + */ | ||
| 6 | +public enum SysAnnmentTypeEnum { | ||
| 7 | + /** | ||
| 8 | + * 邮件跳转组件 | ||
| 9 | + */ | ||
| 10 | + EMAIL("email", "component", "modules/eoa/email/modals/EoaEmailInForm"), | ||
| 11 | + /** | ||
| 12 | + * 工作流跳转链接我的办公 | ||
| 13 | + */ | ||
| 14 | + BPM("bpm", "url", "/bpm/task/MyTaskList"); | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 业务类型(email:邮件 bpm:流程) | ||
| 18 | + */ | ||
| 19 | + private String type; | ||
| 20 | + /** | ||
| 21 | + * 打开方式 组件:component 路由:url | ||
| 22 | + */ | ||
| 23 | + private String openType; | ||
| 24 | + /** | ||
| 25 | + * 组件/路由 地址 | ||
| 26 | + */ | ||
| 27 | + private String openPage; | ||
| 28 | + | ||
| 29 | + SysAnnmentTypeEnum(String type, String openType, String openPage) { | ||
| 30 | + this.type = type; | ||
| 31 | + this.openType = openType; | ||
| 32 | + this.openPage = openPage; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public String getType() { | ||
| 36 | + return type; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public void setType(String type) { | ||
| 40 | + this.type = type; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public String getOpenType() { | ||
| 44 | + return openType; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public void setOpenType(String openType) { | ||
| 48 | + this.openType = openType; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public String getOpenPage() { | ||
| 52 | + return openPage; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public void setOpenPage(String openPage) { | ||
| 56 | + this.openPage = openPage; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + public static SysAnnmentTypeEnum getByType(String type) { | ||
| 60 | + if (oConvertUtils.isEmpty(type)) { | ||
| 61 | + return null; | ||
| 62 | + } | ||
| 63 | + for (SysAnnmentTypeEnum val : values()) { | ||
| 64 | + if (val.getType().equals(type)) { | ||
| 65 | + return val; | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + return null; | ||
| 69 | + } | ||
| 70 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/TokenUtils.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.commons.lang3.StringUtils; | ||
| 5 | +import org.apache.shiro.authc.AuthenticationException; | ||
| 6 | +import org.jeecg.common.api.CommonAPI; | ||
| 7 | +import org.jeecg.common.constant.CommonConstant; | ||
| 8 | +import org.jeecg.common.system.util.JwtUtil; | ||
| 9 | +import org.jeecg.common.system.vo.LoginUser; | ||
| 10 | + | ||
| 11 | +import javax.servlet.http.HttpServletRequest; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * @Author scott | ||
| 15 | + * @Date 2019/9/23 14:12 | ||
| 16 | + * @Description: 编程校验token有效性 | ||
| 17 | + */ | ||
| 18 | +@Slf4j | ||
| 19 | +public class TokenUtils { | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 获取 request 里传递的 token | ||
| 23 | + * | ||
| 24 | + * @param request | ||
| 25 | + * @return | ||
| 26 | + */ | ||
| 27 | + public static String getTokenByRequest(HttpServletRequest request) { | ||
| 28 | + String token = request.getParameter("token"); | ||
| 29 | + if (token == null) { | ||
| 30 | + token = request.getHeader("X-Access-Token"); | ||
| 31 | + } | ||
| 32 | + return token; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 验证Token | ||
| 37 | + */ | ||
| 38 | + public static boolean verifyToken(HttpServletRequest request, CommonAPI commonAPI, RedisUtil redisUtil) { | ||
| 39 | + log.debug(" -- url --" + request.getRequestURL()); | ||
| 40 | + String token = getTokenByRequest(request); | ||
| 41 | + | ||
| 42 | + if (StringUtils.isBlank(token)) { | ||
| 43 | + throw new AuthenticationException("Token不能为空!"); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // 解密获得username,用于和数据库进行对比 | ||
| 47 | + String username = JwtUtil.getUsername(token); | ||
| 48 | + if (username == null) { | ||
| 49 | + throw new AuthenticationException("Token非法无效!"); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // 查询用户信息 | ||
| 53 | + LoginUser user = commonAPI.getUserByName(username); | ||
| 54 | + if (user == null) { | ||
| 55 | + throw new AuthenticationException("用户不存在!"); | ||
| 56 | + } | ||
| 57 | + // 判断用户状态 | ||
| 58 | + if (user.getStatus() != 1) { | ||
| 59 | + throw new AuthenticationException("账号已锁定,请联系管理员!"); | ||
| 60 | + } | ||
| 61 | + // 校验token是否超时失效 & 或者账号密码是否错误 | ||
| 62 | + if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) { | ||
| 63 | + throw new AuthenticationException("Token失效,请重新登录"); | ||
| 64 | + } | ||
| 65 | + return true; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 刷新token(保证用户在线操作不掉线) | ||
| 70 | + * @param token | ||
| 71 | + * @param userName | ||
| 72 | + * @param passWord | ||
| 73 | + * @param redisUtil | ||
| 74 | + * @return | ||
| 75 | + */ | ||
| 76 | + private static boolean jwtTokenRefresh(String token, String userName, String passWord, RedisUtil redisUtil) { | ||
| 77 | + String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token)); | ||
| 78 | + if (oConvertUtils.isNotEmpty(cacheToken)) { | ||
| 79 | + // 校验token有效性 | ||
| 80 | + if (!JwtUtil.verify(cacheToken, userName, passWord)) { | ||
| 81 | + String newAuthorization = JwtUtil.sign(userName, passWord); | ||
| 82 | + // 设置Toekn缓存有效时间 | ||
| 83 | + redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization); | ||
| 84 | + redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000); | ||
| 85 | + } | ||
| 86 | + //update-begin--Author:scott Date:20191005 for:解决每次请求,都重写redis中 token缓存问题 | ||
| 87 | +// else { | ||
| 88 | +// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken); | ||
| 89 | +// // 设置超时时间 | ||
| 90 | +// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000); | ||
| 91 | +// } | ||
| 92 | + //update-end--Author:scott Date:20191005 for:解决每次请求,都重写redis中 token缓存问题 | ||
| 93 | + return true; | ||
| 94 | + } | ||
| 95 | + return false; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * 验证Token | ||
| 100 | + */ | ||
| 101 | + public static boolean verifyToken(String token, CommonAPI commonAPI, RedisUtil redisUtil) { | ||
| 102 | + if (StringUtils.isBlank(token)) { | ||
| 103 | + throw new AuthenticationException("token不能为空!"); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + // 解密获得username,用于和数据库进行对比 | ||
| 107 | + String username = JwtUtil.getUsername(token); | ||
| 108 | + if (username == null) { | ||
| 109 | + throw new AuthenticationException("token非法无效!"); | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + // 查询用户信息 | ||
| 113 | + LoginUser user = commonAPI.getUserByName(username); | ||
| 114 | + if (user == null) { | ||
| 115 | + throw new AuthenticationException("用户不存在!"); | ||
| 116 | + } | ||
| 117 | + // 判断用户状态 | ||
| 118 | + if (user.getStatus() != 1) { | ||
| 119 | + throw new AuthenticationException("账号已被锁定,请联系管理员!"); | ||
| 120 | + } | ||
| 121 | + // 校验token是否超时失效 & 或者账号密码是否错误 | ||
| 122 | + if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) { | ||
| 123 | + throw new AuthenticationException("Token失效,请重新登录!"); | ||
| 124 | + } | ||
| 125 | + return true; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/UUIDGenerator.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import java.net.InetAddress; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * | ||
| 8 | + * @Author 张代浩 | ||
| 9 | + * | ||
| 10 | + */ | ||
| 11 | +public class UUIDGenerator { | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 产生一个32位的UUID | ||
| 16 | + * | ||
| 17 | + * @return | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + public static String generate() { | ||
| 21 | + return new StringBuilder(32).append(format(getIP())).append( | ||
| 22 | + format(getJVM())).append(format(getHiTime())).append( | ||
| 23 | + format(getLoTime())).append(format(getCount())).toString(); | ||
| 24 | + | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + private static final int IP; | ||
| 28 | + static { | ||
| 29 | + int ipadd; | ||
| 30 | + try { | ||
| 31 | + ipadd = toInt(InetAddress.getLocalHost().getAddress()); | ||
| 32 | + } catch (Exception e) { | ||
| 33 | + ipadd = 0; | ||
| 34 | + } | ||
| 35 | + IP = ipadd; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + private static short counter = (short) 0; | ||
| 39 | + | ||
| 40 | + private static final int JVM = (int) (System.currentTimeMillis() >>> 8); | ||
| 41 | + | ||
| 42 | + private final static String format(int intval) { | ||
| 43 | + String formatted = Integer.toHexString(intval); | ||
| 44 | + StringBuilder buf = new StringBuilder("00000000"); | ||
| 45 | + buf.replace(8 - formatted.length(), 8, formatted); | ||
| 46 | + return buf.toString(); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + private final static String format(short shortval) { | ||
| 50 | + String formatted = Integer.toHexString(shortval); | ||
| 51 | + StringBuilder buf = new StringBuilder("0000"); | ||
| 52 | + buf.replace(4 - formatted.length(), 4, formatted); | ||
| 53 | + return buf.toString(); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + private final static int getJVM() { | ||
| 57 | + return JVM; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + private final static short getCount() { | ||
| 61 | + synchronized (UUIDGenerator.class) { | ||
| 62 | + if (counter < 0) { | ||
| 63 | + counter = 0; | ||
| 64 | + } | ||
| 65 | + return counter++; | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 70 | + * Unique in a local network | ||
| 71 | + */ | ||
| 72 | + private final static int getIP() { | ||
| 73 | + return IP; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * Unique down to millisecond | ||
| 78 | + */ | ||
| 79 | + private final static short getHiTime() { | ||
| 80 | + return (short) (System.currentTimeMillis() >>> 32); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + private final static int getLoTime() { | ||
| 84 | + return (int) System.currentTimeMillis(); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + private final static int toInt(byte[] bytes) { | ||
| 88 | + int result = 0; | ||
| 89 | + for (int i = 0; i < 4; i++) { | ||
| 90 | + result = (result << 8) - Byte.MIN_VALUE + (int) bytes[i]; | ||
| 91 | + } | ||
| 92 | + return result; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/YouBianCodeUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import io.netty.util.internal.StringUtil; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 流水号生成规则(按默认规则递增,数字从1-99开始递增,数字到99,递增字母;位数不够增加位数) | ||
| 7 | + * A001 | ||
| 8 | + * A001A002 | ||
| 9 | + * @Author zhangdaihao | ||
| 10 | + * | ||
| 11 | + */ | ||
| 12 | +public class YouBianCodeUtil { | ||
| 13 | + | ||
| 14 | + // 数字位数(默认生成3位的数字) | ||
| 15 | + | ||
| 16 | + private static final int numLength = 2;//代表数字位数 | ||
| 17 | + | ||
| 18 | + public static final int zhanweiLength = 1+numLength; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 根据前一个code,获取同级下一个code | ||
| 22 | + * 例如:当前最大code为D01A04,下一个code为:D01A05 | ||
| 23 | + * | ||
| 24 | + * @param code | ||
| 25 | + * @return | ||
| 26 | + */ | ||
| 27 | + public static synchronized String getNextYouBianCode(String code) { | ||
| 28 | + String newcode = ""; | ||
| 29 | + if (code == null || code =="") { | ||
| 30 | + String zimu = "A"; | ||
| 31 | + String num = getStrNum(1); | ||
| 32 | + newcode = zimu + num; | ||
| 33 | + } else { | ||
| 34 | + String before_code = code.substring(0, code.length() - 1- numLength); | ||
| 35 | + String after_code = code.substring(code.length() - 1 - numLength,code.length()); | ||
| 36 | + char after_code_zimu = after_code.substring(0, 1).charAt(0); | ||
| 37 | + Integer after_code_num = Integer.parseInt(after_code.substring(1)); | ||
| 38 | +// org.jeecgframework.core.util.LogUtil.info(after_code); | ||
| 39 | +// org.jeecgframework.core.util.LogUtil.info(after_code_zimu); | ||
| 40 | +// org.jeecgframework.core.util.LogUtil.info(after_code_num); | ||
| 41 | + | ||
| 42 | + String nextNum = ""; | ||
| 43 | + char nextZimu = 'A'; | ||
| 44 | + // 先判断数字等于999*,则计数从1重新开始,递增 | ||
| 45 | + if (after_code_num == getMaxNumByLength(numLength)) { | ||
| 46 | + nextNum = getNextStrNum(0); | ||
| 47 | + } else { | ||
| 48 | + nextNum = getNextStrNum(after_code_num); | ||
| 49 | + } | ||
| 50 | + // 先判断数字等于999*,则字母从A重新开始,递增 | ||
| 51 | + if(after_code_num == getMaxNumByLength(numLength)) { | ||
| 52 | + nextZimu = getNextZiMu(after_code_zimu); | ||
| 53 | + }else{ | ||
| 54 | + nextZimu = after_code_zimu; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // 例如Z99,下一个code就是Z99A01 | ||
| 58 | + if ('Z' == after_code_zimu && getMaxNumByLength(numLength) == after_code_num) { | ||
| 59 | + newcode = code + (nextZimu + nextNum); | ||
| 60 | + } else { | ||
| 61 | + newcode = before_code + (nextZimu + nextNum); | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + return newcode; | ||
| 65 | + | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 根据父亲code,获取下级的下一个code | ||
| 70 | + * | ||
| 71 | + * 例如:父亲CODE:A01 | ||
| 72 | + * 当前CODE:A01B03 | ||
| 73 | + * 获取的code:A01B04 | ||
| 74 | + * | ||
| 75 | + * @param parentCode 上级code | ||
| 76 | + * @param localCode 同级code | ||
| 77 | + * @return | ||
| 78 | + */ | ||
| 79 | + public static synchronized String getSubYouBianCode(String parentCode,String localCode) { | ||
| 80 | + if(localCode!=null && localCode!=""){ | ||
| 81 | + | ||
| 82 | +// return parentCode + getNextYouBianCode(localCode); | ||
| 83 | + return getNextYouBianCode(localCode); | ||
| 84 | + | ||
| 85 | + }else{ | ||
| 86 | + parentCode = parentCode + "A"+ getNextStrNum(0); | ||
| 87 | + } | ||
| 88 | + return parentCode; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 将数字前面位数补零 | ||
| 95 | + * | ||
| 96 | + * @param num | ||
| 97 | + * @return | ||
| 98 | + */ | ||
| 99 | + private static String getNextStrNum(int num) { | ||
| 100 | + return getStrNum(getNextNum(num)); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * 将数字前面位数补零 | ||
| 105 | + * | ||
| 106 | + * @param num | ||
| 107 | + * @return | ||
| 108 | + */ | ||
| 109 | + private static String getStrNum(int num) { | ||
| 110 | + String s = String.format("%0" + numLength + "d", num); | ||
| 111 | + return s; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * 递增获取下个数字 | ||
| 116 | + * | ||
| 117 | + * @param num | ||
| 118 | + * @return | ||
| 119 | + */ | ||
| 120 | + private static int getNextNum(int num) { | ||
| 121 | + num++; | ||
| 122 | + return num; | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + /** | ||
| 126 | + * 递增获取下个字母 | ||
| 127 | + * | ||
| 128 | + * @param num | ||
| 129 | + * @return | ||
| 130 | + */ | ||
| 131 | + private static char getNextZiMu(char zimu) { | ||
| 132 | + if (zimu == 'Z') { | ||
| 133 | + return 'A'; | ||
| 134 | + } | ||
| 135 | + zimu++; | ||
| 136 | + return zimu; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + /** | ||
| 140 | + * 根据数字位数获取最大值 | ||
| 141 | + * @param length | ||
| 142 | + * @return | ||
| 143 | + */ | ||
| 144 | + private static int getMaxNumByLength(int length){ | ||
| 145 | + if(length==0){ | ||
| 146 | + return 0; | ||
| 147 | + } | ||
| 148 | + String max_num = ""; | ||
| 149 | + for (int i=0;i<length;i++){ | ||
| 150 | + max_num = max_num + "9"; | ||
| 151 | + } | ||
| 152 | + return Integer.parseInt(max_num); | ||
| 153 | + } | ||
| 154 | + public static String[] cutYouBianCode(String code){ | ||
| 155 | + if(code==null || StringUtil.isNullOrEmpty(code)){ | ||
| 156 | + return null; | ||
| 157 | + }else{ | ||
| 158 | + //获取标准长度为numLength+1,截取的数量为code.length/numLength+1 | ||
| 159 | + int c = code.length()/(numLength+1); | ||
| 160 | + String[] cutcode = new String[c]; | ||
| 161 | + for(int i =0 ; i <c;i++){ | ||
| 162 | + cutcode[i] = code.substring(0,(i+1)*(numLength+1)); | ||
| 163 | + } | ||
| 164 | + return cutcode; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + } | ||
| 168 | +// public static void main(String[] args) { | ||
| 169 | +// // org.jeecgframework.core.util.LogUtil.info(getNextZiMu('C')); | ||
| 170 | +// // org.jeecgframework.core.util.LogUtil.info(getNextNum(8)); | ||
| 171 | +// // org.jeecgframework.core.util.LogUtil.info(cutYouBianCode("C99A01B01")[2]); | ||
| 172 | +// } | ||
| 173 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DataSourceCachePool.java
0 → 100644
| 1 | +package org.jeecg.common.util.dynamic.db; | ||
| 2 | + | ||
| 3 | +import com.alibaba.druid.pool.DruidDataSource; | ||
| 4 | +import org.jeecg.common.api.CommonAPI; | ||
| 5 | +import org.jeecg.common.constant.CacheConstant; | ||
| 6 | +import org.jeecg.common.system.vo.DynamicDataSourceModel; | ||
| 7 | +import org.jeecg.common.util.RedisUtil; | ||
| 8 | +import org.jeecg.common.util.SpringContextUtils; | ||
| 9 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 10 | +import java.util.HashMap; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 数据源缓存池 | ||
| 16 | + */ | ||
| 17 | +public class DataSourceCachePool { | ||
| 18 | + /** 数据源连接池缓存【本地 class缓存 - 不支持分布式】 */ | ||
| 19 | + private static Map<String, DruidDataSource> dbSources = new HashMap<>(); | ||
| 20 | + private static RedisTemplate<String, Object> redisTemplate; | ||
| 21 | + | ||
| 22 | + private static RedisTemplate<String, Object> getRedisTemplate() { | ||
| 23 | + if (redisTemplate == null) { | ||
| 24 | + redisTemplate = (RedisTemplate<String, Object>) SpringContextUtils.getBean("redisTemplate"); | ||
| 25 | + } | ||
| 26 | + return redisTemplate; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 获取多数据源缓存 | ||
| 31 | + * | ||
| 32 | + * @param dbKey | ||
| 33 | + * @return | ||
| 34 | + */ | ||
| 35 | + public static DynamicDataSourceModel getCacheDynamicDataSourceModel(String dbKey) { | ||
| 36 | + String redisCacheKey = CacheConstant.SYS_DYNAMICDB_CACHE + dbKey; | ||
| 37 | + if (getRedisTemplate().hasKey(redisCacheKey)) { | ||
| 38 | + return (DynamicDataSourceModel) getRedisTemplate().opsForValue().get(redisCacheKey); | ||
| 39 | + } | ||
| 40 | + CommonAPI commonAPI = SpringContextUtils.getBean(CommonAPI.class); | ||
| 41 | + DynamicDataSourceModel dbSource = commonAPI.getDynamicDbSourceByCode(dbKey); | ||
| 42 | + if (dbSource != null) { | ||
| 43 | + getRedisTemplate().opsForValue().set(redisCacheKey, dbSource); | ||
| 44 | + } | ||
| 45 | + return dbSource; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public static DruidDataSource getCacheBasicDataSource(String dbKey) { | ||
| 49 | + return dbSources.get(dbKey); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * put 数据源缓存 | ||
| 54 | + * | ||
| 55 | + * @param dbKey | ||
| 56 | + * @param db | ||
| 57 | + */ | ||
| 58 | + public static void putCacheBasicDataSource(String dbKey, DruidDataSource db) { | ||
| 59 | + dbSources.put(dbKey, db); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * 清空数据源缓存 | ||
| 64 | + */ | ||
| 65 | + public static void cleanAllCache() { | ||
| 66 | + //关闭数据源连接 | ||
| 67 | + for(Map.Entry<String, DruidDataSource> entry : dbSources.entrySet()){ | ||
| 68 | + String dbkey = entry.getKey(); | ||
| 69 | + DruidDataSource druidDataSource = entry.getValue(); | ||
| 70 | + if(druidDataSource!=null && druidDataSource.isEnable()){ | ||
| 71 | + druidDataSource.close(); | ||
| 72 | + } | ||
| 73 | + //清空redis缓存 | ||
| 74 | + getRedisTemplate().delete(CacheConstant.SYS_DYNAMICDB_CACHE + dbkey); | ||
| 75 | + } | ||
| 76 | + //清空缓存 | ||
| 77 | + dbSources.clear(); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + public static void removeCache(String dbKey) { | ||
| 81 | + //关闭数据源连接 | ||
| 82 | + DruidDataSource druidDataSource = dbSources.get(dbKey); | ||
| 83 | + if(druidDataSource!=null && druidDataSource.isEnable()){ | ||
| 84 | + druidDataSource.close(); | ||
| 85 | + } | ||
| 86 | + //清空redis缓存 | ||
| 87 | + getRedisTemplate().delete(CacheConstant.SYS_DYNAMICDB_CACHE + dbKey); | ||
| 88 | + //清空缓存 | ||
| 89 | + dbSources.remove(dbKey); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DynamicDBUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util.dynamic.db; | ||
| 2 | + | ||
| 3 | +import com.alibaba.druid.pool.DruidDataSource; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.apache.commons.lang3.ArrayUtils; | ||
| 6 | +import org.jeecg.common.exception.JeecgBootException; | ||
| 7 | +import org.jeecg.common.exception.JeecgBootException; | ||
| 8 | +import org.jeecg.common.system.vo.DynamicDataSourceModel; | ||
| 9 | +import org.jeecg.common.util.ReflectHelper; | ||
| 10 | +import org.jeecg.common.util.oConvertUtils; | ||
| 11 | +import org.springframework.jdbc.core.JdbcTemplate; | ||
| 12 | +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; | ||
| 13 | + | ||
| 14 | +import javax.sql.DataSource; | ||
| 15 | +import java.sql.SQLException; | ||
| 16 | +import java.util.HashMap; | ||
| 17 | +import java.util.List; | ||
| 18 | +import java.util.Map; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Spring JDBC 实时数据库访问 | ||
| 22 | + * | ||
| 23 | + * @author chenguobin | ||
| 24 | + * @version 1.0 | ||
| 25 | + * @date 2014-09-05 | ||
| 26 | + */ | ||
| 27 | +@Slf4j | ||
| 28 | +public class DynamicDBUtil { | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 获取数据源【最底层方法,不要随便调用】 | ||
| 32 | + * | ||
| 33 | + * @param dbSource | ||
| 34 | + * @return | ||
| 35 | + */ | ||
| 36 | + private static DruidDataSource getJdbcDataSource(final DynamicDataSourceModel dbSource) { | ||
| 37 | + DruidDataSource dataSource = new DruidDataSource(); | ||
| 38 | + | ||
| 39 | + String driverClassName = dbSource.getDbDriver(); | ||
| 40 | + String url = dbSource.getDbUrl(); | ||
| 41 | + String dbUser = dbSource.getDbUsername(); | ||
| 42 | + String dbPassword = dbSource.getDbPassword(); | ||
| 43 | + dataSource.setDriverClassName(driverClassName); | ||
| 44 | + dataSource.setUrl(url); | ||
| 45 | + //dataSource.setValidationQuery("SELECT 1 FROM DUAL"); | ||
| 46 | + dataSource.setTestWhileIdle(true); | ||
| 47 | + dataSource.setTestOnBorrow(false); | ||
| 48 | + dataSource.setTestOnReturn(false); | ||
| 49 | + dataSource.setBreakAfterAcquireFailure(true); | ||
| 50 | + dataSource.setConnectionErrorRetryAttempts(0); | ||
| 51 | + dataSource.setUsername(dbUser); | ||
| 52 | + dataSource.setMaxWait(60000); | ||
| 53 | + dataSource.setPassword(dbPassword); | ||
| 54 | + | ||
| 55 | + log.info("******************************************"); | ||
| 56 | + log.info("* *"); | ||
| 57 | + log.info("*====【"+dbSource.getCode()+"】=====Druid连接池已启用 ====*"); | ||
| 58 | + log.info("* *"); | ||
| 59 | + log.info("******************************************"); | ||
| 60 | + return dataSource; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + /** | ||
| 64 | + * 通过 dbKey ,获取数据源 | ||
| 65 | + * | ||
| 66 | + * @param dbKey | ||
| 67 | + * @return | ||
| 68 | + */ | ||
| 69 | + public static DruidDataSource getDbSourceByDbKey(final String dbKey) { | ||
| 70 | + //获取多数据源配置 | ||
| 71 | + DynamicDataSourceModel dbSource = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey); | ||
| 72 | + //先判断缓存中是否存在数据库链接 | ||
| 73 | + DruidDataSource cacheDbSource = DataSourceCachePool.getCacheBasicDataSource(dbKey); | ||
| 74 | + if (cacheDbSource != null && !cacheDbSource.isClosed()) { | ||
| 75 | + log.debug("--------getDbSourceBydbKey------------------从缓存中获取DB连接-------------------"); | ||
| 76 | + return cacheDbSource; | ||
| 77 | + } else { | ||
| 78 | + DruidDataSource dataSource = getJdbcDataSource(dbSource); | ||
| 79 | + if(dataSource!=null && dataSource.isEnable()){ | ||
| 80 | + DataSourceCachePool.putCacheBasicDataSource(dbKey, dataSource); | ||
| 81 | + }else{ | ||
| 82 | + throw new JeecgBootException("动态数据源连接失败,dbKey:"+dbKey); | ||
| 83 | + } | ||
| 84 | + log.info("--------getDbSourceBydbKey------------------创建DB数据库连接-------------------"); | ||
| 85 | + return dataSource; | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + /** | ||
| 90 | + * 关闭数据库连接池 | ||
| 91 | + * | ||
| 92 | + * @param dbKey | ||
| 93 | + * @return | ||
| 94 | + */ | ||
| 95 | + public static void closeDbKey(final String dbKey) { | ||
| 96 | + DruidDataSource dataSource = getDbSourceByDbKey(dbKey); | ||
| 97 | + try { | ||
| 98 | + if (dataSource != null && !dataSource.isClosed()) { | ||
| 99 | + dataSource.getConnection().commit(); | ||
| 100 | + dataSource.getConnection().close(); | ||
| 101 | + dataSource.close(); | ||
| 102 | + } | ||
| 103 | + } catch (SQLException e) { | ||
| 104 | + e.printStackTrace(); | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + | ||
| 109 | + private static JdbcTemplate getJdbcTemplate(String dbKey) { | ||
| 110 | + DruidDataSource dataSource = getDbSourceByDbKey(dbKey); | ||
| 111 | + return new JdbcTemplate(dataSource); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + /** | ||
| 115 | + * Executes the SQL statement in this <code>PreparedStatement</code> object, | ||
| 116 | + * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or | ||
| 117 | + * <code>DELETE</code>; or an SQL statement that returns nothing, | ||
| 118 | + * such as a DDL statement. | ||
| 119 | + */ | ||
| 120 | + public static int update(final String dbKey, String sql, Object... param) { | ||
| 121 | + int effectCount; | ||
| 122 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 123 | + if (ArrayUtils.isEmpty(param)) { | ||
| 124 | + effectCount = jdbcTemplate.update(sql); | ||
| 125 | + } else { | ||
| 126 | + effectCount = jdbcTemplate.update(sql, param); | ||
| 127 | + } | ||
| 128 | + return effectCount; | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * 支持miniDao语法操作的Update | ||
| 133 | + * | ||
| 134 | + * @param dbKey 数据源标识 | ||
| 135 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 136 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 137 | + * @return | ||
| 138 | + */ | ||
| 139 | + public static int updateByHash(final String dbKey, String sql, HashMap<String, Object> data) { | ||
| 140 | + int effectCount; | ||
| 141 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 142 | + //根据模板获取sql | ||
| 143 | + sql = FreemarkerParseFactory.parseTemplateContent(sql, data); | ||
| 144 | + NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource()); | ||
| 145 | + effectCount = namedParameterJdbcTemplate.update(sql, data); | ||
| 146 | + return effectCount; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + public static Object findOne(final String dbKey, String sql, Object... param) { | ||
| 150 | + List<Map<String, Object>> list; | ||
| 151 | + list = findList(dbKey, sql, param); | ||
| 152 | + if (oConvertUtils.listIsEmpty(list)) { | ||
| 153 | + log.error("Except one, but not find actually"); | ||
| 154 | + } | ||
| 155 | + if (list.size() > 1) { | ||
| 156 | + log.error("Except one, but more than one actually"); | ||
| 157 | + } | ||
| 158 | + return list.get(0); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + /** | ||
| 162 | + * 支持miniDao语法操作的查询 返回HashMap | ||
| 163 | + * | ||
| 164 | + * @param dbKey 数据源标识 | ||
| 165 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 166 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 167 | + * @return | ||
| 168 | + */ | ||
| 169 | + public static Object findOneByHash(final String dbKey, String sql, HashMap<String, Object> data) { | ||
| 170 | + List<Map<String, Object>> list; | ||
| 171 | + list = findListByHash(dbKey, sql, data); | ||
| 172 | + if (oConvertUtils.listIsEmpty(list)) { | ||
| 173 | + log.error("Except one, but not find actually"); | ||
| 174 | + } | ||
| 175 | + if (list.size() > 1) { | ||
| 176 | + log.error("Except one, but more than one actually"); | ||
| 177 | + } | ||
| 178 | + return list.get(0); | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + /** | ||
| 182 | + * 直接sql查询 根据clazz返回单个实例 | ||
| 183 | + * | ||
| 184 | + * @param dbKey 数据源标识 | ||
| 185 | + * @param sql 执行sql语句 | ||
| 186 | + * @param clazz 返回实例的Class | ||
| 187 | + * @param param | ||
| 188 | + * @return | ||
| 189 | + */ | ||
| 190 | + @SuppressWarnings("unchecked") | ||
| 191 | + public static <T> Object findOne(final String dbKey, String sql, Class<T> clazz, Object... param) { | ||
| 192 | + Map<String, Object> map = (Map<String, Object>) findOne(dbKey, sql, param); | ||
| 193 | + return ReflectHelper.setAll(clazz, map); | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + /** | ||
| 197 | + * 支持miniDao语法操作的查询 返回单个实例 | ||
| 198 | + * | ||
| 199 | + * @param dbKey 数据源标识 | ||
| 200 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 201 | + * @param clazz 返回实例的Class | ||
| 202 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 203 | + * @return | ||
| 204 | + */ | ||
| 205 | + @SuppressWarnings("unchecked") | ||
| 206 | + public static <T> Object findOneByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) { | ||
| 207 | + Map<String, Object> map = (Map<String, Object>) findOneByHash(dbKey, sql, data); | ||
| 208 | + return ReflectHelper.setAll(clazz, map); | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + public static List<Map<String, Object>> findList(final String dbKey, String sql, Object... param) { | ||
| 212 | + List<Map<String, Object>> list; | ||
| 213 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 214 | + | ||
| 215 | + if (ArrayUtils.isEmpty(param)) { | ||
| 216 | + list = jdbcTemplate.queryForList(sql); | ||
| 217 | + } else { | ||
| 218 | + list = jdbcTemplate.queryForList(sql, param); | ||
| 219 | + } | ||
| 220 | + return list; | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + /** | ||
| 224 | + * 支持miniDao语法操作的查询 | ||
| 225 | + * | ||
| 226 | + * @param dbKey 数据源标识 | ||
| 227 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 228 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 229 | + * @return | ||
| 230 | + */ | ||
| 231 | + public static List<Map<String, Object>> findListByHash(final String dbKey, String sql, HashMap<String, Object> data) { | ||
| 232 | + List<Map<String, Object>> list; | ||
| 233 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 234 | + //根据模板获取sql | ||
| 235 | + sql = FreemarkerParseFactory.parseTemplateContent(sql, data); | ||
| 236 | + NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource()); | ||
| 237 | + list = namedParameterJdbcTemplate.queryForList(sql, data); | ||
| 238 | + return list; | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + //此方法只能返回单列,不能返回实体类 | ||
| 242 | + public static <T> List<T> findList(final String dbKey, String sql, Class<T> clazz, Object... param) { | ||
| 243 | + List<T> list; | ||
| 244 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 245 | + | ||
| 246 | + if (ArrayUtils.isEmpty(param)) { | ||
| 247 | + list = jdbcTemplate.queryForList(sql, clazz); | ||
| 248 | + } else { | ||
| 249 | + list = jdbcTemplate.queryForList(sql, clazz, param); | ||
| 250 | + } | ||
| 251 | + return list; | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + /** | ||
| 255 | + * 支持miniDao语法操作的查询 返回单列数据list | ||
| 256 | + * | ||
| 257 | + * @param dbKey 数据源标识 | ||
| 258 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 259 | + * @param clazz 类型Long、String等 | ||
| 260 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 261 | + * @return | ||
| 262 | + */ | ||
| 263 | + public static <T> List<T> findListByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) { | ||
| 264 | + List<T> list; | ||
| 265 | + JdbcTemplate jdbcTemplate = getJdbcTemplate(dbKey); | ||
| 266 | + //根据模板获取sql | ||
| 267 | + sql = FreemarkerParseFactory.parseTemplateContent(sql, data); | ||
| 268 | + NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate.getDataSource()); | ||
| 269 | + list = namedParameterJdbcTemplate.queryForList(sql, data, clazz); | ||
| 270 | + return list; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + /** | ||
| 274 | + * 直接sql查询 返回实体类列表 | ||
| 275 | + * | ||
| 276 | + * @param dbKey 数据源标识 | ||
| 277 | + * @param sql 执行sql语句,sql支持 minidao 语法逻辑 | ||
| 278 | + * @param clazz 返回实体类列表的class | ||
| 279 | + * @param param sql拼接注入中需要的数据 | ||
| 280 | + * @return | ||
| 281 | + */ | ||
| 282 | + public static <T> List<T> findListEntities(final String dbKey, String sql, Class<T> clazz, Object... param) { | ||
| 283 | + List<Map<String, Object>> queryList = findList(dbKey, sql, param); | ||
| 284 | + return ReflectHelper.transList2Entrys(queryList, clazz); | ||
| 285 | + } | ||
| 286 | + | ||
| 287 | + /** | ||
| 288 | + * 支持miniDao语法操作的查询 返回实体类列表 | ||
| 289 | + * | ||
| 290 | + * @param dbKey 数据源标识 | ||
| 291 | + * @param sql 执行sql语句,sql支持minidao语法逻辑 | ||
| 292 | + * @param clazz 返回实体类列表的class | ||
| 293 | + * @param data sql语法中需要判断的数据及sql拼接注入中需要的数据 | ||
| 294 | + * @return | ||
| 295 | + */ | ||
| 296 | + public static <T> List<T> findListEntitiesByHash(final String dbKey, String sql, Class<T> clazz, HashMap<String, Object> data) { | ||
| 297 | + List<Map<String, Object>> queryList = findListByHash(dbKey, sql, data); | ||
| 298 | + return ReflectHelper.transList2Entrys(queryList, clazz); | ||
| 299 | + } | ||
| 300 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/FreemarkerParseFactory.java
0 → 100644
| 1 | +package org.jeecg.common.util.dynamic.db; | ||
| 2 | + | ||
| 3 | +import freemarker.cache.StringTemplateLoader; | ||
| 4 | +import freemarker.core.ParseException; | ||
| 5 | +import freemarker.template.Configuration; | ||
| 6 | +import freemarker.template.Template; | ||
| 7 | +import lombok.extern.slf4j.Slf4j; | ||
| 8 | +import org.apache.commons.lang3.StringUtils; | ||
| 9 | +import org.jeecgframework.codegenerate.generate.util.SimpleFormat; | ||
| 10 | + | ||
| 11 | +import java.io.StringWriter; | ||
| 12 | +import java.util.Map; | ||
| 13 | +import java.util.regex.Pattern; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * @author 赵俊夫 | ||
| 17 | + * @version V1.0 | ||
| 18 | + * @Title:FreemarkerHelper | ||
| 19 | + * @description:Freemarker引擎协助类 | ||
| 20 | + * @date Jul 5, 2013 2:58:29 PM | ||
| 21 | + */ | ||
| 22 | +@Slf4j | ||
| 23 | +public class FreemarkerParseFactory { | ||
| 24 | + | ||
| 25 | + private static final String ENCODE = "utf-8"; | ||
| 26 | + /** | ||
| 27 | + * 参数格式化工具类 | ||
| 28 | + */ | ||
| 29 | + private static final String MINI_DAO_FORMAT = "DaoFormat"; | ||
| 30 | + | ||
| 31 | + /** | ||
| 32 | + * 文件缓存 | ||
| 33 | + */ | ||
| 34 | + private static final Configuration _tplConfig = new Configuration(); | ||
| 35 | + /** | ||
| 36 | + * SQL 缓存 | ||
| 37 | + */ | ||
| 38 | + private static final Configuration _sqlConfig = new Configuration(); | ||
| 39 | + | ||
| 40 | + private static StringTemplateLoader stringTemplateLoader = new StringTemplateLoader(); | ||
| 41 | + | ||
| 42 | + // 使用内嵌的(?ms)打开单行和多行模式 | ||
| 43 | + private final static Pattern p = Pattern | ||
| 44 | + .compile("(?ms)/\\*.*?\\*/|^\\s*//.*?$"); | ||
| 45 | + | ||
| 46 | + static { | ||
| 47 | + _tplConfig.setClassForTemplateLoading( | ||
| 48 | + new FreemarkerParseFactory().getClass(), "/"); | ||
| 49 | + _tplConfig.setNumberFormat("0.#####################"); | ||
| 50 | + _sqlConfig.setTemplateLoader(stringTemplateLoader); | ||
| 51 | + _sqlConfig.setNumberFormat("0.#####################"); | ||
| 52 | + //classic_compatible设置,解决报空指针错误 | ||
| 53 | + _sqlConfig.setClassicCompatible(true); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 判断模板是否存在 | ||
| 58 | + * | ||
| 59 | + * @throws Exception | ||
| 60 | + */ | ||
| 61 | + public static boolean isExistTemplate(String tplName) throws Exception { | ||
| 62 | + try { | ||
| 63 | + Template mytpl = _tplConfig.getTemplate(tplName, "UTF-8"); | ||
| 64 | + if (mytpl == null) { | ||
| 65 | + return false; | ||
| 66 | + } | ||
| 67 | + } catch (Exception e) { | ||
| 68 | + //update-begin--Author:scott Date:20180320 for:解决问题 - 错误提示sql文件不存在,实际问题是sql freemarker用法错误----- | ||
| 69 | + if (e instanceof ParseException) { | ||
| 70 | + log.error(e.getMessage(), e.fillInStackTrace()); | ||
| 71 | + throw new Exception(e); | ||
| 72 | + } | ||
| 73 | + log.debug("----isExistTemplate----" + e.toString()); | ||
| 74 | + //update-end--Author:scott Date:20180320 for:解决问题 - 错误提示sql文件不存在,实际问题是sql freemarker用法错误------ | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + return true; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + /** | ||
| 81 | + * 解析ftl模板 | ||
| 82 | + * | ||
| 83 | + * @param tplName 模板名 | ||
| 84 | + * @param paras 参数 | ||
| 85 | + * @return | ||
| 86 | + */ | ||
| 87 | + public static String parseTemplate(String tplName, Map<String, Object> paras) { | ||
| 88 | + try { | ||
| 89 | + log.debug(" minidao sql templdate : " + tplName); | ||
| 90 | + StringWriter swriter = new StringWriter(); | ||
| 91 | + Template mytpl = _tplConfig.getTemplate(tplName, ENCODE); | ||
| 92 | + if (paras.containsKey(MINI_DAO_FORMAT)) { | ||
| 93 | + throw new RuntimeException("DaoFormat 是 minidao 保留关键字,不允许使用 ,请更改参数定义!"); | ||
| 94 | + } | ||
| 95 | + paras.put(MINI_DAO_FORMAT, new SimpleFormat()); | ||
| 96 | + mytpl.process(paras, swriter); | ||
| 97 | + String sql = getSqlText(swriter.toString()); | ||
| 98 | + paras.remove(MINI_DAO_FORMAT); | ||
| 99 | + return sql; | ||
| 100 | + } catch (Exception e) { | ||
| 101 | + log.error(e.getMessage(), e.fillInStackTrace()); | ||
| 102 | + log.error("发送一次的模板key:{ " + tplName + " }"); | ||
| 103 | + //System.err.println(e.getMessage()); | ||
| 104 | + //System.err.println("模板名:{ "+ tplName +" }"); | ||
| 105 | + throw new RuntimeException("解析SQL模板异常"); | ||
| 106 | + } | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + /** | ||
| 110 | + * 解析ftl | ||
| 111 | + * | ||
| 112 | + * @param tplContent 模板内容 | ||
| 113 | + * @param paras 参数 | ||
| 114 | + * @return String 模板解析后内容 | ||
| 115 | + */ | ||
| 116 | + public static String parseTemplateContent(String tplContent, | ||
| 117 | + Map<String, Object> paras) { | ||
| 118 | + try { | ||
| 119 | + StringWriter swriter = new StringWriter(); | ||
| 120 | + if (stringTemplateLoader.findTemplateSource("sql_" + tplContent.hashCode()) == null) { | ||
| 121 | + stringTemplateLoader.putTemplate("sql_" + tplContent.hashCode(), tplContent); | ||
| 122 | + } | ||
| 123 | + Template mytpl = _sqlConfig.getTemplate("sql_" + tplContent.hashCode(), ENCODE); | ||
| 124 | + if (paras.containsKey(MINI_DAO_FORMAT)) { | ||
| 125 | + throw new RuntimeException("DaoFormat 是 minidao 保留关键字,不允许使用 ,请更改参数定义!"); | ||
| 126 | + } | ||
| 127 | + paras.put(MINI_DAO_FORMAT, new SimpleFormat()); | ||
| 128 | + mytpl.process(paras, swriter); | ||
| 129 | + String sql = getSqlText(swriter.toString()); | ||
| 130 | + paras.remove(MINI_DAO_FORMAT); | ||
| 131 | + return sql; | ||
| 132 | + } catch (Exception e) { | ||
| 133 | + log.error(e.getMessage(), e.fillInStackTrace()); | ||
| 134 | + log.error("发送一次的模板key:{ " + tplContent + " }"); | ||
| 135 | + //System.err.println(e.getMessage()); | ||
| 136 | + //System.err.println("模板内容:{ "+ tplContent +" }"); | ||
| 137 | + throw new RuntimeException("解析SQL模板异常"); | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + /** | ||
| 142 | + * 除去无效字段,去掉注释 不然批量处理可能报错 去除无效的等于 | ||
| 143 | + */ | ||
| 144 | + private static String getSqlText(String sql) { | ||
| 145 | + // 将注释替换成"" | ||
| 146 | + sql = p.matcher(sql).replaceAll(""); | ||
| 147 | + sql = sql.replaceAll("\\n", " ").replaceAll("\\t", " ") | ||
| 148 | + .replaceAll("\\s{1,}", " ").trim(); | ||
| 149 | + // 去掉 最后是 where这样的问题 | ||
| 150 | + if (sql.endsWith("where") || sql.endsWith("where ")) { | ||
| 151 | + sql = sql.substring(0, sql.lastIndexOf("where")); | ||
| 152 | + } | ||
| 153 | + // 去掉where and 这样的问题 | ||
| 154 | + int index = 0; | ||
| 155 | + while ((index = StringUtils.indexOfIgnoreCase(sql, "where and", index)) != -1) { | ||
| 156 | + sql = sql.substring(0, index + 5) | ||
| 157 | + + sql.substring(index + 9, sql.length()); | ||
| 158 | + } | ||
| 159 | + // 去掉 , where 这样的问题 | ||
| 160 | + index = 0; | ||
| 161 | + while ((index = StringUtils.indexOfIgnoreCase(sql, ", where", index)) != -1) { | ||
| 162 | + sql = sql.substring(0, index) | ||
| 163 | + + sql.substring(index + 1, sql.length()); | ||
| 164 | + } | ||
| 165 | + // 去掉 最后是 ,这样的问题 | ||
| 166 | + if (sql.endsWith(",") || sql.endsWith(", ")) { | ||
| 167 | + sql = sql.substring(0, sql.lastIndexOf(",")); | ||
| 168 | + } | ||
| 169 | + return sql; | ||
| 170 | + } | ||
| 171 | +} | ||
| 0 | \ No newline at end of file | 172 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/SqlUtils.java
0 → 100644
| 1 | +package org.jeecg.common.util.dynamic.db; | ||
| 2 | + | ||
| 3 | +import org.apache.commons.lang3.StringUtils; | ||
| 4 | +import org.jeecg.common.constant.DataBaseConstant; | ||
| 5 | +import org.jeecg.common.system.vo.DynamicDataSourceModel; | ||
| 6 | + | ||
| 7 | +import java.text.MessageFormat; | ||
| 8 | +import java.util.Map; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 根据不同的数据库,动态生成SQL,例如分页 | ||
| 12 | + */ | ||
| 13 | +public class SqlUtils { | ||
| 14 | + | ||
| 15 | + public static final String DATABSE_TYPE_MYSQL = "mysql"; | ||
| 16 | + public static final String DATABSE_TYPE_MARIADB = "mariadb"; | ||
| 17 | + public static final String DATABSE_TYPE_POSTGRE = "postgresql"; | ||
| 18 | + public static final String DATABSE_TYPE_ORACLE = "oracle"; | ||
| 19 | + public static final String DATABSE_TYPE_SQLSERVER = "sqlserver"; | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 分页SQL | ||
| 24 | + */ | ||
| 25 | + public static final String MYSQL_SQL = "select * from ( {0}) sel_tab00 limit {1},{2}"; | ||
| 26 | + public static final String POSTGRE_SQL = "select * from ( {0}) sel_tab00 limit {2} offset {1}"; | ||
| 27 | + public static final String ORACLE_SQL = "select * from (select row_.*,rownum rownum_ from ({0}) row_ where rownum <= {1}) where rownum_>{2}"; | ||
| 28 | + public static final String SQLSERVER_SQL = "select * from ( select row_number() over(order by tempColumn) tempRowNumber, * from (select top {1} tempColumn = 0, {0}) t ) tt where tempRowNumber > {2}"; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 获取所有表的SQL | ||
| 32 | + */ | ||
| 33 | + public static final String MYSQL_ALLTABLES_SQL = "select distinct table_name from information_schema.columns where table_schema = {0}"; | ||
| 34 | + public static final String POSTGRE__ALLTABLES_SQL = "SELECT distinct c.relname AS table_name FROM pg_class c"; | ||
| 35 | + public static final String ORACLE__ALLTABLES_SQL = "select distinct colstable.table_name as table_name from user_tab_cols colstable"; | ||
| 36 | + public static final String SQLSERVER__ALLTABLES_SQL = "select distinct c.name as table_name from sys.objects c"; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 获取指定表的所有列名 | ||
| 40 | + */ | ||
| 41 | + public static final String MYSQL_ALLCOLUMNS_SQL = "select column_name from information_schema.columns where table_name = {0} and table_schema = {1}"; | ||
| 42 | + public static final String POSTGRE_ALLCOLUMNS_SQL = "select table_name from information_schema.columns where table_name = {0}"; | ||
| 43 | + public static final String ORACLE_ALLCOLUMNS_SQL = "select column_name from all_tab_columns where table_name ={0}"; | ||
| 44 | + public static final String SQLSERVER_ALLCOLUMNS_SQL = "select name from syscolumns where id={0}"; | ||
| 45 | + | ||
| 46 | + /* | ||
| 47 | + * 判断数据库类型 | ||
| 48 | + */ | ||
| 49 | + | ||
| 50 | + public static boolean dbTypeIsMySQL(String dbType) { | ||
| 51 | + return dbTypeIf(dbType, DATABSE_TYPE_MYSQL, DataBaseConstant.DB_TYPE_MYSQL_NUM) || dbTypeIf(dbType, DATABSE_TYPE_MARIADB, DataBaseConstant.DB_TYPE_MARIADB_NUM); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public static boolean dbTypeIsOracle(String dbType) { | ||
| 55 | + return dbTypeIf(dbType, DATABSE_TYPE_ORACLE, DataBaseConstant.DB_TYPE_ORACLE_NUM); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public static boolean dbTypeIsSQLServer(String dbType) { | ||
| 59 | + return dbTypeIf(dbType, DATABSE_TYPE_SQLSERVER, DataBaseConstant.DB_TYPE_SQLSERVER_NUM); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public static boolean dbTypeIsPostgre(String dbType) { | ||
| 63 | + return dbTypeIf(dbType, DATABSE_TYPE_POSTGRE, DataBaseConstant.DB_TYPE_POSTGRESQL_NUM); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * 判断数据库类型 | ||
| 68 | + */ | ||
| 69 | + public static boolean dbTypeIf(String dbType, String... correctTypes) { | ||
| 70 | + for (String type : correctTypes) { | ||
| 71 | + if (type.equalsIgnoreCase(dbType)) { | ||
| 72 | + return true; | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * 获取全 SQL | ||
| 80 | + * 拼接 where 条件 | ||
| 81 | + * | ||
| 82 | + * @param sql | ||
| 83 | + * @param params | ||
| 84 | + * @return | ||
| 85 | + */ | ||
| 86 | + public static String getFullSql(String sql, Map params) { | ||
| 87 | + return getFullSql(sql, params, null, null); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * 获取全 SQL | ||
| 92 | + * 拼接 where 条件 | ||
| 93 | + * 拼接 order 排序 | ||
| 94 | + * | ||
| 95 | + * @param sql | ||
| 96 | + * @param params | ||
| 97 | + * @param orderColumn 排序字段 | ||
| 98 | + * @param orderBy 排序方式,只能是 DESC 或 ASC | ||
| 99 | + * @return | ||
| 100 | + */ | ||
| 101 | + public static String getFullSql(String sql, Map params, String orderColumn, String orderBy) { | ||
| 102 | + StringBuilder sqlBuilder = new StringBuilder(); | ||
| 103 | + sqlBuilder.append("SELECT t.* FROM ( ").append(sql).append(" ) t "); | ||
| 104 | + if (params != null && params.size() >= 1) { | ||
| 105 | + sqlBuilder.append("WHERE 1=1 "); | ||
| 106 | + for (Object key : params.keySet()) { | ||
| 107 | + String value = String.valueOf(params.get(key)); | ||
| 108 | + if (StringUtils.isNotBlank(value)) { | ||
| 109 | + sqlBuilder.append(" AND (").append(key).append(" = N'").append(value).append("')"); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + if (StringUtils.isNotBlank(orderColumn) && StringUtils.isNotBlank(orderBy)) { | ||
| 113 | + sqlBuilder.append("ORDER BY ").append(orderColumn).append(" ").append("DESC".equalsIgnoreCase(orderBy) ? "DESC" : "ASC"); | ||
| 114 | + } | ||
| 115 | + } | ||
| 116 | + return sqlBuilder.toString(); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * 获取求数量 SQL | ||
| 121 | + * | ||
| 122 | + * @param sql | ||
| 123 | + * @return | ||
| 124 | + */ | ||
| 125 | + public static String getCountSql(String sql) { | ||
| 126 | + return String.format("SELECT COUNT(1) \"total\" FROM ( %s ) temp_count", sql); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + /** | ||
| 130 | + * 生成分页查询 SQL | ||
| 131 | + * | ||
| 132 | + * @param dbType 数据库类型 | ||
| 133 | + * @param sql | ||
| 134 | + * @param page | ||
| 135 | + * @param rows | ||
| 136 | + * @return | ||
| 137 | + */ | ||
| 138 | + public static String createPageSqlByDBType(String dbType, String sql, int page, int rows) { | ||
| 139 | + int beginNum = (page - 1) * rows; | ||
| 140 | + Object[] sqlParam = new Object[3]; | ||
| 141 | + sqlParam[0] = sql; | ||
| 142 | + sqlParam[1] = String.valueOf(beginNum); | ||
| 143 | + sqlParam[2] = String.valueOf(rows); | ||
| 144 | + if (dbTypeIsMySQL(dbType)) { | ||
| 145 | + sql = MessageFormat.format(MYSQL_SQL, sqlParam); | ||
| 146 | + } else if (dbTypeIsPostgre(dbType)) { | ||
| 147 | + sql = MessageFormat.format(POSTGRE_SQL, sqlParam); | ||
| 148 | + } else { | ||
| 149 | + int beginIndex = (page - 1) * rows; | ||
| 150 | + int endIndex = beginIndex + rows; | ||
| 151 | + sqlParam[2] = Integer.toString(beginIndex); | ||
| 152 | + sqlParam[1] = Integer.toString(endIndex); | ||
| 153 | + if (dbTypeIsOracle(dbType)) { | ||
| 154 | + sql = MessageFormat.format(ORACLE_SQL, sqlParam); | ||
| 155 | + } else if (dbTypeIsSQLServer(dbType)) { | ||
| 156 | + sqlParam[0] = sql.substring(getAfterSelectInsertPoint(sql)); | ||
| 157 | + sql = MessageFormat.format(SQLSERVER_SQL, sqlParam); | ||
| 158 | + } | ||
| 159 | + } | ||
| 160 | + return sql; | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * 生成分页查询 SQL | ||
| 165 | + * | ||
| 166 | + * @param sql | ||
| 167 | + * @param page | ||
| 168 | + * @param rows | ||
| 169 | + * @return | ||
| 170 | + */ | ||
| 171 | + public static String createPageSqlByDBKey(String dbKey, String sql, int page, int rows) { | ||
| 172 | + DynamicDataSourceModel dynamicSourceEntity = DataSourceCachePool.getCacheDynamicDataSourceModel(dbKey); | ||
| 173 | + String dbType = dynamicSourceEntity.getDbType(); | ||
| 174 | + return createPageSqlByDBType(dbType, sql, page, rows); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + private static int getAfterSelectInsertPoint(String sql) { | ||
| 178 | + int selectIndex = sql.toLowerCase().indexOf("select"); | ||
| 179 | + int selectDistinctIndex = sql.toLowerCase().indexOf("select distinct"); | ||
| 180 | + return selectIndex + (selectDistinctIndex == selectIndex ? 15 : 6); | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + public static String getAllTableSql(String dbType, Object... params) { | ||
| 184 | + if (StringUtils.isNotEmpty(dbType)) { | ||
| 185 | + if (dbTypeIsMySQL(dbType)) { | ||
| 186 | + return MessageFormat.format(MYSQL_ALLTABLES_SQL, params); | ||
| 187 | + } else if (dbTypeIsOracle(dbType)) { | ||
| 188 | + return ORACLE__ALLTABLES_SQL; | ||
| 189 | + } else if (dbTypeIsPostgre(dbType)) { | ||
| 190 | + return POSTGRE__ALLTABLES_SQL; | ||
| 191 | + } else if (dbTypeIsSQLServer(dbType)) { | ||
| 192 | + return SQLSERVER__ALLTABLES_SQL; | ||
| 193 | + } | ||
| 194 | + } | ||
| 195 | + return null; | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + public static String getAllColumnSQL(String dbType, Object... params) { | ||
| 199 | + if (StringUtils.isNotEmpty(dbType)) { | ||
| 200 | + if (dbTypeIsMySQL(dbType)) { | ||
| 201 | + return MessageFormat.format(MYSQL_ALLCOLUMNS_SQL, params); | ||
| 202 | + } else if (dbTypeIsOracle(dbType)) { | ||
| 203 | + return MessageFormat.format(ORACLE_ALLCOLUMNS_SQL, params); | ||
| 204 | + } else if (dbTypeIsPostgre(dbType)) { | ||
| 205 | + return MessageFormat.format(POSTGRE_ALLCOLUMNS_SQL, params); | ||
| 206 | + } else if (dbTypeIsSQLServer(dbType)) { | ||
| 207 | + return MessageFormat.format(SQLSERVER_ALLCOLUMNS_SQL, params); | ||
| 208 | + } | ||
| 209 | + } | ||
| 210 | + return null; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/AesEncryptUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util.encryption; | ||
| 2 | + | ||
| 3 | +import org.apache.shiro.codec.Base64; | ||
| 4 | + | ||
| 5 | +import javax.crypto.Cipher; | ||
| 6 | +import javax.crypto.spec.IvParameterSpec; | ||
| 7 | +import javax.crypto.spec.SecretKeySpec; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * AES 加密 | ||
| 11 | + */ | ||
| 12 | +public class AesEncryptUtil { | ||
| 13 | + | ||
| 14 | + //使用AES-128-CBC加密模式,key需要为16位,key和iv可以相同! | ||
| 15 | + private static String KEY = EncryptedString.key; | ||
| 16 | + private static String IV = EncryptedString.iv; | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 加密方法 | ||
| 20 | + * @param data 要加密的数据 | ||
| 21 | + * @param key 加密key | ||
| 22 | + * @param iv 加密iv | ||
| 23 | + * @return 加密的结果 | ||
| 24 | + * @throws Exception | ||
| 25 | + */ | ||
| 26 | + public static String encrypt(String data, String key, String iv) throws Exception { | ||
| 27 | + try { | ||
| 28 | + | ||
| 29 | + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");//"算法/模式/补码方式"NoPadding PkcsPadding | ||
| 30 | + int blockSize = cipher.getBlockSize(); | ||
| 31 | + | ||
| 32 | + byte[] dataBytes = data.getBytes(); | ||
| 33 | + int plaintextLength = dataBytes.length; | ||
| 34 | + if (plaintextLength % blockSize != 0) { | ||
| 35 | + plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize)); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + byte[] plaintext = new byte[plaintextLength]; | ||
| 39 | + System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length); | ||
| 40 | + | ||
| 41 | + SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); | ||
| 42 | + IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); | ||
| 43 | + | ||
| 44 | + cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); | ||
| 45 | + byte[] encrypted = cipher.doFinal(plaintext); | ||
| 46 | + | ||
| 47 | + return Base64.encodeToString(encrypted); | ||
| 48 | + | ||
| 49 | + } catch (Exception e) { | ||
| 50 | + e.printStackTrace(); | ||
| 51 | + return null; | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 解密方法 | ||
| 57 | + * @param data 要解密的数据 | ||
| 58 | + * @param key 解密key | ||
| 59 | + * @param iv 解密iv | ||
| 60 | + * @return 解密的结果 | ||
| 61 | + * @throws Exception | ||
| 62 | + */ | ||
| 63 | + public static String desEncrypt(String data, String key, String iv) throws Exception { | ||
| 64 | + try { | ||
| 65 | + byte[] encrypted1 = Base64.decode(data); | ||
| 66 | + | ||
| 67 | + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | ||
| 68 | + SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES"); | ||
| 69 | + IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); | ||
| 70 | + | ||
| 71 | + cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); | ||
| 72 | + | ||
| 73 | + byte[] original = cipher.doFinal(encrypted1); | ||
| 74 | + String originalString = new String(original); | ||
| 75 | + return originalString; | ||
| 76 | + } catch (Exception e) { | ||
| 77 | + e.printStackTrace(); | ||
| 78 | + return null; | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * 使用默认的key和iv加密 | ||
| 84 | + * @param data | ||
| 85 | + * @return | ||
| 86 | + * @throws Exception | ||
| 87 | + */ | ||
| 88 | + public static String encrypt(String data) throws Exception { | ||
| 89 | + return encrypt(data, KEY, IV); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * 使用默认的key和iv解密 | ||
| 94 | + * @param data | ||
| 95 | + * @return | ||
| 96 | + * @throws Exception | ||
| 97 | + */ | ||
| 98 | + public static String desEncrypt(String data) throws Exception { | ||
| 99 | + return desEncrypt(data, KEY, IV); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + | ||
| 103 | + | ||
| 104 | +// /** | ||
| 105 | +// * 测试 | ||
| 106 | +// */ | ||
| 107 | +// public static void main(String args[]) throws Exception { | ||
| 108 | +// String test1 = "sa"; | ||
| 109 | +// String test =new String(test1.getBytes(),"UTF-8"); | ||
| 110 | +// String data = null; | ||
| 111 | +// String key = KEY; | ||
| 112 | +// String iv = IV; | ||
| 113 | +// // /g2wzfqvMOeazgtsUVbq1kmJawROa6mcRAzwG1/GeJ4= | ||
| 114 | +// data = encrypt(test, key, iv); | ||
| 115 | +// System.out.println("数据:"+test); | ||
| 116 | +// System.out.println("加密:"+data); | ||
| 117 | +// String jiemi =desEncrypt(data, key, iv).trim(); | ||
| 118 | +// System.out.println("解密:"+jiemi); | ||
| 119 | +// } | ||
| 120 | + | ||
| 121 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/encryption/EncryptedString.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/StrAttackFilter.java
0 → 100644
| 1 | +package org.jeecg.common.util.filter; | ||
| 2 | + | ||
| 3 | +import java.util.regex.Matcher; | ||
| 4 | +import java.util.regex.Pattern; | ||
| 5 | +import java.util.regex.PatternSyntaxException; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 文件上传字符串过滤特殊字符 | ||
| 9 | + */ | ||
| 10 | +public class StrAttackFilter { | ||
| 11 | + | ||
| 12 | + public static String filter(String str) throws PatternSyntaxException { | ||
| 13 | + // 清除掉所有特殊字符 | ||
| 14 | + String regEx = "[`_《》~!@#$%^&*()+=|{}':;',\\[\\].<>?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]"; | ||
| 15 | + Pattern p = Pattern.compile(regEx); | ||
| 16 | + Matcher m = p.matcher(str); | ||
| 17 | + return m.replaceAll("").trim(); | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | +// public static void main(String[] args) { | ||
| 21 | +// String filter = filter("@#jeecg/《》【bo】¥%……&*(o))))!@t<>,.,/?'\'~~`"); | ||
| 22 | +// System.out.println(filter); | ||
| 23 | +// } | ||
| 24 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oConvertUtils.java
0 → 100644
| 1 | +package org.jeecg.common.util; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.commons.io.IOUtils; | ||
| 5 | +import org.springframework.beans.BeanUtils; | ||
| 6 | + | ||
| 7 | +import javax.servlet.http.HttpServletRequest; | ||
| 8 | +import java.io.IOException; | ||
| 9 | +import java.io.InputStream; | ||
| 10 | +import java.io.UnsupportedEncodingException; | ||
| 11 | +import java.lang.reflect.Field; | ||
| 12 | +import java.math.BigDecimal; | ||
| 13 | +import java.math.BigInteger; | ||
| 14 | +import java.net.InetAddress; | ||
| 15 | +import java.net.NetworkInterface; | ||
| 16 | +import java.net.SocketException; | ||
| 17 | +import java.net.UnknownHostException; | ||
| 18 | +import java.sql.Date; | ||
| 19 | +import java.util.*; | ||
| 20 | +import java.util.regex.Matcher; | ||
| 21 | +import java.util.regex.Pattern; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * | ||
| 25 | + * @Author 张代浩 | ||
| 26 | + * | ||
| 27 | + */ | ||
| 28 | +@Slf4j | ||
| 29 | +public class oConvertUtils { | ||
| 30 | + public static boolean isEmpty(Object object) { | ||
| 31 | + if (object == null) { | ||
| 32 | + return (true); | ||
| 33 | + } | ||
| 34 | + if ("".equals(object)) { | ||
| 35 | + return (true); | ||
| 36 | + } | ||
| 37 | + if ("null".equals(object)) { | ||
| 38 | + return (true); | ||
| 39 | + } | ||
| 40 | + return (false); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public static boolean isNotEmpty(Object object) { | ||
| 44 | + if (object != null && !object.equals("") && !object.equals("null")) { | ||
| 45 | + return (true); | ||
| 46 | + } | ||
| 47 | + return (false); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public static String decode(String strIn, String sourceCode, String targetCode) { | ||
| 51 | + String temp = code2code(strIn, sourceCode, targetCode); | ||
| 52 | + return temp; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public static String StrToUTF(String strIn, String sourceCode, String targetCode) { | ||
| 56 | + strIn = ""; | ||
| 57 | + try { | ||
| 58 | + strIn = new String(strIn.getBytes("ISO-8859-1"), "GBK"); | ||
| 59 | + } catch (UnsupportedEncodingException e) { | ||
| 60 | + // TODO Auto-generated catch block | ||
| 61 | + e.printStackTrace(); | ||
| 62 | + } | ||
| 63 | + return strIn; | ||
| 64 | + | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + private static String code2code(String strIn, String sourceCode, String targetCode) { | ||
| 68 | + String strOut = null; | ||
| 69 | + if (strIn == null || (strIn.trim()).equals("")) { | ||
| 70 | + return strIn; | ||
| 71 | + } | ||
| 72 | + try { | ||
| 73 | + byte[] b = strIn.getBytes(sourceCode); | ||
| 74 | + for (int i = 0; i < b.length; i++) { | ||
| 75 | + System.out.print(b[i] + " "); | ||
| 76 | + } | ||
| 77 | + strOut = new String(b, targetCode); | ||
| 78 | + } catch (Exception e) { | ||
| 79 | + e.printStackTrace(); | ||
| 80 | + return null; | ||
| 81 | + } | ||
| 82 | + return strOut; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + public static int getInt(String s, int defval) { | ||
| 86 | + if (s == null || s == "") { | ||
| 87 | + return (defval); | ||
| 88 | + } | ||
| 89 | + try { | ||
| 90 | + return (Integer.parseInt(s)); | ||
| 91 | + } catch (NumberFormatException e) { | ||
| 92 | + return (defval); | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + public static int getInt(String s) { | ||
| 97 | + if (s == null || s == "") { | ||
| 98 | + return 0; | ||
| 99 | + } | ||
| 100 | + try { | ||
| 101 | + return (Integer.parseInt(s)); | ||
| 102 | + } catch (NumberFormatException e) { | ||
| 103 | + return 0; | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public static int getInt(String s, Integer df) { | ||
| 108 | + if (s == null || s == "") { | ||
| 109 | + return df; | ||
| 110 | + } | ||
| 111 | + try { | ||
| 112 | + return (Integer.parseInt(s)); | ||
| 113 | + } catch (NumberFormatException e) { | ||
| 114 | + return 0; | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public static Integer[] getInts(String[] s) { | ||
| 119 | + Integer[] integer = new Integer[s.length]; | ||
| 120 | + if (s == null) { | ||
| 121 | + return null; | ||
| 122 | + } | ||
| 123 | + for (int i = 0; i < s.length; i++) { | ||
| 124 | + integer[i] = Integer.parseInt(s[i]); | ||
| 125 | + } | ||
| 126 | + return integer; | ||
| 127 | + | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + public static double getDouble(String s, double defval) { | ||
| 131 | + if (s == null || s == "") { | ||
| 132 | + return (defval); | ||
| 133 | + } | ||
| 134 | + try { | ||
| 135 | + return (Double.parseDouble(s)); | ||
| 136 | + } catch (NumberFormatException e) { | ||
| 137 | + return (defval); | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + public static double getDou(Double s, double defval) { | ||
| 142 | + if (s == null) { | ||
| 143 | + return (defval); | ||
| 144 | + } | ||
| 145 | + return s; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + /*public static Short getShort(String s) { | ||
| 149 | + if (StringUtil.isNotEmpty(s)) { | ||
| 150 | + return (Short.parseShort(s)); | ||
| 151 | + } else { | ||
| 152 | + return null; | ||
| 153 | + } | ||
| 154 | + }*/ | ||
| 155 | + | ||
| 156 | + public static int getInt(Object object, int defval) { | ||
| 157 | + if (isEmpty(object)) { | ||
| 158 | + return (defval); | ||
| 159 | + } | ||
| 160 | + try { | ||
| 161 | + return (Integer.parseInt(object.toString())); | ||
| 162 | + } catch (NumberFormatException e) { | ||
| 163 | + return (defval); | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + public static Integer getInt(Object object) { | ||
| 168 | + if (isEmpty(object)) { | ||
| 169 | + return null; | ||
| 170 | + } | ||
| 171 | + try { | ||
| 172 | + return (Integer.parseInt(object.toString())); | ||
| 173 | + } catch (NumberFormatException e) { | ||
| 174 | + return null; | ||
| 175 | + } | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + public static int getInt(BigDecimal s, int defval) { | ||
| 179 | + if (s == null) { | ||
| 180 | + return (defval); | ||
| 181 | + } | ||
| 182 | + return s.intValue(); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + public static Integer[] getIntegerArry(String[] object) { | ||
| 186 | + int len = object.length; | ||
| 187 | + Integer[] result = new Integer[len]; | ||
| 188 | + try { | ||
| 189 | + for (int i = 0; i < len; i++) { | ||
| 190 | + result[i] = new Integer(object[i].trim()); | ||
| 191 | + } | ||
| 192 | + return result; | ||
| 193 | + } catch (NumberFormatException e) { | ||
| 194 | + return null; | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + public static String getString(String s) { | ||
| 199 | + return (getString(s, "")); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + /** | ||
| 203 | + * 转义成Unicode编码 | ||
| 204 | + * @param s | ||
| 205 | + * @return | ||
| 206 | + */ | ||
| 207 | + /*public static String escapeJava(Object s) { | ||
| 208 | + return StringEscapeUtils.escapeJava(getString(s)); | ||
| 209 | + }*/ | ||
| 210 | + | ||
| 211 | + public static String getString(Object object) { | ||
| 212 | + if (isEmpty(object)) { | ||
| 213 | + return ""; | ||
| 214 | + } | ||
| 215 | + return (object.toString().trim()); | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + public static String getString(int i) { | ||
| 219 | + return (String.valueOf(i)); | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + public static String getString(float i) { | ||
| 223 | + return (String.valueOf(i)); | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + public static String getString(String s, String defval) { | ||
| 227 | + if (isEmpty(s)) { | ||
| 228 | + return (defval); | ||
| 229 | + } | ||
| 230 | + return (s.trim()); | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + public static String getString(Object s, String defval) { | ||
| 234 | + if (isEmpty(s)) { | ||
| 235 | + return (defval); | ||
| 236 | + } | ||
| 237 | + return (s.toString().trim()); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + public static long stringToLong(String str) { | ||
| 241 | + Long test = new Long(0); | ||
| 242 | + try { | ||
| 243 | + test = Long.valueOf(str); | ||
| 244 | + } catch (Exception e) { | ||
| 245 | + } | ||
| 246 | + return test.longValue(); | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + /** | ||
| 250 | + * 获取本机IP | ||
| 251 | + */ | ||
| 252 | + public static String getIp() { | ||
| 253 | + String ip = null; | ||
| 254 | + try { | ||
| 255 | + InetAddress address = InetAddress.getLocalHost(); | ||
| 256 | + ip = address.getHostAddress(); | ||
| 257 | + | ||
| 258 | + } catch (UnknownHostException e) { | ||
| 259 | + e.printStackTrace(); | ||
| 260 | + } | ||
| 261 | + return ip; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + /** | ||
| 265 | + * 判断一个类是否为基本数据类型。 | ||
| 266 | + * | ||
| 267 | + * @param clazz | ||
| 268 | + * 要判断的类。 | ||
| 269 | + * @return true 表示为基本数据类型。 | ||
| 270 | + */ | ||
| 271 | + private static boolean isBaseDataType(Class clazz) throws Exception { | ||
| 272 | + return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class) || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class) || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz.isPrimitive()); | ||
| 273 | + } | ||
| 274 | + | ||
| 275 | + /** | ||
| 276 | + * @param request | ||
| 277 | + * IP | ||
| 278 | + * @return IP Address | ||
| 279 | + */ | ||
| 280 | + public static String getIpAddrByRequest(HttpServletRequest request) { | ||
| 281 | + String ip = request.getHeader("x-forwarded-for"); | ||
| 282 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | ||
| 283 | + ip = request.getHeader("Proxy-Client-IP"); | ||
| 284 | + } | ||
| 285 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | ||
| 286 | + ip = request.getHeader("WL-Proxy-Client-IP"); | ||
| 287 | + } | ||
| 288 | + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | ||
| 289 | + ip = request.getRemoteAddr(); | ||
| 290 | + } | ||
| 291 | + return ip; | ||
| 292 | + } | ||
| 293 | + | ||
| 294 | + /** | ||
| 295 | + * @return 本机IP | ||
| 296 | + * @throws SocketException | ||
| 297 | + */ | ||
| 298 | + public static String getRealIp() throws SocketException { | ||
| 299 | + String localip = null;// 本地IP,如果没有配置外网IP则返回它 | ||
| 300 | + String netip = null;// 外网IP | ||
| 301 | + | ||
| 302 | + Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces(); | ||
| 303 | + InetAddress ip = null; | ||
| 304 | + boolean finded = false;// 是否找到外网IP | ||
| 305 | + while (netInterfaces.hasMoreElements() && !finded) { | ||
| 306 | + NetworkInterface ni = netInterfaces.nextElement(); | ||
| 307 | + Enumeration<InetAddress> address = ni.getInetAddresses(); | ||
| 308 | + while (address.hasMoreElements()) { | ||
| 309 | + ip = address.nextElement(); | ||
| 310 | + if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 外网IP | ||
| 311 | + netip = ip.getHostAddress(); | ||
| 312 | + finded = true; | ||
| 313 | + break; | ||
| 314 | + } else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == -1) {// 内网IP | ||
| 315 | + localip = ip.getHostAddress(); | ||
| 316 | + } | ||
| 317 | + } | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + if (netip != null && !"".equals(netip)) { | ||
| 321 | + return netip; | ||
| 322 | + } else { | ||
| 323 | + return localip; | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + /** | ||
| 328 | + * java去除字符串中的空格、回车、换行符、制表符 | ||
| 329 | + * | ||
| 330 | + * @param str | ||
| 331 | + * @return | ||
| 332 | + */ | ||
| 333 | + public static String replaceBlank(String str) { | ||
| 334 | + String dest = ""; | ||
| 335 | + if (str != null) { | ||
| 336 | + Pattern p = Pattern.compile("\\s*|\t|\r|\n"); | ||
| 337 | + Matcher m = p.matcher(str); | ||
| 338 | + dest = m.replaceAll(""); | ||
| 339 | + } | ||
| 340 | + return dest; | ||
| 341 | + | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * 判断元素是否在数组内 | ||
| 346 | + * | ||
| 347 | + * @param substring | ||
| 348 | + * @param source | ||
| 349 | + * @return | ||
| 350 | + */ | ||
| 351 | + public static boolean isIn(String substring, String[] source) { | ||
| 352 | + if (source == null || source.length == 0) { | ||
| 353 | + return false; | ||
| 354 | + } | ||
| 355 | + for (int i = 0; i < source.length; i++) { | ||
| 356 | + String aSource = source[i]; | ||
| 357 | + if (aSource.equals(substring)) { | ||
| 358 | + return true; | ||
| 359 | + } | ||
| 360 | + } | ||
| 361 | + return false; | ||
| 362 | + } | ||
| 363 | + | ||
| 364 | + /** | ||
| 365 | + * 获取Map对象 | ||
| 366 | + */ | ||
| 367 | + public static Map<Object, Object> getHashMap() { | ||
| 368 | + return new HashMap<Object, Object>(); | ||
| 369 | + } | ||
| 370 | + | ||
| 371 | + /** | ||
| 372 | + * SET转换MAP | ||
| 373 | + * | ||
| 374 | + * @param str | ||
| 375 | + * @return | ||
| 376 | + */ | ||
| 377 | + public static Map<Object, Object> SetToMap(Set<Object> setobj) { | ||
| 378 | + Map<Object, Object> map = getHashMap(); | ||
| 379 | + for (Iterator iterator = setobj.iterator(); iterator.hasNext();) { | ||
| 380 | + Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) iterator.next(); | ||
| 381 | + map.put(entry.getKey().toString(), entry.getValue() == null ? "" : entry.getValue().toString().trim()); | ||
| 382 | + } | ||
| 383 | + return map; | ||
| 384 | + | ||
| 385 | + } | ||
| 386 | + | ||
| 387 | + public static boolean isInnerIP(String ipAddress) { | ||
| 388 | + boolean isInnerIp = false; | ||
| 389 | + long ipNum = getIpNum(ipAddress); | ||
| 390 | + /** | ||
| 391 | + * 私有IP:A类 10.0.0.0-10.255.255.255 B类 172.16.0.0-172.31.255.255 C类 192.168.0.0-192.168.255.255 当然,还有127这个网段是环回地址 | ||
| 392 | + **/ | ||
| 393 | + long aBegin = getIpNum("10.0.0.0"); | ||
| 394 | + long aEnd = getIpNum("10.255.255.255"); | ||
| 395 | + long bBegin = getIpNum("172.16.0.0"); | ||
| 396 | + long bEnd = getIpNum("172.31.255.255"); | ||
| 397 | + long cBegin = getIpNum("192.168.0.0"); | ||
| 398 | + long cEnd = getIpNum("192.168.255.255"); | ||
| 399 | + isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals("127.0.0.1"); | ||
| 400 | + return isInnerIp; | ||
| 401 | + } | ||
| 402 | + | ||
| 403 | + private static long getIpNum(String ipAddress) { | ||
| 404 | + String[] ip = ipAddress.split("\\."); | ||
| 405 | + long a = Integer.parseInt(ip[0]); | ||
| 406 | + long b = Integer.parseInt(ip[1]); | ||
| 407 | + long c = Integer.parseInt(ip[2]); | ||
| 408 | + long d = Integer.parseInt(ip[3]); | ||
| 409 | + | ||
| 410 | + long ipNum = a * 256 * 256 * 256 + b * 256 * 256 + c * 256 + d; | ||
| 411 | + return ipNum; | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + private static boolean isInner(long userIp, long begin, long end) { | ||
| 415 | + return (userIp >= begin) && (userIp <= end); | ||
| 416 | + } | ||
| 417 | + | ||
| 418 | + /** | ||
| 419 | + * 将下划线大写方式命名的字符串转换为驼峰式。 | ||
| 420 | + * 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> | ||
| 421 | + * 例如:hello_world->helloWorld | ||
| 422 | + * | ||
| 423 | + * @param name | ||
| 424 | + * 转换前的下划线大写方式命名的字符串 | ||
| 425 | + * @return 转换后的驼峰式命名的字符串 | ||
| 426 | + */ | ||
| 427 | + public static String camelName(String name) { | ||
| 428 | + StringBuilder result = new StringBuilder(); | ||
| 429 | + // 快速检查 | ||
| 430 | + if (name == null || name.isEmpty()) { | ||
| 431 | + // 没必要转换 | ||
| 432 | + return ""; | ||
| 433 | + } else if (!name.contains("_")) { | ||
| 434 | + // 不含下划线,仅将首字母小写 | ||
| 435 | + //update-begin--Author:zhoujf Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能 | ||
| 436 | + //update-begin--Author:zhoujf Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能 | ||
| 437 | + return name.substring(0, 1).toLowerCase() + name.substring(1).toLowerCase(); | ||
| 438 | + //update-end--Author:zhoujf Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能 | ||
| 439 | + } | ||
| 440 | + // 用下划线将原始字符串分割 | ||
| 441 | + String camels[] = name.split("_"); | ||
| 442 | + for (String camel : camels) { | ||
| 443 | + // 跳过原始字符串中开头、结尾的下换线或双重下划线 | ||
| 444 | + if (camel.isEmpty()) { | ||
| 445 | + continue; | ||
| 446 | + } | ||
| 447 | + // 处理真正的驼峰片段 | ||
| 448 | + if (result.length() == 0) { | ||
| 449 | + // 第一个驼峰片段,全部字母都小写 | ||
| 450 | + result.append(camel.toLowerCase()); | ||
| 451 | + } else { | ||
| 452 | + // 其他的驼峰片段,首字母大写 | ||
| 453 | + result.append(camel.substring(0, 1).toUpperCase()); | ||
| 454 | + result.append(camel.substring(1).toLowerCase()); | ||
| 455 | + } | ||
| 456 | + } | ||
| 457 | + return result.toString(); | ||
| 458 | + } | ||
| 459 | + | ||
| 460 | + /** | ||
| 461 | + * 将下划线大写方式命名的字符串转换为驼峰式。 | ||
| 462 | + * 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> | ||
| 463 | + * 例如:hello_world,test_id->helloWorld,testId | ||
| 464 | + * | ||
| 465 | + * @param name | ||
| 466 | + * 转换前的下划线大写方式命名的字符串 | ||
| 467 | + * @return 转换后的驼峰式命名的字符串 | ||
| 468 | + */ | ||
| 469 | + public static String camelNames(String names) { | ||
| 470 | + if(names==null||names.equals("")){ | ||
| 471 | + return null; | ||
| 472 | + } | ||
| 473 | + StringBuffer sf = new StringBuffer(); | ||
| 474 | + String[] fs = names.split(","); | ||
| 475 | + for (String field : fs) { | ||
| 476 | + field = camelName(field); | ||
| 477 | + sf.append(field + ","); | ||
| 478 | + } | ||
| 479 | + String result = sf.toString(); | ||
| 480 | + return result.substring(0, result.length() - 1); | ||
| 481 | + } | ||
| 482 | + | ||
| 483 | + //update-begin--Author:zhoujf Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能 | ||
| 484 | + /** | ||
| 485 | + * 将下划线大写方式命名的字符串转换为驼峰式。(首字母写) | ||
| 486 | + * 如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。</br> | ||
| 487 | + * 例如:hello_world->HelloWorld | ||
| 488 | + * | ||
| 489 | + * @param name | ||
| 490 | + * 转换前的下划线大写方式命名的字符串 | ||
| 491 | + * @return 转换后的驼峰式命名的字符串 | ||
| 492 | + */ | ||
| 493 | + public static String camelNameCapFirst(String name) { | ||
| 494 | + StringBuilder result = new StringBuilder(); | ||
| 495 | + // 快速检查 | ||
| 496 | + if (name == null || name.isEmpty()) { | ||
| 497 | + // 没必要转换 | ||
| 498 | + return ""; | ||
| 499 | + } else if (!name.contains("_")) { | ||
| 500 | + // 不含下划线,仅将首字母小写 | ||
| 501 | + return name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase(); | ||
| 502 | + } | ||
| 503 | + // 用下划线将原始字符串分割 | ||
| 504 | + String camels[] = name.split("_"); | ||
| 505 | + for (String camel : camels) { | ||
| 506 | + // 跳过原始字符串中开头、结尾的下换线或双重下划线 | ||
| 507 | + if (camel.isEmpty()) { | ||
| 508 | + continue; | ||
| 509 | + } | ||
| 510 | + // 其他的驼峰片段,首字母大写 | ||
| 511 | + result.append(camel.substring(0, 1).toUpperCase()); | ||
| 512 | + result.append(camel.substring(1).toLowerCase()); | ||
| 513 | + } | ||
| 514 | + return result.toString(); | ||
| 515 | + } | ||
| 516 | + //update-end--Author:zhoujf Date:20180503 for:TASK #2500 【代码生成器】代码生成器开发一通用模板生成功能 | ||
| 517 | + | ||
| 518 | + /** | ||
| 519 | + * 将驼峰命名转化成下划线 | ||
| 520 | + * @param para | ||
| 521 | + * @return | ||
| 522 | + */ | ||
| 523 | + public static String camelToUnderline(String para){ | ||
| 524 | + if(para.length()<3){ | ||
| 525 | + return para.toLowerCase(); | ||
| 526 | + } | ||
| 527 | + StringBuilder sb=new StringBuilder(para); | ||
| 528 | + int temp=0;//定位 | ||
| 529 | + //从第三个字符开始 避免命名不规范 | ||
| 530 | + for(int i=2;i<para.length();i++){ | ||
| 531 | + if(Character.isUpperCase(para.charAt(i))){ | ||
| 532 | + sb.insert(i+temp, "_"); | ||
| 533 | + temp+=1; | ||
| 534 | + } | ||
| 535 | + } | ||
| 536 | + return sb.toString().toLowerCase(); | ||
| 537 | + } | ||
| 538 | + | ||
| 539 | + /** | ||
| 540 | + * 随机数 | ||
| 541 | + * @param place 定义随机数的位数 | ||
| 542 | + */ | ||
| 543 | + public static String randomGen(int place) { | ||
| 544 | + String base = "qwertyuioplkjhgfdsazxcvbnmQAZWSXEDCRFVTGBYHNUJMIKLOP0123456789"; | ||
| 545 | + StringBuffer sb = new StringBuffer(); | ||
| 546 | + Random rd = new Random(); | ||
| 547 | + for(int i=0;i<place;i++) { | ||
| 548 | + sb.append(base.charAt(rd.nextInt(base.length()))); | ||
| 549 | + } | ||
| 550 | + return sb.toString(); | ||
| 551 | + } | ||
| 552 | + | ||
| 553 | + /** | ||
| 554 | + * 获取类的所有属性,包括父类 | ||
| 555 | + * | ||
| 556 | + * @param object | ||
| 557 | + * @return | ||
| 558 | + */ | ||
| 559 | + public static Field[] getAllFields(Object object) { | ||
| 560 | + Class<?> clazz = object.getClass(); | ||
| 561 | + List<Field> fieldList = new ArrayList<>(); | ||
| 562 | + while (clazz != null) { | ||
| 563 | + fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); | ||
| 564 | + clazz = clazz.getSuperclass(); | ||
| 565 | + } | ||
| 566 | + Field[] fields = new Field[fieldList.size()]; | ||
| 567 | + fieldList.toArray(fields); | ||
| 568 | + return fields; | ||
| 569 | + } | ||
| 570 | + | ||
| 571 | + /** | ||
| 572 | + * 将map的key全部转成小写 | ||
| 573 | + * @param list | ||
| 574 | + * @return | ||
| 575 | + */ | ||
| 576 | + public static List<Map<String, Object>> toLowerCasePageList(List<Map<String, Object>> list){ | ||
| 577 | + List<Map<String, Object>> select = new ArrayList<>(); | ||
| 578 | + for (Map<String, Object> row : list) { | ||
| 579 | + Map<String, Object> resultMap = new HashMap<>(); | ||
| 580 | + Set<String> keySet = row.keySet(); | ||
| 581 | + for (String key : keySet) { | ||
| 582 | + String newKey = key.toLowerCase(); | ||
| 583 | + resultMap.put(newKey, row.get(key)); | ||
| 584 | + } | ||
| 585 | + select.add(resultMap); | ||
| 586 | + } | ||
| 587 | + return select; | ||
| 588 | + } | ||
| 589 | + | ||
| 590 | + /** | ||
| 591 | + * 将entityList转换成modelList | ||
| 592 | + * @param fromList | ||
| 593 | + * @param tClass | ||
| 594 | + * @param <F> | ||
| 595 | + * @param <T> | ||
| 596 | + * @return | ||
| 597 | + */ | ||
| 598 | + public static<F,T> List<T> entityListToModelList(List<F> fromList, Class<T> tClass){ | ||
| 599 | + if(fromList == null || fromList.isEmpty()){ | ||
| 600 | + return null; | ||
| 601 | + } | ||
| 602 | + List<T> tList = new ArrayList<>(); | ||
| 603 | + for(F f : fromList){ | ||
| 604 | + T t = entityToModel(f, tClass); | ||
| 605 | + tList.add(t); | ||
| 606 | + } | ||
| 607 | + return tList; | ||
| 608 | + } | ||
| 609 | + | ||
| 610 | + public static<F,T> T entityToModel(F entity, Class<T> modelClass) { | ||
| 611 | + log.debug("entityToModel : Entity属性的值赋值到Model"); | ||
| 612 | + Object model = null; | ||
| 613 | + if (entity == null || modelClass ==null) { | ||
| 614 | + return null; | ||
| 615 | + } | ||
| 616 | + | ||
| 617 | + try { | ||
| 618 | + model = modelClass.newInstance(); | ||
| 619 | + } catch (InstantiationException e) { | ||
| 620 | + log.error("entityToModel : 实例化异常", e); | ||
| 621 | + } catch (IllegalAccessException e) { | ||
| 622 | + log.error("entityToModel : 安全权限异常", e); | ||
| 623 | + } | ||
| 624 | + BeanUtils.copyProperties(entity, model); | ||
| 625 | + return (T)model; | ||
| 626 | + } | ||
| 627 | + | ||
| 628 | + /** | ||
| 629 | + * 判断 list 是否为空 | ||
| 630 | + * | ||
| 631 | + * @param list | ||
| 632 | + * @return true or false | ||
| 633 | + * list == null : true | ||
| 634 | + * list.size() == 0 : true | ||
| 635 | + */ | ||
| 636 | + public static boolean listIsEmpty(Collection list) { | ||
| 637 | + return (list == null || list.size() == 0); | ||
| 638 | + } | ||
| 639 | + | ||
| 640 | + /** | ||
| 641 | + * 判断 list 是否不为空 | ||
| 642 | + * | ||
| 643 | + * @param list | ||
| 644 | + * @return true or false | ||
| 645 | + * list == null : false | ||
| 646 | + * list.size() == 0 : false | ||
| 647 | + */ | ||
| 648 | + public static boolean listIsNotEmpty(Collection list) { | ||
| 649 | + return !listIsEmpty(list); | ||
| 650 | + } | ||
| 651 | + | ||
| 652 | + /** | ||
| 653 | + * 读取静态文本内容 | ||
| 654 | + * @param url | ||
| 655 | + * @return | ||
| 656 | + */ | ||
| 657 | + public static String readStatic(String url) { | ||
| 658 | + String json = ""; | ||
| 659 | + try { | ||
| 660 | + //换个写法,解决springboot读取jar包中文件的问题 | ||
| 661 | + InputStream stream = oConvertUtils.class.getClassLoader().getResourceAsStream(url.replace("classpath:", "")); | ||
| 662 | + json = IOUtils.toString(stream,"UTF-8"); | ||
| 663 | + } catch (IOException e) { | ||
| 664 | + log.error(e.getMessage(),e); | ||
| 665 | + } | ||
| 666 | + return json; | ||
| 667 | + } | ||
| 668 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util.oss; | ||
| 2 | + | ||
| 3 | +import com.aliyun.oss.ClientConfiguration; | ||
| 4 | +import com.aliyun.oss.OSSClient; | ||
| 5 | +import com.aliyun.oss.common.auth.DefaultCredentialProvider; | ||
| 6 | +import com.aliyun.oss.model.CannedAccessControlList; | ||
| 7 | +import com.aliyun.oss.model.OSSObject; | ||
| 8 | +import com.aliyun.oss.model.PutObjectResult; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | +import org.apache.tomcat.util.http.fileupload.FileItemStream; | ||
| 11 | +import org.jeecg.common.util.CommonUtils; | ||
| 12 | +import org.jeecg.common.util.filter.StrAttackFilter; | ||
| 13 | +import org.jeecg.common.util.oConvertUtils; | ||
| 14 | +import org.springframework.web.multipart.MultipartFile; | ||
| 15 | + | ||
| 16 | +import java.io.BufferedInputStream; | ||
| 17 | +import java.io.IOException; | ||
| 18 | +import java.io.InputStream; | ||
| 19 | +import java.net.URL; | ||
| 20 | +import java.net.URLDecoder; | ||
| 21 | +import java.util.Date; | ||
| 22 | +import java.util.UUID; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * @Description: 阿里云 oss 上传工具类(高依赖版) | ||
| 26 | + * @Date: 2019/5/10 | ||
| 27 | + */ | ||
| 28 | +@Slf4j | ||
| 29 | +public class OssBootUtil { | ||
| 30 | + | ||
| 31 | + private static String endPoint; | ||
| 32 | + private static String accessKeyId; | ||
| 33 | + private static String accessKeySecret; | ||
| 34 | + private static String bucketName; | ||
| 35 | + private static String staticDomain; | ||
| 36 | + | ||
| 37 | + public static void setEndPoint(String endPoint) { | ||
| 38 | + OssBootUtil.endPoint = endPoint; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public static void setAccessKeyId(String accessKeyId) { | ||
| 42 | + OssBootUtil.accessKeyId = accessKeyId; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public static void setAccessKeySecret(String accessKeySecret) { | ||
| 46 | + OssBootUtil.accessKeySecret = accessKeySecret; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public static void setBucketName(String bucketName) { | ||
| 50 | + OssBootUtil.bucketName = bucketName; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public static void setStaticDomain(String staticDomain) { | ||
| 54 | + OssBootUtil.staticDomain = staticDomain; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static String getStaticDomain() { | ||
| 58 | + return staticDomain; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public static String getEndPoint() { | ||
| 62 | + return endPoint; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public static String getAccessKeyId() { | ||
| 66 | + return accessKeyId; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public static String getAccessKeySecret() { | ||
| 70 | + return accessKeySecret; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public static String getBucketName() { | ||
| 74 | + return bucketName; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public static OSSClient getOssClient() { | ||
| 78 | + return ossClient; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + /** | ||
| 82 | + * oss 工具客户端 | ||
| 83 | + */ | ||
| 84 | + private static OSSClient ossClient = null; | ||
| 85 | + | ||
| 86 | + /** | ||
| 87 | + * 上传文件至阿里云 OSS | ||
| 88 | + * 文件上传成功,返回文件完整访问路径 | ||
| 89 | + * 文件上传失败,返回 null | ||
| 90 | + * | ||
| 91 | + * @param file 待上传文件 | ||
| 92 | + * @param fileDir 文件保存目录 | ||
| 93 | + * @return oss 中的相对文件路径 | ||
| 94 | + */ | ||
| 95 | + public static String upload(MultipartFile file, String fileDir,String customBucket) { | ||
| 96 | + String FILE_URL = null; | ||
| 97 | + initOSS(endPoint, accessKeyId, accessKeySecret); | ||
| 98 | + StringBuilder fileUrl = new StringBuilder(); | ||
| 99 | + String newBucket = bucketName; | ||
| 100 | + if(oConvertUtils.isNotEmpty(customBucket)){ | ||
| 101 | + newBucket = customBucket; | ||
| 102 | + } | ||
| 103 | + try { | ||
| 104 | + //判断桶是否存在,不存在则创建桶 | ||
| 105 | + if(!ossClient.doesBucketExist(newBucket)){ | ||
| 106 | + ossClient.createBucket(newBucket); | ||
| 107 | + } | ||
| 108 | + // 获取文件名 | ||
| 109 | + String orgName = file.getOriginalFilename(); | ||
| 110 | + if("" == orgName){ | ||
| 111 | + orgName=file.getName(); | ||
| 112 | + } | ||
| 113 | + orgName = CommonUtils.getFileName(orgName); | ||
| 114 | + String fileName = orgName.indexOf(".")==-1 | ||
| 115 | + ?orgName + "_" + System.currentTimeMillis() | ||
| 116 | + :orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf(".")); | ||
| 117 | + if (!fileDir.endsWith("/")) { | ||
| 118 | + fileDir = fileDir.concat("/"); | ||
| 119 | + } | ||
| 120 | + //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击 | ||
| 121 | + fileDir=StrAttackFilter.filter(fileDir); | ||
| 122 | + //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击 | ||
| 123 | + fileUrl = fileUrl.append(fileDir + fileName); | ||
| 124 | + | ||
| 125 | + if (oConvertUtils.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith("http")) { | ||
| 126 | + FILE_URL = staticDomain + "/" + fileUrl; | ||
| 127 | + } else { | ||
| 128 | + FILE_URL = "https://" + newBucket + "." + endPoint + "/" + fileUrl; | ||
| 129 | + } | ||
| 130 | + PutObjectResult result = ossClient.putObject(newBucket, fileUrl.toString(), file.getInputStream()); | ||
| 131 | + // 设置权限(公开读) | ||
| 132 | +// ossClient.setBucketAcl(newBucket, CannedAccessControlList.PublicRead); | ||
| 133 | + if (result != null) { | ||
| 134 | + log.info("------OSS文件上传成功------" + fileUrl); | ||
| 135 | + } | ||
| 136 | + } catch (IOException e) { | ||
| 137 | + e.printStackTrace(); | ||
| 138 | + return null; | ||
| 139 | + } | ||
| 140 | + return FILE_URL; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + /** | ||
| 144 | + * 获取原始URL | ||
| 145 | + * @param url: 原始URL | ||
| 146 | + * @Return: java.lang.String | ||
| 147 | + */ | ||
| 148 | + public static String getOriginalUrl(String url) { | ||
| 149 | + String originalDomain = "https://" + bucketName + "." + endPoint; | ||
| 150 | + if(url.indexOf(staticDomain)!=-1){ | ||
| 151 | + url = url.replace(staticDomain,originalDomain); | ||
| 152 | + } | ||
| 153 | + return url; | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + /** | ||
| 157 | + * 文件上传 | ||
| 158 | + * @param file | ||
| 159 | + * @param fileDir | ||
| 160 | + * @return | ||
| 161 | + */ | ||
| 162 | + public static String upload(MultipartFile file, String fileDir) { | ||
| 163 | + return upload(file, fileDir,null); | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + /** | ||
| 167 | + * 上传文件至阿里云 OSS | ||
| 168 | + * 文件上传成功,返回文件完整访问路径 | ||
| 169 | + * 文件上传失败,返回 null | ||
| 170 | + * | ||
| 171 | + * @param file 待上传文件 | ||
| 172 | + * @param fileDir 文件保存目录 | ||
| 173 | + * @return oss 中的相对文件路径 | ||
| 174 | + */ | ||
| 175 | + public static String upload(FileItemStream file, String fileDir) { | ||
| 176 | + String FILE_URL = null; | ||
| 177 | + initOSS(endPoint, accessKeyId, accessKeySecret); | ||
| 178 | + StringBuilder fileUrl = new StringBuilder(); | ||
| 179 | + try { | ||
| 180 | + String suffix = file.getName().substring(file.getName().lastIndexOf('.')); | ||
| 181 | + String fileName = UUID.randomUUID().toString().replace("-", "") + suffix; | ||
| 182 | + if (!fileDir.endsWith("/")) { | ||
| 183 | + fileDir = fileDir.concat("/"); | ||
| 184 | + } | ||
| 185 | + fileDir = StrAttackFilter.filter(fileDir); | ||
| 186 | + fileUrl = fileUrl.append(fileDir + fileName); | ||
| 187 | + if (oConvertUtils.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith("http")) { | ||
| 188 | + FILE_URL = staticDomain + "/" + fileUrl; | ||
| 189 | + } else { | ||
| 190 | + FILE_URL = "https://" + bucketName + "." + endPoint + "/" + fileUrl; | ||
| 191 | + } | ||
| 192 | + PutObjectResult result = ossClient.putObject(bucketName, fileUrl.toString(), file.openStream()); | ||
| 193 | + // 设置权限(公开读) | ||
| 194 | + ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead); | ||
| 195 | + if (result != null) { | ||
| 196 | + log.info("------OSS文件上传成功------" + fileUrl); | ||
| 197 | + } | ||
| 198 | + } catch (IOException e) { | ||
| 199 | + e.printStackTrace(); | ||
| 200 | + return null; | ||
| 201 | + } | ||
| 202 | + return FILE_URL; | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + /** | ||
| 206 | + * 删除文件 | ||
| 207 | + * @param url | ||
| 208 | + */ | ||
| 209 | + public static void deleteUrl(String url) { | ||
| 210 | + deleteUrl(url,null); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + /** | ||
| 214 | + * 删除文件 | ||
| 215 | + * @param url | ||
| 216 | + */ | ||
| 217 | + public static void deleteUrl(String url,String bucket) { | ||
| 218 | + String newBucket = bucketName; | ||
| 219 | + if(oConvertUtils.isNotEmpty(bucket)){ | ||
| 220 | + newBucket = bucket; | ||
| 221 | + } | ||
| 222 | + String bucketUrl = ""; | ||
| 223 | + if (oConvertUtils.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith("http")) { | ||
| 224 | + bucketUrl = staticDomain + "/" ; | ||
| 225 | + } else { | ||
| 226 | + bucketUrl = "https://" + newBucket + "." + endPoint + "/"; | ||
| 227 | + } | ||
| 228 | + url = url.replace(bucketUrl,""); | ||
| 229 | + ossClient.deleteObject(newBucket, url); | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | + /** | ||
| 233 | + * 删除文件 | ||
| 234 | + * @param fileName | ||
| 235 | + */ | ||
| 236 | + public static void delete(String fileName) { | ||
| 237 | + ossClient.deleteObject(bucketName, fileName); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + /** | ||
| 241 | + * 获取文件流 | ||
| 242 | + * @param objectName | ||
| 243 | + * @param bucket | ||
| 244 | + * @return | ||
| 245 | + */ | ||
| 246 | + public static InputStream getOssFile(String objectName,String bucket){ | ||
| 247 | + InputStream inputStream = null; | ||
| 248 | + try{ | ||
| 249 | + String newBucket = bucketName; | ||
| 250 | + if(oConvertUtils.isNotEmpty(bucket)){ | ||
| 251 | + newBucket = bucket; | ||
| 252 | + } | ||
| 253 | + initOSS(endPoint, accessKeyId, accessKeySecret); | ||
| 254 | + OSSObject ossObject = ossClient.getObject(newBucket,objectName); | ||
| 255 | + inputStream = new BufferedInputStream(ossObject.getObjectContent()); | ||
| 256 | + }catch (Exception e){ | ||
| 257 | + log.info("文件获取失败" + e.getMessage()); | ||
| 258 | + } | ||
| 259 | + return inputStream; | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + /** | ||
| 263 | + * 获取文件流 | ||
| 264 | + * @param objectName | ||
| 265 | + * @return | ||
| 266 | + */ | ||
| 267 | + public static InputStream getOssFile(String objectName){ | ||
| 268 | + return getOssFile(objectName,null); | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + /** | ||
| 272 | + * 获取文件外链 | ||
| 273 | + * @param bucketName | ||
| 274 | + * @param objectName | ||
| 275 | + * @param expires | ||
| 276 | + * @return | ||
| 277 | + */ | ||
| 278 | + public static String getObjectURL(String bucketName, String objectName, Date expires) { | ||
| 279 | + initOSS(endPoint, accessKeyId, accessKeySecret); | ||
| 280 | + try{ | ||
| 281 | + if(ossClient.doesObjectExist(bucketName,objectName)){ | ||
| 282 | + URL url = ossClient.generatePresignedUrl(bucketName,objectName,expires); | ||
| 283 | + return URLDecoder.decode(url.toString(),"UTF-8"); | ||
| 284 | + } | ||
| 285 | + }catch (Exception e){ | ||
| 286 | + log.info("文件路径获取失败" + e.getMessage()); | ||
| 287 | + } | ||
| 288 | + return null; | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + /** | ||
| 292 | + * 初始化 oss 客户端 | ||
| 293 | + * | ||
| 294 | + * @return | ||
| 295 | + */ | ||
| 296 | + private static OSSClient initOSS(String endpoint, String accessKeyId, String accessKeySecret) { | ||
| 297 | + if (ossClient == null) { | ||
| 298 | + ossClient = new OSSClient(endpoint, | ||
| 299 | + new DefaultCredentialProvider(accessKeyId, accessKeySecret), | ||
| 300 | + new ClientConfiguration()); | ||
| 301 | + } | ||
| 302 | + return ossClient; | ||
| 303 | + } | ||
| 304 | + | ||
| 305 | + | ||
| 306 | + /** | ||
| 307 | + * 上传文件到oss | ||
| 308 | + * @param stream | ||
| 309 | + * @param relativePath | ||
| 310 | + * @return | ||
| 311 | + */ | ||
| 312 | + public static String upload(InputStream stream, String relativePath) { | ||
| 313 | + String FILE_URL = null; | ||
| 314 | + String fileUrl = relativePath; | ||
| 315 | + initOSS(endPoint, accessKeyId, accessKeySecret); | ||
| 316 | + if (oConvertUtils.isNotEmpty(staticDomain) && staticDomain.toLowerCase().startsWith("http")) { | ||
| 317 | + FILE_URL = staticDomain + "/" + relativePath; | ||
| 318 | + } else { | ||
| 319 | + FILE_URL = "https://" + bucketName + "." + endPoint + "/" + fileUrl; | ||
| 320 | + } | ||
| 321 | + PutObjectResult result = ossClient.putObject(bucketName, fileUrl.toString(),stream); | ||
| 322 | + // 设置权限(公开读) | ||
| 323 | + ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead); | ||
| 324 | + if (result != null) { | ||
| 325 | + log.info("------OSS文件上传成功------" + fileUrl); | ||
| 326 | + } | ||
| 327 | + return FILE_URL; | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + | ||
| 331 | +} | ||
| 0 | \ No newline at end of file | 332 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/SecurityTools.java
0 → 100644
| 1 | +package org.jeecg.common.util.security; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.codec.Base64Decoder; | ||
| 4 | +import cn.hutool.core.codec.Base64Encoder; | ||
| 5 | +import cn.hutool.crypto.SecureUtil; | ||
| 6 | +import cn.hutool.crypto.asymmetric.KeyType; | ||
| 7 | +import cn.hutool.crypto.asymmetric.RSA; | ||
| 8 | +import cn.hutool.crypto.asymmetric.Sign; | ||
| 9 | +import cn.hutool.crypto.asymmetric.SignAlgorithm; | ||
| 10 | +import cn.hutool.crypto.symmetric.AES; | ||
| 11 | +import cn.hutool.json.JSONObject; | ||
| 12 | +import org.jeecg.common.util.security.entity.*; | ||
| 13 | + | ||
| 14 | +import javax.crypto.SecretKey; | ||
| 15 | +import java.security.KeyPair; | ||
| 16 | + | ||
| 17 | +public class SecurityTools { | ||
| 18 | + public static final String ALGORITHM = "AES/ECB/PKCS5Padding"; | ||
| 19 | + | ||
| 20 | + public static SecurityResp valid(SecurityReq req) { | ||
| 21 | + SecurityResp resp=new SecurityResp(); | ||
| 22 | + String pubKey=req.getPubKey(); | ||
| 23 | + String aesKey=req.getAesKey(); | ||
| 24 | + String data=req.getData(); | ||
| 25 | + String signData=req.getSignData(); | ||
| 26 | + RSA rsa=new RSA(null, Base64Decoder.decode(pubKey)); | ||
| 27 | + Sign sign= new Sign(SignAlgorithm.SHA1withRSA,null,pubKey); | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + byte[] decryptAes = rsa.decrypt(aesKey, KeyType.PublicKey); | ||
| 32 | + //log.info("rsa解密后的秘钥"+ Base64Encoder.encode(decryptAes)); | ||
| 33 | + AES aes = SecureUtil.aes(decryptAes); | ||
| 34 | + | ||
| 35 | + String dencrptValue =aes.decryptStr(data); | ||
| 36 | + //log.info("解密后报文"+dencrptValue); | ||
| 37 | + resp.setData(new JSONObject(dencrptValue)); | ||
| 38 | + | ||
| 39 | + boolean verify = sign.verify(dencrptValue.getBytes(), Base64Decoder.decode(signData)); | ||
| 40 | + resp.setSuccess(verify); | ||
| 41 | + return resp; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public static SecuritySignResp sign(SecuritySignReq req) { | ||
| 45 | + SecretKey secretKey = SecureUtil.generateKey(ALGORITHM); | ||
| 46 | + byte[] key= secretKey.getEncoded(); | ||
| 47 | + String prikey=req.getPrikey(); | ||
| 48 | + String data=req.getData(); | ||
| 49 | + | ||
| 50 | + AES aes = SecureUtil.aes(key); | ||
| 51 | + aes.getSecretKey().getEncoded(); | ||
| 52 | + String encrptData =aes.encryptBase64(data); | ||
| 53 | + RSA rsa=new RSA(prikey,null); | ||
| 54 | + byte[] encryptAesKey = rsa.encrypt(secretKey.getEncoded(), KeyType.PrivateKey); | ||
| 55 | + //log.info(("rsa加密过的秘钥=="+Base64Encoder.encode(encryptAesKey)); | ||
| 56 | + | ||
| 57 | + Sign sign= new Sign(SignAlgorithm.SHA1withRSA,prikey,null); | ||
| 58 | + byte[] signed = sign.sign(data.getBytes()); | ||
| 59 | + | ||
| 60 | + //log.info(("签名数据===》》"+Base64Encoder.encode(signed)); | ||
| 61 | + | ||
| 62 | + SecuritySignResp resp=new SecuritySignResp(); | ||
| 63 | + resp.setAesKey(Base64Encoder.encode(encryptAesKey)); | ||
| 64 | + resp.setData(encrptData); | ||
| 65 | + resp.setSignData(Base64Encoder.encode(signed)); | ||
| 66 | + return resp; | ||
| 67 | + } | ||
| 68 | + public static MyKeyPair generateKeyPair(){ | ||
| 69 | + KeyPair keyPair= SecureUtil.generateKeyPair(SignAlgorithm.SHA1withRSA.getValue(),2048); | ||
| 70 | + String priKey= Base64Encoder.encode(keyPair.getPrivate().getEncoded()); | ||
| 71 | + String pubkey= Base64Encoder.encode(keyPair.getPublic().getEncoded()); | ||
| 72 | + MyKeyPair resp=new MyKeyPair(); | ||
| 73 | + resp.setPriKey(priKey); | ||
| 74 | + resp.setPubKey(pubkey); | ||
| 75 | + return resp; | ||
| 76 | + } | ||
| 77 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/MyKeyPair.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityReq.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecurityResp.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecuritySignReq.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/security/entity/SecuritySignResp.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/superSearch/ObjectParseUtil.java
0 → 100644
| 1 | +package org.jeecg.common.util.superSearch; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 判断类型,追加查询规则 | ||
| 7 | + * | ||
| 8 | + * @Author Scott | ||
| 9 | + * @Date 2019年02月14日 | ||
| 10 | + */ | ||
| 11 | +public class ObjectParseUtil { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * | ||
| 15 | + * @param queryWrapper QueryWrapper | ||
| 16 | + * @param name 字段名字 | ||
| 17 | + * @param rule 查询规则 | ||
| 18 | + * @param value 查询条件值 | ||
| 19 | + */ | ||
| 20 | + public static void addCriteria(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) { | ||
| 21 | + if (value == null || rule == null) { | ||
| 22 | + return; | ||
| 23 | + } | ||
| 24 | + switch (rule) { | ||
| 25 | + case GT: | ||
| 26 | + queryWrapper.gt(name, value); | ||
| 27 | + break; | ||
| 28 | + case GE: | ||
| 29 | + queryWrapper.ge(name, value); | ||
| 30 | + break; | ||
| 31 | + case LT: | ||
| 32 | + queryWrapper.lt(name, value); | ||
| 33 | + break; | ||
| 34 | + case LE: | ||
| 35 | + queryWrapper.le(name, value); | ||
| 36 | + break; | ||
| 37 | + case EQ: | ||
| 38 | + queryWrapper.eq(name, value); | ||
| 39 | + break; | ||
| 40 | + case NE: | ||
| 41 | + queryWrapper.ne(name, value); | ||
| 42 | + break; | ||
| 43 | + case IN: | ||
| 44 | + queryWrapper.in(name, (Object[]) value); | ||
| 45 | + break; | ||
| 46 | + case LIKE: | ||
| 47 | + queryWrapper.like(name, value); | ||
| 48 | + break; | ||
| 49 | + case LEFT_LIKE: | ||
| 50 | + queryWrapper.likeLeft(name, value); | ||
| 51 | + break; | ||
| 52 | + case RIGHT_LIKE: | ||
| 53 | + queryWrapper.likeRight(name, value); | ||
| 54 | + break; | ||
| 55 | + default: | ||
| 56 | + break; | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/superSearch/QueryRuleEnum.java
0 → 100644
| 1 | +package org.jeecg.common.util.superSearch; | ||
| 2 | + | ||
| 3 | +import org.jeecg.common.util.oConvertUtils; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * Query 规则 常量 | ||
| 7 | + * @Author Scott | ||
| 8 | + * @Date 2019年02月14日 | ||
| 9 | + */ | ||
| 10 | +public enum QueryRuleEnum { | ||
| 11 | + | ||
| 12 | + GT(">","大于"), | ||
| 13 | + GE(">=","大于等于"), | ||
| 14 | + LT("<","小于"), | ||
| 15 | + LE("<=","小于等于"), | ||
| 16 | + EQ("=","等于"), | ||
| 17 | + NE("!=","不等于"), | ||
| 18 | + IN("IN","包含"), | ||
| 19 | + LIKE("LIKE","全模糊"), | ||
| 20 | + LEFT_LIKE("LEFT_LIKE","左模糊"), | ||
| 21 | + RIGHT_LIKE("RIGHT_LIKE","右模糊"), | ||
| 22 | + SQL_RULES("EXTEND_SQL","自定义SQL片段"); | ||
| 23 | + | ||
| 24 | + private String value; | ||
| 25 | + | ||
| 26 | + private String msg; | ||
| 27 | + | ||
| 28 | + QueryRuleEnum(String value, String msg){ | ||
| 29 | + this.value = value; | ||
| 30 | + this.msg = msg; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public String getValue() { | ||
| 34 | + return value; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setValue(String value) { | ||
| 38 | + this.value = value; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public String getMsg() { | ||
| 42 | + return msg; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void setMsg(String msg) { | ||
| 46 | + this.msg = msg; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public static QueryRuleEnum getByValue(String value){ | ||
| 50 | + if(oConvertUtils.isEmpty(value)) { | ||
| 51 | + return null; | ||
| 52 | + } | ||
| 53 | + for(QueryRuleEnum val :values()){ | ||
| 54 | + if (val.getValue().equals(value)){ | ||
| 55 | + return val; | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + return null; | ||
| 59 | + } | ||
| 60 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/superSearch/QueryRuleVo.java
0 → 100644
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import org.jeecgframework.core.util.ApplicationContextUtil; | ||
| 4 | +import org.springframework.context.annotation.Bean; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * @Author: Scott | ||
| 9 | + * @Date: 2018/2/7 | ||
| 10 | + * @description: autopoi 配置类 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +@Configuration | ||
| 14 | +public class AutoPoiConfig { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * excel注解字典参数支持(导入导出字典值,自动翻译) | ||
| 18 | + * 举例: @Excel(name = "性别", width = 15, dicCode = "sex") | ||
| 19 | + * 1、导出的时候会根据字典配置,把值1,2翻译成:男、女; | ||
| 20 | + * 2、导入的时候,会把男、女翻译成1,2存进数据库; | ||
| 21 | + * @return | ||
| 22 | + */ | ||
| 23 | + @Bean | ||
| 24 | + public ApplicationContextUtil applicationContextUtil() { | ||
| 25 | + return new org.jeecgframework.core.util.ApplicationContextUtil(); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.jeecg.common.api.CommonAPI; | ||
| 5 | +import org.jeecg.common.system.vo.DictModel; | ||
| 6 | +import org.jeecg.common.util.oConvertUtils; | ||
| 7 | +import org.jeecgframework.dict.service.AutoPoiDictServiceI; | ||
| 8 | +import org.springframework.context.annotation.Lazy; | ||
| 9 | +import org.springframework.stereotype.Service; | ||
| 10 | + | ||
| 11 | +import javax.annotation.Resource; | ||
| 12 | +import java.util.ArrayList; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +/** | ||
| 16 | + * 描述:AutoPoi Excel注解支持字典参数设置 | ||
| 17 | + * 举例: @Excel(name = "性别", width = 15, dicCode = "sex") | ||
| 18 | + * 1、导出的时候会根据字典配置,把值1,2翻译成:男、女; | ||
| 19 | + * 2、导入的时候,会把男、女翻译成1,2存进数据库; | ||
| 20 | + * | ||
| 21 | + * @Author:scott | ||
| 22 | + * @since:2019-04-09 | ||
| 23 | + * @Version:1.0 | ||
| 24 | + */ | ||
| 25 | +@Slf4j | ||
| 26 | +@Service | ||
| 27 | +public class AutoPoiDictConfig implements AutoPoiDictServiceI { | ||
| 28 | + @Lazy | ||
| 29 | + @Resource | ||
| 30 | + private CommonAPI commonAPI; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 通过字典查询easypoi,所需字典文本 | ||
| 34 | + * | ||
| 35 | + * @Author:scott | ||
| 36 | + * @since:2019-04-09 | ||
| 37 | + * @return | ||
| 38 | + */ | ||
| 39 | + @Override | ||
| 40 | + public String[] queryDict(String dicTable, String dicCode, String dicText) { | ||
| 41 | + List<String> dictReplaces = new ArrayList<String>(); | ||
| 42 | + List<DictModel> dictList = null; | ||
| 43 | + // step.1 如果没有字典表则使用系统字典表 | ||
| 44 | + if (oConvertUtils.isEmpty(dicTable)) { | ||
| 45 | + dictList = commonAPI.queryDictItemsByCode(dicCode); | ||
| 46 | + } else { | ||
| 47 | + try { | ||
| 48 | + dicText = oConvertUtils.getString(dicText, dicCode); | ||
| 49 | + dictList = commonAPI.queryTableDictItemsByCode(dicTable, dicText, dicCode); | ||
| 50 | + } catch (Exception e) { | ||
| 51 | + log.error(e.getMessage(),e); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + for (DictModel t : dictList) { | ||
| 55 | + if(t!=null){ | ||
| 56 | + dictReplaces.add(t.getText() + "_" + t.getValue()); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + if (dictReplaces != null && dictReplaces.size() != 0) { | ||
| 60 | + log.info("---AutoPoi--Get_DB_Dict------"+ dictReplaces.toString()); | ||
| 61 | + return dictReplaces.toArray(new String[dictReplaces.size()]); | ||
| 62 | + } | ||
| 63 | + return null; | ||
| 64 | + } | ||
| 65 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/CorsFilterCondition.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import org.jeecg.common.constant.CommonConstant; | ||
| 4 | +import org.springframework.context.annotation.Condition; | ||
| 5 | +import org.springframework.context.annotation.ConditionContext; | ||
| 6 | +import org.springframework.core.type.AnnotatedTypeMetadata; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 跨域配置加载条件 | ||
| 10 | + */ | ||
| 11 | +public class CorsFilterCondition implements Condition { | ||
| 12 | + | ||
| 13 | + @Override | ||
| 14 | + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { | ||
| 15 | + Object object = context.getEnvironment().getProperty(CommonConstant.CLOUD_SERVER_KEY); | ||
| 16 | + //如果没有服务注册发现的配置 说明是单体应用 则加载跨域配置 返回true | ||
| 17 | + if(object==null){ | ||
| 18 | + return true; | ||
| 19 | + } | ||
| 20 | + return false; | ||
| 21 | + } | ||
| 22 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/DruidConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure; | ||
| 4 | +import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; | ||
| 5 | +import com.alibaba.druid.util.Utils; | ||
| 6 | +import org.springframework.boot.autoconfigure.AutoConfigureAfter; | ||
| 7 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
| 8 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; | ||
| 9 | +import org.springframework.boot.web.servlet.FilterRegistrationBean; | ||
| 10 | +import org.springframework.context.annotation.Bean; | ||
| 11 | +import org.springframework.context.annotation.Configuration; | ||
| 12 | + | ||
| 13 | +import javax.servlet.*; | ||
| 14 | +import java.io.IOException; | ||
| 15 | + | ||
| 16 | +@Configuration | ||
| 17 | +@AutoConfigureAfter(DruidDataSourceAutoConfigure.class) | ||
| 18 | +public class DruidConfig { | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 带有广告的common.js全路径,druid-1.1.14 | ||
| 22 | + */ | ||
| 23 | + private static final String FILE_PATH = "support/http/resources/js/common.js"; | ||
| 24 | + /** | ||
| 25 | + * 原始脚本,触发构建广告的语句 | ||
| 26 | + */ | ||
| 27 | + private static final String ORIGIN_JS = "this.buildFooter();"; | ||
| 28 | + /** | ||
| 29 | + * 替换后的脚本 | ||
| 30 | + */ | ||
| 31 | + private static final String NEW_JS = "//this.buildFooter();"; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 去除Druid监控页面的广告 | ||
| 35 | + * | ||
| 36 | + * @param properties DruidStatProperties属性集合 | ||
| 37 | + * @return {@link org.springframework.boot.web.servlet.FilterRegistrationBean} | ||
| 38 | + */ | ||
| 39 | + @Bean | ||
| 40 | + @ConditionalOnWebApplication | ||
| 41 | + @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true") | ||
| 42 | + public FilterRegistrationBean<RemoveAdFilter> removeDruidAdFilter( | ||
| 43 | + DruidStatProperties properties) throws IOException { | ||
| 44 | + // 获取web监控页面的参数 | ||
| 45 | + DruidStatProperties.StatViewServlet config = properties.getStatViewServlet(); | ||
| 46 | + // 提取common.js的配置路径 | ||
| 47 | + String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*"; | ||
| 48 | + String commonJsPattern = pattern.replaceAll("\\*", "js/common.js"); | ||
| 49 | + // 获取common.js | ||
| 50 | + String text = Utils.readFromResource(FILE_PATH); | ||
| 51 | + // 屏蔽 this.buildFooter(); 不构建广告 | ||
| 52 | + final String newJs = text.replace(ORIGIN_JS, NEW_JS); | ||
| 53 | + FilterRegistrationBean<RemoveAdFilter> registration = new FilterRegistrationBean<>(); | ||
| 54 | + registration.setFilter(new RemoveAdFilter(newJs)); | ||
| 55 | + registration.addUrlPatterns(commonJsPattern); | ||
| 56 | + return registration; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * 删除druid的广告过滤器 | ||
| 61 | + * | ||
| 62 | + * @author BBF | ||
| 63 | + */ | ||
| 64 | + private class RemoveAdFilter implements Filter { | ||
| 65 | + | ||
| 66 | + private final String newJs; | ||
| 67 | + | ||
| 68 | + public RemoveAdFilter(String newJS) { | ||
| 69 | + this.newJs = newJS; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | ||
| 74 | + throws IOException, ServletException { | ||
| 75 | + chain.doFilter(request, response); | ||
| 76 | + // 重置缓冲区,响应头不会被重置 | ||
| 77 | + response.resetBuffer(); | ||
| 78 | + response.getWriter().write(newJs); | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeecgCloudCondition.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import org.jeecg.common.constant.CommonConstant; | ||
| 4 | +import org.springframework.context.annotation.Condition; | ||
| 5 | +import org.springframework.context.annotation.ConditionContext; | ||
| 6 | +import org.springframework.core.type.AnnotatedTypeMetadata; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 微服务环境加载条件 | ||
| 10 | + */ | ||
| 11 | +public class JeecgCloudCondition implements Condition { | ||
| 12 | + | ||
| 13 | + @Override | ||
| 14 | + public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { | ||
| 15 | + Object object = context.getEnvironment().getProperty(CommonConstant.CLOUD_SERVER_KEY); | ||
| 16 | + //如果没有服务注册发现的配置 说明是单体应用 | ||
| 17 | + if(object==null){ | ||
| 18 | + return false; | ||
| 19 | + } | ||
| 20 | + return true; | ||
| 21 | + } | ||
| 22 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/RestTemplateConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import org.springframework.context.annotation.Bean; | ||
| 4 | +import org.springframework.context.annotation.Configuration; | ||
| 5 | +import org.springframework.http.client.ClientHttpRequestFactory; | ||
| 6 | +import org.springframework.http.client.SimpleClientHttpRequestFactory; | ||
| 7 | +import org.springframework.web.client.RestTemplate; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | +* 优雅的http请求方式RestTemplate | ||
| 11 | +* @Return: | ||
| 12 | +*/ | ||
| 13 | +@Configuration | ||
| 14 | +public class RestTemplateConfig { | ||
| 15 | + | ||
| 16 | + @Bean | ||
| 17 | + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { | ||
| 18 | + return new RestTemplate(factory); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + @Bean | ||
| 22 | + public ClientHttpRequestFactory simpleClientHttpRequestFactory() { | ||
| 23 | + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); | ||
| 24 | + factory.setReadTimeout(5000);//ms | ||
| 25 | + factory.setConnectTimeout(15000);//ms | ||
| 26 | + return factory; | ||
| 27 | + } | ||
| 28 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 设置静态参数初始化 | ||
| 9 | + */ | ||
| 10 | +@Component | ||
| 11 | +@Data | ||
| 12 | +public class StaticConfig { | ||
| 13 | + | ||
| 14 | + @Value("${jeecg.oss.accessKey}") | ||
| 15 | + private String accessKeyId; | ||
| 16 | + | ||
| 17 | + @Value("${jeecg.oss.secretKey}") | ||
| 18 | + private String accessKeySecret; | ||
| 19 | + | ||
| 20 | + @Value(value = "${spring.mail.username}") | ||
| 21 | + private String emailFrom; | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + /*@Bean | ||
| 25 | + public void initStatic() { | ||
| 26 | + DySmsHelper.setAccessKeyId(accessKeyId); | ||
| 27 | + DySmsHelper.setAccessKeySecret(accessKeySecret); | ||
| 28 | + EmailSendMsgHandle.setEmailFrom(emailFrom); | ||
| 29 | + }*/ | ||
| 30 | + | ||
| 31 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger2Config.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; | ||
| 5 | +import io.swagger.annotations.ApiOperation; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.jeecg.common.constant.CommonConstant; | ||
| 8 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||
| 9 | +import org.springframework.context.annotation.Bean; | ||
| 10 | +import org.springframework.context.annotation.Configuration; | ||
| 11 | + | ||
| 12 | +import org.springframework.context.annotation.Import; | ||
| 13 | +import org.springframework.web.bind.annotation.RestController; | ||
| 14 | +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||
| 15 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| 16 | +import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; | ||
| 17 | +import springfox.documentation.builders.ApiInfoBuilder; | ||
| 18 | +import springfox.documentation.builders.ParameterBuilder; | ||
| 19 | +import springfox.documentation.builders.PathSelectors; | ||
| 20 | +import springfox.documentation.builders.RequestHandlerSelectors; | ||
| 21 | +import springfox.documentation.schema.ModelRef; | ||
| 22 | +import springfox.documentation.service.*; | ||
| 23 | +import springfox.documentation.spi.DocumentationType; | ||
| 24 | +import springfox.documentation.spi.service.contexts.SecurityContext; | ||
| 25 | +import springfox.documentation.spring.web.plugins.Docket; | ||
| 26 | +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; | ||
| 27 | + | ||
| 28 | +import java.util.ArrayList; | ||
| 29 | +import java.util.Collections; | ||
| 30 | +import java.util.List; | ||
| 31 | + | ||
| 32 | +/** | ||
| 33 | + * @Author scott | ||
| 34 | + */ | ||
| 35 | +@Configuration | ||
| 36 | +@EnableSwagger2WebMvc | ||
| 37 | +@EnableKnife4j | ||
| 38 | +@Import(BeanValidatorPluginsConfiguration.class) | ||
| 39 | +public class Swagger2Config implements WebMvcConfigurer { | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * | ||
| 43 | + * 显示swagger-ui.html文档展示页,还必须注入swagger资源: | ||
| 44 | + * | ||
| 45 | + * @param registry | ||
| 46 | + */ | ||
| 47 | + @Override | ||
| 48 | + public void addResourceHandlers(ResourceHandlerRegistry registry) { | ||
| 49 | + registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); | ||
| 50 | + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); | ||
| 51 | + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等 | ||
| 56 | + * | ||
| 57 | + * @return Docket | ||
| 58 | + */ | ||
| 59 | + @Bean(value = "defaultApi2") | ||
| 60 | + public Docket defaultApi2() { | ||
| 61 | + return new Docket(DocumentationType.SWAGGER_2) | ||
| 62 | + .apiInfo(apiInfo()) | ||
| 63 | + .select() | ||
| 64 | + //此包路径下的类,才生成接口文档 | ||
| 65 | + .apis(RequestHandlerSelectors.basePackage("org.jeecg")) | ||
| 66 | + //加了ApiOperation注解的类,才生成接口文档 | ||
| 67 | + .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)) | ||
| 68 | + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) | ||
| 69 | + .paths(PathSelectors.any()) | ||
| 70 | + .build() | ||
| 71 | + .securitySchemes(Collections.singletonList(securityScheme())) | ||
| 72 | + .securityContexts(securityContexts()); | ||
| 73 | + //.globalOperationParameters(setHeaderToken()); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /*** | ||
| 77 | + * oauth2配置 | ||
| 78 | + * 需要增加swagger授权回调地址 | ||
| 79 | + * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html | ||
| 80 | + * @return | ||
| 81 | + */ | ||
| 82 | + @Bean | ||
| 83 | + SecurityScheme securityScheme() { | ||
| 84 | + return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header"); | ||
| 85 | + } | ||
| 86 | + /** | ||
| 87 | + * JWT token | ||
| 88 | + * @return | ||
| 89 | + */ | ||
| 90 | + private List<Parameter> setHeaderToken() { | ||
| 91 | + ParameterBuilder tokenPar = new ParameterBuilder(); | ||
| 92 | + List<Parameter> pars = new ArrayList<>(); | ||
| 93 | + tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); | ||
| 94 | + pars.add(tokenPar.build()); | ||
| 95 | + return pars; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * api文档的详细信息函数,注意这里的注解引用的是哪个 | ||
| 100 | + * | ||
| 101 | + * @return | ||
| 102 | + */ | ||
| 103 | + private ApiInfo apiInfo() { | ||
| 104 | + return new ApiInfoBuilder() | ||
| 105 | + // //大标题 | ||
| 106 | + .title("Jeecg-Boot 后台服务API接口文档") | ||
| 107 | + // 版本号 | ||
| 108 | + .version("1.0") | ||
| 109 | +// .termsOfServiceUrl("NO terms of service") | ||
| 110 | + // 描述 | ||
| 111 | + .description("后台API接口") | ||
| 112 | + // 作者 | ||
| 113 | + .contact("JEECG团队") | ||
| 114 | + .license("The Apache License, Version 2.0") | ||
| 115 | + .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") | ||
| 116 | + .build(); | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + /** | ||
| 120 | + * 新增 securityContexts 保持登录状态 | ||
| 121 | + */ | ||
| 122 | + private List<SecurityContext> securityContexts() { | ||
| 123 | + return new ArrayList( | ||
| 124 | + Collections.singleton(SecurityContext.builder() | ||
| 125 | + .securityReferences(defaultAuth()) | ||
| 126 | + .forPaths(PathSelectors.regex("^(?!auth).*$")) | ||
| 127 | + .build()) | ||
| 128 | + ); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + private List<SecurityReference> defaultAuth() { | ||
| 132 | + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); | ||
| 133 | + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; | ||
| 134 | + authorizationScopes[0] = authorizationScope; | ||
| 135 | + return new ArrayList( | ||
| 136 | + Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes))); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebMvcConfiguration.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 4 | +import com.fasterxml.jackson.databind.module.SimpleModule; | ||
| 5 | +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; | ||
| 6 | +import org.springframework.beans.factory.annotation.Value; | ||
| 7 | +import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository; | ||
| 8 | +import org.springframework.context.annotation.Bean; | ||
| 9 | +import org.springframework.context.annotation.Conditional; | ||
| 10 | +import org.springframework.context.annotation.Configuration; | ||
| 11 | +import org.springframework.http.converter.HttpMessageConverter; | ||
| 12 | +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; | ||
| 13 | +import org.springframework.web.cors.CorsConfiguration; | ||
| 14 | +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; | ||
| 15 | +import org.springframework.web.filter.CorsFilter; | ||
| 16 | +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; | ||
| 17 | +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; | ||
| 18 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * Spring Boot 2.0 解决跨域问题 | ||
| 24 | + * | ||
| 25 | + * @Author qinfeng | ||
| 26 | + * | ||
| 27 | + */ | ||
| 28 | +@Configuration | ||
| 29 | +public class WebMvcConfiguration implements WebMvcConfigurer { | ||
| 30 | + | ||
| 31 | + @Value("${jeecg.path.upload}") | ||
| 32 | + private String upLoadPath; | ||
| 33 | + @Value("${jeecg.path.webapp}") | ||
| 34 | + private String webAppPath; | ||
| 35 | + @Value("${spring.resource.static-locations}") | ||
| 36 | + private String staticLocations; | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 静态资源的配置 - 使得可以从磁盘中读取 Html、图片、视频、音频等 | ||
| 40 | + */ | ||
| 41 | + @Override | ||
| 42 | + public void addResourceHandlers(ResourceHandlerRegistry registry) { | ||
| 43 | + registry.addResourceHandler("/**") | ||
| 44 | + .addResourceLocations("file:" + upLoadPath + "//", "file:" + webAppPath + "//") | ||
| 45 | + .addResourceLocations(staticLocations.split(",")); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 方案一: 默认访问根路径跳转 doc.html页面 (swagger文档页面) | ||
| 50 | + * 方案二: 访问根路径改成跳转 index.html页面 (简化部署方案: 可以把前端打包直接放到项目的 webapp,上面的配置) | ||
| 51 | + */ | ||
| 52 | + @Override | ||
| 53 | + public void addViewControllers(ViewControllerRegistry registry) { | ||
| 54 | + registry.addViewController("/").setViewName("doc.html"); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Bean | ||
| 58 | + @Conditional(CorsFilterCondition.class) | ||
| 59 | + public CorsFilter corsFilter() { | ||
| 60 | + final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); | ||
| 61 | + final CorsConfiguration corsConfiguration = new CorsConfiguration(); | ||
| 62 | + //是否允许请求带有验证信息 | ||
| 63 | + corsConfiguration.setAllowCredentials(true); | ||
| 64 | + // 允许访问的客户端域名 | ||
| 65 | + corsConfiguration.addAllowedOrigin("*"); | ||
| 66 | + // 允许服务端访问的客户端请求头 | ||
| 67 | + corsConfiguration.addAllowedHeader("*"); | ||
| 68 | + // 允许访问的方法名,GET POST等 | ||
| 69 | + corsConfiguration.addAllowedMethod("*"); | ||
| 70 | + urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); | ||
| 71 | + return new CorsFilter(urlBasedCorsConfigurationSource); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 添加Long转json精度丢失的配置 | ||
| 76 | + * @Return: void | ||
| 77 | + */ | ||
| 78 | + @Override | ||
| 79 | + public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { | ||
| 80 | + MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); | ||
| 81 | + ObjectMapper objectMapper = new ObjectMapper(); | ||
| 82 | + SimpleModule simpleModule = new SimpleModule(); | ||
| 83 | + simpleModule.addSerializer(Long.class, ToStringSerializer.instance); | ||
| 84 | + simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); | ||
| 85 | + objectMapper.registerModule(simpleModule); | ||
| 86 | + jackson2HttpMessageConverter.setObjectMapper(objectMapper); | ||
| 87 | + converters.add(jackson2HttpMessageConverter); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * SpringBootAdmin的Httptrace不见了 | ||
| 92 | + * https://blog.csdn.net/u013810234/article/details/110097201 | ||
| 93 | + */ | ||
| 94 | + @Bean | ||
| 95 | + public InMemoryHttpTraceRepository getInMemoryHttpTrace(){ | ||
| 96 | + return new InMemoryHttpTraceRepository(); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/WebSocketConfig.java
0 → 100644
| 1 | +package org.jeecg.config; | ||
| 2 | + | ||
| 3 | +import org.springframework.context.annotation.Bean; | ||
| 4 | +import org.springframework.context.annotation.Configuration; | ||
| 5 | +import org.springframework.web.socket.server.standard.ServerEndpointExporter; | ||
| 6 | + | ||
| 7 | +@Configuration | ||
| 8 | +public class WebSocketConfig { | ||
| 9 | + /** | ||
| 10 | + * 注入ServerEndpointExporter, | ||
| 11 | + * 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint | ||
| 12 | + */ | ||
| 13 | + @Bean | ||
| 14 | + public ServerEndpointExporter serverEndpointExporter() { | ||
| 15 | + return new ServerEndpointExporter(); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/JeecgTenantParser.java
0 → 100644
| 1 | +package org.jeecg.config.mybatis; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; | ||
| 4 | +import net.sf.jsqlparser.expression.BinaryExpression; | ||
| 5 | +import net.sf.jsqlparser.expression.Expression; | ||
| 6 | +import net.sf.jsqlparser.expression.Parenthesis; | ||
| 7 | +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; | ||
| 8 | +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | ||
| 9 | +import net.sf.jsqlparser.expression.operators.relational.*; | ||
| 10 | +import net.sf.jsqlparser.schema.Column; | ||
| 11 | +import net.sf.jsqlparser.schema.Table; | ||
| 12 | +import net.sf.jsqlparser.statement.select.*; | ||
| 13 | + | ||
| 14 | +import java.util.List; | ||
| 15 | + | ||
| 16 | +/** | ||
| 17 | + * 复写租户条件 | ||
| 18 | + */ | ||
| 19 | +public class JeecgTenantParser extends TenantSqlParser { | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * @param expression | ||
| 23 | + * @param table | ||
| 24 | + * @return | ||
| 25 | + */ | ||
| 26 | + protected Expression processTableAlias(Expression expression, Table table) { | ||
| 27 | + String tableAliasName; | ||
| 28 | + if (table.getAlias() == null) { | ||
| 29 | + tableAliasName = table.getName(); | ||
| 30 | + } else { | ||
| 31 | + tableAliasName = table.getAlias().getName(); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + // in | ||
| 35 | + if (expression instanceof InExpression) { | ||
| 36 | + InExpression in = (InExpression) expression; | ||
| 37 | + if (in.getLeftExpression() instanceof Column) { | ||
| 38 | + setTableAliasNameForColumn((Column) in.getLeftExpression(), tableAliasName); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + // 比较操作 | ||
| 42 | + } else if (expression instanceof BinaryExpression) { | ||
| 43 | + BinaryExpression compare = (BinaryExpression) expression; | ||
| 44 | + if (compare.getLeftExpression() instanceof Column) { | ||
| 45 | + setTableAliasNameForColumn((Column) compare.getLeftExpression(), tableAliasName); | ||
| 46 | + } else if (compare.getRightExpression() instanceof Column) { | ||
| 47 | + setTableAliasNameForColumn((Column) compare.getRightExpression(), tableAliasName); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + // between | ||
| 51 | + } else if (expression instanceof Between) { | ||
| 52 | + Between between = (Between) expression; | ||
| 53 | + if (between.getLeftExpression() instanceof Column) { | ||
| 54 | + setTableAliasNameForColumn((Column) between.getLeftExpression(), tableAliasName); | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + return expression; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + private void setTableAliasNameForColumn(Column column, String tableAliasName) { | ||
| 61 | + column.setColumnName(tableAliasName + "." + column.getColumnName()); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + /** | ||
| 65 | + * 默认是按 tenant_id=1 按等于条件追加 | ||
| 66 | + * | ||
| 67 | + * @param currentExpression 现有的条件:比如你原来的sql查询条件 | ||
| 68 | + * @param table | ||
| 69 | + * @return | ||
| 70 | + */ | ||
| 71 | + @Override | ||
| 72 | + protected Expression builderExpression(Expression currentExpression, Table table) { | ||
| 73 | + final Expression tenantExpression = this.getTenantHandler().getTenantId(true); | ||
| 74 | + Expression appendExpression; | ||
| 75 | + if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) { | ||
| 76 | + appendExpression = new EqualsTo(); | ||
| 77 | + ((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table)); | ||
| 78 | + ((EqualsTo) appendExpression).setRightExpression(tenantExpression); | ||
| 79 | + } else { | ||
| 80 | + appendExpression = processTableAlias(tenantExpression, table); | ||
| 81 | + } | ||
| 82 | + if (currentExpression == null) { | ||
| 83 | + return appendExpression; | ||
| 84 | + } | ||
| 85 | + if (currentExpression instanceof BinaryExpression) { | ||
| 86 | + BinaryExpression binaryExpression = (BinaryExpression) currentExpression; | ||
| 87 | + if (binaryExpression.getLeftExpression() instanceof FromItem) { | ||
| 88 | + processFromItem((FromItem) binaryExpression.getLeftExpression()); | ||
| 89 | + } | ||
| 90 | + if (binaryExpression.getRightExpression() instanceof FromItem) { | ||
| 91 | + processFromItem((FromItem) binaryExpression.getRightExpression()); | ||
| 92 | + } | ||
| 93 | + } else if (currentExpression instanceof InExpression) { | ||
| 94 | + InExpression inExp = (InExpression) currentExpression; | ||
| 95 | + ItemsList rightItems = inExp.getRightItemsList(); | ||
| 96 | + if (rightItems instanceof SubSelect) { | ||
| 97 | + processSelectBody(((SubSelect) rightItems).getSelectBody()); | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + if (currentExpression instanceof OrExpression) { | ||
| 101 | + return new AndExpression(new Parenthesis(currentExpression), appendExpression); | ||
| 102 | + } else { | ||
| 103 | + return new AndExpression(currentExpression, appendExpression); | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + @Override | ||
| 108 | + protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) { | ||
| 109 | + FromItem fromItem = plainSelect.getFromItem(); | ||
| 110 | + if (fromItem instanceof Table) { | ||
| 111 | + Table fromTable = (Table) fromItem; | ||
| 112 | + if (!this.getTenantHandler().doTableFilter(fromTable.getName())) { | ||
| 113 | + plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable)); | ||
| 114 | + if (addColumn) { | ||
| 115 | + plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn()))); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + } else { | ||
| 119 | + processFromItem(fromItem); | ||
| 120 | + } | ||
| 121 | + List<Join> joins = plainSelect.getJoins(); | ||
| 122 | + if (joins != null && joins.size() > 0) { | ||
| 123 | + joins.forEach(j -> { | ||
| 124 | + processJoin(j); | ||
| 125 | + processFromItem(j.getRightItem()); | ||
| 126 | + }); | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisInterceptor.java
0 → 100644
| 1 | +package org.jeecg.config.mybatis; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.ibatis.binding.MapperMethod.ParamMap; | ||
| 5 | +import org.apache.ibatis.executor.Executor; | ||
| 6 | +import org.apache.ibatis.mapping.MappedStatement; | ||
| 7 | +import org.apache.ibatis.mapping.SqlCommandType; | ||
| 8 | +import org.apache.ibatis.plugin.*; | ||
| 9 | +import org.apache.shiro.SecurityUtils; | ||
| 10 | +import org.jeecg.common.system.vo.LoginUser; | ||
| 11 | +import org.jeecg.common.util.oConvertUtils; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +import java.lang.reflect.Field; | ||
| 15 | +import java.util.Date; | ||
| 16 | +import java.util.Properties; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * mybatis拦截器,自动注入创建人、创建时间、修改人、修改时间 | ||
| 20 | + * @Author scott | ||
| 21 | + * @Date 2019-01-19 | ||
| 22 | + * | ||
| 23 | + */ | ||
| 24 | +@Slf4j | ||
| 25 | +@Component | ||
| 26 | +@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) }) | ||
| 27 | +public class MybatisInterceptor implements Interceptor { | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public Object intercept(Invocation invocation) throws Throwable { | ||
| 31 | + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; | ||
| 32 | + String sqlId = mappedStatement.getId(); | ||
| 33 | + log.debug("------sqlId------" + sqlId); | ||
| 34 | + SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); | ||
| 35 | + Object parameter = invocation.getArgs()[1]; | ||
| 36 | + log.debug("------sqlCommandType------" + sqlCommandType); | ||
| 37 | + | ||
| 38 | + if (parameter == null) { | ||
| 39 | + return invocation.proceed(); | ||
| 40 | + } | ||
| 41 | + if (SqlCommandType.INSERT == sqlCommandType) { | ||
| 42 | + LoginUser sysUser = this.getLoginUser(); | ||
| 43 | + Field[] fields = oConvertUtils.getAllFields(parameter); | ||
| 44 | + for (Field field : fields) { | ||
| 45 | + log.debug("------field.name------" + field.getName()); | ||
| 46 | + try { | ||
| 47 | + if ("createBy".equals(field.getName())) { | ||
| 48 | + field.setAccessible(true); | ||
| 49 | + Object local_createBy = field.get(parameter); | ||
| 50 | + field.setAccessible(false); | ||
| 51 | + if (local_createBy == null || local_createBy.equals("")) { | ||
| 52 | + if (sysUser != null) { | ||
| 53 | + // 登录人账号 | ||
| 54 | + field.setAccessible(true); | ||
| 55 | + field.set(parameter, sysUser.getUsername()); | ||
| 56 | + field.setAccessible(false); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + // 注入创建时间 | ||
| 61 | + if ("createTime".equals(field.getName())) { | ||
| 62 | + field.setAccessible(true); | ||
| 63 | + Object local_createDate = field.get(parameter); | ||
| 64 | + field.setAccessible(false); | ||
| 65 | + if (local_createDate == null || local_createDate.equals("")) { | ||
| 66 | + field.setAccessible(true); | ||
| 67 | + field.set(parameter, new Date()); | ||
| 68 | + field.setAccessible(false); | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + //注入部门编码 | ||
| 72 | + if ("sysOrgCode".equals(field.getName())) { | ||
| 73 | + field.setAccessible(true); | ||
| 74 | + Object local_sysOrgCode = field.get(parameter); | ||
| 75 | + field.setAccessible(false); | ||
| 76 | + if (local_sysOrgCode == null || local_sysOrgCode.equals("")) { | ||
| 77 | + // 获取登录用户信息 | ||
| 78 | + if (sysUser != null) { | ||
| 79 | + field.setAccessible(true); | ||
| 80 | + field.set(parameter, sysUser.getOrgCode()); | ||
| 81 | + field.setAccessible(false); | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + } catch (Exception e) { | ||
| 86 | + } | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + if (SqlCommandType.UPDATE == sqlCommandType) { | ||
| 90 | + LoginUser sysUser = this.getLoginUser(); | ||
| 91 | + Field[] fields = null; | ||
| 92 | + if (parameter instanceof ParamMap) { | ||
| 93 | + ParamMap<?> p = (ParamMap<?>) parameter; | ||
| 94 | + //update-begin-author:scott date:20190729 for:批量更新报错issues/IZA3Q-- | ||
| 95 | + if (p.containsKey("et")) { | ||
| 96 | + parameter = p.get("et"); | ||
| 97 | + } else { | ||
| 98 | + parameter = p.get("param1"); | ||
| 99 | + } | ||
| 100 | + //update-end-author:scott date:20190729 for:批量更新报错issues/IZA3Q- | ||
| 101 | + | ||
| 102 | + //update-begin-author:scott date:20190729 for:更新指定字段时报错 issues/#516- | ||
| 103 | + if (parameter == null) { | ||
| 104 | + return invocation.proceed(); | ||
| 105 | + } | ||
| 106 | + //update-end-author:scott date:20190729 for:更新指定字段时报错 issues/#516- | ||
| 107 | + | ||
| 108 | + fields = oConvertUtils.getAllFields(parameter); | ||
| 109 | + } else { | ||
| 110 | + fields = oConvertUtils.getAllFields(parameter); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + for (Field field : fields) { | ||
| 114 | + log.debug("------field.name------" + field.getName()); | ||
| 115 | + try { | ||
| 116 | + if ("updateBy".equals(field.getName())) { | ||
| 117 | + //获取登录用户信息 | ||
| 118 | + if (sysUser != null) { | ||
| 119 | + // 登录账号 | ||
| 120 | + field.setAccessible(true); | ||
| 121 | + field.set(parameter, sysUser.getUsername()); | ||
| 122 | + field.setAccessible(false); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + if ("updateTime".equals(field.getName())) { | ||
| 126 | + field.setAccessible(true); | ||
| 127 | + field.set(parameter, new Date()); | ||
| 128 | + field.setAccessible(false); | ||
| 129 | + } | ||
| 130 | + } catch (Exception e) { | ||
| 131 | + e.printStackTrace(); | ||
| 132 | + } | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | + return invocation.proceed(); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + @Override | ||
| 139 | + public Object plugin(Object target) { | ||
| 140 | + return Plugin.wrap(target, this); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + @Override | ||
| 144 | + public void setProperties(Properties properties) { | ||
| 145 | + // TODO Auto-generated method stub | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + //update-begin--Author:scott Date:20191213 for:关于使用Quzrtz 开启线程任务, #465 | ||
| 149 | + private LoginUser getLoginUser() { | ||
| 150 | + LoginUser sysUser = null; | ||
| 151 | + try { | ||
| 152 | + sysUser = SecurityUtils.getSubject().getPrincipal() != null ? (LoginUser) SecurityUtils.getSubject().getPrincipal() : null; | ||
| 153 | + } catch (Exception e) { | ||
| 154 | + //e.printStackTrace(); | ||
| 155 | + sysUser = null; | ||
| 156 | + } | ||
| 157 | + return sysUser; | ||
| 158 | + } | ||
| 159 | + //update-end--Author:scott Date:20191213 for:关于使用Quzrtz 开启线程任务, #465 | ||
| 160 | + | ||
| 161 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusConfig.java
0 → 100644
| 1 | +package org.jeecg.config.mybatis; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.core.parser.ISqlParser; | ||
| 4 | +import com.baomidou.mybatisplus.core.parser.ISqlParserFilter; | ||
| 5 | +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; | ||
| 6 | +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; | ||
| 7 | +import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler; | ||
| 8 | +import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser; | ||
| 9 | +import net.sf.jsqlparser.expression.Expression; | ||
| 10 | +import net.sf.jsqlparser.expression.LongValue; | ||
| 11 | +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | ||
| 12 | +import net.sf.jsqlparser.expression.operators.relational.InExpression; | ||
| 13 | +import net.sf.jsqlparser.schema.Column; | ||
| 14 | +import org.apache.ibatis.reflection.MetaObject; | ||
| 15 | +import org.jeecg.common.util.oConvertUtils; | ||
| 16 | +import org.mybatis.spring.annotation.MapperScan; | ||
| 17 | +import org.springframework.context.annotation.Bean; | ||
| 18 | +import org.springframework.context.annotation.Configuration; | ||
| 19 | + | ||
| 20 | +import java.util.ArrayList; | ||
| 21 | +import java.util.List; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * 单数据源配置(jeecg.datasource.open = false时生效) | ||
| 25 | + * @Author zhoujf | ||
| 26 | + * | ||
| 27 | + */ | ||
| 28 | +@Configuration | ||
| 29 | +@MapperScan(value={"org.jeecg.modules.**.mapper*"}) | ||
| 30 | +public class MybatisPlusConfig { | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * tenant_id 字段名 | ||
| 34 | + */ | ||
| 35 | + public static final String tenant_field = "tenant_id"; | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * 有哪些表需要做多租户 这些表需要添加一个字段 ,字段名和tenant_field对应的值一样 | ||
| 39 | + */ | ||
| 40 | + private static final List<String> tenantTable = new ArrayList<String>(); | ||
| 41 | + /** | ||
| 42 | + * ddl 关键字 判断不走多租户的sql过滤 | ||
| 43 | + */ | ||
| 44 | + private static final List<String> DDL_KEYWORD = new ArrayList<String>(); | ||
| 45 | + static { | ||
| 46 | + tenantTable.add("jee_bug_danbiao"); | ||
| 47 | + DDL_KEYWORD.add("alter"); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 多租户属于 SQL 解析部分,依赖 MP 分页插件 | ||
| 52 | + */ | ||
| 53 | + @Bean | ||
| 54 | + public PaginationInterceptor paginationInterceptor() { | ||
| 55 | + PaginationInterceptor paginationInterceptor = new PaginationInterceptor().setLimit(-1); | ||
| 56 | + //多租户配置 配置后每次执行sql会走一遍他的转化器 如果不需要多租户功能 可以将其注释 | ||
| 57 | + tenantConfig(paginationInterceptor); | ||
| 58 | + return paginationInterceptor; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + /** | ||
| 62 | + * 多租户的配置 | ||
| 63 | + * @param paginationInterceptor | ||
| 64 | + */ | ||
| 65 | + private void tenantConfig(PaginationInterceptor paginationInterceptor){ | ||
| 66 | + /* | ||
| 67 | + * 【测试多租户】 SQL 解析处理拦截器<br> | ||
| 68 | + * 这里固定写成住户 1 实际情况你可以从cookie读取,因此数据看不到 【 麻花藤 】 这条记录( 注意观察 SQL )<br> | ||
| 69 | + */ | ||
| 70 | + List<ISqlParser> sqlParserList = new ArrayList<>(); | ||
| 71 | + TenantSqlParser tenantSqlParser = new JeecgTenantParser(); | ||
| 72 | + tenantSqlParser.setTenantHandler(new TenantHandler() { | ||
| 73 | + | ||
| 74 | + @Override | ||
| 75 | + public Expression getTenantId(boolean select) { | ||
| 76 | + String tenant_id = oConvertUtils.getString(TenantContext.getTenant(),"0"); | ||
| 77 | + return new LongValue(tenant_id); | ||
| 78 | + } | ||
| 79 | + @Override | ||
| 80 | + public String getTenantIdColumn() { | ||
| 81 | + return tenant_field; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + @Override | ||
| 85 | + public boolean doTableFilter(String tableName) { | ||
| 86 | + //true则不加租户条件查询 false则加 | ||
| 87 | + // return excludeTable.contains(tableName); | ||
| 88 | + if(tenantTable.contains(tableName)){ | ||
| 89 | + return false; | ||
| 90 | + } | ||
| 91 | + return true; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + private Expression in(String ids){ | ||
| 95 | + final InExpression inExpression = new InExpression(); | ||
| 96 | + inExpression.setLeftExpression(new Column(getTenantIdColumn())); | ||
| 97 | + final ExpressionList itemsList = new ExpressionList(); | ||
| 98 | + final List<Expression> inValues = new ArrayList<>(2); | ||
| 99 | + for(String id:ids.split(",")){ | ||
| 100 | + inValues.add(new LongValue(id)); | ||
| 101 | + } | ||
| 102 | + itemsList.setExpressions(inValues); | ||
| 103 | + inExpression.setRightItemsList(itemsList); | ||
| 104 | + return inExpression; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + }); | ||
| 108 | + | ||
| 109 | + sqlParserList.add(tenantSqlParser); | ||
| 110 | + paginationInterceptor.setSqlParserList(sqlParserList); | ||
| 111 | + paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() { | ||
| 112 | + @Override | ||
| 113 | + public boolean doFilter(MetaObject metaObject) { | ||
| 114 | + String sql = (String) metaObject.getValue(PluginUtils.DELEGATE_BOUNDSQL_SQL); | ||
| 115 | + for(String tableName: tenantTable){ | ||
| 116 | + String sql_lowercase = sql.toLowerCase(); | ||
| 117 | + if(sql_lowercase.indexOf(tableName.toLowerCase())>=0){ | ||
| 118 | + for(String key: DDL_KEYWORD){ | ||
| 119 | + if(sql_lowercase.indexOf(key)>=0){ | ||
| 120 | + return true; | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + return false; | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + /*if ("mapper路径.方法名".equals(ms.getId())) { | ||
| 127 | + //使用这种判断也可以避免走此过滤器 | ||
| 128 | + return true; | ||
| 129 | + }*/ | ||
| 130 | + return true; | ||
| 131 | + } | ||
| 132 | + }); | ||
| 133 | + } | ||
| 134 | +// /** | ||
| 135 | +// * mybatis-plus SQL执行效率插件【生产环境可以关闭】 | ||
| 136 | +// */ | ||
| 137 | +// @Bean | ||
| 138 | +// public PerformanceInterceptor performanceInterceptor() { | ||
| 139 | +// return new PerformanceInterceptor(); | ||
| 140 | +// } | ||
| 141 | + | ||
| 142 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/TenantContext.java
0 → 100644
| 1 | +package org.jeecg.config.mybatis; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 多租户 tenant_id存储器 | ||
| 7 | + */ | ||
| 8 | +@Slf4j | ||
| 9 | +public class TenantContext { | ||
| 10 | + | ||
| 11 | + private static ThreadLocal<String> currentTenant = new ThreadLocal<>(); | ||
| 12 | + | ||
| 13 | + public static void setTenant(String tenant) { | ||
| 14 | + log.debug(" setting tenant to " + tenant); | ||
| 15 | + currentTenant.set(tenant); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + public static String getTenant() { | ||
| 19 | + return currentTenant.get(); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public static void clear(){ | ||
| 23 | + currentTenant.remove(); | ||
| 24 | + } | ||
| 25 | +} | ||
| 0 | \ No newline at end of file | 26 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/oss/MinioConfig.java
0 → 100644
| 1 | +package org.jeecg.config.oss; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.jeecg.common.util.MinioUtil; | ||
| 5 | +import org.springframework.beans.factory.annotation.Value; | ||
| 6 | +import org.springframework.context.annotation.Bean; | ||
| 7 | +import org.springframework.context.annotation.Configuration; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * Minio文件上传配置文件 | ||
| 11 | + */ | ||
| 12 | +@Slf4j | ||
| 13 | +@Configuration | ||
| 14 | +public class MinioConfig { | ||
| 15 | + @Value(value = "${jeecg.minio.minio_url}") | ||
| 16 | + private String minioUrl; | ||
| 17 | + @Value(value = "${jeecg.minio.minio_name}") | ||
| 18 | + private String minioName; | ||
| 19 | + @Value(value = "${jeecg.minio.minio_pass}") | ||
| 20 | + private String minioPass; | ||
| 21 | + @Value(value = "${jeecg.minio.bucketName}") | ||
| 22 | + private String bucketName; | ||
| 23 | + | ||
| 24 | + @Bean | ||
| 25 | + public void initMinio(){ | ||
| 26 | + if(!minioUrl.startsWith("http")){ | ||
| 27 | + minioUrl = "http://" + minioUrl; | ||
| 28 | + } | ||
| 29 | + if(!minioUrl.endsWith("/")){ | ||
| 30 | + minioUrl = minioUrl.concat("/"); | ||
| 31 | + } | ||
| 32 | + MinioUtil.setMinioUrl(minioUrl); | ||
| 33 | + MinioUtil.setMinioName(minioName); | ||
| 34 | + MinioUtil.setMinioPass(minioPass); | ||
| 35 | + MinioUtil.setBucketName(bucketName); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/oss/OssConfiguration.java
0 → 100644
| 1 | +package org.jeecg.config.oss; | ||
| 2 | + | ||
| 3 | +import org.jeecg.common.util.oss.OssBootUtil; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.context.annotation.Bean; | ||
| 6 | +import org.springframework.context.annotation.Configuration; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 云存储 配置 | ||
| 10 | + */ | ||
| 11 | +@Configuration | ||
| 12 | +public class OssConfiguration { | ||
| 13 | + | ||
| 14 | + @Value("${jeecg.oss.endpoint}") | ||
| 15 | + private String endpoint; | ||
| 16 | + @Value("${jeecg.oss.accessKey}") | ||
| 17 | + private String accessKeyId; | ||
| 18 | + @Value("${jeecg.oss.secretKey}") | ||
| 19 | + private String accessKeySecret; | ||
| 20 | + @Value("${jeecg.oss.bucketName}") | ||
| 21 | + private String bucketName; | ||
| 22 | + @Value("${jeecg.oss.staticDomain:}") | ||
| 23 | + private String staticDomain; | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + @Bean | ||
| 27 | + public void initOssBootConfiguration() { | ||
| 28 | + OssBootUtil.setEndPoint(endpoint); | ||
| 29 | + OssBootUtil.setAccessKeyId(accessKeyId); | ||
| 30 | + OssBootUtil.setAccessKeySecret(accessKeySecret); | ||
| 31 | + OssBootUtil.setBucketName(bucketName); | ||
| 32 | + OssBootUtil.setStaticDomain(staticDomain); | ||
| 33 | + } | ||
| 34 | +} | ||
| 0 | \ No newline at end of file | 35 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/JwtToken.java
0 → 100644
| 1 | +package org.jeecg.config.shiro; | ||
| 2 | + | ||
| 3 | +import org.apache.shiro.authc.AuthenticationToken; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * @Author Scott | ||
| 7 | + * @create 2018-07-12 15:19 | ||
| 8 | + * @desc | ||
| 9 | + **/ | ||
| 10 | +public class JwtToken implements AuthenticationToken { | ||
| 11 | + | ||
| 12 | + private static final long serialVersionUID = 1L; | ||
| 13 | + private String token; | ||
| 14 | + | ||
| 15 | + public JwtToken(String token) { | ||
| 16 | + this.token = token; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + @Override | ||
| 20 | + public Object getPrincipal() { | ||
| 21 | + return token; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @Override | ||
| 25 | + public Object getCredentials() { | ||
| 26 | + return token; | ||
| 27 | + } | ||
| 28 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
0 → 100644
| 1 | +package org.jeecg.config.shiro; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; | ||
| 5 | +import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; | ||
| 6 | +import org.apache.shiro.mgt.DefaultSubjectDAO; | ||
| 7 | +import org.apache.shiro.mgt.SecurityManager; | ||
| 8 | +import org.apache.shiro.spring.LifecycleBeanPostProcessor; | ||
| 9 | +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; | ||
| 10 | +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | ||
| 11 | +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; | ||
| 12 | +import org.crazycake.shiro.IRedisManager; | ||
| 13 | +import org.crazycake.shiro.RedisCacheManager; | ||
| 14 | +import org.crazycake.shiro.RedisClusterManager; | ||
| 15 | +import org.crazycake.shiro.RedisManager; | ||
| 16 | +import org.jeecg.common.constant.CommonConstant; | ||
| 17 | +import org.jeecg.common.util.oConvertUtils; | ||
| 18 | +import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean; | ||
| 19 | +import org.jeecg.config.shiro.filters.JwtFilter; | ||
| 20 | +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; | ||
| 21 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 22 | +import org.springframework.beans.factory.annotation.Value; | ||
| 23 | +import org.springframework.context.annotation.Bean; | ||
| 24 | +import org.springframework.context.annotation.Configuration; | ||
| 25 | +import org.springframework.context.annotation.DependsOn; | ||
| 26 | +import org.springframework.core.env.Environment; | ||
| 27 | +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; | ||
| 28 | +import org.springframework.util.StringUtils; | ||
| 29 | +import redis.clients.jedis.HostAndPort; | ||
| 30 | +import redis.clients.jedis.JedisCluster; | ||
| 31 | + | ||
| 32 | +import javax.annotation.Resource; | ||
| 33 | +import javax.servlet.Filter; | ||
| 34 | +import java.util.*; | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * @author: Scott | ||
| 38 | + * @date: 2018/2/7 | ||
| 39 | + * @description: shiro 配置类 | ||
| 40 | + */ | ||
| 41 | + | ||
| 42 | +@Slf4j | ||
| 43 | +@Configuration | ||
| 44 | +public class ShiroConfig { | ||
| 45 | + | ||
| 46 | + @Value("${jeecg.shiro.excludeUrls}") | ||
| 47 | + private String excludeUrls; | ||
| 48 | + @Resource | ||
| 49 | + LettuceConnectionFactory lettuceConnectionFactory; | ||
| 50 | + @Autowired | ||
| 51 | + private Environment env; | ||
| 52 | + | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Filter Chain定义说明 | ||
| 56 | + * | ||
| 57 | + * 1、一个URL可以配置多个Filter,使用逗号分隔 | ||
| 58 | + * 2、当设置多个过滤器时,全部验证通过,才视为通过 | ||
| 59 | + * 3、部分过滤器可指定参数,如perms,roles | ||
| 60 | + */ | ||
| 61 | + @Bean("shiroFilter") | ||
| 62 | + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { | ||
| 63 | + CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean(); | ||
| 64 | + shiroFilterFactoryBean.setSecurityManager(securityManager); | ||
| 65 | + // 拦截器 | ||
| 66 | + Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); | ||
| 67 | + if(oConvertUtils.isNotEmpty(excludeUrls)){ | ||
| 68 | + String[] permissionUrl = excludeUrls.split(","); | ||
| 69 | + for(String url : permissionUrl){ | ||
| 70 | + filterChainDefinitionMap.put(url,"anon"); | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + // 配置不会被拦截的链接 顺序判断 | ||
| 74 | + filterChainDefinitionMap.put("/sys/cas/client/validateLogin", "anon"); //cas验证登录 | ||
| 75 | + filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除 | ||
| 76 | + filterChainDefinitionMap.put("/sys/checkCaptcha", "anon"); //登录验证码接口排除 | ||
| 77 | + filterChainDefinitionMap.put("/sys/login", "anon"); //登录接口排除 | ||
| 78 | + filterChainDefinitionMap.put("/sys/mLogin", "anon"); //登录接口排除 | ||
| 79 | + filterChainDefinitionMap.put("/sys/logout", "anon"); //登出接口排除 | ||
| 80 | + filterChainDefinitionMap.put("/sys/thirdLogin/**", "anon"); //第三方登录 | ||
| 81 | + filterChainDefinitionMap.put("/sys/getEncryptedString", "anon"); //获取加密串 | ||
| 82 | + filterChainDefinitionMap.put("/sys/sms", "anon");//短信验证码 | ||
| 83 | + filterChainDefinitionMap.put("/sys/phoneLogin", "anon");//手机登录 | ||
| 84 | + filterChainDefinitionMap.put("/sys/user/checkOnlyUser", "anon");//校验用户是否存在 | ||
| 85 | + filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册 | ||
| 86 | + filterChainDefinitionMap.put("/sys/user/querySysUser", "anon");//根据手机号获取用户信息 | ||
| 87 | + filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号 | ||
| 88 | + filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码 | ||
| 89 | + filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码 | ||
| 90 | + filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token | ||
| 91 | + filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览 | ||
| 92 | + filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件 | ||
| 93 | + filterChainDefinitionMap.put("/", "anon"); | ||
| 94 | + filterChainDefinitionMap.put("/doc.html", "anon"); | ||
| 95 | + filterChainDefinitionMap.put("/**/*.js", "anon"); | ||
| 96 | + filterChainDefinitionMap.put("/**/*.css", "anon"); | ||
| 97 | + filterChainDefinitionMap.put("/**/*.html", "anon"); | ||
| 98 | + filterChainDefinitionMap.put("/**/*.svg", "anon"); | ||
| 99 | + filterChainDefinitionMap.put("/**/*.pdf", "anon"); | ||
| 100 | + filterChainDefinitionMap.put("/**/*.jpg", "anon"); | ||
| 101 | + filterChainDefinitionMap.put("/**/*.png", "anon"); | ||
| 102 | + filterChainDefinitionMap.put("/**/*.ico", "anon"); | ||
| 103 | + | ||
| 104 | + filterChainDefinitionMap.put("/**/*.ttf", "anon"); | ||
| 105 | + filterChainDefinitionMap.put("/**/*.woff", "anon"); | ||
| 106 | + filterChainDefinitionMap.put("/**/*.woff2", "anon"); | ||
| 107 | + | ||
| 108 | + filterChainDefinitionMap.put("/druid/**", "anon"); | ||
| 109 | + filterChainDefinitionMap.put("/swagger-ui.html", "anon"); | ||
| 110 | + filterChainDefinitionMap.put("/swagger**/**", "anon"); | ||
| 111 | + filterChainDefinitionMap.put("/webjars/**", "anon"); | ||
| 112 | + filterChainDefinitionMap.put("/v2/**", "anon"); | ||
| 113 | + | ||
| 114 | + | ||
| 115 | + // update-begin--Author:sunjianlei Date:20210510 for:排除消息通告查看详情页面(用于第三方APP) | ||
| 116 | + filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon"); | ||
| 117 | + // update-end--Author:sunjianlei Date:20210510 for:排除消息通告查看详情页面(用于第三方APP) | ||
| 118 | + | ||
| 119 | + //积木报表排除 | ||
| 120 | +// filterChainDefinitionMap.put("/jmreport/**", "anon"); | ||
| 121 | + filterChainDefinitionMap.put("/**/*.js.map", "anon"); | ||
| 122 | + filterChainDefinitionMap.put("/**/*.css.map", "anon"); | ||
| 123 | + //大屏设计器排除 | ||
| 124 | + filterChainDefinitionMap.put("/bigscreen/**", "anon"); | ||
| 125 | + | ||
| 126 | + //测试示例 | ||
| 127 | + filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子 | ||
| 128 | + //filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试 | ||
| 129 | + //filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面 | ||
| 130 | + //filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试 | ||
| 131 | + | ||
| 132 | + //websocket排除 | ||
| 133 | + filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告 | ||
| 134 | + filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块 | ||
| 135 | + filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例 | ||
| 136 | + | ||
| 137 | + | ||
| 138 | + //性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有) | ||
| 139 | + filterChainDefinitionMap.put("/actuator/**", "anon"); | ||
| 140 | + | ||
| 141 | + // 添加自己的过滤器并且取名为jwt | ||
| 142 | + Map<String, Filter> filterMap = new HashMap<String, Filter>(1); | ||
| 143 | + //如果cloudServer为空 则说明是单体 需要加载跨域配置 | ||
| 144 | + Object cloudServer = env.getProperty(CommonConstant.CLOUD_SERVER_KEY); | ||
| 145 | + filterMap.put("jwt", new JwtFilter(cloudServer==null)); | ||
| 146 | + shiroFilterFactoryBean.setFilters(filterMap); | ||
| 147 | + // <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 | ||
| 148 | + filterChainDefinitionMap.put("/**", "jwt"); | ||
| 149 | + | ||
| 150 | + // 未授权界面返回JSON | ||
| 151 | + shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403"); | ||
| 152 | + shiroFilterFactoryBean.setLoginUrl("/sys/common/403"); | ||
| 153 | + shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); | ||
| 154 | + return shiroFilterFactoryBean; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + @Bean("securityManager") | ||
| 158 | + public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { | ||
| 159 | + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); | ||
| 160 | + securityManager.setRealm(myRealm); | ||
| 161 | + | ||
| 162 | + /* | ||
| 163 | + * 关闭shiro自带的session,详情见文档 | ||
| 164 | + * http://shiro.apache.org/session-management.html#SessionManagement- | ||
| 165 | + * StatelessApplications%28Sessionless%29 | ||
| 166 | + */ | ||
| 167 | + DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); | ||
| 168 | + DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); | ||
| 169 | + defaultSessionStorageEvaluator.setSessionStorageEnabled(false); | ||
| 170 | + subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); | ||
| 171 | + securityManager.setSubjectDAO(subjectDAO); | ||
| 172 | + //自定义缓存实现,使用redis | ||
| 173 | + securityManager.setCacheManager(redisCacheManager()); | ||
| 174 | + return securityManager; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + /** | ||
| 178 | + * 下面的代码是添加注解支持 | ||
| 179 | + * @return | ||
| 180 | + */ | ||
| 181 | + @Bean | ||
| 182 | + @DependsOn("lifecycleBeanPostProcessor") | ||
| 183 | + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { | ||
| 184 | + DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); | ||
| 185 | + defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); | ||
| 186 | + /** | ||
| 187 | + * 解决重复代理问题 github#994 | ||
| 188 | + * 添加前缀判断 不匹配 任何Advisor | ||
| 189 | + */ | ||
| 190 | + defaultAdvisorAutoProxyCreator.setUsePrefix(true); | ||
| 191 | + defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); | ||
| 192 | + return defaultAdvisorAutoProxyCreator; | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + @Bean | ||
| 196 | + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { | ||
| 197 | + return new LifecycleBeanPostProcessor(); | ||
| 198 | + } | ||
| 199 | + | ||
| 200 | + @Bean | ||
| 201 | + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { | ||
| 202 | + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); | ||
| 203 | + advisor.setSecurityManager(securityManager); | ||
| 204 | + return advisor; | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + /** | ||
| 208 | + * cacheManager 缓存 redis实现 | ||
| 209 | + * 使用的是shiro-redis开源插件 | ||
| 210 | + * | ||
| 211 | + * @return | ||
| 212 | + */ | ||
| 213 | + public RedisCacheManager redisCacheManager() { | ||
| 214 | + log.info("===============(1)创建缓存管理器RedisCacheManager"); | ||
| 215 | + RedisCacheManager redisCacheManager = new RedisCacheManager(); | ||
| 216 | + redisCacheManager.setRedisManager(redisManager()); | ||
| 217 | + //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识) | ||
| 218 | + redisCacheManager.setPrincipalIdFieldName("id"); | ||
| 219 | + //用户权限信息缓存时间 | ||
| 220 | + redisCacheManager.setExpire(200000); | ||
| 221 | + return redisCacheManager; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + /** | ||
| 225 | + * 配置shiro redisManager | ||
| 226 | + * 使用的是shiro-redis开源插件 | ||
| 227 | + * | ||
| 228 | + * @return | ||
| 229 | + */ | ||
| 230 | + @Bean | ||
| 231 | + public IRedisManager redisManager() { | ||
| 232 | + log.info("===============(2)创建RedisManager,连接Redis.."); | ||
| 233 | + IRedisManager manager; | ||
| 234 | + // redis 单机支持,在集群为空,或者集群无机器时候使用 add by jzyadmin@163.com | ||
| 235 | + if (lettuceConnectionFactory.getClusterConfiguration() == null || lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().isEmpty()) { | ||
| 236 | + RedisManager redisManager = new RedisManager(); | ||
| 237 | + redisManager.setHost(lettuceConnectionFactory.getHostName()); | ||
| 238 | + redisManager.setPort(lettuceConnectionFactory.getPort()); | ||
| 239 | + redisManager.setDatabase(lettuceConnectionFactory.getDatabase()); | ||
| 240 | + redisManager.setTimeout(0); | ||
| 241 | + if (!StringUtils.isEmpty(lettuceConnectionFactory.getPassword())) { | ||
| 242 | + redisManager.setPassword(lettuceConnectionFactory.getPassword()); | ||
| 243 | + } | ||
| 244 | + manager = redisManager; | ||
| 245 | + }else{ | ||
| 246 | + // redis集群支持,优先使用集群配置 | ||
| 247 | + RedisClusterManager redisManager = new RedisClusterManager(); | ||
| 248 | + Set<HostAndPort> portSet = new HashSet<>(); | ||
| 249 | + lettuceConnectionFactory.getClusterConfiguration().getClusterNodes().forEach(node -> portSet.add(new HostAndPort(node.getHost() , node.getPort()))); | ||
| 250 | + //update-begin--Author:scott Date:20210531 for:修改集群模式下未设置redis密码的bug issues/I3QNIC | ||
| 251 | + if (oConvertUtils.isNotEmpty(lettuceConnectionFactory.getPassword())) { | ||
| 252 | + JedisCluster jedisCluster = new JedisCluster(portSet, 2000, 2000, 5, | ||
| 253 | + lettuceConnectionFactory.getPassword(), new GenericObjectPoolConfig()); | ||
| 254 | + redisManager.setPassword(lettuceConnectionFactory.getPassword()); | ||
| 255 | + redisManager.setJedisCluster(jedisCluster); | ||
| 256 | + } else { | ||
| 257 | + JedisCluster jedisCluster = new JedisCluster(portSet); | ||
| 258 | + redisManager.setJedisCluster(jedisCluster); | ||
| 259 | + } | ||
| 260 | + //update-end--Author:scott Date:20210531 for:修改集群模式下未设置redis密码的bug issues/I3QNIC | ||
| 261 | + manager = redisManager; | ||
| 262 | + } | ||
| 263 | + return manager; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
0 → 100644
| 1 | +package org.jeecg.config.shiro; | ||
| 2 | + | ||
| 3 | +import cn.hutool.crypto.SecureUtil; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.apache.shiro.authc.AuthenticationException; | ||
| 6 | +import org.apache.shiro.authc.AuthenticationInfo; | ||
| 7 | +import org.apache.shiro.authc.AuthenticationToken; | ||
| 8 | +import org.apache.shiro.authc.SimpleAuthenticationInfo; | ||
| 9 | +import org.apache.shiro.authz.AuthorizationInfo; | ||
| 10 | +import org.apache.shiro.authz.SimpleAuthorizationInfo; | ||
| 11 | +import org.apache.shiro.realm.AuthorizingRealm; | ||
| 12 | +import org.apache.shiro.subject.PrincipalCollection; | ||
| 13 | +import org.jeecg.common.api.CommonAPI; | ||
| 14 | +import org.jeecg.common.constant.CacheConstant; | ||
| 15 | +import org.jeecg.common.constant.CommonConstant; | ||
| 16 | +import org.jeecg.common.system.util.JwtUtil; | ||
| 17 | +import org.jeecg.common.system.vo.LoginUser; | ||
| 18 | +import org.jeecg.common.util.RedisUtil; | ||
| 19 | +import org.jeecg.common.util.SpringContextUtils; | ||
| 20 | +import org.jeecg.common.util.oConvertUtils; | ||
| 21 | +import org.springframework.context.annotation.Lazy; | ||
| 22 | +import org.springframework.stereotype.Component; | ||
| 23 | + | ||
| 24 | +import javax.annotation.Resource; | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * @Description: 用户登录鉴权和获取用户授权 | ||
| 29 | + * @Author: Scott | ||
| 30 | + * @Date: 2019-4-23 8:13 | ||
| 31 | + * @Version: 1.1 | ||
| 32 | + */ | ||
| 33 | +@Component | ||
| 34 | +@Slf4j | ||
| 35 | +public class ShiroRealm extends AuthorizingRealm { | ||
| 36 | + @Lazy | ||
| 37 | + @Resource | ||
| 38 | + private CommonAPI commonAPI; | ||
| 39 | + | ||
| 40 | + @Lazy | ||
| 41 | + @Resource | ||
| 42 | + private RedisUtil redisUtil; | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * 必须重写此方法,不然Shiro会报错 | ||
| 46 | + */ | ||
| 47 | + @Override | ||
| 48 | + public boolean supports(AuthenticationToken token) { | ||
| 49 | + return token instanceof JwtToken; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 权限信息认证(包括角色以及权限)是用户访问controller的时候才进行验证(redis存储的此处权限信息) | ||
| 54 | + * 触发检测用户权限时才会调用此方法,例如checkRole,checkPermission | ||
| 55 | + * | ||
| 56 | + * @param principals 身份信息 | ||
| 57 | + * @return AuthorizationInfo 权限信息 | ||
| 58 | + */ | ||
| 59 | + @Override | ||
| 60 | + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { | ||
| 61 | + log.info("===============Shiro权限认证开始============ [ roles、permissions]=========="); | ||
| 62 | + String username = null; | ||
| 63 | + if (principals != null) { | ||
| 64 | + LoginUser sysUser = (LoginUser) principals.getPrimaryPrincipal(); | ||
| 65 | + username = sysUser.getUsername(); | ||
| 66 | + } | ||
| 67 | + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); | ||
| 68 | + | ||
| 69 | + // 设置用户拥有的角色集合,比如“admin,test” | ||
| 70 | + Set<String> roleSet = commonAPI.queryUserRoles(username); | ||
| 71 | + System.out.println(roleSet.toString()); | ||
| 72 | + info.setRoles(roleSet); | ||
| 73 | + | ||
| 74 | + // 设置用户拥有的权限集合,比如“sys:role:add,sys:user:add” | ||
| 75 | + Set<String> permissionSet = commonAPI.queryUserAuths(username); | ||
| 76 | + info.addStringPermissions(permissionSet); | ||
| 77 | + System.out.println(permissionSet); | ||
| 78 | + log.info("===============Shiro权限认证成功=============="); | ||
| 79 | + return info; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * 用户信息认证是在用户进行登录的时候进行验证(不存redis) | ||
| 84 | + * 也就是说验证用户输入的账号和密码是否正确,错误抛出异常 | ||
| 85 | + * | ||
| 86 | + * @param auth 用户登录的账号密码信息 | ||
| 87 | + * @return 返回封装了用户信息的 AuthenticationInfo 实例 | ||
| 88 | + * @throws AuthenticationException | ||
| 89 | + */ | ||
| 90 | + @Override | ||
| 91 | + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { | ||
| 92 | + log.debug("===============Shiro身份认证开始============doGetAuthenticationInfo=========="); | ||
| 93 | + String token = (String) auth.getCredentials(); | ||
| 94 | + if (token == null) { | ||
| 95 | + log.info("————————身份认证失败——————————IP地址: "+ oConvertUtils.getIpAddrByRequest(SpringContextUtils.getHttpServletRequest())); | ||
| 96 | + throw new AuthenticationException("token为空!"); | ||
| 97 | + } | ||
| 98 | + // 校验token有效性 | ||
| 99 | + LoginUser loginUser = this.checkUserTokenIsEffect(token); | ||
| 100 | + return new SimpleAuthenticationInfo(loginUser, token, getName()); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * 校验token的有效性 | ||
| 105 | + * | ||
| 106 | + * @param token | ||
| 107 | + */ | ||
| 108 | + public LoginUser checkUserTokenIsEffect(String token) throws AuthenticationException { | ||
| 109 | + // 解密获得username,用于和数据库进行对比 | ||
| 110 | + String username = JwtUtil.getUsername(token); | ||
| 111 | + if (username == null) { | ||
| 112 | + throw new AuthenticationException("token非法无效!"); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + // 查询用户信息 | ||
| 116 | + log.debug("———校验token是否有效————checkUserTokenIsEffect——————— "+ token); | ||
| 117 | + LoginUser loginUser = commonAPI.getUserByName(username); | ||
| 118 | + if (loginUser == null) { | ||
| 119 | + throw new AuthenticationException("用户不存在!"); | ||
| 120 | + } | ||
| 121 | + // 判断用户状态 | ||
| 122 | + if (loginUser.getStatus() != 1) { | ||
| 123 | + throw new AuthenticationException("账号已被锁定,请联系管理员!"); | ||
| 124 | + } | ||
| 125 | + // 校验token是否超时失效 & 或者账号密码是否错误 | ||
| 126 | + if (!jwtTokenRefresh(token, username, loginUser.getPassword())) { | ||
| 127 | + throw new AuthenticationException("Token失效,请重新登录!"); | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + return loginUser; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + /** | ||
| 134 | + * JWTToken刷新生命周期 (实现: 用户在线操作不掉线功能) | ||
| 135 | + * 1、登录成功后将用户的JWT生成的Token作为k、v存储到cache缓存里面(这时候k、v值一样),缓存有效期设置为Jwt有效时间的2倍 | ||
| 136 | + * 2、当该用户再次请求时,通过JWTFilter层层校验之后会进入到doGetAuthenticationInfo进行身份验证 | ||
| 137 | + * 3、当该用户这次请求jwt生成的token值已经超时,但该token对应cache中的k还是存在,则表示该用户一直在操作只是JWT的token失效了,程序会给token对应的k映射的v值重新生成JWTToken并覆盖v值,该缓存生命周期重新计算 | ||
| 138 | + * 4、当该用户这次请求jwt在生成的token值已经超时,并在cache中不存在对应的k,则表示该用户账户空闲超时,返回用户信息已失效,请重新登录。 | ||
| 139 | + * 注意: 前端请求Header中设置Authorization保持不变,校验有效性以缓存中的token为准。 | ||
| 140 | + * 用户过期时间 = Jwt有效时间 * 2。 | ||
| 141 | + * | ||
| 142 | + * @param userName | ||
| 143 | + * @param passWord | ||
| 144 | + * @return | ||
| 145 | + */ | ||
| 146 | + public boolean jwtTokenRefresh(String token, String userName, String passWord) { | ||
| 147 | + String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token)); | ||
| 148 | + if (oConvertUtils.isNotEmpty(cacheToken)) { | ||
| 149 | + // 校验token有效性 | ||
| 150 | + if (!JwtUtil.verify(cacheToken, userName, passWord)) { | ||
| 151 | + String newAuthorization = JwtUtil.sign(userName, passWord); | ||
| 152 | + // 设置超时时间 | ||
| 153 | + redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, newAuthorization); | ||
| 154 | + redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME *2 / 1000); | ||
| 155 | + log.debug("——————————用户在线操作,更新token保证不掉线—————————jwtTokenRefresh——————— "+ token); | ||
| 156 | + } | ||
| 157 | + //update-begin--Author:scott Date:20191005 for:解决每次请求,都重写redis中 token缓存问题 | ||
| 158 | +// else { | ||
| 159 | +// // 设置超时时间 | ||
| 160 | +// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, cacheToken); | ||
| 161 | +// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000); | ||
| 162 | +// } | ||
| 163 | + //update-end--Author:scott Date:20191005 for:解决每次请求,都重写redis中 token缓存问题 | ||
| 164 | + return true; | ||
| 165 | + } | ||
| 166 | + return false; | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + /** | ||
| 170 | + * 清除当前用户的权限认证缓存 | ||
| 171 | + * | ||
| 172 | + * @param principals 权限信息 | ||
| 173 | + */ | ||
| 174 | + @Override | ||
| 175 | + public void clearCache(PrincipalCollection principals) { | ||
| 176 | + super.clearCache(principals); | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/CustomShiroFilterFactoryBean.java
0 → 100644
| 1 | +package org.jeecg.config.shiro.filters; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; | ||
| 5 | +import org.apache.shiro.web.filter.InvalidRequestFilter; | ||
| 6 | +import org.apache.shiro.web.filter.mgt.DefaultFilter; | ||
| 7 | +import org.apache.shiro.web.filter.mgt.FilterChainManager; | ||
| 8 | +import org.apache.shiro.web.filter.mgt.FilterChainResolver; | ||
| 9 | +import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; | ||
| 10 | +import org.apache.shiro.web.mgt.WebSecurityManager; | ||
| 11 | +import org.apache.shiro.web.servlet.AbstractShiroFilter; | ||
| 12 | +import org.apache.shiro.mgt.SecurityManager; | ||
| 13 | +import org.springframework.beans.factory.BeanInitializationException; | ||
| 14 | + | ||
| 15 | +import javax.servlet.Filter; | ||
| 16 | +import java.util.Map; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * 自定义ShiroFilterFactoryBean解决资源中文路径问题 | ||
| 20 | + */ | ||
| 21 | +@Slf4j | ||
| 22 | +public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean { | ||
| 23 | + @Override | ||
| 24 | + public Class getObjectType() { | ||
| 25 | + return MySpringShiroFilter.class; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + @Override | ||
| 29 | + protected AbstractShiroFilter createInstance() throws Exception { | ||
| 30 | + | ||
| 31 | + SecurityManager securityManager = getSecurityManager(); | ||
| 32 | + if (securityManager == null) { | ||
| 33 | + String msg = "SecurityManager property must be set."; | ||
| 34 | + throw new BeanInitializationException(msg); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + if (!(securityManager instanceof WebSecurityManager)) { | ||
| 38 | + String msg = "The security manager does not implement the WebSecurityManager interface."; | ||
| 39 | + throw new BeanInitializationException(msg); | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + FilterChainManager manager = createFilterChainManager(); | ||
| 43 | + //Expose the constructed FilterChainManager by first wrapping it in a | ||
| 44 | + // FilterChainResolver implementation. The AbstractShiroFilter implementations | ||
| 45 | + // do not know about FilterChainManagers - only resolvers: | ||
| 46 | + PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver(); | ||
| 47 | + chainResolver.setFilterChainManager(manager); | ||
| 48 | + | ||
| 49 | + Map<String, Filter> filterMap = manager.getFilters(); | ||
| 50 | + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); | ||
| 51 | + if (invalidRequestFilter instanceof InvalidRequestFilter) { | ||
| 52 | + //此处是关键,设置false跳过URL携带中文400,servletPath中文校验bug | ||
| 53 | + ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); | ||
| 54 | + } | ||
| 55 | + //Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built | ||
| 56 | + //FilterChainResolver. It doesn't matter that the instance is an anonymous inner class | ||
| 57 | + //here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts | ||
| 58 | + //injection of the SecurityManager and FilterChainResolver: | ||
| 59 | + return new MySpringShiroFilter((WebSecurityManager) securityManager, chainResolver); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + private static final class MySpringShiroFilter extends AbstractShiroFilter { | ||
| 63 | + protected MySpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) { | ||
| 64 | + if (webSecurityManager == null) { | ||
| 65 | + throw new IllegalArgumentException("WebSecurityManager property cannot be null."); | ||
| 66 | + } else { | ||
| 67 | + this.setSecurityManager(webSecurityManager); | ||
| 68 | + if (resolver != null) { | ||
| 69 | + this.setFilterChainResolver(resolver); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | +} | ||
| 0 | \ No newline at end of file | 77 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/JwtFilter.java
0 → 100644
| 1 | +package org.jeecg.config.shiro.filters; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.apache.shiro.authc.AuthenticationException; | ||
| 5 | +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; | ||
| 6 | +import org.jeecg.common.constant.CommonConstant; | ||
| 7 | +import org.jeecg.config.mybatis.TenantContext; | ||
| 8 | +import org.jeecg.config.shiro.JwtToken; | ||
| 9 | +import org.springframework.http.HttpStatus; | ||
| 10 | +import org.springframework.web.bind.annotation.RequestMethod; | ||
| 11 | + | ||
| 12 | +import javax.servlet.ServletRequest; | ||
| 13 | +import javax.servlet.ServletResponse; | ||
| 14 | +import javax.servlet.http.HttpServletRequest; | ||
| 15 | +import javax.servlet.http.HttpServletResponse; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * @Description: 鉴权登录拦截器 | ||
| 19 | + * @Author: Scott | ||
| 20 | + * @Date: 2018/10/7 | ||
| 21 | + **/ | ||
| 22 | +@Slf4j | ||
| 23 | +public class JwtFilter extends BasicHttpAuthenticationFilter { | ||
| 24 | + | ||
| 25 | + private boolean allowOrigin = true; | ||
| 26 | + | ||
| 27 | + public JwtFilter(){} | ||
| 28 | + public JwtFilter(boolean allowOrigin){ | ||
| 29 | + this.allowOrigin = allowOrigin; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 执行登录认证 | ||
| 34 | + * | ||
| 35 | + * @param request | ||
| 36 | + * @param response | ||
| 37 | + * @param mappedValue | ||
| 38 | + * @return | ||
| 39 | + */ | ||
| 40 | + @Override | ||
| 41 | + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { | ||
| 42 | + try { | ||
| 43 | + executeLogin(request, response); | ||
| 44 | + return true; | ||
| 45 | + } catch (Exception e) { | ||
| 46 | + throw new AuthenticationException("Token失效,请重新登录", e); | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * | ||
| 52 | + */ | ||
| 53 | + @Override | ||
| 54 | + protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { | ||
| 55 | + HttpServletRequest httpServletRequest = (HttpServletRequest) request; | ||
| 56 | + String token = httpServletRequest.getHeader(CommonConstant.X_ACCESS_TOKEN); | ||
| 57 | + // update-begin--Author:lvdandan Date:20210105 for:JT-355 OA聊天添加token验证,获取token参数 | ||
| 58 | + if(token == null){ | ||
| 59 | + token = httpServletRequest.getParameter("token"); | ||
| 60 | + } | ||
| 61 | + // update-end--Author:lvdandan Date:20210105 for:JT-355 OA聊天添加token验证,获取token参数 | ||
| 62 | + | ||
| 63 | + JwtToken jwtToken = new JwtToken(token); | ||
| 64 | + // 提交给realm进行登入,如果错误他会抛出异常并被捕获 | ||
| 65 | + getSubject(request, response).login(jwtToken); | ||
| 66 | + // 如果没有抛出异常则代表登入成功,返回true | ||
| 67 | + return true; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * 对跨域提供支持 | ||
| 72 | + */ | ||
| 73 | + @Override | ||
| 74 | + protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { | ||
| 75 | + HttpServletRequest httpServletRequest = (HttpServletRequest) request; | ||
| 76 | + HttpServletResponse httpServletResponse = (HttpServletResponse) response; | ||
| 77 | + if(allowOrigin){ | ||
| 78 | + httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin")); | ||
| 79 | + httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE"); | ||
| 80 | + httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers")); | ||
| 81 | + //update-begin-author:scott date:20200907 for:issues/I1TAAP 前后端分离,shiro过滤器配置引起的跨域问题 | ||
| 82 | + // 是否允许发送Cookie,默认Cookie不包括在CORS请求之中。设为true时,表示服务器允许Cookie包含在请求中。 | ||
| 83 | + httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); | ||
| 84 | + //update-end-author:scott date:20200907 for:issues/I1TAAP 前后端分离,shiro过滤器配置引起的跨域问题 | ||
| 85 | + } | ||
| 86 | + // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态 | ||
| 87 | + if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) { | ||
| 88 | + httpServletResponse.setStatus(HttpStatus.OK.value()); | ||
| 89 | + return false; | ||
| 90 | + } | ||
| 91 | + //update-begin-author:taoyan date:20200708 for:多租户用到 | ||
| 92 | + String tenant_id = httpServletRequest.getHeader(CommonConstant.TENANT_ID); | ||
| 93 | + TenantContext.setTenant(tenant_id); | ||
| 94 | + //update-end-author:taoyan date:20200708 for:多租户用到 | ||
| 95 | + return super.preHandle(request, response); | ||
| 96 | + } | ||
| 97 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/filters/ResourceCheckFilter.java
0 → 100644
| 1 | +package org.jeecg.config.shiro.filters; | ||
| 2 | + | ||
| 3 | +import javax.servlet.ServletRequest; | ||
| 4 | +import javax.servlet.ServletResponse; | ||
| 5 | +import javax.servlet.http.HttpServletRequest; | ||
| 6 | +import javax.servlet.http.HttpServletResponse; | ||
| 7 | +import org.apache.shiro.subject.Subject; | ||
| 8 | +import org.apache.shiro.web.filter.AccessControlFilter; | ||
| 9 | +import lombok.extern.slf4j.Slf4j; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * @Author Scott | ||
| 13 | + * @create 2019-02-01 15:56 | ||
| 14 | + * @desc 鉴权请求URL访问权限拦截器 | ||
| 15 | + */ | ||
| 16 | +@Slf4j | ||
| 17 | +public class ResourceCheckFilter extends AccessControlFilter { | ||
| 18 | + | ||
| 19 | + private String errorUrl; | ||
| 20 | + | ||
| 21 | + public String getErrorUrl() { | ||
| 22 | + return errorUrl; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public void setErrorUrl(String errorUrl) { | ||
| 26 | + this.errorUrl = errorUrl; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 表示是否允许访问 ,如果允许访问返回true,否则false; | ||
| 31 | + * | ||
| 32 | + * @param servletRequest | ||
| 33 | + * @param servletResponse | ||
| 34 | + * @param o 表示写在拦截器中括号里面的字符串 mappedValue 就是 [urls] 配置中拦截器参数部分 | ||
| 35 | + * @return | ||
| 36 | + * @throws Exception | ||
| 37 | + */ | ||
| 38 | + @Override | ||
| 39 | + protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { | ||
| 40 | + Subject subject = getSubject(servletRequest, servletResponse); | ||
| 41 | + String url = getPathWithinApplication(servletRequest); | ||
| 42 | + log.info("当前用户正在访问的 url => " + url); | ||
| 43 | + return subject.isPermitted(url); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * onAccessDenied:表示当访问拒绝时是否已经处理了; 如果返回 true 表示需要继续处理; 如果返回 false | ||
| 48 | + * 表示该拦截器实例已经处理了,将直接返回即可。 | ||
| 49 | + * | ||
| 50 | + * @param servletRequest | ||
| 51 | + * @param servletResponse | ||
| 52 | + * @return | ||
| 53 | + * @throws Exception | ||
| 54 | + */ | ||
| 55 | + @Override | ||
| 56 | + protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { | ||
| 57 | + log.info("当 isAccessAllowed 返回 false 的时候,才会执行 method onAccessDenied "); | ||
| 58 | + | ||
| 59 | + HttpServletRequest request = (HttpServletRequest) servletRequest; | ||
| 60 | + HttpServletResponse response = (HttpServletResponse) servletResponse; | ||
| 61 | + response.sendRedirect(request.getContextPath() + this.errorUrl); | ||
| 62 | + | ||
| 63 | + // 返回 false 表示已经处理,例如页面跳转啥的,表示不在走以下的拦截器了(如果还有配置的话) | ||
| 64 | + return false; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | +} | ||
| 0 | \ No newline at end of file | 68 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthConfiguration.java
0 → 100644
| 1 | +package org.jeecg.config.sign.interceptor; | ||
| 2 | + | ||
| 3 | +import org.springframework.context.annotation.Bean; | ||
| 4 | +import org.springframework.context.annotation.Configuration; | ||
| 5 | +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
| 6 | +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * online 拦截器配置 | ||
| 10 | + */ | ||
| 11 | +@Configuration | ||
| 12 | +public class SignAuthConfiguration implements WebMvcConfigurer { | ||
| 13 | + | ||
| 14 | + @Bean | ||
| 15 | + public SignAuthInterceptor signAuthInterceptor() { | ||
| 16 | + return new SignAuthInterceptor(); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + @Override | ||
| 20 | + public void addInterceptors(InterceptorRegistry registry) { | ||
| 21 | + String[] inculudes = new String[] {"/sys/dict/getDictItems/*", "/sys/dict/loadDict/*", | ||
| 22 | + "/sys/dict/loadDictOrderByValue/*", "/sys/dict/loadDictItem/*", "/sys/dict/loadTreeData", | ||
| 23 | + "/sys/api/queryTableDictItemsByCode", "/sys/api/queryFilterTableDictInfo", "/sys/api/queryTableDictByKeys", | ||
| 24 | + "/sys/api/translateDictFromTable", "/sys/api/translateDictFromTableByKeys"}; | ||
| 25 | + registry.addInterceptor(signAuthInterceptor()).addPathPatterns(inculudes); | ||
| 26 | + } | ||
| 27 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/interceptor/SignAuthInterceptor.java
0 → 100644
| 1 | +package org.jeecg.config.sign.interceptor; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import java.io.PrintWriter; | ||
| 5 | +import java.util.SortedMap; | ||
| 6 | + | ||
| 7 | +import javax.servlet.http.HttpServletRequest; | ||
| 8 | +import javax.servlet.http.HttpServletResponse; | ||
| 9 | + | ||
| 10 | +import org.jeecg.common.api.vo.Result; | ||
| 11 | +import org.jeecg.common.util.DateUtils; | ||
| 12 | +import org.jeecg.config.sign.util.BodyReaderHttpServletRequestWrapper; | ||
| 13 | +import org.jeecg.config.sign.util.HttpUtils; | ||
| 14 | +import org.jeecg.config.sign.util.SignUtil; | ||
| 15 | +import org.springframework.web.servlet.HandlerInterceptor; | ||
| 16 | + | ||
| 17 | +import com.alibaba.fastjson.JSON; | ||
| 18 | + | ||
| 19 | +import lombok.extern.slf4j.Slf4j; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * 签名拦截器 | ||
| 23 | + * @author qinfeng | ||
| 24 | + */ | ||
| 25 | +@Slf4j | ||
| 26 | +public class SignAuthInterceptor implements HandlerInterceptor { | ||
| 27 | + /** | ||
| 28 | + * 5分钟有效期 | ||
| 29 | + */ | ||
| 30 | + private final static long MAX_EXPIRE = 5 * 60; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | ||
| 34 | + log.debug("request URI = " + request.getRequestURI()); | ||
| 35 | + HttpServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(request); | ||
| 36 | + //获取全部参数(包括URL和body上的) | ||
| 37 | + SortedMap<String, String> allParams = HttpUtils.getAllParams(requestWrapper); | ||
| 38 | + //对参数进行签名验证 | ||
| 39 | + String headerSign = request.getHeader("X-Sign"); | ||
| 40 | + String timesTamp = request.getHeader("X-TIMESTAMP"); | ||
| 41 | + | ||
| 42 | + //1.校验时间有消息 | ||
| 43 | + try { | ||
| 44 | + DateUtils.parseDate(timesTamp, "yyyyMMddHHmmss"); | ||
| 45 | + } catch (Exception e) { | ||
| 46 | + throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP格式必须为:yyyyMMddHHmmss"); | ||
| 47 | + } | ||
| 48 | + Long clientTimestamp = Long.parseLong(timesTamp); | ||
| 49 | + //判断时间戳 timestamp=201808091113 | ||
| 50 | + if ((DateUtils.getCurrentTimestamp() - clientTimestamp) > MAX_EXPIRE) { | ||
| 51 | + throw new IllegalArgumentException("签名验证失败:X-TIMESTAMP已过期"); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + //2.校验签名 | ||
| 55 | + boolean isSigned = SignUtil.verifySign(allParams,headerSign); | ||
| 56 | + | ||
| 57 | + if (isSigned) { | ||
| 58 | + log.debug("Sign 签名通过!Header Sign : {}",headerSign); | ||
| 59 | + return true; | ||
| 60 | + } else { | ||
| 61 | + log.error("request URI = " + request.getRequestURI()); | ||
| 62 | + log.error("Sign 签名校验失败!Header Sign : {}",headerSign); | ||
| 63 | +// //打印日志参数 | ||
| 64 | +// Set<String> keySet = allParams.keySet(); | ||
| 65 | +// Iterator<String> paramIt = keySet.iterator(); | ||
| 66 | +// while(paramIt.hasNext()){ | ||
| 67 | +// String pkey = paramIt.next(); | ||
| 68 | +// String pval = allParams.get(pkey); | ||
| 69 | +// log.error(" ["+pkey+":"+pval+"] "); | ||
| 70 | +// } | ||
| 71 | + | ||
| 72 | + //校验失败返回前端 | ||
| 73 | + response.setCharacterEncoding("UTF-8"); | ||
| 74 | + response.setContentType("application/json; charset=utf-8"); | ||
| 75 | + PrintWriter out = response.getWriter(); | ||
| 76 | + Result<?> result = Result.error("Sign签名校验失败!"); | ||
| 77 | + out.print(JSON.toJSON(result)); | ||
| 78 | + return false; | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/BodyReaderHttpServletRequestWrapper.java
0 → 100644
| 1 | +package org.jeecg.config.sign.util; | ||
| 2 | + | ||
| 3 | +import javax.servlet.ReadListener; | ||
| 4 | +import javax.servlet.ServletInputStream; | ||
| 5 | +import javax.servlet.ServletRequest; | ||
| 6 | +import javax.servlet.http.HttpServletRequest; | ||
| 7 | +import javax.servlet.http.HttpServletRequestWrapper; | ||
| 8 | +import java.io.*; | ||
| 9 | +import java.nio.charset.Charset; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 保存过滤器里面的流 | ||
| 13 | + * | ||
| 14 | + * @author show | ||
| 15 | + * @date 10:03 2019/5/30 | ||
| 16 | + */ | ||
| 17 | +public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { | ||
| 18 | + | ||
| 19 | + private final byte[] body; | ||
| 20 | + | ||
| 21 | + public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) { | ||
| 22 | + | ||
| 23 | + super(request); | ||
| 24 | + String sessionStream = getBodyString(request); | ||
| 25 | + body = sessionStream.getBytes(Charset.forName("UTF-8")); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 获取请求Body | ||
| 30 | + * | ||
| 31 | + * @param request | ||
| 32 | + * @return | ||
| 33 | + */ | ||
| 34 | + public String getBodyString(final ServletRequest request) { | ||
| 35 | + | ||
| 36 | + StringBuilder sb = new StringBuilder(); | ||
| 37 | + try (InputStream inputStream = cloneInputStream(request.getInputStream()); | ||
| 38 | + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")))) { | ||
| 39 | + String line; | ||
| 40 | + while ((line = reader.readLine()) != null) { | ||
| 41 | + sb.append(line); | ||
| 42 | + } | ||
| 43 | + } catch (IOException e) { | ||
| 44 | + e.printStackTrace(); | ||
| 45 | + } | ||
| 46 | + return sb.toString(); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + /** | ||
| 50 | + * Description: 复制输入流</br> | ||
| 51 | + * | ||
| 52 | + * @param inputStream | ||
| 53 | + * @return</br> | ||
| 54 | + */ | ||
| 55 | + public InputStream cloneInputStream(ServletInputStream inputStream) { | ||
| 56 | + | ||
| 57 | + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); | ||
| 58 | + byte[] buffer = new byte[1024]; | ||
| 59 | + int len; | ||
| 60 | + try { | ||
| 61 | + while ((len = inputStream.read(buffer)) > -1) { | ||
| 62 | + byteArrayOutputStream.write(buffer, 0, len); | ||
| 63 | + } | ||
| 64 | + byteArrayOutputStream.flush(); | ||
| 65 | + } catch (IOException e) { | ||
| 66 | + e.printStackTrace(); | ||
| 67 | + } | ||
| 68 | + return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + @Override | ||
| 72 | + public BufferedReader getReader() { | ||
| 73 | + | ||
| 74 | + return new BufferedReader(new InputStreamReader(getInputStream())); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public ServletInputStream getInputStream() { | ||
| 79 | + | ||
| 80 | + final ByteArrayInputStream bais = new ByteArrayInputStream(body); | ||
| 81 | + return new ServletInputStream() { | ||
| 82 | + | ||
| 83 | + @Override | ||
| 84 | + public int read() { | ||
| 85 | + | ||
| 86 | + return bais.read(); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public boolean isFinished() { | ||
| 91 | + | ||
| 92 | + return false; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public boolean isReady() { | ||
| 97 | + | ||
| 98 | + return false; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Override | ||
| 102 | + public void setReadListener(ReadListener readListener) { | ||
| 103 | + | ||
| 104 | + } | ||
| 105 | + }; | ||
| 106 | + } | ||
| 107 | +} | ||
| 0 | \ No newline at end of file | 108 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/HttpUtils.java
0 → 100644
| 1 | +package org.jeecg.config.sign.util; | ||
| 2 | + | ||
| 3 | +import java.io.BufferedReader; | ||
| 4 | +import java.io.IOException; | ||
| 5 | +import java.io.InputStreamReader; | ||
| 6 | +import java.io.UnsupportedEncodingException; | ||
| 7 | +import java.net.URLDecoder; | ||
| 8 | +import java.util.HashMap; | ||
| 9 | +import java.util.Map; | ||
| 10 | +import java.util.SortedMap; | ||
| 11 | +import java.util.TreeMap; | ||
| 12 | + | ||
| 13 | +import javax.servlet.http.HttpServletRequest; | ||
| 14 | + | ||
| 15 | +import org.jeecg.common.util.oConvertUtils; | ||
| 16 | +import org.springframework.http.HttpMethod; | ||
| 17 | + | ||
| 18 | +import com.alibaba.fastjson.JSONObject; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * http 工具类 获取请求中的参数 | ||
| 22 | + * | ||
| 23 | + * @author show | ||
| 24 | + * @date 14:23 2019/5/29 | ||
| 25 | + */ | ||
| 26 | +public class HttpUtils { | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 将URL的参数和body参数合并 | ||
| 30 | + * | ||
| 31 | + * @author show | ||
| 32 | + * @date 14:24 2019/5/29 | ||
| 33 | + * @param request | ||
| 34 | + */ | ||
| 35 | + public static SortedMap<String, String> getAllParams(HttpServletRequest request) throws IOException { | ||
| 36 | + | ||
| 37 | + SortedMap<String, String> result = new TreeMap<>(); | ||
| 38 | + // 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username | ||
| 39 | + String pathVariable = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/")+1); | ||
| 40 | + if(pathVariable.contains(",")){ | ||
| 41 | + result.put(SignUtil.xPathVariable,pathVariable); | ||
| 42 | + } | ||
| 43 | + // 获取URL上的参数 | ||
| 44 | + Map<String, String> urlParams = getUrlParams(request); | ||
| 45 | + for (Map.Entry entry : urlParams.entrySet()) { | ||
| 46 | + result.put((String)entry.getKey(), (String)entry.getValue()); | ||
| 47 | + } | ||
| 48 | + Map<String, String> allRequestParam = new HashMap<>(16); | ||
| 49 | + // get请求不需要拿body参数 | ||
| 50 | + if (!HttpMethod.GET.name().equals(request.getMethod())) { | ||
| 51 | + allRequestParam = getAllRequestParam(request); | ||
| 52 | + } | ||
| 53 | + // 将URL的参数和body参数进行合并 | ||
| 54 | + if (allRequestParam != null) { | ||
| 55 | + for (Map.Entry entry : allRequestParam.entrySet()) { | ||
| 56 | + result.put((String)entry.getKey(), (String)entry.getValue()); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + return result; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + /** | ||
| 63 | + * 获取 Body 参数 | ||
| 64 | + * | ||
| 65 | + * @author show | ||
| 66 | + * @date 15:04 2019/5/30 | ||
| 67 | + * @param request | ||
| 68 | + */ | ||
| 69 | + public static Map<String, String> getAllRequestParam(final HttpServletRequest request) throws IOException { | ||
| 70 | + | ||
| 71 | + BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); | ||
| 72 | + String str = ""; | ||
| 73 | + StringBuilder wholeStr = new StringBuilder(); | ||
| 74 | + // 一行一行的读取body体里面的内容; | ||
| 75 | + while ((str = reader.readLine()) != null) { | ||
| 76 | + wholeStr.append(str); | ||
| 77 | + } | ||
| 78 | + // 转化成json对象 | ||
| 79 | + return JSONObject.parseObject(wholeStr.toString(), Map.class); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + /** | ||
| 83 | + * 将URL请求参数转换成Map | ||
| 84 | + * | ||
| 85 | + * @author show | ||
| 86 | + * @param request | ||
| 87 | + */ | ||
| 88 | + public static Map<String, String> getUrlParams(HttpServletRequest request) { | ||
| 89 | + Map<String, String> result = new HashMap<>(16); | ||
| 90 | + if(oConvertUtils.isEmpty(request.getQueryString())){ | ||
| 91 | + return result; | ||
| 92 | + } | ||
| 93 | + String param = ""; | ||
| 94 | + try { | ||
| 95 | + param = URLDecoder.decode(request.getQueryString(), "utf-8"); | ||
| 96 | + } catch (UnsupportedEncodingException e) { | ||
| 97 | + e.printStackTrace(); | ||
| 98 | + } | ||
| 99 | + String[] params = param.split("&"); | ||
| 100 | + for (String s : params) { | ||
| 101 | + int index = s.indexOf("="); | ||
| 102 | + result.put(s.substring(0, index), s.substring(index + 1)); | ||
| 103 | + } | ||
| 104 | + return result; | ||
| 105 | + } | ||
| 106 | +} | ||
| 0 | \ No newline at end of file | 107 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
0 → 100644
| 1 | +package org.jeecg.config.sign.util; | ||
| 2 | + | ||
| 3 | +import com.alibaba.fastjson.JSONObject; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.springframework.util.DigestUtils; | ||
| 6 | +import org.springframework.util.StringUtils; | ||
| 7 | + | ||
| 8 | +import java.util.SortedMap; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 签名工具类 | ||
| 12 | + * | ||
| 13 | + * @author show | ||
| 14 | + * @date 10:01 2019/5/30 | ||
| 15 | + */ | ||
| 16 | +@Slf4j | ||
| 17 | +public class SignUtil { | ||
| 18 | + //签名密钥串(前后端要一致,正式发布请自行修改) | ||
| 19 | + private static final String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | ||
| 20 | + public static final String xPathVariable = "x-path-variable"; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * @param params | ||
| 24 | + * 所有的请求参数都会在这里进行排序加密 | ||
| 25 | + * @return 验证签名结果 | ||
| 26 | + */ | ||
| 27 | + public static boolean verifySign(SortedMap<String, String> params,String headerSign) { | ||
| 28 | + if (params == null || StringUtils.isEmpty(headerSign)) { | ||
| 29 | + return false; | ||
| 30 | + } | ||
| 31 | + // 把参数加密 | ||
| 32 | + String paramsSign = getParamsSign(params); | ||
| 33 | + log.info("Param Sign : {}", paramsSign); | ||
| 34 | + return !StringUtils.isEmpty(paramsSign) && headerSign.equals(paramsSign); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + /** | ||
| 38 | + * @param params | ||
| 39 | + * 所有的请求参数都会在这里进行排序加密 | ||
| 40 | + * @return 得到签名 | ||
| 41 | + */ | ||
| 42 | + public static String getParamsSign(SortedMap<String, String> params) { | ||
| 43 | + //去掉 Url 里的时间戳 | ||
| 44 | + params.remove("_t"); | ||
| 45 | + String paramsJsonStr = JSONObject.toJSONString(params); | ||
| 46 | + log.info("Param paramsJsonStr : {}", paramsJsonStr); | ||
| 47 | + return DigestUtils.md5DigestAsHex((paramsJsonStr+signatureSecret).getBytes()).toUpperCase(); | ||
| 48 | + } | ||
| 49 | +} | ||
| 0 | \ No newline at end of file | 50 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/thirdapp/ThirdAppConfig.java
0 → 100644
| 1 | +package org.jeecg.config.thirdapp; | ||
| 2 | + | ||
| 3 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 第三方App对接配置 | ||
| 9 | + */ | ||
| 10 | +@Configuration | ||
| 11 | +public class ThirdAppConfig { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 钉钉 | ||
| 15 | + */ | ||
| 16 | + public final static String DINGTALK = "DINGTALK"; | ||
| 17 | + /** | ||
| 18 | + * 企业微信 | ||
| 19 | + */ | ||
| 20 | + public final static String WECHAT_ENTERPRISE = "WECHAT_ENTERPRISE"; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 是否启用 第三方App对接 | ||
| 24 | + */ | ||
| 25 | + @Value("${third-app.enabled:false}") | ||
| 26 | + private boolean enabled; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 系统类型,目前支持:WECHAT_ENTERPRISE(企业微信);DINGTALK (钉钉) | ||
| 30 | + */ | ||
| 31 | + @Autowired | ||
| 32 | + private ThirdAppTypeConfig type; | ||
| 33 | + | ||
| 34 | + public boolean isEnabled() { | ||
| 35 | + return enabled; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public ThirdAppConfig setEnabled(boolean enabled) { | ||
| 39 | + this.enabled = enabled; | ||
| 40 | + return this; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 获取企业微信配置 | ||
| 45 | + */ | ||
| 46 | + public ThirdAppTypeItemVo getWechatEnterprise() { | ||
| 47 | + return this.type.getWECHAT_ENTERPRISE(); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 获取钉钉配置 | ||
| 52 | + */ | ||
| 53 | + public ThirdAppTypeItemVo getDingtalk() { | ||
| 54 | + return this.type.getDINGTALK(); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 获取企业微信是否启用 | ||
| 59 | + */ | ||
| 60 | + public boolean isWechatEnterpriseEnabled() { | ||
| 61 | + try { | ||
| 62 | + return this.enabled && this.getWechatEnterprise().isEnabled(); | ||
| 63 | + } catch (Exception e) { | ||
| 64 | + return false; | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + /** | ||
| 69 | + * 获取钉钉是否启用 | ||
| 70 | + */ | ||
| 71 | + public boolean isDingtalkEnabled() { | ||
| 72 | + try { | ||
| 73 | + return this.enabled && this.getDingtalk().isEnabled(); | ||
| 74 | + } catch (Exception e) { | ||
| 75 | + return false; | ||
| 76 | + } | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/thirdapp/ThirdAppTypeConfig.java
0 → 100644
| 1 | +package org.jeecg.config.thirdapp; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 第三方APP配置 | ||
| 9 | + * | ||
| 10 | + * @author sunjianlei | ||
| 11 | + */ | ||
| 12 | +@Data | ||
| 13 | +@Configuration | ||
| 14 | +@ConfigurationProperties(prefix = "third-app.type") | ||
| 15 | +public class ThirdAppTypeConfig { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 对应企业微信配置 | ||
| 19 | + */ | ||
| 20 | + private ThirdAppTypeItemVo WECHAT_ENTERPRISE; | ||
| 21 | + /** | ||
| 22 | + * 对应钉钉配置 | ||
| 23 | + */ | ||
| 24 | + private ThirdAppTypeItemVo DINGTALK; | ||
| 25 | + | ||
| 26 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/thirdapp/ThirdAppTypeItemVo.java
0 → 100644
| 1 | +package org.jeecg.config.thirdapp; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 第三方App对接 | ||
| 7 | + */ | ||
| 8 | +@Data | ||
| 9 | +public class ThirdAppTypeItemVo { | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * 是否启用 | ||
| 13 | + */ | ||
| 14 | + private boolean enabled; | ||
| 15 | + /** | ||
| 16 | + * 应用Key | ||
| 17 | + */ | ||
| 18 | + private String clientId; | ||
| 19 | + /** | ||
| 20 | + * 应用Secret | ||
| 21 | + */ | ||
| 22 | + private String clientSecret; | ||
| 23 | + /** | ||
| 24 | + * 应用ID | ||
| 25 | + */ | ||
| 26 | + private String agentId; | ||
| 27 | + /** | ||
| 28 | + * 目前仅企业微信用到:自建应用Secret | ||
| 29 | + */ | ||
| 30 | + private String agentAppSecret; | ||
| 31 | + | ||
| 32 | + public int getAgentIdInt() { | ||
| 33 | + return Integer.parseInt(agentId); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/BaseCommonMapper.java
0 → 100644
| 1 | +package org.jeecg.modules.base.mapper; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.annotation.SqlParser; | ||
| 4 | +import org.apache.ibatis.annotations.Param; | ||
| 5 | +import org.jeecg.common.api.dto.LogDTO; | ||
| 6 | + | ||
| 7 | +public interface BaseCommonMapper { | ||
| 8 | + | ||
| 9 | + /** | ||
| 10 | + * 保存日志 | ||
| 11 | + * @param dto | ||
| 12 | + */ | ||
| 13 | + @SqlParser(filter=true) | ||
| 14 | + void saveLog(@Param("dto")LogDTO dto); | ||
| 15 | + | ||
| 16 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/mapper/xml/BaseCommonMapper.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 3 | +<mapper namespace="org.jeecg.modules.base.mapper.BaseCommonMapper"> | ||
| 4 | + | ||
| 5 | + <!-- 保存日志11 --> | ||
| 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) | ||
| 8 | + values( | ||
| 9 | + #{dto.id,jdbcType=VARCHAR}, | ||
| 10 | + #{dto.logType,jdbcType=INTEGER}, | ||
| 11 | + #{dto.logContent,jdbcType=VARCHAR}, | ||
| 12 | + #{dto.method,jdbcType=VARCHAR}, | ||
| 13 | + #{dto.operateType,jdbcType=INTEGER}, | ||
| 14 | + #{dto.requestParam,jdbcType=VARCHAR}, | ||
| 15 | + #{dto.ip,jdbcType=VARCHAR}, | ||
| 16 | + #{dto.userid,jdbcType=VARCHAR}, | ||
| 17 | + #{dto.username,jdbcType=VARCHAR}, | ||
| 18 | + #{dto.costTime,jdbcType=BIGINT}, | ||
| 19 | + #{dto.createTime,jdbcType=TIMESTAMP} | ||
| 20 | + ) | ||
| 21 | + </insert> | ||
| 22 | + | ||
| 23 | +</mapper> | ||
| 0 | \ No newline at end of file | 24 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/BaseCommonService.java
0 → 100644
| 1 | +package org.jeecg.modules.base.service; | ||
| 2 | + | ||
| 3 | +import org.jeecg.common.api.dto.LogDTO; | ||
| 4 | +import org.jeecg.common.system.vo.LoginUser; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * common接口 | ||
| 8 | + */ | ||
| 9 | +public interface BaseCommonService { | ||
| 10 | + | ||
| 11 | + /** | ||
| 12 | + * 保存日志 | ||
| 13 | + * @param logDTO | ||
| 14 | + */ | ||
| 15 | + void addLog(LogDTO logDTO); | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 保存日志 | ||
| 19 | + * @param LogContent | ||
| 20 | + * @param logType | ||
| 21 | + * @param operateType | ||
| 22 | + * @param user | ||
| 23 | + */ | ||
| 24 | + void addLog(String LogContent, Integer logType, Integer operateType, LoginUser user); | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 保存日志 | ||
| 28 | + * @param LogContent | ||
| 29 | + * @param logType | ||
| 30 | + * @param operateType | ||
| 31 | + */ | ||
| 32 | + void addLog(String LogContent, Integer logType, Integer operateType); | ||
| 33 | + | ||
| 34 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/base/service/impl/BaseCommonServiceImpl.java
0 → 100644
| 1 | +package org.jeecg.modules.base.service.impl; | ||
| 2 | + | ||
| 3 | +import com.baomidou.mybatisplus.core.toolkit.IdWorker; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.apache.shiro.SecurityUtils; | ||
| 6 | +import org.jeecg.common.api.dto.LogDTO; | ||
| 7 | +import org.jeecg.common.constant.CacheConstant; | ||
| 8 | +import org.jeecg.modules.base.mapper.BaseCommonMapper; | ||
| 9 | +import org.jeecg.modules.base.service.BaseCommonService; | ||
| 10 | +import org.jeecg.common.system.vo.LoginUser; | ||
| 11 | +import org.jeecg.common.system.vo.SysPermissionDataRuleModel; | ||
| 12 | +import org.jeecg.common.system.vo.SysUserCacheInfo; | ||
| 13 | +import org.jeecg.common.util.IPUtils; | ||
| 14 | +import org.jeecg.common.util.SpringContextUtils; | ||
| 15 | +import org.jeecg.common.util.oConvertUtils; | ||
| 16 | +import org.springframework.cache.annotation.Cacheable; | ||
| 17 | +import org.springframework.stereotype.Service; | ||
| 18 | +import org.springframework.util.AntPathMatcher; | ||
| 19 | +import org.springframework.util.PathMatcher; | ||
| 20 | + | ||
| 21 | +import javax.annotation.Resource; | ||
| 22 | +import javax.servlet.http.HttpServletRequest; | ||
| 23 | +import java.util.*; | ||
| 24 | + | ||
| 25 | +@Service | ||
| 26 | +@Slf4j | ||
| 27 | +public class BaseCommonServiceImpl implements BaseCommonService { | ||
| 28 | + | ||
| 29 | + @Resource | ||
| 30 | + private BaseCommonMapper baseCommonMapper; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public void addLog(LogDTO logDTO) { | ||
| 34 | + if(oConvertUtils.isEmpty(logDTO.getId())){ | ||
| 35 | + logDTO.setId(String.valueOf(IdWorker.getId())); | ||
| 36 | + } | ||
| 37 | + //保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238 | ||
| 38 | + try { | ||
| 39 | + baseCommonMapper.saveLog(logDTO); | ||
| 40 | + } catch (Exception e) { | ||
| 41 | + log.warn(" LogContent length : "+logDTO.getLogContent().length()); | ||
| 42 | + log.warn(e.getMessage()); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @Override | ||
| 47 | + public void addLog(String logContent, Integer logType, Integer operatetype, LoginUser user) { | ||
| 48 | + LogDTO sysLog = new LogDTO(); | ||
| 49 | + sysLog.setId(String.valueOf(IdWorker.getId())); | ||
| 50 | + //注解上的描述,操作日志内容 | ||
| 51 | + sysLog.setLogContent(logContent); | ||
| 52 | + sysLog.setLogType(logType); | ||
| 53 | + sysLog.setOperateType(operatetype); | ||
| 54 | + try { | ||
| 55 | + //获取request | ||
| 56 | + HttpServletRequest request = SpringContextUtils.getHttpServletRequest(); | ||
| 57 | + //设置IP地址 | ||
| 58 | + sysLog.setIp(IPUtils.getIpAddr(request)); | ||
| 59 | + } catch (Exception e) { | ||
| 60 | + sysLog.setIp("127.0.0.1"); | ||
| 61 | + } | ||
| 62 | + //获取登录用户信息 | ||
| 63 | + if(user==null){ | ||
| 64 | + try { | ||
| 65 | + user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | ||
| 66 | + } catch (Exception e) { | ||
| 67 | + //e.printStackTrace(); | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + if(user!=null){ | ||
| 71 | + sysLog.setUserid(user.getUsername()); | ||
| 72 | + sysLog.setUsername(user.getRealname()); | ||
| 73 | + } | ||
| 74 | + sysLog.setCreateTime(new Date()); | ||
| 75 | + //保存日志(异常捕获处理,防止数据太大存储失败,导致业务失败)JT-238 | ||
| 76 | + try { | ||
| 77 | + baseCommonMapper.saveLog(sysLog); | ||
| 78 | + } catch (Exception e) { | ||
| 79 | + log.warn(" LogContent length : "+sysLog.getLogContent().length()); | ||
| 80 | + log.warn(e.getMessage()); | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + @Override | ||
| 85 | + public void addLog(String logContent, Integer logType, Integer operateType) { | ||
| 86 | + addLog(logContent, logType, operateType, null); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + | ||
| 90 | + | ||
| 91 | +} |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/resources/static/pca.json
0 → 100644
| 1 | +{ | ||
| 2 | + "86":{ | ||
| 3 | + "110000":"北京市", | ||
| 4 | + "120000":"天津市", | ||
| 5 | + "130000":"河北省", | ||
| 6 | + "140000":"山西省", | ||
| 7 | + "150000":"内蒙古自治区", | ||
| 8 | + "210000":"辽宁省", | ||
| 9 | + "220000":"吉林省", | ||
| 10 | + "230000":"黑龙江省", | ||
| 11 | + "310000":"上海市", | ||
| 12 | + "320000":"江苏省", | ||
| 13 | + "330000":"浙江省", | ||
| 14 | + "340000":"安徽省", | ||
| 15 | + "350000":"福建省", | ||
| 16 | + "360000":"江西省", | ||
| 17 | + "370000":"山东省", | ||
| 18 | + "410000":"河南省", | ||
| 19 | + "420000":"湖北省", | ||
| 20 | + "430000":"湖南省", | ||
| 21 | + "440000":"广东省", | ||
| 22 | + "450000":"广西壮族自治区", | ||
| 23 | + "460000":"海南省", | ||
| 24 | + "500000":"重庆市", | ||
| 25 | + "510000":"四川省", | ||
| 26 | + "520000":"贵州省", | ||
| 27 | + "530000":"云南省", | ||
| 28 | + "540000":"西藏自治区", | ||
| 29 | + "610000":"陕西省", | ||
| 30 | + "620000":"甘肃省", | ||
| 31 | + "630000":"青海省", | ||
| 32 | + "640000":"宁夏回族自治区", | ||
| 33 | + "650000":"新疆维吾尔自治区", | ||
| 34 | + "710000":"台湾省", | ||
| 35 | + "910000":"港澳" | ||
| 36 | + }, | ||
| 37 | + "110000":{"110100":"市辖区"}, | ||
| 38 | + "110100":{"110101":"东城区","110102":"西城区","110105":"朝阳区","110106":"丰台区","110107":"石景山区","110108":"海淀区","110109":"门头沟区","110111":"房山区","110112":"通州区","110113":"顺义区","110114":"昌平区","110115":"大兴区","110116":"怀柔区","110117":"平谷区","110118":"密云区","110119":"延庆区"}, | ||
| 39 | + "120000":{"120100":"市辖区"}, | ||
| 40 | + "120100":{"120101":"和平区","120102":"河东区","120103":"河西区","120104":"南开区","120105":"河北区","120106":"红桥区","120110":"东丽区","120111":"西青区","120112":"津南区","120113":"北辰区","120114":"武清区","120115":"宝坻区","120116":"滨海新区","120117":"宁河区","120118":"静海区","120119":"蓟州区"},"130000":{"130100":"石家庄市","130200":"唐山市","130300":"秦皇岛市","130400":"邯郸市","130500":"邢台市","130600":"保定市","130700":"张家口市","130800":"承德市","130900":"沧州市","131000":"廊坊市","131100":"衡水市","139001":"定州市","139002":"辛集市"},"130100":{"130102":"长安区","130104":"桥西区","130105":"新华区","130107":"井陉矿区","130108":"裕华区","130109":"藁城区","130110":"鹿泉区","130111":"栾城区","130121":"井陉县","130123":"正定县","130125":"行唐县","130126":"灵寿县","130127":"高邑县","130128":"深泽县","130129":"赞皇县","130130":"无极县","130131":"平山县","130132":"元氏县","130133":"赵县","130183":"晋州市","130184":"新乐市"},"130200":{"130202":"路南区","130203":"路北区","130204":"古冶区","130205":"开平区","130207":"丰南区","130208":"丰润区","130209":"曹妃甸区","130223":"滦县","130224":"滦南县","130225":"乐亭县","130227":"迁西县","130229":"玉田县","130281":"遵化市","130283":"迁安市"},"130300":{"130302":"海港区","130303":"山海关区","130304":"北戴河区","130306":"抚宁区","130321":"青龙满族自治县","130322":"昌黎县","130324":"卢龙县"},"130400":{"130402":"邯山区","130403":"丛台区","130404":"复兴区","130406":"峰峰矿区","130421":"邯郸县","130423":"临漳县","130424":"成安县","130425":"大名县","130426":"涉县","130427":"磁县","130428":"肥乡县","130429":"永年县","130430":"邱县","130431":"鸡泽县","130432":"广平县","130433":"馆陶县","130434":"魏县","130435":"曲周县","130481":"武安市"},"130500":{"130502":"桥东区","130503":"桥西区","130521":"邢台县","130522":"临城县","130523":"内丘县","130524":"柏乡县","130525":"隆尧县","130526":"任县","130527":"南和县","130528":"宁晋县","130529":"巨鹿县","130530":"新河县","130531":"广宗县","130532":"平乡县","130533":"威县","130534":"清河县","130535":"临西县","130581":"南宫市","130582":"沙河市"},"130600":{"130602":"竞秀区","130606":"莲池区","130607":"满城区","130608":"清苑区","130609":"徐水区","130623":"涞水县","130624":"阜平县","130626":"定兴县","130627":"唐县","130628":"高阳县","130629":"容城县","130630":"涞源县","130631":"望都县","130632":"安新县","130633":"易县","130634":"曲阳县","130635":"蠡县","130636":"顺平县","130637":"博野县","130638":"雄县","130681":"涿州市","130683":"安国市","130684":"高碑店市"},"130700":{"130702":"桥东区","130703":"桥西区","130705":"宣化区","130706":"下花园区","130708":"万全区","130709":"崇礼区","130722":"张北县","130723":"康保县","130724":"沽源县","130725":"尚义县","130726":"蔚县","130727":"阳原县","130728":"怀安县","130730":"怀来县","130731":"涿鹿县","130732":"赤城县"},"130800":{"130802":"双桥区","130803":"双滦区","130804":"鹰手营子矿区","130821":"承德县","130822":"兴隆县","130823":"平泉县","130824":"滦平县","130825":"隆化县","130826":"丰宁满族自治县","130827":"宽城满族自治县","130828":"围场满族蒙古族自治县"},"130900":{"130902":"新华区","130903":"运河区","130921":"沧县","130922":"青县","130923":"东光县","130924":"海兴县","130925":"盐山县","130926":"肃宁县","130927":"南皮县","130928":"吴桥县","130929":"献县","130930":"孟村回族自治县","130981":"泊头市","130982":"任丘市","130983":"黄骅市","130984":"河间市"},"131000":{"131002":"安次区","131003":"广阳区","131022":"固安县","131023":"永清县","131024":"香河县","131025":"大城县","131026":"文安县","131028":"大厂回族自治县","131081":"霸州市","131082":"三河市"},"131100":{"131102":"桃城区","131103":"冀州区","131121":"枣强县","131122":"武邑县","131123":"武强县","131124":"饶阳县","131125":"安平县","131126":"故城县","131127":"景县","131128":"阜城县","131182":"深州市"},"139001":{"1390011":"留早镇","13900111":"邢邑镇","139001001":"南城区街道","139001002":"北城区街道","139001003":"西城区街道","139001004":"长安路街道","139001101":"清风店镇","139001102":"庞村镇","139001103":"砖路镇","139001104":"明月店镇","139001105":"叮咛店镇","139001106":"东亭镇","139001107":"大辛庄镇","139001108":"东旺镇","139001109":"高蓬镇","139001111":"李亲顾镇","139001112":"子位镇","139001113":"开元镇","139001115":"周村镇","139001116":"息冢镇","139001203":"东留春乡","139001204":"号头庄回族乡","139001205":"杨家庄乡","139001206":"大鹿庄乡","139001208":"西城乡"},"139002":{"1390021":"辛集镇","1390022":"天宫营乡","1390025":"辛集经济开发区","139002101":"旧城镇","139002102":"张古庄镇","139002103":"位伯镇","139002104":"新垒头镇","139002105":"新城镇","139002106":"南智邱镇","139002107":"王口镇","139002201":"前营乡","139002202":"马庄乡","139002203":"和睦井乡","139002204":"田家庄乡","139002205":"中里厢乡","139002206":"小辛庄乡"},"140000":{"140100":"太原市","140200":"大同市","140300":"阳泉市","140400":"长治市","140500":"晋城市","140600":"朔州市","140700":"晋中市","140800":"运城市","140900":"忻州市","141000":"临汾市","141100":"吕梁市"},"140100":{"140105":"小店区","140106":"迎泽区","140107":"杏花岭区","140108":"尖草坪区","140109":"万柏林区","140110":"晋源区","140121":"清徐县","140122":"阳曲县","140123":"娄烦县","140181":"古交市"},"140200":{"140202":"城区","140203":"矿区","140211":"南郊区","140212":"新荣区","140221":"阳高县","140222":"天镇县","140223":"广灵县","140224":"灵丘县","140225":"浑源县","140226":"左云县","140227":"大同县"},"140300":{"140302":"城区","140303":"矿区","140311":"郊区","140321":"平定县","140322":"盂县"},"140400":{"140402":"城区","140411":"郊区","140421":"长治县","140423":"襄垣县","140424":"屯留县","140425":"平顺县","140426":"黎城县","140427":"壶关县","140428":"长子县","140429":"武乡县","140430":"沁县","140431":"沁源县","140481":"潞城市"},"140500":{"140502":"城区","140521":"沁水县","140522":"阳城县","140524":"陵川县","140525":"泽州县","140581":"高平市"},"140600":{"140602":"朔城区","140603":"平鲁区","140621":"山阴县","140622":"应县","140623":"右玉县","140624":"怀仁县"},"140700":{"140702":"榆次区","140721":"榆社县","140722":"左权县","140723":"和顺县","140724":"昔阳县","140725":"寿阳县","140726":"太谷县","140727":"祁县","140728":"平遥县","140729":"灵石县","140781":"介休市"},"140800":{"140802":"盐湖区","140821":"临猗县","140822":"万荣县","140823":"闻喜县","140824":"稷山县","140825":"新绛县","140826":"绛县","140827":"垣曲县","140828":"夏县","140829":"平陆县","140830":"芮城县","140881":"永济市","140882":"河津市"},"140900":{"140902":"忻府区","140921":"定襄县","140922":"五台县","140923":"代县","140924":"繁峙县","140925":"宁武县","140926":"静乐县","140927":"神池县","140928":"五寨县","140929":"岢岚县","140930":"河曲县","140931":"保德县","140932":"偏关县","140981":"原平市"}, | ||
| 41 | + "141000":{"141002":"尧都区","141021":"曲沃县","141022":"翼城县","141023":"襄汾县","141024":"洪洞县","141025":"古县","141026":"安泽县","141027":"浮山县","141028":"吉县","141029":"乡宁县","141030":"大宁县","141031":"隰县","141032":"永和县","141033":"蒲县","141034":"汾西县","141081":"侯马市","141082":"霍州市"},"141100":{"141102":"离石区","141121":"文水县","141122":"交城县","141123":"兴县","141124":"临县","141125":"柳林县","141126":"石楼县","141127":"岚县","141128":"方山县","141129":"中阳县","141130":"交口县","141181":"孝义市","141182":"汾阳市"},"150000":{"150100":"呼和浩特市","150200":"包头市","150300":"乌海市","150400":"赤峰市","150500":"通辽市","150600":"鄂尔多斯市","150700":"呼伦贝尔市","150800":"巴彦淖尔市","150900":"乌兰察布市","152200":"兴安盟","152500":"锡林郭勒盟","152900":"阿拉善盟"},"150100":{"150102":"新城区","150103":"回民区","150104":"玉泉区","150105":"赛罕区","150121":"土默特左旗","150122":"托克托县","150123":"和林格尔县","150124":"清水河县","150125":"武川县"},"150200":{"150202":"东河区","150203":"昆都仑区","150204":"青山区","150205":"石拐区","150206":"白云鄂博矿区","150207":"九原区","150221":"土默特右旗","150222":"固阳县","150223":"达尔罕茂明安联合旗"},"150300":{"150302":"海勃湾区","150303":"海南区","150304":"乌达区"},"150400":{"150402":"红山区","150403":"元宝山区","150404":"松山区","150421":"阿鲁科尔沁旗","150422":"巴林左旗","150423":"巴林右旗","150424":"林西县","150425":"克什克腾旗","150426":"翁牛特旗","150428":"喀喇沁旗","150429":"宁城县","150430":"敖汉旗"},"150500":{"150502":"科尔沁区","150521":"科尔沁左翼中旗","150522":"科尔沁左翼后旗","150523":"开鲁县","150524":"库伦旗","150525":"奈曼旗","150526":"扎鲁特旗","150581":"霍林郭勒市"},"150600":{"150602":"东胜区","150603":"康巴什区","150621":"达拉特旗","150622":"准格尔旗","150623":"鄂托克前旗","150624":"鄂托克旗","150625":"杭锦旗","150626":"乌审旗","150627":"伊金霍洛旗"},"150700":{"150702":"海拉尔区","150703":"扎赉诺尔区","150721":"阿荣旗","150722":"莫力达瓦达斡尔族自治旗","150723":"鄂伦春自治旗","150724":"鄂温克族自治旗","150725":"陈巴尔虎旗","150726":"新巴尔虎左旗","150727":"新巴尔虎右旗","150781":"满洲里市","150782":"牙克石市","150783":"扎兰屯市","150784":"额尔古纳市","150785":"根河市"},"150800":{"150802":"临河区","150821":"五原县","150822":"磴口县","150823":"乌拉特前旗","150824":"乌拉特中旗","150825":"乌拉特后旗","150826":"杭锦后旗"},"150900":{"150902":"集宁区","150921":"卓资县","150922":"化德县","150923":"商都县","150924":"兴和县","150925":"凉城县","150926":"察哈尔右翼前旗","150927":"察哈尔右翼中旗","150928":"察哈尔右翼后旗","150929":"四子王旗","150981":"丰镇市"},"152200":{"152201":"乌兰浩特市","152202":"阿尔山市","152221":"科尔沁右翼前旗","152222":"科尔沁右翼中旗","152223":"扎赉特旗","152224":"突泉县"},"152500":{"152501":"二连浩特市","152502":"锡林浩特市","152522":"阿巴嘎旗","152523":"苏尼特左旗","152524":"苏尼特右旗","152525":"东乌珠穆沁旗","152526":"西乌珠穆沁旗","152527":"太仆寺旗","152528":"镶黄旗","152529":"正镶白旗","152530":"正蓝旗","152531":"多伦县"},"152900":{"152921":"阿拉善左旗","152922":"阿拉善右旗","152923":"额济纳旗"},"210000":{"210100":"沈阳市","210200":"大连市","210300":"鞍山市","210400":"抚顺市","210500":"本溪市","210600":"丹东市","210700":"锦州市","210800":"营口市","210900":"阜新市","211000":"辽阳市","211100":"盘锦市","211200":"铁岭市","211300":"朝阳市","211400":"葫芦岛市"},"210100":{"210102":"和平区","210103":"沈河区","210104":"大东区","210105":"皇姑区","210106":"铁西区","210111":"苏家屯区","210112":"浑南区","210113":"沈北新区","210114":"于洪区","210115":"辽中区","210123":"康平县","210124":"法库县","210181":"新民市"},"210200":{"210202":"中山区","210203":"西岗区","210204":"沙河口区","210211":"甘井子区","210212":"旅顺口区","210213":"金州区","210214":"普兰店区","210224":"长海县","210281":"瓦房店市","210283":"庄河市"},"210300":{"210302":"铁东区","210303":"铁西区","210304":"立山区","210311":"千山区","210321":"台安县","210323":"岫岩满族自治县","210381":"海城市"},"210400":{"210402":"新抚区","210403":"东洲区","210404":"望花区","210411":"顺城区","210421":"抚顺县","210422":"新宾满族自治县","210423":"清原满族自治县"},"210500":{"210502":"平山区","210503":"溪湖区","210504":"明山区","210505":"南芬区","210521":"本溪满族自治县","210522":"桓仁满族自治县"},"210600":{"210602":"元宝区","210603":"振兴区","210604":"振安区","210624":"宽甸满族自治县","210681":"东港市","210682":"凤城市"},"210700":{"210702":"古塔区","210703":"凌河区","210711":"太和区","210726":"黑山县","210727":"义县","210781":"凌海市","210782":"北镇市"},"210800":{"210802":"站前区","210803":"西市区","210804":"鲅鱼圈区","210811":"老边区","210881":"盖州市","210882":"大石桥市"},"210900":{"210902":"海州区","210903":"新邱区","210904":"太平区","210905":"清河门区","210911":"细河区","210921":"阜新蒙古族自治县","210922":"彰武县"},"211000":{"211002":"白塔区","211003":"文圣区","211004":"宏伟区","211005":"弓长岭区","211011":"太子河区","211021":"辽阳县","211081":"灯塔市"},"211100":{"211102":"双台子区","211103":"兴隆台区","211104":"大洼区","211122":"盘山县"},"211200":{"211202":"银州区","211204":"清河区","211221":"铁岭县","211223":"西丰县","211224":"昌图县","211281":"调兵山市","211282":"开原市"},"211300":{"211302":"双塔区","211303":"龙城区","211321":"朝阳县","211322":"建平县","211324":"喀喇沁左翼蒙古族自治县","211381":"北票市","211382":"凌源市"},"211400":{"211402":"连山区","211403":"龙港区","211404":"南票区","211421":"绥中县","211422":"建昌县","211481":"兴城市"},"220000":{"220100":"长春市","220200":"吉林市","220300":"四平市","220400":"辽源市","220500":"通化市","220600":"白山市","220700":"松原市","220800":"白城市","222400":"延边朝鲜族自治州"},"220100":{"220102":"南关区","220103":"宽城区","220104":"朝阳区","220105":"二道区","220106":"绿园区","220112":"双阳区","220113":"九台区","220122":"农安县","220182":"榆树市","220183":"德惠市"},"220200":{"220202":"昌邑区","220203":"龙潭区","220204":"船营区","220211":"丰满区","220221":"永吉县","220281":"蛟河市","220282":"桦甸市","220283":"舒兰市","220284":"磐石市"},"220300":{"220302":"铁西区","220303":"铁东区","220322":"梨树县","220323":"伊通满族自治县","220381":"公主岭市","220382":"双辽市"},"220400":{"220402":"龙山区","220403":"西安区","220421":"东丰县","220422":"东辽县"},"220500":{"220502":"东昌区","220503":"二道江区","220521":"通化县","220523":"辉南县","220524":"柳河县","220581":"梅河口市","220582":"集安市"},"220600":{"220602":"浑江区","220605":"江源区","220621":"抚松县","220622":"靖宇县","220623":"长白朝鲜族自治县","220681":"临江市"},"220700":{"220702":"宁江区","220721":"前郭尔罗斯蒙古族自治县","220722":"长岭县","220723":"乾安县","220781":"扶余市"},"220800":{"220802":"洮北区","220821":"镇赉县","220822":"通榆县","220881":"洮南市","220882":"大安市"},"222400":{"222401":"延吉市","222402":"图们市","222403":"敦化市","222404":"珲春市","222405":"龙井市","222406":"和龙市","222424":"汪清县","222426":"安图县"},"230000":{"230100":"哈尔滨市","230200":"齐齐哈尔市","230300":"鸡西市","230400":"鹤岗市","230500":"双鸭山市","230600":"大庆市","230700":"伊春市","230800":"佳木斯市","230900":"七台河市","231000":"牡丹江市","231100":"黑河市","231200":"绥化市","232700":"大兴安岭地区"},"230100":{"230102":"道里区","230103":"南岗区","230104":"道外区","230108":"平房区","230109":"松北区","230110":"香坊区","230111":"呼兰区","230112":"阿城区","230113":"双城区","230123":"依兰县","230124":"方正县","230125":"宾县","230126":"巴彦县","230127":"木兰县","230128":"通河县","230129":"延寿县","230183":"尚志市","230184":"五常市"},"230200":{"230202":"龙沙区","230203":"建华区","230204":"铁锋区","230205":"昂昂溪区","230206":"富拉尔基区","230207":"碾子山区","230208":"梅里斯达斡尔族区","230221":"龙江县","230223":"依安县","230224":"泰来县","230225":"甘南县","230227":"富裕县","230229":"克山县","230230":"克东县","230231":"拜泉县","230281":"讷河市"},"230300":{"230302":"鸡冠区","230303":"恒山区","230304":"滴道区","230305":"梨树区","230306":"城子河区","230307":"麻山区","230321":"鸡东县","230381":"虎林市","230382":"密山市"},"230400":{"230402":"向阳区","230403":"工农区","230404":"南山区","230405":"兴安区","230406":"东山区","230407":"兴山区","230421":"萝北县","230422":"绥滨县"},"230500":{"230502":"尖山区","230503":"岭东区","230505":"四方台区","230506":"宝山区","230521":"集贤县","230522":"友谊县","230523":"宝清县","230524":"饶河县"},"230600":{"230602":"萨尔图区","230603":"龙凤区","230604":"让胡路区","230605":"红岗区","230606":"大同区","230621":"肇州县","230622":"肇源县","230623":"林甸县","230624":"杜尔伯特蒙古族自治县"},"230700":{"230702":"伊春区","230703":"南岔区","230704":"友好区","230705":"西林区","230706":"翠峦区","230707":"新青区","230708":"美溪区","230709":"金山屯区","230710":"五营区","230711":"乌马河区","230712":"汤旺河区","230713":"带岭区","230714":"乌伊岭区","230715":"红星区","230716":"上甘岭区","230722":"嘉荫县","230781":"铁力市"},"230800":{"230803":"向阳区","230804":"前进区","230805":"东风区","230811":"郊区","230822":"桦南县","230826":"桦川县","230828":"汤原县","230881":"同江市","230882":"富锦市","230883":"抚远市"},"230900":{"230902":"新兴区","230903":"桃山区","230904":"茄子河区","230921":"勃利县"},"231000":{"231002":"东安区","231003":"阳明区","231004":"爱民区","231005":"西安区","231025":"林口县","231081":"绥芬河市","231083":"海林市","231084":"宁安市","231085":"穆棱市","231086":"东宁市"},"231100":{"231102":"爱辉区","231121":"嫩江县","231123":"逊克县","231124":"孙吴县","231181":"北安市","231182":"五大连池市"},"231200":{"231202":"北林区","231221":"望奎县","231222":"兰西县","231223":"青冈县","231224":"庆安县","231225":"明水县","231226":"绥棱县","231281":"安达市","231282":"肇东市","231283":"海伦市"},"232700":{"232721":"呼玛县","232722":"塔河县","232723":"漠河县"},"310000":{"310100":"市辖区"}, | ||
| 42 | + "310100":{"310101":"黄浦区","310104":"徐汇区","310105":"长宁区","310106":"静安区","310107":"普陀区","310109":"虹口区","310110":"杨浦区","310112":"闵行区","310113":"宝山区","310114":"嘉定区","310115":"浦东新区","310116":"金山区","310117":"松江区","310118":"青浦区","310120":"奉贤区","310151":"崇明区"},"320000":{"320100":"南京市","320200":"无锡市","320300":"徐州市","320400":"常州市","320500":"苏州市","320600":"南通市","320700":"连云港市","320800":"淮安市","320900":"盐城市","321000":"扬州市","321100":"镇江市","321200":"泰州市","321300":"宿迁市"},"320100":{"320102":"玄武区","320104":"秦淮区","320105":"建邺区","320106":"鼓楼区","320111":"浦口区","320113":"栖霞区","320114":"雨花台区","320115":"江宁区","320116":"六合区","320117":"溧水区","320118":"高淳区"}, | ||
| 43 | + "320200":{"320205":"锡山区","320206":"惠山区","320211":"滨湖区","320213":"梁溪区","320214":"新吴区","320281":"江阴市","320282":"宜兴市"},"320300":{"320302":"鼓楼区","320303":"云龙区","320305":"贾汪区","320311":"泉山区","320312":"铜山区","320321":"丰县","320322":"沛县","320324":"睢宁县","320381":"新沂市","320382":"邳州市"}, | ||
| 44 | + "320400":{"320402":"天宁区","320404":"钟楼区","320411":"新北区","320412":"武进区","320413":"金坛区","320481":"溧阳市"},"320500":{"320505":"虎丘区","320506":"吴中区","320507":"相城区","320508":"姑苏区","320509":"吴江区","320581":"常熟市","320582":"张家港市","320583":"昆山市","320585":"太仓市"},"320600":{"320602":"崇川区","320611":"港闸区","320612":"通州区","320621":"海安县","320623":"如东县","320681":"启东市","320682":"如皋市","320684":"海门市"},"320700":{"320703":"连云区","320706":"海州区","320707":"赣榆区","320722":"东海县","320723":"灌云县","320724":"灌南县"},"320800":{"320803":"淮安区","320804":"淮阴区","320812":"清江浦区","320813":"洪泽区","320826":"涟水县","320830":"盱眙县","320831":"金湖县"},"320900":{"320902":"亭湖区","320903":"盐都区","320904":"大丰区","320921":"响水县","320922":"滨海县","320923":"阜宁县","320924":"射阳县","320925":"建湖县","320981":"东台市"},"321000":{"321002":"广陵区","321003":"邗江区","321012":"江都区","321023":"宝应县","321081":"仪征市","321084":"高邮市"},"321100":{"321102":"京口区","321111":"润州区","321112":"丹徒区","321181":"丹阳市","321182":"扬中市","321183":"句容市"},"321200":{"321202":"海陵区","321203":"高港区","321204":"姜堰区","321281":"兴化市","321282":"靖江市","321283":"泰兴市"},"321300":{"321302":"宿城区","321311":"宿豫区","321322":"沭阳县","321323":"泗阳县","321324":"泗洪县"},"330000":{"330100":"杭州市","330200":"宁波市","330300":"温州市","330400":"嘉兴市","330500":"湖州市","330600":"绍兴市","330700":"金华市","330800":"衢州市","330900":"舟山市","331000":"台州市","331100":"丽水市"},"330100":{"330102":"上城区","330103":"下城区","330104":"江干区","330105":"拱墅区","330106":"西湖区","330108":"滨江区","330109":"萧山区","330110":"余杭区","330111":"富阳区","330122":"桐庐县","330127":"淳安县","330182":"建德市","330185":"临安市"},"330200":{"330203":"海曙区","330204":"江东区","330205":"江北区","330206":"北仑区","330211":"镇海区","330212":"鄞州区","330225":"象山县","330226":"宁海县","330281":"余姚市","330282":"慈溪市","330283":"奉化市"},"330300":{"330302":"鹿城区","330303":"龙湾区","330304":"瓯海区","330305":"洞头区","330324":"永嘉县","330326":"平阳县","330327":"苍南县","330328":"文成县","330329":"泰顺县","330381":"瑞安市","330382":"乐清市"},"330400":{"330402":"南湖区","330411":"秀洲区","330421":"嘉善县","330424":"海盐县","330481":"海宁市","330482":"平湖市","330483":"桐乡市"},"330500":{"330502":"吴兴区","330503":"南浔区","330521":"德清县","330522":"长兴县","330523":"安吉县"},"330600":{"330602":"越城区","330603":"柯桥区","330604":"上虞区","330624":"新昌县","330681":"诸暨市","330683":"嵊州市"},"330700":{"330702":"婺城区","330703":"金东区","330723":"武义县","330726":"浦江县","330727":"磐安县","330781":"兰溪市","330782":"义乌市","330783":"东阳市","330784":"永康市"},"330800":{"330802":"柯城区","330803":"衢江区","330822":"常山县","330824":"开化县","330825":"龙游县","330881":"江山市"},"330900":{"330902":"定海区","330903":"普陀区","330921":"岱山县","330922":"嵊泗县"},"331000":{"331002":"椒江区","331003":"黄岩区","331004":"路桥区","331021":"玉环县","331022":"三门县","331023":"天台县","331024":"仙居县","331081":"温岭市","331082":"临海市"},"331100":{"331102":"莲都区","331121":"青田县","331122":"缙云县","331123":"遂昌县","331124":"松阳县","331125":"云和县","331126":"庆元县","331127":"景宁畲族自治县","331181":"龙泉市"},"340000":{"340100":"合肥市","340200":"芜湖市","340300":"蚌埠市","340400":"淮南市","340500":"马鞍山市","340600":"淮北市","340700":"铜陵市","340800":"安庆市","341000":"黄山市","341100":"滁州市","341200":"阜阳市","341300":"宿州市","341500":"六安市","341600":"亳州市","341700":"池州市","341800":"宣城市"},"340100":{"340102":"瑶海区","340103":"庐阳区","340104":"蜀山区","340111":"包河区","340121":"长丰县","340122":"肥东县","340123":"肥西县","340124":"庐江县","340181":"巢湖市"},"340200":{"340202":"镜湖区","340203":"弋江区","340207":"鸠江区","340208":"三山区","340221":"芜湖县","340222":"繁昌县","340223":"南陵县","340225":"无为县"},"340300":{"340302":"龙子湖区","340303":"蚌山区","340304":"禹会区","340311":"淮上区","340321":"怀远县","340322":"五河县","340323":"固镇县"},"340400":{"340402":"大通区","340403":"田家庵区","340404":"谢家集区","340405":"八公山区","340406":"潘集区","340421":"凤台县","340422":"寿县"},"340500":{"340503":"花山区","340504":"雨山区","340506":"博望区","340521":"当涂县","340522":"含山县","340523":"和县"},"340600":{"340602":"杜集区","340603":"相山区","340604":"烈山区","340621":"濉溪县"},"340700":{"340705":"铜官区","340706":"义安区","340711":"郊区","340722":"枞阳县"},"340800":{"340802":"迎江区","340803":"大观区","340811":"宜秀区","340822":"怀宁县","340824":"潜山县","340825":"太湖县","340826":"宿松县","340827":"望江县","340828":"岳西县","340881":"桐城市"},"341000":{"341002":"屯溪区","341003":"黄山区","341004":"徽州区","341021":"歙县","341022":"休宁县","341023":"黟县","341024":"祁门县"},"341100":{"341102":"琅琊区","341103":"南谯区","341122":"来安县","341124":"全椒县","341125":"定远县","341126":"凤阳县","341181":"天长市","341182":"明光市"},"341200":{"341202":"颍州区","341203":"颍东区","341204":"颍泉区","341221":"临泉县","341222":"太和县","341225":"阜南县","341226":"颍上县","341282":"界首市"},"341300":{"341302":"埇桥区","341321":"砀山县","341322":"萧县","341323":"灵璧县","341324":"泗县"},"341500":{"341502":"金安区","341503":"裕安区","341504":"叶集区","341522":"霍邱县","341523":"舒城县","341524":"金寨县","341525":"霍山县"},"341600":{"341602":"谯城区","341621":"涡阳县","341622":"蒙城县","341623":"利辛县"},"341700":{"341702":"贵池区","341721":"东至县","341722":"石台县","341723":"青阳县"},"341800":{"341802":"宣州区","341821":"郎溪县","341822":"广德县","341823":"泾县","341824":"绩溪县","341825":"旌德县","341881":"宁国市"},"350000":{"350100":"福州市","350200":"厦门市","350300":"莆田市","350400":"三明市","350500":"泉州市","350600":"漳州市","350700":"南平市","350800":"龙岩市","350900":"宁德市"},"350100":{"350102":"鼓楼区","350103":"台江区","350104":"仓山区","350105":"马尾区","350111":"晋安区","350121":"闽侯县","350122":"连江县","350123":"罗源县","350124":"闽清县","350125":"永泰县","350128":"平潭县","350181":"福清市","350182":"长乐市"},"350200":{"350203":"思明区","350205":"海沧区","350206":"湖里区","350211":"集美区","350212":"同安区","350213":"翔安区"},"350300":{"350302":"城厢区","350303":"涵江区","350304":"荔城区","350305":"秀屿区","350322":"仙游县"},"350400":{"350402":"梅列区","350403":"三元区","350421":"明溪县","350423":"清流县","350424":"宁化县","350425":"大田县","350426":"尤溪县","350427":"沙县","350428":"将乐县","350429":"泰宁县","350430":"建宁县","350481":"永安市"},"350500":{"350502":"鲤城区","350503":"丰泽区","350504":"洛江区","350505":"泉港区","350521":"惠安县","350524":"安溪县","350525":"永春县","350526":"德化县","350527":"金门县","350581":"石狮市","350582":"晋江市","350583":"南安市"},"350600":{"350602":"芗城区","350603":"龙文区","350622":"云霄县","350623":"漳浦县","350624":"诏安县","350625":"长泰县","350626":"东山县","350627":"南靖县","350628":"平和县","350629":"华安县","350681":"龙海市"},"350700":{"350702":"延平区","350703":"建阳区","350721":"顺昌县","350722":"浦城县","350723":"光泽县","350724":"松溪县","350725":"政和县","350781":"邵武市","350782":"武夷山市","350783":"建瓯市"},"350800":{"350802":"新罗区","350803":"永定区","350821":"长汀县","350823":"上杭县","350824":"武平县","350825":"连城县","350881":"漳平市"},"350900":{"350902":"蕉城区","350921":"霞浦县","350922":"古田县","350923":"屏南县","350924":"寿宁县","350925":"周宁县","350926":"柘荣县","350981":"福安市","350982":"福鼎市"},"360000":{"360100":"南昌市","360200":"景德镇市","360300":"萍乡市","360400":"九江市","360500":"新余市","360600":"鹰潭市","360700":"赣州市","360800":"吉安市","360900":"宜春市","361000":"抚州市","361100":"上饶市"},"360100":{"360102":"东湖区","360103":"西湖区","360104":"青云谱区","360105":"湾里区","360111":"青山湖区","360112":"新建区","360121":"南昌县","360123":"安义县","360124":"进贤县"},"360200":{"360202":"昌江区","360203":"珠山区","360222":"浮梁县","360281":"乐平市"},"360300":{"360302":"安源区","360313":"湘东区","360321":"莲花县","360322":"上栗县","360323":"芦溪县"},"360400":{"360402":"濂溪区","360403":"浔阳区","360421":"九江县","360423":"武宁县","360424":"修水县","360425":"永修县","360426":"德安县","360428":"都昌县","360429":"湖口县","360430":"彭泽县","360481":"瑞昌市","360482":"共青城市","360483":"庐山市"},"360500":{"360502":"渝水区","360521":"分宜县"},"360600":{"360602":"月湖区","360622":"余江县","360681":"贵溪市"},"360700":{"360702":"章贡区","360703":"南康区","360721":"赣县","360722":"信丰县","360723":"大余县","360724":"上犹县","360725":"崇义县","360726":"安远县","360727":"龙南县","360728":"定南县","360729":"全南县","360730":"宁都县","360731":"于都县","360732":"兴国县","360733":"会昌县","360734":"寻乌县","360735":"石城县","360781":"瑞金市"},"360800":{"360802":"吉州区","360803":"青原区","360821":"吉安县","360822":"吉水县","360823":"峡江县","360824":"新干县","360825":"永丰县","360826":"泰和县","360827":"遂川县","360828":"万安县","360829":"安福县","360830":"永新县","360881":"井冈山市"},"360900":{"360902":"袁州区","360921":"奉新县","360922":"万载县","360923":"上高县","360924":"宜丰县","360925":"靖安县","360926":"铜鼓县","360981":"丰城市","360982":"樟树市","360983":"高安市"},"361000":{"361002":"临川区","361021":"南城县","361022":"黎川县","361023":"南丰县","361024":"崇仁县","361025":"乐安县","361026":"宜黄县","361027":"金溪县","361028":"资溪县","361029":"东乡县","361030":"广昌县"},"361100":{"361102":"信州区","361103":"广丰区","361121":"上饶县","361123":"玉山县","361124":"铅山县","361125":"横峰县","361126":"弋阳县","361127":"余干县","361128":"鄱阳县","361129":"万年县","361130":"婺源县","361181":"德兴市"},"370000":{"370100":"济南市","370200":"青岛市","370300":"淄博市","370400":"枣庄市","370500":"东营市","370600":"烟台市","370700":"潍坊市","370800":"济宁市","370900":"泰安市","371000":"威海市","371100":"日照市","371200":"莱芜市","371300":"临沂市","371400":"德州市","371500":"聊城市","371600":"滨州市","371700":"菏泽市"},"370100":{"370102":"历下区","370103":"市中区","370104":"槐荫区","370105":"天桥区","370112":"历城区","370113":"长清区","370124":"平阴县","370125":"济阳县","370126":"商河县","370181":"章丘市"},"370200":{"370202":"市南区","370203":"市北区","370211":"黄岛区","370212":"崂山区","370213":"李沧区","370214":"城阳区","370281":"胶州市","370282":"即墨市","370283":"平度市","370285":"莱西市"},"370300":{"370302":"淄川区","370303":"张店区","370304":"博山区","370305":"临淄区","370306":"周村区","370321":"桓台县","370322":"高青县","370323":"沂源县"},"370400":{"370402":"市中区","370403":"薛城区","370404":"峄城区","370405":"台儿庄区","370406":"山亭区","370481":"滕州市"},"370500":{"370502":"东营区","370503":"河口区","370505":"垦利区","370522":"利津县","370523":"广饶县"},"370600":{"370602":"芝罘区","370611":"福山区","370612":"牟平区","370613":"莱山区","370634":"长岛县","370681":"龙口市","370682":"莱阳市","370683":"莱州市","370684":"蓬莱市","370685":"招远市","370686":"栖霞市","370687":"海阳市"},"370700":{"370702":"潍城区","370703":"寒亭区","370704":"坊子区","370705":"奎文区","370724":"临朐县","370725":"昌乐县","370781":"青州市","370782":"诸城市","370783":"寿光市","370784":"安丘市","370785":"高密市","370786":"昌邑市"},"370800":{"370811":"任城区","370812":"兖州区","370826":"微山县","370827":"鱼台县","370828":"金乡县","370829":"嘉祥县","370830":"汶上县","370831":"泗水县","370832":"梁山县","370881":"曲阜市","370883":"邹城市"},"370900":{"370902":"泰山区","370911":"岱岳区","370921":"宁阳县","370923":"东平县","370982":"新泰市","370983":"肥城市"},"371000":{"371002":"环翠区","371003":"文登区","371082":"荣成市","371083":"乳山市"},"371100":{"371102":"东港区","371103":"岚山区","371121":"五莲县","371122":"莒县"},"371200":{"371202":"莱城区","371203":"钢城区"},"371300":{"371302":"兰山区","371311":"罗庄区","371312":"河东区","371321":"沂南县","371322":"郯城县","371323":"沂水县","371324":"兰陵县","371325":"费县","371326":"平邑县","371327":"莒南县","371328":"蒙阴县","371329":"临沭县"},"371400":{"371402":"德城区","371403":"陵城区","371422":"宁津县","371423":"庆云县","371424":"临邑县","371425":"齐河县","371426":"平原县","371427":"夏津县","371428":"武城县","371481":"乐陵市","371482":"禹城市"},"371500":{"371502":"东昌府区","371521":"阳谷县","371522":"莘县","371523":"茌平县","371524":"东阿县","371525":"冠县","371526":"高唐县","371581":"临清市"},"371600":{"371602":"滨城区","371603":"沾化区","371621":"惠民县","371622":"阳信县","371623":"无棣县","371625":"博兴县","371626":"邹平县"},"371700":{"371702":"牡丹区","371703":"定陶区","371721":"曹县","371722":"单县","371723":"成武县","371724":"巨野县","371725":"郓城县","371726":"鄄城县","371728":"东明县"},"410000":{"410100":"郑州市","410200":"开封市","410300":"洛阳市","410400":"平顶山市","410500":"安阳市","410600":"鹤壁市","410700":"新乡市","410800":"焦作市","410900":"濮阳市","411000":"许昌市","411100":"漯河市","411200":"三门峡市","411300":"南阳市","411400":"商丘市","411500":"信阳市","411600":"周口市","411700":"驻马店市","419001":"济源市"},"410100":{"410102":"中原区","410103":"二七区","410104":"管城回族区","410105":"金水区","410106":"上街区","410108":"惠济区","410122":"中牟县","410181":"巩义市","410182":"荥阳市","410183":"新密市","410184":"新郑市","410185":"登封市"},"410200":{"410202":"龙亭区","410203":"顺河回族区","410204":"鼓楼区","410205":"禹王台区","410211":"金明区","410212":"祥符区","410221":"杞县","410222":"通许县","410223":"尉氏县","410225":"兰考县"},"410300":{"410302":"老城区","410303":"西工区","410304":"瀍河回族区","410305":"涧西区","410306":"吉利区","410311":"洛龙区","410322":"孟津县","410323":"新安县","410324":"栾川县","410325":"嵩县","410326":"汝阳县","410327":"宜阳县","410328":"洛宁县","410329":"伊川县","410381":"偃师市"},"410400":{"410402":"新华区","410403":"卫东区","410404":"石龙区","410411":"湛河区","410421":"宝丰县","410422":"叶县","410423":"鲁山县","410425":"郏县","410481":"舞钢市","410482":"汝州市"},"410500":{"410502":"文峰区","410503":"北关区","410505":"殷都区","410506":"龙安区","410522":"安阳县","410523":"汤阴县","410526":"滑县","410527":"内黄县","410581":"林州市"},"410600":{"410602":"鹤山区","410603":"山城区","410611":"淇滨区","410621":"浚县","410622":"淇县"},"410700":{"410702":"红旗区","410703":"卫滨区","410704":"凤泉区","410711":"牧野区","410721":"新乡县","410724":"获嘉县","410725":"原阳县","410726":"延津县","410727":"封丘县","410728":"长垣县","410781":"卫辉市","410782":"辉县市"},"410800":{"410802":"解放区","410803":"中站区","410804":"马村区","410811":"山阳区","410821":"修武县","410822":"博爱县","410823":"武陟县","410825":"温县","410882":"沁阳市","410883":"孟州市"},"410900":{"410902":"华龙区","410922":"清丰县","410923":"南乐县","410926":"范县","410927":"台前县","410928":"濮阳县"},"411000":{"411002":"魏都区","411023":"许昌县","411024":"鄢陵县","411025":"襄城县","411081":"禹州市","411082":"长葛市"},"411100":{"411102":"源汇区","411103":"郾城区","411104":"召陵区","411121":"舞阳县","411122":"临颍县"},"411200":{"411202":"湖滨区","411203":"陕州区","411221":"渑池县","411224":"卢氏县","411281":"义马市","411282":"灵宝市"},"411300":{"411302":"宛城区","411303":"卧龙区","411321":"南召县","411322":"方城县","411323":"西峡县","411324":"镇平县","411325":"内乡县","411326":"淅川县","411327":"社旗县","411328":"唐河县","411329":"新野县","411330":"桐柏县","411381":"邓州市"},"411400":{"411402":"梁园区","411403":"睢阳区","411421":"民权县","411422":"睢县","411423":"宁陵县","411424":"柘城县","411425":"虞城县","411426":"夏邑县","411481":"永城市"},"411500":{"411502":"浉河区","411503":"平桥区","411521":"罗山县","411522":"光山县","411523":"新县","411524":"商城县","411525":"固始县","411526":"潢川县","411527":"淮滨县","411528":"息县"},"411600":{"411602":"川汇区","411621":"扶沟县","411622":"西华县","411623":"商水县","411624":"沈丘县","411625":"郸城县","411626":"淮阳县","411627":"太康县","411628":"鹿邑县","411681":"项城市"},"411700":{"411702":"驿城区","411721":"西平县","411722":"上蔡县","411723":"平舆县","411724":"正阳县","411725":"确山县","411726":"泌阳县","411727":"汝南县","411728":"遂平县","411729":"新蔡县"},"419001":{"4190011":"济源市克井镇","41900111":"济源市下冶镇","419001001":"济源市沁园街道","419001002":"济源市济水街道","419001003":"济源市北海街道","419001004":"济源市天坛街道","419001005":"济源市玉泉街道","419001101":"济源市五龙口镇","419001102":"济源市轵城镇","419001103":"济源市承留镇","419001104":"济源市邵原镇","419001105":"济源市坡头镇","419001106":"济源市梨林镇","419001107":"济源市大峪镇","419001108":"济源市思礼镇","419001109":"济源市王屋镇"},"420000":{"420100":"武汉市","420200":"黄石市","420300":"十堰市","420500":"宜昌市","420600":"襄阳市","420700":"鄂州市","420800":"荆门市","420900":"孝感市","421000":"荆州市","421100":"黄冈市","421200":"咸宁市","421300":"随州市","422800":"恩施土家族苗族自治州","429004":"仙桃市","429005":"潜江市","429006":"天门市","429021":"神农架林区"},"420100":{"420102":"江岸区","420103":"江汉区","420104":"硚口区","420105":"汉阳区","420106":"武昌区","420107":"青山区","420111":"洪山区","420112":"东西湖区","420113":"汉南区","420114":"蔡甸区","420115":"江夏区","420116":"黄陂区","420117":"新洲区"},"420200":{"420202":"黄石港区","420203":"西塞山区","420204":"下陆区","420205":"铁山区","420222":"阳新县","420281":"大冶市"},"420300":{"420302":"茅箭区","420303":"张湾区","420304":"郧阳区","420322":"郧西县","420323":"竹山县","420324":"竹溪县","420325":"房县","420381":"丹江口市"},"420500":{"420502":"西陵区","420503":"伍家岗区","420504":"点军区","420505":"猇亭区","420506":"夷陵区","420525":"远安县","420526":"兴山县","420527":"秭归县","420528":"长阳土家族自治县","420529":"五峰土家族自治县","420581":"宜都市","420582":"当阳市","420583":"枝江市"},"420600":{"420602":"襄城区","420606":"樊城区","420607":"襄州区","420624":"南漳县","420625":"谷城县","420626":"保康县","420682":"老河口市","420683":"枣阳市","420684":"宜城市"},"420700":{"420702":"梁子湖区","420703":"华容区","420704":"鄂城区"},"420800":{"420802":"东宝区","420804":"掇刀区","420821":"京山县","420822":"沙洋县","420881":"钟祥市"},"420900":{"420902":"孝南区","420921":"孝昌县","420922":"大悟县","420923":"云梦县","420981":"应城市","420982":"安陆市","420984":"汉川市"},"421000":{"421002":"沙市区","421003":"荆州区","421022":"公安县","421023":"监利县","421024":"江陵县","421081":"石首市","421083":"洪湖市","421087":"松滋市"},"421100":{"421102":"黄州区","421121":"团风县","421122":"红安县","421123":"罗田县","421124":"英山县","421125":"浠水县","421126":"蕲春县","421127":"黄梅县","421181":"麻城市","421182":"武穴市"},"421200":{"421202":"咸安区","421221":"嘉鱼县","421222":"通城县","421223":"崇阳县","421224":"通山县","421281":"赤壁市"},"421300":{"421303":"曾都区","421321":"随县","421381":"广水市"},"422800":{"422801":"恩施市","422802":"利川市","422822":"建始县","422823":"巴东县","422825":"宣恩县","422826":"咸丰县","422827":"来凤县","422828":"鹤峰县"},"429004":{"4290041":"郑场镇","4290044":"工业园区","42900411":"张沟镇","429004001":"沙嘴街道","429004002":"干河街道","429004003":"龙华山","429004101":"毛嘴镇","429004102":"豆河镇","429004103":"三伏潭镇","429004104":"胡场镇","429004105":"长倘口镇","429004106":"西流河镇","429004107":"沙湖镇","429004108":"杨林尾镇","429004109":"彭场镇","429004111":"郭河镇","429004112":"沔城回族镇","429004113":"通海口镇","429004114":"陈场镇","429004401":"九合垸原种场","429004402":"沙湖原种场","429004404":"五湖渔场","429004405":"赵西垸林场","429004407":"畜禽良种场","429004408":"排湖风景区"},"429005":{"4290051":"竹根滩镇","4290054":"江汉石油管理局","42900545":"周矶管理区","429005001":"园林","429005002":"杨市","429005003":"周矶","429005004":"广华","429005005":"泰丰","429005006":"高场","429005101":"渔洋镇","429005102":"王场镇","429005103":"高石碑镇","429005104":"熊口镇","429005105":"老新镇","429005106":"浩口镇","429005107":"积玉口镇","429005108":"张金镇","429005109":"龙湾镇","429005401":"潜江经济开发区","429005451":"后湖管理区","429005452":"熊口管理区","429005453":"总口管理区","429005454":"白鹭湖管理区","429005455":"运粮湖管理区","429005457":"浩口原种场"},"429006":{"4290061":"多宝镇","42900611":"麻洋镇","42900612":"石河镇","42900645":"蒋湖农场","429006001":"竟陵街道","429006002":"侨乡街道开发区","429006003":"杨林街道","429006101":"拖市镇","429006102":"张港镇","429006103":"蒋场镇","429006104":"汪场镇","429006105":"渔薪镇","429006106":"黄潭镇","429006107":"岳口镇","429006108":"横林镇","429006109":"彭市镇","429006111":"多祥镇","429006112":"干驿镇","429006113":"马湾镇","429006114":"卢市镇","429006115":"小板镇","429006116":"九真镇","429006118":"皂市镇","429006119":"胡市镇","429006121":"佛子山镇","429006201":"净潭乡","429006451":"白茅湖农场","429006452":"沉湖管委会"},"429021":{"4290211":"松柏镇","4290212":"宋洛乡","429021101":"阳日镇","429021102":"木鱼镇","429021103":"红坪镇","429021104":"新华镇","429021105":"九湖镇","429021202":"下谷坪土家族乡"},"430000":{"430100":"长沙市","430200":"株洲市","430300":"湘潭市","430400":"衡阳市","430500":"邵阳市","430600":"岳阳市","430700":"常德市","430800":"张家界市","430900":"益阳市","431000":"郴州市","431100":"永州市","431200":"怀化市","431300":"娄底市","433100":"湘西土家族苗族自治州"},"430100":{"430102":"芙蓉区","430103":"天心区","430104":"岳麓区","430105":"开福区","430111":"雨花区","430112":"望城区","430121":"长沙县","430124":"宁乡县","430181":"浏阳市"},"430200":{"430202":"荷塘区","430203":"芦淞区","430204":"石峰区","430211":"天元区","430221":"株洲县","430223":"攸县","430224":"茶陵县","430225":"炎陵县","430281":"醴陵市"},"430300":{"430302":"雨湖区","430304":"岳塘区","430321":"湘潭县","430381":"湘乡市","430382":"韶山市"},"430400":{"430405":"珠晖区","430406":"雁峰区","430407":"石鼓区","430408":"蒸湘区","430412":"南岳区","430421":"衡阳县","430422":"衡南县","430423":"衡山县","430424":"衡东县","430426":"祁东县","430481":"耒阳市","430482":"常宁市"},"430500":{"430502":"双清区","430503":"大祥区","430511":"北塔区","430521":"邵东县","430522":"新邵县","430523":"邵阳县","430524":"隆回县","430525":"洞口县","430527":"绥宁县","430528":"新宁县","430529":"城步苗族自治县","430581":"武冈市"},"430600":{"430602":"岳阳楼区","430603":"云溪区","430611":"君山区","430621":"岳阳县","430623":"华容县","430624":"湘阴县","430626":"平江县","430681":"汨罗市","430682":"临湘市"},"430700":{"430702":"武陵区","430703":"鼎城区","430721":"安乡县","430722":"汉寿县","430723":"澧县","430724":"临澧县","430725":"桃源县","430726":"石门县","430781":"津市市"},"430800":{"430802":"永定区","430811":"武陵源区","430821":"慈利县","430822":"桑植县"},"430900":{"430902":"资阳区","430903":"赫山区","430921":"南县","430922":"桃江县","430923":"安化县","430981":"沅江市"},"431000":{"431002":"北湖区","431003":"苏仙区","431021":"桂阳县","431022":"宜章县","431023":"永兴县","431024":"嘉禾县","431025":"临武县","431026":"汝城县","431027":"桂东县","431028":"安仁县","431081":"资兴市"},"431100":{"431102":"零陵区","431103":"冷水滩区","431121":"祁阳县","431122":"东安县","431123":"双牌县","431124":"道县","431125":"江永县","431126":"宁远县","431127":"蓝山县","431128":"新田县","431129":"江华瑶族自治县"},"431200":{"431202":"鹤城区","431221":"中方县","431222":"沅陵县","431223":"辰溪县","431224":"溆浦县","431225":"会同县","431226":"麻阳苗族自治县","431227":"新晃侗族自治县","431228":"芷江侗族自治县","431229":"靖州苗族侗族自治县","431230":"通道侗族自治县","431281":"洪江市"},"431300":{"431302":"娄星区","431321":"双峰县","431322":"新化县","431381":"冷水江市","431382":"涟源市"},"433100":{"433101":"吉首市","433122":"泸溪县","433123":"凤凰县","433124":"花垣县","433125":"保靖县","433126":"古丈县","433127":"永顺县","433130":"龙山县"},"440000":{"440100":"广州市","440200":"韶关市","440300":"深圳市","440400":"珠海市","440500":"汕头市","440600":"佛山市","440700":"江门市","440800":"湛江市","440900":"茂名市","441200":"肇庆市","441300":"惠州市","441400":"梅州市","441500":"汕尾市","441600":"河源市","441700":"阳江市","441800":"清远市","441900":"东莞市","442000":"中山市","445100":"潮州市","445200":"揭阳市","445300":"云浮市"},"440100":{"440103":"荔湾区","440104":"越秀区","440105":"海珠区","440106":"天河区","440111":"白云区","440112":"黄埔区","440113":"番禺区","440114":"花都区","440115":"南沙区","440117":"从化区","440118":"增城区"},"440200":{"440203":"武江区","440204":"浈江区","440205":"曲江区","440222":"始兴县","440224":"仁化县","440229":"翁源县","440232":"乳源瑶族自治县","440233":"新丰县","440281":"乐昌市","440282":"南雄市"},"440300":{"440303":"罗湖区","440304":"福田区","440305":"南山区","440306":"宝安区","440307":"龙岗区","440308":"盐田区"},"440400":{"440402":"香洲区","440403":"斗门区","440404":"金湾区"},"440500":{"440507":"龙湖区","440511":"金平区","440512":"濠江区","440513":"潮阳区","440514":"潮南区","440515":"澄海区","440523":"南澳县"},"440600":{"440604":"禅城区","440605":"南海区","440606":"顺德区","440607":"三水区","440608":"高明区"},"440700":{"440703":"蓬江区","440704":"江海区","440705":"新会区","440781":"台山市","440783":"开平市","440784":"鹤山市","440785":"恩平市"},"440800":{"440802":"赤坎区","440803":"霞山区","440804":"坡头区","440811":"麻章区","440823":"遂溪县","440825":"徐闻县","440881":"廉江市","440882":"雷州市","440883":"吴川市"},"440900":{"440902":"茂南区","440904":"电白区","440981":"高州市","440982":"化州市","440983":"信宜市"},"441200":{"441202":"端州区","441203":"鼎湖区","441204":"高要区","441223":"广宁县","441224":"怀集县","441225":"封开县","441226":"德庆县","441284":"四会市"},"441300":{"441302":"惠城区","441303":"惠阳区","441322":"博罗县","441323":"惠东县","441324":"龙门县"},"441400":{"441402":"梅江区","441403":"梅县区","441422":"大埔县","441423":"丰顺县","441424":"五华县","441426":"平远县","441427":"蕉岭县","441481":"兴宁市"},"441500":{"441502":"城区","441521":"海丰县","441523":"陆河县","441581":"陆丰市"},"441600":{"441602":"源城区","441621":"紫金县","441622":"龙川县","441623":"连平县","441624":"和平县","441625":"东源县"},"441700":{"441702":"江城区","441704":"阳东区","441721":"阳西县","441781":"阳春市"},"441800":{"441802":"清城区","441803":"清新区","441821":"佛冈县","441823":"阳山县","441825":"连山壮族瑶族自治县","441826":"连南瑶族自治县","441881":"英德市","441882":"连州市"},"441900":{"441900003":"东城街道","441900004":"南城街道","441900005":"万江街道","441900006":"莞城街道","441900101":"石碣镇","441900102":"石龙镇","441900103":"茶山镇","441900104":"石排镇","441900105":"企石镇","441900106":"横沥镇","441900107":"桥头镇","441900108":"谢岗镇","441900109":"东坑镇","441900110":"常平镇","441900111":"寮步镇","441900112":"樟木头镇","441900113":"大朗镇","441900114":"黄江镇","441900115":"清溪镇","441900116":"塘厦镇","441900117":"凤岗镇","441900118":"大岭山镇","441900119":"长安镇","441900121":"虎门镇","441900122":"厚街镇","441900123":"沙田镇","441900124":"道滘镇","441900125":"洪梅镇","441900126":"麻涌镇","441900127":"望牛墩镇","441900128":"中堂镇","441900129":"高埗镇","441900401":"松山湖管委会","441900402":"虎门港管委会","441900403":"东莞生态园"},"442000":{"442000001":"石岐区街道","442000002":"东区街道","442000003":"火炬开发区街道","442000004":"西区街道","442000005":"南区街道","442000006":"五桂山街道","442000100":"小榄镇","442000101":"黄圃镇","442000102":"民众镇","442000103":"东凤镇","442000104":"东升镇","442000105":"古镇镇","442000106":"沙溪镇","442000107":"坦洲镇","442000108":"港口镇","442000109":"三角镇","442000110":"横栏镇","442000111":"南头镇","442000112":"阜沙镇","442000113":"南朗镇","442000114":"三乡镇","442000115":"板芙镇","442000116":"大涌镇","442000117":"神湾镇"},"445100":{"445102":"湘桥区","445103":"潮安区","445122":"饶平县"},"445200":{"445202":"榕城区","445203":"揭东区","445222":"揭西县","445224":"惠来县","445281":"普宁市"},"445300":{"445302":"云城区","445303":"云安区","445321":"新兴县","445322":"郁南县","445381":"罗定市"},"450000":{"450100":"南宁市","450200":"柳州市","450300":"桂林市","450400":"梧州市","450500":"北海市","450600":"防城港市","450700":"钦州市","450800":"贵港市","450900":"玉林市","451000":"百色市","451100":"贺州市","451200":"河池市","451300":"来宾市","451400":"崇左市"},"450100":{"450102":"兴宁区","450103":"青秀区","450105":"江南区","450107":"西乡塘区","450108":"良庆区","450109":"邕宁区","450110":"武鸣区","450123":"隆安县","450124":"马山县","450125":"上林县","450126":"宾阳县","450127":"横县"},"450200":{"450202":"城中区","450203":"鱼峰区","450204":"柳南区","450205":"柳北区","450206":"柳江区","450222":"柳城县","450223":"鹿寨县","450224":"融安县","450225":"融水苗族自治县","450226":"三江侗族自治县"},"450300":{"450302":"秀峰区","450303":"叠彩区","450304":"象山区","450305":"七星区","450311":"雁山区","450312":"临桂区","450321":"阳朔县","450323":"灵川县","450324":"全州县","450325":"兴安县","450326":"永福县","450327":"灌阳县","450328":"龙胜各族自治县","450329":"资源县","450330":"平乐县","450331":"荔浦县","450332":"恭城瑶族自治县"},"450400":{"450403":"万秀区","450405":"长洲区","450406":"龙圩区","450421":"苍梧县","450422":"藤县","450423":"蒙山县","450481":"岑溪市"},"450500":{"450502":"海城区","450503":"银海区","450512":"铁山港区","450521":"合浦县"},"450600":{"450602":"港口区","450603":"防城区","450621":"上思县","450681":"东兴市"},"450700":{"450702":"钦南区","450703":"钦北区","450721":"灵山县","450722":"浦北县"},"450800":{"450802":"港北区","450803":"港南区","450804":"覃塘区","450821":"平南县","450881":"桂平市"},"450900":{"450902":"玉州区","450903":"福绵区","450921":"容县","450922":"陆川县","450923":"博白县","450924":"兴业县","450981":"北流市"},"451000":{"451002":"右江区","451021":"田阳县","451022":"田东县","451023":"平果县","451024":"德保县","451026":"那坡县","451027":"凌云县","451028":"乐业县","451029":"田林县","451030":"西林县","451031":"隆林各族自治县","451081":"靖西市"},"451100":{"451102":"八步区","451103":"平桂区","451121":"昭平县","451122":"钟山县","451123":"富川瑶族自治县"},"451200":{"451202":"金城江区","451221":"南丹县","451222":"天峨县","451223":"凤山县","451224":"东兰县","451225":"罗城仫佬族自治县","451226":"环江毛南族自治县","451227":"巴马瑶族自治县","451228":"都安瑶族自治县","451229":"大化瑶族自治县","451281":"宜州市"},"451300":{"451302":"兴宾区","451321":"忻城县","451322":"象州县","451323":"武宣县","451324":"金秀瑶族自治县","451381":"合山市"},"451400":{"451402":"江州区","451421":"扶绥县","451422":"宁明县","451423":"龙州县","451424":"大新县","451425":"天等县","451481":"凭祥市"},"460000":{"460100":"海口市","460200":"三亚市","460300":"三沙市","460400":"儋州市","469001":"五指山市","469002":"琼海市","469005":"文昌市","469006":"万宁市","469007":"东方市","469021":"定安县","469022":"屯昌县","469023":"澄迈县","469024":"临高县","469025":"白沙黎族自治县","469026":"昌江黎族自治县","469027":"乐东黎族自治县","469028":"陵水黎族自治县","469029":"保亭黎族苗族自治县","469030":"琼中黎族苗族自治县"},"460100":{"460105":"秀英区","460106":"龙华区","460107":"琼山区","460108":"美兰区"},"460200":{"460202":"海棠区","460203":"吉阳区","460204":"天涯区","460205":"崖州区"},"460300":{"460321":"西沙群岛","460322":"南沙群岛","460323":"中沙群岛的岛礁及其海域"},"460400":{"4604001":"那大镇","4604004":"国营西培农场","4604005":"华南热作学院","46040011":"三都镇","460400101":"和庆镇","460400102":"南丰镇","460400103":"大成镇","460400104":"雅星镇","460400105":"兰洋镇","460400106":"光村镇","460400107":"木棠镇","460400108":"海头镇","460400109":"峨蔓镇","460400111":"王五镇","460400112":"白马井镇","460400113":"中和镇","460400114":"排浦镇","460400115":"东成镇","460400116":"新州镇","460400404":"国营西联农场","460400405":"国营蓝洋农场","460400407":"国营八一农场","460400499":"洋浦经济开发区"},"469001":{"4690011":"通什镇","4690012":"畅好乡","4690014":"畅好农场","469001101":"南圣镇","469001102":"毛阳镇","469001103":"番阳镇","469001201":"毛道乡","469001202":"水满乡"},"469002":{"4690021":"嘉积镇","4690024":"国营东太农场","4690025":"彬村山华侨农场","46900211":"大路镇","469002101":"万泉镇","469002102":"石壁镇","469002103":"中原镇","469002104":"博鳌镇","469002105":"阳江镇","469002106":"龙江镇","469002107":"潭门镇","469002108":"塔洋镇","469002109":"长坡镇","469002111":"会山镇","469002402":"国营东红农场","469002403":"国营东升农场"},"469005":{"4690051":"文城镇","4690054":"国营东路农场","46900511":"昌洒镇","469005101":"重兴镇","469005102":"蓬莱镇","469005103":"会文镇","469005104":"东路镇","469005105":"潭牛镇","469005106":"东阁镇","469005107":"文教镇","469005108":"东郊镇","469005109":"龙楼镇","469005111":"翁田镇","469005112":"抱罗镇","469005113":"冯坡镇","469005114":"锦山镇","469005115":"铺前镇","469005116":"公坡镇","469005401":"国营南阳农场","469005402":"国营罗豆农场"},"469006":{"4690061":"万城镇","4690064":"国营东兴农场","4690065":"兴隆华侨农场","46900611":"南桥镇","469006101":"龙滚镇","469006102":"和乐镇","469006103":"后安镇","469006104":"大茂镇","469006105":"东澳镇","469006106":"礼纪镇","469006107":"长丰镇","469006108":"山根镇","469006109":"北大镇","469006111":"三更罗镇","469006401":"国营东和农场","469006404":"国营新中农场","469006501":"地方国营六连林场"},"469007":{"4690071":"八所镇","4690072":"天安乡","4690074":"国营广坝农场","4690075":"东方华侨农场","469007101":"东河镇","469007102":"大田镇","469007103":"感城镇","469007104":"板桥镇","469007105":"三家镇","469007106":"四更镇","469007107":"新龙镇","469007201":"江边乡"},"469021":{"4690211":"定城镇","4690214":"国营中瑞农场","469021101":"新竹镇","469021102":"龙湖镇","469021103":"黄竹镇","469021104":"雷鸣镇","469021105":"龙门镇","469021106":"龙河镇","469021107":"岭口镇","469021108":"翰林镇","469021109":"富文镇","469021401":"国营南海农场","469021402":"国营金鸡岭农场"},"469022":{"4690221":"屯城镇","4690224":"国营中建农场","469022101":"新兴镇","469022102":"枫木镇","469022103":"乌坡镇","469022104":"南吕镇","469022105":"南坤镇","469022106":"坡心镇","469022107":"西昌镇","469022401":"国营中坤农场"},"469023":{"4690231":"金江镇","4690234":"国营红光农场","46902311":"大丰镇","469023101":"老城镇","469023102":"瑞溪镇","469023103":"永发镇","469023104":"加乐镇","469023105":"文儒镇","469023106":"中兴镇","469023107":"仁兴镇","469023108":"福山镇","469023109":"桥头镇","469023402":"国营西达农场","469023405":"国营金安农场"},"469024":{"4690241":"临城镇","4690244":"国营红华农场","469024101":"波莲镇","469024102":"东英镇","469024103":"博厚镇","469024104":"皇桐镇","469024105":"多文镇","469024106":"和舍镇","469024107":"南宝镇","469024108":"新盈镇","469024109":"调楼镇","469024401":"国营加来农场"},"469025":{"4690251":"牙叉镇","4690252":"细水乡","469025101":"七坊镇","469025102":"邦溪镇","469025103":"打安镇","469025201":"元门乡","469025202":"南开乡","469025203":"阜龙乡","469025204":"青松乡","469025205":"金波乡","469025206":"荣邦乡","469025401":"国营白沙农场","469025404":"国营龙江农场","469025408":"国营邦溪农场"},"469026":{"4690261":"石碌镇","4690262":"王下乡","4690265":"国营霸王岭林场","469026101":"叉河镇","469026102":"十月田镇","469026103":"乌烈镇","469026104":"昌化镇","469026105":"海尾镇","469026106":"七叉镇","469026401":"国营红林农场","469026501":"海南矿业联合有限公司"},"469027":{"4690271":"抱由镇","4690275":"国营尖峰岭林业公司","46902711":"莺歌海镇","469027101":"万冲镇","469027102":"大安镇","469027103":"志仲镇","469027104":"千家镇","469027105":"九所镇","469027106":"利国镇","469027107":"黄流镇","469027108":"佛罗镇","469027109":"尖峰镇","469027401":"国营山荣农场","469027402":"国营乐光农场","469027405":"国营保国农场","469027501":"国营莺歌海盐场"},"469028":{"4690281":"椰林镇","4690282":"提蒙乡","4690284":"国营岭门农场","4690285":"国营吊罗山林业公司","469028101":"光坡镇","469028102":"三才镇","469028103":"英州镇","469028104":"隆广镇","469028105":"文罗镇","469028106":"本号镇","469028107":"新村镇","469028108":"黎安镇","469028201":"群英乡","469028401":"国营南平农场"},"469029":{"4690291":"保城镇","4690292":"六弓乡","469029101":"什玲镇","469029102":"加茂镇","469029103":"响水镇","469029104":"新政镇","469029105":"三道镇","469029201":"南林乡","469029202":"毛感乡","469029401":"国营新星农场","469029402":"海南保亭热带作物研究所","469029403":"国营金江农场","469029405":"国营三道农场"},"469030":{"4690301":"营根镇","4690302":"吊罗山乡","4690305":"海南黎母山省级自然保护区管理站","469030101":"湾岭镇","469030102":"黎母山镇","469030103":"和平镇","469030104":"长征镇","469030105":"红毛镇","469030106":"中平镇","469030201":"上安乡","469030202":"什运乡","469030402":"国营阳江农场","469030403":"国营乌石农场","469030406":"国营加钗农场","469030407":"国营长征农场"},"500000":{"500100":"市辖区","500228":"梁平县","500229":"城口县","500230":"丰都县","500231":"垫江县","500232":"武隆县","500233":"忠县","500235":"云阳县","500236":"奉节县","500237":"巫山县","500238":"巫溪县","500240":"石柱土家族自治县","500241":"秀山土家族苗族自治县","500242":"酉阳土家族苗族自治县","500243":"彭水苗族土家族自治县"},"500100":{"500101":"万州区","500102":"涪陵区","500103":"渝中区","500104":"大渡口区","500105":"江北区","500106":"沙坪坝区","500107":"九龙坡区","500108":"南岸区","500109":"北碚区","500110":"綦江区","500111":"大足区","500112":"渝北区","500113":"巴南区","500114":"黔江区","500115":"长寿区","500116":"江津区","500117":"合川区","500118":"永川区","500119":"南川区","500120":"璧山区","500151":"铜梁区","500152":"潼南区","500153":"荣昌区","500154":"开州区"},"500228":{"5002282":"安胜乡","5002284":"梁平县农场","50022811":"聚奎镇","50022812":"合兴镇","500228001":"梁平县梁山街道","500228002":"梁平县双桂街道","500228101":"仁贤镇","500228102":"礼让镇","500228103":"云龙镇","500228104":"屏锦镇","500228106":"袁驿镇","500228107":"新盛镇","500228108":"福禄镇","500228109":"金带镇","500228111":"明达镇","500228112":"荫平镇","500228113":"和林镇","500228114":"回龙镇","500228115":"碧山镇","500228116":"虎城镇","500228117":"七星镇","500228118":"龙门镇","500228119":"文化镇","500228121":"石安镇","500228122":"柏家镇","500228123":"大观镇","500228124":"竹山镇","500228125":"蟠龙镇","500228126":"星桥镇","500228127":"曲水镇","500228201":"铁门乡","500228202":"龙胜乡","500228203":"复平乡","500228205":"紫照乡","500228401":"梁平县双桂工业园区"},"500229":{"50022911":"咸宜镇","50022921":"双河乡","50022922":"厚坪乡","500229001":"葛城街道","500229002":"复兴街道","500229102":"巴山镇","500229103":"坪坝镇","500229104":"庙坝镇","500229105":"明通镇","500229106":"修齐镇","500229107":"高观镇","500229108":"高燕镇","500229109":"东安镇","500229111":"高楠镇","500229201":"龙田乡","500229202":"北屏乡","500229205":"左岚乡","500229208":"沿河乡","500229211":"蓼子乡","500229212":"鸡鸣乡","500229214":"周溪乡","500229216":"明中乡","500229217":"治平乡","500229219":"岚天乡","500229221":"河鱼乡"},"500230":{"500230":"名山街道","50023011":"兴义镇","50023012":"兴龙镇","50023021":"三建乡","500230101":"虎威镇","500230102":"社坛镇","500230103":"三元镇","500230104":"许明寺镇","500230105":"董家镇","500230106":"树人镇","500230107":"十直镇","500230109":"高家镇","500230111":"双路镇","500230112":"江池镇","500230113":"龙河镇","500230114":"武平镇","500230115":"包鸾镇","500230116":"湛普镇","500230118":"南天湖镇","500230119":"保合镇","500230121":"仁沙镇","500230122":"龙孔镇","500230123":"暨龙镇","500230124":"双龙镇","500230125":"仙女湖镇","500230202":"青龙乡","500230206":"太平坝乡","500230207":"都督乡","500230209":"栗子乡"},"500231":{"50023111":"太平镇","50023112":"裴兴镇","500231001":"桂溪街道","500231002":"桂阳街道","500231101":"新民镇","500231102":"沙坪镇","500231103":"周嘉镇","500231104":"普顺镇","500231105":"永安镇","500231106":"高安镇","500231107":"高峰镇","500231108":"五洞镇","500231109":"澄溪镇","500231111":"鹤游镇","500231112":"坪山镇","500231113":"砚台镇","500231114":"曹回镇","500231115":"杠家镇","500231116":"包家镇","500231117":"白家镇","500231118":"永平镇","500231119":"三溪镇","500231121":"黄沙镇","500231122":"长龙镇","500231202":"沙河乡","500231204":"大石乡"},"500232":{"5002321":"巷口镇","5002322":"凤来乡","50023211":"土坎镇","50023221":"后坪苗族土家族乡","500232101":"火炉镇","500232102":"白马镇","500232103":"鸭江镇","500232104":"长坝镇","500232105":"江口镇","500232106":"平桥镇","500232107":"羊角镇","500232108":"仙女山镇","500232109":"桐梓镇","500232111":"和顺镇","500232112":"双河镇","500232202":"庙垭乡","500232203":"石桥苗族土家族乡","500232205":"黄莺乡","500232206":"沧沟乡","500232207":"文复苗族土家族乡","500232208":"土地乡","500232209":"白云乡","500232211":"浩口苗族仡佬族乡","500232212":"接龙乡","500232213":"赵家乡","500232214":"大洞河乡"},"500233":{"50023311":"官坝镇","50023312":"白石镇","50023321":"兴峰乡","500233001":"忠州街道","500233002":"白公街道","500233101":"新生镇","500233102":"任家镇","500233103":"乌杨镇","500233104":"洋渡镇","500233105":"东溪镇","500233106":"复兴镇","500233107":"石宝镇","500233108":"汝溪镇","500233109":"野鹤镇","500233111":"石黄镇","500233112":"马灌镇","500233113":"金鸡镇","500233114":"新立镇","500233115":"双桂镇","500233116":"拔山镇","500233117":"花桥镇","500233118":"永丰镇","500233119":"三汇镇","500233122":"黄金镇","500233201":"善广乡","500233203":"石子乡","500233204":"磨子土家族乡","500233206":"涂井乡","500233208":"金声乡"},"500235":{"50023513":"桑坪镇","50023514":"蔈草镇","500235001":"双江街道","500235002":"青龙街道","500235003":"人和街道","500235004":"盘龙街道","500235105":"龙角镇","500235107":"故陵镇","500235108":"红狮镇","500235115":"路阳镇","500235116":"农坝镇","500235118":"渠马镇","500235121":"黄石镇","500235122":"巴阳镇","500235123":"沙市镇","500235124":"鱼泉镇","500235125":"凤鸣镇","500235127":"宝坪镇","500235128":"南溪镇","500235129":"双土镇","500235131":"江口镇","500235132":"高阳镇","500235133":"平安镇","500235135":"云阳镇","500235136":"云安镇","500235137":"栖霞镇","500235138":"双龙镇","500235139":"泥溪镇","500235141":"养鹿镇","500235142":"水口镇","500235143":"堰坪镇","500235144":"龙洞镇","500235145":"后叶镇","500235146":"耀灵镇","500235147":"大阳镇","500235208":"外郎乡","500235215":"新津乡","500235216":"普安乡","500235218":"洞鹿乡","500235219":"石门乡","500235239":"上坝乡","500235242":"清水土家族自治乡"},"500236":{"50023612":"康乐镇","50023613":"新民镇","50023627":"康坪乡","500236001":"永安街道","500236002":"鱼复街道","500236003":"夔门街道","500236117":"白帝镇","500236118":"草堂镇","500236119":"汾河镇","500236121":"大树镇","500236122":"竹园镇","500236123":"公平镇","500236124":"朱衣镇","500236125":"甲高镇","500236126":"羊市镇","500236127":"吐祥镇","500236128":"兴隆镇","500236129":"青龙镇","500236131":"永乐镇","500236132":"安坪镇","500236133":"五马镇","500236134":"青莲镇","500236265":"岩湾乡","500236266":"平安乡","500236267":"红土乡","500236269":"石岗乡","500236272":"太和土家族乡","500236274":"鹤峰乡","500236275":"冯坪乡","500236276":"长安土家族乡","500236277":"龙桥土家族乡","500236278":"云雾土家族乡"},"500237":{"5002372":"红椿乡","50023711":"铜鼓镇","50023721":"建坪乡","500237001":"高唐街道","500237002":"龙门街道","500237101":"庙宇镇","500237102":"大昌镇","500237103":"福田镇","500237104":"龙溪镇","500237105":"双龙镇","500237106":"官阳镇","500237107":"骡坪镇","500237108":"抱龙镇","500237109":"官渡镇","500237111":"巫峡镇","500237207":"两坪乡","500237208":"曲尺乡","500237211":"大溪乡","500237214":"金坪乡","500237216":"平河乡","500237219":"当阳乡","500237222":"竹贤乡","500237225":"三溪乡","500237227":"培石乡","500237229":"笃坪乡","500237231":"邓家乡"},"500238":{"5002381":"城厢镇","5002384":"红池坝经济开发区","50023811":"峰灵镇","50023821":"长桂乡","50023824":"双阳乡","500238001":"宁河街道","500238002":"柏杨街道","500238101":"凤凰镇","500238102":"宁厂镇","500238103":"上磺镇","500238104":"古路镇","500238105":"文峰镇","500238106":"徐家镇","500238107":"白鹿镇","500238108":"尖山镇","500238109":"下堡镇","500238111":"塘坊镇","500238112":"朝阳镇","500238113":"田坝镇","500238114":"通城镇","500238115":"菱角镇","500238116":"蒲莲镇","500238117":"土城镇","500238204":"胜利乡","500238207":"大河乡","500238208":"天星乡","500238226":"鱼鳞乡","500238227":"乌龙乡","500238234":"中岗乡","500238237":"花台乡","500238239":"兰英乡","500238242":"中梁乡","500238243":"天元乡"},"500240":{"500240":"下路街道","50024011":"龙沙镇","50024021":"石家乡","500240101":"西沱镇","500240103":"悦崃镇","500240104":"临溪镇","500240105":"黄水镇","500240106":"马武镇","500240107":"沙子镇","500240108":"王场镇","500240109":"沿溪镇","500240111":"鱼池镇","500240112":"三河镇","500240113":"大歇镇","500240114":"桥头镇","500240115":"万朝镇","500240116":"冷水镇","500240117":"黄鹤镇","500240203":"黎场乡","500240204":"三星乡","500240205":"六塘乡","500240207":"三益乡","500240208":"王家乡","500240209":"河嘴乡","500240212":"枫木乡","500240213":"中益乡","500240214":"洗新乡","500240216":"龙潭乡","500240217":"新乐乡","500240218":"金铃乡","500240219":"金竹乡"},"500241":{"50024111":"雅江镇","500241001":"中和街道","500241002":"乌杨街道","500241003":"平凯街道","500241102":"清溪场镇","500241103":"隘口镇","500241104":"溶溪镇","500241105":"官庄镇","500241106":"龙池镇","500241107":"石堤镇","500241108":"峨溶镇","500241109":"洪安镇","500241111":"石耶镇","500241112":"梅江镇","500241113":"兰桥镇","500241114":"膏田镇","500241115":"溪口镇","500241116":"妙泉镇","500241117":"宋农镇","500241118":"里仁镇","500241119":"钟灵镇","500241201":"孝溪乡","500241207":"海洋乡","500241208":"大溪乡","500241211":"涌洞乡","500241214":"中平乡","500241215":"岑溪乡"},"500242":{"5002422":"涂市乡","50024211":"泔溪镇","50024221":"后坪乡","50024222":"清泉乡","500242001":"桃花源街道","500242002":"钟多街道","500242101":"龙潭镇","500242102":"麻旺镇","500242103":"酉酬镇","500242104":"大溪镇","500242105":"兴隆镇","500242106":"黑水镇","500242107":"丁市镇","500242108":"龚滩镇","500242109":"李溪镇","500242111":"酉水河镇","500242112":"苍岭镇","500242113":"小河镇","500242114":"板溪镇","500242202":"铜鼓乡","500242204":"可大乡","500242205":"偏柏乡","500242206":"五福乡","500242207":"木叶乡","500242208":"毛坝乡","500242209":"花田乡","500242211":"天馆乡","500242212":"宜居乡","500242213":"万木乡","500242214":"两罾乡","500242215":"板桥乡","500242216":"官清乡","500242217":"南腰界乡","500242218":"车田乡","500242219":"腴地乡","500242221":"庙溪乡","500242222":"浪坪乡","500242223":"双泉乡","500242224":"楠木乡"},"500243":{"50024311":"万足镇","50024321":"走马乡","500243001":"汉葭街道","500243002":"绍庆街道","500243003":"靛水街道","500243101":"保家镇","500243102":"郁山镇","500243103":"高谷镇","500243104":"桑柘镇","500243105":"鹿角镇","500243106":"黄家镇","500243107":"普子镇","500243108":"龙射镇","500243109":"连湖镇","500243111":"平安镇","500243112":"长生镇","500243113":"新田镇","500243114":"鞍子镇","500243115":"太原镇","500243116":"龙溪镇","500243117":"梅子垭镇","500243118":"大同镇","500243201":"岩东乡","500243202":"鹿鸣乡","500243204":"棣棠乡","500243206":"三义乡","500243207":"联合乡","500243208":"石柳乡","500243211":"芦塘乡","500243213":"乔梓乡","500243217":"诸佛乡","500243219":"桐楼乡","500243222":"善感乡","500243223":"双龙乡","500243224":"石盘乡","500243225":"大垭乡","500243226":"润溪乡","500243227":"朗溪乡","500243228":"龙塘乡"},"510000":{"510100":"成都市","510300":"自贡市","510400":"攀枝花市","510500":"泸州市","510600":"德阳市","510700":"绵阳市","510800":"广元市","510900":"遂宁市","511000":"内江市","511100":"乐山市","511300":"南充市","511400":"眉山市","511500":"宜宾市","511600":"广安市","511700":"达州市","511800":"雅安市","511900":"巴中市","512000":"资阳市","513200":"阿坝藏族羌族自治州","513300":"甘孜藏族自治州","513400":"凉山彝族自治州"},"510100":{"510104":"锦江区","510105":"青羊区","510106":"金牛区","510107":"武侯区","510108":"成华区","510112":"龙泉驿区","510113":"青白江区","510114":"新都区","510115":"温江区","510116":"双流区","510121":"金堂县","510124":"郫县","510129":"大邑县","510131":"蒲江县","510132":"新津县","510181":"都江堰市","510182":"彭州市","510183":"邛崃市","510184":"崇州市","510185":"简阳市"},"510300":{"510302":"自流井区","510303":"贡井区","510304":"大安区","510311":"沿滩区","510321":"荣县","510322":"富顺县"},"510400":{"510402":"东区","510403":"西区","510411":"仁和区","510421":"米易县","510422":"盐边县"},"510500":{"510502":"江阳区","510503":"纳溪区","510504":"龙马潭区","510521":"泸县","510522":"合江县","510524":"叙永县","510525":"古蔺县"},"510600":{"510603":"旌阳区","510623":"中江县","510626":"罗江县","510681":"广汉市","510682":"什邡市","510683":"绵竹市"},"510700":{"510703":"涪城区","510704":"游仙区","510705":"安州区","510722":"三台县","510723":"盐亭县","510725":"梓潼县","510726":"北川羌族自治县","510727":"平武县","510781":"江油市"},"510800":{"510802":"利州区","510811":"昭化区","510812":"朝天区","510821":"旺苍县","510822":"青川县","510823":"剑阁县","510824":"苍溪县"},"510900":{"510903":"船山区","510904":"安居区","510921":"蓬溪县","510922":"射洪县","510923":"大英县"},"511000":{"511002":"市中区","511011":"东兴区","511024":"威远县","511025":"资中县","511028":"隆昌县"},"511100":{"511102":"市中区","511111":"沙湾区","511112":"五通桥区","511113":"金口河区","511123":"犍为县","511124":"井研县","511126":"夹江县","511129":"沐川县","511132":"峨边彝族自治县","511133":"马边彝族自治县","511181":"峨眉山市"},"511300":{"511302":"顺庆区","511303":"高坪区","511304":"嘉陵区","511321":"南部县","511322":"营山县","511323":"蓬安县","511324":"仪陇县","511325":"西充县","511381":"阆中市"},"511400":{"511402":"东坡区","511403":"彭山区","511421":"仁寿县","511423":"洪雅县","511424":"丹棱县","511425":"青神县"},"511500":{"511502":"翠屏区","511503":"南溪区","511521":"宜宾县","511523":"江安县","511524":"长宁县","511525":"高县","511526":"珙县","511527":"筠连县","511528":"兴文县","511529":"屏山县"},"511600":{"511602":"广安区","511603":"前锋区","511621":"岳池县","511622":"武胜县","511623":"邻水县","511681":"华蓥市"},"511700":{"511702":"通川区","511703":"达川区","511722":"宣汉县","511723":"开江县","511724":"大竹县","511725":"渠县","511781":"万源市"},"511800":{"511802":"雨城区","511803":"名山区","511822":"荥经县","511823":"汉源县","511824":"石棉县","511825":"天全县","511826":"芦山县","511827":"宝兴县"},"511900":{"511902":"巴州区","511903":"恩阳区","511921":"通江县","511922":"南江县","511923":"平昌县"},"512000":{"512002":"雁江区","512021":"安岳县","512022":"乐至县"},"513200":{"513201":"马尔康市","513221":"汶川县","513222":"理县","513223":"茂县","513224":"松潘县","513225":"九寨沟县","513226":"金川县","513227":"小金县","513228":"黑水县","513230":"壤塘县","513231":"阿坝县","513232":"若尔盖县","513233":"红原县"},"513300":{"513301":"康定市","513322":"泸定县","513323":"丹巴县","513324":"九龙县","513325":"雅江县","513326":"道孚县","513327":"炉霍县","513328":"甘孜县","513329":"新龙县","513330":"德格县","513331":"白玉县","513332":"石渠县","513333":"色达县","513334":"理塘县","513335":"巴塘县","513336":"乡城县","513337":"稻城县","513338":"得荣县"},"513400":{"513401":"西昌市","513422":"木里藏族自治县","513423":"盐源县","513424":"德昌县","513425":"会理县","513426":"会东县","513427":"宁南县","513428":"普格县","513429":"布拖县","513430":"金阳县","513431":"昭觉县","513432":"喜德县","513433":"冕宁县","513434":"越西县","513435":"甘洛县","513436":"美姑县","513437":"雷波县"},"520000":{"520100":"贵阳市","520200":"六盘水市","520300":"遵义市","520400":"安顺市","520500":"毕节市","520600":"铜仁市","522300":"黔西南布依族苗族自治州","522600":"黔东南苗族侗族自治州","522700":"黔南布依族苗族自治州"},"520100":{"520102":"南明区","520103":"云岩区","520111":"花溪区","520112":"乌当区","520113":"白云区","520115":"观山湖区","520121":"开阳县","520122":"息烽县","520123":"修文县","520181":"清镇市"},"520200":{"520201":"钟山区","520203":"六枝特区","520221":"水城县","520222":"盘县"},"520300":{"520302":"红花岗区","520303":"汇川区","520304":"播州区","520322":"桐梓县","520323":"绥阳县","520324":"正安县","520325":"道真仡佬族苗族自治县","520326":"务川仡佬族苗族自治县","520327":"凤冈县","520328":"湄潭县","520329":"余庆县","520330":"习水县","520381":"赤水市","520382":"仁怀市"},"520400":{"520402":"西秀区","520403":"平坝区","520422":"普定县","520423":"镇宁布依族苗族自治县","520424":"关岭布依族苗族自治县","520425":"紫云苗族布依族自治县"},"520500":{"520502":"七星关区","520521":"大方县","520522":"黔西县","520523":"金沙县","520524":"织金县","520525":"纳雍县","520526":"威宁彝族回族苗族自治县","520527":"赫章县"},"520600":{"520602":"碧江区","520603":"万山区","520621":"江口县","520622":"玉屏侗族自治县","520623":"石阡县","520624":"思南县","520625":"印江土家族苗族自治县","520626":"德江县","520627":"沿河土家族自治县","520628":"松桃苗族自治县"},"522300":{"522301":"兴义市","522322":"兴仁县","522323":"普安县","522324":"晴隆县","522325":"贞丰县","522326":"望谟县","522327":"册亨县","522328":"安龙县"},"522600":{"522601":"凯里市","522622":"黄平县","522623":"施秉县","522624":"三穗县","522625":"镇远县","522626":"岑巩县","522627":"天柱县","522628":"锦屏县","522629":"剑河县","522630":"台江县","522631":"黎平县","522632":"榕江县","522633":"从江县","522634":"雷山县","522635":"麻江县","522636":"丹寨县"},"522700":{"522701":"都匀市","522702":"福泉市","522722":"荔波县","522723":"贵定县","522725":"瓮安县","522726":"独山县","522727":"平塘县","522728":"罗甸县","522729":"长顺县","522730":"龙里县","522731":"惠水县","522732":"三都水族自治县"},"530000":{"530100":"昆明市","530300":"曲靖市","530400":"玉溪市","530500":"保山市","530600":"昭通市","530700":"丽江市","530800":"普洱市","530900":"临沧市","532300":"楚雄彝族自治州","532500":"红河哈尼族彝族自治州","532600":"文山壮族苗族自治州","532800":"西双版纳傣族自治州","532900":"大理白族自治州","533100":"德宏傣族景颇族自治州","533300":"怒江傈僳族自治州","533400":"迪庆藏族自治州"},"530100":{"530102":"五华区","530103":"盘龙区","530111":"官渡区","530112":"西山区","530113":"东川区","530114":"呈贡区","530122":"晋宁县","530124":"富民县","530125":"宜良县","530126":"石林彝族自治县","530127":"嵩明县","530128":"禄劝彝族苗族自治县","530129":"寻甸回族彝族自治县","530181":"安宁市"},"530300":{"530302":"麒麟区","530303":"沾益区","530321":"马龙县","530322":"陆良县","530323":"师宗县","530324":"罗平县","530325":"富源县","530326":"会泽县","530381":"宣威市"},"530400":{"530402":"红塔区","530403":"江川区","530422":"澄江县","530423":"通海县","530424":"华宁县","530425":"易门县","530426":"峨山彝族自治县","530427":"新平彝族傣族自治县","530428":"元江哈尼族彝族傣族自治县"},"530500":{"530502":"隆阳区","530521":"施甸县","530523":"龙陵县","530524":"昌宁县","530581":"腾冲市"},"530600":{"530602":"昭阳区","530621":"鲁甸县","530622":"巧家县","530623":"盐津县","530624":"大关县","530625":"永善县","530626":"绥江县","530627":"镇雄县","530628":"彝良县","530629":"威信县","530630":"水富县"},"530700":{"530702":"古城区","530721":"玉龙纳西族自治县","530722":"永胜县","530723":"华坪县","530724":"宁蒗彝族自治县"},"530800":{"530802":"思茅区","530821":"宁洱哈尼族彝族自治县","530822":"墨江哈尼族自治县","530823":"景东彝族自治县","530824":"景谷傣族彝族自治县","530825":"镇沅彝族哈尼族拉祜族自治县","530826":"江城哈尼族彝族自治县","530827":"孟连傣族拉祜族佤族自治县","530828":"澜沧拉祜族自治县","530829":"西盟佤族自治县"},"530900":{"530902":"临翔区","530921":"凤庆县","530922":"云县","530923":"永德县","530924":"镇康县","530925":"双江拉祜族佤族布朗族傣族自治县","530926":"耿马傣族佤族自治县","530927":"沧源佤族自治县"},"532300":{"532301":"楚雄市","532322":"双柏县","532323":"牟定县","532324":"南华县","532325":"姚安县","532326":"大姚县","532327":"永仁县","532328":"元谋县","532329":"武定县","532331":"禄丰县"},"532500":{"532501":"个旧市","532502":"开远市","532503":"蒙自市","532504":"弥勒市","532523":"屏边苗族自治县","532524":"建水县","532525":"石屏县","532527":"泸西县","532528":"元阳县","532529":"红河县","532530":"金平苗族瑶族傣族自治县","532531":"绿春县","532532":"河口瑶族自治县"},"532600":{"532601":"文山市","532622":"砚山县","532623":"西畴县","532624":"麻栗坡县","532625":"马关县","532626":"丘北县","532627":"广南县","532628":"富宁县"},"532800":{"532801":"景洪市","532822":"勐海县","532823":"勐腊县"},"532900":{"532901":"大理市","532922":"漾濞彝族自治县","532923":"祥云县","532924":"宾川县","532925":"弥渡县","532926":"南涧彝族自治县","532927":"巍山彝族回族自治县","532928":"永平县","532929":"云龙县","532930":"洱源县","532931":"剑川县","532932":"鹤庆县"},"533100":{"533102":"瑞丽市","533103":"芒市","533122":"梁河县","533123":"盈江县","533124":"陇川县"},"533300":{"533301":"泸水市","533323":"福贡县","533324":"贡山独龙族怒族自治县","533325":"兰坪白族普米族自治县"},"533400":{"533401":"香格里拉市","533422":"德钦县","533423":"维西傈僳族自治县"},"540000":{"540100":"拉萨市","540200":"日喀则市","540300":"昌都市","540400":"林芝市","540500":"山南市","542400":"那曲地区","542500":"阿里地区"},"540100":{"540102":"城关区","540103":"堆龙德庆区","540121":"林周县","540122":"当雄县","540123":"尼木县","540124":"曲水县","540126":"达孜县","540127":"墨竹工卡县"},"540200":{"540202":"桑珠孜区","540221":"南木林县","540222":"江孜县","540223":"定日县","540224":"萨迦县","540225":"拉孜县","540226":"昂仁县","540227":"谢通门县","540228":"白朗县","540229":"仁布县","540230":"康马县","540231":"定结县","540232":"仲巴县","540233":"亚东县","540234":"吉隆县","540235":"聂拉木县","540236":"萨嘎县","540237":"岗巴县"},"540300":{"540302":"卡若区","540321":"江达县","540322":"贡觉县","540323":"类乌齐县","540324":"丁青县","540325":"察雅县","540326":"八宿县","540327":"左贡县","540328":"芒康县","540329":"洛隆县","540330":"边坝县"},"540400":{"540402":"巴宜区","540421":"工布江达县","540422":"米林县","540423":"墨脱县","540424":"波密县","540425":"察隅县","540426":"朗县"},"540500":{"540502":"乃东区","540521":"扎囊县","540522":"贡嘎县","540523":"桑日县","540524":"琼结县","540525":"曲松县","540526":"措美县","540527":"洛扎县","540528":"加查县","540529":"隆子县","540530":"错那县","540531":"浪卡子县"},"542400":{"542421":"那曲县","542422":"嘉黎县","542423":"比如县","542424":"聂荣县","542425":"安多县","542426":"申扎县","542427":"索县","542428":"班戈县","542429":"巴青县","542430":"尼玛县","542431":"双湖县"},"542500":{"542521":"普兰县","542522":"札达县","542523":"噶尔县","542524":"日土县","542525":"革吉县","542526":"改则县","542527":"措勤县"},"610000":{"610100":"西安市","610200":"铜川市","610300":"宝鸡市","610400":"咸阳市","610500":"渭南市","610600":"延安市","610700":"汉中市","610800":"榆林市","610900":"安康市","611000":"商洛市"},"610100":{"610102":"新城区","610103":"碑林区","610104":"莲湖区","610111":"灞桥区","610112":"未央区","610113":"雁塔区","610114":"阎良区","610115":"临潼区","610116":"长安区","610117":"高陵区","610122":"蓝田县","610124":"周至县","610125":"户县"},"610200":{"610202":"王益区","610203":"印台区","610204":"耀州区","610222":"宜君县"},"610300":{"610302":"渭滨区","610303":"金台区","610304":"陈仓区","610322":"凤翔县","610323":"岐山县","610324":"扶风县","610326":"眉县","610327":"陇县","610328":"千阳县","610329":"麟游县","610330":"凤县","610331":"太白县"},"610400":{"610402":"秦都区","610403":"杨陵区","610404":"渭城区","610422":"三原县","610423":"泾阳县","610424":"乾县","610425":"礼泉县","610426":"永寿县","610427":"彬县","610428":"长武县","610429":"旬邑县","610430":"淳化县","610431":"武功县","610481":"兴平市"},"610500":{"610502":"临渭区","610503":"华州区","610522":"潼关县","610523":"大荔县","610524":"合阳县","610525":"澄城县","610526":"蒲城县","610527":"白水县","610528":"富平县","610581":"韩城市","610582":"华阴市"},"610600":{"610602":"宝塔区","610603":"安塞区","610621":"延长县","610622":"延川县","610623":"子长县","610625":"志丹县","610626":"吴起县","610627":"甘泉县","610628":"富县","610629":"洛川县","610630":"宜川县","610631":"黄龙县","610632":"黄陵县"},"610700":{"610702":"汉台区","610721":"南郑县","610722":"城固县","610723":"洋县","610724":"西乡县","610725":"勉县","610726":"宁强县","610727":"略阳县","610728":"镇巴县","610729":"留坝县","610730":"佛坪县"},"610800":{"610802":"榆阳区","610803":"横山区","610821":"神木县","610822":"府谷县","610824":"靖边县","610825":"定边县","610826":"绥德县","610827":"米脂县","610828":"佳县","610829":"吴堡县","610830":"清涧县","610831":"子洲县"},"610900":{"610902":"汉滨区","610921":"汉阴县","610922":"石泉县","610923":"宁陕县","610924":"紫阳县","610925":"岚皋县","610926":"平利县","610927":"镇坪县","610928":"旬阳县","610929":"白河县"},"611000":{"611002":"商州区","611021":"洛南县","611022":"丹凤县","611023":"商南县","611024":"山阳县","611025":"镇安县","611026":"柞水县"},"620000":{"620100":"兰州市","620200":"嘉峪关市","620300":"金昌市","620400":"白银市","620500":"天水市","620600":"武威市","620700":"张掖市","620800":"平凉市","620900":"酒泉市","621000":"庆阳市","621100":"定西市","621200":"陇南市","622900":"临夏回族自治州","623000":"甘南藏族自治州"},"620100":{"620102":"城关区","620103":"七里河区","620104":"西固区","620105":"安宁区","620111":"红古区","620121":"永登县","620122":"皋兰县","620123":"榆中县"},"620200":{},"620300":{"620302":"金川区","620321":"永昌县"},"620400":{"620402":"白银区","620403":"平川区","620421":"靖远县","620422":"会宁县","620423":"景泰县"},"620500":{"620502":"秦州区","620503":"麦积区","620521":"清水县","620522":"秦安县","620523":"甘谷县","620524":"武山县","620525":"张家川回族自治县"},"620600":{"620602":"凉州区","620621":"民勤县","620622":"古浪县","620623":"天祝藏族自治县"},"620700":{"620702":"甘州区","620721":"肃南裕固族自治县","620722":"民乐县","620723":"临泽县","620724":"高台县","620725":"山丹县"},"620800":{"620802":"崆峒区","620821":"泾川县","620822":"灵台县","620823":"崇信县","620824":"华亭县","620825":"庄浪县","620826":"静宁县"},"620900":{"620902":"肃州区","620921":"金塔县","620922":"瓜州县","620923":"肃北蒙古族自治县","620924":"阿克塞哈萨克族自治县","620981":"玉门市","620982":"敦煌市"},"621000":{"621002":"西峰区","621021":"庆城县","621022":"环县","621023":"华池县","621024":"合水县","621025":"正宁县","621026":"宁县","621027":"镇原县"},"621100":{"621102":"安定区","621121":"通渭县","621122":"陇西县","621123":"渭源县","621124":"临洮县","621125":"漳县","621126":"岷县"},"621200":{"621202":"武都区","621221":"成县","621222":"文县","621223":"宕昌县","621224":"康县","621225":"西和县","621226":"礼县","621227":"徽县","621228":"两当县"},"622900":{"622901":"临夏市","622921":"临夏县","622922":"康乐县","622923":"永靖县","622924":"广河县","622925":"和政县","622926":"东乡族自治县","622927":"积石山保安族东乡族撒拉族自治县"},"623000":{"623001":"合作市","623021":"临潭县","623022":"卓尼县","623023":"舟曲县","623024":"迭部县","623025":"玛曲县","623026":"碌曲县","623027":"夏河县"},"630000":{"630100":"西宁市","630200":"海东市","632200":"海北藏族自治州","632300":"黄南藏族自治州","632500":"海南藏族自治州","632600":"果洛藏族自治州","632700":"玉树藏族自治州","632800":"海西蒙古族藏族自治州"},"630100":{"630102":"城东区","630103":"城中区","630104":"城西区","630105":"城北区","630121":"大通回族土族自治县","630122":"湟中县","630123":"湟源县"},"630200":{"630202":"乐都区","630203":"平安区","630222":"民和回族土族自治县","630223":"互助土族自治县","630224":"化隆回族自治县","630225":"循化撒拉族自治县"},"632200":{"632221":"门源回族自治县","632222":"祁连县","632223":"海晏县","632224":"刚察县"},"632300":{"632321":"同仁县","632322":"尖扎县","632323":"泽库县","632324":"河南蒙古族自治县"},"632500":{"632521":"共和县","632522":"同德县","632523":"贵德县","632524":"兴海县","632525":"贵南县"},"632600":{"632621":"玛沁县","632622":"班玛县","632623":"甘德县","632624":"达日县","632625":"久治县","632626":"玛多县"},"632700":{"632701":"玉树市","632722":"杂多县","632723":"称多县","632724":"治多县","632725":"囊谦县","632726":"曲麻莱县"},"632800":{"632801":"格尔木市","632802":"德令哈市","632821":"乌兰县","632822":"都兰县","632823":"天峻县"},"640000":{"640100":"银川市","640200":"石嘴山市","640300":"吴忠市","640400":"固原市","640500":"中卫市"},"640100":{"640104":"兴庆区","640105":"西夏区","640106":"金凤区","640121":"永宁县","640122":"贺兰县","640181":"灵武市"},"640200":{"640202":"大武口区","640205":"惠农区","640221":"平罗县"},"640300":{"640302":"利通区","640303":"红寺堡区","640323":"盐池县","640324":"同心县","640381":"青铜峡市"},"640400":{"640402":"原州区","640422":"西吉县","640423":"隆德县","640424":"泾源县","640425":"彭阳县"},"640500":{"640502":"沙坡头区","640521":"中宁县","640522":"海原县"},"650000":{"650100":"乌鲁木齐市","650200":"克拉玛依市","650400":"吐鲁番市","650500":"哈密市","652300":"昌吉回族自治州","652700":"博尔塔拉蒙古自治州","652800":"巴音郭楞蒙古自治州","652900":"阿克苏地区","653000":"克孜勒苏柯尔克孜自治州","653100":"喀什地区","653200":"和田地区","654000":"伊犁哈萨克自治州","654200":"塔城地区","654300":"阿勒泰地区","659001":"石河子市","659002":"阿拉尔市","659003":"图木舒克市","659004":"五家渠市","659006":"铁门关市"},"650100":{"650102":"天山区","650103":"沙依巴克区","650104":"新市区","650105":"水磨沟区","650106":"头屯河区","650107":"达坂城区","650109":"米东区","650121":"乌鲁木齐县"},"650200":{"650202":"独山子区","650203":"克拉玛依区","650204":"白碱滩区","650205":"乌尔禾区"},"650400":{"650402":"高昌区","650421":"鄯善县","650422":"托克逊县"},"650500":{"650502":"伊州区","650521":"巴里坤哈萨克自治县","650522":"伊吾县"},"652300":{"652301":"昌吉市","652302":"阜康市","652323":"呼图壁县","652324":"玛纳斯县","652325":"奇台县","652327":"吉木萨尔县","652328":"木垒哈萨克自治县"},"652700":{"652701":"博乐市","652702":"阿拉山口市","652722":"精河县","652723":"温泉县"},"652800":{"652801":"库尔勒市","652822":"轮台县","652823":"尉犁县","652824":"若羌县","652825":"且末县","652826":"焉耆回族自治县","652827":"和静县","652828":"和硕县","652829":"博湖县"},"652900":{"652901":"阿克苏市","652922":"温宿县","652923":"库车县","652924":"沙雅县","652925":"新和县","652926":"拜城县","652927":"乌什县","652928":"阿瓦提县","652929":"柯坪县"},"653000":{"653001":"阿图什市","653022":"阿克陶县","653023":"阿合奇县","653024":"乌恰县"},"653100":{"653101":"喀什市","653121":"疏附县","653122":"疏勒县","653123":"英吉沙县","653124":"泽普县","653125":"莎车县","653126":"叶城县","653127":"麦盖提县","653128":"岳普湖县","653129":"伽师县","653130":"巴楚县","653131":"塔什库尔干塔吉克自治县"},"653200":{"653201":"和田市","653221":"和田县","653222":"墨玉县","653223":"皮山县","653224":"洛浦县","653225":"策勒县","653226":"于田县","653227":"民丰县"},"654000":{"654002":"伊宁市","654003":"奎屯市","654004":"霍尔果斯市","654021":"伊宁县","654022":"察布查尔锡伯自治县","654023":"霍城县","654024":"巩留县","654025":"新源县","654026":"昭苏县","654027":"特克斯县","654028":"尼勒克县"},"654200":{"654201":"塔城市","654202":"乌苏市","654221":"额敏县","654223":"沙湾县","654224":"托里县","654225":"裕民县","654226":"和布克赛尔蒙古自治县"},"654300":{"654301":"阿勒泰市","654321":"布尔津县","654322":"富蕴县","654323":"福海县","654324":"哈巴河县","654325":"青河县","654326":"吉木乃县"},"659001":{"6590011":"北泉镇","6590015":"兵团一五二团","659001001":"新城街道","659001002":"向阳街道","659001003":"红山街道","659001004":"老街街道","659001005":"东城街道","659001101":"石河子镇"},"659002":{"6590022":"托喀依乡","6590025":"兵团七团","65900252":"兵团三团","659002001":"金银川路街道","659002002":"幸福路街道","659002003":"青松路街道","659002004":"南口街道","659002402":"工业园区","659002501":"兵团八团","659002503":"兵团十团","659002504":"兵团十一团","659002505":"兵团十二团","659002506":"兵团十三团","659002507":"兵团十四团","659002509":"兵团十六团","659002511":"兵团第一师水利水电工程处","659002512":"兵团第一师塔里木灌区水利管理处","659002513":"阿拉尔农场","659002514":"兵团第一师幸福农场","659002515":"中心监狱","659002516":"兵团一团","659002517":"兵团农一师沙井子水利管理处","659002518":"西工业园区管理委员会","659002519":"兵团二团"},"659003":{"65900351":"兵团五十团","659003001":"齐干却勒街道","659003002":"前海街道","659003003":"永安坝街道","659003504":"兵团四十四团","659003509":"兵团四十九团","659003511":"兵团五十一团","659003513":"兵团五十三团","659003514":"兵团图木舒克市喀拉拜勒镇"},"659004":{"6590045":"兵团一零一团","659004001":"军垦路街道","659004002":"青湖路街道","659004003":"人民路街道","659004501":"兵团一零二团","659004502":"兵团一零三团"}, | ||
| 45 | + "659006":{"6590061":"博古其镇","659006101":"双丰镇"}, | ||
| 46 | + "710000":{"710100":"台湾省"}, | ||
| 47 | + "710100":{"710101":"金门","710102":"连江","710103":"苗栗","710104":"南投","710105":"澎湖","710106":"屏东","710107":"台东","710108":"台中","710109":"台南","710110":"台北","710111":"桃园","710112":"云林","710113":"新北","710114":"彰化","710115":"嘉义","710116":"新竹","710117":"花莲","710118":"宜兰","710119":"高雄","710120":"基隆"}, | ||
| 48 | + "910000":{"810000":"香港特别行政区","820000":"澳门特别行政区"}, | ||
| 49 | + "810000":{"810101":"中西区","810102":"东区","810103":"九龙城区","810104":"观塘区","810105":"深水埗区","810106":"湾仔区","810107":"黄大仙区","810108":"油尖旺区","810109":"离岛区","810110":"葵青区","810111":"北区","810112":"西贡区","810113":"沙田区","810114":"屯门区","810115":"大埔区","810116":"荃湾区","810117":"元朗区","810118":"香港","810119":"九龙","810120":"新界"}, | ||
| 50 | + "820000":{"820101":"离岛","820102":"澳门半岛","820103":"凼仔","820104":"路凼城","820105":"路环"} | ||
| 51 | +} | ||
| 0 | \ No newline at end of file | 52 | \ No newline at end of file |
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/CommonAPI.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/IWpsBaseAPI.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/desform/ISysTranslateAPI.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/FileDownDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/FileUploadDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/LogDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/OnlineAuthDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/message/BusMessageDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/message/BusTemplateMessageDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/message/MessageDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/message/TemplateDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/dto/message/TemplateMessageDTO.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/vo/OaWpsModel.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/api/vo/Result.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/AutoLogAspect$1.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/AutoLogAspect.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/DictAspect.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/PermissionDataAspect.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/UrlMatchEnum.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/annotation/AutoLog.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/annotation/Dict.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/annotation/OnlineAuth.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/aspect/annotation/PermissionData.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/CommonConstant.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/CommonSendStatus.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/DataBaseConstant.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/FillRuleConstant.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/ProvinceCityArea$Area.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/ProvinceCityArea.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/ServiceNameConstants.class
0 → 100644
No preview for this file type
juvenile-prosecution-boot/jeecg-boot-base/jeecg-boot-base-core/target/classes/org/jeecg/common/constant/VXESocketConst.class
0 → 100644
No preview for this file type