map = new HashMap<>();
+ if (list != null) {
+ try {
+ Method methodGetKey = c.getMethod(fieldName);
+ for (int i = 0; i < list.size(); i++) {
+ V value = list.get(i);
+ @SuppressWarnings("unchecked")
+ K key = (K) methodGetKey.invoke(list.get(i));
+ map.put(key, value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return map;
+ }
+
+}
diff --git a/src/main/java/com/mixi/common/utils/DateUtil.java b/src/main/java/com/mixi/common/utils/DateUtil.java
new file mode 100644
index 0000000..7144c7f
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/DateUtil.java
@@ -0,0 +1,65 @@
+package com.mixi.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.TimeZone;
+
+@Slf4j
+public class DateUtil {
+ public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+ public static final String YYYYMM = "yyyyMM";
+ public static final String YYYY_MM_DD = "yyyyMMdd";
+ /**
+ * LocalDate -> Date
+ */
+ public static Date asDate(LocalDate localDate) {
+ return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
+ }
+
+ /**
+ * LocalDateTime -> Date
+ */
+ public static Date asDate(LocalDateTime localDateTime) {
+ return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
+ }
+ /**
+ * date 装 String
+ * @param date
+ * @param formatter
+ * @return
+ */
+ public static String dateToStr(Date date, String formatter) {
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatter);
+ Instant instant = date.toInstant();
+ ZoneId zoneId = ZoneId.systemDefault();
+ LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
+ return dateTimeFormatter.format(localDateTime);
+ }
+ /**
+ * 根据时区获取时间
+ * @param timeZone "Asia/Tokyo"
+ * @return
+ */
+ public static Date getByTimeZone(String timeZone) {
+ String dateStr = dateToStr(new Date(),YYYY_MM_DD_HH_MM_SS);
+ SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
+ // 设置时区
+ sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
+ Date date = null;
+ try{
+ date = sdf.parse(dateStr);
+ }catch (ParseException parseException){
+ log.error("时间转换异常!",parseException);
+ }
+ return date;
+ }
+
+}
diff --git a/src/main/java/com/mixi/common/utils/FileUtil.java b/src/main/java/com/mixi/common/utils/FileUtil.java
new file mode 100644
index 0000000..7c32c19
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/FileUtil.java
@@ -0,0 +1,266 @@
+package com.mixi.common.utils;
+
+import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import com.mixi.common.config.exception.BusinessException;
+import com.mixi.model.vo.FileVO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+public class FileUtil extends cn.hutool.core.io.FileUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
+
+ /**
+ * 系统临时目录
+ *
+ * windows 包含路径分割符,但Linux 不包含,
+ * 在windows \\==\ 前提下,
+ * 为安全起见 同意拼装 路径分割符,
+ *
+ * java.io.tmpdir
+ * windows : C:\Users/xxx\AppData\Local\Temp\
+ * linux: /temp
+ *
+ */
+ public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
+ /**
+ * 定义GB的计算常量
+ */
+ private static final int GB = 1024 * 1024 * 1024;
+ /**
+ * 定义MB的计算常量
+ */
+ private static final int MB = 1024 * 1024;
+ /**
+ * 定义KB的计算常量
+ */
+ private static final int KB = 1024;
+
+ /**
+ * 格式化小数
+ */
+ private static final DecimalFormat DF = new DecimalFormat("0.00");
+
+ public static final String IMAGE = "图片";
+ public static final String TXT = "文档";
+ public static final String MUSIC = "音乐";
+ public static final String VIDEO = "视频";
+ public static final String OTHER = "其他";
+
+
+ /**
+ * MultipartFile转File
+ */
+ public static File toFile(MultipartFile multipartFile) {
+ // 获取文件名
+ String fileName = multipartFile.getOriginalFilename();
+ // 获取文件后缀
+ String prefix = "." + getExtensionName(fileName);
+ File file = null;
+ try {
+ // 用uuid作为文件名,防止生成的临时文件重复
+ file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
+ // MultipartFile to File
+ multipartFile.transferTo(file);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ return file;
+ }
+
+// public static void main(String[] args) {
+// File file = new File(
+// "http://18.162.111.141:5568/download/202211/userFile/collection/Printboard/1/a3c9838c-2171-44d7-af54-c94ee6affcd9print_2.jpg.png");
+// FileUtil.getFileSize()
+// }
+
+ /**
+ * 获取文件扩展名,不带 .
+ */
+ public static String getExtensionName(String filename) {
+ if ((filename != null) && (filename.length() > 0)) {
+ int dot = filename.lastIndexOf('.');
+ if ((dot > -1) && (dot < (filename.length() - 1))) {
+ return filename.substring(dot + 1);
+ }
+ }
+ return filename;
+ }
+
+
+ /**
+ * inputStream 转 File
+ */
+ static File inputStreamToFile(InputStream ins, String name) {
+ File file = new File(SYS_TEM_DIR + name);
+ if (file.exists()) {
+ return file;
+ }
+ OutputStream os = null;
+ try {
+ os = new FileOutputStream(file);
+ int bytesRead;
+ int len = 8192;
+ byte[] buffer = new byte[len];
+ while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ CloseUtil.close(os);
+ CloseUtil.close(ins);
+ }
+ return file;
+ }
+
+ /**
+ * 获取文件尺寸
+ */
+ public static FileVO getFileSize(MultipartFile file) {
+ int width = 0;
+ int height = 0;
+ try{
+ // 图片对象
+ BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
+ // 宽度
+ width = bufferedImage.getWidth();
+ // 高度
+ height = bufferedImage.getHeight();
+ }catch (IOException ioException){
+ log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
+ }
+ return new FileVO(height,width);
+ }
+ /**
+ * 获取文件尺寸
+ */
+ public static FileVO getFileSize(InputStream inputStream) {
+ int width = 0;
+ int height = 0;
+ try{
+ // 图片对象
+ BufferedImage bufferedImage = ImageIO.read(inputStream);
+ // 宽度
+ width = bufferedImage.getWidth();
+ // 高度
+ height = bufferedImage.getHeight();
+ }catch (IOException ioException){
+ log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
+ }
+ return new FileVO(height,width);
+ }
+ /**
+ * 获取远程文件流
+ */
+ public static InputStream getOriginFile(String path) {
+
+ try{
+ //远程
+ URL url = new URL(path);
+ return url.openStream();
+ }catch (IOException ioException){
+ log.error("获取文件尺寸异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException),path);
+ throw new BusinessException("get file is failed!");
+ }
+ }
+ /**
+ * 将文件名解析成文件的上传路径
+ */
+ public static File upload(MultipartFile file, String filePath) {
+ Date date = new Date();
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
+ String suffix = getExtensionName(file.getOriginalFilename());
+ String nowStr = format.format(date)+"-" ;
+ try {
+ String fileName = file.getOriginalFilename();
+ String path = filePath + fileName;
+ // getCanonicalFile 可解析正确各种路径
+ File dest = new File(path).getCanonicalFile();
+ // 检测是否存在目录
+ if (!dest.getParentFile().exists()) {
+ if (!dest.getParentFile().mkdirs()) {
+ System.out.println("was not successful.");
+ }
+ }
+ // 文件写入
+ file.transferTo(dest);
+ return dest;
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return null;
+ }
+ /**
+ * 删除文件
+ */
+ public static boolean delete(String path) {
+ File file = new File(path);
+ if (file.exists()) {
+ return file.delete();
+ }
+ return false;
+ }
+ /**
+ * 获取指定文件夹下所有文件,不含文件夹里的文件
+ *
+ * @param dirFilePath 文件夹路径
+ * @return
+ */
+ public static List getAllFile(String dirFilePath) {
+ if (StrUtil.isBlank(dirFilePath)){
+ return null;
+ }
+ return getAllFile(new File(dirFilePath));
+ }
+
+ /**
+ * 获取指定文件夹下所有文件,不含文件夹里的文件
+ *
+ * @param dirFile 文件夹
+ * @return
+ */
+ public static List getAllFile(File dirFile) {
+ // 如果文件夹不存在或着不是文件夹,则返回 null
+ if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile()){
+ return null;
+ }
+ File[] childrenFiles = dirFile.listFiles();
+ if (Objects.isNull(childrenFiles) || childrenFiles.length == 0){
+ return null;
+ }
+ List files = new ArrayList<>();
+ for (File childFile : childrenFiles) {
+ // 如果是文件,直接添加到结果集合
+ if (childFile.isFile()) {
+ files.add(childFile);
+ }
+ //以下几行代码取消注释后可以将所有子文件夹里的文件也获取到列表里
+ else {
+ // 如果是文件夹,则将其内部文件添加进结果集合
+ List cFiles = getAllFile(childFile);
+ if (Objects.isNull(cFiles) || cFiles.isEmpty()){
+ continue;
+ }
+ files.addAll(cFiles);
+ }
+ }
+ return files;
+ }
+
+
+}
diff --git a/src/main/java/com/mixi/common/utils/JSONResponseUtils.java b/src/main/java/com/mixi/common/utils/JSONResponseUtils.java
new file mode 100644
index 0000000..4fbf6a9
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/JSONResponseUtils.java
@@ -0,0 +1,42 @@
+package com.mixi.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.mixi.common.response.Response;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.ServletResponse;
+import java.io.PrintWriter;
+
+
+/**
+ * @author: dangweijian
+ * @description: 构造JSON响应工具类
+ * @Author dwjian
+ * @Date 2020/7/10 15:51
+ **/
+@Slf4j
+public class JSONResponseUtils {
+
+ /**
+ * 使用response输出JSON
+ *
+ * @param servletResponse
+ * @param response
+ */
+ public static void build(ServletResponse servletResponse, Response> response) {
+ PrintWriter out = null;
+ try {
+ servletResponse.setCharacterEncoding("UTF-8");
+ servletResponse.setContentType("application/json");
+ out = servletResponse.getWriter();
+ out.println(JSON.toJSONString(response));
+ } catch (Exception e) {
+ log.error(e + "输出JSON出错");
+ } finally {
+ if (out != null) {
+ out.flush();
+ out.close();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/LocalCacheUtils.java b/src/main/java/com/mixi/common/utils/LocalCacheUtils.java
new file mode 100644
index 0000000..df5bfd1
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/LocalCacheUtils.java
@@ -0,0 +1,277 @@
+package com.mixi.common.utils;
+
+import com.google.common.cache.*;
+import com.mixi.model.dto.ProductProcessDTO;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author: yanglei
+ * @description: 本地缓存工具
+ * @create: 2022-08-11 9:23
+ **/
+@Slf4j
+public final class LocalCacheUtils {
+ /**
+ * token
+ */
+ private static LoadingCache tokenCache = loadTokenCache();
+ /**
+ * 邮箱,短信验证码
+ */
+ private static LoadingCache emailCache = CacheBuilder.newBuilder()
+ //设置并发级别为5,并发级别是指可以同时写缓存的线程数
+ .concurrencyLevel(5)
+ //设置写缓存后一分钟过期
+ .expireAfterWrite(60, TimeUnit.SECONDS)
+ //刷新机制 每隔一定时间刷新缓存loader 只有调用get具体的操作才生效(懒加载) 不设置则不刷新
+// .refreshAfterWrite(60, TimeUnit.SECONDS)
+ //设置缓存容器的初始容量为100
+ .initialCapacity(100)
+ //设置缓存最大容量10000,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
+ .maximumSize(10000)
+ //设置要统计缓存的命中率
+ .recordStats()
+ //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
+ .build(new CacheLoader() {
+ @Override
+ public String load(String key) throws Exception {
+ return RandomsUtil.generateVerifyCode(1000L,9999L);
+ }
+ });;
+
+ /**
+ *
+ *缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存
+ */
+ private static LoadingCache loadTokenCache(){
+ LoadingCache tokenCache = CacheBuilder.newBuilder()
+ .concurrencyLevel(20)
+ .expireAfterWrite(24*100, TimeUnit.HOURS)
+ .initialCapacity(100)
+ .maximumSize(10000)
+ .recordStats()
+ .build(new CacheLoader() {
+ @Override
+ public String load(String key) throws Exception {
+ return "null";
+ }
+ });
+ return tokenCache;
+ }
+
+ /**
+ * aida 接口限流(先粗暴做)
+ */
+ private static LoadingCache aidaInterfaceCurrentLimiting = CacheBuilder.newBuilder()
+ //设置并发级别为5,并发级别是指可以同时写缓存的线程数
+ .concurrencyLevel(20)
+ //设置写缓存后30天过期
+ .expireAfterWrite(60*60*24*30, TimeUnit.SECONDS)
+ //设置缓存容器的初始容量为100
+ .initialCapacity(5)
+ //设置缓存最大容量50000,超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
+ .maximumSize(20)
+ //设置要统计缓存的命中率
+ .recordStats()
+ //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
+ .build(new CacheLoader() {
+ @Override
+ public Integer load(String key) throws Exception {
+ return 0;
+ }
+ });
+
+ /**
+ * 商品文件进度统计
+ */
+ private static LoadingCache productProcessCache = CacheBuilder.newBuilder()
+ //设置并发级别为10,并发级别是指可以同时写缓存的线程数
+ .concurrencyLevel(1000)
+ //设置写缓存后5分钟过期
+ .expireAfterWrite(60*30, TimeUnit.SECONDS)
+ //设置缓存容器的初始容量为100
+ .initialCapacity(5)
+ //设置缓存最大容量50000,超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
+ .maximumSize(100)
+ //设置要统计缓存的命中率
+ .recordStats()
+ //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存
+ .build(new CacheLoader() {
+ @Override
+ public ProductProcessDTO load(Long key) throws Exception {
+ return new ProductProcessDTO(0,0,"Attribute",0);
+ }
+ });
+ /**
+ * 添加token本地缓存
+ * @param key
+ * @param value
+ */
+ public static void setTokenCache(String key, String value) {
+ tokenCache.put(key, value);
+ }
+
+ /**
+ * 获取token本地缓存
+ * @param key
+ * @return
+ */
+ public static String getTokenCache(String key) {
+ try {
+ String value = tokenCache.get(key);
+ if ("null".equals(value)) {
+ return null;
+ }
+ return value;
+ } catch (ExecutionException e) {
+ log.error("getTokenCache方法错误", e);
+ }
+ return null;
+ }
+ /**
+ * 获取token本地缓存
+ * @param key
+ * @return
+ */
+ public static void clearTokenCache(String key) {
+ try {
+ tokenCache.invalidate(key);
+ } catch (Exception e) {
+ log.error("clearTokenCache方法错误", e);
+ }
+ }
+
+ /**
+ * 设置本次接口流量数
+ * @param key
+ * @param value
+ */
+ public static void setAidaInterfaceCurrentLimitingCache(String key, Integer value) {
+ aidaInterfaceCurrentLimiting.put(key, value);
+ }
+
+ /**
+ * 获取本次接口流量数
+ * @param key
+ * @return
+ */
+ public static Integer getAidaInterfaceCurrentLimitingCache(String key) {
+ try {
+ return aidaInterfaceCurrentLimiting.get(key);
+ } catch (ExecutionException e) {
+ log.error("getAidaInterfaceCurrentLimitingCache方法错误", e);
+ }
+ return null;
+ }
+ /**
+ * 添加token本地缓存
+ * @param key
+ * @param value
+ */
+ public static void setEmailCache(String key, String value) {
+ emailCache.put(key, value);
+ }
+
+ /**
+ * 获取验证码本地缓存
+ * @param key
+ * @return
+ */
+ public static String getVerifyCodeCache(String key) {
+ try {
+ String value = emailCache.get(key);
+ if ("null".equals(value)) {
+ return null;
+ }
+ return value;
+ } catch (ExecutionException e) {
+ log.error("getTokenCache方法错误", e);
+ }
+ return null;
+ }
+
+ /**
+ * 添加商品文件进度统计
+ * @param key
+ * @param productProcess
+ */
+ public static void setProductUploadProcessCache(Long key, ProductProcessDTO productProcess) {
+ productProcessCache.put(key, productProcess);
+ }
+
+ /**
+ * 获取商品文件进度统计
+ * @param key
+ * @return
+ */
+ public static ProductProcessDTO getProductUploadProcessCache(Long key) {
+ try {
+ return productProcessCache.get(key);
+ } catch (ExecutionException e) {
+ log.error("getProductUploadProcessCache方法错误", e);
+ }
+ return null;
+ }
+ /**
+ * 进度统计完后 删除进度
+ * @param key
+ * @return
+ */
+ public static void delProductUploadProcessCache(Long key) {
+ try {
+ productProcessCache.invalidate(key);
+ } catch (Exception e) {
+ log.error("delProductUploadProcessCache方法错误", e);
+ }
+ }
+
+ /**
+ * 预签名URL缓存
+ */
+ private static LoadingCache presignedUrlCache = CacheBuilder.newBuilder()
+ .concurrencyLevel(10)
+ .expireAfterWrite((24 * 60 - 1), TimeUnit.MINUTES)
+ .initialCapacity(100)
+ .maximumSize(10000)
+ .recordStats()
+ .build(new CacheLoader() {
+ @Override
+ public String load(String key) throws Exception {
+ return "null";
+ }
+ });
+
+ /**
+ * 添加预签名URL到缓存
+ *
+ * @param key URL的唯一标识
+ * @param value 预签名URL
+ */
+ public static void setPresignedUrlCache(String key, String value) {
+ presignedUrlCache.put(key, value);
+ }
+
+ /**
+ * 获取预签名URL
+ *
+ * @param key URL的唯一标识
+ * @return 预签名URL,如果不存在则返回null
+ */
+ public static String getPresignedUrlCache(String key) {
+ try {
+ String value = presignedUrlCache.get(key);
+ if ("null".equals(value)) {
+ return null;
+ }
+ return value;
+ } catch (ExecutionException e) {
+ log.error("getPresignedUrlCache方法错误", e);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/MD5Utils.java b/src/main/java/com/mixi/common/utils/MD5Utils.java
new file mode 100644
index 0000000..96ebbb7
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/MD5Utils.java
@@ -0,0 +1,116 @@
+package com.mixi.common.utils;
+
+import cn.hutool.core.exceptions.ExceptionUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5加密工具
+ */
+@Slf4j
+public class MD5Utils {
+
+ /**
+ * MD5加密
+ *
+ * @param str
+ * @return
+ */
+ public static String encrypt(String str) {
+ byte[] mdBytes = null;
+ try {
+ mdBytes = MessageDigest.getInstance("MD5").digest(
+ str.getBytes());
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("MD5算法不存在!");
+ }
+ String mdCode = new BigInteger(1, mdBytes).toString(16);
+
+ if (mdCode.length() < 32) {
+ int a = 32 - mdCode.length();
+ for (int i = 0; i < a; i++) {
+ mdCode = "0" + mdCode;
+ }
+ }
+ // 默认返回32位小写
+ return mdCode;
+ }
+
+ /**
+ * MD5加密文件
+ *
+ * @param file
+ * @return
+ */
+ public static String encryptFile(MultipartFile file) {
+ String md5 = null;
+ try {
+ md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
+ } catch (IOException ioException) {
+ log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
+ }
+ return md5;
+ }
+ /**
+ * MD5加密文件
+ *
+ * @param inputStream
+ * @return
+ */
+ public static String encryptFile(FileInputStream inputStream) {
+ String md5 = null;
+ try {
+ md5 = DigestUtils.md5DigestAsHex(inputStream);
+ } catch (IOException ioException) {
+ log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
+ }
+ return md5;
+ }
+
+ public static void main(String[] args) throws FileNotFoundException, IOException {
+ File file1 = new File("/Users/yanglei/Documents/阳磊日报2019-04-23.numbers");
+ File file2 = new File("/Users/yanglei/Documents/7777.numbers");
+ FileInputStream fileInputStream1 = new FileInputStream(file1);
+ FileInputStream fileInputStream2 = new FileInputStream(file2);
+ String md51 = DigestUtils.md5DigestAsHex(fileInputStream1);
+ String md52 = DigestUtils.md5DigestAsHex(fileInputStream2);
+ if (md51.equals(md52)) {
+ System.out.println(md51);
+ }
+ System.out.println("md51==" + md51);
+ System.out.println("md52==" + md52);
+
+ }
+
+
+ /**
+ * MD5加密文件
+ *
+ * @param path
+ * @return
+ */
+ public static String encryptFile(String path, Boolean isLocal) {
+ String md5 = null;
+ try {
+ InputStream inputStream = null;
+ if (isLocal) {
+ File file = new File(path);
+ inputStream = new FileInputStream(file);
+ } else {
+ //远程
+ inputStream = FileUtil.getOriginFile(path);
+ }
+ md5 = DigestUtils.md5DigestAsHex(inputStream);
+ } catch (IOException ioException) {
+ log.error("文件File md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
+ }
+ return md5;
+ }
+
+}
diff --git a/src/main/java/com/mixi/common/utils/MinioUtil.java b/src/main/java/com/mixi/common/utils/MinioUtil.java
new file mode 100644
index 0000000..2095ffb
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/MinioUtil.java
@@ -0,0 +1,419 @@
+package com.mixi.common.utils;
+
+import com.mixi.common.config.exception.BusinessException;
+import io.minio.*;
+import io.minio.errors.MinioException;
+import io.minio.http.Method;
+import io.minio.messages.DeleteError;
+import io.minio.messages.DeleteObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @description: minio工具类
+ * @version:3.0
+ */
+@Component
+public class MinioUtil {
+ @Autowired
+ private MinioClient minioClient;
+
+ /**
+ * description: 判断bucket是否存在,不存在则创建
+ *
+ * @return: void
+ */
+ public void existBucket(String name) {
+ try {
+ boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
+ if (!exists) {
+ minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 创建存储bucket
+ *
+ * @param bucketName 存储bucket名称
+ * @return Boolean
+ */
+ public Boolean makeBucket(String bucketName) {
+ try {
+ minioClient.makeBucket(MakeBucketArgs.builder()
+ .bucket(bucketName)
+ .build());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 删除存储bucket
+ *
+ * @param bucketName 存储bucket名称
+ * @return Boolean
+ */
+ public Boolean removeBucket(String bucketName) {
+ try {
+ minioClient.removeBucket(RemoveBucketArgs.builder()
+ .bucket(bucketName)
+ .build());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * description: 上传文件
+ *
+ * @param bucketName
+ * @param path
+ * @param multipartFile
+ * @return: java.lang.String
+ */
+ public List uploadBatch(String bucketName, String path, MultipartFile[] multipartFile) {
+ List names = new ArrayList<>(multipartFile.length);
+ for (MultipartFile file : multipartFile) {
+ String fileName = file.getOriginalFilename();
+ String[] split = fileName.split("\\.");
+ if (split.length > 1) {
+ fileName = path + "/" + UUID.randomUUID() + "." + split[1];
+ } else {
+ fileName = path + "/" + UUID.randomUUID();
+ }
+ InputStream in = null;
+ try {
+ in = file.getInputStream();
+ minioClient.putObject(PutObjectArgs.builder()
+ .bucket(bucketName)
+ .object(fileName)
+ .stream(in, in.available(), -1)
+ .contentType(file.getContentType())
+ .build()
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ names.add(fileName);
+ }
+ return names;
+ }
+
+ /**
+ * description: 上传文件
+ *
+ * @param bucketName
+ * @param path
+ * @param file
+ * @return: java.lang.String
+ */
+ public String upload(String bucketName, String path, MultipartFile file) {
+ String fileName = file.getOriginalFilename();
+// String[] split = fileName.split("\\.");
+ fileName = path;
+ InputStream in = null;
+ try {
+ in = file.getInputStream();
+ minioClient.putObject(PutObjectArgs.builder()
+ .bucket(bucketName)
+ .object(fileName)
+ .stream(in, in.available(), -1)
+ .contentType(file.getContentType())
+ .build()
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return bucketName + "/" + fileName;
+ }
+
+ public String upload(String bucketName, String path, MultipartFile file, String copy) {
+ InputStream in = null;
+ try {
+ in = file.getInputStream();
+ minioClient.putObject(PutObjectArgs.builder()
+ .bucket(bucketName)
+ .object(path)
+ .stream(in, in.available(), -1)
+ .contentType(file.getContentType())
+ .build()
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return bucketName + "/" + path;
+ }
+
+// public String upload(String bucketName, String path, File file) {
+// InputStream in = null;
+// try {
+// in = new FileInputStream(file);
+// minioClient.putObject(PutObjectArgs.builder()
+// .bucket(bucketName)
+// .object(path)
+// .stream(in, in.available(), -1)
+// .contentType(file.getContentType())
+// .build()
+// );
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// if (in != null) {
+// try {
+// in.close();
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+// }
+// return fileName;
+// }
+
+ public InputStream download(String bucketName, String objectName) throws MinioException, IOException {
+ try {
+ return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException(e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public InputStream download(String path) throws MinioException, IOException {
+ if (!path.contains("/")) {
+ throw new BusinessException("the.path.is.error");
+ }
+ int index = path.indexOf("/");
+ String bucketName = path.substring(0, index);
+ String objectName = path.substring(index + 1);
+ return download(bucketName, objectName);
+ }
+
+ /**
+ * description: 下载文件
+ *
+ * @param path
+ * @param bucketName
+ * @return: org.springframework.http.ResponseEntity
+ */
+// public ResponseEntity download(String path, String bucketName) {
+// ResponseEntity responseEntity = null;
+// InputStream in = null;
+// ByteArrayOutputStream out = null;
+// try {
+// in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(path).build());
+// out = new ByteArrayOutputStream();
+// IOUtils.copy(in, out);
+// //封装返回值
+// byte[] bytes = out.toByteArray();
+// HttpHeaders headers = new HttpHeaders();
+// try {
+// headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(path, "UTF-8"));
+// } catch (UnsupportedEncodingException e) {
+// e.printStackTrace();
+// }
+// headers.setContentLength(bytes.length);
+// headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+// headers.setAccessControlExposeHeaders(Arrays.asList("*"));
+// responseEntity = new ResponseEntity(bytes, headers, HttpStatus.OK);
+// } catch (Exception e) {
+// e.printStackTrace();
+// } finally {
+// try {
+// if (in != null) {
+// try {
+// in.close();
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+// if (out != null) {
+// out.close();
+// }
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// }
+// return responseEntity;
+// }
+
+ /**
+ * 查看文件对象
+ *
+ * @param bucketName 存储bucket名称
+ * @return 存储bucket内文件对象信息
+ */
+// public List listObjects(String bucketName) {
+// Iterable> results = minioClient.listObjects(
+// ListObjectsArgs.builder().bucket(bucketName).build());
+// List objectItems = new ArrayList<>();
+// try {
+// for (Result- result : results) {
+// Item item = result.get();
+// ObjectItem objectItem = new ObjectItem();
+// objectItem.setObjectName(item.objectName());
+// objectItem.setSize(item.size());
+// objectItems.add(objectItem);
+// }
+// } catch (Exception e) {
+// e.printStackTrace();
+// return null;
+// }
+// return objectItems;
+// }
+
+ /**
+ * 批量删除文件对象
+ *
+ * @param bucketName 存储bucket名称
+ * @param objects 对象名称集合
+ */
+ public Iterable> removeObjects(String bucketName, List objects) {
+ List dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
+ Iterable> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
+ return results;
+ }
+
+ public void deleteObject(String bucketName, String objectName) {
+ try {
+ minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
+ System.out.println("Object " + objectName + " successfully removed from bucket " + bucketName);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.err.println("Error while removing object " + objectName + " from bucket " + bucketName + ": " + e.getMessage());
+ }
+ }
+
+ public void deleteObject(String path) {
+ if (!path.contains("/")) {
+ throw new BusinessException("The path is error!");
+ }
+ int index = path.indexOf("/");
+ String bucketName = path.substring(0, index);
+ String objectName = path.substring(index + 1);
+ deleteObject(bucketName, objectName);
+ }
+
+ /**
+ * 获取文件的临时URL
+ *
+ * @param bucketName 存储桶名称
+ * @param fileName 文件名
+ * @param expiry 过期时间(单位:分)
+ * @return 文件的临时URL,如果出现异常则返回null
+ */
+ public String getPresignedUrl(String bucketName, String fileName, int expiry) {
+ try {
+ return minioClient.getPresignedObjectUrl(
+ GetPresignedObjectUrlArgs.builder()
+ .bucket(bucketName)
+ .object(fileName)
+ .expiry(expiry, TimeUnit.MINUTES)
+ .method(Method.GET)
+ .build()
+ );
+ } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ throw new BusinessException(e.getMessage());
+ }
+ }
+
+ public String getPresignedUrl(String path, int expiry) {
+ if (LocalCacheUtils.getPresignedUrlCache(path) != null) {
+ return LocalCacheUtils.getPresignedUrlCache(path);
+ } else {
+ if (!path.contains("/")) {
+ throw new BusinessException("The path is error!");
+ }
+ int index = path.indexOf("/");
+ String bucketName = path.substring(0, index);
+ String fileName = path.substring(index + 1);
+ String presignedUrl = getPresignedUrl(bucketName, fileName, expiry);
+ LocalCacheUtils.setPresignedUrlCache(path, presignedUrl);
+ return presignedUrl;
+ }
+ }
+
+ /**
+ * 将桶名、文件名从url中分离出来
+ *
+ * @param url 带桶名、文件名的url
+ * @param expiry 图片过期时间
+ * @return 可以直接访问的minio图片地址
+ */
+ public String splitThenGetPreviewUrl(String url, int expiry) {
+ String[] parts = url.split("/");
+ String bucketName = parts[0];
+ StringBuilder fileName = new StringBuilder();
+ for (int i = 1; i < parts.length; i++) {
+ fileName.append(parts[i]);
+ if (i != parts.length - 1) {
+ fileName.append("/");
+ }
+ }
+ return getPresignedUrl(bucketName, String.valueOf(fileName), expiry);
+ }
+
+ public boolean doesObjectExist(String bucketName, String objectName) {
+ try {
+ minioClient.statObject(
+ StatObjectArgs.builder()
+ .bucket(bucketName)
+ .object(objectName)
+ .build()
+ );
+ return true;
+ } catch (Exception e) {
+ // 如果发生异常,说明文件不存在或者出现了其他错误
+ return false;
+ }
+ }
+
+ public String getMinioPath(Long accountId, String itemGroup, String subGroup, String originalFilename) {
+ return accountId + "/" + itemGroup+ "/" + subGroup+ "/" + originalFilename;
+ }
+}
+
+
diff --git a/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java b/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java
new file mode 100644
index 0000000..9db87cd
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java
@@ -0,0 +1,170 @@
+package com.mixi.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 多次读写BODY用HTTP REQUEST - 解决流只能读一次问题
+ */
+@Slf4j
+public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
+
+ private final byte[] body;
+
+ public MultiReadHttpServletRequest(HttpServletRequest request) {
+ super(request);
+ String sessionStream = getBodyString(request);
+ body = sessionStream.getBytes(StandardCharsets.UTF_8);
+ }
+
+ /**
+ * 获取请求Body
+ *
+ * @param request 请求
+ * @return Body字符串
+ */
+ private String getBodyString(final ServletRequest request) {
+ StringBuilder sb = new StringBuilder();
+ InputStream inputStream = null;
+ BufferedReader reader = null;
+ try {
+ inputStream = cloneInputStream(request.getInputStream());
+ reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ String line = "";
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 复制输入流
+ * @param inputStream 请求输入流
+ * @return 复制出来的输入流
+ */
+ private InputStream cloneInputStream(ServletInputStream inputStream) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len;
+ try {
+ while ((len = inputStream.read(buffer)) > -1) {
+ byteArrayOutputStream.write(buffer, 0, len);
+ }
+ byteArrayOutputStream.flush();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+ }
+
+ @Override
+ public BufferedReader getReader() {
+ return new BufferedReader(new InputStreamReader(getInputStream()));
+ }
+
+ @Override
+ public ServletInputStream getInputStream() {
+
+ final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+
+ return new ServletInputStream() {
+
+ @Override
+ public int read() {
+ return bais.read();
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ }
+ };
+ }
+
+ /**
+ * 将前端请求的表单数据转换成json字符串 - 前后端一体的情况下使用
+ *
+ * @param request:
+ * @return: java.lang.String
+ */
+ public static String getBodyJsonStrByForm(ServletRequest request) {
+ Map bodyMap = new HashMap<>(16);
+ try {
+ // 参数定义
+ String paraName = null;
+ // 获取请求参数并转换
+ Enumeration e = request.getParameterNames();
+ while (e.hasMoreElements()) {
+ paraName = e.nextElement();
+ bodyMap.put(paraName, request.getParameter(paraName));
+ }
+ } catch (Exception e) {
+ log.error("请求参数转换错误!", e);
+ }
+ return JSONObject.toJSONString(bodyMap);
+ }
+
+ /**
+ * 将前端传递的json数据转换成json字符串 - 前后端分离的情况下使用
+ *
+ * @param request:
+ * @return: java.lang.String
+ */
+ public static String getBodyJsonStrByJson(ServletRequest request) {
+ StringBuffer json = new StringBuffer();
+ String line;
+ try {
+ BufferedReader reader = request.getReader();
+ while ((line = reader.readLine()) != null) {
+ json.append(line);
+ }
+ } catch (Exception e) {
+ log.error("请求参数转换错误!", e);
+ }
+ return json.toString();
+ }
+
+}
diff --git a/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java b/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java
new file mode 100644
index 0000000..fb4389e
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java
@@ -0,0 +1,77 @@
+package com.mixi.common.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+/**
+ * 多次读写BODY用HTTP RESPONSE - 解决流只能读一次问题
+ */
+public class MultiReadHttpServletResponse extends HttpServletResponseWrapper {
+
+ private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ private HttpServletResponse response;
+
+ public MultiReadHttpServletResponse(HttpServletResponse response) {
+ super(response);
+ response.setCharacterEncoding("UTF-8");
+ response.setContentType("application/json");
+ this.response = response;
+ }
+
+ public byte[] getBody() {
+ return byteArrayOutputStream.toByteArray();
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() {
+ return new ServletOutputStreamWrapper(this.byteArrayOutputStream, this.response);
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return new PrintWriter(new OutputStreamWriter(getOutputStream(), this.response.getCharacterEncoding()));
+ }
+
+
+ @Data
+ @AllArgsConstructor
+ private static class ServletOutputStreamWrapper extends ServletOutputStream {
+
+ private ByteArrayOutputStream outputStream;
+ private HttpServletResponse response;
+
+ @Override
+ public boolean isReady() {
+ return true;
+ }
+
+ @Override
+ public void setWriteListener(WriteListener listener) {
+
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ this.outputStream.write(b);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if (!this.response.isCommitted()) {
+ byte[] body = this.outputStream.toByteArray();
+ ServletOutputStream outputStream = this.response.getOutputStream();
+ outputStream.write(body);
+ outputStream.flush();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/ObjectUtils.java b/src/main/java/com/mixi/common/utils/ObjectUtils.java
new file mode 100644
index 0000000..1d13531
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/ObjectUtils.java
@@ -0,0 +1,34 @@
+package com.mixi.common.utils;
+import java.lang.reflect.Field;
+
+public class ObjectUtils {
+
+ /**
+ * 判断该对象是否所有属性为空
+ * 返回ture表示所有属性为null,返回false表示不是所有属性都是null
+ */
+ public static boolean isAllFieldNull(Object object) {
+ boolean flag = true;
+
+ Class clazz = object.getClass();
+ Field[] fields = clazz.getDeclaredFields();
+
+ for (Field field : fields) {
+ //设置属性是可以访问的(私有的也可以)
+ field.setAccessible(true);
+ Object value = null;
+ try {
+ value = field.get(object);
+ // 只要有1个属性不为空,那么就不是所有的属性值都为空
+ if (value != null) {
+ flag = false;
+ break;
+ }
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return flag;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/RandomsUtil.java b/src/main/java/com/mixi/common/utils/RandomsUtil.java
new file mode 100644
index 0000000..1caaf11
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/RandomsUtil.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019-2020 Zheng Jie
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.mixi.common.utils;
+
+import cn.hutool.core.util.RandomUtil;
+
+import java.text.DecimalFormat;
+
+/**
+ * @author yanglei
+ * @description 随机数工具类
+ * @date 2022-07
+ **/
+public class RandomsUtil {
+
+ private static String PREFIX = "ver";
+
+
+
+ /**
+ * 生成验证码
+ *
+ * @param randomStart
+ * @param randomEnd
+ */
+ public static String generateVerifyCode(Long randomStart, Long randomEnd) {
+ return String.valueOf(RandomUtil.randomLong(randomStart,randomEnd));
+ }
+
+
+}
diff --git a/src/main/java/com/mixi/common/utils/RedisCacheUtils.java b/src/main/java/com/mixi/common/utils/RedisCacheUtils.java
new file mode 100644
index 0000000..af4cfcc
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/RedisCacheUtils.java
@@ -0,0 +1,50 @@
+package com.mixi.common.utils;
+
+import cn.hutool.core.util.StrUtil;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author: dangweijian
+ * @description: redis缓存工具
+ * @create: 2021-01-08 9:23
+ **/
+public final class RedisCacheUtils {
+
+ private static RedisTemplate getRedisTemplate(){
+ return SpringUtils.getBean("redisTemplate");
+ }
+
+ private static RedisTemplate getRedisTemplate(Class clazz){
+ return SpringUtils.getBean("redisTemplate");
+ }
+
+ private static RedisTemplate> getListRedisTemplate(Class clazz){
+ return SpringUtils.getBean("redisTemplate");
+ }
+
+ public static T get(String key, Class clazz){
+ return getRedisTemplate(clazz).opsForValue().get(key);
+ }
+
+ public static List getList(String key, Class clazz){
+ return getListRedisTemplate(clazz).opsForValue().get(key);
+ }
+
+ public static void set(String key, Object value){
+ getRedisTemplate().opsForValue().set(key, value);
+ }
+
+ public static void set(String key, Object value, long time, TimeUnit unit){
+ getRedisTemplate().opsForValue().set(key, value, time, unit);
+ }
+
+ public static boolean delete(String key){
+ if(StrUtil.isNotEmpty(key)){
+ return Boolean.TRUE.equals(getRedisTemplate().delete(key));
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java b/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java
new file mode 100644
index 0000000..ffbb88c
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java
@@ -0,0 +1,70 @@
+package com.mixi.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.security.*;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * Rsa解密工具
+ */
+@Slf4j
+public class RsaDecryptUtils {
+
+ public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg==";
+
+ public static String decrypt(String content, String privateKey) {
+ byte[] result;
+ try {
+ PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PrivateKey privateKeyText = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, privateKeyText);
+ result = doLongerCipherFinal(cipher, Base64.decodeBase64(content));
+ } catch (Exception e) {
+ log.error("RSA解密失败", e);
+ return null;
+ }
+ return new String(result);
+ }
+
+ private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ out.write(cipher.doFinal(source));
+ out.close();
+ return out.toByteArray();
+ }
+
+ /**
+ * 构建RSA密钥对
+ * @param args
+ */
+// public static void main(String[] args) throws NoSuchAlgorithmException {
+// KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+// keyPairGenerator.initialize(1024);
+// KeyPair keyPair = keyPairGenerator.generateKeyPair();
+// RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
+// RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
+// String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
+// String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
+// System.out.println("公钥:" + publicKeyString);
+// System.out.println("私钥:" + privateKeyString);
+// }
+
+ /**
+ * 解密
+ * @param args
+ * @throws NoSuchAlgorithmException
+ */
+ public static void main(String[] args) throws Exception {
+ String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg==";
+ String decrypt = decrypt("EzAxC/373prww88TXDayIZTvxS3uFAvGhhzLNs+5cOfJU6zm3x/1RA5KcouuWwcYs0bbvNV7zSitLeEGeo23aPUxzr+rsNvCqKHrPNKbcl/oyOFBtOfguVbuHVEy8Q4cpVxfWCd/aEXx9OJXkLEAvlDdDF6SHyKhf+RUmSGEQOg=", privateKey);
+ System.out.println(decrypt);
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java b/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java
new file mode 100644
index 0000000..95f7be5
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java
@@ -0,0 +1,46 @@
+package com.mixi.common.utils;
+
+import org.apache.tomcat.util.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayOutputStream;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Rsa加密工具
+ */
+public class RsaEncryptUtils {
+
+ /**
+ * 加密方法
+ *
+ * @param content 需要加密的内容
+ * @param publicKey 公钥
+ * @return 加密后得到的字符串
+ * @throws Exception
+ */
+ public static String encrypt(String content, String publicKey) throws Exception {
+ X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ PublicKey publicKeyText = keyFactory.generatePublic(x509EncodedKeySpec2);
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, publicKeyText);
+ byte[] result = doLongerCipherFinal(cipher, content.getBytes());
+ return Base64.encodeBase64String(result);
+ }
+
+ private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ int offset = 0;
+ int totalSize = source.length;
+ while (totalSize - offset > 0) {
+ int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset);
+ out.write(cipher.doFinal(source, offset, size));
+ offset += size;
+ }
+ out.close();
+ return out.toByteArray();
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/SecurityContextUtils.java b/src/main/java/com/mixi/common/utils/SecurityContextUtils.java
new file mode 100644
index 0000000..64f4655
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/SecurityContextUtils.java
@@ -0,0 +1,32 @@
+package com.mixi.common.utils;
+
+import com.mixi.model.vo.AuthPrincipalVo;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+public class SecurityContextUtils {
+
+ public static AuthPrincipalVo getCurrentUser() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ if(authentication != null && authentication.getPrincipal() != null){
+ return (AuthPrincipalVo) authentication.getPrincipal();
+ }
+ return null;
+ }
+
+ public static Long getCurrentUserId() {
+ AuthPrincipalVo currentUser = getCurrentUser();
+ if(currentUser != null){
+ return currentUser.getId();
+ }
+ return null;
+ }
+
+ public static String getCurrentUsername() {
+ AuthPrincipalVo currentUser = getCurrentUser();
+ if(currentUser != null){
+ return currentUser.getUsername();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/SendEmailUtil.java b/src/main/java/com/mixi/common/utils/SendEmailUtil.java
new file mode 100644
index 0000000..335eca6
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/SendEmailUtil.java
@@ -0,0 +1,103 @@
+package com.mixi.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.mixi.common.config.exception.BusinessException;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.ses.v20201002.SesClient;
+import com.tencentcloudapi.ses.v20201002.models.SendEmailRequest;
+import com.tencentcloudapi.ses.v20201002.models.SendEmailResponse;
+import com.tencentcloudapi.ses.v20201002.models.Template;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 邮件发送类
+ */
+@Slf4j
+public class SendEmailUtil {
+ /**
+ * 秘钥id
+ */
+ private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr";
+ /**
+ * 秘钥key
+ */
+ private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq";
+ /**
+ * 发信地址
+ */
+ private static String SEND_ADDRESS = "intelligent.curtain@w.mbzn360.com";
+ /**
+ * 登入主题
+ */
+ public static String LOGIN_SUBJECT = "智能窗帘登入";
+ /**
+ * 忘记密码主题
+ */
+ public static String FORGET_PWD_SUBJECT = "智能窗帘忘记密码";
+ /**
+ * 注册主题
+ */
+ public static String REGISTER_SUBJECT = "智能窗帘注册";
+ /**
+ * 登入操作
+ */
+ public static String LOGIN_OPERATION = "智能窗帘登入操作";
+ /**
+ * 忘记密码操作
+ */
+ public static String FORGET_PWD_OPERATION = "智能窗帘忘记密码操作";
+ /**
+ * 注册操作
+ */
+ public static String REGISTER_OPERATION = "智能窗帘注册";
+ /**
+ * 模板id
+ */
+ private static Long TEMPLATE_ID = 34986L;
+
+
+ public static Boolean send(String receiverAddress,String subject,String operation,String verifyCode) {
+ try{
+ // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
+ // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
+ Credential cred = new Credential(SECRET_ID, SECRET_KEy);
+ // 实例化一个http选项,可选的,没有特殊需求可以跳过
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setEndpoint("ses.tencentcloudapi.com");
+ // 实例化一个client选项,可选的,没有特殊需求可以跳过
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+ // 实例化要请求产品的client对象,clientProfile是可选的
+ SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
+ // 实例化一个请求对象,每个接口都会对应一个request对象
+ SendEmailRequest req = new SendEmailRequest();
+
+ req.setFromEmailAddress(SEND_ADDRESS);
+ req.setDestination(new String[]{receiverAddress});
+ req.setSubject(subject);
+ req.setTemplate(contractTemplate(operation, verifyCode));
+
+ // 返回的resp是一个SendEmailResponse的实例,与请求对象对应
+ SendEmailResponse resp = client.SendEmail(req);
+ // 输出json格式的字符串回包
+ log.info("短信发送结果res###{}",SendEmailResponse.toJsonString(resp));
+ return Boolean.TRUE;
+ } catch (TencentCloudSDKException e) {
+ log.info("邮件发送失败###{}",e.toString());
+ throw new BusinessException(e.getMessage());
+ }
+ }
+ private static Template contractTemplate(String operation,String verifyCode){
+ Template template = new Template();
+ template.setTemplateID(TEMPLATE_ID);
+
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("operation",operation);
+ jsonObject.put("code",verifyCode);
+ template.setTemplateData(jsonObject.toJSONString());
+ return template;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/SendSmsUtil.java b/src/main/java/com/mixi/common/utils/SendSmsUtil.java
new file mode 100644
index 0000000..5a4afde
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/SendSmsUtil.java
@@ -0,0 +1,106 @@
+package com.mixi.common.utils;
+
+import com.mixi.common.config.exception.BusinessException;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.sms.v20210111.SmsClient;
+import com.tencentcloudapi.sms.v20210111.models.*;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.util.Arrays;
+
+import java.util.Objects;
+
+/**
+ * 短信发送类
+ */
+@Slf4j
+public class SendSmsUtil {
+ /**
+ * 秘钥id
+ */
+ private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr";
+ /**
+ * 秘钥key
+ */
+ private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq";
+ /**
+ * sdkAppId
+ */
+ private static String SDK_APP_ID = "1400722195";
+ /**
+ * 签名
+ */
+ public static String SIGN_NAME = "深呼吸智能窗帘";
+ /**
+ * 忘记密码模板
+ */
+ public static String FORGET_TEMPLATE_ID = "1514353";
+ /**
+ * 登入模板
+ */
+ public static String LOGIN_TEMPLATE_ID = "1514349";
+ /**
+ * 登入操作
+ */
+ public static String LOGIN_OPERATION = "登入";
+ /**
+ * 忘记密码操作
+ */
+ public static String FORGET_PWD_OPERATION = "忘记密码操作";
+
+
+ public static Boolean send(String phone, String templateId, String verifyCode) {
+ try{
+ // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
+ // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
+ Credential cred = new Credential(SECRET_ID, SECRET_KEy);
+ // 实例化一个http选项,可选的,没有特殊需求可以跳过
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setReqMethod("POST");
+ /* SDK有默认的超时时间,非必要请不要进行调整
+ * 如有需要请在代码中查阅以获取最新的默认值 */
+ httpProfile.setConnTimeout(60);
+ /* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
+ httpProfile.setEndpoint("sms.tencentcloudapi.com");
+
+ /* 非必要步骤:
+ * 实例化一个客户端配置对象,可以指定超时时间等配置 */
+ ClientProfile clientProfile = new ClientProfile();
+ /* SDK默认用TC3-HMAC-SHA256进行签名
+ * 非必要请不要修改这个字段 */
+ clientProfile.setSignMethod("HmacSHA256");
+ clientProfile.setHttpProfile(httpProfile);
+ /* 实例化要请求产品(以sms为例)的client对象
+ * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
+ SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
+
+ SendSmsRequest req = new SendSmsRequest();
+ req.setSmsSdkAppId(SDK_APP_ID);
+ req.setSignName(SIGN_NAME);
+ req.setTemplateId(templateId);
+ //模板参数
+ String[] templateParamSet = {verifyCode};
+ req.setTemplateParamSet(templateParamSet);
+ /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
+ * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */
+ String[] phoneNumberSet = {phone};
+ req.setPhoneNumberSet(phoneNumberSet);
+ //发送短信
+ SendSmsResponse res = client.SendSms(req);
+ log.info("短信发送结果res###{}",SendSmsResponse.toJsonString(res));
+ if(Objects.isNull(res)|| Arrays.isNullOrContainsNull(res.getSendStatusSet())
+ ||(! res.getSendStatusSet()[0].getCode().equals("Ok")) ){
+ SendStatus message = res.getSendStatusSet()[0];
+ throw new BusinessException(message.getMessage());
+ }
+ // 输出json格式的字符串回包
+ } catch (TencentCloudSDKException e) {
+ log.error(e.toString());
+ return Boolean.FALSE;
+ }
+ return Boolean.TRUE;
+ }
+
+}
diff --git a/src/main/java/com/mixi/common/utils/SpringUtils.java b/src/main/java/com/mixi/common/utils/SpringUtils.java
new file mode 100644
index 0000000..8328963
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/SpringUtils.java
@@ -0,0 +1,44 @@
+package com.mixi.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * @ClassName SpringUtils
+ * @Description springBean工具
+ * @Author dwjian
+ * @Date 2020/1/15 17:10
+ */
+@Component
+public class SpringUtils implements ApplicationContextAware {
+
+ private static ApplicationContext applicationContext;
+
+ public static T getBean(Class clazz) {
+ return applicationContext.getBean(clazz);
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ SpringUtils.applicationContext = applicationContext;
+ }
+
+ public static T getBean(String beanName) {
+ if(applicationContext.containsBean(beanName)){
+ return (T) applicationContext.getBean(beanName);
+ }else{
+ return null;
+ }
+ }
+
+ public static Map getBeansOfType(Class baseType){
+ return applicationContext.getBeansOfType(baseType);
+ }
+
+ public static ApplicationContext getApplicationContext(){
+ return applicationContext;
+ }
+}
diff --git a/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java b/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java
new file mode 100644
index 0000000..f73d10a
--- /dev/null
+++ b/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java
@@ -0,0 +1,89 @@
+package com.mixi.common.utils.export;
+
+import com.alibaba.excel.metadata.CellData;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.util.StyleUtil;
+import com.alibaba.excel.write.handler.CellWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
+import com.alibaba.excel.write.metadata.style.WriteCellStyle;
+import org.apache.poi.ss.usermodel.*;
+
+import java.util.List;
+
+/**
+ * @author yanglei
+ * @date 2023/5/27 21:04
+ */
+public class ProductCellWriteHandler implements CellWriteHandler {
+ @Override
+ public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
+
+ }
+
+ @Override
+ public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
+
+ }
+
+ @Override
+ public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
+ //当前行的第i列
+ int i = cell.getColumnIndex();
+ int r = cell.getRowIndex();
+ // 根据单元格获取workbook
+ Sheet sheet = cell.getSheet();
+ sheet.setColumnWidth(i,20*256);
+ Workbook workbook = sheet.getWorkbook();
+ if (0 == r) {
+ // 单元格策略
+ WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
+ // 设置背景颜色白色
+ //contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
+ // 设置垂直居中为居中对齐
+ contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+ // 设置左右对齐为靠左对齐
+ contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+
+ // 设置单元格上下左右边框为细边框
+ contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
+
+ contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
+
+
+ CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);
+ cellStyle.setWrapText(true);
+ cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式
+ cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色
+ //设置当前行第i列的样式
+ cell.getRow().getCell(i).setCellStyle(cellStyle);
+ } else {
+ WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
+ // 设置垂直居中为居中对齐
+ contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+ contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
+ // 设置单元格上下左右边框为细边框
+ contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
+ contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
+
+ contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
+ contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
+ CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);
+ cellStyle.setWrapText(true);
+ cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式
+ cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色
+ //设置当前行第i列的样式
+ cell.getRow().getCell(i).setCellStyle(cellStyle);
+ }
+ }
+}
diff --git a/src/main/java/com/mixi/controller/AccountController.java b/src/main/java/com/mixi/controller/AccountController.java
new file mode 100644
index 0000000..db3d63d
--- /dev/null
+++ b/src/main/java/com/mixi/controller/AccountController.java
@@ -0,0 +1,78 @@
+package com.mixi.controller;
+
+import com.mixi.common.response.PageBaseResponse;
+import com.mixi.common.response.Response;
+import com.mixi.model.dto.*;
+import com.mixi.model.vo.AccountLoginVO;
+import com.mixi.model.vo.AccountVO;
+import com.mixi.service.AccountService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+@Api(tags = "账户")
+@Slf4j
+@RestController
+@RequestMapping("/api/account")
+public class AccountController {
+
+ @Resource
+ private AccountService accountService;
+
+ @ApiOperation(value = "用户分页列表")
+ @PostMapping("/queryUserPage")
+ public Response> queryUserPage(@Valid @RequestBody QueryAccountPageDTO query) {
+ return Response.success(accountService.queryUserPage(query));
+ }
+
+ @ApiOperation(value = "添加或编辑账号")
+ @PostMapping("/saveOrEdit")
+ public Response saveOrEdit(@Valid @RequestBody AccountEditDTO accountEditDTO) {
+ return Response.success(accountService.saveOrEdit(accountEditDTO));
+ }
+
+ @ApiOperation(value = "删除账户")
+ @PostMapping("/delete")
+ public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
+ return Response.success(accountService.delete(storeDeleteDTO));
+ }
+
+ @ApiOperation(value = "禁用/停用账户")
+ @PostMapping("/enable")
+ public Response enableAccount(@Valid @RequestBody AccountEnableDTO accountEnableDTO) {
+ return Response.success(accountService.enableAccount(accountEnableDTO));
+ }
+
+ @ApiOperation(value = "登入")
+ @PostMapping("/login")
+ public Response login(@Valid @RequestBody AccountLoginDTO accountDTO) {
+ return Response.success(accountService.login(accountDTO));
+ }
+
+ @ApiOperation(value = "忘记密码")
+ @PostMapping("/resetPwd")
+ public Response