Commit 97c98e6f by zhangxingmin

Initial commit

parents
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/../../../../../../:\soft\ideaproject\v2\yd-scrm-cloud\.idea/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="yd-gateway" />
<module name="yd-fileservice" />
<module name="yd-order-service" />
<module name="yd-scrm-api" />
<module name="yd-sms" />
<module name="yd-sfp-service" />
<module name="yd-common" />
<module name="yd-cffp-service" />
<module name="yd-sfp-api" />
<module name="yd-cffp-api" />
<module name="yd-email" />
<module name="yd-auth" />
<module name="yd-order-api" />
<module name="yd-pay-api" />
<module name="yd-scheduler" />
<module name="yd-scrm-service" />
<module name="yd-feign" />
<module name="yd-pay-service" />
<module name="yd-framework" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="yd-ai" target="1.8" />
<module name="yd-user-api" target="1.5" />
<module name="yd-user-service" target="1.5" />
<module name="yd-wecom" target="1.8" />
<module name="yd-wx-api" target="1.8" />
</bytecodeTargetLevel>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="public" />
<option name="name" value="aliyun nexus" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo1.maven.org/maven2/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/yd-scrm-service/pom.xml" />
</list>
</option>
<option name="ignoredFiles">
<set>
<option value="$PROJECT_DIR$/yd-ai/pom.xml" />
<option value="$PROJECT_DIR$/yd-user-api/pom.xml" />
<option value="$PROJECT_DIR$/yd-user-service/pom.xml" />
<option value="$PROJECT_DIR$/yd-wecom/pom.xml" />
</set>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
spring:
profiles:
active: test
# active: '@spring.profiles.active@'
---
spring:
profiles: dev
main:
allow-bean-definition-overriding: true
allow-circular-references: true
cloud:
nacos:
# 配置中心
config:
# 命名空间id(此处不用public,因public初始化的空间, id为空) 4e237601-cea8-414d-b7b9-d7adc8cbcf95
namespace: 22f9d61e-9011-4d45-88cb-24f9857e3eec
# nacos的ip地址和端口 120.79.64.17:10848
server-addr: 127.0.0.1:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension: yml
config-retry-time: 300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]:
dataId: linkwe-common.yml
refresh: true
# 发布到注册中心 (如果没有使用可以不配)
discovery:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace: ${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr: ${spring.cloud.nacos.config.server-addr}
---
spring:
profiles: test
main:
allow-bean-definition-overriding: true
allow-circular-references: true
cloud:
nacos:
# 配置中心
config:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace: d2446fdc-2683-4c82-aa86-61242c61b5cd
# nacos的ip地址和端口
server-addr: 139.224.145.34:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension: yml
config-retry-time: 300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]:
dataId: linkwe-common.yml
refresh: true
# 发布到注册中心 (如果没有使用可以不配)
discovery:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace: ${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr: ${spring.cloud.nacos.config.server-addr}
---
spring:
profiles: prod
main:
allow-bean-definition-overriding: true
allow-circular-references: true
cloud:
nacos:
# 配置中心
config:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace: ewscrm
# nacos的ip地址和端口
server-addr: 127.0.0.1:8848
# 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
file-extension: yml
config-retry-time: 300000
# 共享配置, 可以把公共配置放在同个命名空间下,然后创建一个 common.yml 文件 ,里面可以放共用的配置
shared-configs[0]:
dataId: linkwe-common.yml
refresh: true
# 发布到注册中心 (如果没有使用可以不配)
discovery:
# 命名空间id(此处不用public,因public初始化的空间, id为空)
namespace: ${spring.cloud.nacos.config.namespace}
# nacos的ip地址和端口
server-addr: ${spring.cloud.nacos.config.server-addr}
\ No newline at end of file
<?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.yd</groupId>
<artifactId>yd-cloud</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>yd-cloud</name>
<!-- 版本声明 -->
<properties>
<spring-cloud.version>2021.0.1</spring-cloud.version>
<spring-cloud-gateway.version>3.0.7</spring-cloud-gateway.version>
<spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version>
<springboot.version>2.6.6</springboot.version>
<druid.version>1.2.8</druid.version>
<pagehelper.boot.version>1.4.2</pagehelper.boot.version>
<swagger.version>2.9.2</swagger.version>
<swagger-annotations.version>1.5.21</swagger-annotations.version>
<swagger-models.version>1.5.21</swagger-models.version>
<commons.lang3.version>3.12.0</commons.lang3.version>
<fastjson.version>1.2.83</fastjson.version>
<lombok.version>1.18.16</lombok.version>
<mybatis-plus.version>3.4.0</mybatis-plus.version>
<rabbit.mq.version>2.6.1</rabbit.mq.version>
<redisson.version>3.20.0</redisson.version>
<starter-bootstrap.version>3.0.4</starter-bootstrap.version>
<springboot.maven.version>2.3.3.RELEASE</springboot.maven.version>
<hutool.version>5.8.16</hutool.version>
<forest.version>1.5.24</forest.version>
<transmittable-thread-local.version>2.12.2</transmittable-thread-local.version>
<minio.version>8.3.3</minio.version>
<easyexcel.version>3.1.1</easyexcel.version>
<jwt.version>0.9.0</jwt.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringCloud 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-dependencies</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- gateway网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-dependencies</artifactId>
<version>${spring-cloud-gateway.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud Alibaba 微服务 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${springboot.version}</version>
</dependency>
<!--阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.boot.version}</version>
</dependency>
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${swagger-models.version}</version>
</dependency>
<!-- swagger2-UI-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- bootstrap 启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>${rabbit.mq.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-scrm-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-cffp-service</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 订单基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-order-service</artifactId>
<version>${project.version}</version>
</dependency>
<!-- 支付基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-pay-service</artifactId>
<version>${project.version}</version>
</dependency>
<!-- sfp基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-sfp-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--forset-->
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>${forest.version}</version>
</dependency>
<!-- 线程传递值 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>${transmittable-thread-local.version}</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<!--Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,需要导入如下的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>${starter-bootstrap.version}</version>
</dependency>
</dependencies>
<modules>
<module>yd-scrm-api</module>
<module>yd-auth</module>
<module>yd-common</module>
<module>yd-fileservice</module>
<module>yd-framework</module>
<module>yd-gateway</module>
<module>yd-scheduler</module>
<module>yd-scrm-service</module>
<module>yd-sms</module>
<module>yd-pay-api</module>
<module>yd-pay-service</module>
<module>yd-order-api</module>
<module>yd-order-service</module>
<module>yd-email</module>
<module>yd-cffp-api</module>
<module>yd-cffp-service</module>
<module>yd-sfp-api</module>
<module>yd-sfp-service</module>
<module>yd-feign</module>
</modules>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<!-- 引用外部文件,打包上传服务器是将此段注释 -->
<resource>
<directory>../config/run</directory>
</resource>
</resources>
<plugins>
<!-- 配置Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
</plugin>
</plugins>
</build>
<!--项目本身的jar从指定镜像下载-->
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<!--maven相关打包编译等操作配置了以后从当前指定仓库下载-->
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-auth</artifactId>
<description>角色权限部门用户认证等模块</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<!-- <version>2021.1</version>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>yd-auth</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.yd.auth;
import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
import com.yd.common.config.fegin.FeginConfig;
import com.yd.common.constant.WeServerNameConstants;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* 启动程序
*
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, PageHelperAutoConfiguration.class})
@MapperScan("com.yd.**.mapper")
@EnableAsync
@EnableFeignClients(defaultConfiguration = FeginConfig.class)
public class AuthApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(AuthApplication.class)
.properties("spring.config.name:bootstrap", "config/bootstrap.yml")
.properties("spring.application.name="+ WeServerNameConstants.ydAuth)
.build().run(args);
System.out.println("(♥◠‿◠)ノ゙ yd-auth启动成功 ლ(´ڡ`ლ)゙ ");
}
}
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ _ _ _
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_ / \ _ _| |_| |__
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __| / _ \| | | | __| '_ \
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_ / ___ \ |_| | |_| | | |
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__/_/ \_\__,_|\__|_| |_|
${AnsiColor.BRIGHT_WHITE}
Spring Boot Version: ${spring-boot.version}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
<!-- 邮件 -->
<!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
<property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
<!-- SMTP server的端口地址。默认值:25 -->
<property name="smtpPort" value="25"/>
<!-- 发送邮件账号,默认为null -->
<property name="username" value="*"/><!--发件人账号-->
<!-- 发送邮件密码,默认为null -->
<property name="password" value="*"/><!--发件人密码-->
<!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
<property name="SSL" value="true"/>
<!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
<property name="email_to" value="*"/>
<!--收件人账号多个可以逗号隔开-->
<!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
<property name="email_from" value="1" />
<!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
<property name="email_subject" value="【yd-auth】【Error】: %logger" />
<property name="app_name" value="yd-auth"/>
<!-- 日志根目录-->
<springProperty scope="context" name="log.path" source="logging.path"
defaultValue="./logs/yd-auth"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug/${app_name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_debug"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info/${app_name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn/${app_name}.warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_warn"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${app_name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- ERROR邮件发送 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>${smtpHost}</smtpHost>
<smtpPort>${smtpPort}</smtpPort>
<username>${username}</username>
<password>${password}</password>
<!-- <asynchronousSending>true</asynchronousSending>-->
<SSL>${SSL}</SSL>
<!--<STARTTLS>true</STARTTLS>-->
<to>${email_to}</to>
<from>${email_from}</from>
<subject>${email_subject}</subject>
<!-- html格式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<Pattern>%date%level%thread%logger{0}%line%message</Pattern>
</layout>
<!-- 这里采用等级过滤器 指定等级相符才发送 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- 每个电子邮件只发送一个日志条目 -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="cn.yd" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="arollingfile_debug" />
<appender-ref ref="arollingfile_info" />
<appender-ref ref="arollingfile_warn" />
<appender-ref ref="arollingfile_error" />
<!-- <appender-ref ref="alarm_error" />-->
<appender-ref ref="EMAIL" />
</root>
</configuration>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-cffp-api</artifactId>
<description>cffp接口模块(cffp项目个性化定制接口及实现的能力,不和数据库直接交互,需要调用对应service模块和数据库交互)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- feign组件模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
</dependency>
<!-- cffp基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-cffp-service</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-cffp-api</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-cffp-service</artifactId>
<description>cffp实现模块(数据库直接交互,提供基础服务实现的能力)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-cffp-service</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
\ No newline at end of file
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-common</artifactId>
<description>公共组件模块</description>
<dependencies>
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<!-- swagger2-UI-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<!-- spring cloud -->
<!-- SpringCloud Openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
</project>
package com.yd.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
/**
* 自定义导出Excel数据注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
/**
* 导出时在excel中排序
*/
public int sort() default Integer.MAX_VALUE;
/**
* 导出到Excel中的名字.
*/
public String name() default "";
/**
* 日期格式, 如: yyyy-MM-dd
*/
public String dateFormat() default "";
/**
* 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
*/
public String dictType() default "";
/**
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
*/
public String readConverterExp() default "";
/**
* 分隔符,读取字符串组内容
*/
public String separator() default ",";
/**
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
*/
public int scale() default -1;
/**
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
*/
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出类型(0数字 1字符串)
*/
public ColumnType cellType() default ColumnType.STRING;
/**
* 导出时在excel中每个列的高度 单位为字符
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
*/
public double width() default 16;
/**
* 文字后缀,如% 90 变成90%
*/
public String suffix() default "";
/**
* 当值为空时,字段的默认值
*/
public String defaultValue() default "";
/**
* 提示信息
*/
public String prompt() default "";
/**
* 设置只能选择不能输入的列内容.
*/
public String[] combo() default {};
/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
public boolean isExport() default true;
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
public String targetAttr() default "";
/**
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
*/
Type type() default Type.ALL;
public enum Type
{
ALL(0), EXPORT(1), IMPORT(2);
private final int value;
Type(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
public enum ColumnType
{
NUMERIC(0), STRING(1);
private final int value;
ColumnType(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
}
package com.yd.common.config.fegin;
import com.yd.common.interceptor.FeignRequestInterceptor;
import feign.Logger;
import feign.RequestInterceptor;
import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* fegin配置
*/
@Configuration
public class FeginConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.BASIC;
}
@Bean
Logger feignLogger() {
return new FeginLogger(); // 你的继承类
}
@Bean
public Retryer.Default retryerDefault(){
return new Retryer.Default();
}
@Bean
public RequestInterceptor requestInterceptor()
{
return new FeignRequestInterceptor();
}
}
package com.yd.common.config.fegin;
import feign.Request;
import feign.Response;
import feign.Util;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import static feign.Util.decodeOrDefault;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* fegin日志统一输出
*/
@Slf4j
public class FeginLogger extends feign.Logger {
@Override
protected Response logAndRebufferResponse(String configKey,
Level logLevel,
Response response,
long elapsedTime) throws IOException {
Request request = response.request();
String requestMsg = request.httpMethod().name() + " " + request.url() + " HTTP/1.1";
boolean hasReqBody = request.body() != null;
String bodyMsg = hasReqBody ? new String(request.body()) : "";
if(requestMsg.contains("/file/upload")){
bodyMsg = "";
}
String responseMsg = "";
int status = response.status();
boolean hasResBody = response.body() != null && !(status == 204 || status == 205);
if (hasResBody) {
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
response = response.toBuilder().body(bodyData).build();
responseMsg = decodeOrDefault(bodyData, UTF_8, "");
}
log(configKey, "request【%s】, body【%s】, response【%s】", requestMsg, bodyMsg, responseMsg);
return response;
}
@Override
protected IOException logIOException(String configKey, Level logLevel, IOException ioe, long elapsedTime) {
log(configKey, "<--- ERROR %s: %s (%sms)", ioe.getClass().getSimpleName(), ioe.getMessage(),
elapsedTime);
return ioe;
}
@Override
protected void log(String configKey, String format, Object... args) {
if (log.isInfoEnabled()) {
log.info(String.format(methodTag(configKey) + format, args));
}
}
}
package com.yd.common.constant;
import com.yd.common.utils.StringUtils;
/**
* 权限通用常量
*/
public class AuthorityConstants {
/** 公共企业Id */
public static final Long COMMON_ENTERPRISE = 0L;
/** 公共企业Id */
public static final Long COMMON_USER = 0L;
/** 控制参数 */
public static final Long DELETE_PARAM = 0L;
/** 模块&菜单树 - 顶级节点Id */
public static final Long SYSTEM_TOP_NODE = -1L;
/** 菜单树 - 顶级节点Id */
public static final Long MENU_TOP_NODE = 0L;
/** 用户类型 */
public enum UserType {
ORDINARY("01", "普通用户"), ADMIN("00", "超管用户");
private final String code;
private final String info;
UserType(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 租户类型 */
public enum TenantType {
ORDINARY("N", "普通租户"), ADMIN("Y", "租管租户");
private final String code;
private final String info;
TenantType(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 角色类型 */
public enum RoleType {
NORMAL("0", "常规"),
DERIVE_TENANT("1", "租户衍生"),
DERIVE_ENTERPRISE("2", "企业衍生"),
DERIVE_DEPT("3", "部门衍生"),
DERIVE_POST("4", "岗位衍生"),
DERIVE_USER("5", "用户衍生");
private final String code;
private final String info;
RoleType(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
public static RoleType getValue(String code){
for(RoleType roleType : values()){
if(StringUtils.equals(code, roleType.getCode())){
return roleType;
}
}
return null;
}
}
/** 公共数据 */
public enum IsCommon {
YES("Y", "是"), NO("N", "否");
private final String code;
private final String info;
IsCommon(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 数据范围 */
public enum DataScope {
ALL("1","全部数据权限"),
CUSTOM("2","自定义数据权限"),
DEPT("3","本部门数据权限"),
DEPT_AND_CHILD("4","本部门及以下数据权限"),
POST("5","本岗位数据权限"),
SELF("6","仅本人数据权限");
private final String code;
private final String info;
DataScope(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
public static DataScope getValue(String code){
for(DataScope scope : values()){
if(StringUtils.equals(code, scope.getCode())){
return scope;
}
}
return null;
}
}
/** 菜单状态 */
public enum Visible {
YES("Y", "显示"), NO("N", "隐藏");
private final String code;
private final String info;
Visible(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 是否缓存 */
public enum Cache {
YES("Y", "是"), NO("N", "否");
private final String code;
private final String info;
Cache(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 是否菜单外链 */
public enum Frame {
YES("Y", "是"), NO("N", "否");
private final String code;
private final String info;
Frame(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 菜单类型 */
public enum MenuType {
DIR("M", "目录"), MENU("C", "菜单"), BUTTON("F", "按钮");
private final String code;
private final String info;
MenuType(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 组件标识 */
public enum ComponentType {
LAYOUT("Layout", "Layout"), PARENT_VIEW("ParentView", "ParentView"), INNER_LINK("InnerLink", "InnerLink");
private final String code;
private final String info;
ComponentType(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
}
package com.yd.common.constant;
/**
* 缓存的key 常量
*/
public class CacheConstants {
/**
* 缓存有效期,默认720(分钟)
*/
public final static Integer EXPIRATION = 720;
/**
* 缓存刷新时间,默认120(分钟)
*/
public final static Integer REFRESH_TIME = 120;
/**
* 权限缓存前缀
*/
public final static String LOGIN_TOKEN_KEY = "login_tokens:";
/** 字典管理 cache key */
public static final String SYS_DICT_KEY = "sys_dict:";
/**路由key*/
public static final String GATEWAY_ROUTES="gateway_dynamic_routes";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
}
package com.yd.common.constant;
/**
* 通用常量信息
*
*/
public class Constants
{
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 用户ID
*/
public static final String JWT_USERID = "userid";
/**
* 用户名称
*/
public static final String JWT_USERNAME = "sub";
/**
* 用户头像
*/
public static final String JWT_AVATAR = "avatar";
/**
* 创建时间
*/
public static final String JWT_CREATED = "created";
/**
* 用户权限
*/
public static final String JWT_AUTHORITIES = "authorities";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/** 是否为系统默认(是) */
public static final int SERVICE_STATUS_ERROR = -1;
/** 启用状态 */
public static final String NORMAL_CODE=new String("0");
/** 删除状态 */
public static final String DELETE_CODE=new String("2");
/** 业务判断成功状态 */
public static final Integer SERVICE_RETURN_SUCCESS_CODE=0;
/** 系统用户 */
public static final String USER_TYPE_SYS="00";
/** 企业微信用户 */
public static final String USER_TYPE_WECOME="11";
/** 企业管理 */
public static final String USER_TYOE_CORP_ADMIN="22";
/** 企业微信用户系统中默认用户 */
public static final String DEFAULT_WECOME_ROLE_KEY="WeCome";
/** 企业微信用户系统中默认用户 */
public static final String DEFAULT_WECOME_CORP_ADMIN="CROP_ADMIN_ROLE";
/**完成待办*/
public static final String HANDLE_SUCCESS="3";
/**
* 正常状态(未删除)
*/
public static final Integer COMMON_STATE = 0;
/**
* 删除状态
*/
public static final Integer DELETE_STATE = 1;
/**
* 员工活码 redis key
*/
public static final String USER_CODE_KEY = "user_code:";
/**
* 企业信息管理 cache key
*/
public static final String CORP_ACCOUNT_KEY = "corp_account_key";
}
package com.yd.common.constant;
/**
* 网络协议通用常量
*/
public class HttpConstants {
/** ws请求匹配头 */
public static final String DEFAULT_FILTER_PATH = "/ws/";
/** ws请求端口偏移 */
public static final int WS_PORT = 10;
/** 字符集 */
public enum Character {
UTF8("UTF-8", "UTF-8"), GBK("GBK", "GBK");
private final String code;
private final String info;
Character(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 请求类型 */
public enum Type {
LOOKUP_RMI("rmi:", "RMI 远程方法调用"),
LOOKUP_LDAP("ldap:", "LDAP 远程方法调用"),
LOOKUP_LDAPS("ldaps:", "LDAPS 远程方法调用"),
HTTP("http://", "http请求"),
HTTPS("https://", "https请求"),
WS("ws://", "ws请求"),
WSS("wss://", "wss请求");
private final String code;
private final String info;
Type(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
/** 返回状态码 */
public enum Status {
SUCCESS(200, "操作成功"),
CREATED(201, "对象创建成功"),
ACCEPTED(202, "请求已经被接受"),
NO_CONTENT(204, "操作已经执行成功,但是没有返回数据"),
MOVED_PERM(301, "资源已被移除"),
SEE_OTHER(303, "重定向"),
NOT_MODIFIED(304, "资源没有被修改"),
BAD_REQUEST(400, "参数列表错误(缺少,格式不匹配)"),
UNAUTHORIZED(401, "未授权"),
FORBIDDEN(403, "访问受限,授权过期"),
NOT_FOUND(404, "资源,服务未找到"),
BAD_METHOD(405, "不允许的http方法"),
CONFLICT(409, "资源冲突,或者资源被锁"),
UNSUPPORTED_TYPE(415, "不支持的数据,媒体类型"),
ERROR(500, "系统内部错误"),
NOT_IMPLEMENTED(501, "接口未实现");
private final int code;
private final String info;
Status(int code, String info) {
this.code = code;
this.info = info;
}
public int getCode() {
return code;
}
public String getInfo() {
return info;
}
}
}
package com.yd.common.constant;
/**
* 返回状态码
*/
public class HttpStatus
{
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 对象创建成功
*/
public static final int CREATED = 201;
/**
* 请求已经被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已经执行成功,但是没有返回数据
*/
public static final int NO_CONTENT = 204;
/**
* 资源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400;
/**
* 未授权
*/
public static final int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
public static final int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
public static final int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static final int ERROR = 500;
/**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 未注册
*/
public static final int NOT_REGISTER=505;
/**
*
*/
public static final int NOT_ORTHER_IMPLEMENTED = 502;
/**
* 字段值不可重复
*/
public static final int NOT_DATA_DUPLICATION=433;
/**
* 参数未配置
*/
public static final int NOT_TO_CONFIG=226;
}
package com.yd.common.constant;
/**
* 安全相关通用常量
*/
public class SecurityConstants {
/** 请求来源 */
public static final String FROM_SOURCE = "from-source";
/** 授权信息 */
public static final String AUTHORIZATION_HEADER = "authorization";
/** 企业Id */
public static final String CORP_ID = "corp_id";
/** 企业账号 */
public static final String CORP_NAME = "corp_name";
/** 租户ID */
public static final String TENANT_ID = "tenant_id";
/** 用户Id */
public static final String USER_ID = "user_id";
/** 用户账号 */
public static final String USER_NAME = "user_name";
/** 用户类型 */
public static final String USER_TYPE = "user_type";
/** 用户标识 */
public static final String USER_KEY = "user_key";
/** 登录用户 */
public static final String LOGIN_USER = "login_user";
/** 登录类型 **/
public static final String LOGIN_TYPE = "login_type";
/** 内部请求 */
public static final String INNER = "inner";
/**公众号id*/
public static final String WE_APP_ID="weAppId";
/**公众号密钥*/
public static final String WE_APP_SECRET="weAppSecret";
/**Feign请求标识*/
public static final String IS_FEGIN="isFeign";
/** 授权字段 */
public enum Details {
CORP_ID("corp_id", "企业Id"),
TENANT_ID("tenant_id", "租户Id"),
CORP_NAME("corp_name", "企业账号"),
IS_LESSOR("is_lessor", "企业类型"),
USER_ID("user_id", "用户Id"),
USER_NAME("user_name", "用户账号"),
USER_TYPE("user_type", "用户类型"),
USER_KEY("user_key", "用户标识"),
LOGIN_USER("login_user", "登录用户");
private final String code;
private final String info;
Details(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}
}
package com.yd.common.constant;
/**
* Token的Key常量
*
*/
public class TokenConstants {
/**
* 令牌自定义标识
*/
public static final String AUTHENTICATION = "Authorization";
/**
* 令牌前缀
*/
public static final String PREFIX = "Bearer ";
/**
* 令牌秘钥
*/
public final static String SECRET = "a1531c389f0e48a784542a3662f64f22";
}
package com.yd.common.constant;
/**
* 系统服务名称
*/
public class WeServerNameConstants {
/**
* yd-ai服务名称
*/
public static String ydAi="yd-ai";
/**
* yd-scrm-api服务名称
*/
public static String ydApi="yd-scrm-api";
/**
* yd-auth服务名称
*/
public static String ydAuth="yd-auth";
/**
* yd-event-task服务名称
*/
public static String ydEventTask="yd-event-task";
/**
* yd-file服务名称
*/
public static String ydFile="yd-file";
/**
* yd-gateway服务名称
*/
public static String ydGateway="yd-gateway";
/**
* yd-scheduler服务名称
*/
public static String ydScheduler="yd-scheduler";
/**
* yd-wecom服务名称
*/
public static String ydWecom="yd-wecom";
/**
* yd-wx-api服务名称
*/
public static String ydWxApi="yd-wx-api";
}
package com.yd.common.context;
import cn.hutool.core.convert.Convert;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.yd.common.constant.SecurityConstants;
import com.yd.common.utils.StringUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 获取当前线程变量中的 企业Id | 企业账号 | 租户类型 | 用户id | 用户账号 | 用户类型 | Token等信息
* 注意: 必须在网关通过请求头的方法传入,同时在HeaderInterceptor拦截器设置值。 否则这里无法获取
*/
public class SecurityContextHolder {
private static final TransmittableThreadLocal<Map<String, Object>> THREAD_LOCAL = new TransmittableThreadLocal<>();
public static void set(String key, Object value) {
Map<String, Object> map = getLocalMap();
map.put(key, value == null ? StringUtils.EMPTY : value);
}
public static void remove(String key) {
Map<String, Object> map = getLocalMap();
map.remove(key);
}
public static String get(String key) {
Map<String, Object> map = getLocalMap();
return Convert.toStr(map.getOrDefault(key, StringUtils.EMPTY));
}
public static <T> T get(String key, Class<T> clazz) {
Map<String, Object> map = getLocalMap();
return StringUtils.cast(map.getOrDefault(key, null));
}
public static Map<String, Object> getLocalMap() {
Map<String, Object> map = THREAD_LOCAL.get();
if (map == null) {
map = new ConcurrentHashMap<String, Object>();
THREAD_LOCAL.set(map);
}
return map;
}
public static void setLocalMap(Map<String, Object> threadLocalMap) {
THREAD_LOCAL.set(threadLocalMap);
}
public static String getCorpId() {
return Convert.toStr(get(SecurityConstants.Details.CORP_ID.getCode()));
}
public static void setCorpId(String corpId) {
set(SecurityConstants.Details.CORP_ID.getCode(), corpId);
}
public static String getCorpName() {
return get(SecurityConstants.Details.CORP_NAME.getCode());
}
public static void setCorpName(String corpName) {
set(SecurityConstants.Details.CORP_NAME.getCode(), corpName);
}
public static Long getUserId() {
return Convert.toLong(get(SecurityConstants.Details.USER_ID.getCode()), 0L);
}
public static void setUserId(String userId) {
set(SecurityConstants.Details.USER_ID.getCode(), userId);
}
public static String getUserName() {
return get(SecurityConstants.Details.USER_NAME.getCode());
}
public static void setUserName(String userName) {
set(SecurityConstants.Details.USER_NAME.getCode(), userName);
}
public static String getUserType() {
return get(SecurityConstants.Details.USER_TYPE.getCode());
}
public static void setUserType(String userType) {
set(SecurityConstants.Details.USER_TYPE.getCode(), userType);
}
public static String getUserKey() {
return get(SecurityConstants.Details.USER_KEY.getCode());
}
public static void setUserKey(String userKey) {
set(SecurityConstants.Details.USER_KEY.getCode(), userKey);
}
public static void remove() {
THREAD_LOCAL.remove();
}
public static void setTenantId(Integer tenantId) {
set(SecurityConstants.Details.TENANT_ID.getCode(), tenantId);
}
public static Integer getTenantId() {
return Convert.toInt(get(SecurityConstants.Details.TENANT_ID.getCode()));
}
}
package com.yd.common.core.domain;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yd.common.utils.DateUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Entity基类
*/
@Data
public class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 搜索值
*/
@TableField(exist = false)
@ApiModelProperty(hidden = true)
@ExcelIgnore
private String searchValue;
/**
* 创建者
*/
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT)
@ExcelIgnore
private String createBy;
/**
* 创建者ID
*/
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT)
@ExcelIgnore
private Long createById;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT)
@ExcelIgnore
private Date createTime;
/**
* 更新者
*/
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT_UPDATE)
@ExcelIgnore
private String updateBy;
/**
* 更新者ID
*/
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT_UPDATE)
@ExcelIgnore
private Long updateById;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@ApiModelProperty(hidden = true)
@TableField(fill = FieldFill.INSERT_UPDATE)
@ExcelIgnore
private Date updateTime;
/**
* 备注
*/
@TableField(exist = false)
@ApiModelProperty(hidden = true)
@ExcelIgnore
private String remark;
/**
* 开始时间
*/
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty(hidden = true)
@ExcelIgnore
private String beginTime;
/**
* 结束时间
*/
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty(hidden = true)
@ExcelIgnore
private String endTime;
/**
* 请求参数
*/
@TableField(exist = false)
@ApiModelProperty(hidden = true)
@ExcelIgnore
private Map<String, Object> params;
public String getSearchValue() {
return searchValue;
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
if (createTime == null) {
this.createTime = DateUtils.getNowDate();
} else {
this.createTime = createTime;
}
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getBeginTime() {
return beginTime;
}
public void setBeginTime(String beginTime) {
this.beginTime = beginTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public Map<String, Object> getParams() {
if (params == null) {
params = new HashMap<>();
}
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
}
package com.yd.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yd.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
/**
* 部门表 sys_dept
*/
@Data
@TableName(value = "sys_dept")
public class SysDept extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 部门ID
*/
@ApiModelProperty(value = "主键id")
@TableId(type = IdType.INPUT)
@TableField("dept_id")
private Long deptId;
/**
* 父部门ID
*/
@ApiModelProperty(value = "父部门id")
@TableField("parent_id")
private Long parentId;
/**
* 祖级列表
*/
@ApiModelProperty(value = "祖级列表")
@TableField("ancestors")
private String ancestors;
/**
* 部门名称
*/
@ApiModelProperty(value = "部门名称")
@TableField("dept_name")
private String deptName;
/**
* 部门英文名称
*/
@ApiModelProperty(value = "部门英文名称")
@TableField("dept_en_name")
private String deptEnName;
/**
* 显示顺序
*/
@ApiModelProperty(value = "显示顺序")
@TableField("order_num")
private Long orderNum;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
@TableField("leader")
private String leader;
/**
* 联系电话
*/
@ApiModelProperty(value = "联系电话")
@TableField("phone")
private String phone;
/**
* 邮箱
*/
@ApiModelProperty(value = "邮箱")
@TableField("email")
private String email;
/**
* 部门状态:0正常,1停用
*/
@ApiModelProperty(value = "部门状态:0正常,1停用")
@TableField("status")
private String status;
/**
* 删除标志(0代表存在 2代表删除)
*/
@TableField("del_flag")
private String delFlag;
/**
* 父部门名称
*/
@TableField(exist = false)
private String parentName;
/**
* 子部门
*/
@TableField(exist = false)
private List<SysDept> children = new ArrayList<SysDept>();
@NotBlank(message = "部门名称不能为空")
@Size(min = 0, max = 32, message = "部门名称长度不能超过32个字符")
public String getDeptName() {
return deptName;
}
@Size(min = 0, max = 32, message = "部门英文名称长度不能超过32个字符")
public String getDeptEnName() {
return deptEnName;
}
@NotBlank(message = "显示顺序不能为空")
public Long getOrderNum() {
return orderNum;
}
@Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
public String getPhone() {
return phone;
}
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
public String getEmail() {
return email;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("deptId", getDeptId())
.append("parentId", getParentId()).append("ancestors", getAncestors()).append("deptName", getDeptName())
.append("orderNum", getOrderNum()).append("leader", getLeader()).append("phone", getPhone())
.append("email", getEmail()).append("status", getStatus()).append("delFlag", getDelFlag())
.append("createBy", getCreateBy()).append("createTime", getCreateTime())
.append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).toString();
}
}
package com.yd.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yd.common.annotation.Excel;
import com.yd.common.core.domain.BaseEntity;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 角色表 sys_role
*
*
*/
@EqualsAndHashCode(callSuper = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@TableName("sys_role")
public class SysRole extends BaseEntity {
private static final long serialVersionUID = 1L;
public SysRole(Long roleId) {
this.roleId = roleId;
}
public SysRole(String roleKey) {
this.roleKey = roleKey;
}
/**
* 角色ID
*/
@Excel(name = "角色序号", cellType = Excel.ColumnType.NUMERIC)
@TableId(type = IdType.AUTO)
@TableField("role_id")
private Long roleId;
/**
* 角色名称
*/
@Excel(name = "角色名称")
@TableField("role_name")
private String roleName;
/**
* 角色权限
*/
@Excel(name = "角色权限")
@TableField("role_key")
private String roleKey;
/**
* 角色排序
*/
@Excel(name = "角色排序")
@TableField("role_sort")
private String roleSort;
/**
* 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限)
*/
@Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限")
@TableField("data_scope")
private String dataScope;
/**
* 角色状态(0正常 1停用)
*/
@Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
@TableField("status")
private String status;
/**
* 删除标志(0代表存在 2代表删除)
*/
@TableField("del_flag")
private String delFlag;
/**
* 菜单组
*/
@TableField(exist = false)
private Long[] menuIds;
/**
* 部门组(数据权限)
*/
@TableField(exist = false)
private Long[] deptIds;
@TableField("base_role")
private Integer baseRole;
@TableField(exist = false)
private Long[] users;
@TableField(exist = false)
private Long oldRoleId;
public boolean isAdmin() {
return isAdmin(this.roleId);
}
public boolean isAdmin(Long roleId) {
return roleId != null && "SUPPER_ADMIN".equals(getRoleKey());
}
@NotBlank(message = "角色名称不能为空")
@Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
public String getRoleName() {
return roleName;
}
@NotBlank(message = "权限字符不能为空")
@Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
public String getRoleKey() {
return roleKey;
}
@NotBlank(message = "显示顺序不能为空")
public String getRoleSort() {
return roleSort;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("roleId", getRoleId())
.append("roleName", getRoleName()).append("roleKey", getRoleKey()).append("roleSort", getRoleSort())
.append("dataScope", getDataScope()).append("status", getStatus()).append("delFlag", getDelFlag())
.append("createBy", getCreateBy()).append("createTime", getCreateTime())
.append("updateBy", getUpdateBy()).append("updateTime", getUpdateTime()).append("remark", getRemark())
.append("baseRole", getBaseRole()).toString();
}
}
package com.yd.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.yd.common.annotation.Excel;
import com.yd.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 用户对象 sys_user
*
*
*/
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 用户ID
*/
@Excel(name = "用户序号", cellType = Excel.ColumnType.NUMERIC, prompt = "用户编号")
@ApiModelProperty(value = "主键id")
@TableId(type = IdType.AUTO)
@TableField("user_id")
private Long userId;
/**
* 当前微信用户对应微信端的id
*/
@ApiModelProperty(value = "当前微信用户对应微信端的id")
@TableField("we_user_id")
private String weUserId;
/**
* 对应mainDepartment
*/
@ApiModelProperty(value = "对应mainDepartment")
@TableField("dept_id")
private Long deptId;
/**
* 对应mainDepartmentName
*/
@ApiModelProperty(value = "对应mainDepartmentName")
@TableField(exist = false)
private String deptName;
@TableField(exist = false)
private SysDept dept;
/**
* 用户账号
*/
@Excel(name = "登录名称")
@ApiModelProperty(value = "用户账号")
@TableField("user_name")
private String userName;
/**
* 用户部门关联信息
*/
@TableField(exist = false)
private List<SysUserDept> userDepts;
/**
* 职务信息,与岗位数据相匹配
*/
@ApiModelProperty(value = "职务信息")
@TableField("position")
private String position;
/**
* 手机号码
*/
@Excel(name = "手机号码")
@ApiModelProperty(value = "手机号码")
@TableField("phone_number")
private String phoneNumber;
/**
* 用户性别
*/
@Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
@ApiModelProperty(value = "用户性别, 0=男,1=女,2=未知")
@TableField("sex")
private String sex;
/**
* 用户邮箱
*/
@Excel(name = "用户邮箱")
@ApiModelProperty(value = "用户邮箱")
@TableField("email")
private String email;
/**
* 企业邮箱
*/
@Excel(name = "企业邮箱")
@ApiModelProperty(value = "企业邮箱")
@TableField("biz_mail")
private String bizMail;
/**
* 直属上级
*/
@ApiModelProperty(value = "直属上级")
@TableField("leader")
private String leader;
/**
* 用户头像
*/
@ApiModelProperty(value = "用户头像")
@TableField("avatar")
private String avatar;
/**
* 用户头像缩略图
*/
@ApiModelProperty(value = "用户头像缩略图")
@TableField("thumb_avatar")
private String thumbAvatar;
/**
* 座机号码
*/
@ApiModelProperty(value = "座机号码")
@TableField("telephone")
private String telephone;
/**
* 用户昵称
*/
@Excel(name = "用户名称")
@ApiModelProperty(value = "用户昵称")
@TableField("nick_name")
private String nickName;
/**
* 扩展属性
*/
@ApiModelProperty(value = "扩展属性")
@TableField("ext_attr")
private String extAttr;
/**
* 企微用户激活状态(1=已激活,2=已禁用,4=未激活,5=退出企业)
*/
@ApiModelProperty(value = "企微用户激活状态(1=已激活,2=已禁用,4=未激活,5=退出企业)")
@TableField("we_user_status")
private Integer weUserStatus;
/**
* 员工个人二维码
*/
@ApiModelProperty(value = "员工个人二维码")
@TableField("qr_code")
private String qrCode;
/**
* 成员对外属性
*/
@ApiModelProperty(value = "成员对外属性")
@TableField("external_profile")
private String externalProfile;
/**
* 对外职务
*/
@ApiModelProperty(value = "对外职务")
@TableField("external_position")
private String externalPosition;
/**
* 地址
*/
@ApiModelProperty(value = "地址")
@TableField("address")
private String address;
/**
* open_userid
*/
@ApiModelProperty(value = "open_userid")
@TableField("open_userid")
private String openUserid;
/**
* 客服接待状态。1:接待中,2:停止接待
*/
@ApiModelProperty(value = "接待状态。1:接待中,2:停止接待")
@TableField("kf_status")
private Integer kfStatus;
/**
* 数据范围(1:全部数据权限 2:自定义数据权限 3:本部门数据权限 4:本部门及以下数据权限)
*/
private Integer dataScope;
/**
* 工号
*/
private String jobNumber;
/**
* 用户类型(00管理员)(企微用户类型 1.创建者 2.内部系统管理员 3.外部系统管理员 4.分级管理员 5.成员)
*/
@ApiModelProperty(value = "用户类型")
@TableField("user_type")
private String userType;
/**
* 离职状态员工,数据分配状态:0:未分配;1:已分配
*/
private Integer isAllocate;
/**
* 是否离职1:是;0:否
*/
private Integer isUserLeave;
/**
* 离职时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date dimissionTime;
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 盐加密
*/
@TableField(exist = false)
private String salt;
/**
* 帐号状态(0正常 1停用)
*/
@Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
@ApiModelProperty(value = "帐号状态")
@TableField("status")
private String status;
/**
* 删除标志(0代表存在 1代表删除)
*/
@TableField("del_flag")
private Integer delFlag;
/**
* 最后登陆IP
*/
@Excel(name = "最后登陆IP", type = Excel.Type.EXPORT)
@TableField("login_ip")
private String loginIp;
/**
* 最后登陆时间
*/
@Excel(name = "最后登陆时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Excel.Type.EXPORT)
@TableField("login_date")
private Date loginDate;
/**
* 是否开启会话存档 0-未开启 1-开启
*/
private Integer isOpenChat;
/**
* 角色对象
*/
@TableField(exist = false)
private List<SysRole> roles;
/**
* 角色组
*/
@TableField(exist = false)
private Long[] roleIds;
/**
* 角色检索id
*/
@TableField(exist = false)
private Long roleId;
/**
* 岗位组
*/
@TableField(exist = false)
private Long[] postIds;
@TableField(exist = false)
private String companyName;
/**
* 员工所在部门id多个使用逗号隔开
*/
@TableField(exist = false)
private String deptIds;
/**
* 是否开启动态日报 0开启,1关闭 默认开启0
*/
@TableField("is_open_daily")
private Integer openDaily;
/**
* 是否按照跟节点查询所有数据来查询,默认不是
*/
@TableField(exist = false)
private boolean checkIsRoot=false;
public SysUser(Long userId) {
this.userId = userId;
}
public boolean isAdmin() {
return isAdmin(this.userId);
}
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
public String getNickName() {
return nickName;
}
@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
public String getUserName() {
return userName;
}
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
public String getEmail() {
return email;
}
@Email(message = "企业邮箱格式不正确")
@Size(min = 0, max = 50, message = "企业邮箱长度不能超过50个字符")
public String getBizMail() {
return bizMail;
}
@Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
public String getPhoneNumber() {
return phoneNumber;
}
@JsonIgnore
@JsonProperty
public String getPassword() {
return password;
}
public boolean isCheckIsRoot() {
return checkIsRoot;
}
public void setCheckIsRoot(boolean checkIsRoot) {
this.checkIsRoot = checkIsRoot;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("userId", getUserId())
.append("userName", getUserName()).append("nickName", getNickName()).append("email", getEmail())
.append("bizMail", getBizMail()).append("phonenumber", getPhoneNumber()).append("sex", getSex())
.append("avatar", getAvatar()).append("password", getPassword()).append("salt", getSalt())
.append("status", getStatus()).append("delFlag", getDelFlag()).append("loginIp", getLoginIp())
.append("loginDate", getLoginDate()).append("createBy", getCreateBy())
.append("createTime", getCreateTime()).append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime()).append("remark", getRemark()).toString();
}
}
package com.yd.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yd.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户部门关联信息
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("sys_user_dept")
public class SysUserDept extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ApiModelProperty(value = "主键id")
@TableId(type = IdType.AUTO)
@TableField("user_dept_id")
private Long userDeptId;
/**
* 用户id
*/
@ApiModelProperty(value = "用户主键")
@TableField("user_id")
private Long userId;
/**
* 企微用户id
*/
@ApiModelProperty(value = "企微用户id")
@TableField("we_user_id")
private String weUserId;
/**
* open_userid
*/
@ApiModelProperty(value = "open_userid")
@TableField("open_userid")
private String openUserid;
/**
* 部门id
*/
@ApiModelProperty(value = "部门id")
@TableField("dept_id")
private Long deptId;
/**
* 部门名称
*/
@ApiModelProperty(value = "部门名称")
@TableField(exist = false)
private String deptName;
/**
* 部门英文名称
*/
@ApiModelProperty(value = "部门英文名称")
@TableField(exist = false)
private String deptEnName;
/**
* 部门内的排序值
*/
@ApiModelProperty(value = "部门内的排序值")
@TableField("order_in_dept")
private String orderInDept;
/**
* 在所在的部门内是否为部门负责人,0-否;1-是
*/
@ApiModelProperty(value = "在所在的部门内是否为部门负责人,0-否;1-是")
@TableField("leader_in_dept")
private Integer leaderInDept;
/**
* 删除标志(0代表存在 2代表删除)
*/
@TableField("del_flag")
private String delFlag;
}
package com.yd.common.core.domain.model;
import com.yd.common.core.domain.entity.SysUser;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
/**
* 登录用户身份权限
*
*
*/
@Data
public class LoginUser implements Serializable
{
private static final long serialVersionUID = 1L;
/** 用户唯一标识 */
private String token;
/** 企业账号Id */
private String corpId;
/** 企业账号 */
private String corpName;
/** 租户标识 */
private String isLessor;
/** 用户名Id */
private Long userId;
/** 用户名 */
private String userName;
/** 用户标识 */
private String userType;
/** 登录时间 */
private Long loginTime;
/** 过期时间 */
private Long expireTime;
/** 登录IP地址 */
private String ipaddr;
/** 权限列表 */
private Set<String> permissions;
/** 角色权限列表 */
private Set<String> roles;
/** 角色列表 */
private Set<Long> roleIds;
/** 主数据源 */
private String mainSource;
/** 用户信息 */
private SysUser sysUser;
/**朋友圈同步需要的字段*/
private Integer filterType;
/**业务id,多个使用逗号隔开**/
private String businessIds;
/**企业微信员工id集合*/
private List<String> weUserIds;
/**企微客群id集合*/
private List<String> chatIds;
/**客户id集合*/
private List<String> extIds;
}
package com.yd.common.core.domain.model;
import com.alibaba.fastjson.JSONArray;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 登录微信用户身份权限
*/
@Data
public class WxLoginUser implements Serializable
{
private static final long serialVersionUID = 1L;
@ApiModelProperty("用户的唯一标识")
private String openId;
@ApiModelProperty("用户昵称")
private String nickName;
@ApiModelProperty("用户的性别,值为1时是男性,值为2时是女性,值为0时是未知")
private Integer sex;
@ApiModelProperty("用户个人资料填写的省份")
private String province;
@ApiModelProperty("普通用户个人资料填写的城市")
private String city;
@ApiModelProperty("国家,如中国为CN")
private String country;
@ApiModelProperty("用户头像")
private String headImgUrl;
@ApiModelProperty("用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)")
private JSONArray privilege;
@ApiModelProperty("只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。")
private String unionId;
@ApiModelProperty("企微用户ID")
private String externalUserId;
/** 登录时间 */
private Long loginTime;
/** 过期时间 */
private Long expireTime;
/** 登录IP地址 */
private String ipaddr;
/** 用户唯一标识 */
private String token;
}
package com.yd.common.core.page;
import com.linkwechat.common.utils.StringUtils;
/**
* 分页数据
*
*
*/
public class PageDomain
{
/** 当前记录起始索引 */
private Integer pageNum;
/** 每页显示记录数 */
private Integer pageSize;
/** 排序列 */
private String orderByColumn;
/** 排序的方向desc或者asc */
private String isAsc = "asc";
public String getOrderBy()
{
if (StringUtils.isEmpty(orderByColumn))
{
return "";
}
return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
}
public Integer getPageNum()
{
return pageNum;
}
public void setPageNum(Integer pageNum)
{
this.pageNum = pageNum;
}
public Integer getPageSize()
{
return pageSize;
}
public void setPageSize(Integer pageSize)
{
this.pageSize = pageSize;
}
public String getOrderByColumn()
{
return orderByColumn;
}
public void setOrderByColumn(String orderByColumn)
{
this.orderByColumn = orderByColumn;
}
public String getIsAsc()
{
return isAsc;
}
public void setIsAsc(String isAsc)
{
this.isAsc = isAsc;
}
}
package com.yd.common.core.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* spring redis 工具类
**/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
public class RedisService {
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取超时时间
* @param key Redis键
* @param unit 时间单位
* @return
*/
public Long getExpire(final String key, final TimeUnit unit) {
return redisTemplate.getExpire(key, unit);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> long setCacheSet(final String key, final Set<T> dataSet) {
Long count = redisTemplate.opsForSet().add(key, dataSet);
return count == null ? 0 : count;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
/**
* 将给定的消息发布到给定的频道
*
* @param channel 要发布到的频道
* @param message 消息内容
*/
public void convertAndSend(String channel, Object message) {
redisTemplate.convertAndSend(channel, message);
}
/**
* 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能;
*
* @param key
* @param value
* @param score
*/
public Boolean setCacheZSet(String key, String value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 删除元素 zrem
*
* @param key
* @param start
* @param end
*/
public Long removeRangeCacheZSet(String key, long start, long end) {
return redisTemplate.opsForZSet().removeRange(key, start, end);
}
/**
* 删除元素 zrem
*
* @param key
* @param value
*/
public long removeCacheZSet(String key, String value) {
return redisTemplate.opsForZSet().remove(key, value);
}
/**
* score的增加or减少 zincrby
*
* @param key
* @param value
* @param score
*/
public Double incrScoreCacheZSet(String key, String value, double score) {
return redisTemplate.opsForZSet().incrementScore(key, value, score);
}
/**
* 查询value对应的score zscore
*
* @param key
* @param value
* @return
*/
public Double getCacheZSetScore(String key, String value) {
return redisTemplate.opsForZSet().score(key, value);
}
/**
* 判断value在zset中的排名 zrank
*
* @param key
* @param value
* @return
*/
public Long rankCacheZSet(String key, String value) {
return redisTemplate.opsForZSet().rank(key, value);
}
/**
* 返回集合的长度
*
* @param key
* @return
*/
public Long getCacheZSetSize(String key) {
return redisTemplate.opsForZSet().zCard(key);
}
/**
* 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容 zrange
* <p>
* 返回有序的集合,score小的在前面
*
* @param key
* @param start
* @param end
* @return
*/
public Set<String> rangeCacheZSet(String key, int start, int end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/**
* 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容
*
* @param key
* @param start
* @param end
* @return
*/
public Set<ZSetOperations.TypedTuple<String>> rangeWithScore(String key, int start, int end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
/**
* 查询集合中指定顺序的值 zrevrange
* <p>
* 返回有序的集合中,score大的在前面
*
* @param key
* @param start
* @param end
* @return
*/
public Set<String> revRangeCacheZSet(String key, int start, int end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
/**
* 根据score的值,来获取满足条件的集合 zrangebyscore
*
* @param key
* @param min
* @param max
* @return
*/
public Set<String> sortRangeCacheZSet(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
/**
* 根据score的值,来获取满足条件的集合
*
* @param key
* @param min
* @param max
* @return
*/
public Set<ZSetOperations.TypedTuple<String>> sortRangeWithScoresCacheZSet(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
//判断key存在
public boolean keyIsExists(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
/**
* 自增
* @param key
* @return
*/
public Long increment(String key){
return redisTemplate.opsForValue().increment(key);
}
/**
* 自减
* @param key
* @return
*/
public Long decrement(String key){
return redisTemplate.opsForValue().decrement(key);
}
/**
* HyperLogLog计数
* @param key
* @param value
*/
public Long hyperLogLogAdd(String key, Object... value) {
return redisTemplate.opsForHyperLogLog().add(key,value);
}
/**
* HyperLogLog获取总数
* @param key
*/
public Long hyperLogLogCount(String... key) {
return redisTemplate.opsForHyperLogLog().size(key);
}
/**
* 加锁
* @param key 键
* @param value 值
* @param second 秒
**/
public Boolean tryLock(String key,String value, Long second){
Boolean lockStatus = this.redisTemplate.opsForValue().setIfAbsent(key,value, Duration.ofSeconds(second));
return lockStatus;
}
/**
* 加锁
* @param key 键
* @param value 值
* @param timeout 时间
* @param unit 时间类型
**/
public Boolean tryLock(String key,String value, long timeout, TimeUnit unit){
Boolean lockStatus = this.redisTemplate.opsForValue().setIfAbsent(key,value, timeout, unit);
return lockStatus;
}
/**
* 释放锁
* @param key 键
* @param value 值
**/
public Long unLock(String key,String value){
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
RedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript,Long.class);
Long releaseStatus = (Long)this.redisTemplate.execute(redisScript, Collections.singletonList(key),value);
return releaseStatus;
}
}
package com.yd.common.core.text;
import com.yd.common.utils.StringUtils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* 字符集工具类
*
*
*/
public class CharsetKit
{
/** ISO-8859-1 */
public static final String ISO_8859_1 = "ISO-8859-1";
/** UTF-8 */
public static final String UTF_8 = "UTF-8";
/** GBK */
public static final String GBK = "GBK";
/** ISO-8859-1 */
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
/** UTF-8 */
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
/** GBK */
public static final Charset CHARSET_GBK = Charset.forName(GBK);
/**
* 转换为Charset对象
*
* @param charset 字符集,为空则返回默认字符集
* @return Charset
*/
public static Charset charset(String charset)
{
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, String srcCharset, String destCharset)
{
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
}
/**
* 转换字符串的字符集编码
*
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
* @return 转换后的字符集
*/
public static String convert(String source, Charset srcCharset, Charset destCharset)
{
if (null == srcCharset)
{
srcCharset = StandardCharsets.ISO_8859_1;
}
if (null == destCharset)
{
srcCharset = StandardCharsets.UTF_8;
}
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
{
return source;
}
return new String(source.getBytes(srcCharset), destCharset);
}
/**
* @return 系统字符集编码
*/
public static String systemCharset()
{
return Charset.defaultCharset().name();
}
}
package com.yd.common.core.text;
import com.yd.common.utils.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
/**
* 类型转换器
*
*
*/
public class Convert
{
/**
* 转换为字符串<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static String toStr(Object value, String defaultValue)
{
if (null == value)
{
return defaultValue;
}
if (value instanceof String)
{
return (String) value;
}
return value.toString();
}
/**
* 转换为字符串<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static String toStr(Object value)
{
return toStr(value, null);
}
/**
* 转换为字符<br>
* 如果给定的值为null,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Character toChar(Object value, Character defaultValue)
{
if (null == value)
{
return defaultValue;
}
if (value instanceof Character)
{
return (Character) value;
}
final String valueStr = toStr(value, null);
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
}
/**
* 转换为字符<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Character toChar(Object value)
{
return toChar(value, null);
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Byte toByte(Object value, Byte defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Byte)
{
return (Byte) value;
}
if (value instanceof Number)
{
return ((Number) value).byteValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return Byte.parseByte(valueStr);
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为byte<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Byte toByte(Object value)
{
return toByte(value, null);
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Short toShort(Object value, Short defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Short)
{
return (Short) value;
}
if (value instanceof Number)
{
return ((Number) value).shortValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return Short.parseShort(valueStr.trim());
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为Short<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Short toShort(Object value)
{
return toShort(value, null);
}
/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Number toNumber(Object value, Number defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Number)
{
return (Number) value;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return NumberFormat.getInstance().parse(valueStr);
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为Number<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Number toNumber(Object value)
{
return toNumber(value, null);
}
/**
* 转换为int<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Integer toInt(Object value, Integer defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Integer)
{
return (Integer) value;
}
if (value instanceof Number)
{
return ((Number) value).intValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return Integer.parseInt(valueStr.trim());
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为int<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Integer toInt(Object value)
{
return toInt(value, null);
}
/**
* 转换为Integer数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String str)
{
return toIntArray(",", str);
}
/**
* 转换为Long数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String str)
{
return toLongArray(",", str);
}
/**
* 转换为Integer数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static Integer[] toIntArray(String split, String str)
{
if (StringUtils.isEmpty(str))
{
return new Integer[] {};
}
String[] arr = str.split(split);
final Integer[] ints = new Integer[arr.length];
for (int i = 0; i < arr.length; i++)
{
final Integer v = toInt(arr[i], 0);
ints[i] = v;
}
return ints;
}
/**
* 转换为Long数组<br>
*
* @param split 分隔符
* @param str 被转换的值
* @return 结果
*/
public static Long[] toLongArray(String split, String str)
{
if (StringUtils.isEmpty(str))
{
return new Long[] {};
}
String[] arr = str.split(split);
final Long[] longs = new Long[arr.length];
for (int i = 0; i < arr.length; i++)
{
final Long v = toLong(arr[i], null);
longs[i] = v;
}
return longs;
}
/**
* 转换为String数组<br>
*
* @param str 被转换的值
* @return 结果
*/
public static String[] toStrArray(String str)
{
return toStrArray(",", str);
}
/**
* 转换为String数组<br>
*
* @param split 分隔符
* @param split 被转换的值
* @return 结果
*/
public static String[] toStrArray(String split, String str)
{
return str.split(split);
}
/**
* 转换为long<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Long toLong(Object value, Long defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Long)
{
return (Long) value;
}
if (value instanceof Number)
{
return ((Number) value).longValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
// 支持科学计数法
return new BigDecimal(valueStr.trim()).longValue();
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为long<br>
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Long toLong(Object value)
{
return toLong(value, null);
}
/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Double toDouble(Object value, Double defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Double)
{
return (Double) value;
}
if (value instanceof Number)
{
return ((Number) value).doubleValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
// 支持科学计数法
return new BigDecimal(valueStr.trim()).doubleValue();
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为double<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Double toDouble(Object value)
{
return toDouble(value, null);
}
/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Float toFloat(Object value, Float defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Float)
{
return (Float) value;
}
if (value instanceof Number)
{
return ((Number) value).floatValue();
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return Float.parseFloat(valueStr.trim());
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为Float<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Float toFloat(Object value)
{
return toFloat(value, null);
}
/**
* 转换为boolean<br>
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static Boolean toBool(Object value, Boolean defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof Boolean)
{
return (Boolean) value;
}
String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
valueStr = valueStr.trim().toLowerCase();
switch (valueStr)
{
case "true":
return true;
case "false":
return false;
case "yes":
return true;
case "ok":
return true;
case "no":
return false;
case "1":
return true;
case "0":
return false;
default:
return defaultValue;
}
}
/**
* 转换为boolean<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static Boolean toBool(Object value)
{
return toBool(value, null);
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
*
* @param clazz Enum的Class
* @param value 值
* @param defaultValue 默认值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (clazz.isAssignableFrom(value.getClass()))
{
@SuppressWarnings("unchecked")
E myE = (E) value;
return myE;
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return Enum.valueOf(clazz, valueStr);
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为Enum对象<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
*
* @param clazz Enum的Class
* @param value 值
* @return Enum
*/
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
{
return toEnum(clazz, value, null);
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof BigInteger)
{
return (BigInteger) value;
}
if (value instanceof Long)
{
return BigInteger.valueOf((Long) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return new BigInteger(valueStr);
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为BigInteger<br>
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigInteger toBigInteger(Object value)
{
return toBigInteger(value, null);
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @param defaultValue 转换错误时的默认值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
{
if (value == null)
{
return defaultValue;
}
if (value instanceof BigDecimal)
{
return (BigDecimal) value;
}
if (value instanceof Long)
{
return new BigDecimal((Long) value);
}
if (value instanceof Double)
{
return new BigDecimal((Double) value);
}
if (value instanceof Integer)
{
return new BigDecimal((Integer) value);
}
final String valueStr = toStr(value, null);
if (StringUtils.isEmpty(valueStr))
{
return defaultValue;
}
try
{
return new BigDecimal(valueStr);
}
catch (Exception e)
{
return defaultValue;
}
}
/**
* 转换为BigDecimal<br>
* 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错
*
* @param value 被转换的值
* @return 结果
*/
public static BigDecimal toBigDecimal(Object value)
{
return toBigDecimal(value, null);
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @return 字符串
*/
public static String utf8Str(Object obj)
{
return str(obj, CharsetKit.CHARSET_UTF_8);
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charsetName 字符集
* @return 字符串
*/
public static String str(Object obj, String charsetName)
{
return str(obj, Charset.forName(charsetName));
}
/**
* 将对象转为字符串<br>
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
*
* @param obj 对象
* @param charset 字符集
* @return 字符串
*/
public static String str(Object obj, Charset charset)
{
if (null == obj)
{
return null;
}
if (obj instanceof String)
{
return (String) obj;
}
else if (obj instanceof byte[] || obj instanceof Byte[])
{
return str((Byte[]) obj, charset);
}
else if (obj instanceof ByteBuffer)
{
return str((ByteBuffer) obj, charset);
}
return obj.toString();
}
/**
* 将byte数组转为字符串
*
* @param bytes byte数组
* @param charset 字符集
* @return 字符串
*/
public static String str(byte[] bytes, String charset)
{
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
}
/**
* 解码字节码
*
* @param data 字符串
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
* @return 解码后的字符串
*/
public static String str(byte[] data, Charset charset)
{
if (data == null)
{
return null;
}
if (null == charset)
{
return new String(data);
}
return new String(data, charset);
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, String charset)
{
if (data == null)
{
return null;
}
return str(data, Charset.forName(charset));
}
/**
* 将编码的byteBuffer数据转换为字符串
*
* @param data 数据
* @param charset 字符集,如果为空使用当前系统字符集
* @return 字符串
*/
public static String str(ByteBuffer data, Charset charset)
{
if (null == charset)
{
charset = Charset.defaultCharset();
}
return charset.decode(data).toString();
}
// ----------------------------------------------------------------------- 全角半角转换
/**
* 半角转全角
*
* @param input String.
* @return 全角字符串.
*/
public static String toSBC(String input)
{
return toSBC(input, null);
}
/**
* 半角转全角
*
* @param input String
* @param notConvertSet 不替换的字符集合
* @return 全角字符串.
*/
public static String toSBC(String input, Set<Character> notConvertSet)
{
char c[] = input.toCharArray();
for (int i = 0; i < c.length; i++)
{
if (null != notConvertSet && notConvertSet.contains(c[i]))
{
// 跳过不替换的字符
continue;
}
if (c[i] == ' ')
{
c[i] = '\u3000';
}
else if (c[i] < '\177')
{
c[i] = (char) (c[i] + 65248);
}
}
return new String(c);
}
/**
* 全角转半角
*
* @param input String.
* @return 半角字符串
*/
public static String toDBC(String input)
{
return toDBC(input, null);
}
/**
* 替换全角为半角
*
* @param text 文本
* @param notConvertSet 不替换的字符集合
* @return 替换后的字符
*/
public static String toDBC(String text, Set<Character> notConvertSet)
{
char c[] = text.toCharArray();
for (int i = 0; i < c.length; i++)
{
if (null != notConvertSet && notConvertSet.contains(c[i]))
{
// 跳过不替换的字符
continue;
}
if (c[i] == '\u3000')
{
c[i] = ' ';
}
else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
{
c[i] = (char) (c[i] - 65248);
}
}
String returnString = new String(c);
return returnString;
}
/**
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
*
* @param n 数字
* @return 中文大写数字
*/
public static String digitUppercase(double n)
{
String[] fraction = { "角", "分" };
String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
String head = n < 0 ? "负" : "";
n = Math.abs(n);
String s = "";
for (int i = 0; i < fraction.length; i++)
{
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1)
{
s = "整";
}
int integerPart = (int) Math.floor(n);
for (int i = 0; i < unit[0].length && integerPart > 0; i++)
{
String p = "";
for (int j = 0; j < unit[1].length && n > 0; j++)
{
p = digit[integerPart % 10] + unit[1][j] + p;
integerPart = integerPart / 10;
}
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
}
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
}
}
package com.yd.common.core.text;
import com.yd.common.utils.StringUtils;
/**
* 字符串格式化
*
*
*/
public class StrFormatter
{
public static final String EMPTY_JSON = "{}";
public static final char C_BACKSLASH = '\\';
public static final char C_DELIM_START = '{';
public static final char C_DELIM_END = '}';
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public static String format(final String strPattern, final Object... argArray)
{
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
{
return strPattern;
}
final int strPatternLength = strPattern.length();
// 初始化定义好的长度以获得更好的性能
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;
int delimIndex;// 占位符所在位置
for (int argIndex = 0; argIndex < argArray.length; argIndex++)
{
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
if (delimIndex == -1)
{
if (handledPosition == 0)
{
return strPattern;
}
else
{ // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
}
else
{
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
{
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
{
// 转义符之前还有一个转义符,占位符依旧有效
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
else
{
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(C_DELIM_START);
handledPosition = delimIndex + 1;
}
}
else
{
// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(Convert.utf8Str(argArray[argIndex]));
handledPosition = delimIndex + 2;
}
}
}
// 加入最后一个占位符后所有的字符
sbuf.append(strPattern, handledPosition, strPattern.length());
return sbuf.toString();
}
}
package com.yd.common.domain;
import com.yd.common.constant.Constants;
import java.io.Serializable;
/**
* 响应信息主体
*
*/
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 成功
*/
public static final int SUCCESS = Integer.parseInt(Constants.SUCCESS);
/**
* 失败
*/
public static final int FAIL = Integer.parseInt(Constants.FAIL);
private int code;
private String msg;
private T data;
public static <T> R<T> ok() {
return restResult(null, SUCCESS, null);
}
public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, null);
}
public static <T> R<T> ok(T data, String msg) {
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail() {
return restResult(null, FAIL, null);
}
public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data) {
return restResult(data, FAIL, null);
}
public static <T> R<T> fail(T data, String msg) {
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg) {
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package com.yd.common.enums;
/**
* 返回码
*
* @author zxm
*/
public enum ErrorCode {
SUCCESS(200,"ok","") ,
CHECK_ONLY_ERROR(10000,"校验唯一性错误",""),
NULL_ERROR(40001,"请求参数为空",""),
SYSTEM_ERROR(50000,"系统内部异常",""),
;
//返回码
private final int code;
//操作响应信息
private final String message;
//响应信息的详细描述
private final String description;
//构造函数
ErrorCode(int code, String message, String description) {
this.code = code;
this.message = message;
this.description = description;
}
//get方法
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
}
package com.yd.common.exception;
import com.yd.common.enums.ErrorCode;
import lombok.Data;
import java.io.Serializable;
/**
* 通用返回类
*
* @author zxm
* @param <T>
*/
@Data
public class BaseResponse<T> implements Serializable {
private int code;
private T data;
private String message;
private String description;
// 添加无参构造方法
public BaseResponse() {
this(ErrorCode.SUCCESS.getCode(),null,ErrorCode.SUCCESS.getMessage(),ErrorCode.SUCCESS.getDescription());
}
/**
* 构造函数
* @param code 状态码
* @param data 向前端传的数据
* @param message 操作反馈信息:如登录成功、查询成功、查询失败、账号密码错误等提示信息。有利于后续纠错。
* @param description 反馈信息的详细描述
*/
public BaseResponse(int code, T data, String message, String description) {
this.code = code;
this.data = data;
this.message = message;
this.description=description;
}
/**
*定义各种构造函数,有利于灵活的返回各种信息。如下面这个只返回状态码、数据、操作反馈信息,但不返回详细描述。
* 而再下一个只返回code和data,不返回message和description的信息。
*/
public BaseResponse(int code, T data, String message) {
this(code,data,message,"");
}
/**
* 成功默认返回
* @param data
*/
public BaseResponse(T data) {
this(ErrorCode.SUCCESS.getCode(),data,ErrorCode.SUCCESS.getMessage(),ErrorCode.SUCCESS.getDescription());
}
public BaseResponse(int code, T data) {
this(code,data,"","");
}
public BaseResponse(ErrorCode errorCode){
this(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescription());
}
public BaseResponse(ErrorCode errorCode, String description){
this(errorCode.getCode(),null,errorCode.getMessage(),description);
}
}
package com.yd.common.exception;
import com.yd.common.enums.ErrorCode;
/**
* 业务异常类
* 继承RuntimeException异常处理类。
*
* @author zxm
*/
public class BusinessException extends RuntimeException{
private int code;
private String description;
/**
* 各种构造函数,供我们灵活的使用
*/
public BusinessException(String message, int code, String description) {
super(message);
this.code = code;
this.description = description;
}
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = errorCode.getDescription();
}
public BusinessException(ErrorCode errorCode,String description) {
super(errorCode.getMessage());
this.code = errorCode.getCode();
this.description = description;
}
public int getCode() {
return code;
}
public String getDescription() {
return description;
}
}
package com.yd.common.exception;
import com.yd.common.enums.ErrorCode;
import com.yd.common.utils.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
/**
* 全局异常处理器
* Slf4j是用来记录日志信息的,lombok中自带的。
*
* @author zxm
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/**
* 处理业务返回的异常
* @param e
* @return
*/
@ExceptionHandler(BusinessException.class)
public BaseResponse businessExceptionHandler(BusinessException e){
log.error("BusinessException:{}",e);
return ResultUtils.error(e.getCode(),e.getMessage(),e.getDescription());
// throw new BusinessException(e.getMessage(),e.getCode(),e.getDescription());
}
/**
* 处理系统异常
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public BaseResponse exceptionHandler(Exception e){
log.error("Exception:{}",e);
//系统异常
return ResultUtils.error(ErrorCode.SYSTEM_ERROR);
}
/**
* @Validated校验器触发的异常 @RequestBody对象校验
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public BaseResponse methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
BindingResult bindingResult = e.getBindingResult();
// Map<String, String> errors = new HashMap<>();
// for (FieldError fieldError : bindingResult.getFieldErrors()) {
// errors.put(fieldError.getField(), fieldError.getDefaultMessage());
// }
String msg = bindingResult.getFieldErrors().get(0).getDefaultMessage();
//集中处理
//请求参数为空校验
log.error("MethodArgumentNotValidException:{}",e);
return ResultUtils.error(ErrorCode.NULL_ERROR.getCode(),msg,msg);
}
/**
* @Validated校验器触发的异常 RequestParam 参数校验
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public BaseResponse constraintViolationExceptionHandler(ConstraintViolationException e){
String msg = e.getConstraintViolations().stream().collect(Collectors.toList()).get(0).getMessage();
log.error("ConstraintViolationException:{}",e);
//请求参数为空校验
return ResultUtils.error(ErrorCode.NULL_ERROR.getCode(),msg,msg);
}
}
package com.yd.common.interceptor;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.yd.common.constant.TokenConstants;
import com.yd.common.utils.SecurityUtils;
import com.yd.common.utils.StringUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.Enumeration;
/**
* feign 请求拦截器
*/
@Slf4j
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
String name;
// 将原有请求中的header,数据转移至新的请求中
if (headerNames != null) {
while(headerNames.hasMoreElements()) {
name = (String)headerNames.nextElement();
String values = request.getHeader(name);
if (!name.equalsIgnoreCase("content-length")) {
requestTemplate.header(name, new String[]{values});
}
}
}
}
String corpId = SecurityUtils.getCorpId();
if (StringUtils.isNotEmpty(corpId)) {
String method = requestTemplate.method();
if("GET".equals(method)){
Collection<String> corpidParm = requestTemplate.queries().get("corpid");
if(CollectionUtil.isEmpty(corpidParm)){
requestTemplate.query("corpid", corpId);
}
}
if (requestTemplate.body() != null) {
int length = requestTemplate.body().length;
boolean hasFormData = requestTemplate.headers().get("Content-Type").stream()
.anyMatch(h -> h.contains("form-data"));
if (0 < length && !hasFormData) {
String jsonBody = new String(requestTemplate.body());
if (!StringUtils.isEmpty(jsonBody)) {
JSONObject parse = JSONObject.parseObject(jsonBody);
parse.put("corpid", corpId);
// 替换请求体
byte[] bodyData = parse.toJSONString().getBytes(Util.UTF_8);
requestTemplate.body(bodyData, Util.UTF_8);
}
}
}
} else {
log.warn("url:{} corpId 为null", requestTemplate.url());
}
}
/**
* 获取请求token
*/
private String getToken(String token) {
// 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
}
return token;
}
}
package com.yd.common.typeHandler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@MappedJdbcTypes(JdbcType.VARBINARY)
@MappedTypes({List.class})
public abstract class ListTypeHandler<T> extends BaseTypeHandler<List<T>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
String content = CollUtil.isEmpty(parameter) ? null : JSON.toJSONString(parameter);
ps.setString(i, content);
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return this.getListByJsonArrayString(rs.getString(columnName));
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return this.getListByJsonArrayString(rs.getString(columnIndex));
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return this.getListByJsonArrayString(cs.getString(columnIndex));
}
private List<T> getListByJsonArrayString(String content) {
return StrUtil.isBlank(content) ? new ArrayList<>() : JSON.parseObject(content, this.specificType());
}
/**
* 具体类型,由子类提供
*
* @return 具体类型
*/
protected abstract TypeReference<List<T>> specificType();
}
package com.yd.common.utils;
import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* 时间工具类
*
*
*/
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
{
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
public static String YYYY_MM_DD = "yyyy-MM-dd";
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 获取当前Date型日期
*
* @return Date() 当前日期
*/
public static Date getNowDate()
{
return new Date();
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
*
* @return String
*/
public static String getDate()
{
return dateTimeNow(YYYY_MM_DD);
}
public static final String getTime()
{
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
public static final String dateTimeNow()
{
return dateTimeNow(YYYYMMDDHHMMSS);
}
public static final String dateTimeNow(final String format)
{
return parseDateToStr(format, new Date());
}
public static final String dateTime(final Date date)
{
return parseDateToStr(YYYY_MM_DD, date);
}
public static final String parseDateToStr(final String format, final Date date)
{
return new SimpleDateFormat(format).format(date);
}
public static final Date dateTime(final String format, final String ts)
{
try
{
return new SimpleDateFormat(format).parse(ts);
}
catch (ParseException e)
{
throw new RuntimeException(e);
}
}
/**
* 日期路径 即年/月/日 如2018/08/08
*/
public static final String datePath()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
/**
* 日期路径 即年/月/日 如20180808
*/
public static final String dateTime()
{
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str)
{
if (str == null)
{
return null;
}
try
{
return parseDate(str.toString(), parsePatterns);
}
catch (ParseException e)
{
return null;
}
}
/**
* 获取服务器启动时间
*/
public static Date getServerStartDate()
{
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
/**
* 计算两个时间差
*/
public static String getDatePoor(Date endDate, Date nowDate)
{
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
// long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟";
}
/**
* 计算两个时间差
*/
public static long diffTime(Date endDate, Date nowDate){
return endDate.getTime() - nowDate.getTime();
}
/**
* 获取时间段内所有日期
* @param dBegin
* @param dEnd
* @return
*/
public static List<Date> findDates(Date dBegin, Date dEnd)
{
List lDate = new ArrayList();
lDate.add(dBegin);
Calendar calBegin = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
calEnd.setTime(dEnd);
// 测试此日期是否在指定日期之后
while (dEnd.after(calBegin.getTime()))
{
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
calBegin.add(Calendar.DAY_OF_MONTH, 1);
lDate.add(calBegin.getTime());
}
return lDate;
}
public static long getMillionSceondsBydate(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
long millionSeconds = sdf.parse(date).getTime();//毫秒
return millionSeconds;
}
public static int getAge(Date birthDay) throws Exception {
Calendar cal = Calendar.getInstance();
if (cal.before(birthDay)) { //出生日期晚于当前时间,无法计算
throw new IllegalArgumentException(
"The birthDay is before Now.It's unbelievable!");
}
int yearNow = cal.get(Calendar.YEAR); //当前年份
int monthNow = cal.get(Calendar.MONTH); //当前月份
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
cal.setTime(birthDay);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
int age = yearNow - yearBirth; //计算整岁数
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前,年龄减一
}else{
age--;//当前月份在生日之前,年龄减一
} }
return age;
}
/**
* 获取当前时间的时间戳
*/
public static int getCurrentTimeIntValue() {
return (int) (System.currentTimeMillis() / 1000);
}
/**
* 获取days天后的当前时间 时间戳
*/
public static int addDaysTimeStamp(int days) {
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, days);
return (int) (cal.getTimeInMillis() / 1000);
}
/**
* 获取今日零点的时间戳
*/
public static int getStartTimeStamp() {
Calendar todayStart = Calendar.getInstance();
todayStart.set(Calendar.HOUR_OF_DAY, 0);
todayStart.set(Calendar.MINUTE, 0);
todayStart.set(Calendar.SECOND, 0);
todayStart.set(Calendar.MILLISECOND, 0);
long time = todayStart.getTimeInMillis()/1000;
return (int)time;
}
/**
* 获取今日23:59:59的时间戳
*/
public static int getEndTimeStamp() {
Calendar todayEnd = Calendar.getInstance();
todayEnd.set(Calendar.HOUR_OF_DAY, 23);
todayEnd.set(Calendar.MINUTE, 59);
todayEnd.set(Calendar.SECOND, 59);
todayEnd.set(Calendar.MILLISECOND, 999);
long time = todayEnd.getTimeInMillis() / 1000;
return (int) time;
}
/**
* 获取指定时间零点的时间戳
*/
public static int getStartTimeStamp(Date date) {
Calendar todayStart = Calendar.getInstance();
todayStart.setTime(date);
todayStart.set(Calendar.HOUR_OF_DAY, 0);
todayStart.set(Calendar.MINUTE, 0);
todayStart.set(Calendar.SECOND, 0);
todayStart.set(Calendar.MILLISECOND, 0);
long time = todayStart.getTimeInMillis()/1000;
return (int)time;
}
/**
* 获取指定时间23:59:59的时间戳
*/
public static int getEndTimeStamp(Date date) {
Calendar todayEnd = Calendar.getInstance();
todayEnd.setTime(date);
todayEnd.set(Calendar.HOUR_OF_DAY, 23);
todayEnd.set(Calendar.MINUTE, 59);
todayEnd.set(Calendar.SECOND, 59);
todayEnd.set(Calendar.MILLISECOND, 999);
long time = todayEnd.getTimeInMillis() / 1000;
return (int) time;
}
/**
* 获取昨天零点的时间(字符串)
*/
public static String getYesterDayStartTimeStamp() {
SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND,0); //这是将【秒】设置为0
calendar.set(Calendar.MINUTE,0); //这是将【分】设置为0
calendar.set(Calendar.HOUR_OF_DAY,0); //这是将【时】设置为0
calendar.add(Calendar.DATE,-1); //当前日期加一
String yesterday = sdfYMD.format(calendar.getTime()); //获取昨天的时间 如2021-02-25 00:00:00
return yesterday;
}
/**
* 获取昨天零点的时间戳
*/
public static Integer getBeforeStartTime(){
Calendar todayStart = Calendar.getInstance();
todayStart.set(Calendar.HOUR_OF_DAY, 0);
todayStart.set(Calendar.MINUTE, 0);
todayStart.set(Calendar.SECOND, 0);
todayStart.set(Calendar.MILLISECOND, 0);
long time = todayStart.getTimeInMillis()/1000;
return (int)time-86400;
}
/**
* 获取昨天23:59:59的时间(字符串)
*/
public static String getYesterDayEndTimeStamp() {
SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND,59); //这是将当天的【秒】设置为0
calendar.set(Calendar.MINUTE,59); //这是将当天的【分】设置为0
calendar.set(Calendar.HOUR_OF_DAY,23); //这是将当天的【时】设置为0
calendar.add(Calendar.DATE,-1); //当前日期加一
String yesterday = sdfYMD.format(calendar.getTime()); //获取第二天的时间 2021-02-25 00:00:00
return yesterday;
}
/**
* 获取明天零点的时间戳
*/
public static Integer getAfterStartime()
{
Calendar todayStart = Calendar.getInstance();
todayStart.set(Calendar.HOUR_OF_DAY, 0);
todayStart.set(Calendar.MINUTE, 0);
todayStart.set(Calendar.SECOND, 0);
todayStart.set(Calendar.MILLISECOND, 0);
long time = todayStart.getTimeInMillis()/1000;
return (int)time+86400;
}
/**
* 将昨天凌晨时间转换为Date类型(下面设置成这样 new simpleDateFormat("yyyy-MM-dd HH:mm:ss") 数据中对应的字段类型就是DateTime)   * 这个方法中调用了上面的getYesterDayStartTimeStamp()方法哦
*/
public static Date getDateTime()
{
Date dateTime = null;
String yesterDayStartTimeStamp = getYesterDayStartTimeStamp();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
dateTime = formatter.parse(yesterDayStartTimeStamp);
}
catch (ParseException e)
{
e.printStackTrace();
}
//Sun May 09 00:00:00 CST 2021
return dateTime;
}
public static Long getBeforeByDayLongTime(int day){
LocalDateTime now = LocalDateTime.now();
now = now.minus(-day, ChronoUnit.DAYS);
return now.toEpochSecond(ZoneOffset.of("+8"));
}
/**
* 当前时间向推N天
* @param day 小时
* @return String
*/
public static String getBeforeByDayTime(int day){
LocalDateTime now = LocalDateTime.now();
now = now.minus(-day, ChronoUnit.DAYS);
return now.toString();
}
/**
* 日期范围 - 切片
*
*
* @param startDate 起始日期
* @param endDate 结束日期
* @param type 切片类型 1年 2月 3日 4小时
* @return 切片日期
*/
public static List<String> sliceUpDateRange(String startDate, String endDate ,int type) {
List<String> rs = new ArrayList<>();
try {
int dt = Calendar.DATE;
String pattern = "yyyy-MM-dd";
if (type==1) {
pattern = "yyyy";
dt = Calendar.YEAR;
} else if (type==2) {
pattern = "yyyy-MM";
dt = Calendar.MONTH;
} else if (type==3) {
pattern = "yyyy-MM-dd";
dt = Calendar.DATE;
}else if (type==4) {
pattern = "yyyy-MM-dd HH";
dt = Calendar.HOUR_OF_DAY;
}
SimpleDateFormat sd = new SimpleDateFormat(pattern);
Calendar sc = Calendar.getInstance();
Calendar ec = Calendar.getInstance();
sc.setTime(sd.parse(startDate));
ec.setTime(sd.parse(endDate));
while (sc.compareTo(ec) < 1) {
rs.add(sd.format(sc.getTime()));
sc.add(dt, 1);
}
} catch (ParseException e) {
e.printStackTrace();
}
return rs;
}
/**判断是否超过多少小时 如:24
*
* @param tableTime 业务时间
* @param hour 多少小时
* @return boolean true未超过 false超过
* @throws Exception
*/
public static boolean judgmentDate(String tableTime, Integer hour) throws Exception {
String currentTime = dateTimeNow(YYYY_MM_DD_HH_MM_SS);//当前时间
SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
Date start = sdf.parse(tableTime);//业务时间
Date end = sdf.parse(currentTime);//当前时间
long cha = end.getTime() - start.getTime();
if (cha < 0) {
return false;
}
double result = cha * 1.0 / (1000 * 60 * 60);
if (result <= hour) {
return true;//是小于等于 hour 小时
} else {
return false;
}
}
/**
* 当前时间向推几小时
* @param ihour 小时
* @return String
*/
public static String getBeforeByHourTime(int ihour){
String returnstr = "";
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - ihour);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
returnstr = df.format(calendar.getTime());
return returnstr;
}
/**
* 当前时间向前推n分钟
* @param minute
* @return
*/
public static String getBeforeByMinute(int minute){
Calendar beforeTime = Calendar.getInstance();
beforeTime.add(Calendar.MINUTE, -minute);// n分钟之前的时间
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return df.format(beforeTime.getTime());
}
/**
* 获取二个日期见相差多少天
* @param startdate
* @param enddate
* @return
* @throws ParseException
*/
public static int daysBetween(String startdate,String enddate) throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat(YYYY_MM_DD);
Calendar calendar = Calendar.getInstance();
calendar.setTime(sdf.parse(startdate));
long start = calendar.getTimeInMillis();
calendar.setTime(sdf.parse(enddate));
long end = calendar.getTimeInMillis();
long betweendays=(end-start)/(1000*3600*24);
int days = Integer.parseInt(String.valueOf(betweendays));
return days;
}
public static String initSqlBeginTime(String str){
if(ObjectUtil.isEmpty(str)){
str = dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
return str + " 00:00:00";
}
public static String initSqlEndTime(String str){
if(ObjectUtil.isEmpty(str)){
str = dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
return str + " 59:59:59";
}
/**
* 获得指定时间的前几天或后几天是哪一天
* @param oneday
* @param amount n
* @return
*/
public static Date daysAgoOrAfter(Date oneday,int amount){
Calendar mon = Calendar.getInstance();
mon.setTime(oneday);
mon.add(Calendar.DATE,amount);
return mon.getTime();
}
/**
* 判断当前时间是否在[startTime, endTime]区间,注意时间格式要一致
*
* @param nowTime 当前时间
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
if (nowTime.getTime() == startTime.getTime()
|| nowTime.getTime() == endTime.getTime()) {
return true;
}
Calendar date = Calendar.getInstance();
date.setTime(nowTime);
Calendar begin = Calendar.getInstance();
begin.setTime(startTime);
Calendar end = Calendar.getInstance();
end.setTime(endTime);
if (date.after(begin) && date.before(end)) {
return true;
} else {
return false;
}
}
/**
* 秒转化为:n小时k分这种
* @param diff
* @return
*/
public static String ShowTimeInterval(long diff) {
if(diff<60){
return diff+"秒";
}
long minutes = diff / 60;
long min = minutes % 60;
long hou = minutes / 60;
return hou+"小时"+min+"分";
}
public static String formatTime(Long ms) {
Integer ss = 1000;
Integer mi = ss * 60;
Integer hh = mi * 60;
Integer dd = hh * 24;
Long day = ms / dd;
Long hour = (ms - day * dd) / hh;
Long minute = (ms - day * dd - hour * hh) / mi;
Long second = (ms - day * dd - hour * hh - minute * mi) / ss;
// Long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
StringBuffer sb = new StringBuffer();
if(day > 0) {
sb.append(day+"天");
}
if(hour > 0) {
sb.append(hour+"小时");
}
if(minute > 0) {
sb.append(minute+"分");
}
if(second > 0) {
sb.append(second+"秒");
}
// if(milliSecond > 0) {
// sb.append(milliSecond+"毫秒");
// }
return sb.toString();
}
public static String getYesterday(String format){
// 获取当前日期
LocalDate today = LocalDate.now();
// 计算昨天的日期
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
// 创建日期格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
// 将昨天的日期转换为字符串
return yesterday.format(formatter);
}
/**
* 获取二个间的秒数
* @param startTime
* @param endTime
* @return
*/
public static long timeDifference(Date startTime,Date endTime){
// 计算两个时间点之间的秒数
Duration duration = Duration.between(LocalDateTime.ofInstant(endTime.toInstant(), ZoneId.systemDefault()),
LocalDateTime.ofInstant(startTime.toInstant(), ZoneId.systemDefault()));
return duration.getSeconds();
}
}
package com.yd.common.utils;
import com.yd.common.constant.SecurityConstants;
import com.yd.common.constant.TokenConstants;
import com.yd.common.core.text.Convert;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Map;
/**
* Jwt工具类
*/
public class JwtUtils {
public static String secret = TokenConstants.SECRET;
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
public static String createToken(Map<String, Object> claims) {
return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
public static Claims parseToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}
/**
* 根据令牌获取企业Id
*
* @param token 令牌
* @return 企业Id
*/
public static String getCorpId(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.CORP_ID.getCode());
}
/**
* 根据身份信息获取企业Id
*
* @param claims 身份信息
* @return 企业Id
*/
public static String getCorpId(Claims claims) {
return getValue(claims, SecurityConstants.Details.CORP_ID.getCode());
}
/**
* 根据令牌获取企业账号
*
* @param token 令牌
* @return 企业账号
*/
public static String getCorpName(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.CORP_NAME.getCode());
}
/**
* 根据身份信息获取企业账号
*
* @param claims 身份信息
* @return 企业账号
*/
public static String getCorpName(Claims claims) {
return getValue(claims, SecurityConstants.Details.CORP_NAME.getCode());
}
/**
* 根据令牌获取租户id
*
* @param token 身份信息
* @return 租户ID
*/
public static Integer getTenantId(String token) {
Claims claims = parseToken(token);
Integer tenantId = getIntValue(claims, SecurityConstants.Details.TENANT_ID.getCode());
if(tenantId != null){
return tenantId;
}else {
return null;
}
}
/**
* 根据身份信息获取企业账号
*
* @param claims 身份信息
* @return 企业账号
*/
public static Integer getTenantId(Claims claims) {
Integer tenantId = getIntValue(claims, SecurityConstants.Details.TENANT_ID.getCode());
if(tenantId != null){
return tenantId;
}else {
return null;
}
}
/**
* 根据令牌获取用户Id
*
* @param token 令牌
* @return 用户Id
*/
public static String getUserId(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.USER_ID.getCode());
}
/**
* 根据身份信息获取用户Id
*
* @param claims 身份信息
* @return 用户Id
*/
public static String getUserId(Claims claims) {
return getValue(claims, SecurityConstants.Details.USER_ID.getCode());
}
/**
* 根据令牌获取用户账号
*
* @param token 令牌
* @return 用户账号
*/
public static String getUserName(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.USER_NAME.getCode());
}
/**
* 根据身份信息获取用户账号
*
* @param claims 身份信息
* @return 用户账号
*/
public static String getUserName(Claims claims) {
return getValue(claims, SecurityConstants.Details.USER_NAME.getCode());
}
/**
* 根据令牌获取用户信息
*
* @param token 令牌
* @return 用户账号
*/
public static String getLoginUser(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.LOGIN_USER.getCode());
}
/**
* 根据身份信息获取用户用户信息
*
* @param claims 身份信息
* @return 用户账号
*/
public static String getLoginUser(Claims claims) {
return getValue(claims, SecurityConstants.Details.LOGIN_USER.getCode());
}
/**
* 根据身份信息获取用户类型
*
* @param claims 身份信息
* @return 用户类型
*/
public static String getUserType(Claims claims) {
return getValue(claims, SecurityConstants.Details.USER_TYPE.getCode());
}
/**
* 根据令牌获取用户类型
*
* @param token 令牌
* @return 用户类型
*/
public static String getUserType(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.USER_TYPE.getCode());
}
/**
* 根据令牌获取用户标识
*
* @param token 令牌
* @return 用户Id
*/
public static String getUserKey(String token) {
Claims claims = parseToken(token);
return getValue(claims, SecurityConstants.Details.USER_KEY.getCode());
}
/**
* 根据令牌获取用户标识
*
* @param claims 身份信息
* @return 用户Id
*/
public static String getUserKey(Claims claims) {
return getValue(claims, SecurityConstants.Details.USER_KEY.getCode());
}
/**
* 根据身份信息获取键值
*
* @param claims 身份信息
* @param key 键
* @return 值
*/
public static String getValue(Claims claims, String key) {
return Convert.toStr(claims.get(key), "");
}
/**
* 根据身份信息获取键值
*
* @param claims 身份信息
* @param key 键
* @return 值
*/
public static Integer getIntValue(Claims claims, String key) {
return Convert.toInt(claims.get(key));
}
}
package com.yd.common.utils;
import com.yd.common.enums.ErrorCode;
import com.yd.common.exception.BaseResponse;
/**
* 返回类型工具类
*
* @author zxm
*/
public class ResultUtils {
/**
* 成功
* @param data
* @param <T>
* @return
*/
public static <T> BaseResponse<T> success(T data) {
return new BaseResponse<>(0, data, "ok");
}
/**
* 成功
* @param data
* @return
*/
public static BaseResponse success(int data) {
return new BaseResponse(0, data, "ok");
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode){
return new BaseResponse<>(errorCode.getCode(),null,errorCode.getMessage(),errorCode.getDescription()) ;
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode, String message, String description){
return new BaseResponse<>(errorCode.getCode(),description) ;
}
/**
* 失败
* @param code
* @return
*/
public static BaseResponse error(int code,String message,String description){
return new BaseResponse<>(code,null,message,description) ;
}
/**
* 失败
* @param errorCode
* @return
*/
public static BaseResponse error(ErrorCode errorCode,String description){
return new BaseResponse<>(errorCode.getCode(),null,errorCode.getMessage(),description) ;
}
}
package com.yd.common.utils;
import cn.hutool.core.util.ObjectUtil;
import com.yd.common.constant.AuthorityConstants;
import com.yd.common.constant.SecurityConstants;
import com.yd.common.constant.TokenConstants;
import com.yd.common.context.SecurityContextHolder;
import com.yd.common.core.domain.model.LoginUser;
import com.yd.common.core.domain.model.WxLoginUser;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.servlet.http.HttpServletRequest;
/**
* 安全服务工具类
*
*/
public class SecurityUtils
{
/**
* 获取企业Id
* @return
*/
public static String getCorpId() {
return SecurityContextHolder.getCorpId();
}
/**
* 获取企业名称
* @return
*/
public static String getCorpName() {
return SecurityContextHolder.getCorpName();
}
/**
* 获取用户Id
*/
public static Long getUserId() {
return SecurityContextHolder.getUserId();
}
/**
* 获取用户
*/
public static String getUserName() {
return SecurityContextHolder.getUserName();
}
/**
* 获取用户权限标识
*/
public static String getUserType() {
return SecurityContextHolder.getUserType();
}
/**
* 获取用户key
*/
public static String getUserKey() {
return SecurityContextHolder.getUserKey();
}
/**
* 获取登录用户信息
*/
public static LoginUser getLoginUser() {
return SecurityContextHolder.get(SecurityConstants.Details.LOGIN_USER.getCode(), LoginUser.class);
}
public static WxLoginUser getWxLoginUser() {
return SecurityContextHolder.get(SecurityConstants.Details.LOGIN_USER.getCode(), WxLoginUser.class);
}
/**
* 获取请求token
*/
public static String getToken() {
return getToken(ServletUtils.getRequest());
}
/**
* 根据request获取请求token
*/
public static String getToken(HttpServletRequest request) {
// 从header获取token标识
String token = request.getHeader(TokenConstants.AUTHENTICATION);
return replaceTokenPrefix(token);
}
/**
* 裁剪token前缀
*/
public static String replaceTokenPrefix(String token) {
// 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
token = token.replaceFirst(TokenConstants.PREFIX, "");
}
return token;
}
/**
* 是否为超管用户
*
* @return 结果
*/
public static boolean isAdminUser() {
return ObjectUtil.equal(AuthorityConstants.UserType.ADMIN.getCode(),getUserType());
//return StringUtils.equals(AuthorityConstants.UserType.ADMIN.getCode(), getUserType());
}
/**
* 是否为超管租户
*
* @return 结果
*/
public static boolean isAdminTenant() {
// return StringUtils.equals(AuthorityConstants.TenantType.ADMIN.getCode(), getIsLessor());
return StringUtils.equals(AuthorityConstants.TenantType.ADMIN.getCode(), null);
}
/**
* 生成BCryptPasswordEncoder密码
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
}
package com.yd.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.yd.common.constant.Constants;
import com.yd.common.constant.HttpConstants;
import com.yd.common.core.text.Convert;
import com.yd.common.domain.R;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import reactor.core.publisher.Mono;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 客户端工具类
*
*
*/
public class ServletUtils {
/**
* 获取String参数
*/
public static String getParameter(String name) {
return getRequest().getParameter(name);
}
/**
* 获取String参数
*/
public static String getParameter(String name, String defaultValue) {
return Convert.toStr(getRequest().getParameter(name), defaultValue);
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name) {
return Convert.toInt(getRequest().getParameter(name));
}
/**
* 获取Integer参数
*/
public static Integer getParameterToInt(String name, Integer defaultValue) {
return Convert.toInt(getRequest().getParameter(name), defaultValue);
}
/**
* 获取request
*/
public static HttpServletRequest getRequest() {
return getRequestAttributes() == null ? null:getRequestAttributes().getRequest();
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
return getRequestAttributes().getResponse();
}
/**
* 获取session
*/
public static HttpSession getSession() {
return getRequest().getSession();
}
public static ServletRequestAttributes getRequestAttributes() {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
if(attributes == null){
return null;
}
return (ServletRequestAttributes) attributes;
}
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try {
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static String getHeader(HttpServletRequest request, String name)
{
String value = request.getHeader(name);
if (StringUtils.isEmpty(value))
{
return StringUtils.EMPTY;
}
return urlDecode(value);
}
public static Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
map.put(key, value);
}
}
return map;
}
/**
* 内容解码
*
* @param str 内容
* @return 解码后的内容
*/
public static String urlDecode(String str) {
try {
return URLDecoder.decode(str, HttpConstants.Character.UTF8.getCode());
} catch (UnsupportedEncodingException e) {
return StringUtils.EMPTY;
}
}
/**
* 是否是Ajax异步请求
*
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) {
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) {
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) {
return true;
}
return false;
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value) {
return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code) {
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value,
int code) {
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
}
/**
* 设置webflux模型响应
*
* @param response ServerHttpResponse
* @param contentType content-type
* @param status http状态码
* @param code 响应状态码
* @param value 响应内容
* @return Mono<Void>
*/
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status,
Object value, int code) {
response.setStatusCode(status);
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
R<?> result = R.fail(code, value.toString());
DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(result).getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
/**
* 内容编码
*
* @param str 内容
* @return 编码后的内容
*/
public static String urlEncode(String str) {
try {
return URLEncoder.encode(str, Constants.UTF8);
} catch (UnsupportedEncodingException e) {
return StringUtils.EMPTY;
}
}
}
package com.yd.common.utils;
import com.yd.common.core.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.util.*;
import java.util.regex.Pattern;
/**
* 字符串工具类
*
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
private static final String REGEX_MOBILE = "((\\+86|0086)?\\s*)((134[0-8]\\d{7})|(((13([0-3]|[5-9]))|(14[5-9])|15([0-3]|[5-9])|(16(2|[5-7]))|17([0-3]|[5-8])|18[0-9]|19(1|[8-9]))\\d{8})|(14(0|1|4)0\\d{7})|(1740([0-5]|[6-9]|[10-12])\\d{7}))";
/**
* 空字符串
*/
private static final String NULLSTR = "";
/**
* 下划线
*/
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空,包含List,Set,Queue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* * @return true:为空 false:非空
*/
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public static boolean isNull(Object object) {
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str) {
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
return NULLSTR;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULLSTR;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return NULLSTR;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
*/
public static String format(String template, Object... params) {
if (isEmpty(params) || isEmpty(template)) {
return template;
}
return StrFormatter.format(template, params);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static final Set<String> str2Set(String str, String sep) {
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) {
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && StringUtils.isBlank(string)) {
continue;
}
if (trim) {
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 下划线转驼峰命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs) {
if (str != null && strs != null) {
for (String s : strs) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如:user_name->userName
*/
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == SEPARATOR) {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
/**
* 将数组使用分隔符变为字符串
*
* @param array
* @param separator
* @return
*/
public static String join(Object[] array, String separator) {
return join(array, 0, array.length, separator);
}
private static String join(Object[] array, int startIndex, int endIndex, String separator) {
if (separator == null) {
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = startIndex; i < endIndex; i++) {
/**
* 在前面加,就不会出瑞最后多一个分隔符的现象同时判断不是第一个才加分隔符
*/
if (i > startIndex) {
sb.append(separator);
}
if (array[i] != null) {
sb.append(array[i]);
}
}
return sb.toString();
}
/**
* 企微用户客户机器判断
*
* @param str
* @return
*/
public static int weCustomTypeJudgment(String str) {
if (isNotEmpty(str)) {
if (str.startsWith("wo") || str.startsWith("wm")) {
return 1;
}
if (str.startsWith("wb")) {
return 2;
}
}
return 0;
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (isEmpty(str) || isEmpty(strs)) {
return false;
}
for (String pattern : strs) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
/**
* 判断是否是手机号
*
* @param tel 手机号
* @return boolean true:是 false:否
*/
public static boolean isMobile(String tel) {
if (StringUtils.isEmpty(tel)) {
return false;
}
return Pattern.matches(REGEX_MOBILE, tel);
}
public static void main(String[] args) {
Integer[] arrays = {1, 2, 3, 4, 5, 6, 7};
String join = join(arrays, ",");
System.out.println(join);// 1,2,3,4,5,6,7
}
/**
* 生成指定位数的随机字符串
*
* @param length
* @return
*/
public static String getRandomString(int length) {
//1. 定义一个字符串(A-Z,a-z,0-9)即62个数字字母;
String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
//2. 由Random生成随机数
Random random = new Random();
StringBuffer sb = new StringBuffer();
//3. 长度为几就循环几次
for (int i = 0; i < length; ++i) {
//从62个的数字或字母中选择
int number = random.nextInt(62);
//将产生的数字通过length次承载到sb中
sb.append(str.charAt(number));
}
//将承载的字符转换成字符串
return sb.toString();
}
/**
* 转译特殊符号
*
* @param query
* @return
*/
public static String queryReplace(String query) {
if (StringUtils.isBlank(query)) {
return query;
}
return query
.replace("%", "\\" + "%")
.replace("_", "\\" + "_")
.replace("'", "\\" + "'")
.replace("\"", "\\" + "\"");
}
}
package com.yd.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import com.linkwechat.common.utils.StringUtils;
import com.linkwechat.common.utils.file.FileUtil;
import com.linkwechat.common.utils.spring.SpringUtils;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.linkwechat.common.annotation.Excel;
import com.linkwechat.common.annotation.Excel.ColumnType;
import com.linkwechat.common.annotation.Excel.Type;
import com.linkwechat.common.annotation.Excels;
import com.linkwechat.common.config.LinkWeChatConfig;
import com.linkwechat.common.core.domain.AjaxResult;
import com.linkwechat.common.core.text.Convert;
import com.linkwechat.common.exception.CustomException;
import com.linkwechat.common.utils.DateUtils;
import com.linkwechat.common.utils.DictUtils;
import com.linkwechat.common.utils.reflect.ReflectUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
/**
* Excel相关处理(当前导出工具类已废弃请使用easyExcel)
*
*
*/
@Deprecated
public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
/**
* Excel sheet最大行数,默认65536
*/
public static final int sheetSize = 65536;
/**
* 工作表名称
*/
private String sheetName;
/**
* 导出类型(EXPORT:导出数据;IMPORT:导入模板)
*/
private Type type;
/**
* 工作薄对象
*/
private Workbook wb;
/**
* 工作表对象
*/
private Sheet sheet;
/**
* 样式列表
*/
private Map<String, CellStyle> styles;
/**
* 导入导出数据列表
*/
private List<T> list;
/**
* 注解列表
*/
private List<Object[]> fields;
/**
* 实体对象
*/
public Class<T> clazz;
public ExcelUtil(Class<T> clazz)
{
this.clazz = clazz;
}
public void init(List<T> list, String sheetName, Type type)
{
if (list == null)
{
list = new ArrayList<T>();
}
this.list = list;
this.sheetName = sheetName;
this.type = type;
createExcelField();
createWorkbook();
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream is) throws Exception
{
return importExcel(StringUtils.EMPTY, is);
}
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream is) throws Exception
{
this.type = Type.IMPORT;
this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>();
Sheet sheet = null;
if (StringUtils.isNotEmpty(sheetName))
{
// 如果指定sheet名,则取指定sheet中的内容.
sheet = wb.getSheet(sheetName);
}
else
{
// 如果传入的sheet名不存在则默认指向第1个sheet.
sheet = wb.getSheetAt(0);
}
if (sheet == null)
{
throw new IOException("文件sheet不存在");
}
int rows = sheet.getPhysicalNumberOfRows();
if (rows > 0)
{
// 定义一个map用于存放excel列的序号和field.
Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头
Row heard = sheet.getRow(0);
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
{
Cell cell = heard.getCell(i);
if (StringUtils.isNotNull(cell))
{
String value = this.getCellValue(heard, i).toString();
cellMap.put(value, i);
}
else
{
cellMap.put(null, i);
}
}
// 有数据时才处理 得到类的所有field.
Field[] allFields = clazz.getDeclaredFields();
// 定义一个map用于存放列的序号和field.
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
for (int col = 0; col < allFields.length; col++)
{
Field field = allFields[col];
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
// 设置类的私有字段属性可访问.
field.setAccessible(true);
Integer column = cellMap.get(attr.name());
if (column != null)
{
fieldsMap.put(column, field);
}
}
}
for (int i = 1; i < rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
T entity = null;
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
{
Object val = this.getCellValue(row, entry.getKey());
// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = fieldsMap.get(entry.getKey());
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}
else
{
val = Convert.toStr(val);
}
}
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
{
val = Convert.toInt(val);
}
else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
{
val = Convert.toLong(val);
}
else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
{
val = Convert.toDouble(val);
}
else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
{
val = Convert.toFloat(val);
}
else if (BigDecimal.class == fieldType)
{
val = Convert.toBigDecimal(val);
}
else if (Date.class == fieldType)
{
if (val instanceof String)
{
val = DateUtils.parseDate(val);
}
else if (val instanceof Double)
{
val = DateUtil.getJavaDate((Double) val);
}
}
if (StringUtils.isNotNull(fieldType))
{
Excel attr = field.getAnnotation(Excel.class);
String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr()))
{
propertyName = field.getName() + "." + attr.targetAttr();
}
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
}
else if (StringUtils.isNotEmpty(attr.dictType()))
{
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
list.add(entity);
}
}
return list;
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult exportExcel(List<T> list, String sheetName)
{
this.init(list, sheetName, Type.EXPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @param sheetName 工作表的名称
* @return 结果
*/
public AjaxResult importTemplateExcel(String sheetName)
{
this.init(null, sheetName, Type.IMPORT);
return exportExcel();
}
/**
* 对list数据源将其里面的数据导入到excel表单
*
* @return 结果
*/
public AjaxResult exportExcel()
{
OutputStream out = null;
try
{
// 取出一共有多少个sheet.
double sheetNo = Math.ceil(list.size() / sheetSize);
for (int index = 0; index <= sheetNo; index++)
{
createSheet(sheetNo, index);
// 产生一行
Row row = sheet.createRow(0);
int column = 0;
// 写入各个字段的列头名称
for (Object[] os : fields)
{
Excel excel = (Excel) os[1];
this.createCell(excel, row, column++);
}
if (Type.EXPORT.equals(type))
{
fillExcelData(index, row);
}
}
String filename = encodingFilename(sheetName);
out = new FileOutputStream(getAbsoluteFile(filename));
wb.write(out);
return AjaxResult.success(filename);
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new CustomException("导出Excel失败,请联系网站管理员!");
}
finally
{
if (wb != null)
{
try
{
wb.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
if (out != null)
{
try
{
out.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
}
}
/**
* 填充excel数据
*
* @param index 序号
* @param row 单元格行
*/
public void fillExcelData(int index, Row row)
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
for (int i = startNo; i < endNo; i++)
{
row = sheet.createRow(i + 1 - startNo);
// 得到导出对象.
T vo = (T) list.get(i);
int column = 0;
for (Object[] os : fields)
{
Field field = (Field) os[0];
Excel excel = (Excel) os[1];
// 设置实体类私有属性可访问
field.setAccessible(true);
this.addCell(excel, row, vo, field, column++);
}
}
}
/**
* 创建表格样式
*
* @param wb 工作薄对象
* @return 样式列表
*/
private Map<String, CellStyle> createStyles(Workbook wb)
{
// 写入各条记录,每条记录对应excel表中的一行
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
CellStyle style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
style.setFont(dataFont);
styles.put("data", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
Font headerFont = wb.createFont();
headerFont.setFontName("Arial");
headerFont.setFontHeightInPoints((short) 10);
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont);
styles.put("header", style);
return styles;
}
/**
* 创建单元格
*/
public Cell createCell(Excel attr, Row row, int column)
{
// 创建列
Cell cell = row.createCell(column);
// 写入列信息
cell.setCellValue(attr.name());
setDataValidation(attr, row, column);
cell.setCellStyle(styles.get("header"));
return cell;
}
/**
* 设置单元格信息
*
* @param value 单元格值
* @param attr 注解相关
* @param cell 单元格信息
*/
public void setCellVo(Object value, Excel attr, Cell cell)
{
if (ColumnType.STRING == attr.cellType())
{
cell.setCellType(CellType.STRING);
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
}
else if (ColumnType.NUMERIC == attr.cellType())
{
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(Integer.parseInt(value + ""));
}
}
/**
* 创建表格样式
*/
public void setDataValidation(Excel attr, Row row, int column)
{
if (attr.name().indexOf("注:") >= 0)
{
sheet.setColumnWidth(column, 6000);
}
else
{
// 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
}
// 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt()))
{
// 这里默认设了2-101列提示.
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
}
}
/**
* 添加单元格
*/
public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
{
Cell cell = null;
try
{
// 设置行高
row.setHeight((short) (attr.height() * 20));
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport())
{
// 创建cell
cell = row.createCell(column);
cell.setCellStyle(styles.get("data"));
// 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
String separator = attr.separator();
String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
}
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{
cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
}
else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
{
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));
}
else if (value instanceof BigDecimal && -1 != attr.scale())
{
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
}
else
{
// 设置列类型
setCellVo(value, attr, cell);
}
}
}
catch (Exception e)
{
log.error("导出Excel失败{}", e);
}
return cell;
}
/**
* 设置 POI XSSFSheet 单元格提示
*
* @param sheet 表单
* @param promptTitle 提示标题
* @param promptContent 提示内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
*/
public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
int firstCol, int endCol)
{
DataValidationHelper helper = sheet.getDataValidationHelper();
DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
DataValidation dataValidation = helper.createValidation(constraint, regions);
dataValidation.createPromptBox(promptTitle, promptContent);
dataValidation.setShowPromptBox(true);
sheet.addValidationData(dataValidation);
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
{
DataValidationHelper helper = sheet.getDataValidationHelper();
// 加载下拉列表内容
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, regions);
// 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation)
{
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
}
else
{
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation);
}
/**
* 解析导出值 0=男,1=女,2=未知
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
*/
public static String convertByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[0].equals(value))
{
propertyString.append(itemArray[1] + separator);
break;
}
}
}
else
{
if (itemArray[0].equals(propertyValue))
{
return itemArray[1];
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 反向解析值 男=0,女=1,未知=2
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
*/
public static String reverseByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[1].equals(value))
{
propertyString.append(itemArray[0] + separator);
break;
}
}
}
else
{
if (itemArray[1].equals(propertyValue))
{
return itemArray[0];
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 解析字典值
*
* @param dictValue 字典值
* @param dictType 字典类型
* @param separator 分隔符
* @return 字典标签
*/
public static String convertDictByExp(String dictValue, String dictType, String separator)
{
return DictUtils.getDictLabel(dictType, dictValue, separator);
}
/**
* 反向解析值字典值
*
* @param dictLabel 字典标签
* @param dictType 字典类型
* @param separator 分隔符
* @return 字典值
*/
public static String reverseDictByExp(String dictLabel, String dictType, String separator)
{
return DictUtils.getDictValue(dictType, dictLabel, separator);
}
/**
* 编码文件名
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
// filename = UUID.randomUUID().toString() + "_" + filename;
return filename;
}
/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename) {
String downloadPath = LinkWeChatConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
return downloadPath;
}
/**
* 获取bean中的属性值
*
* @param vo 实体对象
* @param field 字段
* @param excel 注解
* @return 最终的属性值
* @throws Exception
*/
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{
Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr()))
{
String target = excel.targetAttr();
if (target.indexOf(".") > -1)
{
String[] targets = target.split("[.]");
for (String name : targets)
{
o = getValue(o, name);
}
}
else
{
o = getValue(o, target);
}
}
return o;
}
/**
* 以类的属性的get方法方法形式获取值
*
* @param o
* @param name
* @return value
* @throws Exception
*/
private Object getValue(Object o, String name) throws Exception
{
if (StringUtils.isNotEmpty(name))
{
Class<?> clazz = o.getClass();
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method method = clazz.getMethod(methodName);
o = method.invoke(o);
}
return o;
}
/**
* 得到所有定义字段
*/
private void createExcelField()
{
this.fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields)
{
// 单注解
if (field.isAnnotationPresent(Excel.class))
{
putToField(field, field.getAnnotation(Excel.class));
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel excel : excels)
{
putToField(field, excel);
}
}
}
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
}
/**
* 放到字段集合中
*/
private void putToField(Field field, Excel attr)
{
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
this.fields.add(new Object[] { field, attr });
}
}
/**
* 创建一个工作簿
*/
public void createWorkbook()
{
this.wb = new SXSSFWorkbook(500);
}
/**
* 创建工作表
*
* @param sheetNo sheet数量
* @param index 序号
*/
public void createSheet(double sheetNo, int index)
{
this.sheet = wb.createSheet();
this.styles = createStyles(wb);
// 设置工作表的名称.
if (sheetNo == 0)
{
wb.setSheetName(index, sheetName);
}
else
{
wb.setSheetName(index, sheetName + index);
}
}
/**
* 获取单元格值
*
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
*/
public Object getCellValue(Row row, int column)
{
if (row == null)
{
return row;
}
Object val = "";
try
{
Cell cell = row.getCell(column);
if (StringUtils.isNotNull(cell))
{
if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA)
{
val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell))
{
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
}
else
{
if ((Double) val % 1 > 0)
{
val = new BigDecimal(val.toString());
}
else
{
val = new DecimalFormat("0").format(val);
}
}
}
else if (cell.getCellTypeEnum() == CellType.STRING)
{
val = cell.getStringCellValue();
}
else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
{
val = cell.getBooleanCellValue();
}
else if (cell.getCellTypeEnum() == CellType.ERROR)
{
val = cell.getErrorCellValue();
}
}
}
catch (Exception e)
{
return val;
}
return val;
}
}
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-email</artifactId>
<description>邮箱模块</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-email</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-feign</artifactId>
<description>Feign组件模块</description>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
\ No newline at end of file
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-fileservice</artifactId>
<description>文件服务模块</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-fileservice</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.yd.fileservice;
import com.yd.common.constant.WeServerNameConstants;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
/**
* 文件服务
*
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
public class FileApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(FileApplication.class)
.properties("spring.config.name:bootstrap", "config/bootstrap.yml")
.properties("spring.application.name="+ WeServerNameConstants.ydFile)
.build().run(args);
System.out.println("(♥◠‿◠)ノ゙ yd-fileservice启动成功 ლ(´ڡ`ლ)゙ ");
}
}
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ _____ _ _
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_| ___(_) | ___
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __| |_ | | |/ _ \
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_| _| | | | __/
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__|_| |_|_|\___|
${AnsiColor.BRIGHT_WHITE}
Spring Application Name: ${spring.application.name}
Spring Application Name: ${spring.application.name}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n"/>
<!-- 邮件 -->
<!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
<property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
<!-- SMTP server的端口地址。默认值:25 -->
<property name="smtpPort" value="25"/>
<!-- 发送邮件账号,默认为null -->
<property name="username" value="*"/><!--发件人账号-->
<!-- 发送邮件密码,默认为null -->
<property name="password" value="*"/><!--发件人密码-->
<!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
<property name="SSL" value="true"/>
<!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
<property name="email_to" value="*"/>
<!--收件人账号多个可以逗号隔开-->
<!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
<property name="email_from" value="1" />
<!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
<property name="email_subject" value="【yd-file】【Error】: %logger" />
<property name="app_name" value="yd-file"/>
<!-- 日志根目录-->
<springProperty scope="context" name="log.path" source="logging.path"
defaultValue="./logs/yd-file"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug/${app_name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_debug"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info/${app_name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn/${app_name}.warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_warn"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${app_name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- ERROR邮件发送 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>${smtpHost}</smtpHost>
<smtpPort>${smtpPort}</smtpPort>
<username>${username}</username>
<password>${password}</password>
<!-- <asynchronousSending>true</asynchronousSending>-->
<SSL>${SSL}</SSL>
<!--<STARTTLS>true</STARTTLS>-->
<to>${email_to}</to>
<from>${email_from}</from>
<subject>${email_subject}</subject>
<!-- html格式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<Pattern>%date%level%thread%logger{0}%line%message</Pattern>
</layout>
<!-- 这里采用等级过滤器 指定等级相符才发送 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- 每个电子邮件只发送一个日志条目 -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="cn.yd" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="arollingfile_debug" />
<appender-ref ref="arollingfile_info" />
<appender-ref ref="arollingfile_warn" />
<appender-ref ref="arollingfile_error" />
<!-- <appender-ref ref="alarm_error" />-->
<appender-ref ref="EMAIL" />
</root>
</configuration>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-framework</artifactId>
<description>框架配置</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot 拦截器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-framework</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-gateway</artifactId>
<description>网关服务</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- SpringCloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.1.1</version>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.1</version>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.1</version>
</dependency>
<!-- SpringCloud Alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
<!-- SpringCloud Alibaba Sentinel Gateway -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2021.1</version>
</dependency>
<!-- Sentinel Datasource Nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-common</artifactId>
<version>2.9.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>yd-gateway</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.yd.gateway;
import com.yd.common.config.fegin.FeginConfig;
import com.yd.common.constant.WeServerNameConstants;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 网关启动程序
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class})
@EnableFeignClients(basePackages="com.yd.**",defaultConfiguration = FeginConfig.class)
public class GatewayApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(GatewayApplication.class)
.properties("spring.config.name:bootstrap", "config/run/bootstrap.yml")
.properties("spring.application.name="+ WeServerNameConstants.ydGateway)
.build().run(args);
System.out.println("(♥◠‿◠)ノ゙ yd-gateway启动成功 ლ(´ڡ`ლ)゙ ");
}
}
package com.yd.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* 跨域配置
*/
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
package com.yd.gateway.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.yd.common.constant.CacheConstants;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.util.List;
/**
* @author leejoker
* @version 1.0
* @date 2021/11/24 10:30
*/
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
List<RouteDefinition> routeDefinitions = Lists.newArrayList();
stringRedisTemplate.opsForHash().values(CacheConstants.GATEWAY_ROUTES).forEach(routeDefinition -> routeDefinitions.add(
JSON.parseObject(routeDefinition.toString(), RouteDefinition.class)));
return Flux.fromIterable(routeDefinitions);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(routeDefinition -> {
stringRedisTemplate.opsForHash()
.put(CacheConstants.GATEWAY_ROUTES, routeDefinition.getId(), JSONObject.toJSONString(routeDefinition));
return Mono.empty();
});
}
@Override
public Mono<Void> delete(Mono<String> routeId) {
return routeId.flatMap(id -> {
if (stringRedisTemplate.opsForHash().hasKey(CacheConstants.GATEWAY_ROUTES, id)) {
stringRedisTemplate.opsForHash().delete(CacheConstants.GATEWAY_ROUTES, id);
return Mono.empty();
}
return Mono.defer(
() -> Mono.error(new NotFoundException("route definition is not found, routeId:" + routeId)));
});
}
}
package com.yd.gateway.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* 放行白名单配置
*/
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.ignore")
public class IgnoreWhiteProperties {
/**
* 放行白名单配置,网关不校验此处的白名单
*/
private List<String> whites = new ArrayList<>();
public List<String> getWhites() {
return whites;
}
public void setWhites(List<String> whites) {
this.whites = whites;
}
}
package com.yd.gateway.filter;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.yd.common.constant.CacheConstants;
import com.yd.common.constant.HttpStatus;
import com.yd.common.constant.SecurityConstants;
import com.yd.common.constant.TokenConstants;
import com.yd.common.core.domain.model.LoginUser;
import com.yd.common.core.domain.model.WxLoginUser;
import com.yd.common.core.redis.RedisService;
import com.yd.common.utils.JwtUtils;
import com.yd.common.utils.ServletUtils;
import com.yd.common.utils.StringUtils;
import com.yd.gateway.config.properties.IgnoreWhiteProperties;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
/**
* 网关鉴权
*/
@Component
public class AuthFilter implements GlobalFilter, Ordered {
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
// 排除过滤的 uri 地址,nacos自行添加
@Resource
private IgnoreWhiteProperties ignoreWhite;
@Resource
private RedisService redisService;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpRequest.Builder mutate = request.mutate();
String url = request.getURI().getPath();
// 跳过不需要验证的路径
if (StringUtils.matches(url, ignoreWhite.getWhites())) {
return chain.filter(exchange);
}
String token = getToken(request);
if (StringUtils.isEmpty(token)) {
return unauthorizedResponse(exchange, "令牌不能为空");
}
try {
Claims claims = JwtUtils.parseToken(token);
if (claims == null) {
return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
}
String userKey = JwtUtils.getUserKey(claims);
boolean islogin = redisService.hasKey(getTokenKey(userKey));
if (!islogin) {
return unauthorizedResponse(exchange, "登录状态已过期");
}
/** 登陆类型 **/
//之后改为策略模式
String loginType = JwtUtils.getValue(claims, SecurityConstants.LOGIN_TYPE);
addHeader(mutate, SecurityConstants.LOGIN_TYPE, loginType);
if (StringUtils.isNotEmpty(loginType) && loginType.equals("WXAPI")) {
WxLoginUser wxLoginUser = getWxLoginUser(token);
// 设置用户信息到请求
addHeader(mutate, SecurityConstants.LOGIN_USER, JSONObject.toJSONString(wxLoginUser));
} else {
String corpId = JwtUtils.getCorpId(claims);
String corpName = JwtUtils.getCorpName(claims);
String userId = JwtUtils.getUserId(claims);
String userName = JwtUtils.getUserName(claims);
String userType = JwtUtils.getUserType(claims);
LoginUser loginUser = getLoginUser(token);
//String loginUser = JwtUtils.getLoginUser(claims);
// 设置用户信息到请求
addHeader(mutate, SecurityConstants.CORP_ID, corpId);
addHeader(mutate, SecurityConstants.CORP_NAME, corpName);
addHeader(mutate, SecurityConstants.USER_ID, userId);
addHeader(mutate, SecurityConstants.USER_NAME, userName);
addHeader(mutate, SecurityConstants.USER_TYPE, userType);
addHeader(mutate, SecurityConstants.USER_KEY, userKey);
addHeader(mutate, SecurityConstants.LOGIN_USER, JSONObject.toJSONString(loginUser));
}
} catch (Exception e) {
return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
}
// 内部请求来源参数清除
removeHeader(mutate, SecurityConstants.FROM_SOURCE);
return chain.filter(exchange.mutate().request(mutate.build()).build());
}
private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
if (value == null) {
return;
}
String valueStr = value.toString();
String valueEncode = ServletUtils.urlEncode(valueStr);
mutate.header(name, valueEncode);
}
private void removeHeader(ServerHttpRequest.Builder mutate, String name) {
mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
}
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
log.error("[鉴权异常处理]请求路径:{},msg:{}", exchange.getRequest().getPath(), msg);
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
}
/**
* 获取缓存key
*/
private String getTokenKey(String token) {
return CacheConstants.LOGIN_TOKEN_KEY + token;
}
/**
* 获取请求token
*/
private String getToken(ServerHttpRequest request) {
String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
if (StrUtil.isBlank(token)) {
//判断是否是websocket链接
String connection = request.getHeaders().getFirst("Connection");
String upgrade = request.getHeaders().getFirst("Upgrade");
if ("Upgrade".equals(connection) && "websocket".equals(upgrade)) {
token = request.getHeaders().getFirst("Sec-WebSocket-Protocol");
}
}
// 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
}
return token;
}
@Override
public int getOrder() {
return -200;
}
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(String token) {
try {
if (StringUtils.isNotEmpty(token)) {
String userKey = JwtUtils.getUserKey(token);
return redisService.getCacheObject(getTokenKey(userKey));
}
} catch (Exception ignored) {
}
return null;
}
public WxLoginUser getWxLoginUser(String token) {
try {
if (StringUtils.isNotEmpty(token)) {
String userKey = JwtUtils.getUserKey(token);
return redisService.getCacheObject(getTokenKey(userKey));
}
} catch (Exception ignored) {
}
return null;
}
}
package com.yd.gateway.handler;
import com.yd.common.utils.ServletUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 网关统一异常处理
*
* @author leejoker
*/
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
String msg;
if (ex instanceof NotFoundException) {
msg = "服务未找到";
} else if (ex instanceof ResponseStatusException) {
ResponseStatusException responseStatusException = (ResponseStatusException) ex;
msg = responseStatusException.getMessage();
} else {
msg = "内部服务器错误";
}
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
return ServletUtils.webFluxResponseWriter(response, msg);
}
}
package com.yd.gateway.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.yd.common.constant.CacheConstants;
import com.yd.common.core.redis.RedisService;
import com.yd.common.utils.StringUtils;
import com.yd.gateway.config.RedisRouteDefinitionRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* 网关动态路由服务
* 核心功能:通过监听Nacos配置中心,实现网关路由规则的动态更新
*
* 工作流程:
* 1. 初始化时从Nacos加载路由配置
* 2. 注册Nacos监听器实时接收配置变更
* 3. 将路由规则持久化到Redis
* 4. 通过Spring事件机制刷新网关路由
*/
@Service
@Slf4j
public class GatewayDynamicRouteService implements ApplicationEventPublisherAware {
@Resource
private RedisRouteDefinitionRepository redisRouteDefinitionRepository; // 路由存储仓库
@Resource
private RedisService redisService; // Redis操作服务
private ApplicationEventPublisher applicationEventPublisher; // Spring事件发布器
private ConfigService configService; // Nacos配置服务客户端
private static final long timeout = 30000L; // Nacos配置读取超时时间(30秒)
// Nacos配置参数
@Value("${nacos.gateway.route.config.data-id:gateway-router}")
private String dataId; // 路由配置的dataId(默认gateway-router)
@Value("${nacos.gateway.route.config.group:DEFAULT_GROUP}")
private String routeGroup; // 路由配置的分组(默认DEFAULT_GROUP)
@Value("${spring.cloud.nacos.discovery.server-addr}")
private String serverAddress; // Nacos服务器地址
@Value("${spring.cloud.nacos.discovery.namespace:}")
private String namespace; // Nacos命名空间(可选)
// 设置Spring事件发布器
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* 初始化方法 - 服务启动时执行
* 1. 清空旧路由缓存
* 2. 初始化Nacos配置服务
* 3. 加载初始路由配置
* 4. 注册配置变更监听器
*/
@PostConstruct
public void init() {
log.info("网关路由初始化开始...");
// 步骤1: 清空Redis中的旧路由缓存
redisService.deleteObject(CacheConstants.GATEWAY_ROUTES);
try {
// 步骤2: 初始化Nacos配置服务客户端
configService = initConfigService();
if (configService == null) {
log.warn("Nacos配置服务初始化失败");
return;
}
// 步骤3: 从Nacos获取初始路由配置
String configInfo = configService.getConfig(dataId, routeGroup, timeout);
log.info("从Nacos获取网关路由配置:\r\n{}", configInfo);
// 步骤4: 解析JSON配置为路由定义对象
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
for (RouteDefinition definition : definitionList) {
log.info("添加路由: {}", definition.toString());
add(definition); // 添加到网关
}
} catch (Exception e) {
log.error("网关路由初始化过程中发生错误", e);
}
// 步骤5: 注册Nacos配置变更监听器
dynamicRouteByNacosListener(dataId, routeGroup);
}
/**
* 初始化Nacos配置服务
* @return ConfigService实例
*/
private ConfigService initConfigService() {
try {
Properties properties = new Properties();
properties.setProperty("serverAddr", serverAddress); // 设置Nacos服务器地址
// 如果配置了命名空间,则添加命名空间参数
if (StringUtils.isNotBlank(namespace)) {
properties.setProperty("namespace", namespace);
}
// 创建Nacos配置服务实例
return NacosFactory.createConfigService(properties);
} catch (Exception e) {
log.error("创建Nacos配置服务失败", e);
return null;
}
}
/**
* 注册Nacos配置变更监听器
* @param dataId 配置ID
* @param group 配置分组
*/
public void dynamicRouteByNacosListener(String dataId, String group) {
try {
// 添加Nacos配置监听器
configService.addListener(dataId, group, new Listener() {
/**
* 当配置变更时的回调方法
* @param configInfo 变更后的新配置内容
*/
@Override
public void receiveConfigInfo(String configInfo) {
log.info("接收到网关路由配置变更通知:\n\r{}", configInfo);
// 解析新配置为路由定义列表
List<RouteDefinition> definitionList = JSON.parseArray(configInfo, RouteDefinition.class);
log.info("更新路由: {}", definitionList);
// 遍历更新每个路由规则
definitionList.forEach(route -> update(route));
}
/**
* 获取监听器执行器
* @return 执行器实例(返回null使用默认线程池)
*/
@Override
public Executor getExecutor() {
log.info("获取Nacos监听器执行器");
return null; // 使用默认线程池
}
});
} catch (NacosException e) {
log.error("注册Nacos配置监听器失败", e);
}
}
/**
* 获取所有路由定义
* @return 路由定义流
*/
public Flux<RouteDefinition> list() {
return redisRouteDefinitionRepository.getRouteDefinitions();
}
/**
* 添加新路由
* @param routeDefinition 路由定义对象
* @return 操作结果(1=成功)
*/
public int add(RouteDefinition routeDefinition) {
// 1. 保存路由到Redis
redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
// 2. 发布路由刷新事件
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
return 1; // 返回成功标识
}
/**
* 更新路由
* @param routeDefinition 新的路由定义
* @return 操作结果(1=成功)
*/
public int update(RouteDefinition routeDefinition) {
// 1. 先删除旧路由
redisRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId()));
// 2. 再添加新路由
return add(routeDefinition);
}
/**
* 删除路由
* @param id 路由ID
* @return 响应对象(Mono流式响应)
*/
public Mono<ResponseEntity<Object>> delete(String id) {
// 1. 从Redis删除路由
return redisRouteDefinitionRepository.delete(Mono.just(id))
// 2. 删除成功返回200 OK
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
// 3. 处理路由不存在的异常(返回404 Not Found)
.onErrorResume(t -> t instanceof NotFoundException,
t -> Mono.just(ResponseEntity.notFound().build()));
}
}
package com.yd.gateway.service;
import com.yd.common.constant.CacheConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.SmartLifecycle;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import reactor.core.Disposable;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import reactor.retry.Repeat;
import javax.annotation.Resource;
import java.time.Duration;
@Slf4j
@Component
public class GatewayVersionSmartLifeCycle implements SmartLifecycle {
private boolean isRunning = false;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Autowired
private GatewayDynamicRouteService publisher;
private Disposable disposable;
@Override
public void start() {
/* 每10秒检查当前route version是否最新 不是最新时刷新
* 监听 RefreshRoutesResultEvent 得到刷新结果
* 刷新失败的原因大概率是因为路由规则设置错误 失败时重置版本为 0 不断重试
*/
disposable =
Mono.defer(() -> {
if(!stringRedisTemplate.hasKey(CacheConstants.GATEWAY_ROUTES)){
//重新初始化
this.publisher.init();
}
return Mono.empty();
})
.repeatWhen(
Repeat.onlyIf(repeatContext -> true)
.fixedBackoff(Duration.ofSeconds(1)))
.subscribeOn(Schedulers.boundedElastic()).subscribe();
isRunning = true;
}
@Override
public void stop() {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
isRunning = false;
}
@Override
public boolean isRunning() {
return isRunning;
}
}
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ ____ _ __ __
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_ / ___| __ _| |_ __\ \ / /_ _ _ _
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __| | _ / _` | __/ _ \ \ /\ / / _` | | | |
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_| |_| | (_| | || __/\ V V / (_| | |_| |
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__|\____|\__,_|\__\___| \_/\_/ \__,_|\__, |
|___/
${AnsiColor.BRIGHT_WHITE}
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
<!-- 邮件 -->
<!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
<property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
<!-- SMTP server的端口地址。默认值:25 -->
<property name="smtpPort" value="25"/>
<!-- 发送邮件账号,默认为null -->
<property name="username" value="*"/><!--发件人账号-->
<!-- 发送邮件密码,默认为null -->
<property name="password" value="*"/><!--发件人密码-->
<!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
<property name="SSL" value="true"/>
<!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
<property name="email_to" value="*"/>
<!--收件人账号多个可以逗号隔开-->
<!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
<property name="email_from" value="1" />
<!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
<property name="email_subject" value="【yd-gateway】【Error】: %logger" />
<property name="app_name" value="yd-gateway"/>
<!-- 日志根目录-->
<springProperty scope="context" name="log.path" source="logging.path"
defaultValue="./logs/yd-gateway"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug/${app_name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_debug"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info/${app_name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn/${app_name}.warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_warn"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${app_name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- ERROR邮件发送 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>${smtpHost}</smtpHost>
<smtpPort>${smtpPort}</smtpPort>
<username>${username}</username>
<password>${password}</password>
<!-- <asynchronousSending>true</asynchronousSending>-->
<SSL>${SSL}</SSL>
<!--<STARTTLS>true</STARTTLS>-->
<to>${email_to}</to>
<from>${email_from}</from>
<subject>${email_subject}</subject>
<!-- html格式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<Pattern>%date%level%thread%logger{0}%line%message</Pattern>
</layout>
<!-- 这里采用等级过滤器 指定等级相符才发送 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- 每个电子邮件只发送一个日志条目 -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="cn.yd" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="arollingfile_debug" />
<appender-ref ref="arollingfile_info" />
<appender-ref ref="arollingfile_warn" />
<appender-ref ref="arollingfile_error" />
<!-- <appender-ref ref="alarm_error" />-->
<appender-ref ref="EMAIL" />
</root>
</configuration>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-order-api</artifactId>
<description>订单接口模块(订单个性化定制接口及实现的能力,不和数据库直接交互,需要调用对应service模块和数据库交互)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- feign组件模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
</dependency>
<!-- 订单基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-order-service</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-order-api</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-order-service</artifactId>
<description>订单实现模块(数据库直接交互,提供基础服务实现的能力)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-order-service</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-pay-api</artifactId>
<description>支付接口模块(支付个性化定制接口及实现的能力,不和数据库直接交互,需要调用对应service模块和数据库交互)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- feign组件模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
</dependency>
<!-- 支付基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-pay-service</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-pay-api</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-pay-service</artifactId>
<description>支付实现模块(数据库直接交互,提供基础服务实现的能力)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-pay-service</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-scheduler</artifactId>
<description>定时任务相关模块</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<xxl-job.version>2.3.1</xxl-job.version>
</properties>
<dependencies>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- SpringBoot Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>yd-scheduler</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.yd.scheduler;
import com.yd.common.config.fegin.FeginConfig;
import com.yd.common.constant.WeServerNameConstants;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@ComponentScan("com.yd.**")
@MapperScan("com.yd.**.mapper")
@EnableFeignClients(basePackages="com.yd.**",defaultConfiguration = FeginConfig.class)
@SpringBootApplication
public class SchedulerApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SchedulerApplication.class)
.properties("spring.config.name:bootstrap", "config/bootstrap.yml")
.properties("spring.application.name="+ WeServerNameConstants.ydScheduler)
.build().run(args);
System.out.println("(♥◠‿◠)ノ゙ yd-scheduler启动成功 ლ(´ڡ`ლ)゙ ");
}
}
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ ____ _ _ _
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_/ ___| ___| |__ ___ __| |_ _| | ___ _ __
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __\___ \ / __| '_ \ / _ \/ _` | | | | |/ _ \ '__|
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_ ___) | (__| | | | __/ (_| | |_| | | __/ |
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__|____/ \___|_| |_|\___|\__,_|\__,_|_|\___|_|
${AnsiColor.BRIGHT_WHITE}
Spring Application Name: ${spring.application.name}
Spring Application Name: ${spring.application.name}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n"/>
<!-- 邮件 -->
<!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
<property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
<!-- SMTP server的端口地址。默认值:25 -->
<property name="smtpPort" value="25"/>
<!-- 发送邮件账号,默认为null -->
<property name="username" value="*"/><!--发件人账号-->
<!-- 发送邮件密码,默认为null -->
<property name="password" value="*"/><!--发件人密码-->
<!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
<property name="SSL" value="true"/>
<!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
<property name="email_to" value="*"/>
<!--收件人账号多个可以逗号隔开-->
<!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
<property name="email_from" value="1" />
<!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
<property name="email_subject" value="【yd-scheduler】【Error】: %logger" />
<property name="app_name" value="yd-scheduler"/>
<!-- 日志根目录-->
<springProperty scope="context" name="log.path" source="logging.path"
defaultValue="./logs/yd-scheduler"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug/${app_name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_debug"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info/${app_name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn/${app_name}.warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_warn"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${app_name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- ERROR邮件发送 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>${smtpHost}</smtpHost>
<smtpPort>${smtpPort}</smtpPort>
<username>${username}</username>
<password>${password}</password>
<!-- <asynchronousSending>true</asynchronousSending>-->
<SSL>${SSL}</SSL>
<!--<STARTTLS>true</STARTTLS>-->
<to>${email_to}</to>
<from>${email_from}</from>
<subject>${email_subject}</subject>
<!-- html格式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<Pattern>%date%level%thread%logger{0}%line%message</Pattern>
</layout>
<!-- 这里采用等级过滤器 指定等级相符才发送 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- 每个电子邮件只发送一个日志条目 -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="cn.yd" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="arollingfile_debug" />
<appender-ref ref="arollingfile_info" />
<appender-ref ref="arollingfile_warn" />
<appender-ref ref="arollingfile_error" />
<!-- <appender-ref ref="alarm_error" />-->
<appender-ref ref="EMAIL" />
</root>
</configuration>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-scrm-api</artifactId>
<description>scrm接口模块(scrm项目个性化定制接口及实现的能力,不和数据库直接交互,需要调用对应service模块和数据库交互)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.1</version>
</dependency>
<!-- SpringCloud Alibaba Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- feign组件模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
</dependency>
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-scrm-service</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-scrm-api</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package com.yd.scrm.api;
import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
import com.yd.common.config.fegin.FeginConfig;
import com.yd.common.constant.WeServerNameConstants;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
@MapperScan("com.yd.**.mapper")
@SpringBootApplication(exclude = {PageHelperAutoConfiguration.class})
@EnableAsync
@EnableFeignClients(defaultConfiguration = FeginConfig.class)
public class ApiApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ApiApplication.class)
.properties("spring.config.name:bootstrap", "config/bootstrap.yml")
.properties("spring.application.name="+ WeServerNameConstants.ydApi)
.build().run(args);
System.out.println("(♥◠‿◠)ノ゙ yd-scrm-api启动成功 ლ(´ڡ`ლ)゙ ");
}
}
${AnsiColor.GREEN}
_ _ _ __ __ ____ _ _ _ _
| | (_)_ __ | | _\ \ / /__ / ___| |__ __ _| |_ / \ _ __ (_)
| | | | '_ \| |/ /\ \ /\ / / _ \ | | '_ \ / _` | __| / _ \ | '_ \| |
| |___| | | | | < \ V V / __/ |___| | | | (_| | |_ / ___ \| |_) | |
|_____|_|_| |_|_|\_\ \_/\_/ \___|\____|_| |_|\__,_|\__/_/ \_\ .__/|_|
|_|
${AnsiColor.BRIGHT_WHITE}
Spring Boot Version: ${spring-boot.version}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 日志存放路径 -->
<property name="app_name" value="yd-scrm-api"/>
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
<!-- 邮件 -->
<!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
<property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
<!-- SMTP server的端口地址。默认值:25 -->
<property name="smtpPort" value="25"/>
<!-- 发送邮件账号,默认为null -->
<property name="username" value="*"/><!--发件人账号-->
<!-- 发送邮件密码,默认为null -->
<property name="password" value="*"/><!--发件人密码-->
<!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
<property name="SSL" value="true"/>
<!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
<property name="email_to" value="*"/>
<!--收件人账号多个可以逗号隔开-->
<!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
<property name="email_from" value="1" />
<!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
<property name="email_subject" value="【yd-scrm-api】【Error】: %logger" />
<!-- 日志根目录-->
<springProperty scope="context" name="log.path" source="logging.path"
defaultValue="./logs/yd-scrm-api"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/debug/${app_name}.debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_debug"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/info/${app_name}.info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/warn/${app_name}.warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_warn"/>
</appender>
<!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/error/${app_name}.error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/>
</appender>
<!-- ERROR邮件发送 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>${smtpHost}</smtpHost>
<smtpPort>${smtpPort}</smtpPort>
<username>${username}</username>
<password>${password}</password>
<!-- <asynchronousSending>true</asynchronousSending>-->
<SSL>${SSL}</SSL>
<!--<STARTTLS>true</STARTTLS>-->
<to>${email_to}</to>
<from>${email_from}</from>
<subject>${email_subject}</subject>
<!-- html格式-->
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<Pattern>%date%level%thread%logger{0}%line%message</Pattern>
</layout>
<!-- 这里采用等级过滤器 指定等级相符才发送 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
<!-- 每个电子邮件只发送一个日志条目 -->
<bufferSize>1</bufferSize>
</cyclicBufferTracker>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="cn.yd" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<!--系统操作日志-->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="arollingfile_debug" />
<appender-ref ref="arollingfile_info" />
<appender-ref ref="arollingfile_warn" />
<appender-ref ref="arollingfile_error" />
<!-- <appender-ref ref="alarm_error" />-->
<appender-ref ref="EMAIL" />
</root>
</configuration>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-scrm-service</artifactId>
<description>scrm实现模块(数据库直接交互,提供基础服务实现的能力)</description>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
</dependency>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-scrm-service</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-sfp-api</artifactId>
<description>sfp接口模块(sfp项目个性化定制接口及实现的能力,不和数据库直接交互,需要调用对应service模块和数据库交互)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- feign组件模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-feign</artifactId>
</dependency>
<!-- sfp基础数据交互实现模块依赖 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-sfp-service</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-sfp-api</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-sfp-service</artifactId>
<description>sfp实现模块(数据库直接交互,提供基础服务实现的能力)</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<!-- 公共组件模块 -->
<dependency>
<groupId>com.yd</groupId>
<artifactId>yd-common</artifactId>
</dependency>
</dependencies>
<build>
<finalName>yd-pay-service</finalName>
<plugins>
<!-- 引用Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.maven.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>yd-cloud</artifactId>
<groupId>com.yd</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yd-sms</artifactId>
<description>短信模块</description>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment