First
This commit is contained in:
commit
7011024e46
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
.factorypath
|
||||
.classpath
|
||||
.project
|
||||
*.class
|
||||
.settings
|
||||
pom.properties
|
||||
**/target/**
|
||||
mvnw
|
||||
mvnw.cmd
|
||||
maven-wrapper.properties
|
||||
33
admin-server/.gitignore
vendored
Normal file
33
admin-server/.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
68
admin-server/pom.xml
Normal file
68
admin-server/pom.xml
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>battery-cloud</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>admin-server</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>admin-server</name>
|
||||
<description>监控和日志</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,18 @@
|
||||
package com.evotech.hd.admin;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
import de.codecentric.boot.admin.server.config.EnableAdminServer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@EnableAdminServer
|
||||
public class AdminServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AdminServerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.evotech.hd.admin.config;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import de.codecentric.boot.admin.server.domain.entities.Instance;
|
||||
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
|
||||
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
|
||||
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
|
||||
import de.codecentric.boot.admin.server.notify.AbstractStatusChangeNotifier;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 自定义通知
|
||||
* 继承 AbstractStatusChangeNotifier 类,实现了 doNotify 方法,
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class NotifierConfig extends AbstractStatusChangeNotifier {
|
||||
|
||||
public NotifierConfig(InstanceRepository repository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
|
||||
return Mono.fromRunnable(() -> {
|
||||
if (event instanceof InstanceStatusChangedEvent) {
|
||||
log.info("===>>>实例名称:"+instance.getRegistration().getName());
|
||||
log.info("===>>>实例服务地址:"+instance.getRegistration().getServiceUrl());
|
||||
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
|
||||
switch (status) {
|
||||
case "DOWN":
|
||||
log.info("健康检查没通过!");
|
||||
break;
|
||||
case "OFFLINE":
|
||||
log.info("服务离线!");
|
||||
break;
|
||||
case "UP":
|
||||
log.info("服务上线!");
|
||||
break;
|
||||
case "UNKNOWN":
|
||||
log.info("服务未知异常!");
|
||||
break;
|
||||
default:
|
||||
log.info(status);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.evotech.hd.admin.config;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Component
|
||||
@Order(value = 100)
|
||||
@Slf4j
|
||||
public class PrintConfig implements ApplicationRunner {
|
||||
|
||||
@Resource
|
||||
private Environment env;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
int port = env.getProperty("server.port", Integer.class) == null?8080:env.getProperty("server.port", Integer.class);
|
||||
String address = "127.0.0.1";
|
||||
try {
|
||||
address = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
address = "192.168.5.213";
|
||||
e.printStackTrace();
|
||||
}
|
||||
String url = "http://" + address + ":" + port;
|
||||
String path = env.getProperty("server.servlet.context-path");
|
||||
if (StringUtils.hasText(path)) {
|
||||
url += path;
|
||||
}
|
||||
|
||||
log.info("\r\n===>>>项目已启动,访问地址:{}", url);
|
||||
}
|
||||
|
||||
}
|
||||
58
admin-server/src/main/resources/application.yml
Normal file
58
admin-server/src/main/resources/application.yml
Normal file
@ -0,0 +1,58 @@
|
||||
# 1.server
|
||||
server:
|
||||
port: 9099
|
||||
servlet:
|
||||
context-path: /admonitor
|
||||
# 2. log
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
|
||||
# 3. spring
|
||||
spring:
|
||||
application:
|
||||
name: admin-monitor
|
||||
boot:
|
||||
admin:
|
||||
ui:
|
||||
# 登陆页面标题
|
||||
title: 微服务监控
|
||||
# 登陆后,页面左上标题
|
||||
brand: <span>服务监控和日志</span>
|
||||
# 配置一个账号和密码
|
||||
# security:
|
||||
# user:
|
||||
# name: zrb
|
||||
# password: zrb123
|
||||
cloud:
|
||||
nacos:
|
||||
serverAddr: 192.168.5.213:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
discovery:
|
||||
register-enabled: true
|
||||
#server-addr: 10.10.1.6:8848
|
||||
#ip: 10.10.1.2
|
||||
# metadata:
|
||||
# user:
|
||||
# name: ${spring.security.user.name}
|
||||
# password: ${spring.security.user.password}
|
||||
# 因添加了context-path,admin-server要想发现正确路径,需要加这个
|
||||
metadata:
|
||||
management:
|
||||
context-path: ${server.servlet.context-path}/actuator
|
||||
|
||||
#开放指定信息给服务器看
|
||||
management:
|
||||
httpexchanges:
|
||||
recording:
|
||||
enabled: true
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
# xml文件中配置的日志文件的名称
|
||||
logfile:
|
||||
external-file: /logs/admin/admin-server.log
|
||||
90
admin-server/src/main/resources/logback-spring.xml
Normal file
90
admin-server/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
|
||||
<property name="CONTEXT_NAME" value="admin-server" />
|
||||
<property name="LOG_PATH" value="/logs/admin" />
|
||||
<property name="MAX_FILE_SIZE" value="100MB" />
|
||||
<property name="MAX_HISTORY" value="30" />
|
||||
<!--读取配置中心的属性 -->
|
||||
<!-- <springProperty scope="context" name="LOG_PATH_NAME" source="logging.file.name"/> -->
|
||||
|
||||
<contextName>${CONTEXT_NAME}</contextName>
|
||||
|
||||
<!--输出到控制台 -->
|
||||
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%i索引【从数字0开始递增】 -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<!--%logger{50}:表示logger名字最长50个字符,否则按照句点分割 -->
|
||||
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''} -- %msg%n</Pattern>
|
||||
<!-- 设置字符集 -->
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--所有日志输出到文件 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--日志名,指定最新的文件名,其他文件名使用FileNamePattern -->
|
||||
<File>${LOG_PATH}/${CONTEXT_NAME}.log</File>
|
||||
<!--日志文件输出格式 -->
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{50}.%M\(%line\) -- %msg%n</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志归档 后面可以加.zip -->
|
||||
<fileNamePattern>${LOG_PATH}/${CONTEXT_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
|
||||
<!--日志文件保留天数 -->
|
||||
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大时会被压缩和切割 -->
|
||||
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- 异步日志输出看情况配置 -->
|
||||
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>512</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<!-- 统一配置日志输出,root标签和logger标签,如果这开启了就把不同环境的关上 -->
|
||||
<!-- root标签:相当于开关,只有把定义的appender添加到这里 才会生效有日志 -->
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
<!-- <appender-ref ref="ASYNC_ERROR_FILE" /> -->
|
||||
</root>
|
||||
<!-- logger标签:用来设置某一个包或者具体的某一个类的日志打印级别 -->
|
||||
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO" />
|
||||
|
||||
<!-- 配置不同环境的日志输出,root标签和logger标签 -->
|
||||
<!-- <springProfile name="dev">
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
<appender-ref ref="ASYNC_ERROR_FILE" />
|
||||
</root>
|
||||
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG" />
|
||||
</springProfile> -->
|
||||
|
||||
<!-- <springProfile name="prod">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
<appender-ref ref="ASYNC_ERROR_FILE" />
|
||||
</root>
|
||||
</springProfile> -->
|
||||
|
||||
</configuration>
|
||||
33
authorization-server/.gitignore
vendored
Normal file
33
authorization-server/.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
104
authorization-server/pom.xml
Normal file
104
authorization-server/pom.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>battery-cloud</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>authorization-server</artifactId>
|
||||
<name>authorization-server</name>
|
||||
<description>认证服务</description>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
|
||||
</dependency>
|
||||
<!-- openfein -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>common-web</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>common-redis</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>common-mybatis</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-jwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 不加这个打包有warning -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,19 @@
|
||||
package com.evotech.hd.authorization;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
@ComponentScan("com.evotech.hd.**")
|
||||
@EnableFeignClients
|
||||
public class AuthorizationServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AuthorizationServerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,262 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
|
||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
||||
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
|
||||
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
|
||||
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
|
||||
import org.springframework.security.oauth2.server.authorization.token.JwtGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator;
|
||||
|
||||
import com.evotech.hd.authorization.config.oauth2.passwordmode.OAuth2PasswordAuthenticationConverter;
|
||||
import com.evotech.hd.authorization.config.oauth2.passwordmode.OAuth2PasswordAuthenticationProvider;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
|
||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||
import com.nimbusds.jose.proc.SecurityContext;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Configuration
|
||||
public class AuthorizationServerConfig {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private static final String KEY_ID = "jnGZxjHC54hP4ZnXrrEedtNweQ6aK29w";
|
||||
|
||||
@Resource
|
||||
private MyOAuth2TokenJwtCustomizer jwtCustomizer;
|
||||
@Resource
|
||||
private RSAKeyPair rsaKeyPair;
|
||||
|
||||
/**
|
||||
* 授权服务器端点配置
|
||||
*/
|
||||
@Bean
|
||||
@Order(1)
|
||||
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http,
|
||||
AuthenticationManager authenticationManager,
|
||||
OAuth2AuthorizationService authorizationService,
|
||||
OAuth2TokenGenerator<?> tokenGenerator) throws Exception {
|
||||
// 这是 http 的默认配置,可以点进去看一下,我们为了加入自己的密码模式,需要把
|
||||
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
|
||||
// OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer();
|
||||
// RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();
|
||||
// http.securityMatcher(endpointsMatcher)
|
||||
// .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
|
||||
// .csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
|
||||
// .apply(authorizationServerConfigurer);
|
||||
|
||||
// 添加password模式
|
||||
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).tokenEndpoint(tokenEndpoint ->
|
||||
tokenEndpoint
|
||||
// 添加授权模式转换器(Converter)
|
||||
.accessTokenRequestConverter(new OAuth2PasswordAuthenticationConverter())
|
||||
// 添加 授权模式提供者(Provider)
|
||||
.authenticationProvider(new OAuth2PasswordAuthenticationProvider(authenticationManager, authorizationService, tokenGenerator))
|
||||
// 成功响应
|
||||
.accessTokenResponseHandler(new MyAuthenticationSuccessHandler())
|
||||
// 失败响应
|
||||
.errorResponseHandler(new MyAuthenticationFailureHandler()));
|
||||
|
||||
// 开启OpenID Connect 1.0协议相关端点
|
||||
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults());
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 配置认证服务器请求地址
|
||||
*/
|
||||
@Bean
|
||||
@Order(2)
|
||||
AuthorizationServerSettings authorizationServerSettings() {
|
||||
// 什么都不配置,则使用默认地址
|
||||
return AuthorizationServerSettings.builder().build();
|
||||
}
|
||||
|
||||
|
||||
// 客户端信息表:oauth2_registered_client
|
||||
@Bean
|
||||
@Order(3)
|
||||
RegisteredClientRepository registeredClientRepository(JdbcTemplate jdbcTemplate) {
|
||||
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
|
||||
return registeredClientRepository;
|
||||
}
|
||||
|
||||
|
||||
// 和 token表交互数据用的:oauth2_authorization
|
||||
@Bean
|
||||
OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
|
||||
|
||||
JdbcOAuth2AuthorizationService service = new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
|
||||
JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper rowMapper = new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(registeredClientRepository);
|
||||
rowMapper.setLobHandler(new DefaultLobHandler());
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
ClassLoader classLoader = JdbcOAuth2AuthorizationService.class.getClassLoader();
|
||||
List<Module> modules = SecurityJackson2Modules.getModules(classLoader);
|
||||
objectMapper.registerModules(modules);
|
||||
objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module());
|
||||
// 使用刷新模式,需要从 oauth2_authorization 表反序列化attributes字段得到用户信息(SysUserDetails)
|
||||
// objectMapper.addMixIn(SysUserDetails.class, SysUserMixin.class);
|
||||
objectMapper.addMixIn(Long.class, Object.class);
|
||||
|
||||
rowMapper.setObjectMapper(objectMapper);
|
||||
service.setAuthorizationRowMapper(rowMapper);
|
||||
return service;
|
||||
}
|
||||
|
||||
// 和授权记录表交互数据用的:oauth2_authorization_consent
|
||||
@Bean
|
||||
OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
|
||||
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ========= Token部分 ========
|
||||
*/
|
||||
|
||||
/**
|
||||
* 配置 JWK,为JWT(id_token)提供加密密钥,用于加密/解密或签名/验签
|
||||
* JWK详细见:https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41
|
||||
*/
|
||||
@Bean
|
||||
JWKSource<SecurityContext> jwkSource() {
|
||||
RSAPublicKey publicKey = null;
|
||||
RSAPrivateKey privateKey = null;
|
||||
String publicKeyBase64 = rsaKeyPair.getPublicKeyBase64();
|
||||
String privateKeyBase64 = rsaKeyPair.getPrivateKeyBase64();
|
||||
if (StringUtils.hasText(publicKeyBase64) && StringUtils.hasText(privateKeyBase64)) {
|
||||
publicKey = getPublicKey(publicKeyBase64);
|
||||
privateKey = getPrivateKey(privateKeyBase64);
|
||||
} else {
|
||||
KeyPair keyPair = generateRsaKey();
|
||||
publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
privateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
log.warn("未设置生成token的秘钥!!!");
|
||||
log.info("生成临时秘钥:");
|
||||
log.info("\r\n===publicKey===" +
|
||||
"\r\n" +
|
||||
Base64.getEncoder().encodeToString(publicKey.getEncoded()) +
|
||||
"\r\n===privateKey===" +
|
||||
"\r\n" +
|
||||
Base64.getEncoder().encodeToString(privateKey.getEncoded()));
|
||||
}
|
||||
|
||||
RSAKey rsaKey = new RSAKey.Builder(publicKey)
|
||||
.privateKey(privateKey)
|
||||
.keyID(KEY_ID)
|
||||
.build();
|
||||
JWKSet jwkSet = new JWKSet(rsaKey);
|
||||
return new ImmutableJWKSet<>(jwkSet);
|
||||
}
|
||||
|
||||
private RSAPublicKey getPublicKey(String publicKeyBase64) {
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBase64));
|
||||
RSAPublicKey rsaPublicKey = null;
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
rsaPublicKey = (RSAPublicKey)keyFactory.generatePublic(keySpec);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return rsaPublicKey;
|
||||
}
|
||||
|
||||
private RSAPrivateKey getPrivateKey(String privateKeyBase64) {
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyBase64));
|
||||
RSAPrivateKey rsaPrivateKey = null;
|
||||
try {
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return rsaPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成RSA密钥对,给上面jwkSource() 方法的提供密钥对
|
||||
*/
|
||||
private static KeyPair generateRsaKey() {
|
||||
KeyPair keyPair;
|
||||
try {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(2048);
|
||||
keyPair = keyPairGenerator.generateKeyPair();
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置jwt解析器
|
||||
*/
|
||||
@Bean
|
||||
JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
|
||||
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置token生成器
|
||||
*/
|
||||
@Bean
|
||||
OAuth2TokenGenerator<?> tokenGenerator(JWKSource<SecurityContext> jwkSource) {
|
||||
JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource));
|
||||
// token 中加入自定义的字段内容
|
||||
jwtGenerator.setJwtCustomizer(jwtCustomizer);
|
||||
|
||||
OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
|
||||
OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
||||
return new DelegatingOAuth2TokenGenerator(jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class MyAccessToken {
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String refreshToken;
|
||||
|
||||
private String tokenType;
|
||||
|
||||
private long expiresIn;
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
|
||||
|
||||
private final HttpMessageConverter<Object> httpResponseConverter = new MappingJackson2HttpMessageConverter();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
Result<String> res = new Result<String>();
|
||||
if (exception instanceof UsernameNotFoundException) {
|
||||
res.error(CodeMsg.USERNAME_OR_PASSWORD_ERROR);
|
||||
} else if (exception instanceof OAuth2AuthenticationException) {
|
||||
OAuth2Error error = ((OAuth2AuthenticationException) exception).getError();
|
||||
res.error(error.getErrorCode());
|
||||
}
|
||||
|
||||
System.out.println("error走这个了: MyAuthenticationFailureHandler");
|
||||
|
||||
httpResponseConverter.write(res, null, httpResponse);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.DefaultOAuth2AccessTokenResponseMapConverter;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
|
||||
|
||||
/**
|
||||
* MappingJackson2HttpMessageConverter 是 Spring 框架提供的一个 HTTP 消息转换器,用于将 HTTP 请求和响应的 JSON 数据与 Java 对象之间进行转换
|
||||
*/
|
||||
private final HttpMessageConverter<Object> accessTokenHttpResponseConverter = new MappingJackson2HttpMessageConverter();
|
||||
private Converter<OAuth2AccessTokenResponse, Map<String, Object>> accessTokenResponseParametersConverter = new DefaultOAuth2AccessTokenResponseMapConverter();
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException, ServletException {
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) authentication;
|
||||
|
||||
OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
|
||||
OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
|
||||
Map<String, Object> additionalParameters = accessTokenAuthentication.getAdditionalParameters();
|
||||
|
||||
OAuth2AccessTokenResponse.Builder builder =OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue()).tokenType(accessToken.getTokenType());
|
||||
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
||||
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
||||
}
|
||||
if (refreshToken != null) {
|
||||
builder.refreshToken(refreshToken.getTokenValue());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(additionalParameters)) {
|
||||
builder.additionalParameters(additionalParameters);
|
||||
}
|
||||
OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
||||
|
||||
Map<String, Object> tokenResponseParameters = accessTokenResponseParametersConverter.convert(accessTokenResponse);
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
|
||||
|
||||
this.accessTokenHttpResponseConverter.write(new Result<String>().success(tokenResponseParameters), null, httpResponse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
||||
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
|
||||
|
||||
import com.evotech.hd.authorization.config.security.userdetail.MyUserDetail;
|
||||
|
||||
/**
|
||||
* 自定义Token包含的字段信息,
|
||||
* 通过context拿到authentication和其他信息,然后再拿到Principal(userDetails数据)或者其他
|
||||
*/
|
||||
@Configuration
|
||||
public class MyOAuth2TokenJwtCustomizer implements OAuth2TokenCustomizer<JwtEncodingContext> {
|
||||
|
||||
@Override
|
||||
public void customize(JwtEncodingContext context) {
|
||||
JwtClaimsSet.Builder claims = context.getClaims();
|
||||
System.out.println("自定义token字段");
|
||||
Authentication authentication = context.getPrincipal();
|
||||
MyUserDetail detail = (MyUserDetail) authentication.getPrincipal();
|
||||
claims.claim("uid", detail.getUid());
|
||||
claims.claim("rcodes", detail.getRcodes());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.evotech.hd.authorization.config.oauth2;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class RSAKeyPair {
|
||||
|
||||
@Value("${security.token.public_key_base64:null}")
|
||||
private String publicKeyBase64;
|
||||
|
||||
@Value("${security.token.private_key_base64:null}")
|
||||
private String privateKeyBase64;
|
||||
|
||||
public String getPublicKeyBase64() {
|
||||
return publicKeyBase64;
|
||||
}
|
||||
|
||||
public String getPrivateKeyBase64() {
|
||||
return privateKeyBase64;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package com.evotech.hd.authorization.config.oauth2.passwordmode;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.ClaimAccessor;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2Token;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationCode;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenContext;
|
||||
|
||||
public class OAuth2AuthenticationProviderUtils {
|
||||
|
||||
private OAuth2AuthenticationProviderUtils() {
|
||||
}
|
||||
|
||||
public static OAuth2ClientAuthenticationToken getAuthenticatedClientElseThrowInvalidClient(Authentication authentication) {
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = null;
|
||||
if (OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication.getPrincipal().getClass())) {
|
||||
clientPrincipal = (OAuth2ClientAuthenticationToken) authentication.getPrincipal();
|
||||
}
|
||||
if (clientPrincipal != null && clientPrincipal.isAuthenticated()) {
|
||||
return clientPrincipal;
|
||||
}
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_CLIENT);
|
||||
}
|
||||
|
||||
public static <T extends OAuth2Token> OAuth2Authorization invalidate(OAuth2Authorization authorization, T token) {
|
||||
|
||||
// @formatter:off
|
||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.from(authorization)
|
||||
.token(token,
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
|
||||
if (OAuth2RefreshToken.class.isAssignableFrom(token.getClass())) {
|
||||
authorizationBuilder.token(
|
||||
authorization.getAccessToken().getToken(),
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
|
||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode =
|
||||
authorization.getToken(OAuth2AuthorizationCode.class);
|
||||
if (authorizationCode != null && !authorizationCode.isInvalidated()) {
|
||||
authorizationBuilder.token(
|
||||
authorizationCode.getToken(),
|
||||
(metadata) ->
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, true));
|
||||
}
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
return authorizationBuilder.build();
|
||||
}
|
||||
|
||||
public static <T extends OAuth2Token> OAuth2AccessToken accessToken(OAuth2Authorization.Builder builder, T token,
|
||||
OAuth2TokenContext accessTokenContext) {
|
||||
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, token.getTokenValue(),
|
||||
token.getIssuedAt(), token.getExpiresAt(), accessTokenContext.getAuthorizedScopes());
|
||||
OAuth2TokenFormat accessTokenFormat = accessTokenContext.getRegisteredClient()
|
||||
.getTokenSettings()
|
||||
.getAccessTokenFormat();
|
||||
builder.token(accessToken, (metadata) -> {
|
||||
if (token instanceof ClaimAccessor claimAccessor) {
|
||||
metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, claimAccessor.getClaims());
|
||||
}
|
||||
metadata.put(OAuth2Authorization.Token.INVALIDATED_METADATA_NAME, false);
|
||||
metadata.put(OAuth2TokenFormat.class.getName(), accessTokenFormat.getValue());
|
||||
});
|
||||
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
package com.evotech.hd.authorization.config.oauth2.passwordmode;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public class OAuth2EndpointUtils {
|
||||
|
||||
public static final String ACCESS_TOKEN_REQUEST_ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||
|
||||
private OAuth2EndpointUtils() {
|
||||
}
|
||||
|
||||
public static MultiValueMap<String, String> getFormParameters(HttpServletRequest request) {
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameterMap.forEach((key, values) -> {
|
||||
String queryString = StringUtils.hasText(request.getQueryString()) ? request.getQueryString() : "";
|
||||
// If not query parameter then it's a form parameter
|
||||
if (!queryString.contains(key) && values.length > 0) {
|
||||
for (String value : values) {
|
||||
parameters.add(key, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public static MultiValueMap<String, String> getQueryParameters(HttpServletRequest request) {
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
|
||||
parameterMap.forEach((key, values) -> {
|
||||
String queryString = StringUtils.hasText(request.getQueryString()) ? request.getQueryString() : "";
|
||||
if (queryString.contains(key) && values.length > 0) {
|
||||
for (String value : values) {
|
||||
parameters.add(key, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getParametersIfMatchesAuthorizationCodeGrantRequest(HttpServletRequest request,
|
||||
String... exclusions) {
|
||||
if (!matchesAuthorizationCodeGrantRequest(request)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
MultiValueMap<String, String> multiValueParameters = "GET".equals(request.getMethod())
|
||||
? getQueryParameters(request) : getFormParameters(request);
|
||||
for (String exclusion : exclusions) {
|
||||
multiValueParameters.remove(exclusion);
|
||||
}
|
||||
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
multiValueParameters.forEach(
|
||||
(key, value) -> parameters.put(key, (value.size() == 1) ? value.get(0) : value.toArray(new String[0])));
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public static boolean matchesAuthorizationCodeGrantRequest(HttpServletRequest request) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue()
|
||||
.equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE))
|
||||
&& request.getParameter(OAuth2ParameterNames.CODE) != null;
|
||||
}
|
||||
|
||||
public static boolean matchesPkceTokenRequest(HttpServletRequest request) {
|
||||
return matchesAuthorizationCodeGrantRequest(request)
|
||||
&& request.getParameter(PkceParameterNames.CODE_VERIFIER) != null;
|
||||
}
|
||||
|
||||
public static void throwError(String errorCode, String parameterName, String errorUri) {
|
||||
OAuth2Error error = new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, errorUri);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
|
||||
public static String normalizeUserCode(String userCode) {
|
||||
Assert.hasText(userCode, "userCode cannot be empty");
|
||||
StringBuilder sb = new StringBuilder(userCode.toUpperCase().replaceAll("[^A-Z\\d]+", ""));
|
||||
Assert.isTrue(sb.length() == 8, "userCode must be exactly 8 alpha/numeric characters");
|
||||
sb.insert(4, '-');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean validateUserCode(String userCode) {
|
||||
return (userCode != null && userCode.toUpperCase().replaceAll("[^A-Z\\d]+", "").length() == 8);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package com.evotech.hd.authorization.config.oauth2.passwordmode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.web.authentication.AuthenticationConverter;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 限定必须要传的参数
|
||||
* 只是要这些参数,并没有对参数值校验
|
||||
*/
|
||||
public class OAuth2PasswordAuthenticationConverter implements AuthenticationConverter {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Authentication convert(HttpServletRequest request) {
|
||||
// 1. 提取表单参数,准备校验用,用的这个方法就是复制的sas自带的
|
||||
MultiValueMap<String, String> parameters = OAuth2EndpointUtils.getFormParameters(request);
|
||||
// 2. 授权类型参数 (必须)
|
||||
// String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
||||
String grantType = parameters.getFirst(OAuth2ParameterNames.GRANT_TYPE);
|
||||
if (!OAuth2PasswordAuthenticationToken.PASSWORD.getValue().equals(grantType)) {
|
||||
return null;
|
||||
}
|
||||
// 3. 令牌申请访问范围参数 (可选)
|
||||
String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
|
||||
if (StringUtils.hasText(scope) && parameters.get(OAuth2ParameterNames.SCOPE).size() != 1) {
|
||||
OAuth2EndpointUtils.throwError(
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.SCOPE,
|
||||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||
}
|
||||
|
||||
Set<String> requestedScopes = null;
|
||||
if (StringUtils.hasText(scope)) {
|
||||
requestedScopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
|
||||
}
|
||||
// 4. 账号密码参数校验
|
||||
// 4.1 用户名参数 (必须)
|
||||
String username = parameters.getFirst(OAuth2ParameterNames.USERNAME);
|
||||
if (!StringUtils.hasText(username) || parameters.get(OAuth2ParameterNames.USERNAME).size() != 1) {
|
||||
OAuth2EndpointUtils.throwError(
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.USERNAME,
|
||||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||
}
|
||||
|
||||
// 4.2 密码参数 (必须)
|
||||
String password = parameters.getFirst(OAuth2ParameterNames.PASSWORD);
|
||||
if (!StringUtils.hasText(password) || parameters.get(OAuth2ParameterNames.PASSWORD).size() != 1) {
|
||||
OAuth2EndpointUtils.throwError(
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.PASSWORD,
|
||||
OAuth2EndpointUtils.ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||
}
|
||||
|
||||
// 5. 客户端凭据信息,在header 中填写的那个
|
||||
Authentication clientPrincipal = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
// 6. 参数封装成additionalParameters放到OAuth2PasswordAuthenticationToken中传给 PasswordAuthenticationProvider 用于验证值
|
||||
Map<String, Object> additionalParameters = new HashMap<>();
|
||||
parameters.forEach((key, value) -> {
|
||||
if (!key.equals(OAuth2ParameterNames.GRANT_TYPE) && !key.equals(OAuth2ParameterNames.SCOPE)) {
|
||||
additionalParameters.put(key, value.get(0));
|
||||
}
|
||||
});
|
||||
return new OAuth2PasswordAuthenticationToken(clientPrincipal, requestedScopes, additionalParameters);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,186 @@
|
||||
package com.evotech.hd.authorization.config.oauth2.passwordmode;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.ClaimAccessor;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2Token;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||
import org.springframework.security.oauth2.server.authorization.context.AuthorizationServerContextHolder;
|
||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext;
|
||||
import org.springframework.security.oauth2.server.authorization.token.DefaultOAuth2TokenContext.Builder;
|
||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 参考授权码(主要)"OAuth2AuthorizationCodeAuthenticationProvider"和客户端"OAuth2ClientCredentialsAuthenticationProvider"
|
||||
*/
|
||||
public class OAuth2PasswordAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
@Resource
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
// 这部分代码和OAuth2ClientCredentialsAuthenticationProvider类似,只是添加了AuthenticationManager
|
||||
private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final OAuth2AuthorizationService authorizationService;
|
||||
private final OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator;
|
||||
|
||||
|
||||
public OAuth2PasswordAuthenticationProvider(AuthenticationManager authenticationManager,
|
||||
OAuth2AuthorizationService authorizationService,
|
||||
OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator) {
|
||||
|
||||
Assert.notNull(authorizationService, "authorizationService cannot be null");
|
||||
Assert.notNull(tokenGenerator, "tokenGenerator cannot be null");
|
||||
this.authenticationManager = authenticationManager;
|
||||
this.authorizationService = authorizationService;
|
||||
this.tokenGenerator = tokenGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
|
||||
// PasswordAuthenticationToken
|
||||
OAuth2PasswordAuthenticationToken passwordAuthenticationToken = (OAuth2PasswordAuthenticationToken) authentication;
|
||||
|
||||
// coverter中最后生成的token,包含3部分内容,在这里拿出来,下面用
|
||||
Map<String, Object> additionalParameters = passwordAuthenticationToken.getAdditionalParameters();
|
||||
OAuth2ClientAuthenticationToken clientPrincipal = OAuth2AuthenticationProviderUtils.getAuthenticatedClientElseThrowInvalidClient(passwordAuthenticationToken);
|
||||
RegisteredClient registeredClient = clientPrincipal.getRegisteredClient();
|
||||
|
||||
// 1. 验证客户端是否支持密码模式类型(grant_type=password)
|
||||
if (!registeredClient.getAuthorizationGrantTypes().contains(passwordAuthenticationToken.getGrantType())) {
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE);
|
||||
}
|
||||
// 2. 校验范围scope
|
||||
Set<String> authorizedScopes = registeredClient.getScopes();
|
||||
Set<String> requestedScopes = passwordAuthenticationToken.getScopes();
|
||||
if (!CollectionUtils.isEmpty(requestedScopes )) {
|
||||
Set<String> unauthorizedScopes = requestedScopes.stream()
|
||||
.filter(scope -> !registeredClient.getScopes().contains(scope))
|
||||
.collect(Collectors.toSet());
|
||||
if (!CollectionUtils.isEmpty(unauthorizedScopes)) {
|
||||
throw new OAuth2AuthenticationException(OAuth2ErrorCodes.INVALID_SCOPE);
|
||||
}
|
||||
authorizedScopes = new LinkedHashSet<>(requestedScopes);
|
||||
}
|
||||
// 3 用户名密码校验
|
||||
String username = (String) additionalParameters.get(OAuth2ParameterNames.USERNAME);
|
||||
String password = (String) additionalParameters.get(OAuth2ParameterNames.PASSWORD);
|
||||
// 我们不自己校验了,用oauth2的方法校验
|
||||
// MyUserDetail userDetail = userDetailsService.loadUserByUsername(username);
|
||||
// if (userDetail == null) {
|
||||
// throw new OAuth2AuthenticationException("用户不存在!");
|
||||
// }
|
||||
// if (!passwordEncoder.matches(password, userDetail.getPassword())) {
|
||||
// throw new OAuth2AuthenticationException("密码不正确!");
|
||||
// }
|
||||
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
||||
Authentication usernamePasswordAuthentication = null;
|
||||
try {
|
||||
usernamePasswordAuthentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
|
||||
} catch (AuthenticationException e) {
|
||||
e.printStackTrace();
|
||||
throw new OAuth2AuthenticationException("账号或密码错误");
|
||||
}
|
||||
// 处理userDetails的时候,我们没有添加权限信息,这拿不到数据
|
||||
// Collection<? extends GrantedAuthority> authorities = usernamePasswordAuthentication.getAuthorities();
|
||||
// for (GrantedAuthority authoriti : authorities) {
|
||||
// }
|
||||
|
||||
// 4. 生成token
|
||||
// 4.1 填充token需要的上下文数据,按照授权码模式来的
|
||||
Builder tokenContextBuilder = DefaultOAuth2TokenContext.builder()
|
||||
.registeredClient(registeredClient)
|
||||
// 身份验证成功的认证信息(用户名、权限等信息)
|
||||
.principal(usernamePasswordAuthentication)
|
||||
.authorizationServerContext(AuthorizationServerContextHolder.getContext())
|
||||
.authorizedScopes(authorizedScopes)
|
||||
// 授权类型
|
||||
.authorizationGrantType(passwordAuthenticationToken.getGrantType())
|
||||
// 授权具体对象
|
||||
.authorizationGrant(passwordAuthenticationToken)
|
||||
;
|
||||
// 4.2 生成访问令牌(Access Token)
|
||||
DefaultOAuth2TokenContext tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.ACCESS_TOKEN).build();
|
||||
OAuth2Token generatedAccessToken = this.tokenGenerator.generate(tokenContext);
|
||||
if (generatedAccessToken == null) {
|
||||
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
|
||||
"The token generator failed to generate the access token.", ERROR_URI);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
|
||||
generatedAccessToken.getTokenValue(), generatedAccessToken.getIssuedAt(),
|
||||
generatedAccessToken.getExpiresAt(), tokenContext.getAuthorizedScopes());
|
||||
|
||||
// 4. 生成刷新令牌(Refresh Token)
|
||||
OAuth2RefreshToken refreshToken = null;
|
||||
if (registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.REFRESH_TOKEN) &&
|
||||
// Do not issue refresh token to public client
|
||||
!clientPrincipal.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.NONE)) {
|
||||
tokenContext = tokenContextBuilder.tokenType(OAuth2TokenType.REFRESH_TOKEN).build();
|
||||
OAuth2Token generatedRefreshToken = this.tokenGenerator.generate(tokenContext);
|
||||
if (!(generatedRefreshToken instanceof OAuth2RefreshToken)) {
|
||||
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.SERVER_ERROR,
|
||||
"The token generator failed to generate the refresh token.", ERROR_URI);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
refreshToken = (OAuth2RefreshToken) generatedRefreshToken;
|
||||
}
|
||||
|
||||
|
||||
// 5. 组装数据入库
|
||||
OAuth2Authorization.Builder authorizationBuilder = OAuth2Authorization.withRegisteredClient(registeredClient)
|
||||
.principalName(clientPrincipal.getName())
|
||||
.authorizationGrantType(passwordAuthenticationToken.getGrantType())
|
||||
.authorizedScopes(authorizedScopes)
|
||||
.attribute(Principal.class.getName(), usernamePasswordAuthentication);
|
||||
if (generatedAccessToken instanceof ClaimAccessor) {
|
||||
authorizationBuilder.token(accessToken, (metadata) -> metadata.put(OAuth2Authorization.Token.CLAIMS_METADATA_NAME, ((ClaimAccessor) generatedAccessToken).getClaims()));
|
||||
} else {
|
||||
authorizationBuilder.accessToken(accessToken);
|
||||
authorizationBuilder.refreshToken(refreshToken);
|
||||
}
|
||||
OAuth2Authorization authorization = authorizationBuilder.build();
|
||||
// 入库
|
||||
this.authorizationService.save(authorization);
|
||||
additionalParameters = Collections.emptyMap();
|
||||
|
||||
return new OAuth2AccessTokenAuthenticationToken(registeredClient, clientPrincipal, accessToken, refreshToken, additionalParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return OAuth2PasswordAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.evotech.hd.authorization.config.oauth2.passwordmode;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken;
|
||||
|
||||
|
||||
/**
|
||||
* 这个token就是传递数据用的一个实体,想要什么数据可以写成变量
|
||||
* 在converter生成时赋值,在provider中拿出来用
|
||||
*/
|
||||
public class OAuth2PasswordAuthenticationToken extends OAuth2AuthorizationGrantAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = -7029686994815546552L;
|
||||
|
||||
public static final AuthorizationGrantType PASSWORD = new AuthorizationGrantType("password");
|
||||
|
||||
private final Set<String> scopes;
|
||||
|
||||
/**
|
||||
* 密码模式身份验证令牌
|
||||
*
|
||||
* @param clientPrincipal 客户端信息
|
||||
* @param scopes 令牌申请访问范围
|
||||
* @param additionalParameters 自定义额外参数(用户名和密码等)
|
||||
*/
|
||||
protected OAuth2PasswordAuthenticationToken(Authentication clientPrincipal, @Nullable Set<String> scopes,
|
||||
@Nullable Map<String, Object> additionalParameters) {
|
||||
super(PASSWORD, clientPrincipal, additionalParameters);
|
||||
this.scopes = Collections.unmodifiableSet((scopes != null) ? new HashSet<>(scopes) : Collections.emptySet());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 这个方法 父类中直接返回了空字符串,
|
||||
* 我们可以根据自己的需要重写,可以返回密码
|
||||
*/
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return this.getAdditionalParameters().get(OAuth2ParameterNames.PASSWORD);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getScopes() {
|
||||
return this.scopes;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.evotech.hd.authorization.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 登陆了,没有权限时,触发异常 返回信息
|
||||
*/
|
||||
public class MyAccessDeniedHandler implements AccessDeniedHandler {
|
||||
|
||||
private final HttpMessageConverter<Object> httpResponseConverter = new MappingJackson2HttpMessageConverter();
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response,
|
||||
AccessDeniedException accessDeniedException) throws IOException, ServletException {
|
||||
System.out.println("=====无权限的异常处理");
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
|
||||
Result<Integer> res = new Result<Integer>().error(accessDeniedException.getLocalizedMessage());
|
||||
|
||||
|
||||
httpResponseConverter.write(res, null, httpResponse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package com.evotech.hd.authorization.config.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.server.resource.InvalidBearerTokenException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 未认证(没有登录)时,返回异常 信息
|
||||
*/
|
||||
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
private final HttpMessageConverter<Object> httpResponseConverter = new MappingJackson2HttpMessageConverter();
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException authException) throws IOException, ServletException {
|
||||
if (authException instanceof InvalidBearerTokenException) {
|
||||
System.out.println(authException.getMessage());
|
||||
}
|
||||
authException.printStackTrace();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
|
||||
Result<String> res = new Result<String>().error(CodeMsg.AUTHENTICATION_FAILED);
|
||||
|
||||
httpResponseConverter.write(res, null, httpResponse);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
package com.evotech.hd.authorization.config.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import com.evotech.hd.authorization.config.security.userdetail.UserDetailService;
|
||||
|
||||
@Configuration
|
||||
public class WebSecutiryConfig {
|
||||
|
||||
|
||||
@Bean
|
||||
UserDetailsService userDetailsService() {
|
||||
UserDetailService userDetail = new UserDetailService();
|
||||
return userDetail;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Security 安全过滤器链配置
|
||||
*/
|
||||
@Bean
|
||||
@Order(1)
|
||||
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
|
||||
|
||||
// 1. 开启认证,提前排除 不需要认证的
|
||||
http.authorizeHttpRequests(authorize -> {
|
||||
authorize
|
||||
// 路径不用加context-path
|
||||
.requestMatchers("/oauth2/**").permitAll()
|
||||
// 登陆图形验证码
|
||||
.requestMatchers("/captcha/**").permitAll()
|
||||
// 登陆
|
||||
.requestMatchers("/login/**").permitAll()
|
||||
.anyRequest().authenticated();
|
||||
})
|
||||
|
||||
|
||||
|
||||
;
|
||||
// 2. 登陆方式:默认是使用security提供表单的登陆页面和方式,我们这里关闭
|
||||
http.formLogin(Customizer.withDefaults());
|
||||
// http.formLogin(AbstractHttpConfigurer::disable);
|
||||
|
||||
// 3. 登出配置
|
||||
// http.logout(logout -> logout.logoutSuccessHandler(new MyLogoutSuccessHandler()));
|
||||
|
||||
// 4. security异常错误配置
|
||||
http.exceptionHandling(exception -> {
|
||||
// 未认证时 访问接口,返回错误
|
||||
exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());
|
||||
// 未授权时,返回错误,一般资源服务器 才会用到这个
|
||||
exception.accessDeniedHandler(new MyAccessDeniedHandler());
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 5. csrf是默认开启的,此时对于post请求,会需要一个"_csrf"的隐藏字段传递,为了前端方便,这个关了
|
||||
http.csrf(csrf -> csrf.disable());
|
||||
|
||||
// 6. 跨域处理
|
||||
http.cors(Customizer.withDefaults());
|
||||
|
||||
// 7. session管理,设置同一个账号只能登陆一次.单体服务这个管用,微服务 不能用
|
||||
// http.sessionManagement(session -> session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy()));
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Security 排除路径
|
||||
*/
|
||||
@Bean
|
||||
WebSecurityCustomizer webSecurityCustomizer() {
|
||||
return (web) ->
|
||||
// 不走过滤器链(swagger和静态资源js、css、html)
|
||||
web.ignoring().requestMatchers(
|
||||
"/webjars/**",
|
||||
"/doc.html",
|
||||
"/swagger-resources/**",
|
||||
"/v3/api-docs/**",
|
||||
"/swagger-ui/**",
|
||||
// admin监控
|
||||
"/actuator/**",
|
||||
"/instances/**"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package com.evotech.hd.authorization.config.security.userdetail;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class MyUserDetail extends AuthUser implements UserDetails {
|
||||
|
||||
private static final long serialVersionUID = 786868339462173799L;
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.getUname();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return UserDetails.super.isAccountNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return UserDetails.super.isAccountNonLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return UserDetails.super.isCredentialsNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.getStatus() == 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.evotech.hd.authorization.config.security.userdetail;
|
||||
|
||||
import org.springframework.security.authentication.DisabledException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import com.evotech.hd.authorization.service.ResourceService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class UserDetailService implements UserDetailsService {
|
||||
|
||||
@Resource
|
||||
private ResourceService resourceService;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
Result<AuthUser> result = resourceService.loadUserByName(username);
|
||||
if(!CodeMsg.SUCCESS.getCode().equals(result.getCode())) {
|
||||
throw new UsernameNotFoundException("账号或密码错误!");
|
||||
}
|
||||
AuthUser user = BeanUtil.toBean(result.getData(), AuthUser.class) ;
|
||||
MyUserDetail userDetail = new MyUserDetail();
|
||||
BeanUtil.copyProperties(user, userDetail, false);
|
||||
if (!userDetail.isEnabled()) {
|
||||
throw new DisabledException("账号状态异常!");
|
||||
}
|
||||
|
||||
return userDetail;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.evotech.hd.authorization.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.authorization.service.CaptchaService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Tag(name = "验证码")
|
||||
@RestController
|
||||
@RequestMapping("/captcha")
|
||||
public class CaptchaController {
|
||||
|
||||
@Resource
|
||||
private CaptchaService captchaService;
|
||||
|
||||
|
||||
@Operation(summary = "获取")
|
||||
@GetMapping("/get")
|
||||
public Result<String> getCaptcha() {
|
||||
return captchaService.getCaptcha();
|
||||
}
|
||||
|
||||
@Operation(summary = "校验", description = "code格式 -- captchaId:code")
|
||||
@PostMapping("/check")
|
||||
public Result<Boolean> checkCaptcha(String code) {
|
||||
return captchaService.checkCaptcha(code);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.evotech.hd.authorization.controller;
|
||||
|
||||
import org.apache.http.auth.AuthenticationException;
|
||||
import org.springdoc.core.annotations.ParameterObject;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.evotech.hd.authorization.entity.LoginRequest;
|
||||
import com.evotech.hd.authorization.entity.UserVo;
|
||||
import com.evotech.hd.authorization.service.LoginService;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
@Tag(name = "登陆")
|
||||
@RestController
|
||||
@RequestMapping("/login")
|
||||
public class LoginController {
|
||||
|
||||
@Resource
|
||||
private LoginService loginService;
|
||||
|
||||
@Operation(summary = "登陆")
|
||||
@PostMapping("/oauthlogin")
|
||||
@Parameters(
|
||||
|
||||
)
|
||||
@Parameter(name="Authorization", example = "Basic eXRoZDpZVEhEMTIz")
|
||||
public Result<UserVo> oauthLogin(@RequestHeader String Authorization, @Valid @ParameterObject LoginRequest lr, HttpServletRequest request) throws AuthenticationException {
|
||||
return loginService.oauthLogin(lr, request);
|
||||
}
|
||||
|
||||
@Operation(summary = "登出")
|
||||
@DeleteMapping("/oauthlogout")
|
||||
public Result<String> AuthLogout(HttpServletRequest request) {
|
||||
return loginService.logout(request);
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "检验token")
|
||||
@PostMapping("/checktoken")
|
||||
public Result<Boolean> checkToken(String token) throws AuthenticationException {
|
||||
return loginService.checkToken(token);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.evotech.hd.authorization.entity;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LoginRequest {
|
||||
|
||||
@Schema(description = "账号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "账号不能为空")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "密码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "验证码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "验证码不能为空")
|
||||
private String code;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.evotech.hd.authorization.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.evotech.hd.authorization.config.oauth2.MyAccessToken;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthRole;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "登陆时返回前端的对象")
|
||||
@ApiResponse
|
||||
public class UserVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String uid;
|
||||
|
||||
@Schema(name = "账号")
|
||||
private String uname;
|
||||
|
||||
@Schema(name = "姓名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "账号类型:1-开发者,2-运营方,3-客户")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "关联方代码")
|
||||
private String typeRelateCode;
|
||||
|
||||
@Schema(name = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(name = "手机")
|
||||
private String mobile;
|
||||
|
||||
@Schema(name = "性别")
|
||||
private String sex;
|
||||
|
||||
@Schema(name = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(name = "token")
|
||||
private MyAccessToken token;
|
||||
|
||||
@Schema(name = "角色")
|
||||
List<AuthRole> roleList;
|
||||
|
||||
@Schema(name = "权限")
|
||||
List<String> permCodeList;
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.evotech.hd.authorization.service;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
|
||||
public interface CaptchaService {
|
||||
|
||||
public Result<String> getCaptcha();
|
||||
|
||||
public Result<Boolean> checkCaptcha(String code);
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.evotech.hd.authorization.service;
|
||||
|
||||
import org.apache.http.auth.AuthenticationException;
|
||||
|
||||
import com.evotech.hd.authorization.entity.LoginRequest;
|
||||
import com.evotech.hd.authorization.entity.UserVo;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface LoginService {
|
||||
|
||||
public Result<UserVo> oauthLogin(LoginRequest lr, HttpServletRequest request) throws AuthenticationException;
|
||||
|
||||
public Result<String> logout(HttpServletRequest request);
|
||||
|
||||
public Result<Boolean> checkToken(String token) throws AuthenticationException;
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.evotech.hd.authorization.service;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.evotech.hd.common.core.entity.LoginCacheInfo;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.resource.LogLogin;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@FeignClient(value = "resource-server")
|
||||
public interface ResourceService {
|
||||
|
||||
|
||||
@GetMapping(value = "/resource/user/userbyname",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<AuthUser> loadUserByName(@RequestParam("uname") String userName);
|
||||
|
||||
@PostMapping(value = "/resource/user/userpermbyid",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<String> userPermById(@NotNull @RequestParam("uid") String userId, @RequestParam("type")Integer type);
|
||||
|
||||
@PostMapping(value = "/resource/loginlog/add",
|
||||
consumes = {MediaType.APPLICATION_JSON_VALUE})
|
||||
public Result<Integer> addLoginLog(@RequestBody LogLogin log);
|
||||
|
||||
@GetMapping(value = "/resource/logininfo/get",
|
||||
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
|
||||
public Result<LoginCacheInfo> loginInfo(@RequestParam("uid") String uid);
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.evotech.hd.authorization.service.impl;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.evotech.hd.authorization.service.CaptchaService;
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
|
||||
import cn.hutool.captcha.CaptchaUtil;
|
||||
import cn.hutool.captcha.LineCaptcha;
|
||||
import cn.hutool.captcha.generator.RandomGenerator;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class CaptchaServiceImpl implements CaptchaService {
|
||||
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Value("${yt.captcha.expire:300}")
|
||||
private Integer captchaExpire;
|
||||
|
||||
@Override
|
||||
public Result<String> getCaptcha() {
|
||||
RandomGenerator randomGenerator = new RandomGenerator("0123456789", 4);
|
||||
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 30);
|
||||
captcha.setGenerator(randomGenerator);
|
||||
captcha.createCode();
|
||||
String code = captcha.getCode();
|
||||
String imageBase64Data = captcha.getImageBase64Data();
|
||||
String captchaId = IdUtil.fastSimpleUUID();
|
||||
redisUtil.set(HDConstant.CAPTCHA_REDIS_PREFIX + captchaId, code, captchaExpire);
|
||||
return new Result<String>().success("OK", captchaId + ":" + imageBase64Data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Boolean> checkCaptcha(String code) {
|
||||
String[] codeArr = code.split(":");
|
||||
if (codeArr.length != 2) {
|
||||
return new Result<Boolean>().error("验证码格式错误!");
|
||||
}
|
||||
String captchaId = codeArr[0];
|
||||
code = codeArr[1];
|
||||
if (!redisUtil.hasKey(HDConstant.CAPTCHA_REDIS_PREFIX + captchaId)) {
|
||||
return new Result<Boolean>().error("验证码错误或已过期");
|
||||
}
|
||||
if (code.equals(redisUtil.get(HDConstant.CAPTCHA_REDIS_PREFIX + captchaId).toString())) {
|
||||
return new Result<Boolean>().success(true);
|
||||
}
|
||||
return new Result<Boolean>().error("验证码错误!");
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
package com.evotech.hd.authorization.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.http.auth.AuthenticationException;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.evotech.hd.authorization.config.oauth2.MyAccessToken;
|
||||
import com.evotech.hd.authorization.entity.LoginRequest;
|
||||
import com.evotech.hd.authorization.entity.UserVo;
|
||||
import com.evotech.hd.authorization.service.ResourceService;
|
||||
import com.evotech.hd.authorization.service.CaptchaService;
|
||||
import com.evotech.hd.authorization.service.LoginService;
|
||||
import com.evotech.hd.authorization.utils.LoginRequesHeadertUtil;
|
||||
import com.evotech.hd.authorization.utils.Oauth2AccessTokenUtil;
|
||||
import com.evotech.hd.authorization.utils.TokenUtil;
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
import com.evotech.hd.common.core.entity.LoginCacheInfo;
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.entity.resource.LogLogin;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthPermission;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthRole;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
import com.evotech.hd.common.redis.utils.RedisUtil;
|
||||
import com.evotech.hd.common.web.util.IpUtil;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Service
|
||||
public class LoginServiceImpl implements LoginService {
|
||||
|
||||
public static final Long DEFAULT_TOKEN_EXPIRATION = 7200L;
|
||||
public static final String TOKEN_END_POINT = "/oauth2/token";
|
||||
|
||||
@Resource
|
||||
private CaptchaService captchaService;
|
||||
@Resource
|
||||
private ResourceService resourceService;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private Environment env;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Result<UserVo> oauthLogin(LoginRequest lr, HttpServletRequest request) throws AuthenticationException {
|
||||
// 1. 校验验证码
|
||||
Result<Boolean> res = captchaService.checkCaptcha(lr.getCode());
|
||||
if (res.getStatus() != 1) {
|
||||
return new Result<UserVo>().error(res.getCode(), res.getMsg());
|
||||
}
|
||||
// 2. 从请求头获取client信息
|
||||
Map<String, String> oAuth2Client = LoginRequesHeadertUtil.getOAuth2Client(request);
|
||||
if (oAuth2Client == null) {
|
||||
return new Result<UserVo>().error("无客户端Client信息!");
|
||||
}
|
||||
// 3. 获取token
|
||||
String url = getTokenUrl();
|
||||
MyAccessToken token = Oauth2AccessTokenUtil.getToken(url, oAuth2Client.get("clientId"), oAuth2Client.get("clientSecret"), lr.getUsername(), lr.getPassword());
|
||||
|
||||
// 4.添加缓存
|
||||
UserVo uv = new UserVo();
|
||||
uv.setToken(token);
|
||||
uv = addRedisCache(uv);
|
||||
// 5. 添加登录记录
|
||||
Boolean loginLogFlag = true;
|
||||
if (loginLogFlag) {
|
||||
try {
|
||||
writeLoginLog(request, uv);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return new Result<UserVo>().success(uv);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接获取token的地址
|
||||
*/
|
||||
private String getTokenUrl() {
|
||||
int port = env.getProperty("server.port", Integer.class) == null?8080:env.getProperty("server.port", Integer.class);
|
||||
String url = "http://127.0.0.1" + ":" + port;
|
||||
String path = env.getProperty("server.servlet.context-path");
|
||||
url = StringUtils.hasText(path) ? url + path : url;
|
||||
url = url + TOKEN_END_POINT;
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
private void writeLoginLog(HttpServletRequest request, UserVo uv) {
|
||||
LogLogin loginLog = new LogLogin();
|
||||
Date d = new Date();
|
||||
loginLog.setUid(uv.getUid());
|
||||
loginLog.setUname(uv.getUname());
|
||||
loginLog.setName(uv.getName());
|
||||
loginLog.setLoginTime(d);
|
||||
loginLog.setCtime(d);
|
||||
loginLog.setRequestIp(IpUtil.getRemoteIP(request));
|
||||
String uaStr = request.getHeader("User-Agent");
|
||||
UserAgent ua = UserAgentUtil.parse(uaStr);
|
||||
loginLog.setUa(uaStr);
|
||||
loginLog.setBrowser(ua.getBrowser().toString());
|
||||
loginLog.setBrowserVersion(ua.getVersion());
|
||||
loginLog.setOperatingSystem(ua.getOs().toString());
|
||||
loginLog.setPlatForm(ua.getPlatform().toString());
|
||||
loginLog.setCreater("SYSTEM");
|
||||
resourceService.addLoginLog(loginLog);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 登陆缓存内容暂定
|
||||
* key:
|
||||
* hd:login:jti:token
|
||||
* hd:login:jti:user
|
||||
* hd:login:jti:rcodes
|
||||
* hd:login:jti:perms
|
||||
*
|
||||
*/
|
||||
private UserVo addRedisCache(UserVo uv) {
|
||||
String token = uv.getToken().getAccessToken();
|
||||
String uid = TokenUtil.getUserId(token);
|
||||
|
||||
// 1. 请求数据
|
||||
Result<LoginCacheInfo> res = resourceService.loginInfo(uid);
|
||||
if (!CodeMsg.SUCCESS.getCode().equals(res.getCode())) {
|
||||
throw new RuntimeException(res.getMsg());
|
||||
}
|
||||
|
||||
// 2. 处理数据
|
||||
String jti = TokenUtil.getJti(token);
|
||||
Object o = redisUtil.get(HDConstant.HD_CACHE_TOKEN_EXP_KEY);
|
||||
Long tokenExp = o == null ? DEFAULT_TOKEN_EXPIRATION : Long.valueOf(o.toString());
|
||||
redisUtil.set(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":token", token, tokenExp);
|
||||
|
||||
JSONObject jo = JSONUtil.parseObj(res.getData());
|
||||
AuthUser user = JSONUtil.toBean(jo.getJSONObject("user"), AuthUser.class);
|
||||
BeanUtils.copyProperties(user, uv);
|
||||
redisUtil.set(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":user", user, tokenExp);
|
||||
|
||||
List<AuthRole> roleList = JSONUtil.toList(jo.getJSONArray("roleList"), AuthRole.class);
|
||||
uv.setRoleList(roleList);
|
||||
String rcodes = roleList.stream().map(i -> i.getRcode()).collect(Collectors.joining(","));
|
||||
redisUtil.set(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":rcodes", rcodes, tokenExp);
|
||||
|
||||
List<String> rcodeList = roleList.stream().map(i -> i.getRcode()).toList();
|
||||
if (!rcodeList.contains(HDConstant.SYSTEM_MANAGER_ROLE_CODE)) {
|
||||
List<AuthPermission> permissionList = JSONUtil.toList(jo.getJSONArray("permissionList"), AuthPermission.class);
|
||||
List<String> permUriList = permissionList.stream().map(i -> i.getUri()).toList();
|
||||
List<String> permCodeList = permissionList.stream().map(i -> i.getCode()).toList();
|
||||
uv.setPermCodeList(permCodeList);
|
||||
redisUtil.lSet(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":perms", permUriList.toArray(new String[permUriList.size()]), tokenExp);
|
||||
}
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Result<String> logout(HttpServletRequest request) {
|
||||
String authorization = request.getHeader(HDConstant.AUTHORIZATION_KEY);
|
||||
if (authorization != null && authorization.contains(HDConstant.JWT_PREFIX)) {
|
||||
String token = authorization.substring(HDConstant.JWT_PREFIX.length());
|
||||
String jti = TokenUtil.getJti(token);
|
||||
redisUtil.del(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":token");
|
||||
redisUtil.del(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":user");
|
||||
redisUtil.del(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":rcodes");
|
||||
if (redisUtil.hasKey(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":perms")) {
|
||||
redisUtil.del(HDConstant.LOGIN_CACHE_KEY_PREFIX + jti + ":perms");
|
||||
}
|
||||
return new Result<String>().success("退出成功");
|
||||
} else {
|
||||
return new Result<String>().error("无token");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Result<Boolean> checkToken(String token) throws AuthenticationException {
|
||||
// TODO 发送到自带的token验证接口 验证
|
||||
|
||||
|
||||
return new Result<Boolean>().success(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package com.evotech.hd.authorization.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
import com.evotech.hd.common.core.constant.HDConstant;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public class LoginRequesHeadertUtil {
|
||||
|
||||
|
||||
public static Map<String, String> getOAuth2Client(HttpServletRequest request) {
|
||||
// 从请求头获取
|
||||
String basic = request.getHeader(HDConstant.AUTHORIZATION_KEY);
|
||||
if (StrUtil.isBlank(basic) || !basic.startsWith(HDConstant.BASIC_PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
basic = basic.replace(HDConstant.BASIC_PREFIX, Strings.EMPTY);
|
||||
//client:secret
|
||||
String basicPlainText = new String(Base64.getDecoder().decode(basic.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
|
||||
Map<String, String> m = new HashMap<>();
|
||||
m.put("clientId", basicPlainText.split(":")[0]);
|
||||
m.put("clientSecret", basicPlainText.split(":")[1]);
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.evotech.hd.authorization.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.evotech.hd.authorization.config.oauth2.MyAccessToken;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
public class Oauth2AccessTokenUtil {
|
||||
|
||||
|
||||
public static MyAccessToken getToken(String url, String clientId, String clientSecret, String username, String password) {
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("grant_type", "password");
|
||||
m.put("username", username);
|
||||
m.put("password", password);
|
||||
m.put("scope", "ALL");
|
||||
String body = HttpUtil
|
||||
.createPost(url)
|
||||
.basicAuth(clientId, clientSecret)
|
||||
.form(m)
|
||||
.execute()
|
||||
.body();
|
||||
JSONObject jo = JSONUtil.parseObj(body);
|
||||
if (CodeMsg.SUCCESS.getCode().equals(jo.getStr("code"))) {
|
||||
JSONObject jo1 = jo.getJSONObject("data");
|
||||
MyAccessToken tokenRes = new MyAccessToken();
|
||||
tokenRes.setAccessToken(jo1.getStr("access_token"));
|
||||
tokenRes.setExpiresIn(jo1.getLong("expires_in"));
|
||||
tokenRes.setRefreshToken(jo1.getStr("refresh_token"));
|
||||
tokenRes.setTokenType(jo1.getStr("token_type"));
|
||||
return tokenRes;
|
||||
} else {
|
||||
throw new RuntimeException("生成token出错");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.evotech.hd.authorization.utils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTUtil;
|
||||
|
||||
/**
|
||||
* token解析工具类
|
||||
*/
|
||||
public class TokenUtil {
|
||||
|
||||
|
||||
public static JWT parseToJwt(String token) {
|
||||
JWT parseToken = JWTUtil.parseToken(token);
|
||||
return parseToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从token中获取userId
|
||||
*/
|
||||
public static String getUserId(String token) {
|
||||
String uid = parseToJwt(token).getPayloads().getStr("uid");
|
||||
return uid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从token中获取jti
|
||||
*/
|
||||
public static String getJti(String token) {
|
||||
String jti = parseToJwt(token).getPayloads().getStr(JwtClaimNames.JTI).replaceAll("-", "");
|
||||
return jti;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从token中获取过期时间
|
||||
*/
|
||||
public static Date getExp(String token) {
|
||||
String exp = parseToJwt(token).getPayloads().getStr(JwtClaimNames.EXP).toString();
|
||||
return DateUtil.date(Long.valueOf(exp) * 1000);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
{"properties": [
|
||||
{
|
||||
"name": "security.token.public_key_base64",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'security.token.public_key_base64'"
|
||||
},
|
||||
{
|
||||
"name": "security.token.private_key_base64",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'security.token.private_key_base64'"
|
||||
}
|
||||
]}
|
||||
41
authorization-server/src/main/resources/application.yml
Normal file
41
authorization-server/src/main/resources/application.yml
Normal file
@ -0,0 +1,41 @@
|
||||
security.token.public_key_base64: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA23qzsZ/51EA9PAYvGyGwlSYEZxnGmF3FxiraUvLyeiBawyGFCHprnmG+fr+80KmhGh1UMbNwuwIRgn8tEY9TjlfK7iNhsX1QGEjrL6LggDJeXlA/XN4kRPY9sW7+VQpr1MPJjB5tQYVkPLvv3L8v/7k5hcPEoHIFwQoOnYBuQqLkj38EQ/NlOQLKzhyDRFWSm+6WzQF46fTMRLzRpfuFhUBk9oF3B8Y/vAajY90QDw5xdV0uGreK6CgESldCzx6hh1AHiLLICINRKTNL1t+uhRaz/f0xm8baxaKzusv2relz69GADCQl/GrTArcfWXVXqvetFzsQOt35EBOpxl3nRwIDAQAB
|
||||
security.token.private_key_base64: MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDberOxn/nUQD08Bi8bIbCVJgRnGcaYXcXGKtpS8vJ6IFrDIYUIemueYb5+v7zQqaEaHVQxs3C7AhGCfy0Rj1OOV8ruI2GxfVAYSOsvouCAMl5eUD9c3iRE9j2xbv5VCmvUw8mMHm1BhWQ8u+/cvy//uTmFw8SgcgXBCg6dgG5CouSPfwRD82U5AsrOHINEVZKb7pbNAXjp9MxEvNGl+4WFQGT2gXcHxj+8BqNj3RAPDnF1XS4at4roKARKV0LPHqGHUAeIssgIg1EpM0vW366FFrP9/TGbxtrForO6y/at6XPr0YAMJCX8atMCtx9ZdVeq960XOxA63fkQE6nGXedHAgMBAAECggEAGU5mDrp/31nC1btuzgWN6zyVcF/X9rSFO8qwHrVVgQBfBrXENYyMARiLEuk/t51/blfoX8ytWFquMyo/w5EPlM+JnfilaIYm6I3r1DPHB/EG0YAWNjqE2xC7X0yJdbu8YC1s/UN63H2pZ5lR2FWRDr7II6TFdKyA/lePBNkMnZEc6SueoCFxUVNjalE9XNwaBqTvS1omxh11m/I6y+V3YW3ymwFN4tXdIWv1NsM4l3HfAbAVreqSRPL9Z1HHPpAD06aWKZD4BqA1umHs31IkbgQ4RvsUu2XeXOI5a/T+7kXHItNk0u2ozM7H92M4VrEvMXAso7woqs9bHxBouaQVnQKBgQDiD3Iz2r/PRghARoZdO8vzzph4/p7DscjJmv3V/SqwWSVAkLVJbjEDB6omuar2EW7nxpW7yc9hwRLB5fEYIVUeUbkhTCY33WAikKYAkdGqAV9N/nI2euSavdluo9LB1FwuTz4yLXydPP+c97EiwAY4Xle0Zbg41g1DhAz6rqrnswKBgQD4jCBnDvb/GQROip0FDLSu63STLySwka/bP8OIC8x4UN6eI+heT9sPoxBBsUdHwSKUfOP1oKoW+fLYGyX/2Gn64M/5L6ds5e7yaIZFykNVU0ysItTuAFt9tsOEZtxhRZlaQb9F3RRkzd10rZB0s0Pueg9X19ncUvpHqn+aIyO4HQKBgFA+CVystk893anrHsCzfBbj661vPC3cypf9g0LVJbUJP7bmZuNU0OLxco1idHP6BjMRg47v+MQLQ7w+AdF963firGNMY3iLBRff3nzvRcwhxpGp0yLRhpoC785dKm+RENODX2FyUfyCbX1rUp4yKUMTAfDP9o9+M6EWm4DURWgPAoGAcxr6GqBclTFxxCn/pAoJV4TlvRA1LqyZw7EZDdVhAUt6fcRlZeAXtHsxGStPtpRkPl5EeEnK288vvxN7mqwQEMayqlV+dTlbWto7bPDKFCb6uDF9aSezN1o/2/6DC21fIuSV/3XubuzEJbgH0XP//t56YpUtaRLoo+37IFgrv6UCgYAsTEQkg8la0BgKL9maiubnqdbl9nwS6l4lJqtlNNLaWIkiePmsY1dlkY91oQbc+YH3IJFexX/viuzZBXBJm9Hnf/MG+VeUz0f6ldZ2tI8fYbXIu0YadNmh0nnEAsUMaG7wYK6xnXiklh0LSjZUfWGmC4x/s2s1ixQme5ZIO2IPKQ==
|
||||
# 1.server
|
||||
server:
|
||||
port: 9101
|
||||
servlet:
|
||||
context-path: /oauth2
|
||||
# 2. log
|
||||
logging:
|
||||
config: classpath:logback-spring.xml
|
||||
# 3.spring
|
||||
spring:
|
||||
application:
|
||||
name: oauth2-server
|
||||
config:
|
||||
import:
|
||||
- nacos:${spring.application.name}.yaml?refreshEnabled=true
|
||||
cloud:
|
||||
nacos:
|
||||
serverAddr: 192.168.5.213:8848
|
||||
username: nacos
|
||||
password: nacos
|
||||
discovery:
|
||||
register-enabled: true
|
||||
#server-addr: 10.10.1.6:8848
|
||||
#ip: 192.168.5.200
|
||||
metadata:
|
||||
management:
|
||||
context-path: ${server.servlet.context-path}/actuator
|
||||
# 5.为springbootadmin开启所有检查
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "*"
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
# xml文件中配置的日志文件的名称
|
||||
logfile:
|
||||
external-file: /logs/oauth2/oauth2-server.log
|
||||
91
authorization-server/src/main/resources/logback-spring.xml
Normal file
91
authorization-server/src/main/resources/logback-spring.xml
Normal file
@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="10 seconds">
|
||||
|
||||
<property name="CONTEXT_NAME" value="oauth2-server" />
|
||||
<property name="LOG_PATH" value="/logs/oauth2" />
|
||||
<property name="MAX_FILE_SIZE" value="100MB" />
|
||||
<property name="MAX_HISTORY" value="30" />
|
||||
<!--读取配置中心的属性 -->
|
||||
<!-- <springProperty scope="context" name="LOG_PATH_NAME" source="logging.file.name"/> -->
|
||||
|
||||
<contextName>${CONTEXT_NAME}</contextName>
|
||||
|
||||
<!--输出到控制台 -->
|
||||
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%i索引【从数字0开始递增】 -->
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>DEBUG</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<!--%logger{50}:表示logger名字最长50个字符,否则按照句点分割 -->
|
||||
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %replace(%caller{1}){'\t|Caller.{1}0|\r\n', ''} -- %msg%n</Pattern>
|
||||
<!-- 设置字符集 -->
|
||||
<charset>UTF-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--所有日志输出到文件 -->
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--日志名,指定最新的文件名,其他文件名使用FileNamePattern -->
|
||||
<File>${LOG_PATH}/${CONTEXT_NAME}.log</File>
|
||||
<!--日志文件输出格式 -->
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{50}.%M\(%line\) -- %msg%n</pattern>
|
||||
<charset>UTF-8</charset> <!-- 设置字符集 -->
|
||||
</encoder>
|
||||
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志归档 后面可以加.zip -->
|
||||
<fileNamePattern>${LOG_PATH}/${CONTEXT_NAME}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
|
||||
<!--日志文件保留天数 -->
|
||||
<maxHistory>${MAX_HISTORY}</maxHistory>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<!--文件达到 最大时会被压缩和切割 -->
|
||||
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- ERROR 日志 -->
|
||||
<!-- 暂时不用了,输出到一个文件 -->
|
||||
|
||||
<!-- 异步日志输出看情况配置 -->
|
||||
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>512</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
|
||||
<!-- 统一配置日志输出,root标签和logger标签,如果这开启了就把不同环境的关上 -->
|
||||
<!-- root标签:相当于开关,只有把定义的appender添加到这里 才会生效有日志 -->
|
||||
<root level="Info">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
</root>
|
||||
<!-- logger标签:用来设置某一个包或者具体的某一个类的日志打印级别 -->
|
||||
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="INFO" />
|
||||
|
||||
<!-- 配置不同环境的日志输出,root标签和logger标签 -->
|
||||
<!-- <springProfile name="dev">
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE" />
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
</root>
|
||||
<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG" />
|
||||
</springProfile> -->
|
||||
|
||||
<!-- <springProfile name="prod">
|
||||
<root level="INFO">
|
||||
<appender-ref ref="ASYNC_FILE" />
|
||||
</root>
|
||||
</springProfile> -->
|
||||
|
||||
</configuration>
|
||||
@ -0,0 +1,13 @@
|
||||
package com.evotech.hd.authorization;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class AuthorizationServerApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
71
base-commons/common-core/pom.xml
Normal file
71
base-commons/common-core/pom.xml
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>base-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-core</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||
</dependency>
|
||||
<!-- 注解校验参数需要的2个包,2个都需要 -->
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
</build>
|
||||
</project>
|
||||
@ -0,0 +1,74 @@
|
||||
package com.evotech.hd.common.core.constant;
|
||||
|
||||
public interface HDConstant {
|
||||
|
||||
/**
|
||||
* 系统管理员角色
|
||||
*/
|
||||
String SYSTEM_MANAGER_ROLE_CODE = "SYSADMIN";
|
||||
|
||||
/**
|
||||
* 认证请求头key
|
||||
*/
|
||||
String AUTHORIZATION_KEY = "Authorization";
|
||||
|
||||
/**
|
||||
* JWT令牌前缀
|
||||
*/
|
||||
String JWT_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* Basic认证前缀
|
||||
*/
|
||||
String BASIC_PREFIX = "Basic ";
|
||||
|
||||
/**
|
||||
* JWT载体key
|
||||
*/
|
||||
String JWT_PAYLOAD_KEY = "payload";
|
||||
|
||||
|
||||
/**
|
||||
* jwt中添加的属性
|
||||
*/
|
||||
String USER_ID_KEY = "uid";
|
||||
String ROLE_CODE_KEY = "rcodes";
|
||||
|
||||
|
||||
/**
|
||||
* 登陆验证码缓存key
|
||||
* hd:login:captcha: + captchaId
|
||||
*/
|
||||
String CAPTCHA_REDIS_PREFIX = "hd:login:captcha:";
|
||||
|
||||
/**
|
||||
* 登陆缓存内容前缀
|
||||
* key: hd:login:jti:token
|
||||
*/
|
||||
String LOGIN_CACHE_KEY_PREFIX = "hd:login:";
|
||||
|
||||
/**
|
||||
* 缓存系统token有效时间,s
|
||||
*/
|
||||
String HD_CACHE_TOKEN_EXP_KEY = "hd:cache:tokenExp";
|
||||
|
||||
/**
|
||||
* 资源权限类型
|
||||
*/
|
||||
String RESOURCE_TYPE_PERM = "PER";
|
||||
String RESOURCE_TYPE_MENU = "MENU";
|
||||
|
||||
|
||||
/**
|
||||
* 交换数据非对称加密RSA秘钥前缀
|
||||
*/
|
||||
String HD_STATION_SECRET_KEY_RSA_PREFIX = "hd:station:secretKey:rsa:";
|
||||
|
||||
|
||||
/**
|
||||
* 交换数据对称加密AES秘钥前缀
|
||||
*/
|
||||
String HD_STATION_SECRET_KEY_AES_PREFIX = "hd:station:secretKey:aes:";
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.ProxyOperater;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-15
|
||||
*/
|
||||
public interface ProxyOperaterDao extends BaseMapper<ProxyOperater> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthMenu;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthMenuDao extends BaseMapper<AuthMenu> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthPermission;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthPermissionDao extends BaseMapper<AuthPermission> {
|
||||
|
||||
List<AuthPermission> listPermByUid(@Param("uid") String uid);
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthRole;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthRoleDao extends BaseMapper<AuthRole> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthRoleResource;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthRoleResourceDao extends BaseMapper<AuthRoleResource> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthUserDao extends BaseMapper<AuthUser> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUserRole;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
public interface AuthUserRoleDao extends BaseMapper<AuthUserRole> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.dict;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.dict.AdmdvsInfo;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
public interface AdmdvsInfoDao extends BaseMapper<AdmdvsInfo> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.evotech.hd.common.core.dao.resource.dict;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.request.ListDictRequest;
|
||||
import com.evotech.hd.common.core.entity.resource.dict.Dict;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
public interface DictDao extends BaseMapper<Dict> {
|
||||
|
||||
List<Dict> listDict(@Param("ldr") ListDictRequest ldr);
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.evotech.hd.common.core.dao.resource.dict;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.evotech.hd.common.core.entity.resource.dict.DictType;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
public interface DictTypeDao extends BaseMapper<DictType> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.evotech.hd.common.core.entity;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "分页基类")
|
||||
public class BasePageRequest {
|
||||
|
||||
|
||||
@Schema(description = "每页条数", requiredMode = RequiredMode.REQUIRED, example = "10" )
|
||||
@Min(value = 1)
|
||||
private Integer pageSize = 10;
|
||||
@Schema(description = "页数", requiredMode = RequiredMode.REQUIRED, example = "1")
|
||||
@Min(1)
|
||||
private Integer pageNo = 1;
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.evotech.hd.common.core.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthPermission;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthRole;
|
||||
import com.evotech.hd.common.core.entity.resource.auth.AuthUser;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "登陆时缓存数据")
|
||||
public class LoginCacheInfo {
|
||||
|
||||
@Schema(description = "token")
|
||||
private String token;
|
||||
|
||||
@Schema(description = "权限")
|
||||
private AuthUser user;
|
||||
|
||||
@Schema(description = "角色")
|
||||
List<AuthRole> roleList;
|
||||
|
||||
@Schema(description = "权限")
|
||||
List<AuthPermission> permissionList;
|
||||
|
||||
}
|
||||
@ -0,0 +1,164 @@
|
||||
package com.evotech.hd.common.core.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @date 2024年9月2日17:25:54
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "请求返回对象")
|
||||
public class Result<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7806513009135956518L;
|
||||
|
||||
@Schema(description = "请求处理状态", example = "1")
|
||||
private Integer status;
|
||||
@Schema(description = "状态码", example = "1000")
|
||||
private String code;
|
||||
@Schema(description = "返回消息")
|
||||
private String msg;
|
||||
@Schema(description = "返回数据")
|
||||
private Object data;
|
||||
|
||||
private T obj;
|
||||
|
||||
|
||||
public Result(Integer status, String code, String msg, Object data) {
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Result(Integer status, String msg, Object data) {
|
||||
this.status = status;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Result(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Result() {
|
||||
}
|
||||
|
||||
public Result(Integer status, String code, String msg) {
|
||||
this.status = status;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Result(Integer status, String msg) {
|
||||
this.status = status;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Result<T> success(Object o) {
|
||||
this.status = 1;
|
||||
this.code = CodeMsg.SUCCESS.getCode();
|
||||
this.msg = CodeMsg.SUCCESS.getMsg();
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> success(String msg, Object o) {
|
||||
this.status = 1;
|
||||
this.code = CodeMsg.SUCCESS.getCode();
|
||||
this.msg = msg;
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> success(String msg) {
|
||||
this.status = 1;
|
||||
this.code = CodeMsg.SUCCESS.getCode();
|
||||
this.msg = msg;
|
||||
this.data = CodeMsg.SUCCESS.getMsg();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> success(String code, String msg, Object o) {
|
||||
this.status = 1;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> success(CodeMsg cm, Object o) {
|
||||
this.status = 0;
|
||||
this.code = cm.getCode();
|
||||
this.msg = cm.getMsg();
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error(String msg) {
|
||||
this.status = 0;
|
||||
this.code = CodeMsg.ERROR.getCode();
|
||||
this.msg = msg;
|
||||
this.data = "ERROR";
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error(String code, String msg) {
|
||||
this.status = 0;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = "ERROR";
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error(CodeMsg cm) {
|
||||
this.status = 0;
|
||||
this.code = cm.getCode();
|
||||
this.msg = cm.getMsg();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error(CodeMsg cm, Object o) {
|
||||
return error(cm.getCode(), cm.getMsg(), o);
|
||||
}
|
||||
|
||||
public Result<T> error(String code, String msg, Object o) {
|
||||
this.status = 0;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Result<T> error(String msg, Object o) {
|
||||
this.status = 0;
|
||||
this.code = CodeMsg.ERROR.getCode();
|
||||
this.msg = msg;
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Result<T> exception(Object data) {
|
||||
this.status = -1;
|
||||
this.code = CodeMsg.ERROR.getCode();
|
||||
this.msg = CodeMsg.ERROR.getMsg();
|
||||
this.data = data==null?"未知异常":data;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Result<T> bussinessException(String code, String msg, Object o) {
|
||||
this.status = -1;
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = o;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-15
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_battery_station")
|
||||
@Schema(name = "BatteryStation", description = "换电站")
|
||||
public class BatteryStation implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Hidden
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "归属运营商ID", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "无关联运营商信息")
|
||||
private String proxyId;
|
||||
|
||||
@Schema(description = "站点名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "站点名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "站点编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "站点编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "状态:1-正常营业,2-正常停运,3-故障停运,4-指令停运,9-其它", requiredMode = RequiredMode.REQUIRED)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "站点类型ID")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "地址-省")
|
||||
private String addressProvince;
|
||||
|
||||
@Schema(description = "地址-市")
|
||||
private String addressCity;
|
||||
|
||||
@Schema(description = "地址-区县")
|
||||
private String addressArea;
|
||||
|
||||
@Schema(description = "注册日期")
|
||||
private String registerDate;
|
||||
|
||||
@Schema(description = "联系人")
|
||||
private String contacts;
|
||||
|
||||
@Schema(description = "联系电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "删除标识:1-已删除,0-未删除")
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "激活日期")
|
||||
private String activeDate;
|
||||
|
||||
@Schema(description = "经纬度信息")
|
||||
private String locationPoint;
|
||||
|
||||
@Schema(description = "全天营业:1-是,0-否")
|
||||
private Integer openAllDay;
|
||||
|
||||
@Schema(description = "通道数")
|
||||
private Integer tdQuantity;
|
||||
|
||||
@Schema(description = "机器人数量")
|
||||
private Integer jqrQuantity;
|
||||
|
||||
@Schema(description = "充电机数量")
|
||||
private Integer cdjQuantity;
|
||||
|
||||
@Schema(description = "电池仓数量")
|
||||
private Integer dccQuantity;
|
||||
|
||||
@Schema(description = "电池数量")
|
||||
private Integer dcQuantity;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
|
||||
@Schema(description = "电池列表", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationDc> dcList;
|
||||
|
||||
@Schema(description = "电池仓列表", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationDcc> dccList;
|
||||
|
||||
@Schema(description = "电机列表", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationDj> djList;
|
||||
|
||||
@Schema(description = "机器人列表", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationRobot> robotList;
|
||||
|
||||
@Schema(description = "换电费用标准", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationHdFeeStandard> feeStandardList;
|
||||
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_dc")
|
||||
@Schema(name = "电站-电池")
|
||||
public class BatteryStationDc implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "电池型号编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "型号编码不能为空")
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "电池编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "电池编码不能为空")
|
||||
private String batCode;
|
||||
|
||||
@Schema(description = "生产日期", example = "yyyyMMdd")
|
||||
private String productionDate;
|
||||
|
||||
@Schema(description = "注册时间", example = "yyyyMMdd")
|
||||
private String registrationDate;
|
||||
|
||||
@Schema(description = "初始来源:1-站,2-车", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "初始来源不能为空")
|
||||
private Integer sourceFrom;
|
||||
|
||||
@Schema(description = "站码或车牌照")
|
||||
private String sourceCode;
|
||||
|
||||
@Schema(description = "状态:1-出租中,2-充电中,3-充电完毕,4-故障,5-其它", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "当前电量")
|
||||
private Integer soc;
|
||||
|
||||
@Schema(description = "删除标志:1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_dcc")
|
||||
@Schema(name = "电站-电池仓")
|
||||
public class BatteryStationDcc implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "电池仓序号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "电池仓序号不能为空")
|
||||
private String dccNo;
|
||||
|
||||
@Schema(description = "状态:1-正常,2-检修, 3-坏", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,80 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_dj")
|
||||
@Schema(name = "电站-电机")
|
||||
public class BatteryStationDj implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "充电机编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "充电机编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "充电机软件版本", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "充电机软件版本不能为空")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "电池仓序号")
|
||||
private String dccNo;
|
||||
|
||||
@Schema(description = "充电连接类型:1-连接器,2-充电枪", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "充电连接类型不能为空")
|
||||
private Integer switchType;
|
||||
|
||||
@Schema(description = "状态:1-正常,2-检修, 3-坏", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "充电枪数量")
|
||||
private Integer gunNum;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_hd_fee_standard")
|
||||
@Schema(name = "电站-换电费用标准")
|
||||
public class BatteryStationHdFeeStandard implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "费用标准名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "开始日期", requiredMode = RequiredMode.REQUIRED, example = DatePattern.PURE_DATE_PATTERN)
|
||||
@NotBlank(message = "开始时间不能为空")
|
||||
private String dayBegin;
|
||||
|
||||
@Schema(description = "结束日期", requiredMode = RequiredMode.REQUIRED, example = DatePattern.PURE_DATE_PATTERN)
|
||||
@NotBlank(message = "结束时间不能为空")
|
||||
private String dayEnd;
|
||||
|
||||
@Schema(description = "正常换电服务费")
|
||||
private BigDecimal commonRemainFee;
|
||||
|
||||
@Schema(description = "换电时正常电量范围")
|
||||
private String commonRemainSocRange;
|
||||
|
||||
@Schema(description = "换电时电量剩余过多的soc界定")
|
||||
private Integer moreRemainSoc;
|
||||
|
||||
@Schema(description = "换电时电量剩余过多的服务费")
|
||||
private BigDecimal moreRemainFee;
|
||||
|
||||
@Schema(description = "换电时电量剩余一般的soc界定")
|
||||
private Integer fewRemainSoc;
|
||||
|
||||
@Schema(description = "换电时电量剩余一般的服务费")
|
||||
private BigDecimal fewRemainFee;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
@Schema(description = "换电费用标准细节", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<BatteryStationHdFeeStandardDetail> detailList;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_hd_fee_standard_detail")
|
||||
@Schema(name = "电站-换电费用标准细节")
|
||||
public class BatteryStationHdFeeStandardDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "收费规则ID", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer standardId;
|
||||
|
||||
@Schema(description = "每公里收费")
|
||||
private BigDecimal eachKmFee;
|
||||
|
||||
@Schema(description = "每SOC收费")
|
||||
private BigDecimal eachSocFee;
|
||||
|
||||
@Schema(description = "每度电收费")
|
||||
private BigDecimal eachKwhFee;
|
||||
|
||||
@Schema(description = "开始时间", requiredMode = RequiredMode.REQUIRED, example = DatePattern.NORM_TIME_PATTERN)
|
||||
@NotNull
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_TIME_PATTERN)
|
||||
private LocalTime timeBegin;
|
||||
|
||||
@Schema(description = "结束时间", requiredMode = RequiredMode.REQUIRED, example = DatePattern.NORM_TIME_PATTERN)
|
||||
@NotNull
|
||||
@DateTimeFormat(pattern = DatePattern.NORM_TIME_PATTERN)
|
||||
private LocalTime timeEnd;
|
||||
|
||||
@Schema(description = "谷段服务费")
|
||||
private BigDecimal timeServiceFee;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_battery_station_robot")
|
||||
@Schema(name = "电站-机器人")
|
||||
public class BatteryStationRobot implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "机器人编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "机器人编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "状态:1-正常", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "运行模式:1-就地,2-远程")
|
||||
private Integer runMode;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-12-06
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_battery_trace")
|
||||
@Schema(name = "电池追溯表")
|
||||
public class BatteryTrace implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "电池编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String batCode;
|
||||
|
||||
@Schema(description = "轨迹点类型:1-电站,2-车辆", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer pointType;
|
||||
|
||||
@Schema(description = "开始时间", example = "yyyy-MM-dd HH:mm:ss", requiredMode = RequiredMode.REQUIRED)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date beginTime;
|
||||
|
||||
@Schema(description = "轨迹点编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String pointCode;
|
||||
|
||||
@Schema(description = "轨迹点名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String pointName;
|
||||
|
||||
@Schema(description = "结束时间", example = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_order_recharge")
|
||||
@Schema(name = "充值订单")
|
||||
public class OrderRecharge implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "订单时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date orderTime;
|
||||
|
||||
@Schema(description = "订单编码", hidden = true)
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站名称")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "钱包账户账号")
|
||||
private String accountCode;
|
||||
|
||||
@Schema(description = "充值账号ID")
|
||||
private String userId;
|
||||
|
||||
@Schema(description = "交易编码")
|
||||
private String tradeNo;
|
||||
|
||||
@Schema(description = "删除状态:1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_order_swap_battery")
|
||||
@Schema(name = "换电订单信息表")
|
||||
public class OrderSwapBattery implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "预约订单ID")
|
||||
private Integer orderPreId;
|
||||
|
||||
@Schema(description = "预约用户")
|
||||
private String orderPreUid;
|
||||
|
||||
@Schema(description = "预约用户名称")
|
||||
private String orderPreUname;
|
||||
|
||||
@Schema(description = "预约用户手机")
|
||||
private String orderPrePhone;
|
||||
|
||||
@Schema(description = "类型:1-换电,2-充电", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "订单类型不能为空")
|
||||
private Integer orderType;
|
||||
|
||||
@Schema(description = "订单编码", hidden = true)
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "车牌号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "车牌号不能为空")
|
||||
private String plateNum;
|
||||
|
||||
@Schema(description = "订单时间", example = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date orderTime;
|
||||
|
||||
@Schema(description = "换电站编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "换电站名称不能为空")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "金额账号")
|
||||
private String accountCode;
|
||||
|
||||
@Schema(description = "订单金额")
|
||||
private Integer amount;
|
||||
|
||||
@Schema(description = "订单状态:1-已创建,2-换电中,3-换电完成,4-充电中,5-充电完成,6-待结算,7-已完成,9-已取消")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "计算费用方式:1-ODO,2-SOC,3-按电量")
|
||||
private Integer feeType;
|
||||
|
||||
@Schema(description = "基础费用")
|
||||
private Integer basicFee;
|
||||
|
||||
@Schema(description = "服务开始时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date serviceTimeBegin;
|
||||
|
||||
@Schema(description = "服务结束时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date serviceTimeEnd;
|
||||
|
||||
@Schema(description = "服务费")
|
||||
private Integer serviceFee;
|
||||
|
||||
@Schema(description = "上次租赁电池时车辆里程")
|
||||
private BigDecimal lastRentBatCarOdo;
|
||||
|
||||
@Schema(description = "归还电池时车辆里程")
|
||||
private BigDecimal nowReturnBatCarOdo;
|
||||
|
||||
@Schema(description = "按ODO换电费")
|
||||
private BigDecimal odoAmount;
|
||||
|
||||
@Schema(description = "充电开始时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date chargeTimeBegin;
|
||||
|
||||
@Schema(description = "充电结束时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date chargeTimeEnd;
|
||||
|
||||
@Schema(description = "总充电量")
|
||||
private BigDecimal electAmount;
|
||||
|
||||
@Schema(description = "租借电池包仓位")
|
||||
private Integer rentBatNo;
|
||||
|
||||
@Schema(description = "租用电池包编码")
|
||||
private String rentBatCode;
|
||||
|
||||
@Schema(description = "租用电池包SOC")
|
||||
private Integer rentBatSoc;
|
||||
|
||||
@Schema(description = "归还电池包编码")
|
||||
private String returnBatCode;
|
||||
|
||||
@Schema(description = "归还电池包仓位")
|
||||
private Integer returnBatNo;
|
||||
|
||||
@Schema(description = "归还电池包SOC")
|
||||
private Integer returnBatSoc;
|
||||
|
||||
@Schema(description = "归还电池租出时soc")
|
||||
private Integer returnBatRentSoc;
|
||||
|
||||
@Schema(description = "归还电池租出的换电站编码")
|
||||
private String returnBatRentStationCode;
|
||||
|
||||
@Schema(description = "归还电池租出的换电站")
|
||||
private String returnBatRentStationName;
|
||||
|
||||
@Schema(description = "换电模式:1-全自动,2-半自动,3-人工干预 ")
|
||||
private Integer changeMode;
|
||||
|
||||
@Schema(description = "换电车道 1-A 车道;2-B 车道")
|
||||
private Integer changeLane;
|
||||
|
||||
@Schema(description = "删除状态:1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "交易编码", hidden = true)
|
||||
private String tradeNo;
|
||||
|
||||
@Schema(description = "备注信息")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-12-04
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_order_swap_battery_pre")
|
||||
@Schema(name = "换电预约订单")
|
||||
public class OrderSwapBatteryPre implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(description = "ID", hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "来源:1-小程序,2-云端,3-站端", requiredMode = RequiredMode.REQUIRED)
|
||||
private Integer from;
|
||||
|
||||
@Schema(description = "来源是站端时,记录发送Id,其他来源不需要", hidden = true)
|
||||
private String sourceId;
|
||||
|
||||
@Schema(description = "预约人编码")
|
||||
private String ucode;
|
||||
|
||||
@Schema(description = "预约人姓名")
|
||||
private String uname;
|
||||
|
||||
@Schema(description = "手机号码")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "车牌号")
|
||||
private String plateNum;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "换电站名称")
|
||||
private String stationName;
|
||||
|
||||
@Schema(description = "预约时间", hidden = true)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date reservationTime;
|
||||
|
||||
@Schema(description = "预约换电日期", example = "yyyyMMdd", requiredMode = RequiredMode.REQUIRED)
|
||||
private String swapDay;
|
||||
|
||||
@Schema(description = "预约换电时间段", example = "8:00-10:00")
|
||||
private String swapDuration;
|
||||
|
||||
@Schema(description = "状态:1-预约成功,2-到店使用,3-取消,4-过期", hidden = true)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_order_swap_battery_step")
|
||||
@Schema(name = "换电步骤记录")
|
||||
public class OrderSwapBatteryStep implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(description = "ID", hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "订单编码")
|
||||
private String orderNo;
|
||||
|
||||
@Schema(description = "步骤:1-车辆进站,2-车辆到达指定位置,3-对中机构,4-取新电,5-拆旧电,6-装新电,7-放旧电,8-完成")
|
||||
private Integer step;
|
||||
|
||||
@Schema(description = "步骤时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date stepTime;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_trade_detail")
|
||||
@Schema(name = "交易信息表")
|
||||
public class TradeDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "换电站编码")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "账号编码")
|
||||
private String accountCode;
|
||||
|
||||
@Schema(description = "账号")
|
||||
private String accountName;
|
||||
|
||||
@Schema(description = "交易编码")
|
||||
private String outTradeNo;
|
||||
|
||||
@Schema(description = "交易类型:1-充值,2-订单消费,3-提现")
|
||||
private Integer tradeType;
|
||||
|
||||
@Schema(description = "支付方式:1-账户余额,2-微信,3-支付宝,4-网银,5 -充电补偿")
|
||||
private Integer payType;
|
||||
|
||||
@Schema(description = "订单数量")
|
||||
private Integer orderCount;
|
||||
|
||||
@Schema(description = "订单编码")
|
||||
private String orderNums;
|
||||
|
||||
@Schema(description = "交易金额")
|
||||
private Integer tradeAmount;
|
||||
|
||||
@Schema(description = "交易前账户余额")
|
||||
private Integer preAccountAmount;
|
||||
|
||||
@Schema(description = "交易后账户余额")
|
||||
private Integer afterAccountAmount;
|
||||
|
||||
@Schema(description = "优惠券编码")
|
||||
private String couponCode;
|
||||
|
||||
@Schema(description = "优惠金额")
|
||||
private Integer giftAmount;
|
||||
|
||||
@Schema(description = "微信支付订单号")
|
||||
private String transactionId;
|
||||
|
||||
@Schema(description = "支付结果: 0-未支付, 1-已支付, 2-支付失败")
|
||||
private Integer payResult;
|
||||
|
||||
@Schema(description = "在微信等支付网关创建支付订单时失败,返回的失败原因")
|
||||
private String payMsg;
|
||||
|
||||
@Schema(description = "删除标识,1-已删除,0-未删除")
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
@Schema(description = "退款结果: 0-未退款, 1-退款中,2-已退款, 3-退款失败")
|
||||
private Integer refundResult;
|
||||
|
||||
@Schema(description = "在微信等退款网关创建退款订单时失败,返回的失败原因")
|
||||
private String refundMsg;
|
||||
|
||||
@Schema(description = "退款返回数据")
|
||||
private String refundReturn;
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_vehicle_info")
|
||||
@Schema(name = "车辆信息表")
|
||||
public class VehicleInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "型号编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "型号编码不能为空")
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "车辆识别代码VIN号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "VIN号不能为空")
|
||||
private String vinNo;
|
||||
|
||||
@Schema(description = "车架号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "车架号不能为空")
|
||||
private String frameworkNo;
|
||||
|
||||
@Schema(description = "车主类型:1-个人,2-企业", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "车主类型不能为空")
|
||||
private Integer ownerType;
|
||||
|
||||
@Schema(description = "车主ID")
|
||||
private String ownerId;
|
||||
|
||||
@Schema(description = "车主名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "车主名称不能为空")
|
||||
private String ownerName;
|
||||
|
||||
@Schema(description = "车牌号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "车牌号不能为空")
|
||||
private String plateNum;
|
||||
|
||||
@Schema(description = "引擎号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "引擎号不能为空")
|
||||
private String engineNo;
|
||||
|
||||
@Schema(description = "座位数")
|
||||
private Integer seatsCount;
|
||||
|
||||
@Schema(description = "车身颜色")
|
||||
private String carColor;
|
||||
|
||||
@Schema(description = "车籍/归属地")
|
||||
private String carArea;
|
||||
|
||||
@Schema(description = "出厂日期")
|
||||
private String productionDate;
|
||||
|
||||
@Schema(description = "购车日期")
|
||||
private String purchaseDate;
|
||||
|
||||
@Schema(description = "上牌日期")
|
||||
private String boardDate;
|
||||
|
||||
@Schema(description = "首次登记日期")
|
||||
private String registrationDate;
|
||||
|
||||
@Schema(description = "消费方式:1-电量,2-里程", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "消费方式不能为空")
|
||||
private Integer usageType;
|
||||
|
||||
@Schema(description = "总里程")
|
||||
private BigDecimal totalMileage;
|
||||
|
||||
@Schema(description = "联系电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "删除状态,1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "公司名称")
|
||||
private String cname;
|
||||
|
||||
@Schema(description = "组织机构代码")
|
||||
private String ccode;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_vehicle_wechat_user_relation")
|
||||
@Schema(name = "车辆和用户关系")
|
||||
public class VehicleWechatUserRelation implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "用户编码", requiredMode = RequiredMode.REQUIRED)
|
||||
private String ucode;
|
||||
|
||||
@Schema(description = "用户名称", requiredMode = RequiredMode.REQUIRED)
|
||||
private String uname;
|
||||
|
||||
@Schema(description = "微信用户标识")
|
||||
private String openid;
|
||||
|
||||
@Schema(description = "车牌号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "车牌号不能为空")
|
||||
private String plateNum;
|
||||
|
||||
@Schema(description = "车主类型:1-个人,2-企业", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "车主类型不能为空")
|
||||
private Integer ownerType;
|
||||
|
||||
@Schema(description = "关联人手机号", requiredMode = RequiredMode.REQUIRED)
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_wallet_account")
|
||||
@Schema(name = "资金钱包账户表")
|
||||
public class WalletAccount implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "户主类型:1-个人,2-企业", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull(message = "类型不能为空")
|
||||
private Integer ownerType;
|
||||
|
||||
@Schema(description = "户主ID", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "用户编码不能为空")
|
||||
private String ownerId;
|
||||
|
||||
@Schema(description = "编码", hidden = true)
|
||||
private String code;
|
||||
|
||||
@Schema(description = "账户总金额,分:总金额=充值金额+赠送金额")
|
||||
private Integer totalAmount;
|
||||
|
||||
@Schema(description = "充值余额,分")
|
||||
private Integer rechargeAmount;
|
||||
|
||||
@Schema(description = "赠送金额,分")
|
||||
private Integer giftAmount;
|
||||
|
||||
@Schema(description = "积分余额")
|
||||
private Integer point;
|
||||
|
||||
@Schema(description = "押金")
|
||||
private Integer deposit;
|
||||
|
||||
@Schema(description = "SN码")
|
||||
private String snCode;
|
||||
|
||||
@Schema(description = "租金")
|
||||
private Integer rent;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Boolean status;
|
||||
|
||||
@Schema(description = "引入站点", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "站点编码不能为空")
|
||||
private String stationCode;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package com.evotech.hd.common.core.entity.cloud;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-22
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_t_wallet_account_detail")
|
||||
@Schema(name = "资金账户明细")
|
||||
public class WalletAccountDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
@Schema(hidden = true)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String code;
|
||||
|
||||
@Schema(description = "交易编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String tradeNo;
|
||||
|
||||
@Schema(description = "交易前账户总金额,分:总金额=充值金额+赠送金额", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer preTotalAmount;
|
||||
|
||||
@Schema(description = "交易前充值余额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer preRechargeAmount;
|
||||
|
||||
@Schema(description = "交易前赠送金额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer preGiftAmount;
|
||||
|
||||
@Schema(description = "交易总金额,分:总金额=充值金额+赠送金额", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer tradeTotalAmount;
|
||||
|
||||
@Schema(description = "交易充值余额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer tradeRechargeAmount;
|
||||
|
||||
@Schema(description = "交易赠送金额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer tradeGiftAmount;
|
||||
|
||||
@Schema(description = "交易后总金额,分:总金额=充值金额+赠送金额", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer afterTotalAmount;
|
||||
|
||||
@Schema(description = "交易后充值余额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer afterRechargeAmount;
|
||||
|
||||
@Schema(description = "交易后赠送金额,分", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer afterGiftAmount;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.evotech.hd.common.core.entity.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(name = "查询字典参数")
|
||||
public class ListDictRequest {
|
||||
|
||||
@Schema(description = "字典类型id")
|
||||
private String typeId;
|
||||
|
||||
@Schema(description = "字典类型名")
|
||||
private String typeName;
|
||||
|
||||
@Schema(description = "字典类型编码")
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "字典id")
|
||||
private String dictId;
|
||||
|
||||
@Schema(description = "字典名")
|
||||
private String dictName;
|
||||
|
||||
@Schema(description = "字典编码")
|
||||
private String dictCode;
|
||||
|
||||
@Schema(description = "字典值")
|
||||
private String dictValue;
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
package com.evotech.hd.common.core.entity.resource;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @date 2024年9月6日08:35:28
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("yt_log_login")
|
||||
@Schema(name = "登录日志", description = "登录日志")
|
||||
public class LogLogin implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "登录人ID")
|
||||
private String uid;
|
||||
|
||||
@Schema(description = "操作IP")
|
||||
private String requestIp;
|
||||
|
||||
@Schema(description = "登录人姓名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "账号")
|
||||
private String uname;
|
||||
|
||||
@Schema(description = "登录描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "登录时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date loginTime;
|
||||
|
||||
@Schema(description = "浏览器请求头")
|
||||
private String ua;
|
||||
|
||||
@Schema(description = "浏览器名称")
|
||||
private String browser;
|
||||
|
||||
@Schema(description = "浏览器版本")
|
||||
private String browserVersion;
|
||||
|
||||
@Schema(description = "操作系统")
|
||||
private String operatingSystem;
|
||||
|
||||
@Schema(description = "平台")
|
||||
private String platForm;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private String creater;
|
||||
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.evotech.hd.common.core.entity.resource;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-01
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("hd_resource.yt_log_upload")
|
||||
@Schema(name = "上传记录表")
|
||||
public class LogUpload implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("pk_id")
|
||||
private String pkId;
|
||||
|
||||
@Schema(description = "公司编码")
|
||||
private String ccode;
|
||||
|
||||
@Schema(description = "运营商编码")
|
||||
private String pocode;
|
||||
|
||||
@Schema(description = "自定义类型,会新建此文件夹,默认值 hd")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "本次上传内容,不填取第一个文件名字")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "数量")
|
||||
private Integer amount;
|
||||
|
||||
@Schema(description = "状态:1-成功")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "用户")
|
||||
private String user;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private String creater;
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package com.evotech.hd.common.core.entity.resource;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-10-15
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_t_proxy_operater")
|
||||
@Schema(name = "代理运营商信息")
|
||||
public class ProxyOperater implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "ID", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "区划名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "区划名称不能为空")
|
||||
private String division;
|
||||
|
||||
@Schema(description = "区划编码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "区划编码不能为空")
|
||||
private String divisionNo;
|
||||
|
||||
@Schema(description = "运营商名称", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "运营商名称不能为空")
|
||||
private String poname;
|
||||
|
||||
@Schema(description = "运营商组织机构代码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "运营商组织机构代码不能为空")
|
||||
private String pocode;
|
||||
|
||||
@Schema(description = "地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "地址-省")
|
||||
private String addressProvince;
|
||||
|
||||
@Schema(description = "地址-市")
|
||||
private String addressCity;
|
||||
|
||||
@Schema(description = "地址-区县")
|
||||
private String addressArea;
|
||||
|
||||
@Schema(description = "联系人")
|
||||
private String contacts;
|
||||
|
||||
@Schema(description = "联系电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "状态:1-启用,0-禁用")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "只读:1-是,0-否")
|
||||
private Integer readonly;
|
||||
|
||||
@Schema(description = "删除标识:1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "换电站数量")
|
||||
private Integer stationCount;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.evotech.hd.common.core.entity.resource;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-11-01
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("hd_resource.yt_t_upload_file")
|
||||
@Schema(name = "上传文件表")
|
||||
public class UploadFile implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "公司编码")
|
||||
private String ccode;
|
||||
|
||||
@Schema(description = "运营商编码")
|
||||
private String pocode;
|
||||
|
||||
@Schema(description = "数据类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "上传ID")
|
||||
private String uploadId;
|
||||
|
||||
@Schema(description = "文件原名")
|
||||
private String fileOriginalName;
|
||||
|
||||
@Schema(description = "文件类型")
|
||||
private String fileType;
|
||||
|
||||
@Schema(description = "文件大小")
|
||||
private Long fileSize;
|
||||
|
||||
@Schema(description = "文件最终名字")
|
||||
private String fileFinalName;
|
||||
|
||||
@Schema(description = "文件路径")
|
||||
private String filePath;
|
||||
|
||||
@Schema(description = "路径+名称")
|
||||
private String pathName;
|
||||
|
||||
@Schema(description = "地址")
|
||||
private String fileUrl;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private String creater;
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_auth_menu")
|
||||
@Schema(name = "菜单")
|
||||
public class AuthMenu implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "主键", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "菜单名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "功能描述")
|
||||
private String mark;
|
||||
|
||||
@Schema(description = "对应路由组件component")
|
||||
private String component;
|
||||
|
||||
@Schema(description = "对应路由path")
|
||||
private String path;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "菜单图标")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "菜单类型:系统-1,目录-2,页面-3")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "父级菜单id")
|
||||
private Integer parentId;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
@Schema(description = "子目录", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<AuthMenu> subMenuList;
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_auth_permission")
|
||||
@Schema(name = "资源权限")
|
||||
public class AuthPermission implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "ID", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "资源编码:页面:操作")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "接口名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "菜单ID")
|
||||
private Integer menuId;
|
||||
|
||||
@Schema(description = "允许访问路径,gateway-允许网关访问,private-不允许网关访问")
|
||||
private String allow;
|
||||
|
||||
@Schema(description = "uri路径")
|
||||
private String uri;
|
||||
|
||||
@Schema(description = "请求方式:GET/POST/DEL/PUSH")
|
||||
private String requestType;
|
||||
|
||||
@Schema(description = "接口描述")
|
||||
private String mark;
|
||||
|
||||
@Schema(description = "创建人id")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_auth_role")
|
||||
@Schema(name = "角色")
|
||||
public class AuthRole implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "id", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "角色名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "角色编码")
|
||||
private String rcode;
|
||||
|
||||
@Schema(description = "功能描述")
|
||||
private String mark;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "角色类型:1-开发者,2-运营方,3-客户")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "是否内置角色,内置角色不允许修改")
|
||||
private Integer readonly;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_auth_role_resource")
|
||||
@Schema(name = "角色的权限")
|
||||
public class AuthRoleResource implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "主键")
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "角色编码")
|
||||
private String rcode;
|
||||
|
||||
@Schema(description = "权限类型:SYS-系统,MENU-菜单,PER-资源权限")
|
||||
private String resourceType;
|
||||
|
||||
@Schema(description = "权限id")
|
||||
private Integer resourceId;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "创建人", hidden = true)
|
||||
private String creater;
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Data
|
||||
@TableName("yt_auth_user")
|
||||
@Schema(name = "账号")
|
||||
public class AuthUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "主键", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private String uid;
|
||||
|
||||
@Schema(description = "账号", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "账号不能为空")
|
||||
private String uname;
|
||||
|
||||
@Schema(description = "账号类型:1-开发者,2-运营方,3-客户", requiredMode = RequiredMode.REQUIRED)
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "关联方代码")
|
||||
private String typeRelateCode;
|
||||
|
||||
@Schema(description = "姓名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "密码", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
@Schema(description = "邮箱")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "手机")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private String sex;
|
||||
|
||||
@Schema(description = "状态:1-启用,0-禁用", requiredMode = RequiredMode.REQUIRED)
|
||||
@NotNull
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否内置账号,内置账号不允许动")
|
||||
private Integer readonly;
|
||||
|
||||
@Schema(description = "删除标识:1-已删除,0-未删除", hidden = true)
|
||||
private Integer delFlag;
|
||||
|
||||
@Schema(description = "头像")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "最后一次输错密码时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date passwordErrorLastTime;
|
||||
|
||||
@Schema(description = "密码错误次数", hidden = true)
|
||||
private Integer passwordErrorNum;
|
||||
|
||||
@Schema(description = "密码过期时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date passwordExpireTime;
|
||||
|
||||
@Schema(description = "最后登录时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date lastLoginTime;
|
||||
|
||||
@Schema(description = "创建人", hidden = true)
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新人", hidden = true)
|
||||
private String updater;
|
||||
|
||||
@Schema(description = "更新时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
@Schema(description = "角色编码", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private String rcodes;
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.evotech.hd.common.core.entity.resource.auth;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-04
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_auth_user_role")
|
||||
@Schema(name = "账号角色关系")
|
||||
public class AuthUserRole implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
@NotBlank
|
||||
private String uid;
|
||||
|
||||
@Schema(description = "角色编码")
|
||||
@NotBlank
|
||||
private String rcode;
|
||||
|
||||
@Schema(description = "创建人")
|
||||
private String creater;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "修改时间", hidden = true)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.evotech.hd.common.core.entity.resource.dict;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("yt_d_admdvs_info")
|
||||
@Schema(name = "行政区划信息表")
|
||||
public class AdmdvsInfo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("pk_id")
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "区划代码")
|
||||
private String admdvsNo;
|
||||
|
||||
@Schema(description = "区划名称")
|
||||
private String admdvsName;
|
||||
|
||||
@Schema(description = "父级代码")
|
||||
private String pno;
|
||||
|
||||
@Schema(description = "等级,1-省;2-市;3-区县")
|
||||
private Integer level;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
|
||||
@Schema(description = "子区划", hidden = true)
|
||||
@TableField(exist = false)
|
||||
private List<AdmdvsInfo> subAdmdvsInfoList;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.evotech.hd.common.core.entity.resource.dict;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("hd_resource.yt_d_dict")
|
||||
@Schema(name = "字典")
|
||||
public class Dict implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "主键", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "字典名称")
|
||||
private String dictName;
|
||||
|
||||
@Schema(description = "字典编码")
|
||||
private String dictCode;
|
||||
|
||||
@Schema(description = "字典值")
|
||||
private String dictValue;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "类型ID")
|
||||
private Integer typeId;
|
||||
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.evotech.hd.common.core.entity.resource.dict;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @since 2024-09-05
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("hd_resource.yt_d_dict_type")
|
||||
@Schema(name = "字典类型")
|
||||
public class DictType implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "主键", hidden = true)
|
||||
@TableId(value = "pk_id", type = IdType.AUTO)
|
||||
private Integer pkId;
|
||||
|
||||
@Schema(description = "类型名称")
|
||||
private String typeName;
|
||||
|
||||
@Schema(description = "类型编码")
|
||||
private String typeCode;
|
||||
|
||||
@Schema(description = "描述")
|
||||
private String mark;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date ctime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
|
||||
private Date uptime;
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package com.evotech.hd.common.core.enums;
|
||||
|
||||
/**
|
||||
* 100 Continue 继续。客户端应继续其请求
|
||||
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
|
||||
200 OK 请求成功。一般用于GET与POST请求
|
||||
201 Created 已创建。成功请求并创建了新的资源
|
||||
202 Accepted 已接受。已经接受请求,但未处理完成
|
||||
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
|
||||
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
|
||||
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
|
||||
206 Partial Content 部分内容。服务器成功处理了部分GET请求
|
||||
300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
|
||||
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
|
||||
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
|
||||
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
|
||||
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
|
||||
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
|
||||
306 Unused 已经被废弃的HTTP状态码
|
||||
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
|
||||
400 Bad Request 客户端请求的语法错误,服务器无法理解
|
||||
401 Unauthorized 请求要求用户的身份认证
|
||||
402 Payment Required 保留,将来使用
|
||||
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
|
||||
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
|
||||
405 Method Not Allowed 客户端请求中的方法被禁止
|
||||
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
|
||||
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
|
||||
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
|
||||
409 Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
|
||||
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
|
||||
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
|
||||
412 Precondition Failed 客户端请求信息的先决条件错误
|
||||
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
|
||||
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
|
||||
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
|
||||
416 Requested range not satisfiable 客户端请求的范围无效
|
||||
417 Expectation Failed 服务器无法满足Expect的请求头信息
|
||||
500 Internal Server Error 服务器内部错误,无法完成请求
|
||||
501 Not Implemented 服务器不支持请求的功能,无法完成请求
|
||||
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
|
||||
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
|
||||
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
|
||||
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理
|
||||
*/
|
||||
public enum CodeMsg {
|
||||
// 统一回复
|
||||
SUCCESS("1000", "OK"),
|
||||
ERROR("4000", "ERROR"),
|
||||
// 系统错误 S
|
||||
USERNAME_OR_PASSWORD_ERROR("S0400", "用户名或密码错误!"),
|
||||
PASSWORD_ENTER_EXCEED_LIMIT("S0401", "用户输入密码次数超限!"),
|
||||
USER_NOT_LOGIN("S0402", "用户未登陆!"),
|
||||
AUTHENTICATION_FAILED("S0403", "认证失败!"),
|
||||
TOKEN_INVALID("S0404", "无效token!"),
|
||||
TOKEN_EXPIRED("S0405", "token已过期!"),
|
||||
ACCESS_DENY("S0406", "访问未授权!"),
|
||||
ACCESS_SCOPE_ERROR("S0407", "客户端权限范围出错"),
|
||||
GATEWAY_EXECUTION_TIMEOUT("S0408", "网关执行超时"),
|
||||
GATEWAY_EXECUTION_ERROR("S0409", "网关执行出错"),
|
||||
// 业务错误 B
|
||||
BUSSINESS_ERROR("B0400", "业务出错"),
|
||||
PARAM_IS_NULL("B0401", "请求参数为空"),
|
||||
PARAM_ERROR("B0402", "用户请求参数错误"),
|
||||
UPLOAD_FILE_ERROR("B0403", "用户上传文件异常"),
|
||||
UPLOAD_FILE_TYPE_NOT_MATCH("B0404", "用户上传文件类型不匹配"),
|
||||
UPLOAD_FILE_SIZE_EXCEEDS("B0405", "用户上传文件太大"),
|
||||
|
||||
// 数据库错误 D
|
||||
DATABASE_ERROR("D0400", "数据库服务出错"),
|
||||
DATA_EXIST("D0401", "此数据已存在!"),
|
||||
DATABASE_RESULT_NULL("D0402", "查询结果为空"),
|
||||
DATABASE_TABLE_NOT_EXIST("D0403", "表不存在"),
|
||||
DATABASE_COLUMN_NOT_EXIST("D0404", "列不存在"),
|
||||
SQL_RUN_ERROR("D0405", "sql运行异常"),
|
||||
REDIS_ERROR("D0410", "REDIS数据出错"),
|
||||
|
||||
// 小程序 w
|
||||
WECHAT_LOGIN_ERROR("W0400", "小程序登录出错"),
|
||||
WECHAT_SERRION_ERROR("W0401", "小程序登录态错误"),
|
||||
WECHAT_API_ERROR("W0402", "小程序接口调用异常");
|
||||
|
||||
String code;
|
||||
|
||||
String msg;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
CodeMsg(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.evotech.hd.common.core.utils;
|
||||
|
||||
import cn.hutool.core.lang.Snowflake;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @date 2024年9月5日10:25:58
|
||||
*/
|
||||
public class SnowflakeUtil {
|
||||
|
||||
public static final Snowflake sf = IdUtil.getSnowflake(1, 1);
|
||||
|
||||
public static Long getId() {
|
||||
return sf.nextId();
|
||||
}
|
||||
|
||||
public static String getIdStr() {
|
||||
return sf.nextIdStr();
|
||||
}
|
||||
|
||||
}
|
||||
51
base-commons/common-mybatis/pom.xml
Normal file
51
base-commons/common-mybatis/pom.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>base-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-mybatis</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- 原来有代码生成器,现在移出去了,这个打包配置先不用了 -->
|
||||
<!--<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
</exclude>
|
||||
<exclude></exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>templates/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>-->
|
||||
</project>
|
||||
34
base-commons/common-redis/pom.xml
Normal file
34
base-commons/common-redis/pom.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>base-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-redis</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,71 @@
|
||||
package com.evotech.hd.common.redis.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @date 2024年9月3日17:13:42
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
/**
|
||||
* 其实SpringBoot自动帮我们在容器中生成了一个RedisTemplate和一个StringRedisTemplate。
|
||||
* 但是,这个RedisTemplate的泛型是<Object,Object>,写代码不方便,需要写好多类型转换的代码;我们需要一个泛型为<String,Object>形式的RedisTemplate
|
||||
* 同时,设置key-value的序列化方式
|
||||
*/
|
||||
@Bean
|
||||
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
|
||||
template.setConnectionFactory(factory);
|
||||
/*
|
||||
* 设置序列化参数
|
||||
*/
|
||||
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
|
||||
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(om, Object.class);
|
||||
|
||||
|
||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
||||
// key采用String的序列化方式
|
||||
template.setKeySerializer(stringRedisSerializer);
|
||||
// value序列化方式
|
||||
template.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
// hash的key也采用String的序列化方式
|
||||
template.setHashKeySerializer(stringRedisSerializer);
|
||||
// hash的value序列化方式采用jackson
|
||||
template.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
|
||||
// RedisTemplate的初始化,我们上面没有设置到的参数会在这个方法中设置成默认的,若没有这个,缺少设置有时会报错
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
|
||||
/***
|
||||
* 添加了这个类,SpringBoot不会帮我们自动生成StringRedisTemplate,为了方便程序中使用,我们自己生成一个放到容器中
|
||||
* stringRedisTemplate默认采用的是String的序列化策略
|
||||
* @param redisConnectionFactory
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
|
||||
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||
return stringRedisTemplate;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,663 @@
|
||||
package com.evotech.hd.common.redis.utils;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author zrb
|
||||
* @date 2024年9月3日17:15:36
|
||||
*/
|
||||
@Component
|
||||
public class RedisUtil {
|
||||
|
||||
/**
|
||||
* 注入redisTemplate bean
|
||||
*/
|
||||
@Autowired
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean expire(String key, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据key获取过期时间
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public long getExpire(String key) {
|
||||
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
try {
|
||||
return redisTemplate.hasKey(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
*
|
||||
* @param key 可以传一个值 或多个
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void del(String... key) {
|
||||
if (key != null && key.length > 0) {
|
||||
if (key.length == 1) {
|
||||
redisTemplate.delete(key[0]);
|
||||
} else {
|
||||
redisTemplate.delete((List<String>) CollectionUtils.arrayToList(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
// ============================String(字符串)=============================
|
||||
|
||||
/**
|
||||
* 普通缓存获取
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return key == null ? null : redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean set(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
try {
|
||||
if (time > 0) {
|
||||
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
set(key, value);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递增
|
||||
*
|
||||
* @param key 键
|
||||
* @param delta 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public long incr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递增因子必须大于0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, delta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param delta 要减少几(小于0)
|
||||
* @return
|
||||
*/
|
||||
public long decr(String key, long delta) {
|
||||
if (delta < 0) {
|
||||
throw new RuntimeException("递减因子必须大于0");
|
||||
}
|
||||
return redisTemplate.opsForValue().increment(key, -delta);
|
||||
}
|
||||
// ================================Hash(哈希)=================================
|
||||
|
||||
/**
|
||||
* HashGet
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return 值
|
||||
*/
|
||||
public Object hget(String key, String item) {
|
||||
return redisTemplate.opsForHash().get(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hashKey对应的所有键值
|
||||
*
|
||||
* @param key 键
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public Map<Object, Object> hmget(String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet 并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @param time 时间(秒)
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<String, Object> map, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, String item, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除hash表中的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 可以使多个 不能为null
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断hash表中是否有该项的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public double hincr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要减少记(小于0)
|
||||
* @return
|
||||
*/
|
||||
public double hdecr(String key, String item, double by) {
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
// ============================Set(集合)=============================
|
||||
|
||||
/**
|
||||
* 根据key获取Set中的所有值
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> sGet(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据value从一个set中查询,是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入set缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将set数据放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSetAndTime(String key, long time, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取set缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除值为value的
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
try {
|
||||
Long count = redisTemplate.opsForSet().remove(key, values);
|
||||
return count;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// ===============================List(列表)=================================
|
||||
|
||||
/**
|
||||
* 获取list缓存的内容
|
||||
*
|
||||
* @param key 键
|
||||
* @param start 开始
|
||||
* @param end 结束 0 到 -1代表所有值
|
||||
* @return
|
||||
*/
|
||||
public List<Object> lGet(String key, long start, long end) {
|
||||
try {
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
try {
|
||||
return redisTemplate.opsForList().size(key);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引 获取list中的值
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
|
||||
* @return
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
try {
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
* 要放数组,放list就是个bug,list先转数组
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object[] value) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
* 要放数组,放list就是个bug,list先转数组
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object[] value, long time) {
|
||||
try {
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出并获取列表的第一个元素
|
||||
*
|
||||
* @param key
|
||||
* @return 删除的元素
|
||||
*/
|
||||
public Object lLeftPop(String key) {
|
||||
return redisTemplate.opsForList().leftPop(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
|
||||
*
|
||||
* @param key
|
||||
* @param timeout
|
||||
* 等待时间
|
||||
* @param unit
|
||||
* 时间单位
|
||||
* @return
|
||||
*/
|
||||
public Object lBLeftPop(String key, long timeout, TimeUnit unit) {
|
||||
return redisTemplate.opsForList().leftPop(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除并获取列表最后一个元素
|
||||
*
|
||||
* @param key
|
||||
* @return 删除的元素
|
||||
*/
|
||||
public Object lRightPop(String key) {
|
||||
return redisTemplate.opsForList().rightPop(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
|
||||
*
|
||||
* @param key
|
||||
* @param timeout
|
||||
* 等待时间
|
||||
* @param unit
|
||||
* 时间单位
|
||||
* @return
|
||||
*/
|
||||
public Object lBRightPop(String key, long timeout, TimeUnit unit) {
|
||||
return redisTemplate.opsForList().rightPop(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
|
||||
*
|
||||
* @param sourceKey
|
||||
* @param destinationKey
|
||||
* @return
|
||||
*/
|
||||
public Object lRightPopAndLeftPush(String sourceKey, String destinationKey) {
|
||||
return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
|
||||
destinationKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
|
||||
*
|
||||
* @param sourceKey
|
||||
* @param destinationKey
|
||||
* @param timeout
|
||||
* @param unit
|
||||
* @return
|
||||
*/
|
||||
public Object lBRightPopAndLeftPush(String sourceKey, String destinationKey,
|
||||
long timeout, TimeUnit unit) {
|
||||
return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,
|
||||
destinationKey, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引修改list中的某条数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
try {
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除N个值为value
|
||||
*
|
||||
* @param key 键
|
||||
* @param count 移除多少个
|
||||
* @param value 值
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
try {
|
||||
Long remove = redisTemplate.opsForList().remove(key, count, value);
|
||||
return remove;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据正则表达式获取key列表
|
||||
*
|
||||
* @param patternKey 正则表达式
|
||||
* @return 匹配key列表
|
||||
*/
|
||||
public Set<String> keys(String patternKey) {
|
||||
try {
|
||||
Set<String> keys = redisTemplate.keys(patternKey);
|
||||
return keys;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
72
base-commons/common-web/pom.xml
Normal file
72
base-commons/common-web/pom.xml
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xml>
|
||||
<project xmlns="https://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>base-commons</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-web</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.evotech.hd</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -0,0 +1,84 @@
|
||||
package com.evotech.hd.common.web.exception;
|
||||
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import com.evotech.hd.common.core.entity.Result;
|
||||
import com.evotech.hd.common.core.enums.CodeMsg;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 全局异常处理
|
||||
* @author zrb
|
||||
*/
|
||||
|
||||
/**
|
||||
* @RestControllerAdvice注解和controller相对应,
|
||||
* 若用controller,则此处用ControllerAdvice,
|
||||
* 若用RestController,此处用@RestControllerAdvice
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 处理空指针的异常
|
||||
* @param req
|
||||
* @param e
|
||||
*/
|
||||
@ExceptionHandler(value = NullPointerException.class)
|
||||
public Result<String> exceptionHandler(HttpServletRequest req, NullPointerException e) {
|
||||
log.error("空指针异常:", e);
|
||||
return new Result<String>().bussinessException(CodeMsg.ERROR.getCode(), e.getMessage(), null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Http请求消息异常
|
||||
*/
|
||||
@ExceptionHandler(value = HttpMessageNotReadableException.class)
|
||||
public Result<String> exceptionHandler(HttpServletRequest req, HttpMessageNotReadableException e) {
|
||||
log.error("http请求参数解析异常:", e);
|
||||
return new Result<String>().bussinessException(CodeMsg.PARAM_ERROR.getCode(), "http请求参数解析异常", e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数校验异常
|
||||
* @param req
|
||||
* @param e
|
||||
*/
|
||||
@ExceptionHandler(value = MyArgumentException.class)
|
||||
public Result<String> exceptionHandler(HttpServletRequest req, MyArgumentException e) {
|
||||
log.error("请求参数异常:", e);
|
||||
return new Result<String>().bussinessException(CodeMsg.PARAM_ERROR.getCode(), CodeMsg.PARAM_ERROR.getMsg(), e.getParamArr());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 这个异常的意思就是在更新(update或insert)数据库时,新的数据违反了完整性,
|
||||
* 例如主键重复,我这里的问题是数据库的id字段未设置自增,默认值也没设,在插入的时候就出现了这个异常
|
||||
* @param req
|
||||
* @param e
|
||||
*/
|
||||
@ExceptionHandler(value = DataIntegrityViolationException.class)
|
||||
public Result<String> exceptionHandler(HttpServletRequest req, DataIntegrityViolationException e) {
|
||||
log.error("sql语句异常:", e);
|
||||
return new Result<String>().bussinessException(CodeMsg.SQL_RUN_ERROR.getCode(), e.getCause().toString(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自己抛出的运行异常
|
||||
* @param req
|
||||
* @param e
|
||||
*/
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public Result<String> exceptionHandler(HttpServletRequest req, RuntimeException e) {
|
||||
log.error("捕获运行异常:", e);
|
||||
return new Result<String>().bussinessException(CodeMsg.ERROR.getCode(), e instanceof RuntimeException?e.getMessage():e.toString(), null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.evotech.hd.common.web.exception;
|
||||
|
||||
public class MyArgumentException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 请求的参数数据,若参数校验不通过,此字段存储请求参数,返回前端
|
||||
*/
|
||||
private String[] paramArr;
|
||||
|
||||
public String[] getParamArr() {
|
||||
return paramArr;
|
||||
}
|
||||
|
||||
public void setParamArr(String[] paramArr) {
|
||||
this.paramArr = paramArr;
|
||||
}
|
||||
|
||||
public MyArgumentException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MyArgumentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MyArgumentException(String message, String params) {
|
||||
super(message);
|
||||
this.paramArr = params.split(",");
|
||||
}
|
||||
|
||||
public MyArgumentException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MyArgumentException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.evotech.hd.common.web.filter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
|
||||
@Configuration
|
||||
public class MyFilterConfig {
|
||||
|
||||
@Autowired
|
||||
private RequestBodyFilter requestBodyFilter;
|
||||
|
||||
/**
|
||||
* 将过滤器注册到FilterRegistrationBean中
|
||||
* 进行简单配置
|
||||
*/
|
||||
@Bean
|
||||
FilterRegistrationBean<Filter> myFilterRegistration() {
|
||||
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(requestBodyFilter);
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("requestBodyFilter");
|
||||
return registration;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.evotech.hd.common.web.filter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import jakarta.servlet.ReadListener;
|
||||
import jakarta.servlet.ServletInputStream;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
* 自定义request对象,将body处理后,放到这个对象里面,
|
||||
* 一定要重写getReader()和getInputStream()方法,将body放进去,
|
||||
* 这样后面的controller才能从这个request的getReader()和getInputStream()
|
||||
* 方法中拿到新的body对象
|
||||
* @author zrb
|
||||
*/
|
||||
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private byte[] body;
|
||||
|
||||
public MyHttpServletRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
// 缓存按 8192 大小
|
||||
final CharBuffer buffer = CharBuffer.allocate(2 << 12);
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = request.getReader();
|
||||
while (-1 != reader.read(buffer)) {
|
||||
builder.append(buffer.flip());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
String bodyStr = builder.toString();
|
||||
try {
|
||||
bodyStr = URLDecoder.decode(bodyStr, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("body解码出错!");
|
||||
}
|
||||
body = bodyStr.getBytes(Charset.defaultCharset());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public byte[] getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public BufferedReader getReader() throws IOException {
|
||||
return new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ServletInputStream getInputStream() throws IOException {
|
||||
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
|
||||
return new ServletInputStream() {
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return bais.available() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener readListener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return bais.read();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user