24282 1 سال پیش
کامیت
e8b6ed153e
24فایلهای تغییر یافته به همراه1593 افزوده شده و 0 حذف شده
  1. 36 0
      .gitignore
  2. 30 0
      code-generation/pom.xml
  3. 19 0
      code-generation/src/main/java/com/sd/Generation.java
  4. 52 0
      pom.xml
  5. 29 0
      sd-business/pom.xml
  6. 84 0
      sd-business/src/main/java/com/sd/business/upload/ObsUploadService.java
  7. 95 0
      sd-business/src/main/java/com/sd/business/util/CodeEnum.java
  8. 42 0
      sd-framework/pom.xml
  9. 54 0
      sd-framework/src/main/java/com/sd/framework/aspect/DataSourceAspect.java
  10. 28 0
      sd-framework/src/main/java/com/sd/framework/controller/SdDictController.java
  11. 121 0
      sd-framework/src/main/java/com/sd/framework/util/Assert.java
  12. 21 0
      sd-framework/src/main/java/com/sd/framework/util/StreamUtil.java
  13. 167 0
      sd-framework/src/main/java/com/sd/framework/util/TemplateExcelUtil.java
  14. 35 0
      sd-framework/src/main/java/com/sd/framework/util/excel/listener/DataListener.java
  15. 56 0
      sd-framework/src/main/java/com/sd/framework/util/excel/listener/ImportListener.java
  16. 14 0
      sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelException.java
  17. 19 0
      sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelImporter.java
  18. 198 0
      sd-framework/src/main/java/com/sd/framework/util/excel/util/ExcelUtil.java
  19. 67 0
      sd-starter/pom.xml
  20. 27 0
      sd-starter/src/main/java/com/sd/SdApplication.java
  21. 62 0
      sd-starter/src/main/resources/application-dev.yml
  22. 106 0
      sd-starter/src/main/resources/application-prod.yml
  23. 66 0
      sd-starter/src/main/resources/application-test.yml
  24. 165 0
      sd-starter/src/main/resources/application.yml

+ 36 - 0
.gitignore

@@ -0,0 +1,36 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs
+hs_err_pid*
+
+.idea/.gitignore
+.idea/misc.xml
+.idea/modules.xml
+.idea/vcs.xml
+
+.idea
+app-log
+**/target
+**/libraries
+**/*.iml

+ 30 - 0
code-generation/pom.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sd</groupId>
+        <artifactId>sdhy_project</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>code-generation</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.fly</groupId>
+            <artifactId>fly-generator</artifactId>
+            <version>1.0.hx</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 19 - 0
code-generation/src/main/java/com/sd/Generation.java

@@ -0,0 +1,19 @@
+package com.sd;
+
+import fly.generator.GeneratorApplication;
+
+public class Generation {
+
+    public static void main(String[] args) {
+        GeneratorApplication.builder()
+                .url("jdbc:mysql://121.37.194.75:30102/sd_business?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true")
+                .username("root")
+                .password("5fWD*oa^nso@kmKa")
+                .port(9989)
+                .module("sd-business")
+                .parent("com.sd.business")
+                .superServiceClass("com.ruoyi.common.core.service.BaseService")
+                .build();
+    }
+
+}

+ 52 - 0
pom.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.sd</groupId>
+    <artifactId>sdhy_project</artifactId>
+    <version>1.0</version>
+
+    <packaging>pom</packaging>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <sd.version>1.0</sd.version>
+        <base.version>1.0.2</base.version>
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.7.6</version>
+    </parent>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <dependency>
+                <groupId>com.fjhx</groupId>
+                <artifactId>hx-base</artifactId>
+                <version>${base.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.sd</groupId>
+                <artifactId>sd-framework</artifactId>
+                <version>${sd.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.sd</groupId>
+                <artifactId>sd-business</artifactId>
+                <version>${sd.version}</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+</project>

+ 29 - 0
sd-business/pom.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sd</groupId>
+        <artifactId>sdhy_project</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>sd-business</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.sd</groupId>
+            <artifactId>sd-framework</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 84 - 0
sd-business/src/main/java/com/sd/business/upload/ObsUploadService.java

@@ -0,0 +1,84 @@
+package com.sd.business.upload;
+
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.obs.services.ObsClient;
+import com.ruoyi.common.exception.ServiceException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayInputStream;
+import java.util.Date;
+import java.util.StringJoiner;
+
+/**
+ * 文件上传服务
+ */
+@Component
+public class ObsUploadService {
+    @Value("${obs.ak}")
+    private String ak;
+
+    @Value("${obs.sk}")
+    private String sk;
+
+    @Value("${obs.endPoint}")
+    private String endPoint;
+
+    @Value("${obs.url}")
+    private String url;
+
+    @Value("${obs.bucketName}")
+    private String bucketName;
+
+    @Value("${spring.profiles.active}")
+    private String active;
+
+    @Value("${ruoyi.name}")
+    private String name;
+
+    public String uploadFileByte(ByteArrayInputStream bis, String fileName) {
+        if (fileName.length() > 100) {
+            throw new ServiceException("文件名过长,请缩短后重试!!!");
+        }
+
+        // 文件后缀名
+        String suffix = FileUtil.getSuffix(fileName);
+
+        // 文件路径
+        String objectKey = new StringJoiner("/")
+                .add(name)
+                .add(active)
+                .add(DateUtil.format(new Date(), "yyyy/MM/dd"))
+                .add(IdUtil.fastSimpleUUID() + (ObjectUtil.isEmpty(suffix) ? "" : "." + suffix))
+                .toString();
+
+        ObsClient obsClient = null;
+
+        try {
+            // 获取oss链接客户端
+            obsClient = getObsClient();
+            // 上传
+            obsClient.putObject(bucketName, objectKey, bis);
+        } catch (Exception e) {
+            throw new ServiceException("上传失败");
+        } finally {
+            IoUtil.close(obsClient);
+            IoUtil.close(bis);
+        }
+
+        return objectKey;
+    }
+
+
+    /**
+     * 获取oss链接客户端
+     */
+    private ObsClient getObsClient() {
+        return new ObsClient(ak, sk, endPoint);
+    }
+}

+ 95 - 0
sd-business/src/main/java/com/sd/business/util/CodeEnum.java

@@ -0,0 +1,95 @@
+package com.sd.business.util;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.exception.ServiceException;
+import lombok.Getter;
+
+import java.util.Date;
+import java.util.Map;
+
+@Getter
+public enum CodeEnum {
+
+    ;
+
+    // 编码前缀
+    private final String prefix;
+    // 编码加日期规则
+    private final String dateFormat;
+    // 长度
+    private final Integer length;
+    // 编码字段名
+    private final String codeFieldName;
+    // service
+    private final IService<?> service;
+
+    CodeEnum(String prefix, String dateFormat, String codeFieldName, Integer length, Class<? extends IService<?>> serviceCls) {
+        this.prefix = prefix;
+        this.dateFormat = dateFormat;
+        this.length = length;
+        this.codeFieldName = codeFieldName;
+        this.service = SpringUtil.getBean(serviceCls);
+    }
+
+    /**
+     * 不够位数的在前面补0,保留num的长度位数字
+     */
+    private static String autoGenericCode(int length, Integer codeNum) {
+        return String.format("%0" + length + "d", codeNum + 1);
+    }
+
+    // /**
+    //  * 获取键值对
+    //  */
+    // public String getCode(String code) {
+    //     if (ObjectUtil.isNotEmpty(code)) {
+    //         Long count = service.query().eq(codeFieldName, code).count();
+    //         if (count != 0) {
+    //             throw new ServiceException("编码已存在");
+    //         }
+    //         return code;
+    //     } else {
+    //         return getCode();
+    //     }
+    // }
+
+    /**
+     * 获取键值对
+     */
+    public String getCode() {
+        String itemPrefix;
+
+        if (ObjectUtil.isNotEmpty(dateFormat)) {
+            Date date = new Date();
+            String format = DateUtil.format(date, dateFormat);
+            itemPrefix = prefix + format;
+        } else {
+            itemPrefix = prefix;
+        }
+
+        Object obj = service.query()
+                .likeRight(codeFieldName, itemPrefix)
+                .orderByDesc(codeFieldName)
+                .last("limit 1")
+                .one();
+
+        if (obj == null) {
+            return itemPrefix + autoGenericCode(length, 0);
+        }
+
+        Map<String, Object> map = Convert.toMap(String.class, Object.class, obj);
+        String code = Convert.toStr(map.get(CharSequenceUtil.toCamelCase(codeFieldName)));
+        Integer codeNum = Convert.toInt(code.substring(itemPrefix.length()));
+        if (ObjectUtil.isEmpty(codeNum)) {
+            throw new ServiceException("自定义编码与系统编码生成规则冲突,暂时无法生成编码,请联系管理员");
+        }
+
+        return itemPrefix + autoGenericCode(length, codeNum);
+    }
+
+}

+ 42 - 0
sd-framework/pom.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sd</groupId>
+        <artifactId>sdhy_project</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>sd-framework</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.fjhx</groupId>
+            <artifactId>hx-base</artifactId>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.14</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>3.3.2</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 54 - 0
sd-framework/src/main/java/com/sd/framework/aspect/DataSourceAspect.java

@@ -0,0 +1,54 @@
+package com.sd.framework.aspect;
+
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+@Aspect
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class DataSourceAspect {
+
+    @Pointcut("execution (* com.*.*.service.*.*.*(..)) || execution (* com.*.*.service.*.*(..)) || execution(* com.*.*.flow.*.*(..))")
+    public void pointcut() {
+
+    }
+
+    @Around(value = "pointcut()")
+    public Object before(ProceedingJoinPoint point) throws Throwable {
+        Object target = point.getTarget();
+        String name = target.getClass().getName();
+        String moduleName = name.split("\\.")[1];
+
+        String peek = DynamicDataSourceContextHolder.peek();
+        if ("sd".equals(moduleName)) {
+            if ("business".equals(peek)) {
+                return point.proceed();
+            } else {
+                try {
+                    DynamicDataSourceContextHolder.push("business");
+                    return point.proceed();
+                } finally {
+                    DynamicDataSourceContextHolder.poll();
+                }
+            }
+        } else {
+            if ("base".equals(peek)) {
+                return point.proceed();
+            } else {
+                try {
+                    DynamicDataSourceContextHolder.push("base");
+                    return point.proceed();
+                } finally {
+                    DynamicDataSourceContextHolder.poll();
+                }
+            }
+        }
+    }
+
+}

+ 28 - 0
sd-framework/src/main/java/com/sd/framework/controller/SdDictController.java

@@ -0,0 +1,28 @@
+package com.sd.framework.controller;
+
+import com.fjhx.tenant.entity.dict.po.DictCommonData;
+import com.fjhx.tenant.service.dict.DictCommonDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+public class SdDictController {
+
+    @Autowired
+    private DictCommonDataService dictCommonDataService;
+
+    /**
+     * 字典对象
+     */
+    @PostMapping("/allDictMap")
+    public Map<String, List<DictCommonData>> allDictMap() {
+        return dictCommonDataService.list(q -> q.orderByAsc(DictCommonData::getSort))
+                .stream().collect(Collectors.groupingBy(DictCommonData::getDictCode));
+    }
+
+}

+ 121 - 0
sd-framework/src/main/java/com/sd/framework/util/Assert.java

@@ -0,0 +1,121 @@
+package com.sd.framework.util;
+
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.ruoyi.common.exception.ServiceException;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+
+public class Assert {
+
+    /**
+     * 断言为空
+     */
+    public static void empty(Object obj, String errStr) {
+        if (ObjectUtil.isNotEmpty(obj)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言不为空
+     */
+    public static void notEmpty(Object obj, String errStr) {
+        if (ObjectUtil.isEmpty(obj)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言不为空
+     */
+    public static void notNull(Object obj, String errStr) {
+        if (ObjectUtil.isNull(obj)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言不为空
+     */
+    public static void notBlank(String str, String errStr) {
+        if (StrUtil.isBlank(str)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言为0
+     */
+    public static void eqZero(Integer integer, String errStr) {
+        if (!Objects.equals(integer, 0)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言为0
+     */
+    public static void eqZero(Long along, String errStr) {
+        if (!Objects.equals(along, 0L)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言为1
+     */
+    public static void eqOne(Integer integer, String errStr) {
+        if (!Objects.equals(integer, 1)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言为1
+     */
+    public static void eqOne(Long along, String errStr) {
+        if (!Objects.equals(along, 1L)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言为真
+     */
+    public static void eqTrue(Boolean flag, String errStr) {
+        if (flag == null || flag.equals(false)) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言大于0
+     */
+    public static void gtZero(BigDecimal bigDecimal, String errStr) {
+        if (bigDecimal == null || BigDecimal.ZERO.compareTo(bigDecimal) > 0) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言大于等于0
+     */
+    public static void geZero(BigDecimal bigDecimal, String errStr) {
+        if (bigDecimal == null || BigDecimal.ZERO.compareTo(bigDecimal) >= 0) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+    /**
+     * 断言大于0
+     */
+    public static void gtZero(Integer integer, String errStr) {
+        if (integer == null || integer <= 0) {
+            throw new ServiceException(errStr);
+        }
+    }
+
+}

+ 21 - 0
sd-framework/src/main/java/com/sd/framework/util/StreamUtil.java

@@ -0,0 +1,21 @@
+package com.sd.framework.util;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+public class StreamUtil {
+
+    /**
+     * 数组某个字段值相加
+     *
+     * @param list   数组
+     * @param mapper 字段
+     * @return 相加结果
+     */
+    public static <T> BigDecimal bigDecimalAdd(List<T> list, Function<T, BigDecimal> mapper) {
+        return list.stream().map(mapper).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
+}

+ 167 - 0
sd-framework/src/main/java/com/sd/framework/util/TemplateExcelUtil.java

@@ -0,0 +1,167 @@
+package com.sd.framework.util;
+
+import cn.hutool.core.io.IoUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.handler.WriteHandler;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import com.alibaba.excel.write.metadata.fill.FillConfig;
+import com.ruoyi.common.exception.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.ClassPathResource;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+public class TemplateExcelUtil {
+
+    /**
+     * 自定义模板excel写入浏览器
+     *
+     * @param templateName 模板名称
+     * @param fileName     文件名称
+     * @param response     response
+     * @param data         模板字段替换数据
+     */
+    public static void writeBrowser(String templateName, String fileName, HttpServletResponse response, Object... data) {
+
+        ExcelWriter excelWriter = null;
+        InputStream is = null;
+        ServletOutputStream os = null;
+        try {
+            String fileNameCn = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
+
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+            response.setHeader("Content-disposition", "attachment;filename=" + fileNameCn + ".xlsx");
+
+            ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + templateName);
+            is = classPathResource.getInputStream();
+            os = response.getOutputStream();
+
+            excelWriter = EasyExcel.write(os).withTemplate(is).build();
+            WriteSheet writeSheet = EasyExcel.writerSheet().build();
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+
+            for (Object item : data) {
+                excelWriter.fill(item, fillConfig, writeSheet);
+            }
+
+        } catch (IOException e) {
+            log.error("excel导出失败", e);
+            throw new ServiceException("excel导出失败");
+        } finally {
+            if (excelWriter != null) {
+                excelWriter.finish();
+            }
+            IoUtil.close(excelWriter);
+            IoUtil.close(is);
+            IoUtil.close(os);
+        }
+
+    }
+    /**
+     * 自定义模板excel写入浏览器
+     *
+     * @param templateName 模板名称
+     * @param sheetNum     写入sheet的数量
+     * @param fileName     文件名称
+     * @param response     response
+     * @param data         模板字段替换数据
+     */
+    public static void writeBrowserMultiSheet(String templateName, int sheetNum, String fileName, HttpServletResponse response, Object... data) {
+
+        ExcelWriter excelWriter = null;
+        InputStream is = null;
+        ServletOutputStream os = null;
+        try {
+            String fileNameCn = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
+
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+            response.setHeader("Content-disposition", "attachment;filename=" + fileNameCn + ".xlsx");
+
+            ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + templateName);
+            is = classPathResource.getInputStream();
+            os = response.getOutputStream();
+
+            excelWriter = EasyExcel.write(os).withTemplate(is).build();
+            List<WriteSheet> writeSheetList = new ArrayList<>();
+            for (int i = 0; i < sheetNum; i++) {
+                writeSheetList.add(EasyExcel.writerSheet(i).build());
+            }
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+
+            for (int i = 0; i < writeSheetList.size(); i++) {
+                excelWriter.fill(data[i], fillConfig, writeSheetList.get(i));
+            }
+
+        } catch (IOException e) {
+            log.error("excel导出失败", e);
+            throw new ServiceException("excel导出失败");
+        } finally {
+            if (excelWriter != null) {
+                excelWriter.finish();
+            }
+            IoUtil.close(excelWriter);
+            IoUtil.close(is);
+            IoUtil.close(os);
+        }
+
+    }
+
+    /**
+     * 自定义模板excel写入浏览器
+     *
+     * @param templateName 模板名称
+     * @param fileName     文件名称
+     * @param writeHandler 合并策略
+     * @param response     response
+     * @param data         模板字段替换数据
+     */
+    public static void writeBrowser(String templateName, String fileName, WriteHandler writeHandler, HttpServletResponse response, Object... data) {
+
+        ExcelWriter excelWriter = null;
+        InputStream is = null;
+        ServletOutputStream os = null;
+        try {
+            String fileNameCn = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
+
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+            response.setHeader("Content-disposition", "attachment;filename=" + fileNameCn + ".xlsx");
+
+            ClassPathResource classPathResource = new ClassPathResource("template" + File.separator + templateName);
+            is = classPathResource.getInputStream();
+            os = response.getOutputStream();
+
+            excelWriter = EasyExcel.write(os).withTemplate(is).build();
+            WriteSheet writeSheet = EasyExcel.writerSheet().registerWriteHandler(writeHandler).build();
+            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
+
+            for (Object item : data) {
+                excelWriter.fill(item, fillConfig, writeSheet);
+            }
+
+        } catch (IOException e) {
+            log.error("excel导出失败", e);
+            throw new ServiceException("excel导出失败");
+        } finally {
+            IoUtil.close(os);
+            IoUtil.close(is);
+            if (excelWriter != null) {
+                excelWriter.finish();
+            }
+            IoUtil.close(excelWriter);
+        }
+
+    }
+
+}

+ 35 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/listener/DataListener.java

@@ -0,0 +1,35 @@
+package com.sd.framework.util.excel.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel监听器
+ *
+ * @author Chill
+ */
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class DataListener<T> extends AnalysisEventListener<T> {
+
+    /**
+     * 缓存的数据列表
+     */
+    private final List<T> dataList = new ArrayList<>();
+
+    @Override
+    public void invoke(T data, AnalysisContext analysisContext) {
+        dataList.add(data);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+
+    }
+
+}

+ 56 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/listener/ImportListener.java

@@ -0,0 +1,56 @@
+package com.sd.framework.util.excel.listener;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.sd.framework.util.excel.support.ExcelImporter;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Excel监听器
+ *
+ * @author Chill
+ */
+@Data
+@RequiredArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ImportListener<T> extends AnalysisEventListener<T> {
+
+    /**
+     * 数据导入类
+     */
+    private final ExcelImporter<T> importer;
+    /**
+     * 默认每隔3000条存储数据库
+     */
+    private int batchCount = 3000;
+    /**
+     * 缓存的数据列表
+     */
+    private List<T> list = new ArrayList<>();
+
+    @Override
+    public void invoke(T data, AnalysisContext analysisContext) {
+        list.add(data);
+        // 达到BATCH_COUNT,则调用importer方法入库,防止数据几万条数据在内存,容易OOM
+        if (list.size() >= batchCount) {
+            // 调用importer方法
+            importer.save(list);
+            // 存储完成清理list
+            list.clear();
+        }
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+        // 调用importer方法
+        importer.save(list);
+        // 存储完成清理list
+        list.clear();
+    }
+
+}

+ 14 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelException.java

@@ -0,0 +1,14 @@
+package com.sd.framework.util.excel.support;
+
+/**
+ * Excel异常处理类
+ *
+ * @author Chill
+ */
+public class ExcelException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public ExcelException(String message) {
+        super(message);
+    }
+}

+ 19 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/support/ExcelImporter.java

@@ -0,0 +1,19 @@
+package com.sd.framework.util.excel.support;
+
+import java.util.List;
+
+/**
+ * Excel统一导入接口
+ *
+ * @author Chill
+ */
+public interface ExcelImporter<T> {
+
+    /**
+     * 导入数据逻辑
+     *
+     * @param data 数据集合
+     */
+    void save(List<T> data);
+
+}

+ 198 - 0
sd-framework/src/main/java/com/sd/framework/util/excel/util/ExcelUtil.java

@@ -0,0 +1,198 @@
+package com.sd.framework.util.excel.util;
+
+import cn.hutool.core.convert.Convert;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.read.builder.ExcelReaderBuilder;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.util.DateUtils;
+import com.alibaba.excel.write.handler.WriteHandler;
+import com.sd.framework.util.excel.listener.DataListener;
+import com.sd.framework.util.excel.listener.ImportListener;
+import com.sd.framework.util.excel.support.ExcelException;
+import com.sd.framework.util.excel.support.ExcelImporter;
+import lombok.SneakyThrows;
+import org.apache.commons.codec.Charsets;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Excel工具类
+ *
+ * @author Chill
+ * @apiNote { https://www.yuque.com/easyexcel/doc/easyexcel }
+ */
+public class ExcelUtil {
+
+    /**
+     * 读取excel的所有sheet数据
+     *
+     * @param excel excel文件
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, Class<T> clazz) {
+        DataListener<T> dataListener = new DataListener<>();
+        ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
+        builder.doReadAll();
+        return dataListener.getDataList();
+    }
+
+    /**
+     * 读取excel的指定sheet数据
+     *
+     * @param excel   excel文件
+     * @param sheetNo sheet序号(从0开始)
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, int sheetNo, Class<T> clazz) {
+        return read(excel, sheetNo, 1, clazz);
+    }
+
+    /**
+     * 读取excel的指定sheet数据
+     *
+     * @param excel         excel文件
+     * @param sheetNo       sheet序号(从0开始)
+     * @param headRowNumber 表头行数
+     * @return List<Object>
+     */
+    public static <T> List<T> read(MultipartFile excel, int sheetNo, int headRowNumber, Class<T> clazz) {
+        DataListener<T> dataListener = new DataListener<>();
+        ExcelReaderBuilder builder = getReaderBuilder(excel, dataListener, clazz);
+        builder.sheet(sheetNo).headRowNumber(headRowNumber).doRead();
+        return dataListener.getDataList();
+    }
+
+    /**
+     * 读取并导入数据
+     *
+     * @param excel    excel文件
+     * @param importer 导入逻辑类
+     * @param <T>      泛型
+     */
+    public static <T> void save(MultipartFile excel, ExcelImporter<T> importer, Class<T> clazz) {
+        ImportListener<T> importListener = new ImportListener<>(importer);
+        ExcelReaderBuilder builder = getReaderBuilder(excel, importListener, clazz);
+        builder.doReadAll();
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response 响应类
+     * @param dataList 数据列表
+     * @param clazz    class类
+     * @param <T>      泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, List<T> dataList, Class<T> clazz) {
+        export(response, DateUtils.format(new Date(), DateUtils.DATE_FORMAT_14), "导出数据", dataList, clazz);
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response  响应类
+     * @param fileName  文件名
+     * @param sheetName sheet名
+     * @param dataList  数据列表
+     * @param clazz     class类
+     * @param <T>       泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, Class<T> clazz) {
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding(Charsets.UTF_8.name());
+        fileName = URLEncoder.encode(fileName, Charsets.UTF_8.name());
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+        EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(dataList);
+    }
+
+    /**
+     * 导出excel
+     *
+     * @param response     响应类
+     * @param fileName     文件名
+     * @param sheetName    sheet名
+     * @param dataList     数据列表
+     * @param clazz        class类
+     * @param writeHandler 自定义处理器
+     * @param <T>          泛型
+     */
+    @SneakyThrows
+    public static <T> void export(HttpServletResponse response, String fileName, String sheetName, List<T> dataList, WriteHandler writeHandler, Class<T> clazz) {
+        response.setContentType("application/vnd.ms-excel");
+        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
+        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+        EasyExcel.write(response.getOutputStream(), clazz).registerWriteHandler(writeHandler).sheet(sheetName).doWrite(dataList);
+    }
+
+    /**
+     * 获取构建类
+     *
+     * @param excel        excel文件
+     * @param readListener excel监听类
+     * @return ExcelReaderBuilder
+     */
+    public static <T> ExcelReaderBuilder getReaderBuilder(MultipartFile excel, ReadListener<T> readListener, Class<T> clazz) {
+        String filename = excel.getOriginalFilename();
+        if (ObjectUtils.isEmpty(filename)) {
+            throw new ExcelException("请上传文件!");
+        }
+        if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
+            throw new ExcelException("请上传正确的excel文件!");
+        }
+        InputStream inputStream;
+        try {
+            inputStream = new BufferedInputStream(excel.getInputStream());
+            return EasyExcel.read(inputStream, clazz, readListener);
+        } catch (IOException e) {
+            throw new ExcelException("读取文件失败!");
+        }
+    }
+
+    /**
+     * 获取修改ExcelProperty的value值的class,用于导出
+     * @param t 类对象
+     * @param keys key为修改的字段和value为它对应表头值
+     * @return
+     */
+    public static <T> Class<T> getClassNew(T t, Map<String, String> keys) {
+        if(t == null) {
+            return null;
+        }
+        try{
+            for(String key: keys.keySet()) {
+                Field value = t.getClass().getDeclaredField(key);
+                value.setAccessible(true);
+                ExcelProperty property = value.getAnnotation(ExcelProperty.class);
+                InvocationHandler invocationHandler = Proxy.getInvocationHandler(property);
+                Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
+                memberValues.setAccessible(true);
+                Map<String, Object> values = Convert.toMap(String.class, Object.class, memberValues.get(invocationHandler));
+                values.put("value", new String[]{keys.get(key)});
+                memberValues.set(invocationHandler, values);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return (Class<T>) t.getClass();
+    }
+
+}

+ 67 - 0
sd-starter/pom.xml

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.sd</groupId>
+        <artifactId>sdhy_project</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>sd-starter</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.sd</groupId>
+            <artifactId>sd-framework</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sd</groupId>
+            <artifactId>sd-business</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 27 - 0
sd-starter/src/main/java/com/sd/SdApplication.java

@@ -0,0 +1,27 @@
+package com.sd;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Slf4j
+@EnableScheduling
+@EnableTransactionManagement
+@SpringBootApplication(scanBasePackages = {"com.ruoyi.**", "com.fjhx.**", "com.sd.**"})
+@MapperScan("com.sd.**.mapper")
+public class SdApplication {
+
+    public static void main(String[] args) {
+
+        SpringApplication.run(SdApplication.class, args);
+
+        log.info("\r\n==================================================================\r\n"
+                + ">>>>> " + SdApplication.class.getSimpleName() + " is success!\r\n"
+                + "==================================================================\r\n");
+
+    }
+
+}

+ 62 - 0
sd-starter/src/main/resources/application-dev.yml

@@ -0,0 +1,62 @@
+# 数据源配置
+spring:
+  datasource:
+    dynamic:
+      strict: true
+      primary: base
+      datasource:
+        base:
+          url: jdbc:mysql://121.37.194.75:30102/sd_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: root
+          password: 5fWD*oa^nso@kmKa
+        business:
+          url: jdbc:mysql://121.37.194.75:30102/sd_business?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: root
+          password: 5fWD*oa^nso@kmKa
+
+  rabbitmq:
+    port: 2762
+    host: 139.9.184.42
+    username: fjhx_sd_rabbit_mq
+    password: da3aKs*Sa_s13D*das
+    virtual-host: test
+    #这个配置是保证提供者确保消息推送到交换机中,不管成不成功,都会回调
+    publisher-confirm-type: correlated
+    #保证交换机能把消息推送到队列中
+    publisher-returns: true
+    #这个配置是保证消费者会消费消息,手动确认
+    listener:
+      simple:
+        acknowledge-mode: manual
+
+  # redis 配置
+  redis:
+    # 地址
+    host: 121.37.194.75
+    # 端口,默认为6379
+    port: 30103
+    # 数据库索引
+    database: 3
+    # 密码
+    password: Fjhx@pwd123
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+
+# token配置
+token:
+  # 令牌自定义标识
+  header: Authorization
+  # 令牌密钥
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 令牌有效期(默认30分钟)
+  expireTime: 2880

+ 106 - 0
sd-starter/src/main/resources/application-prod.yml

@@ -0,0 +1,106 @@
+# 数据源配置
+spring:
+  datasource:
+    dynamic:
+      strict: true
+      primary: base
+      datasource:
+        base:
+          url: jdbc:mysql://192.168.0.238:23063/sd_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: sd_prod
+          password: lG0-nX8#rJ4#jT5
+        business:
+          url: jdbc:mysql://192.168.0.238:23063/sd_business?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: sd_prod
+          password: lG0-nX8#rJ4#jT5
+
+  rabbitmq:
+    port: 2762
+    host: 127.0.0.1
+    username: fjhx_sd_rabbit_mq
+    password: da3aKs*Sa_s13D*das
+    virtual-host: prod
+    #这个配置是保证提供者确保消息推送到交换机中,不管成不成功,都会回调
+    publisher-confirm-type: correlated
+    #保证交换机能把消息推送到队列中
+    publisher-returns: true
+    #这个配置是保证消费者会消费消息,手动确认
+    listener:
+      simple:
+        acknowledge-mode: manual
+
+  # redis 配置
+  redis:
+    # 地址
+    host: 127.0.0.1
+    # 端口,默认为6379
+    port: 29736
+    # 数据库索引
+    database: 3
+    # 密码
+    password: d~as&6x2dS2Fsv_sd-24
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+
+
+## 数据源配置
+#spring:
+#  datasource:
+#    dynamic:
+#      strict: true
+#      primary: base
+#      datasource:
+#        base:
+#          url: jdbc:mysql://110.41.2.116:23063/sd_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+#          username: sd_prod
+#          password: lG0-nX8#rJ4#jT5
+#        business:
+#          url: jdbc:mysql://110.41.2.116:23063/sd_business?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+#          username: sd_prod
+#          password: lG0-nX8#rJ4#jT5
+#
+#  # redis 配置
+#  redis:
+#    # 地址
+#    host: 121.37.194.75
+#    # 端口,默认为6379
+#    port: 30103
+#    # 数据库索引
+#    database: 3
+#    # 密码
+#    password: Fjhx@pwd123
+#    # 连接超时时间
+#    timeout: 10s
+#    lettuce:
+#      pool:
+#        # 连接池中的最小空闲连接
+#        min-idle: 0
+#        # 连接池中的最大空闲连接
+#        max-idle: 8
+#        # 连接池的最大数据库连接数
+#        max-active: 8
+#        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+#        max-wait: -1ms
+
+server:
+  servlet:
+    context-path: /prod-api
+
+# token配置
+token:
+  # 令牌自定义标识
+  header: Authorization
+  # 令牌密钥
+  secret: daskj@dsadsadj782asdasIUD4HSIb123UIS
+  # 令牌有效期(默认30分钟)
+  expireTime: 360

+ 66 - 0
sd-starter/src/main/resources/application-test.yml

@@ -0,0 +1,66 @@
+# 数据源配置
+spring:
+  datasource:
+    dynamic:
+      strict: true
+      primary: base
+      datasource:
+        base:
+          url: jdbc:mysql://127.0.0.1:30102/sd_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: root
+          password: 5fWD*oa^nso@kmKa
+        business:
+          url: jdbc:mysql://127.0.0.1:30102/sd_business?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+          username: root
+          password: 5fWD*oa^nso@kmKa
+
+  rabbitmq:
+    port: 2762
+    host: 139.9.184.42
+    username: fjhx_sd_rabbit_mq
+    password: da3aKs*Sa_s13D*das
+    virtual-host: test
+    #这个配置是保证提供者确保消息推送到交换机中,不管成不成功,都会回调
+    publisher-confirm-type: correlated
+    #保证交换机能把消息推送到队列中
+    publisher-returns: true
+    #这个配置是保证消费者会消费消息,手动确认
+    listener:
+      simple:
+        acknowledge-mode: manual
+
+  # redis 配置
+  redis:
+    # 地址
+    host: 127.0.0.1
+    # 端口,默认为6379
+    port: 30103
+    # 数据库索引
+    database: 3
+    # 密码
+    password: Fjhx@pwd123
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+
+server:
+  servlet:
+    context-path: /test-api
+
+# token配置
+token:
+  # 令牌自定义标识
+  header: Authorization
+  # 令牌密钥
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 令牌有效期(默认30分钟)
+  expireTime: 2880

+ 165 - 0
sd-starter/src/main/resources/application.yml

@@ -0,0 +1,165 @@
+# 项目相关配置
+ruoyi:
+  # 名称
+  name: sdhy
+  # 版本
+  version: 3.8.5
+  # 版权年份
+  copyrightYear: 2023
+  # 实例演示开关
+  demoEnabled: true
+  # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
+  profile: D:/ruoyi/uploadPath
+  # 获取ip地址开关
+  addressEnabled: false
+  # 验证码类型 math 数组计算 char 字符验证
+  captchaType: math
+
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 7777
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # 连接数满后的排队数,默认为100
+    accept-count: 1000
+    threads:
+      # tomcat最大线程数,默认为200
+      max: 800
+      # Tomcat启动初始化的线程数,默认值10
+      min-spare: 100
+
+# 日志配置
+logging:
+  level:
+    com.ruoyi: info
+    com.fjhx: info
+    org.springframework: warn
+
+# 用户配置
+user:
+  password:
+    # 密码最大错误次数
+    maxRetryCount: 5
+    # 密码锁定时间(默认10分钟)
+    lockTime: 10
+
+# Spring配置
+spring:
+  mvc:
+    path-match:
+      matching-strategy: ant_path_matcher
+  # 资源信息
+  messages:
+    # 国际化资源文件路径
+    basename: i18n/messages
+  profiles:
+    active: dev
+  # 文件上传
+  servlet:
+    multipart:
+      # 单个文件大小
+      max-file-size: 10MB
+      # 设置总上传的文件大小
+      max-request-size: 20MB
+  main:
+    allow-circular-references: true
+
+  autoconfigure:
+    # 排除 Druid 自动配置
+    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
+
+  datasource:
+    # 指定使用 Druid 数据源
+    type: com.alibaba.druid.pool.DruidDataSource
+
+    dynamic:
+      druid:
+        # 初始连接数
+        initialSize: 3
+        # 最小连接池数量
+        minIdle: 10
+        # 最大连接池数量
+        maxActive: 100
+        # 配置获取连接等待超时的时间
+        maxWait: 60000
+        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+        timeBetweenEvictionRunsMillis: 60000
+        # 配置一个连接在池中最小生存的时间,单位是毫秒
+        minEvictableIdleTimeMillis: 300000
+        # 配置一个连接在池中最大生存的时间,单位是毫秒
+        maxEvictableIdleTimeMillis: 900000
+        validationQueryTimeout: 10000
+        # 配置检测连接是否有效
+        validationQuery: SELECT 1
+        testWhileIdle: true
+        testOnBorrow: false
+        testOnReturn: false
+        poolPreparedStatements: true
+        maxPoolPreparedStatementPerConnectionSize: 20
+
+    druid:
+      webStatFilter:
+        enabled: true
+        exclusions:
+          - "*.js"
+          - "/druid/*"
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        urlPattern: /druid/*
+        # 控制台管理用户名和密码
+        loginUsername: superAdmin
+        loginPassword: 123456
+      filter:
+        # 配置StatFilter (SQL监控配置)
+        stat:
+          enabled: true # 开启 SQL 监控
+          logSlowSql: true  # 记录慢查询 SQL
+          slowSqlMillis: 1000 # 多长时间算慢查询
+          mergeSql: true # 条件参数化作为一条sql统计
+
+        # 配置WallFilter (防火墙配置)
+        wall:
+          enabled: true # 开启防火墙
+          config:
+            dropTableAllow: true # 允许删表操作
+            updateAllow: true # 允许更新操作
+            insertAllow: true # 允许插入操作
+            deleteAllow: true # 允许删除操作
+            multiStatementAllow: true # 支持一次执行多条sql
+
+# MyBatis Plus配置
+mybatis-plus:
+  # 搜索指定包别名
+  typeAliasesPackage: com.ruoyi.**.domain,com.sd.**.entity.po,com.fjhx.**.entity.po
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
+  global-config:
+    banner: false
+
+# PageHelper分页插件
+page-helper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# 防止XSS攻击
+xss:
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes: /system/notice
+  # 匹配链接
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
+obs:
+  ak: 9HNBVBHO7F3GLUCGTK5C
+  sk: ZowLEoMJrICA9tOyln0yWVm0xGSiupe0gnbsZimk
+  endPoint: obs.cn-south-1.myhuaweicloud.com
+  url: https://os.winfaster.cn/
+  bucketName: winfaster