From 02d7d63276789e4d0283c6eb700d51ef0282cada Mon Sep 17 00:00:00 2001 From: fuhouyin Date: Tue, 24 Dec 2024 15:22:53 +0800 Subject: [PATCH] =?UTF-8?q?:tada:=20=E6=B7=BB=E5=8A=A0=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/{pojo => }/PublicConst.java | 2 +- .../com/darkness/common/util/Base64Utils.java | 104 ++++++ .../darkness/common/util/CamelCaseUtil.java | 51 +++ .../com/darkness/common/util/CryptoUtils.java | 67 ++++ .../darkness/common/util/DateTimeUtils.java | 101 ++++++ .../com/darkness/common/util/EntityUtil.java | 74 +++++ .../com/darkness/common/util/FileUtils.java | 299 ++++++++++++++++++ .../com/darkness/common/util/HandlePage.java | 17 + .../darkness/common/util/MethodGetAndSet.java | 90 ++++++ .../com/darkness/common/util/SM2Util.java | 293 +++++++++++++++++ .../darkness/common/util/page/PageHelper.java | 89 ++++++ .../darkness/common/util/page/PageReq.java | 16 + .../darkness/common/util/page/PageReqCmd.java | 14 + .../darkness/common/util/page/PageResp.java | 15 + .../common/util/redis/RedisCacheUtils.java | 177 +++++++++++ .../util/redis/RedisTemplateProvider.java | 14 + .../util/redis/RedisTemplateProviderImpl.java | 95 ++++++ .../common/util/response/ResultEnums.java | 59 ++++ .../common/util/response/VoResult.java | 148 +++++++++ 19 files changed, 1724 insertions(+), 1 deletion(-) rename src/main/java/com/darkness/common/{pojo => }/PublicConst.java (97%) create mode 100644 src/main/java/com/darkness/common/util/Base64Utils.java create mode 100644 src/main/java/com/darkness/common/util/CamelCaseUtil.java create mode 100644 src/main/java/com/darkness/common/util/CryptoUtils.java create mode 100644 src/main/java/com/darkness/common/util/DateTimeUtils.java create mode 100644 src/main/java/com/darkness/common/util/EntityUtil.java create mode 100644 src/main/java/com/darkness/common/util/FileUtils.java create mode 100644 src/main/java/com/darkness/common/util/HandlePage.java create mode 100644 src/main/java/com/darkness/common/util/MethodGetAndSet.java create mode 100644 src/main/java/com/darkness/common/util/SM2Util.java create mode 100644 src/main/java/com/darkness/common/util/page/PageHelper.java create mode 100644 src/main/java/com/darkness/common/util/page/PageReq.java create mode 100644 src/main/java/com/darkness/common/util/page/PageReqCmd.java create mode 100644 src/main/java/com/darkness/common/util/page/PageResp.java create mode 100644 src/main/java/com/darkness/common/util/redis/RedisCacheUtils.java create mode 100644 src/main/java/com/darkness/common/util/redis/RedisTemplateProvider.java create mode 100644 src/main/java/com/darkness/common/util/redis/RedisTemplateProviderImpl.java create mode 100644 src/main/java/com/darkness/common/util/response/ResultEnums.java create mode 100644 src/main/java/com/darkness/common/util/response/VoResult.java diff --git a/src/main/java/com/darkness/common/pojo/PublicConst.java b/src/main/java/com/darkness/common/PublicConst.java similarity index 97% rename from src/main/java/com/darkness/common/pojo/PublicConst.java rename to src/main/java/com/darkness/common/PublicConst.java index 3fb9a16..a31b93e 100644 --- a/src/main/java/com/darkness/common/pojo/PublicConst.java +++ b/src/main/java/com/darkness/common/PublicConst.java @@ -1,4 +1,4 @@ -package com.darkness.common.pojo; +package com.darkness.common; /** * 公共常量类 diff --git a/src/main/java/com/darkness/common/util/Base64Utils.java b/src/main/java/com/darkness/common/util/Base64Utils.java new file mode 100644 index 0000000..83bd8a6 --- /dev/null +++ b/src/main/java/com/darkness/common/util/Base64Utils.java @@ -0,0 +1,104 @@ +package com.darkness.common.util; + +import org.apache.commons.codec.binary.Base64; + +import java.io.*; + +public class Base64Utils { + + /** + * BASE64编码解码工具包 + * 依赖javabase64-1.3.1.jar + * + * @date 2012-5-19 + * @version 1.0 + */ + + /** + * 文件读取缓冲区大小 + */ + private static final int CACHE_SIZE = 1024; + + /** + * BASE64字符串解码为二进制数据 + */ + public static byte[] decode(String base64) throws Exception { + return Base64.decodeBase64(base64.getBytes()); + // return Base64.decode(base64.getBytes()); + } + + /** + * 二进制数据编码为BASE64字符串 + */ + public static String encode(byte[] bytes) throws Exception { + return new String(Base64.encodeBase64(bytes)); + // return new String(Base64.encode(bytes)); + } + + /** + * 将文件编码为BASE64字符串 + * 大文件慎用,可能会导致内存溢出 + * + * @param filePath 文件绝对路径 + */ + public static String encodeFile(String filePath) throws Exception { + byte[] bytes = fileToByte(filePath); + return encode(bytes); + } + + /** + * BASE64字符串转回文件 + * @param filePath 文件绝对路径 + * @param base64 编码字符串 + */ + public static void decodeToFile(String filePath, String base64) throws Exception { + byte[] bytes = decode(base64); + byteArrayToFile(bytes, filePath); + } + + /** + * 文件转换为二进制数组 + * @param filePath 文件路径 + */ + public static byte[] fileToByte(String filePath) throws Exception { + byte[] data = new byte[0]; + File file = new File(filePath); + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream out = new ByteArrayOutputStream(2048); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + data = out.toByteArray(); + } + return data; + } + + /** + * 二进制数据写文件 + * @param bytes 二进制数据 + * @param filePath 文件生成目录 + */ + public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { + InputStream in = new ByteArrayInputStream(bytes); + File destFile = new File(filePath); + if (!destFile.getParentFile().exists()) { + destFile.getParentFile().mkdirs(); + } + destFile.createNewFile(); + OutputStream out = new FileOutputStream(destFile); + byte[] cache = new byte[CACHE_SIZE]; + int nRead = 0; + while ((nRead = in.read(cache)) != -1) { + out.write(cache, 0, nRead); + out.flush(); + } + out.close(); + in.close(); + } +} diff --git a/src/main/java/com/darkness/common/util/CamelCaseUtil.java b/src/main/java/com/darkness/common/util/CamelCaseUtil.java new file mode 100644 index 0000000..dade93f --- /dev/null +++ b/src/main/java/com/darkness/common/util/CamelCaseUtil.java @@ -0,0 +1,51 @@ +package com.darkness.common.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CamelCaseUtil { + + /** + * 数据表字段名转换为驼峰式名字的实体类属性名 + * @param tabAttr 数据表字段名 + * @return 转换后的驼峰式命名 + */ + public static String camelize(String tabAttr){ + if(isBlank(tabAttr)) + return tabAttr; + Pattern pattern = Pattern.compile("(.*)_(\\w)(.*)"); + Matcher matcher = pattern.matcher(tabAttr); + if(matcher.find()){ + return camelize(matcher.group(1) + matcher.group(2).toUpperCase() + matcher.group(3)); + }else{ + return tabAttr; + } + } + + /** + * 驼峰式的实体类属性名转换为数据表字段名 + * @param camelCaseStr 驼峰式的实体类属性名 + * @return 转换后的以"_"分隔的数据表字段名 + */ + public static String decamelize(String camelCaseStr){ + return isBlank(camelCaseStr) ? camelCaseStr : camelCaseStr.replaceAll("[A-Z]", "_$0").toLowerCase(); + } + + /** + * 字符串是否为空 + * @param cs 待检查的字符串 + * @return 空:true; 非空:false + */ + public static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/com/darkness/common/util/CryptoUtils.java b/src/main/java/com/darkness/common/util/CryptoUtils.java new file mode 100644 index 0000000..069fa89 --- /dev/null +++ b/src/main/java/com/darkness/common/util/CryptoUtils.java @@ -0,0 +1,67 @@ +package com.darkness.common.util; + +import org.apache.commons.codec.binary.Hex; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; + +public class CryptoUtils { + + static { + if (Security.getProvider("BC") == null) { + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } else { + Security.removeProvider("BC"); + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + } + } + + /** + * 使用AES-128-CBC加密模式,key需要为16位,key和iv可以相同,也可以不同! + */ + private static final String KEY = "UNo49jvVsvz5idwx"; + private static final String IV = "UNo49jvVsvz5idwx"; + private static Cipher cipher = null; + private static final byte[] raw = KEY.getBytes(StandardCharsets.UTF_8); + private static final SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + private static final IvParameterSpec iv = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));// 使用CBC模式,需要一个向量iv,可增加加密算法的强度 + + static { + try { + cipher = Cipher.getInstance("AES/CBC/PKCS7Padding","BC"); + } catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException e) { + e.printStackTrace(); + } + } + + /** + * 加密 + */ + public static String encryptAESPkcs7(String sourceStr) throws Exception{ + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); + byte[] encrypted = cipher.doFinal(sourceStr.getBytes(StandardCharsets.UTF_8)); + return Hex.encodeHexString(encrypted); + + } + + public static String decryptAESPkcs7(String sourceStr) throws Exception{ + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + byte[] original = cipher.doFinal(Hex.decodeHex(sourceStr)); + return new String(original, StandardCharsets.UTF_8); + } + + // 文章参考 https://blog.csdn.net/haoyafei_/article/details/106826423 + public static void main(String[] args) throws Exception{ + String str = "3.141592653579"; + String enc = encryptAESPkcs7(str); + String dec = decryptAESPkcs7(enc); + System.out.println(enc); + System.out.println(dec); + } +} diff --git a/src/main/java/com/darkness/common/util/DateTimeUtils.java b/src/main/java/com/darkness/common/util/DateTimeUtils.java new file mode 100644 index 0000000..014e9c4 --- /dev/null +++ b/src/main/java/com/darkness/common/util/DateTimeUtils.java @@ -0,0 +1,101 @@ +package com.darkness.common.util; + +import lombok.Data; + +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.util.Calendar; +import java.util.Date; +import java.util.Objects; + + +public class DateTimeUtils { + + /** + * 计算两个日期之间相差的天数 + * @param smdate 开始时间 + * @param bdate 结束时间 + */ + public static int daysBetween(Date smdate, Date bdate) throws ParseException { + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); + smdate=sdf.parse(sdf.format(smdate)); + bdate=sdf.parse(sdf.format(bdate)); + Calendar cal = Calendar.getInstance(); + cal.setTime(smdate); + long time1 = cal.getTimeInMillis(); + cal.setTime(bdate); + long time2 = cal.getTimeInMillis(); + long between_days=(time2-time1)/(1000*3600*24); + return Integer.parseInt(String.valueOf(between_days)); + } + + /** + * 计算临期/超期天数 + * 临期 包括今天 + * 超期 不包括今天 + * @param endDate 截至时间 + * @param finishDate 完成时间 + */ + public static TimeOverdueAdventPojo overdueAdvent(Date endDate, Date finishDate) throws ParseException { + + TimeOverdueAdventPojo timeOverdueAdventPojo = new TimeOverdueAdventPojo(); + + SimpleDateFormat sdf_YMD2359 = new SimpleDateFormat("yyyy-MM-dd 23:59:59"); + SimpleDateFormat sdf_YMDHMS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + SimpleDateFormat sdf_YMD = new SimpleDateFormat("yyyy-MM-dd"); + + String format = sdf_YMD2359.format(endDate); + + //当前时间 + Date nowTime = new Date(Timestamp.from(Instant.now()).getTime()); + Date endTime = new Date(sdf_YMD.parse(format).getTime()); + Date endTime_flag = new Date(sdf_YMDHMS.parse(format).getTime()); + + Calendar cal = Calendar.getInstance(); + cal.setTime(endTime); + long timeEnd = cal.getTimeInMillis(); + cal.setTime(nowTime); + long timeNow = cal.getTimeInMillis(); + + if (Objects.isNull(finishDate)){ + if (nowTime.after(endTime_flag)){ + long between_days = (timeEnd - timeNow) / (1000 * 3600 * 24); + timeOverdueAdventPojo.setFlag((byte) 1); + timeOverdueAdventPojo.setOaFlag("逾期"); + timeOverdueAdventPojo.setDays(Integer.parseInt(String.valueOf(between_days))); + }else { + long between_days = (endTime_flag.getTime() - nowTime.getTime()) / (1000 * 3600 * 24); + timeOverdueAdventPojo.setFlag((byte) 0); + timeOverdueAdventPojo.setOaFlag("临期"); + timeOverdueAdventPojo.setDays(Integer.parseInt(String.valueOf(between_days + 1))); + } + }else { + Date finishTime = new Date(finishDate.getTime()); + cal.setTime(finishTime); + long timeFinish = cal.getTimeInMillis(); + if (finishDate.after(endTime_flag)){ + long between_days = (timeEnd - timeFinish) / (1000 * 3600 * 24); + timeOverdueAdventPojo.setFlag((byte) 1); + timeOverdueAdventPojo.setOaFlag("逾期"); + timeOverdueAdventPojo.setDays(Integer.parseInt(String.valueOf(between_days))); + }else { + long between_days = (endTime_flag.getTime() - timeFinish) / (1000 * 3600 * 24); + timeOverdueAdventPojo.setFlag((byte) 0); + timeOverdueAdventPojo.setOaFlag("临期"); + timeOverdueAdventPojo.setDays(Integer.parseInt(String.valueOf(between_days + 1))); + } + } + + return timeOverdueAdventPojo; + } + + @Data + public static class TimeOverdueAdventPojo { + + private int days; + private byte flag; //未逾期 0 逾期 1 + private String oaFlag; //临期 advent 逾期 overdue + } +} diff --git a/src/main/java/com/darkness/common/util/EntityUtil.java b/src/main/java/com/darkness/common/util/EntityUtil.java new file mode 100644 index 0000000..f3faeb2 --- /dev/null +++ b/src/main/java/com/darkness/common/util/EntityUtil.java @@ -0,0 +1,74 @@ +package com.darkness.common.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EntityUtil { + + /** + * 实体类转Map + */ + public static Map entityToMap(Object entity) { + Map result = new HashMap<>(); + Field[] fields = entity.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + try { + result.put(field.getName(), field.get(entity)); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + return result; + } + + /** + * 获取实体类中所有不为空的字段名 + */ + public static List findNotNullFields(Object obj) { + List notNullFields = new ArrayList<>(); + Class clazz = obj.getClass(); + for (Field field : clazz.getDeclaredFields()) { + field.setAccessible(true); + try { + Object value = field.get(obj); + if (value!= null) { + notNullFields.add(field.getName()); + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + return notNullFields; + } + + /** + * 根据字段名获取值 + */ + public static Object getFieldValue(String fieldName, Object obj) throws Exception { + Class clazz = obj.getClass(); + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(obj); + } + + /** + * 解析json字符串为MultiValueMap + */ + public static MultiValueMap getMultiValueMap(String json) throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + Map map = objectMapper.readValue(json, Map.class); + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + for (Map.Entry entry : map.entrySet()) { + multiValueMap.add(entry.getKey(), entry.getValue()); + } + return multiValueMap; + } +} diff --git a/src/main/java/com/darkness/common/util/FileUtils.java b/src/main/java/com/darkness/common/util/FileUtils.java new file mode 100644 index 0000000..edd273f --- /dev/null +++ b/src/main/java/com/darkness/common/util/FileUtils.java @@ -0,0 +1,299 @@ +package com.darkness.common.util; + +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; + +public class FileUtils { + + /** + * 根据文件后缀名,获取base64的文件头 + * @param str 文件名后缀 + */ + public static String suffix(String str){ + String strSuffix = null; + switch (str) { + case "txt": strSuffix = "data:text/plain;base64,"; break; + case "doc": strSuffix = "data:application/msword;base64,";break; + case "docx": strSuffix = "data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,";break; + case "xls": strSuffix = "data:application/vnd.ms-excel;base64,";break; + case "xlsx": strSuffix = "data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,";break; + case "pdf": strSuffix = "data:application/pdf;base64,";break; + case "pptx": strSuffix = "data:application/vnd.openxmlformats-officedocument.presentationml.presentation;base64,";break; + case "ppt": strSuffix = "data:application/vnd.ms-powerpoint;base64,";break; + case "png": strSuffix = "data:image/png;base64,";break; + case "jpg": strSuffix = "data:image/jpeg;base64,";break; + case "gif": strSuffix = "data:image/gif;base64,";break; + case "svg": strSuffix = "data:image/svg+xml;base64,";break; + case "ico": strSuffix = "data:image/x-icon;base64,";break; + case "bmp": strSuffix = "data:image/bmp;base64,";break; + default: strSuffix = "data:image/bmp;base64,";break; + } + return strSuffix; + } + + /** + * 文件转base64 + * @param path 文件地址 + */ + public static String fileToBase64(String path) throws Exception { + byte[] b = Files.readAllBytes(Paths.get(path)); + String strSuffix = suffix(path.substring(path.lastIndexOf(".") + 1)); + String base64 = Base64.getEncoder().encodeToString(b); + return strSuffix + base64; + } + + /** + * 保存文件 + * @param path 文件地址 + * @param multipartFile 文件 + */ + public static void saveFile(String path, MultipartFile multipartFile) throws Exception { + File dest = new File(path); + assert multipartFile != null; + multipartFile.transferTo(dest); + } + + /** + * 将InputStream写入本地文件 + * @param destination 写入本地目录 指定到文件名 + * @param input 输入流 + */ + public static void writeToLocal(String destination, InputStream input) + throws IOException { + int index; + byte[] bytes = new byte[1024]; + FileOutputStream downloadFile = new FileOutputStream(destination); + while ((index = input.read(bytes)) != -1) { + downloadFile.write(bytes, 0, index); + downloadFile.flush(); + } + downloadFile.close(); + input.close(); + } + + /** + * 网络文件转File + * @param url + */ + public static File getFile(String url) throws Exception { + //对本地文件命名 + String fileName = url.substring(url.lastIndexOf("."),url.length()); + File file = null; + + URL urlfile; + InputStream inStream = null; + OutputStream os = null; + try { + file = File.createTempFile("net_url", fileName); + //下载 + urlfile = new URL(url); + inStream = urlfile.openStream(); + os = new FileOutputStream(file); + + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (null != os) { + os.close(); + } + if (null != inStream) { + inStream.close(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + return file; + } + + /** + * base64转MultiFile + */ + public static class Base64ToMultipartFile implements MultipartFile { + + private final byte[] imgContent; + private final String header; + + + public Base64ToMultipartFile(byte[] imgContent, String header) { + this.imgContent = imgContent; + this.header = header.split(";")[0]; + } + + @Override + public String getName() { + return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1]; + } + + @Override + public String getOriginalFilename() { + return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1]; + } + + @Override + public String getContentType() { + return header.split(":")[1]; + } + + @Override + public boolean isEmpty() { + return imgContent == null || imgContent.length == 0; + } + + @Override + public long getSize() { + return imgContent.length; + } + + @Override + public byte[] getBytes() throws IOException { + return imgContent; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(imgContent); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + new FileOutputStream(dest).write(imgContent); + } + + /** + * base转为MultipartFile base64需要带着头 + */ + public static MultipartFile base64ToMultipart(String base64) { + String[] baseStrs = base64.split(","); + + Base64.Decoder decoder = Base64.getDecoder(); + byte[] b = new byte[0]; + b = decoder.decode(baseStrs[1]); + + for (int i = 0; i < b.length; ++i) { + if (b[i] < 0) { + b[i] += 256; + } + } + return new Base64ToMultipartFile(b, baseStrs[0]); + } + + } + + /** + * file转MultipartFile的时候会用到MockMultipartFile + * 当你导入spring-test依赖的时候 会跟某些依赖冲突(暂未找到具体是哪个冲突) + * 解决方法 重写一个类去实现MultipartFile接口 + * 直接用MockMultipartFile的源码 + */ + public static class MockMultipartFile implements MultipartFile { + private final String name; + + private String originalFilename; + + private String contentType; + + private final byte[] content; + + /** + * Create a new MultipartFileDto with the given content. + * @param name the name of the file + * @param content the content of the file + */ + public MockMultipartFile(String name, byte[] content) { + this(name, "", null, content); + } + + /** + * Create a new MultipartFileDto with the given content. + * @param name the name of the file + * @param contentStream the content of the file as stream + * @throws IOException if reading from the stream failed + */ + public MockMultipartFile(String name, InputStream contentStream) throws IOException { + this(name, "", null, FileCopyUtils.copyToByteArray(contentStream)); + } + + /** + * Create a new MultipartFileDto with the given content. + * @param name the name of the file + * @param originalFilename the original filename (as on the client's machine) + * @param contentType the content type (if known) + * @param content the content of the file + */ + public MockMultipartFile(String name, String originalFilename, String contentType, byte[] content) { + this.name = name; + this.originalFilename = (originalFilename != null ? originalFilename : ""); + this.contentType = contentType; + this.content = (content != null ? content : new byte[0]); + } + + /** + * Create a new MultipartFileDto with the given content. + * @param name the name of the file + * @param originalFilename the original filename (as on the client's machine) + * @param contentType the content type (if known) + * @param contentStream the content of the file as stream + * @throws IOException if reading from the stream failed + */ + public MockMultipartFile(String name, String originalFilename, String contentType, InputStream contentStream) + throws IOException { + + this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream)); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getOriginalFilename() { + return this.originalFilename; + } + + @Override + public String getContentType() { + return this.contentType; + } + + @Override + public boolean isEmpty() { + return (this.content.length == 0); + } + + @Override + public long getSize() { + return this.content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return this.content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.content); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + FileCopyUtils.copy(this.content, dest); + } + } +} diff --git a/src/main/java/com/darkness/common/util/HandlePage.java b/src/main/java/com/darkness/common/util/HandlePage.java new file mode 100644 index 0000000..7cfdd88 --- /dev/null +++ b/src/main/java/com/darkness/common/util/HandlePage.java @@ -0,0 +1,17 @@ +package com.darkness.common.util; + +import java.util.List; + +public class HandlePage { + + /**分页 start = (page - 1) * size, end = page * size*/ + private List handlePage(List source, int start, int end){ + int total = source.size(); +// end = end > total ? total : end; + end = Math.min(end, total); + if (end <= start) { + return null; + } + return source.subList(start,end); + } +} diff --git a/src/main/java/com/darkness/common/util/MethodGetAndSet.java b/src/main/java/com/darkness/common/util/MethodGetAndSet.java new file mode 100644 index 0000000..1262225 --- /dev/null +++ b/src/main/java/com/darkness/common/util/MethodGetAndSet.java @@ -0,0 +1,90 @@ +package com.darkness.common.util; + +import java.lang.reflect.Method; +import java.math.BigDecimal; + +public class MethodGetAndSet { + + /**根据属性,获取get方法*/ + public static Object getGetMethod(Object ob , String name)throws Exception{ + Method[] m = ob.getClass().getMethods(); + for(int i = 0;i < m.length;i++){ + if(("get"+name).toLowerCase().equals(m[i].getName().toLowerCase())){ + return m[i].invoke(ob); + } + } + return null; + } + + /**根据属性,拿到set方法,并把值set到对象中*/ + public static void setValue(Object obj, Class clazz, String filedName, Class typeClass, Object value){ + filedName = removeLine(filedName); + String methodName = "set" + filedName.substring(0,1).toUpperCase()+filedName.substring(1); + try{ + Method method = clazz.getDeclaredMethod(methodName, new Class[]{typeClass}); + method.invoke(obj, new Object[]{getClassTypeValue(typeClass, value)}); + }catch(Exception ex){ + ex.printStackTrace(); + } + } + + /**通过class类型获取获取对应类型的值*/ + public static Object getClassTypeValue(Class typeClass, Object value){ + if(typeClass == int.class || value instanceof Integer){ + if(null == value){ + return 0; + } + return value; + }else if(typeClass == short.class){ + if(null == value){ + return 0; + } + return value; + }else if(typeClass == byte.class){ + if(null == value){ + return 0; + } + return value; + }else if(typeClass == double.class){ + if(null == value){ + return 0; + } + return value; + }else if(typeClass == long.class){ + if(null == value){ + return 0; + } + return value; + }else if(typeClass == String.class){ + if(null == value){ + return ""; + } + return value; + }else if(typeClass == boolean.class){ + if(null == value){ + return true; + } + return value; + }else if(typeClass == BigDecimal.class){ + if(null == value){ + return new BigDecimal(0); + } + return new BigDecimal(value+""); + }else { + return typeClass.cast(value); + } + } + + /**处理字符串 如: abc_dex ---> abcDex*/ + public static String removeLine(String str){ + if(null != str && str.contains("_")){ + int i = str.indexOf("_"); + char ch = str.charAt(i+1); + char newCh = (ch+"").substring(0, 1).toUpperCase().toCharArray()[0]; + String newStr = str.replace(str.charAt(i+1), newCh); + String newStr2 = newStr.replace("_", ""); + return newStr2; + } + return str; + } +} diff --git a/src/main/java/com/darkness/common/util/SM2Util.java b/src/main/java/com/darkness/common/util/SM2Util.java new file mode 100644 index 0000000..e06f4e5 --- /dev/null +++ b/src/main/java/com/darkness/common/util/SM2Util.java @@ -0,0 +1,293 @@ +package com.darkness.common.util; + +import org.bouncycastle.asn1.gm.GMNamedCurves; +import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.engines.SM2Engine; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPrivateKeySpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.util.encoders.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.ECGenParameterSpec; +import java.util.HashMap; +import java.util.Map; + + +public class SM2Util { + private static final Logger logger = LoggerFactory.getLogger(SM2Util.class.getSimpleName()); + //ECC 曲线 SM2命名曲线 + private final static String NAME_CURVE = "sm2p256v1"; + private final static ECGenParameterSpec SM2_SPEC = new ECGenParameterSpec(NAME_CURVE); + + //椭圆曲线ECParameters ASN.1 结构 + private static final X9ECParameters x9ECParameters = GMNamedCurves.getByName(NAME_CURVE); + //椭圆曲线公钥或私钥的基本域参数。 + private static final ECParameterSpec ecDomainParameters = new ECParameterSpec(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + /** + * 生成密钥 + */ + public static Map generateKey() { + Map resultMap = new HashMap<>(); + KeyPair keyPair = initECKeyPair(); + if (null != keyPair) { + //生成公钥 + PublicKey publicKey = keyPair.getPublic(); + if (publicKey instanceof BCECPublicKey) { + byte[] publicKeyByte = ((BCECPublicKey) publicKey).getQ().getEncoded(false); + logger.info("publicKey is : " + Hex.toHexString(publicKeyByte)); + logger.info("publicKey byte size : " + publicKeyByte.length); + if (publicKeyByte.length > 0) { + resultMap.put("PublicKey", Hex.toHexString(publicKeyByte)); + } + } + //生成私钥 + PrivateKey privateKey = keyPair.getPrivate(); + if (privateKey instanceof BCECPrivateKey) { + byte[] privateKeyByte = ((BCECPrivateKey) privateKey).getD().toByteArray(); + logger.info("privateKey is : " + Hex.toHexString(privateKeyByte)); + logger.info("privateKey byte size : " + privateKeyByte.length); + if (privateKeyByte.length > 0) + resultMap.put("PrivateKey", Hex.toHexString(privateKeyByte)); + } + } + return resultMap; + } + + /** + * 初始化密钥 + */ + private static KeyPair initECKeyPair() { + KeyPairGenerator kpg; + try { + kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider()); + kpg.initialize(SM2_SPEC, new SecureRandom()); + return kpg.generateKeyPair(); + } catch (Exception e) { + logger.error("生成密钥错误:" + e.getMessage()); + return null; + } + } + + /** + * 内容加密 + */ + public static byte[] encrypt(byte[] publicKeyByte, byte[] data) { + //通过公钥对象获取公钥的基本与参数 + BCECPublicKey publicKey = getECPublicKeyByPublicKeyHex(Hex.toHexString(publicKeyByte)); + ECParameterSpec ecParameterSpec = publicKey.getParameters(); + ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN()); + ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(publicKey.getQ(), ecDomainParameters); + + SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom())); + byte[] arrayOfBytes = null; + try { + arrayOfBytes = sm2Engine.processBlock(data, 0, data.length); + } catch (Exception e) { + logger.error("加密错误:" + e.getMessage()); + } + return arrayOfBytes; + } + + /** + * 内容公钥加密 返回字符串 + */ + public static String encrypt(String publicKeyHex, String data) { + byte[] publicKeyByte = Hex.decode(publicKeyHex); + byte[] dataByte = data.getBytes(StandardCharsets.UTF_8); + byte[] encryptByte = encrypt(publicKeyByte, dataByte); + return Hex.toHexString(encryptByte); + } + + /** + * 私钥解密 + */ + public static byte[] decrypt(byte[] privateKeyByte, byte[] data) { + //通过私钥对象获取私钥的基本域参数。 + BCECPrivateKey privateKey = getBCECPrivateKeyByPrivateKeyHex(Hex.toHexString(privateKeyByte)); + ECParameterSpec ecParameterSpec = privateKey.getParameters(); + ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(), + ecParameterSpec.getG(), ecParameterSpec.getN()); + + //通过私钥值和私钥钥基本参数创建私钥参数对象 + ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(privateKey.getD(), + ecDomainParameters); + + //通过解密模式创建解密引擎并初始化 + SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + sm2Engine.init(false, ecPrivateKeyParameters); + + try { + //通过解密引擎对密文字节串进行解密 + //将解密后的字节串转换为utf8字符编码的字符串(需要与明文加密时字符串转换成字节串所指定的字符编码保持一致) + return sm2Engine.processBlock(data, 0, data.length); + } catch (Exception e) { + logger.error("解密错误:" + e.getMessage()); + return null; + } + + } + + /** + * 私钥解密 返回字符串 + */ + public static String decrypt(String privateKeyHex, String data) { + byte[] privateKeyByte = Hex.decode(privateKeyHex); + byte[] dataByte = Hex.decode(data); + byte[] decryptByte = decrypt(privateKeyByte, dataByte); + return new String(decryptByte, StandardCharsets.UTF_8); + } + + /** + * 签名 + */ + public static byte[] sign(String privateKeyHex, byte[] message) { + try { + Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), new BouncyCastleProvider()); + signature.initSign(getBCECPrivateKeyByPrivateKeyHex(privateKeyHex)); + signature.update(message); + return signature.sign(); + } catch (Exception e) { + logger.error("签名错误:" + e.getMessage()); + return null; + } + + } + + /** + * 私钥生成签名 返回字符串 + */ + public static String sign(String privateKeyHex, String message) { + byte[] messageByte = message.getBytes(StandardCharsets.UTF_8); + byte[] signByte = sign(privateKeyHex, messageByte); + return Hex.toHexString(signByte); + } + + /** + * 验签 + */ + public static boolean verifySign(String publicKeyHex, byte[] signedMsg, byte[] originMsg) { + try { + Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), new BouncyCastleProvider()); + signature.initVerify(getECPublicKeyByPublicKeyHex(publicKeyHex)); + signature.update(originMsg); + return signature.verify(signedMsg); + } catch (Exception e) { + logger.error("验签错误:" + e.getMessage()); + return false; + } + + } + + /** + * 公钥验签 返回布尔值 + */ + public static boolean verifySign(String publicKeyHex, String signedMsg, String originMsg) { + byte[] signedMsgByte = Hex.decode(signedMsg); + byte[] originMsgByte = originMsg.getBytes(StandardCharsets.UTF_8); + return verifySign(publicKeyHex, signedMsgByte, originMsgByte); + } + + /** + * 根据16进制内容生成公钥 + */ + public static BCECPublicKey getECPublicKeyByPublicKeyHex(String pubKeyHex) { + //截取64字节有效的SM2公钥(如果公钥首个字节为0x04) + if (pubKeyHex.length() > 128) { + pubKeyHex = pubKeyHex.substring(pubKeyHex.length() - 128); + } + //将公钥拆分为x,y分量(各32字节) + String stringX = pubKeyHex.substring(0, 64); + String stringY = pubKeyHex.substring(stringX.length()); + //将公钥x、y分量转换为BigInteger类型 + BigInteger x = new BigInteger(stringX, 16); + BigInteger y = new BigInteger(stringY, 16); + //通过公钥x、y分量创建椭圆曲线公钥规范 + ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(x9ECParameters.getCurve().createPoint(x, y), ecDomainParameters); + //通过椭圆曲线公钥规范,创建出椭圆曲线公钥对象(可用于SM2加密及验签) + return new BCECPublicKey("EC", ecPublicKeySpec, BouncyCastleProvider.CONFIGURATION); + } + + + /** + * 私钥字符串转换为 BCECPrivateKey 私钥对象 + * + * @param privateKeyHex: 32字节十六进制私钥字符串 + * @return BCECPrivateKey:SM2私钥对象 + */ + public static BCECPrivateKey getBCECPrivateKeyByPrivateKeyHex(String privateKeyHex) { + //将十六进制私钥字符串转换为BigInteger对象 + BigInteger d = new BigInteger(privateKeyHex, 16); + //通过私钥和私钥域参数集创建椭圆曲线私钥规范 + ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d, ecDomainParameters); + //通过椭圆曲线私钥规范,创建出椭圆曲线私钥对象(可用于SM2解密和签名) + return new BCECPrivateKey("EC", ecPrivateKeySpec, BouncyCastleProvider.CONFIGURATION); + } + + + public static void main(String[] args) { + // 生成密钥对 + Map map = generateKey(); + + /* + * 密钥对 + * 通常加解密 和 签名验签 所用的公私钥不是一套 + * 公钥加密 私钥解密 私钥签名 公钥验签 + */ + String signPublicKey = map.get("PublicKey"); + String signPrivateKey = map.get("PrivateKey"); + + //加密内容 + String info = "Test123Test123Test1234567"; + +// //加密 +// byte[] encodeInfoBytes = encrypt(Hex.decode(signPublicKey),info.getBytes(StandardCharsets.UTF_8)); +// String encodeInfo = Hex.toHexString(encodeInfoBytes); +// logger.info("加密内容"+encodeInfo); +// +// // 解密 +// byte[] decodeInfoBytes = decrypt(Hex.decode(signPrivateKey),Hex.decode(encodeInfo)); +// String decodeInfo = null; +// if (decodeInfoBytes != null) { +// decodeInfo = new String(decodeInfoBytes); +// } +// logger.info("解密内容"+decodeInfo); +// +// String signedInfo = Hex.toHexString(Objects.requireNonNull(sign(signPrivateKey, encodeInfo.getBytes(StandardCharsets.UTF_8)))); +// logger.info("签名:" + signedInfo); +// +// boolean isSigned = verifySign(signPublicKey,Hex.decode(signedInfo),encodeInfo.getBytes(StandardCharsets.UTF_8)); +// logger.info("验签:" + isSigned); + + //加密 + String encodeInfo = encrypt(signPublicKey,info); + logger.info("加密内容"+encodeInfo); + + //解密 + String decodeInfo = decrypt(signPrivateKey,encodeInfo); + logger.info("解密内容"+decodeInfo); + + //签名 + String signedInfo = sign(signPrivateKey,encodeInfo); + logger.info("签名:" + signedInfo); + + //验签 + boolean isSigned = verifySign(signPublicKey,signedInfo,encodeInfo); + logger.info("验签:" + isSigned); + + } +} diff --git a/src/main/java/com/darkness/common/util/page/PageHelper.java b/src/main/java/com/darkness/common/util/page/PageHelper.java new file mode 100644 index 0000000..0103201 --- /dev/null +++ b/src/main/java/com/darkness/common/util/page/PageHelper.java @@ -0,0 +1,89 @@ +package com.darkness.common.util.page; + +import lombok.Data; +import org.springframework.util.CollectionUtils; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +/** + * @author fuhouyin + * @time 2023/2/17 17:37 + */ +@Data +public class PageHelper implements Serializable { + private static final long serialVersionUID = -4653064203154489390L; + + public static final Integer MAX_PAGE_SIZE = 1000000; + + private Integer pageNum; + private Integer pageSize; + private Integer totalRowCount; + private Integer nextPageNum; + + public PageHelper() { + } + + public PageHelper(Integer pageNum, Integer pageSize) { + if (pageNum == null || pageNum <= 0) { + this.pageNum = 1; + } else { + this.pageNum = pageNum; + } + + if (pageSize == null || pageSize < 0) { + this.pageSize = MAX_PAGE_SIZE; + } else { + this.pageSize = pageSize; + } + } + + public PageHelper(PageReqCmd reqCmd, Integer totalRowCount){ + if (reqCmd.getPageNum() == null || reqCmd.getPageNum() <= 0) { + this.pageNum = 1; + } else { + this.pageNum = reqCmd.getPageNum(); + } + + if (reqCmd.getPageSize() == null || reqCmd.getPageSize() < 0) { + this.pageSize = MAX_PAGE_SIZE; + } else { + this.pageSize = reqCmd.getPageSize(); + } + + setTotalRowCount(totalRowCount); + } + + /** + * 以页码从1开始计算的偏移量 + * @return + */ + public Integer offset() { + if (null == pageNum || null == totalRowCount) { + return 0; + } + int offset = (pageNum - 1) * pageSize; + return offset; + } + + /** + * Java分页 + * @param sourceList + * @return + */ + public List pageList(List sourceList){ + if (CollectionUtils.isEmpty(sourceList)) { + return sourceList; + } + Integer offset = offset(); + if (offset > (totalRowCount - 1)) { + return Collections.EMPTY_LIST; + } + int end = offset + pageSize; + end = Math.min(end,totalRowCount); + return sourceList.subList(offset,end); + } + +} + diff --git a/src/main/java/com/darkness/common/util/page/PageReq.java b/src/main/java/com/darkness/common/util/page/PageReq.java new file mode 100644 index 0000000..694019a --- /dev/null +++ b/src/main/java/com/darkness/common/util/page/PageReq.java @@ -0,0 +1,16 @@ +package com.darkness.common.util.page; + +/** + * @author fuhouyin + * @time 2023/2/17 17:38 + */ +public interface PageReq { + + Integer getPageNum(); + + void setPageNum(Integer pageNum); + + Integer getPageSize(); + + void setPageSize(Integer pageSize); +} \ No newline at end of file diff --git a/src/main/java/com/darkness/common/util/page/PageReqCmd.java b/src/main/java/com/darkness/common/util/page/PageReqCmd.java new file mode 100644 index 0000000..d588874 --- /dev/null +++ b/src/main/java/com/darkness/common/util/page/PageReqCmd.java @@ -0,0 +1,14 @@ +package com.darkness.common.util.page; + +import lombok.Data; + +/** + * @author fuhouyin + * @time 2023/2/17 17:38 + */ +@Data +public class PageReqCmd implements PageReq { + private T filter; + private Integer pageNum = 1; + private Integer pageSize = 20; +} diff --git a/src/main/java/com/darkness/common/util/page/PageResp.java b/src/main/java/com/darkness/common/util/page/PageResp.java new file mode 100644 index 0000000..eb3fd0a --- /dev/null +++ b/src/main/java/com/darkness/common/util/page/PageResp.java @@ -0,0 +1,15 @@ +package com.darkness.common.util.page; + +import lombok.Data; + +import java.util.List; + +/** + * @author fuhouyin + * @time 2023/2/17 17:26 + */ +@Data +public class PageResp { + private List list; + private Integer totalCount; +} \ No newline at end of file diff --git a/src/main/java/com/darkness/common/util/redis/RedisCacheUtils.java b/src/main/java/com/darkness/common/util/redis/RedisCacheUtils.java new file mode 100644 index 0000000..3dbad4d --- /dev/null +++ b/src/main/java/com/darkness/common/util/redis/RedisCacheUtils.java @@ -0,0 +1,177 @@ +package com.darkness.common.util.redis; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * @author fuhouyin + * @time 2023/4/11 9:30 + */ +@Slf4j +@Component +public class RedisCacheUtils { + + @Autowired + private RedisTemplateProvider redisTemplateProvider; + @Autowired + private RedisTemplate redisTemplate; + private final StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + public static final String SETNX_SCRIPT = "return redis.call('setnx',KEYS[1], ARGV[1])"; + + public void setValue(String key, Object value){ + RedisTemplate redisTemplate = getRedisTemplate(); + redisTemplate.opsForValue().set(key,value); + } + + public void setValue(String key, Object value,Long timeout, TimeUnit timeUnit){ + RedisTemplate redisTemplate = getRedisTemplate(); + redisTemplate.opsForValue().set(key,value,timeout, timeUnit); + } + + public Object getValue(String key){ + RedisTemplate redisTemplate = getRedisTemplate(); + return redisTemplate.opsForValue().get(key); + } + + public String getCacheKey(Object... keys) { + return StringUtils.join(Arrays.asList(keys), ":"); + } + + public Long hashIncrement(String key, String hashKey){ + RedisTemplate redisTemplate = getRedisTemplate(); + Long increment = redisTemplate.opsForHash().increment(key, hashKey, 1); + return increment; + } + + public boolean hasKey(String key){ + return getRedisTemplate().hasKey(key); + } + + public boolean delKey(String key){ + if (StringUtils.isEmpty(key)) { + return Boolean.FALSE; + } + RedisTemplate redisTemplate = getRedisTemplate(); + if (redisTemplate.hasKey(key)) { + return redisTemplate.delete(key); + } + return Boolean.TRUE; + } + + public boolean hashHasKey(String key, String hashKey){ + return getRedisTemplate().opsForHash().hasKey(key, hashKey); + } + + public Object hashGet(String key, String hashKey){ + return getRedisTemplate().opsForHash().get(key, hashKey); + } + + private RedisTemplate getRedisTemplate(){ + RedisTemplate template = redisTemplateProvider.getTemplate(stringRedisSerializer); + return template; + } + + public void hashPut(String key,String hashKey, String value){ + getRedisTemplate().opsForHash().put(key,hashKey,value); + } + + public void hashPutIfAbsent(String key, String hashKey, String value) { + getRedisTemplate().opsForHash().putIfAbsent(key,hashKey,value); + } + + public Boolean expire(String key, long time, TimeUnit timeUnit){ + Boolean result = getRedisTemplate().expire(key, time, timeUnit); + return result; + } + + /** + * 指定缓存失效时间 + */ + public void expire(String key, long time) { + redisTemplate.expire(key, time, TimeUnit.MILLISECONDS); + } + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(毫秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.MILLISECONDS); + } + + public Boolean lock(String key){ + return getRedisTemplate().opsForValue().setIfAbsent(key, BigDecimal.ZERO.intValue()); + } + + /** + * redis实现分布式锁 + * @param key time是:毫秒毫秒毫秒毫秒毫秒 + * @return + */ + public boolean lock(String key,Long time) { + //自定义脚本 + DefaultRedisScript script = new DefaultRedisScript<>(SETNX_SCRIPT, List.class); + //执行脚本,传入参数,由于value没啥用,这里随便写死的"1" + List rst = (List) redisTemplate.execute(script, Collections.singletonList(key), "1"); + //返回1,表示设置成功,拿到锁 + if(rst.get(0) == 1){ + log.info(key+"成功拿到锁"); + //设置过期时间 + expire(key,time); + log.info(key+"已成功设置过期时间:"+time +" 秒"); + return true; + }else{ + long expire = getExpire(key); + log.info(key+"未拿到到锁,还有"+expire+"释放"); + return false; + } + } + + public Boolean tryLock(String key){ + try { + for (int i = 0; i < 3; i++) { + if (lock(key)) { + return Boolean.TRUE; + } + Thread.sleep(100L); + } + } catch (InterruptedException e) { + return Boolean.FALSE; + } + return Boolean.FALSE; + } + + public void unlock(String key){ + getRedisTemplate().delete(key); + } + + + public Long increment(String key, Long delta){ + return getRedisTemplate().opsForValue().increment(key,delta); + } + + public Boolean setIfAbsent(String key, Object value){ + return getRedisTemplate().opsForValue().setIfAbsent(key,value); + } + + public Set keys(String keyPattern) { + return getRedisTemplate().keys(keyPattern); + } + + public Object getAndSet(String key, Object value){ + return getRedisTemplate().opsForValue().getAndSet(key,value); + } +} diff --git a/src/main/java/com/darkness/common/util/redis/RedisTemplateProvider.java b/src/main/java/com/darkness/common/util/redis/RedisTemplateProvider.java new file mode 100644 index 0000000..9379af7 --- /dev/null +++ b/src/main/java/com/darkness/common/util/redis/RedisTemplateProvider.java @@ -0,0 +1,14 @@ +package com.darkness.common.util.redis; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +/** + * @author fuhouyin + * @time 2023/4/11 9:30 + */ +public interface RedisTemplateProvider { + RedisTemplate getTemplate(); + + RedisTemplate getTemplate(RedisSerializer valueSerializer); +} diff --git a/src/main/java/com/darkness/common/util/redis/RedisTemplateProviderImpl.java b/src/main/java/com/darkness/common/util/redis/RedisTemplateProviderImpl.java new file mode 100644 index 0000000..b1646e9 --- /dev/null +++ b/src/main/java/com/darkness/common/util/redis/RedisTemplateProviderImpl.java @@ -0,0 +1,95 @@ +package com.darkness.common.util.redis; + +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * @author fuhouyin + * @time 2023/4/11 9:30 + */ +@Component +public class RedisTemplateProviderImpl implements RedisTemplateProvider { + public static final RedisSerializer JDK_SERIALIZER = new JdkSerializationRedisSerializer(); + public static final RedisSerializer STRING_SERIALIZER = new StringRedisSerializer(); + private final Map> redisTemplateMap = new HashMap(); + private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private final Lock r; + private final Lock w; + private final RedisConnectionFactory redisStoreConnectionFactory; + + public RedisTemplateProviderImpl(RedisConnectionFactory redisStoreConnectionFactory) { + this.r = this.rwl.readLock(); + this.w = this.rwl.writeLock(); + this.redisStoreConnectionFactory = redisStoreConnectionFactory; + } + + public RedisTemplate getTemplate() { + return this.getTemplate(STRING_SERIALIZER); + } + + public RedisTemplate getTemplate(RedisSerializer valueSerializer) { + return this.getTemplate(STRING_SERIALIZER, valueSerializer); + } + + private RedisTemplate getTemplate(RedisSerializer keySerializer, RedisSerializer valueSerializer) { + String cacheKey = this.getTemplateCacheKey(keySerializer, valueSerializer); + + try { + this.r.lock(); + RedisTemplate template = (RedisTemplate)this.redisTemplateMap.get(cacheKey); + if (template != null) { + RedisTemplate var5 = template; + return var5; + } + } finally { + this.r.unlock(); + } + + return this.createAndPut(keySerializer, valueSerializer, cacheKey); + } + + private RedisTemplate createAndPut(RedisSerializer keySerializer, RedisSerializer valueSerializer, String cacheKey) { + RedisTemplate var5; + try { + this.w.lock(); + RedisTemplate template = (RedisTemplate)this.redisTemplateMap.get(cacheKey); + if (template == null) { + template = this.createRedisTemplate(keySerializer, valueSerializer); + this.redisTemplateMap.put(cacheKey, template); + } + + var5 = template; + } finally { + this.w.unlock(); + } + + return var5; + } + + private RedisTemplate createRedisTemplate(RedisSerializer keySerializer, RedisSerializer valueSerializer) { + RedisTemplate template = new RedisTemplate(); + template.setKeySerializer(keySerializer); + template.setHashKeySerializer(keySerializer); + template.setHashValueSerializer(valueSerializer); + template.setValueSerializer(valueSerializer); + template.setConnectionFactory(this.redisStoreConnectionFactory); + template.afterPropertiesSet(); + return template; + } + + private String getTemplateCacheKey(RedisSerializer keySerializer, RedisSerializer valueSerializer) { + Assert.notNull(keySerializer, "keySerializer should not null"); + Assert.notNull(valueSerializer, "valueSerializer should not null"); + return keySerializer.getClass().getName() + "-" + valueSerializer.getClass().getName(); + } +} diff --git a/src/main/java/com/darkness/common/util/response/ResultEnums.java b/src/main/java/com/darkness/common/util/response/ResultEnums.java new file mode 100644 index 0000000..27529c7 --- /dev/null +++ b/src/main/java/com/darkness/common/util/response/ResultEnums.java @@ -0,0 +1,59 @@ +package com.darkness.common.util.response; + +/** + * @author fuhouyin + * @time 2023/2/17 18:03 + */ +public enum ResultEnums { + TRUE_200(200, "成功"), + FALSE_300(300, "失败"), + FALSE_400(400, "内部错误"), + FALSE_423(423, "数据不存在"), + FALSE_424(424, "数据已存在"), + FALSE_500(500, "错误"), + FALSE_600(600, "session超时或未登录"); + + private int code; + private String message; + + ResultEnums(){} + + ResultEnums(int code, String message) { + this.code = code; + this.message = message; + } + + public static String valueOfCode(String code) { + for (ResultEnums obj : ResultEnums.values()) { + if (java.util.Objects.equals(obj.code, code)) { + return obj.message; + } + } + return null; + } + + public static Number valueOfMessage(String message) { + for (ResultEnums obj : ResultEnums.values()) { + if (java.util.Objects.equals(obj.message, message)) { + return obj.code; + } + } + return null; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/src/main/java/com/darkness/common/util/response/VoResult.java b/src/main/java/com/darkness/common/util/response/VoResult.java new file mode 100644 index 0000000..23d1bd1 --- /dev/null +++ b/src/main/java/com/darkness/common/util/response/VoResult.java @@ -0,0 +1,148 @@ +package com.darkness.common.util.response; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author fuhouyin + * @time 2023/2/17 18:02 + */ +public class VoResult { + + private Integer resultCode; + + private String resultMsg; + + private Map resultData = new HashMap(); + + public Map getResultData() { + return resultData; + } + + public void setResultData(Map resultData) { + this.resultData = resultData; + } + + + /** + * sessionn超时或未登录 + */ + public static VoResult sessionNotExists(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_600.getCode()); + result.setResultMsg(ResultEnums.FALSE_600.getMessage()); + return result; + } + + /** + * 数据已存在 + */ + public static VoResult dataExists(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_424.getCode()); + result.setResultMsg(ResultEnums.FALSE_424.getMessage()); + return result; + } + + /** + * 数据不存在 + */ + public static VoResult dataNotExists(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_423.getCode()); + result.setResultMsg(ResultEnums.FALSE_423.getMessage()); + return result; + } + + /** + * 数据不存在 + */ + public static VoResult dataNotExists(String resultMsg){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_423.getCode()); + result.setResultMsg(resultMsg); + return result; + } + + /** + * 成功 + */ + public static VoResult success(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.TRUE_200.getCode()); + result.setResultMsg(ResultEnums.TRUE_200.getMessage()); + return result; + } + + /** + * 失败 + */ + public static VoResult fail(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_300.getCode()); + result.setResultMsg(ResultEnums.FALSE_300.getMessage()); + return result; + } + + /** + * 内部错误(参数错误) + */ + public static VoResult errorParam(){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_400.getCode()); + result.setResultMsg(ResultEnums.FALSE_400.getMessage()); + return result; + } + + /** + * 如需自定义错误信息,请使用该方法 + */ + public static VoResult errorParam(String msg){ + VoResult result = new VoResult(); + result.setResultCode(ResultEnums.FALSE_400.getCode()); + result.setResultMsg(msg); + return result; + } + + public VoResult add(String key, Object value){ + this.getResultData().put(key, value); + return this; + } + + public VoResult addData(Object value){ + this.getResultData().put("data", value); + return this; + } + + public VoResult add(Map map){ + this.setResultData(map); + return this; + } + + public VoResult(){ + + } + + public VoResult(Integer resultCode, String resultMsg, Map resultData) { + this.resultCode = resultCode; + this.resultMsg = resultMsg; + this.resultData = resultData; + } + + public Integer getResultCode() { + return resultCode; + } + + public void setResultCode(Integer resultCode) { + this.resultCode = resultCode; + } + + public String getResultMsg() { + return resultMsg; + } + + public void setResultMsg(String resultMsg) { + this.resultMsg = resultMsg; + } + +}