245 changed files with 20 additions and 29637 deletions
@ -1,12 +0,0 @@ |
|||
<component name="ProjectRunConfigurationManager"> |
|||
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> |
|||
<deployment type="dockerfile"> |
|||
<settings> |
|||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.3" /> |
|||
<option name="buildOnly" value="true" /> |
|||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" /> |
|||
</settings> |
|||
</deployment> |
|||
<method v="2" /> |
|||
</configuration> |
|||
</component> |
|||
@ -1,12 +0,0 @@ |
|||
<component name="ProjectRunConfigurationManager"> |
|||
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机"> |
|||
<deployment type="dockerfile"> |
|||
<settings> |
|||
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.3" /> |
|||
<option name="buildOnly" value="true" /> |
|||
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" /> |
|||
</settings> |
|||
</deployment> |
|||
<method v="2" /> |
|||
</configuration> |
|||
</component> |
|||
@ -1,12 +0,0 @@ |
|||
<component name="ProjectRunConfigurationManager"> |
|||
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> |
|||
<deployment type="dockerfile"> |
|||
<settings> |
|||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.3" /> |
|||
<option name="buildOnly" value="true" /> |
|||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" /> |
|||
</settings> |
|||
</deployment> |
|||
<method v="2" /> |
|||
</configuration> |
|||
</component> |
|||
@ -1,20 +0,0 @@ |
|||
The MIT License (MIT) |
|||
|
|||
Copyright (c) 2019 RuoYi-Vue-Plus |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|||
this software and associated documentation files (the "Software"), to deal in |
|||
the Software without restriction, including without limitation the rights to |
|||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
|||
the Software, and to permit persons to whom the Software is furnished to do so, |
|||
subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
|||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
|||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|||
@ -1,8 +0,0 @@ |
|||
Application Version: ${revision} |
|||
Spring Boot Version: ${spring-boot.version} |
|||
__________ _____.___.__ ____ ____ __________.__ |
|||
\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ |
|||
| _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ |
|||
| | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ |
|||
|____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > |
|||
\/ \/ \/ \/ |
|||
@ -1,46 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>ruoyi-common-job</artifactId> |
|||
|
|||
<description> |
|||
ruoyi-common-job 定时任务 |
|||
</description> |
|||
|
|||
<dependencies> |
|||
|
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-autoconfigure</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- SnailJob client --> |
|||
<dependency> |
|||
<groupId>com.aizuda</groupId> |
|||
<artifactId>snail-job-client-starter</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.aizuda</groupId> |
|||
<artifactId>snail-job-client-job-core</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-core</artifactId> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
</project> |
|||
@ -1,37 +0,0 @@ |
|||
package org.dromara.common.job.config; |
|||
|
|||
import ch.qos.logback.classic.Logger; |
|||
import ch.qos.logback.classic.LoggerContext; |
|||
import ch.qos.logback.classic.spi.ILoggingEvent; |
|||
import com.aizuda.snailjob.client.common.appender.SnailLogbackAppender; |
|||
import com.aizuda.snailjob.client.common.event.SnailClientStartingEvent; |
|||
import com.aizuda.snailjob.client.starter.EnableSnailJob; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.boot.autoconfigure.AutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
|||
import org.springframework.context.event.EventListener; |
|||
import org.springframework.scheduling.annotation.EnableScheduling; |
|||
|
|||
/** |
|||
* 启动定时任务 |
|||
* |
|||
* @author opensnail |
|||
* @date 2024-05-17 |
|||
*/ |
|||
@AutoConfiguration |
|||
@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true") |
|||
@EnableScheduling |
|||
@EnableSnailJob |
|||
public class SnailJobConfig { |
|||
|
|||
@EventListener(SnailClientStartingEvent.class) |
|||
public void onStarting(SnailClientStartingEvent event) { |
|||
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); |
|||
SnailLogbackAppender<ILoggingEvent> ca = new SnailLogbackAppender<>(); |
|||
ca.setName("snail_log_appender"); |
|||
ca.start(); |
|||
Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME); |
|||
rootLogger.addAppender(ca); |
|||
} |
|||
|
|||
} |
|||
@ -1 +0,0 @@ |
|||
org.dromara.common.job.config.SnailJobConfig |
|||
@ -1,19 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>ruoyi-vue-plus</artifactId> |
|||
<groupId>org.dromara</groupId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<artifactId>ruoyi-extend</artifactId> |
|||
<packaging>pom</packaging> |
|||
|
|||
<modules> |
|||
<module>ruoyi-monitor-admin</module> |
|||
<module>ruoyi-snailjob-server</module> |
|||
</modules> |
|||
|
|||
</project> |
|||
@ -1,20 +0,0 @@ |
|||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ |
|||
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds |
|||
#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds |
|||
#FROM findepi/graalvm:java17-native |
|||
|
|||
LABEL maintainer="Lion Li" |
|||
|
|||
RUN mkdir -p /ruoyi/monitor/logs |
|||
|
|||
WORKDIR /ruoyi/monitor |
|||
|
|||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" |
|||
|
|||
EXPOSE 9090 |
|||
|
|||
ADD ./target/ruoyi-monitor-admin.jar ./app.jar |
|||
|
|||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \ |
|||
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ |
|||
-jar app.jar |
|||
@ -1,76 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>ruoyi-extend</artifactId> |
|||
<groupId>org.dromara</groupId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<packaging>jar</packaging> |
|||
<artifactId>ruoyi-monitor-admin</artifactId> |
|||
|
|||
<dependencies> |
|||
<!-- SpringBoot Web容器 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
<exclusions> |
|||
<exclusion> |
|||
<artifactId>spring-boot-starter-tomcat</artifactId> |
|||
<groupId>org.springframework.boot</groupId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
<!-- web 容器使用 undertow 性能更强 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-undertow</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- spring security 安全认证 --> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-security</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> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
|
|||
<build> |
|||
<finalName>${project.artifactId}</finalName> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<configuration> |
|||
<!-- <fork>true</fork> <!– 如果没有该配置,devtools不会生效 –>--> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
|||
@ -1,19 +0,0 @@ |
|||
package org.dromara.monitor.admin; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
/** |
|||
* Admin 监控启动程序 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@SpringBootApplication |
|||
public class MonitorAdminApplication { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(MonitorAdminApplication.class, args); |
|||
System.out.println("Admin 监控启动成功"); |
|||
} |
|||
|
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
package org.dromara.monitor.admin.config; |
|||
|
|||
import de.codecentric.boot.admin.server.config.EnableAdminServer; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
|||
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration; |
|||
import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.context.annotation.Lazy; |
|||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
|||
|
|||
import java.util.concurrent.Executor; |
|||
|
|||
/** |
|||
* springboot-admin server配置类 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Configuration |
|||
@EnableAdminServer |
|||
public class AdminServerConfig { |
|||
|
|||
@Lazy |
|||
@Bean(name = TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME) |
|||
@ConditionalOnMissingBean(Executor.class) |
|||
public ThreadPoolTaskExecutor applicationTaskExecutor(ThreadPoolTaskExecutorBuilder builder) { |
|||
return builder.build(); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -1,54 +0,0 @@ |
|||
package org.dromara.monitor.admin.config; |
|||
|
|||
import de.codecentric.boot.admin.server.config.AdminServerProperties; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.security.config.Customizer; |
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; |
|||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; |
|||
import org.springframework.security.web.SecurityFilterChain; |
|||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; |
|||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; |
|||
|
|||
/** |
|||
* admin 监控 安全配置 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@EnableWebSecurity |
|||
@Configuration |
|||
public class SecurityConfig { |
|||
|
|||
private final String adminContextPath; |
|||
|
|||
public SecurityConfig(AdminServerProperties adminServerProperties) { |
|||
this.adminContextPath = adminServerProperties.getContextPath(); |
|||
} |
|||
|
|||
@Bean |
|||
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { |
|||
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); |
|||
successHandler.setTargetUrlParameter("redirectTo"); |
|||
successHandler.setDefaultTargetUrl(adminContextPath + "/"); |
|||
|
|||
return httpSecurity |
|||
.headers((header) -> |
|||
header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) |
|||
.authorizeHttpRequests((authorize) -> |
|||
authorize.requestMatchers( |
|||
new AntPathRequestMatcher(adminContextPath + "/assets/**"), |
|||
new AntPathRequestMatcher(adminContextPath + "/login") |
|||
).permitAll() |
|||
.anyRequest().authenticated()) |
|||
.formLogin((formLogin) -> |
|||
formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler)) |
|||
.logout((logout) -> |
|||
logout.logoutUrl(adminContextPath + "/logout")) |
|||
.httpBasic(Customizer.withDefaults()) |
|||
.csrf(AbstractHttpConfigurer::disable) |
|||
.build(); |
|||
} |
|||
|
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
package org.dromara.monitor.admin.notifier; |
|||
|
|||
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.AbstractEventNotifier; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Component; |
|||
import reactor.core.publisher.Mono; |
|||
|
|||
import static de.codecentric.boot.admin.server.domain.values.StatusInfo.*; |
|||
|
|||
/** |
|||
* 自定义事件通知处理 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class CustomNotifier extends AbstractEventNotifier { |
|||
|
|||
protected CustomNotifier(InstanceRepository repository) { |
|||
super(repository); |
|||
} |
|||
|
|||
@Override |
|||
@SuppressWarnings("all") |
|||
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) { |
|||
return Mono.fromRunnable(() -> { |
|||
// 实例状态改变事件
|
|||
if (event instanceof InstanceStatusChangedEvent) { |
|||
// 获取实例注册名称
|
|||
String registName = instance.getRegistration().getName(); |
|||
// 获取实例ID
|
|||
String instanceId = event.getInstance().getValue(); |
|||
// 获取实例状态
|
|||
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); |
|||
// 获取服务URL
|
|||
String serviceUrl = instance.getRegistration().getServiceUrl(); |
|||
String statusName = switch (status) { |
|||
case STATUS_UP -> "服务上线"; // 实例成功启动并可以正常处理请求
|
|||
case STATUS_OFFLINE -> "服务离线"; //实例被手动或自动地从服务中移除
|
|||
case STATUS_RESTRICTED -> "服务受限"; //表示实例在某些方面受限,可能无法完全提供所有服务
|
|||
case STATUS_OUT_OF_SERVICE -> "停止服务状态"; //表示实例已被标记为停止提供服务,可能是计划内维护或测试
|
|||
case STATUS_DOWN -> "服务下线"; //实例因崩溃、错误或其他原因停止运行
|
|||
case STATUS_UNKNOWN -> "服务未知异常"; //监控系统无法确定实例的当前状态
|
|||
default -> "未知状态"; //没有匹配的状态
|
|||
}; |
|||
log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】", |
|||
statusName, registName, instanceId, status, serviceUrl); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
server: |
|||
port: 9090 |
|||
spring: |
|||
application: |
|||
name: ruoyi-monitor-admin |
|||
profiles: |
|||
active: @profiles.active@ |
|||
|
|||
logging: |
|||
config: classpath:logback-plus.xml |
|||
|
|||
--- # 监控中心服务端配置 |
|||
spring: |
|||
security: |
|||
user: |
|||
name: @monitor.username@ |
|||
password: @monitor.password@ |
|||
boot: |
|||
admin: |
|||
ui: |
|||
title: RuoYi-Vue-Plus服务监控中心 |
|||
context-path: /admin |
|||
|
|||
--- # Actuator 监控端点的配置项 |
|||
management: |
|||
endpoints: |
|||
web: |
|||
exposure: |
|||
include: '*' |
|||
endpoint: |
|||
health: |
|||
show-details: ALWAYS |
|||
logfile: |
|||
external-file: ./logs/ruoyi-monitor-admin.log |
|||
|
|||
--- # 监控配置 |
|||
spring.boot.admin.client: |
|||
# 增加客户端开关 |
|||
enabled: true |
|||
# 设置 Spring Boot Admin Server 地址 |
|||
url: http://localhost:9090/admin |
|||
instance: |
|||
service-host-type: IP |
|||
metadata: |
|||
username: ${spring.boot.admin.client.username} |
|||
userpassword: ${spring.boot.admin.client.password} |
|||
username: @monitor.username@ |
|||
password: @monitor.password@ |
|||
@ -1,8 +0,0 @@ |
|||
Application Version: ${revision} |
|||
Spring Boot Version: ${spring-boot.version} |
|||
__ __ _ _ _ _ |
|||
| \/ | (_) | /\ | | (_) |
|||
| \ / | ___ _ __ _| |_ ___ _ __ ______ / \ __| |_ __ ___ _ _ __ |
|||
| |\/| |/ _ \| '_ \| | __/ _ \| '__|______/ /\ \ / _` | '_ ` _ \| | '_ \ |
|||
| | | | (_) | | | | | || (_) | | / ____ \ (_| | | | | | | | | | | |
|||
|_| |_|\___/|_| |_|_|\__\___/|_| /_/ \_\__,_|_| |_| |_|_|_| |_| |
|||
@ -1,34 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration debug="false" scan="true" scanPeriod="1 seconds"> |
|||
|
|||
<contextName>logback</contextName> |
|||
<property name="log.path" value="./logs/ruoyi-monitor-admin"/> |
|||
<property name="console.log.pattern" |
|||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> |
|||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/> |
|||
|
|||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>${console.log.pattern}</pattern> |
|||
<charset>utf-8</charset> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${log.path}.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<fileNamePattern>${log.path}.%d{yyyy-MM-dd}.log</fileNamePattern> |
|||
<!-- 日志最大的历史 60天 --> |
|||
<maxHistory>60</maxHistory> |
|||
</rollingPolicy> |
|||
<encoder> |
|||
<pattern>${log.pattern}</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<root level="info"> |
|||
<appender-ref ref="console"/> |
|||
<appender-ref ref="file"/> |
|||
</root> |
|||
|
|||
</configuration> |
|||
@ -1,21 +0,0 @@ |
|||
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ |
|||
FROM bellsoft/liberica-openjdk-debian:17.0.11-cds |
|||
#FROM bellsoft/liberica-openjdk-debian:21.0.3-cds |
|||
#FROM findepi/graalvm:java17-native |
|||
|
|||
LABEL maintainer="Lion Li" |
|||
|
|||
RUN mkdir -p /ruoyi/snailjob/logs |
|||
|
|||
WORKDIR /ruoyi/snailjob |
|||
|
|||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m" |
|||
|
|||
EXPOSE 8800 |
|||
EXPOSE 17888 |
|||
|
|||
ADD ./target/ruoyi-snailjob-server.jar ./app.jar |
|||
|
|||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \ |
|||
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ |
|||
-jar app.jar |
|||
@ -1,58 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-extend</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<packaging>jar</packaging> |
|||
<artifactId>ruoyi-snailjob-server</artifactId> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.aizuda</groupId> |
|||
<artifactId>snail-job-server-starter</artifactId> |
|||
<version>${snailjob.version}</version> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.scala-lang</groupId> |
|||
<artifactId>scala-library</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.scala-lang</groupId> |
|||
<artifactId>scala-library</artifactId> |
|||
<version>2.13.9</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>de.codecentric</groupId> |
|||
<artifactId>spring-boot-admin-starter-client</artifactId> |
|||
<version>${spring-boot-admin.version}</version> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
<build> |
|||
<finalName>${project.artifactId}</finalName> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
</build> |
|||
|
|||
</project> |
|||
@ -1,64 +0,0 @@ |
|||
package com.aizuda.snailjob.server.starter.filter; |
|||
|
|||
import jakarta.servlet.*; |
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
|
|||
import java.io.IOException; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.Base64; |
|||
|
|||
public class ActuatorAuthFilter implements Filter { |
|||
|
|||
private final String username; |
|||
private final String password; |
|||
|
|||
public ActuatorAuthFilter(String username, String password) { |
|||
this.username = username; |
|||
this.password = password; |
|||
} |
|||
|
|||
@Override |
|||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { |
|||
HttpServletRequest request = (HttpServletRequest) servletRequest; |
|||
HttpServletResponse response = (HttpServletResponse) servletResponse; |
|||
|
|||
// 获取 Authorization 头
|
|||
String authHeader = request.getHeader("Authorization"); |
|||
|
|||
if (authHeader == null || !authHeader.startsWith("Basic ")) { |
|||
// 如果没有提供 Authorization 或者格式不对,则返回 401
|
|||
response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); |
|||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); |
|||
return; |
|||
} |
|||
|
|||
// 解码 Base64 编码的用户名和密码
|
|||
String base64Credentials = authHeader.substring("Basic ".length()); |
|||
byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); |
|||
String credentials = new String(credDecoded, StandardCharsets.UTF_8); |
|||
String[] split = credentials.split(":"); |
|||
if (split.length != 2) { |
|||
response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); |
|||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); |
|||
return; |
|||
} |
|||
// 验证用户名和密码
|
|||
if (!username.equals(split[0]) && password.equals(split[1])) { |
|||
response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); |
|||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); |
|||
return; |
|||
} |
|||
// 如果认证成功,继续处理请求
|
|||
filterChain.doFilter(request, response); |
|||
} |
|||
|
|||
@Override |
|||
public void init(FilterConfig filterConfig) { |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
} |
|||
|
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
package com.aizuda.snailjob.server.starter.filter; |
|||
|
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.web.servlet.FilterRegistrationBean; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
/** |
|||
* 权限安全配置 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Configuration |
|||
public class SecurityConfig { |
|||
|
|||
@Value("${spring.boot.admin.client.username}") |
|||
private String username; |
|||
@Value("${spring.boot.admin.client.password}") |
|||
private String password; |
|||
|
|||
@Bean |
|||
public FilterRegistrationBean<ActuatorAuthFilter> actuatorFilterRegistrationBean() { |
|||
FilterRegistrationBean<ActuatorAuthFilter> registrationBean = new FilterRegistrationBean<>(); |
|||
registrationBean.setFilter(new ActuatorAuthFilter(username, password)); |
|||
registrationBean.addUrlPatterns("/actuator", "/actuator/**"); |
|||
return registrationBean; |
|||
} |
|||
|
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
package org.dromara.snailjob; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
/** |
|||
* SnailJob Server 启动程序 |
|||
* |
|||
* @author opensnail |
|||
* @date 2024-05-17 |
|||
*/ |
|||
@SpringBootApplication |
|||
public class SnailJobServerApplication { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(com.aizuda.snailjob.server.SnailJobServerApplication.class, args); |
|||
} |
|||
|
|||
} |
|||
@ -1,50 +0,0 @@ |
|||
spring: |
|||
datasource: |
|||
type: com.zaxxer.hikari.HikariDataSource |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true |
|||
username: root |
|||
password: root |
|||
hikari: |
|||
connection-timeout: 30000 |
|||
validation-timeout: 5000 |
|||
minimum-idle: 10 |
|||
maximum-pool-size: 20 |
|||
idle-timeout: 600000 |
|||
max-lifetime: 900000 |
|||
keepaliveTime: 30000 |
|||
|
|||
--- # snail-job 服务端配置 |
|||
snail-job: |
|||
# 拉取重试数据的每批次的大小 |
|||
retry-pull-page-size: 1000 |
|||
# 拉取重试数据的每批次的大小 |
|||
job-pull-page-size: 1000 |
|||
# 服务端netty端口 |
|||
netty-port: 17888 |
|||
# 一个客户端每秒最多接收的重试数量指令 |
|||
limiter: 1000 |
|||
# 号段模式下步长配置 |
|||
step: 100 |
|||
# 日志保存时间(单位: day) |
|||
log-storage: 90 |
|||
# 回调配置 |
|||
callback: |
|||
#回调最大执行次数 |
|||
max-count: 288 |
|||
#间隔时间 |
|||
trigger-interval: 900 |
|||
retry-max-pull-count: 10 |
|||
|
|||
--- # 监控中心配置 |
|||
spring.boot.admin.client: |
|||
# 增加客户端开关 |
|||
enabled: true |
|||
url: http://localhost:9090/admin |
|||
instance: |
|||
service-host-type: IP |
|||
metadata: |
|||
username: ${spring.boot.admin.client.username} |
|||
userpassword: ${spring.boot.admin.client.password} |
|||
username: @monitor.username@ |
|||
password: @monitor.password@ |
|||
@ -1,50 +0,0 @@ |
|||
spring: |
|||
datasource: |
|||
type: com.zaxxer.hikari.HikariDataSource |
|||
driver-class-name: com.mysql.cj.jdbc.Driver |
|||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true |
|||
username: root |
|||
password: root |
|||
hikari: |
|||
connection-timeout: 30000 |
|||
validation-timeout: 5000 |
|||
minimum-idle: 10 |
|||
maximum-pool-size: 20 |
|||
idle-timeout: 600000 |
|||
max-lifetime: 900000 |
|||
keepaliveTime: 30000 |
|||
|
|||
--- # snail-job 服务端配置 |
|||
snail-job: |
|||
# 拉取重试数据的每批次的大小 |
|||
retry-pull-page-size: 1000 |
|||
# 拉取重试数据的每批次的大小 |
|||
job-pull-page-size: 1000 |
|||
# 服务端 netty 端口 |
|||
netty-port: 17888 |
|||
# 一个客户端每秒最多接收的重试数量指令 |
|||
limiter: 1000 |
|||
# 号段模式下步长配置 |
|||
step: 100 |
|||
# 日志保存时间(单位: day) |
|||
log-storage: 90 |
|||
# 回调配置 |
|||
callback: |
|||
#回调最大执行次数 |
|||
max-count: 288 |
|||
#间隔时间 |
|||
trigger-interval: 900 |
|||
retry-max-pull-count: 10 |
|||
|
|||
--- # 监控中心配置 |
|||
spring.boot.admin.client: |
|||
# 增加客户端开关 |
|||
enabled: true |
|||
url: http://localhost:9090/admin |
|||
instance: |
|||
service-host-type: IP |
|||
metadata: |
|||
username: ${spring.boot.admin.client.username} |
|||
userpassword: ${spring.boot.admin.client.password} |
|||
username: @monitor.username@ |
|||
password: @monitor.password@ |
|||
@ -1,39 +0,0 @@ |
|||
server: |
|||
port: 8800 |
|||
servlet: |
|||
context-path: /snail-job |
|||
|
|||
spring: |
|||
application: |
|||
name: ruoyi-snailjob-server |
|||
profiles: |
|||
active: @profiles.active@ |
|||
web: |
|||
resources: |
|||
static-locations: classpath:admin/ |
|||
|
|||
mybatis-plus: |
|||
typeAliasesPackage: com.aizuda.snailjob.template.datasource.persistence.po |
|||
global-config: |
|||
db-config: |
|||
where-strategy: NOT_EMPTY |
|||
capital-mode: false |
|||
logic-delete-value: 1 |
|||
logic-not-delete-value: 0 |
|||
configuration: |
|||
map-underscore-to-camel-case: true |
|||
cache-enabled: true |
|||
|
|||
logging: |
|||
config: classpath:logback-plus.xml |
|||
|
|||
management: |
|||
endpoints: |
|||
web: |
|||
exposure: |
|||
include: '*' |
|||
endpoint: |
|||
health: |
|||
show-details: ALWAYS |
|||
logfile: |
|||
external-file: ./logs/ruoyi-snailjob-server/console.log |
|||
@ -1,11 +0,0 @@ |
|||
Application Version: ${revision} |
|||
Spring Boot Version: ${spring-boot.version} |
|||
_ _ _ _ |
|||
(_) (_) | | |
|||
___ _ __ __ _ _| |_ ___ | |__ ______ ___ ___ _ ____ _____ _ __ |
|||
/ __| '_ \ / _` | | | |/ _ \| '_ \______/ __|/ _ \ '__\ \ / / _ \ '__| |
|||
\__ \ | | | (_| | | | | (_) | |_) | \__ \ __/ | \ V / __/ | |
|||
|___/_| |_|\__,_|_|_| |\___/|_.__/ |___/\___|_| \_/ \___|_| |
|||
_/ | |
|||
|__/ |
|||
|
|||
@ -1,92 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration> |
|||
<property name="log.path" value="./logs/ruoyi-snailjob-server" /> |
|||
<property name="console.log.pattern" |
|||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/> |
|||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/> |
|||
|
|||
|
|||
<!-- 控制台输出 --> |
|||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>${console.log.pattern}</pattern> |
|||
<charset>utf-8</charset> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<!-- 控制台输出 --> |
|||
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${log.path}/console.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<!-- 日志文件名格式 --> |
|||
<fileNamePattern>${log.path}/console.%d{yyyy-MM-dd}.log</fileNamePattern> |
|||
<!-- 日志最大 1天 --> |
|||
<maxHistory>1</maxHistory> |
|||
</rollingPolicy> |
|||
<encoder> |
|||
<pattern>${log.pattern}</pattern> |
|||
<charset>utf-8</charset> |
|||
</encoder> |
|||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
|||
<!-- 过滤的级别 --> |
|||
<level>INFO</level> |
|||
</filter> |
|||
</appender> |
|||
|
|||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${log.path}/info.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<FileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</FileNamePattern> |
|||
<MaxHistory>60</MaxHistory> |
|||
</rollingPolicy> |
|||
<encoder> |
|||
<pattern>${log.pattern}</pattern> |
|||
</encoder> |
|||
<filter class="ch.qos.logback.classic.filter.LevelFilter"> |
|||
<level>INFO</level> |
|||
<onMatch>ACCEPT</onMatch> |
|||
<onMismatch>DENY</onMismatch> |
|||
</filter> |
|||
</appender> |
|||
|
|||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
|||
<file>${log.path}/error.log</file> |
|||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
|||
<FileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log |
|||
</FileNamePattern> |
|||
<MaxHistory>60</MaxHistory> |
|||
</rollingPolicy> |
|||
<encoder> |
|||
<pattern>${log.pattern}</pattern> |
|||
</encoder> |
|||
<filter class="ch.qos.logback.classic.filter.LevelFilter"> |
|||
<level>ERROR</level> |
|||
<onMatch>ACCEPT</onMatch> |
|||
<onMismatch>DENY</onMismatch> |
|||
</filter> |
|||
</appender> |
|||
|
|||
<appender name ="async_info" class= "ch.qos.logback.classic.AsyncAppender"> |
|||
<discardingThreshold >100</discardingThreshold> |
|||
<queueSize>1024</queueSize> |
|||
<appender-ref ref ="file_info"/> |
|||
</appender> |
|||
|
|||
<appender name ="async_error" class= "ch.qos.logback.classic.AsyncAppender"> |
|||
<discardingThreshold >100</discardingThreshold> |
|||
<queueSize>1024</queueSize> |
|||
<appender-ref ref ="file_error"/> |
|||
</appender> |
|||
|
|||
<!-- SnailJob appender --> |
|||
<appender name="snail_log_server_appender" class="com.aizuda.snailjob.server.common.appender.SnailJobServerLogbackAppender"> |
|||
</appender> |
|||
|
|||
<!-- 控制台输出日志级别 --> |
|||
<root level="info"> |
|||
<appender-ref ref="console" /> |
|||
<appender-ref ref="async_info" /> |
|||
<appender-ref ref="async_error" /> |
|||
<appender-ref ref="snail_log_server_appender" /> |
|||
</root> |
|||
</configuration> |
|||
@ -1,108 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-modules</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>ruoyi-demo</artifactId> |
|||
|
|||
<description> |
|||
demo模块 |
|||
</description> |
|||
|
|||
<dependencies> |
|||
|
|||
<!-- 通用工具--> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-core</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-doc</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-sms</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-mail</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-redis</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-idempotent</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-mybatis</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-log</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-excel</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-security</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-web</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-ratelimiter</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-translation</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-sensitive</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-encrypt</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-tenant</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-websocket</artifactId> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
|
|||
</project> |
|||
@ -1,52 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.mail.utils.MailUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.io.File; |
|||
|
|||
|
|||
/** |
|||
* 邮件发送案例 |
|||
* |
|||
* @author Michelle.Chung |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/mail") |
|||
public class MailController { |
|||
|
|||
/** |
|||
* 发送邮件 |
|||
* |
|||
* @param to 接收人 |
|||
* @param subject 标题 |
|||
* @param text 内容 |
|||
*/ |
|||
@GetMapping("/sendSimpleMessage") |
|||
public R<Void> sendSimpleMessage(String to, String subject, String text) { |
|||
MailUtils.sendText(to, subject, text); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 发送邮件(带附件) |
|||
* |
|||
* @param to 接收人 |
|||
* @param subject 标题 |
|||
* @param text 内容 |
|||
* @param filePath 附件路径 |
|||
*/ |
|||
@GetMapping("/sendMessageWithAttachment") |
|||
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) { |
|||
MailUtils.sendText(to, subject, text, new File(filePath)); |
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
|||
@ -1,95 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.constant.CacheNames; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.redis.utils.RedisUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheEvict; |
|||
import org.springframework.cache.annotation.CachePut; |
|||
import org.springframework.cache.annotation.Cacheable; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.Duration; |
|||
|
|||
/** |
|||
* spring-cache 演示案例 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
// 类级别 缓存统一配置
|
|||
//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE)
|
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/cache") |
|||
public class RedisCacheController { |
|||
|
|||
/** |
|||
* 测试 @Cacheable |
|||
* <p> |
|||
* 表示这个方法有了缓存的功能,方法的返回值会被缓存下来 |
|||
* 下一次调用该方法前,会去检查是否缓存中已经有值 |
|||
* 如果有就直接返回,不调用方法 |
|||
* 如果没有,就调用方法,然后把结果缓存起来 |
|||
* 这个注解「一般用在查询方法上」 |
|||
* <p> |
|||
* 重点说明: 缓存注解严谨与其他筛选数据功能一起使用 |
|||
* 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题 |
|||
* <p> |
|||
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 |
|||
*/ |
|||
@Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null") |
|||
@GetMapping("/test1") |
|||
public R<String> test1(String key, String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试 @CachePut |
|||
* <p> |
|||
* 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用 |
|||
* 它「通常用在新增或者实时更新方法上」 |
|||
* <p> |
|||
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 |
|||
*/ |
|||
@CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") |
|||
@GetMapping("/test2") |
|||
public R<String> test2(String key, String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试 @CacheEvict |
|||
* <p> |
|||
* 使用了CacheEvict注解的方法,会清空指定缓存 |
|||
* 「一般用在删除的方法上」 |
|||
* <p> |
|||
* cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 |
|||
*/ |
|||
@CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") |
|||
@GetMapping("/test3") |
|||
public R<String> test3(String key, String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试设置过期时间 |
|||
* 手动设置过期时间10秒 |
|||
* 11秒后获取 判断是否相等 |
|||
*/ |
|||
@GetMapping("/test6") |
|||
public R<Boolean> test6(String key, String value) { |
|||
RedisUtils.setCacheObject(key, value); |
|||
boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10)); |
|||
System.out.println("***********" + flag); |
|||
try { |
|||
Thread.sleep(11 * 1000); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
Object obj = RedisUtils.getCacheObject(key); |
|||
return R.ok(value.equals(obj)); |
|||
} |
|||
|
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import com.baomidou.lock.LockInfo; |
|||
import com.baomidou.lock.LockTemplate; |
|||
import com.baomidou.lock.annotation.Lock4j; |
|||
import com.baomidou.lock.executor.RedissonLockExecutor; |
|||
import org.dromara.common.core.domain.R; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.time.LocalTime; |
|||
|
|||
|
|||
/** |
|||
* 测试分布式锁的样例 |
|||
* |
|||
* @author shenxinquan |
|||
*/ |
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/demo/redisLock") |
|||
public class RedisLockController { |
|||
|
|||
@Autowired |
|||
private LockTemplate lockTemplate; |
|||
|
|||
/** |
|||
* 测试lock4j 注解 |
|||
*/ |
|||
@Lock4j(keys = {"#key"}) |
|||
@GetMapping("/testLock4j") |
|||
public R<String> testLock4j(String key, String value) { |
|||
System.out.println("start:" + key + ",time:" + LocalTime.now().toString()); |
|||
try { |
|||
Thread.sleep(10000); |
|||
} catch (InterruptedException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
System.out.println("end :" + key + ",time:" + LocalTime.now().toString()); |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试lock4j 工具 |
|||
*/ |
|||
@GetMapping("/testLock4jLockTemplate") |
|||
public R<String> testLock4jLockTemplate(String key, String value) { |
|||
final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class); |
|||
if (null == lockInfo) { |
|||
throw new RuntimeException("业务处理中,请稍后再试"); |
|||
} |
|||
// 获取锁成功,处理业务
|
|||
try { |
|||
try { |
|||
Thread.sleep(8000); |
|||
} catch (InterruptedException e) { |
|||
//
|
|||
} |
|||
System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName()); |
|||
} finally { |
|||
//释放锁
|
|||
lockTemplate.releaseLock(lockInfo); |
|||
} |
|||
//结束
|
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
} |
|||
@ -1,47 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.redis.utils.RedisUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* Redis 发布订阅 演示案例 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/redis/pubsub") |
|||
public class RedisPubSubController { |
|||
|
|||
/** |
|||
* 发布消息 |
|||
* |
|||
* @param key 通道Key |
|||
* @param value 发送内容 |
|||
*/ |
|||
@GetMapping("/pub") |
|||
public R<Void> pub(String key, String value) { |
|||
RedisUtils.publish(key, value, consumer -> { |
|||
System.out.println("发布通道 => " + key + ", 发送值 => " + value); |
|||
}); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 订阅消息 |
|||
* |
|||
* @param key 通道Key |
|||
*/ |
|||
@GetMapping("/sub") |
|||
public R<Void> sub(String key) { |
|||
RedisUtils.subscribe(key, String.class, msg -> { |
|||
System.out.println("订阅通道 => " + key + ", 接收值 => " + msg); |
|||
}); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
} |
|||
@ -1,64 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.ratelimiter.annotation.RateLimiter; |
|||
import org.dromara.common.ratelimiter.enums.LimitType; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
|
|||
/** |
|||
* 测试分布式限流样例 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Slf4j |
|||
@RestController |
|||
@RequestMapping("/demo/rateLimiter") |
|||
public class RedisRateLimiterController { |
|||
|
|||
/** |
|||
* 测试全局限流 |
|||
* 全局影响 |
|||
*/ |
|||
@RateLimiter(count = 2, time = 10) |
|||
@GetMapping("/test") |
|||
public R<String> test(String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试请求IP限流 |
|||
* 同一IP请求受影响 |
|||
*/ |
|||
@RateLimiter(count = 2, time = 10, limitType = LimitType.IP) |
|||
@GetMapping("/testip") |
|||
public R<String> testip(String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试集群实例限流 |
|||
* 启动两个后端服务互不影响 |
|||
*/ |
|||
@RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER) |
|||
@GetMapping("/testcluster") |
|||
public R<String> testcluster(String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
/** |
|||
* 测试请求IP限流(key基于参数获取) |
|||
* 同一IP请求受影响 |
|||
* |
|||
* 简单变量获取 #变量 复杂表达式 #{#变量 != 1 ? 1 : 0} |
|||
*/ |
|||
@RateLimiter(count = 2, time = 10, limitType = LimitType.IP, key = "#value") |
|||
@GetMapping("/testObj") |
|||
public R<String> testObj(String value) { |
|||
return R.ok("操作成功", value); |
|||
} |
|||
|
|||
} |
|||
@ -1,82 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.sms4j.api.SmsBlend; |
|||
import org.dromara.sms4j.api.entity.SmsResponse; |
|||
import org.dromara.sms4j.core.factory.SmsFactory; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.LinkedHashMap; |
|||
|
|||
/** |
|||
* 短信演示案例 |
|||
* 请先阅读文档 否则无法使用 |
|||
* |
|||
* @author Lion Li |
|||
* @version 4.2.0 |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/sms") |
|||
public class SmsController { |
|||
/** |
|||
* 发送短信Aliyun |
|||
* |
|||
* @param phones 电话号 |
|||
* @param templateId 模板ID |
|||
*/ |
|||
@GetMapping("/sendAliyun") |
|||
public R<Object> sendAliyun(String phones, String templateId) { |
|||
LinkedHashMap<String, String> map = new LinkedHashMap<>(1); |
|||
map.put("code", "1234"); |
|||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); |
|||
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); |
|||
return R.ok(smsResponse); |
|||
} |
|||
|
|||
/** |
|||
* 发送短信Tencent |
|||
* |
|||
* @param phones 电话号 |
|||
* @param templateId 模板ID |
|||
*/ |
|||
@GetMapping("/sendTencent") |
|||
public R<Object> sendTencent(String phones, String templateId) { |
|||
LinkedHashMap<String, String> map = new LinkedHashMap<>(1); |
|||
// map.put("2", "测试测试");
|
|||
map.put("1", "1234"); |
|||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config2"); |
|||
SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, map); |
|||
return R.ok(smsResponse); |
|||
} |
|||
|
|||
/** |
|||
* 添加黑名单 |
|||
* |
|||
* @param phone 手机号 |
|||
*/ |
|||
@GetMapping("/addBlacklist") |
|||
public R<Object> addBlacklist(String phone){ |
|||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); |
|||
smsBlend.joinInBlacklist(phone); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 移除黑名单 |
|||
* |
|||
* @param phone 手机号 |
|||
*/ |
|||
@GetMapping("/removeBlacklist") |
|||
public R<Object> removeBlacklist(String phone){ |
|||
SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); |
|||
smsBlend.removeFromBlacklist(phone); |
|||
return R.ok(); |
|||
} |
|||
|
|||
} |
|||
@ -1,31 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestPart; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
/** |
|||
* swagger3 用法示例 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@RestController |
|||
@RequestMapping("/swagger/demo") |
|||
public class Swagger3DemoController { |
|||
|
|||
/** |
|||
* 上传请求 |
|||
* 必须使用 @RequestPart 注解标注为文件 |
|||
* |
|||
* @param file 文件 |
|||
*/ |
|||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
|||
public R<String> upload(@RequestPart("file") MultipartFile file) { |
|||
return R.ok("操作成功", file.getOriginalFilename()); |
|||
} |
|||
|
|||
} |
|||
@ -1,90 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import org.dromara.demo.mapper.TestDemoMapper; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.web.bind.annotation.DeleteMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 测试批量方法 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-05-30 |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/batch") |
|||
public class TestBatchController extends BaseController { |
|||
|
|||
/** |
|||
* 为了便于测试 直接引入mapper |
|||
*/ |
|||
private final TestDemoMapper testDemoMapper; |
|||
|
|||
/** |
|||
* 新增批量方法 可完美替代 saveBatch 秒级插入上万数据 (对mysql负荷较大) |
|||
* <p> |
|||
* 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度 |
|||
*/ |
|||
@PostMapping("/add") |
|||
// @DS("slave")
|
|||
public R<Void> add() { |
|||
List<TestDemo> list = new ArrayList<>(); |
|||
for (int i = 0; i < 1000; i++) { |
|||
TestDemo testDemo = new TestDemo(); |
|||
testDemo.setOrderNum(-1); |
|||
testDemo.setTestKey("批量新增"); |
|||
testDemo.setValue("测试新增"); |
|||
list.add(testDemo); |
|||
} |
|||
return toAjax(testDemoMapper.insertBatch(list)); |
|||
} |
|||
|
|||
/** |
|||
* 新增或更新 可完美替代 saveOrUpdateBatch 高性能 |
|||
* <p> |
|||
* 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度 |
|||
*/ |
|||
@PostMapping("/addOrUpdate") |
|||
// @DS("slave")
|
|||
public R<Void> addOrUpdate() { |
|||
List<TestDemo> list = new ArrayList<>(); |
|||
for (int i = 0; i < 1000; i++) { |
|||
TestDemo testDemo = new TestDemo(); |
|||
testDemo.setOrderNum(-1); |
|||
testDemo.setTestKey("批量新增"); |
|||
testDemo.setValue("测试新增"); |
|||
list.add(testDemo); |
|||
} |
|||
testDemoMapper.insertBatch(list); |
|||
for (int i = 0; i < list.size(); i++) { |
|||
TestDemo testDemo = list.get(i); |
|||
testDemo.setTestKey("批量新增或修改"); |
|||
testDemo.setValue("批量新增或修改"); |
|||
if (i % 2 == 0) { |
|||
testDemo.setId(null); |
|||
} |
|||
} |
|||
return toAjax(testDemoMapper.insertOrUpdateBatch(list)); |
|||
} |
|||
|
|||
/** |
|||
* 删除批量方法 |
|||
*/ |
|||
@DeleteMapping() |
|||
// @DS("slave")
|
|||
public R<Void> remove() { |
|||
return toAjax(testDemoMapper.delete(new LambdaQueryWrapper<TestDemo>() |
|||
.eq(TestDemo::getOrderNum, -1L))); |
|||
} |
|||
|
|||
} |
|||
@ -1,147 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import cn.dev33.satoken.annotation.SaCheckPermission; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.ValidatorUtils; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.core.validate.QueryGroup; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.dromara.common.idempotent.annotation.RepeatSubmit; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.excel.core.ExcelResult; |
|||
import org.dromara.common.excel.utils.ExcelUtil; |
|||
import org.dromara.common.log.annotation.Log; |
|||
import org.dromara.common.log.enums.BusinessType; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import org.dromara.demo.domain.bo.TestDemoBo; |
|||
import org.dromara.demo.domain.bo.TestDemoImportVo; |
|||
import org.dromara.demo.domain.vo.TestDemoVo; |
|||
import org.dromara.demo.service.ITestDemoService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import jakarta.validation.constraints.NotEmpty; |
|||
import jakarta.validation.constraints.NotNull; |
|||
|
|||
import java.util.*; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 测试单表Controller |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/demo") |
|||
public class TestDemoController extends BaseController { |
|||
|
|||
private final ITestDemoService testDemoService; |
|||
|
|||
/** |
|||
* 查询测试单表列表 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:list") |
|||
@GetMapping("/list") |
|||
public TableDataInfo<TestDemoVo> list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { |
|||
return testDemoService.queryPageList(bo, pageQuery); |
|||
} |
|||
|
|||
/** |
|||
* 自定义分页查询 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:list") |
|||
@GetMapping("/page") |
|||
public TableDataInfo<TestDemoVo> page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { |
|||
return testDemoService.customPageList(bo, pageQuery); |
|||
} |
|||
|
|||
/** |
|||
* 导入数据 |
|||
* |
|||
* @param file 导入文件 |
|||
*/ |
|||
@Log(title = "测试单表", businessType = BusinessType.IMPORT) |
|||
@SaCheckPermission("demo:demo:import") |
|||
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
|||
public R<Void> importData(@RequestPart("file") MultipartFile file) throws Exception { |
|||
ExcelResult<TestDemoImportVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true); |
|||
List<TestDemo> list = MapstructUtils.convert(excelResult.getList(), TestDemo.class); |
|||
testDemoService.saveBatch(list); |
|||
return R.ok(excelResult.getAnalysis()); |
|||
} |
|||
|
|||
/** |
|||
* 导出测试单表列表 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:export") |
|||
@Log(title = "测试单表", businessType = BusinessType.EXPORT) |
|||
@PostMapping("/export") |
|||
public void export(@Validated TestDemoBo bo, HttpServletResponse response) { |
|||
List<TestDemoVo> list = testDemoService.queryList(bo); |
|||
// 测试雪花id导出
|
|||
// for (TestDemoVo vo : list) {
|
|||
// vo.setId(1234567891234567893L);
|
|||
// }
|
|||
ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response); |
|||
} |
|||
|
|||
/** |
|||
* 获取测试单表详细信息 |
|||
* |
|||
* @param id 测试ID |
|||
*/ |
|||
@SaCheckPermission("demo:demo:query") |
|||
@GetMapping("/{id}") |
|||
public R<TestDemoVo> getInfo(@NotNull(message = "主键不能为空") |
|||
@PathVariable("id") Long id) { |
|||
return R.ok(testDemoService.queryById(id)); |
|||
} |
|||
|
|||
/** |
|||
* 新增测试单表 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:add") |
|||
@Log(title = "测试单表", businessType = BusinessType.INSERT) |
|||
@RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}") |
|||
@PostMapping() |
|||
public R<Void> add(@RequestBody TestDemoBo bo) { |
|||
// 使用校验工具对标 @Validated(AddGroup.class) 注解
|
|||
// 用于在非 Controller 的地方校验对象
|
|||
ValidatorUtils.validate(bo, AddGroup.class); |
|||
return toAjax(testDemoService.insertByBo(bo)); |
|||
} |
|||
|
|||
/** |
|||
* 修改测试单表 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:edit") |
|||
@Log(title = "测试单表", businessType = BusinessType.UPDATE) |
|||
@RepeatSubmit |
|||
@PutMapping() |
|||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) { |
|||
return toAjax(testDemoService.updateByBo(bo)); |
|||
} |
|||
|
|||
/** |
|||
* 删除测试单表 |
|||
* |
|||
* @param ids 测试ID串 |
|||
*/ |
|||
@SaCheckPermission("demo:demo:remove") |
|||
@Log(title = "测试单表", businessType = BusinessType.DELETE) |
|||
@DeleteMapping("/{ids}") |
|||
public R<Void> remove(@NotEmpty(message = "主键不能为空") |
|||
@PathVariable Long[] ids) { |
|||
return toAjax(testDemoService.deleteWithValidByIds(Arrays.asList(ids), true)); |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.demo.domain.TestDemoEncrypt; |
|||
import org.dromara.demo.mapper.TestDemoEncryptMapper; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
|
|||
/** |
|||
* 测试数据库加解密功能 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Validated |
|||
@RestController |
|||
@RequestMapping("/demo/encrypt") |
|||
public class TestEncryptController { |
|||
|
|||
@Autowired |
|||
private TestDemoEncryptMapper mapper; |
|||
@Value("${mybatis-encryptor.enable}") |
|||
private Boolean encryptEnable; |
|||
|
|||
/** |
|||
* 测试数据库加解密 |
|||
* |
|||
* @param key 测试key |
|||
* @param value 测试value |
|||
*/ |
|||
@GetMapping() |
|||
public R<Map<String, TestDemoEncrypt>> test(String key, String value) { |
|||
if (!encryptEnable) { |
|||
throw new RuntimeException("加密功能未开启!"); |
|||
} |
|||
Map<String, TestDemoEncrypt> map = new HashMap<>(2); |
|||
TestDemoEncrypt demo = new TestDemoEncrypt(); |
|||
demo.setTestKey(key); |
|||
demo.setValue(value); |
|||
mapper.insert(demo); |
|||
map.put("加密", demo); |
|||
TestDemoEncrypt testDemo = mapper.selectById(demo.getId()); |
|||
map.put("解密", testDemo); |
|||
return R.ok(map); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -1,160 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import cn.hutool.core.collection.CollUtil; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.excel.core.ExcelResult; |
|||
import org.dromara.common.excel.utils.ExcelUtil; |
|||
import org.dromara.demo.domain.vo.ExportDemoVo; |
|||
import org.dromara.demo.listener.ExportDemoListener; |
|||
import org.dromara.demo.service.IExportExcelService; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 测试Excel功能 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/excel") |
|||
public class TestExcelController { |
|||
|
|||
private final IExportExcelService exportExcelService; |
|||
|
|||
/** |
|||
* 单列表多数据 |
|||
*/ |
|||
@GetMapping("/exportTemplateOne") |
|||
public void exportTemplateOne(HttpServletResponse response) { |
|||
Map<String, String> map = new HashMap<>(); |
|||
map.put("title", "单列表多数据"); |
|||
map.put("test1", "数据测试1"); |
|||
map.put("test2", "数据测试2"); |
|||
map.put("test3", "数据测试3"); |
|||
map.put("test4", "数据测试4"); |
|||
map.put("testTest", "666"); |
|||
List<TestObj> list = new ArrayList<>(); |
|||
list.add(new TestObj("单列表测试1", "列表测试1", "列表测试2", "列表测试3", "列表测试4")); |
|||
list.add(new TestObj("单列表测试2", "列表测试5", "列表测试6", "列表测试7", "列表测试8")); |
|||
list.add(new TestObj("单列表测试3", "列表测试9", "列表测试10", "列表测试11", "列表测试12")); |
|||
ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "单列表.xlsx", "excel/单列表.xlsx", response); |
|||
} |
|||
|
|||
/** |
|||
* 多列表多数据 |
|||
*/ |
|||
@GetMapping("/exportTemplateMuliti") |
|||
public void exportTemplateMuliti(HttpServletResponse response) { |
|||
Map<String, String> map = new HashMap<>(); |
|||
map.put("title1", "标题1"); |
|||
map.put("title2", "标题2"); |
|||
map.put("title3", "标题3"); |
|||
map.put("title4", "标题4"); |
|||
map.put("author", "Lion Li"); |
|||
List<TestObj1> list1 = new ArrayList<>(); |
|||
list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3")); |
|||
list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6")); |
|||
list1.add(new TestObj1("list1测试7", "list1测试8", "list1测试9")); |
|||
List<TestObj1> list2 = new ArrayList<>(); |
|||
list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3")); |
|||
list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6")); |
|||
List<TestObj1> list3 = new ArrayList<>(); |
|||
list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3")); |
|||
List<TestObj1> list4 = new ArrayList<>(); |
|||
list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3")); |
|||
list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6")); |
|||
list4.add(new TestObj1("list4测试7", "list4测试8", "list4测试9")); |
|||
list4.add(new TestObj1("list4测试10", "list4测试11", "list4测试12")); |
|||
Map<String, Object> multiListMap = new HashMap<>(); |
|||
multiListMap.put("map", map); |
|||
multiListMap.put("data1", list1); |
|||
multiListMap.put("data2", list2); |
|||
multiListMap.put("data3", list3); |
|||
multiListMap.put("data4", list4); |
|||
ExcelUtil.exportTemplateMultiList(multiListMap, "多列表.xlsx", "excel/多列表.xlsx", response); |
|||
} |
|||
|
|||
/** |
|||
* 导出下拉框 |
|||
* |
|||
* @param response / |
|||
*/ |
|||
@GetMapping("/exportWithOptions") |
|||
public void exportWithOptions(HttpServletResponse response) { |
|||
exportExcelService.exportWithOptions(response); |
|||
} |
|||
|
|||
/** |
|||
* 多个sheet导出 |
|||
*/ |
|||
@GetMapping("/exportTemplateMultiSheet") |
|||
public void exportTemplateMultiSheet(HttpServletResponse response) { |
|||
List<TestObj1> list1 = new ArrayList<>(); |
|||
list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3")); |
|||
list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6")); |
|||
List<TestObj1> list2 = new ArrayList<>(); |
|||
list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3")); |
|||
list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6")); |
|||
List<TestObj1> list3 = new ArrayList<>(); |
|||
list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3")); |
|||
list3.add(new TestObj1("list3测试4", "list3测试5", "list3测试6")); |
|||
List<TestObj1> list4 = new ArrayList<>(); |
|||
list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3")); |
|||
list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6")); |
|||
|
|||
List<Map<String, Object>> list = new ArrayList<>(); |
|||
Map<String, Object> sheetMap1 = new HashMap<>(); |
|||
sheetMap1.put("data1", list1); |
|||
Map<String, Object> sheetMap2 = new HashMap<>(); |
|||
sheetMap2.put("data2", list2); |
|||
Map<String, Object> sheetMap3 = new HashMap<>(); |
|||
sheetMap3.put("data3", list3); |
|||
Map<String, Object> sheetMap4 = new HashMap<>(); |
|||
sheetMap4.put("data4", list4); |
|||
|
|||
list.add(sheetMap1); |
|||
list.add(sheetMap2); |
|||
list.add(sheetMap3); |
|||
list.add(sheetMap4); |
|||
ExcelUtil.exportTemplateMultiSheet(list, "多sheet列表", "excel/多sheet列表.xlsx", response); |
|||
} |
|||
|
|||
/** |
|||
* 导入表格 |
|||
*/ |
|||
@PostMapping(value = "/importWithOptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
|||
public List<ExportDemoVo> importWithOptions(@RequestPart("file") MultipartFile file) throws Exception { |
|||
// 处理解析结果
|
|||
ExcelResult<ExportDemoVo> excelResult = ExcelUtil.importExcel(file.getInputStream(), ExportDemoVo.class, new ExportDemoListener()); |
|||
return excelResult.getList(); |
|||
} |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
static class TestObj1 { |
|||
private String test1; |
|||
private String test2; |
|||
private String test3; |
|||
} |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
static class TestObj { |
|||
private String name; |
|||
private String list1; |
|||
private String list2; |
|||
private String list3; |
|||
private String list4; |
|||
} |
|||
|
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.core.utils.MessageUtils; |
|||
import lombok.Data; |
|||
import org.hibernate.validator.constraints.Range; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import jakarta.validation.constraints.NotBlank; |
|||
import jakarta.validation.constraints.NotNull; |
|||
|
|||
|
|||
/** |
|||
* 测试国际化 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Validated |
|||
@RestController |
|||
@RequestMapping("/demo/i18n") |
|||
public class TestI18nController { |
|||
|
|||
/** |
|||
* 通过code获取国际化内容 |
|||
* code为 messages.properties 中的 key |
|||
* <p> |
|||
* 测试使用 user.register.success |
|||
* |
|||
* @param code 国际化code |
|||
*/ |
|||
@GetMapping() |
|||
public R<Void> get(String code) { |
|||
return R.ok(MessageUtils.message(code)); |
|||
} |
|||
|
|||
/** |
|||
* Validator 校验国际化 |
|||
* 不传值 分别查看异常返回 |
|||
* <p> |
|||
* 测试使用 not.null |
|||
*/ |
|||
@GetMapping("/test1") |
|||
public R<Void> test1(@NotBlank(message = "{not.null}") String str) { |
|||
return R.ok(str); |
|||
} |
|||
|
|||
/** |
|||
* Bean 校验国际化 |
|||
* 不传值 分别查看异常返回 |
|||
* <p> |
|||
* 测试使用 not.null |
|||
*/ |
|||
@GetMapping("/test2") |
|||
public R<TestI18nBo> test2(@Validated TestI18nBo bo) { |
|||
return R.ok(bo); |
|||
} |
|||
|
|||
@Data |
|||
public static class TestI18nBo { |
|||
|
|||
@NotBlank(message = "{not.null}") |
|||
private String name; |
|||
|
|||
@NotNull(message = "{not.null}") |
|||
@Range(min = 0, max = 100, message = "{length.not.valid}") |
|||
private Integer age; |
|||
} |
|||
} |
|||
@ -1,76 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.dromara.common.sensitive.annotation.Sensitive; |
|||
import org.dromara.common.sensitive.core.SensitiveStrategy; |
|||
import lombok.Data; |
|||
import org.dromara.common.sensitive.core.SensitiveService; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 测试数据脱敏控制器 |
|||
* <p> |
|||
* 默认管理员不过滤 |
|||
* 需自行根据业务重写实现 |
|||
* |
|||
* @author Lion Li |
|||
* @version 3.6.0 |
|||
* @see SensitiveService |
|||
*/ |
|||
@RestController |
|||
@RequestMapping("/demo/sensitive") |
|||
public class TestSensitiveController extends BaseController { |
|||
|
|||
/** |
|||
* 测试数据脱敏 |
|||
*/ |
|||
@GetMapping("/test") |
|||
public R<TestSensitive> test() { |
|||
TestSensitive testSensitive = new TestSensitive(); |
|||
testSensitive.setIdCard("210397198608215431"); |
|||
testSensitive.setPhone("17640125371"); |
|||
testSensitive.setAddress("北京市朝阳区某某四合院1203室"); |
|||
testSensitive.setEmail("17640125371@163.com"); |
|||
testSensitive.setBankCard("6226456952351452853"); |
|||
return R.ok(testSensitive); |
|||
} |
|||
|
|||
@Data |
|||
static class TestSensitive { |
|||
|
|||
/** |
|||
* 身份证 |
|||
*/ |
|||
@Sensitive(strategy = SensitiveStrategy.ID_CARD) |
|||
private String idCard; |
|||
|
|||
/** |
|||
* 电话 |
|||
*/ |
|||
@Sensitive(strategy = SensitiveStrategy.PHONE, roleKey = "common") |
|||
private String phone; |
|||
|
|||
/** |
|||
* 地址 |
|||
*/ |
|||
@Sensitive(strategy = SensitiveStrategy.ADDRESS, perms = "system:user:query") |
|||
private String address; |
|||
|
|||
/** |
|||
* 邮箱 |
|||
*/ |
|||
@Sensitive(strategy = SensitiveStrategy.EMAIL, roleKey = "common", perms = "system:user:query1") |
|||
private String email; |
|||
|
|||
/** |
|||
* 银行卡 |
|||
*/ |
|||
@Sensitive(strategy = SensitiveStrategy.BANK_CARD, roleKey = "common1", perms = "system:user:query") |
|||
private String bankCard; |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -1,107 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import cn.dev33.satoken.annotation.SaCheckPermission; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.core.validate.QueryGroup; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.dromara.common.excel.utils.ExcelUtil; |
|||
import org.dromara.common.idempotent.annotation.RepeatSubmit; |
|||
import org.dromara.common.log.annotation.Log; |
|||
import org.dromara.common.log.enums.BusinessType; |
|||
import org.dromara.demo.domain.bo.TestTreeBo; |
|||
import org.dromara.demo.domain.vo.TestTreeVo; |
|||
import org.dromara.demo.service.ITestTreeService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import jakarta.validation.constraints.NotEmpty; |
|||
import jakarta.validation.constraints.NotNull; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 测试树表Controller |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/tree") |
|||
public class TestTreeController extends BaseController { |
|||
|
|||
private final ITestTreeService testTreeService; |
|||
|
|||
/** |
|||
* 查询测试树表列表 |
|||
*/ |
|||
@SaCheckPermission("demo:tree:list") |
|||
@GetMapping("/list") |
|||
public R<List<TestTreeVo>> list(@Validated(QueryGroup.class) TestTreeBo bo) { |
|||
List<TestTreeVo> list = testTreeService.queryList(bo); |
|||
return R.ok(list); |
|||
} |
|||
|
|||
/** |
|||
* 导出测试树表列表 |
|||
*/ |
|||
@SaCheckPermission("demo:tree:export") |
|||
@Log(title = "测试树表", businessType = BusinessType.EXPORT) |
|||
@GetMapping("/export") |
|||
public void export(@Validated TestTreeBo bo, HttpServletResponse response) { |
|||
List<TestTreeVo> list = testTreeService.queryList(bo); |
|||
ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response); |
|||
} |
|||
|
|||
/** |
|||
* 获取测试树表详细信息 |
|||
* |
|||
* @param id 测试树ID |
|||
*/ |
|||
@SaCheckPermission("demo:tree:query") |
|||
@GetMapping("/{id}") |
|||
public R<TestTreeVo> getInfo(@NotNull(message = "主键不能为空") |
|||
@PathVariable("id") Long id) { |
|||
return R.ok(testTreeService.queryById(id)); |
|||
} |
|||
|
|||
/** |
|||
* 新增测试树表 |
|||
*/ |
|||
@SaCheckPermission("demo:tree:add") |
|||
@Log(title = "测试树表", businessType = BusinessType.INSERT) |
|||
@RepeatSubmit |
|||
@PostMapping() |
|||
public R<Void> add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) { |
|||
return toAjax(testTreeService.insertByBo(bo)); |
|||
} |
|||
|
|||
/** |
|||
* 修改测试树表 |
|||
*/ |
|||
@SaCheckPermission("demo:tree:edit") |
|||
@Log(title = "测试树表", businessType = BusinessType.UPDATE) |
|||
@RepeatSubmit |
|||
@PutMapping() |
|||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) { |
|||
return toAjax(testTreeService.updateByBo(bo)); |
|||
} |
|||
|
|||
/** |
|||
* 删除测试树表 |
|||
* |
|||
* @param ids 测试树ID串 |
|||
*/ |
|||
@SaCheckPermission("demo:tree:remove") |
|||
@Log(title = "测试树表", businessType = BusinessType.DELETE) |
|||
@DeleteMapping("/{ids}") |
|||
public R<Void> remove(@NotEmpty(message = "主键不能为空") |
|||
@PathVariable Long[] ids) { |
|||
return toAjax(testTreeService.deleteWithValidByIds(Arrays.asList(ids), true)); |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
|
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.websocket.dto.WebSocketMessageDto; |
|||
import org.dromara.common.websocket.utils.WebSocketUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* WebSocket 演示案例 |
|||
* |
|||
* @author zendwang |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/websocket") |
|||
@Slf4j |
|||
public class WeSocketController { |
|||
|
|||
/** |
|||
* 发布消息 |
|||
* |
|||
* @param dto 发送内容 |
|||
*/ |
|||
@GetMapping("/send") |
|||
public R<Void> send(WebSocketMessageDto dto) throws InterruptedException { |
|||
WebSocketUtils.publishMessage(dto); |
|||
return R.ok("操作成功"); |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
package org.dromara.demo.controller; |
|||
@ -1,92 +0,0 @@ |
|||
package org.dromara.demo.controller.queue; |
|||
|
|||
import cn.dev33.satoken.annotation.SaIgnore; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.redis.utils.QueueUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.redisson.api.RBoundedBlockingQueue; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 有界队列 演示案例 |
|||
* <p> |
|||
* 轻量级队列 重量级数据量 请使用 MQ |
|||
* <p> |
|||
* 集群测试通过 同一个数据只会被消费一次 做好事务补偿 |
|||
* 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条 |
|||
* |
|||
* @author Lion Li |
|||
* @version 3.6.0 |
|||
*/ |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/queue/bounded") |
|||
public class BoundedQueueController { |
|||
|
|||
|
|||
/** |
|||
* 添加队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
* @param capacity 容量 |
|||
*/ |
|||
@GetMapping("/add") |
|||
public R<Void> add(String queueName, int capacity) { |
|||
// 用完了一定要销毁 否则会一直存在
|
|||
boolean b = QueueUtils.destroyBoundedQueue(queueName); |
|||
log.info("通道: {} , 删除: {}", queueName, b); |
|||
// 初始化设置一次即可
|
|||
if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) { |
|||
log.info("通道: {} , 设置容量: {}", queueName, capacity); |
|||
} else { |
|||
log.info("通道: {} , 设置容量失败", queueName); |
|||
return R.fail("操作失败"); |
|||
} |
|||
for (int i = 0; i < 11; i++) { |
|||
String data = "data-" + i; |
|||
boolean flag = QueueUtils.addBoundedQueueObject(queueName, data); |
|||
if (flag == false) { |
|||
log.info("通道: {} , 发送数据: {} 失败, 通道已满", queueName, data); |
|||
} else { |
|||
log.info("通道: {} , 发送数据: {}", queueName, data); |
|||
} |
|||
} |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 删除队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/remove") |
|||
public R<Void> remove(String queueName) { |
|||
String data = "data-" + 5; |
|||
if (QueueUtils.removeBoundedQueueObject(queueName, data)) { |
|||
log.info("通道: {} , 删除数据: {}", queueName, data); |
|||
} else { |
|||
return R.fail("操作失败"); |
|||
} |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 获取队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/get") |
|||
public R<Void> get(String queueName) { |
|||
String data; |
|||
do { |
|||
data = QueueUtils.getBoundedQueueObject(queueName); |
|||
log.info("通道: {} , 获取数据: {}", queueName, data); |
|||
} while (data != null); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
} |
|||
@ -1,97 +0,0 @@ |
|||
package org.dromara.demo.controller.queue; |
|||
|
|||
import cn.dev33.satoken.annotation.SaIgnore; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.redis.utils.QueueUtils; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import java.util.concurrent.CompletableFuture; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 延迟队列 演示案例 |
|||
* <p> |
|||
* 轻量级队列 重量级数据量 请使用 MQ |
|||
* 例如: 创建订单30分钟后过期处理 |
|||
* <p> |
|||
* 集群测试通过 同一个数据只会被消费一次 做好事务补偿 |
|||
* 集群测试流程 两台集群分别开启订阅 在其中一台发送数据 观察接收消息的规律 |
|||
* |
|||
* @author Lion Li |
|||
* @version 3.6.0 |
|||
*/ |
|||
@SaIgnore |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/queue/delayed") |
|||
public class DelayedQueueController { |
|||
|
|||
/** |
|||
* 订阅队列 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/subscribe") |
|||
public R<Void> subscribe(String queueName) { |
|||
log.info("通道: {} 监听中......", queueName); |
|||
// 项目初始化设置一次即可
|
|||
QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> { |
|||
// 观察接收时间
|
|||
log.info("通道: {}, 收到数据: {}", queueName, orderNum); |
|||
return CompletableFuture.runAsync(() -> { |
|||
// 异步处理数据逻辑 不要在上方处理业务逻辑
|
|||
log.info("数据处理: {}", orderNum); |
|||
}); |
|||
}, true); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 添加队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
* @param orderNum 订单号 |
|||
* @param time 延迟时间(秒) |
|||
*/ |
|||
@GetMapping("/add") |
|||
public R<Void> add(String queueName, String orderNum, Long time) { |
|||
QueueUtils.addDelayedQueueObject(queueName, orderNum, time, TimeUnit.SECONDS); |
|||
// 观察发送时间
|
|||
log.info("通道: {} , 发送数据: {}", queueName, orderNum); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 删除队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
* @param orderNum 订单号 |
|||
*/ |
|||
@GetMapping("/remove") |
|||
public R<Void> remove(String queueName, String orderNum) { |
|||
if (QueueUtils.removeDelayedQueueObject(queueName, orderNum)) { |
|||
log.info("通道: {} , 删除数据: {}", queueName, orderNum); |
|||
} else { |
|||
return R.fail("操作失败"); |
|||
} |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 销毁队列 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/destroy") |
|||
public R<Void> destroy(String queueName) { |
|||
// 用完了一定要销毁 否则会一直存在
|
|||
QueueUtils.destroyDelayedQueue(queueName); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
} |
|||
@ -1,22 +0,0 @@ |
|||
package org.dromara.demo.controller.queue; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
/** |
|||
* 实体类 注意不允许使用内部类 否则会找不到类 |
|||
* |
|||
* @author Lion Li |
|||
* @version 3.6.0 |
|||
*/ |
|||
@Data |
|||
@NoArgsConstructor |
|||
public class PriorityDemo implements Comparable<PriorityDemo> { |
|||
private String name; |
|||
private Integer orderNum; |
|||
|
|||
@Override |
|||
public int compareTo(PriorityDemo other) { |
|||
return Integer.compare(getOrderNum(), other.getOrderNum()); |
|||
} |
|||
} |
|||
@ -1,89 +0,0 @@ |
|||
package org.dromara.demo.controller.queue; |
|||
|
|||
import cn.hutool.core.util.RandomUtil; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.redis.utils.QueueUtils; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
/** |
|||
* 优先队列 演示案例 |
|||
* <p> |
|||
* 轻量级队列 重量级数据量 请使用 MQ |
|||
* <p> |
|||
* 集群测试通过 同一个消息只会被消费一次 做好事务补偿 |
|||
* 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条 |
|||
* |
|||
* @author Lion Li |
|||
* @version 3.6.0 |
|||
*/ |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/demo/queue/priority") |
|||
public class PriorityQueueController { |
|||
|
|||
/** |
|||
* 添加队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/add") |
|||
public R<Void> add(String queueName) { |
|||
// 用完了一定要销毁 否则会一直存在
|
|||
boolean b = QueueUtils.destroyPriorityQueue(queueName); |
|||
log.info("通道: {} , 删除: {}", queueName, b); |
|||
|
|||
for (int i = 0; i < 10; i++) { |
|||
int randomNum = RandomUtil.randomInt(10); |
|||
PriorityDemo data = new PriorityDemo(); |
|||
data.setName("data-" + i); |
|||
data.setOrderNum(randomNum); |
|||
if (QueueUtils.addPriorityQueueObject(queueName, data)) { |
|||
log.info("通道: {} , 发送数据: {}", queueName, data); |
|||
} else { |
|||
log.info("通道: {} , 发送数据: {}, 发送失败", queueName, data); |
|||
} |
|||
} |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 删除队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
* @param name 对象名 |
|||
* @param orderNum 排序号 |
|||
*/ |
|||
@GetMapping("/remove") |
|||
public R<Void> remove(String queueName, String name, Integer orderNum) { |
|||
PriorityDemo data = new PriorityDemo(); |
|||
data.setName(name); |
|||
data.setOrderNum(orderNum); |
|||
if (QueueUtils.removePriorityQueueObject(queueName, data)) { |
|||
log.info("通道: {} , 删除数据: {}", queueName, data); |
|||
} else { |
|||
return R.fail("操作失败"); |
|||
} |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
/** |
|||
* 获取队列数据 |
|||
* |
|||
* @param queueName 队列名 |
|||
*/ |
|||
@GetMapping("/get") |
|||
public R<Void> get(String queueName) { |
|||
PriorityDemo data; |
|||
do { |
|||
data = QueueUtils.getPriorityQueueObject(queueName); |
|||
log.info("通道: {} , 获取数据: {}", queueName, data); |
|||
} while (data != null); |
|||
return R.ok("操作成功"); |
|||
} |
|||
|
|||
} |
|||
@ -1,68 +0,0 @@ |
|||
package org.dromara.demo.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.*; |
|||
import org.dromara.common.tenant.core.TenantEntity; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serial; |
|||
|
|||
/** |
|||
* 测试单表对象 test_demo |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@TableName("test_demo") |
|||
public class TestDemo extends TenantEntity { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@TableId(value = "id") |
|||
private Long id; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 排序号 |
|||
*/ |
|||
@OrderBy(asc = false, sort = 1) |
|||
private Integer orderNum; |
|||
|
|||
/** |
|||
* key键 |
|||
*/ |
|||
private String testKey; |
|||
|
|||
/** |
|||
* 值 |
|||
*/ |
|||
private String value; |
|||
|
|||
/** |
|||
* 版本 |
|||
*/ |
|||
@Version |
|||
private Long version; |
|||
|
|||
/** |
|||
* 删除标志 |
|||
*/ |
|||
@TableLogic |
|||
private Long delFlag; |
|||
|
|||
} |
|||
@ -1,29 +0,0 @@ |
|||
package org.dromara.demo.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import org.dromara.common.encrypt.annotation.EncryptField; |
|||
import org.dromara.common.encrypt.enumd.AlgorithmType; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@TableName("test_demo") |
|||
public class TestDemoEncrypt extends TestDemo { |
|||
|
|||
/** |
|||
* key键 |
|||
*/ |
|||
// @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==")
|
|||
@EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB") |
|||
private String testKey; |
|||
|
|||
/** |
|||
* 值 |
|||
*/ |
|||
// @EncryptField // 什么也不写走默认yml配置
|
|||
// @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5")
|
|||
@EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5") |
|||
private String value; |
|||
|
|||
} |
|||
@ -1,65 +0,0 @@ |
|||
package org.dromara.demo.domain; |
|||
|
|||
import com.baomidou.mybatisplus.annotation.TableId; |
|||
import com.baomidou.mybatisplus.annotation.TableLogic; |
|||
import com.baomidou.mybatisplus.annotation.TableName; |
|||
import com.baomidou.mybatisplus.annotation.Version; |
|||
import org.dromara.common.tenant.core.TenantEntity; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serial; |
|||
|
|||
/** |
|||
* 测试树表对象 test_tree |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@TableName("test_tree") |
|||
public class TestTree extends TenantEntity { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@TableId(value = "id") |
|||
private Long id; |
|||
|
|||
/** |
|||
* 父ID |
|||
*/ |
|||
private Long parentId; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 树节点名 |
|||
*/ |
|||
private String treeName; |
|||
|
|||
/** |
|||
* 版本 |
|||
*/ |
|||
@Version |
|||
private Long version; |
|||
|
|||
/** |
|||
* 删除标志 |
|||
*/ |
|||
@TableLogic |
|||
private Long delFlag; |
|||
|
|||
} |
|||
@ -1,62 +0,0 @@ |
|||
package org.dromara.demo.domain.bo; |
|||
|
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import jakarta.validation.constraints.NotBlank; |
|||
import jakarta.validation.constraints.NotNull; |
|||
|
|||
/** |
|||
* 测试单表业务对象 test_demo |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
|
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@AutoMapper(target = TestDemo.class, reverseConvertGenerate = false) |
|||
public class TestDemoBo extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@NotNull(message = "主键不能为空", groups = {EditGroup.class}) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
@NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
@NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 排序号 |
|||
*/ |
|||
@NotNull(message = "排序号不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private Integer orderNum; |
|||
|
|||
/** |
|||
* key键 |
|||
*/ |
|||
@NotBlank(message = "key键不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private String testKey; |
|||
|
|||
/** |
|||
* 值 |
|||
*/ |
|||
@NotBlank(message = "值不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private String value; |
|||
|
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
package org.dromara.demo.domain.bo; |
|||
|
|||
import com.alibaba.excel.annotation.ExcelProperty; |
|||
import lombok.Data; |
|||
|
|||
import jakarta.validation.constraints.NotBlank; |
|||
import jakarta.validation.constraints.NotNull; |
|||
|
|||
/** |
|||
* 测试单表业务对象 test_demo |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Data |
|||
public class TestDemoImportVo { |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
@NotNull(message = "部门id不能为空") |
|||
@ExcelProperty(value = "部门id") |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
@NotNull(message = "用户id不能为空") |
|||
@ExcelProperty(value = "用户id") |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 排序号 |
|||
*/ |
|||
@NotNull(message = "排序号不能为空") |
|||
@ExcelProperty(value = "排序号") |
|||
private Long orderNum; |
|||
|
|||
/** |
|||
* key键 |
|||
*/ |
|||
@NotBlank(message = "key键不能为空") |
|||
@ExcelProperty(value = "key键") |
|||
private String testKey; |
|||
|
|||
/** |
|||
* 值 |
|||
*/ |
|||
@NotBlank(message = "值不能为空") |
|||
@ExcelProperty(value = "值") |
|||
private String value; |
|||
|
|||
} |
|||
@ -1,54 +0,0 @@ |
|||
package org.dromara.demo.domain.bo; |
|||
|
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.mybatis.core.domain.BaseEntity; |
|||
import org.dromara.demo.domain.TestTree; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import jakarta.validation.constraints.NotNull; |
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
/** |
|||
* 测试树表业务对象 test_tree |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
|
|||
@Data |
|||
@EqualsAndHashCode(callSuper = true) |
|||
@AutoMapper(target = TestTree.class, reverseConvertGenerate = false) |
|||
public class TestTreeBo extends BaseEntity { |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@NotNull(message = "主键不能为空", groups = {EditGroup.class}) |
|||
private Long id; |
|||
|
|||
/** |
|||
* 父ID |
|||
*/ |
|||
private Long parentId; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
@NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
@NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 树节点名 |
|||
*/ |
|||
@NotBlank(message = "树节点名不能为空", groups = {AddGroup.class, EditGroup.class}) |
|||
private String treeName; |
|||
|
|||
} |
|||
@ -1 +0,0 @@ |
|||
package org.dromara.demo.domain; |
|||
@ -1,118 +0,0 @@ |
|||
package org.dromara.demo.domain.vo; |
|||
|
|||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
|||
import com.alibaba.excel.annotation.ExcelProperty; |
|||
import jakarta.validation.constraints.NotEmpty; |
|||
import jakarta.validation.constraints.NotNull; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.dromara.common.core.enums.UserStatus; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.excel.annotation.ExcelDictFormat; |
|||
import org.dromara.common.excel.annotation.ExcelEnumFormat; |
|||
import org.dromara.common.excel.convert.ExcelDictConvert; |
|||
import org.dromara.common.excel.convert.ExcelEnumConvert; |
|||
|
|||
/** |
|||
* 带有下拉选的Excel导出 |
|||
* |
|||
* @author Emil.Zhang |
|||
*/ |
|||
@Data |
|||
@ExcelIgnoreUnannotated |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
public class ExportDemoVo { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 用户昵称 |
|||
*/ |
|||
@ExcelProperty(value = "用户名", index = 0) |
|||
@NotEmpty(message = "用户名不能为空", groups = AddGroup.class) |
|||
private String nickName; |
|||
|
|||
/** |
|||
* 用户类型 |
|||
* </p> |
|||
* 使用ExcelEnumFormat注解需要进行下拉选的部分 |
|||
*/ |
|||
@ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) |
|||
@ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") |
|||
@NotEmpty(message = "用户类型不能为空", groups = AddGroup.class) |
|||
private String userStatus; |
|||
|
|||
/** |
|||
* 性别 |
|||
* <p> |
|||
* 使用ExcelDictFormat注解需要进行下拉选的部分 |
|||
*/ |
|||
@ExcelProperty(value = "性别", index = 2, converter = ExcelDictConvert.class) |
|||
@ExcelDictFormat(dictType = "sys_user_sex") |
|||
@NotEmpty(message = "性别不能为空", groups = AddGroup.class) |
|||
private String gender; |
|||
|
|||
/** |
|||
* 手机号 |
|||
*/ |
|||
@ExcelProperty(value = "手机号", index = 3) |
|||
@NotEmpty(message = "手机号不能为空", groups = AddGroup.class) |
|||
private String phoneNumber; |
|||
|
|||
/** |
|||
* Email |
|||
*/ |
|||
@ExcelProperty(value = "Email", index = 4) |
|||
@NotEmpty(message = "Email不能为空", groups = AddGroup.class) |
|||
private String email; |
|||
|
|||
/** |
|||
* 省 |
|||
* <p> |
|||
* 级联下拉,仅判断是否选了 |
|||
*/ |
|||
@ExcelProperty(value = "省", index = 5) |
|||
@NotNull(message = "省不能为空", groups = AddGroup.class) |
|||
private String province; |
|||
|
|||
/** |
|||
* 数据库中的省ID |
|||
* </p> |
|||
* 处理完毕后再判断是否市正确的值 |
|||
*/ |
|||
@NotNull(message = "请勿手动输入", groups = EditGroup.class) |
|||
private Integer provinceId; |
|||
|
|||
/** |
|||
* 市 |
|||
* <p> |
|||
* 级联下拉 |
|||
*/ |
|||
@ExcelProperty(value = "市", index = 6) |
|||
@NotNull(message = "市不能为空", groups = AddGroup.class) |
|||
private String city; |
|||
|
|||
/** |
|||
* 数据库中的市ID |
|||
*/ |
|||
@NotNull(message = "请勿手动输入", groups = EditGroup.class) |
|||
private Integer cityId; |
|||
|
|||
/** |
|||
* 县 |
|||
* <p> |
|||
* 级联下拉 |
|||
*/ |
|||
@ExcelProperty(value = "县", index = 7) |
|||
@NotNull(message = "县不能为空", groups = AddGroup.class) |
|||
private String area; |
|||
|
|||
/** |
|||
* 数据库中的县ID |
|||
*/ |
|||
@NotNull(message = "请勿手动输入", groups = EditGroup.class) |
|||
private Integer areaId; |
|||
} |
|||
@ -1,104 +0,0 @@ |
|||
package org.dromara.demo.domain.vo; |
|||
|
|||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
|||
import com.alibaba.excel.annotation.ExcelProperty; |
|||
import org.dromara.common.translation.annotation.Translation; |
|||
import org.dromara.common.translation.constant.TransConstant; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
|
|||
/** |
|||
* 测试单表视图对象 test_demo |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Data |
|||
@ExcelIgnoreUnannotated |
|||
@AutoMapper(target = TestDemo.class) |
|||
public class TestDemoVo implements Serializable { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
@ExcelProperty(value = "主键") |
|||
private Long id; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
@ExcelProperty(value = "部门id") |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
@ExcelProperty(value = "用户id") |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 排序号 |
|||
*/ |
|||
@ExcelProperty(value = "排序号") |
|||
private Integer orderNum; |
|||
|
|||
/** |
|||
* key键 |
|||
*/ |
|||
@ExcelProperty(value = "key键") |
|||
private String testKey; |
|||
|
|||
/** |
|||
* 值 |
|||
*/ |
|||
@ExcelProperty(value = "值") |
|||
private String value; |
|||
|
|||
/** |
|||
* 创建时间 |
|||
*/ |
|||
@ExcelProperty(value = "创建时间") |
|||
private Date createTime; |
|||
|
|||
/** |
|||
* 创建人 |
|||
*/ |
|||
@ExcelProperty(value = "创建人") |
|||
private Long createBy; |
|||
|
|||
/** |
|||
* 创建人账号 |
|||
*/ |
|||
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") |
|||
@ExcelProperty(value = "创建人账号") |
|||
private String createByName; |
|||
|
|||
/** |
|||
* 更新时间 |
|||
*/ |
|||
@ExcelProperty(value = "更新时间") |
|||
private Date updateTime; |
|||
|
|||
/** |
|||
* 更新人 |
|||
*/ |
|||
@ExcelProperty(value = "更新人") |
|||
private Long updateBy; |
|||
|
|||
/** |
|||
* 更新人账号 |
|||
*/ |
|||
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy") |
|||
@ExcelProperty(value = "更新人账号") |
|||
private String updateByName; |
|||
|
|||
} |
|||
@ -1,64 +0,0 @@ |
|||
package org.dromara.demo.domain.vo; |
|||
|
|||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
|||
import com.alibaba.excel.annotation.ExcelProperty; |
|||
import org.dromara.demo.domain.TestTree; |
|||
import io.github.linpeilie.annotations.AutoMapper; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serial; |
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
|
|||
/** |
|||
* 测试树表视图对象 test_tree |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@Data |
|||
@ExcelIgnoreUnannotated |
|||
@AutoMapper(target = TestTree.class) |
|||
public class TestTreeVo implements Serializable { |
|||
|
|||
@Serial |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** |
|||
* 主键 |
|||
*/ |
|||
private Long id; |
|||
|
|||
/** |
|||
* 父id |
|||
*/ |
|||
@ExcelProperty(value = "父id") |
|||
private Long parentId; |
|||
|
|||
/** |
|||
* 部门id |
|||
*/ |
|||
@ExcelProperty(value = "部门id") |
|||
private Long deptId; |
|||
|
|||
/** |
|||
* 用户id |
|||
*/ |
|||
@ExcelProperty(value = "用户id") |
|||
private Long userId; |
|||
|
|||
/** |
|||
* 树节点名 |
|||
*/ |
|||
@ExcelProperty(value = "树节点名") |
|||
private String treeName; |
|||
|
|||
/** |
|||
* 创建时间 |
|||
*/ |
|||
@ExcelProperty(value = "创建时间") |
|||
private Date createTime; |
|||
|
|||
|
|||
} |
|||
@ -1,68 +0,0 @@ |
|||
package org.dromara.demo.listener; |
|||
|
|||
import cn.hutool.core.util.NumberUtil; |
|||
import com.alibaba.excel.context.AnalysisContext; |
|||
import org.dromara.common.core.utils.ValidatorUtils; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.excel.core.DefaultExcelListener; |
|||
import org.dromara.common.excel.core.DropDownOptions; |
|||
import org.dromara.demo.domain.vo.ExportDemoVo; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* Excel带下拉框的解析处理器 |
|||
* |
|||
* @author Emil.Zhang |
|||
*/ |
|||
public class ExportDemoListener extends DefaultExcelListener<ExportDemoVo> { |
|||
|
|||
public ExportDemoListener() { |
|||
// 显示使用构造函数,否则将导致空指针
|
|||
super(true); |
|||
} |
|||
|
|||
@Override |
|||
public void invoke(ExportDemoVo data, AnalysisContext context) { |
|||
// 先校验必填
|
|||
ValidatorUtils.validate(data, AddGroup.class); |
|||
|
|||
// 处理级联下拉的部分
|
|||
String province = data.getProvince(); |
|||
String city = data.getCity(); |
|||
String area = data.getArea(); |
|||
// 本行用户选择的省
|
|||
List<String> thisRowSelectedProvinceOption = DropDownOptions.analyzeOptionValue(province); |
|||
if (thisRowSelectedProvinceOption.size() == 2) { |
|||
String provinceIdStr = thisRowSelectedProvinceOption.get(1); |
|||
if (NumberUtil.isNumber(provinceIdStr)) { |
|||
// 严格要求数据的话可以在这里做与数据库相关的判断
|
|||
// 例如判断省信息是否在数据库中存在等,建议结合RedisCache做缓存10s,减少数据库调用
|
|||
data.setProvinceId(Integer.parseInt(provinceIdStr)); |
|||
} |
|||
} |
|||
// 本行用户选择的市
|
|||
List<String> thisRowSelectedCityOption = DropDownOptions.analyzeOptionValue(city); |
|||
if (thisRowSelectedCityOption.size() == 2) { |
|||
String cityIdStr = thisRowSelectedCityOption.get(1); |
|||
if (NumberUtil.isNumber(cityIdStr)) { |
|||
data.setCityId(Integer.parseInt(cityIdStr)); |
|||
} |
|||
} |
|||
// 本行用户选择的县
|
|||
List<String> thisRowSelectedAreaOption = DropDownOptions.analyzeOptionValue(area); |
|||
if (thisRowSelectedAreaOption.size() == 2) { |
|||
String areaIdStr = thisRowSelectedAreaOption.get(1); |
|||
if (NumberUtil.isNumber(areaIdStr)) { |
|||
data.setAreaId(Integer.parseInt(areaIdStr)); |
|||
} |
|||
} |
|||
|
|||
// 处理完毕以后判断是否符合规则
|
|||
ValidatorUtils.validate(data, EditGroup.class); |
|||
|
|||
// 添加到处理结果中
|
|||
getExcelResult().getList().add(data); |
|||
} |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
package org.dromara.demo.mapper; |
|||
|
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.demo.domain.TestDemoEncrypt; |
|||
|
|||
/** |
|||
* 测试加密功能 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
public interface TestDemoEncryptMapper extends BaseMapperPlus<TestDemoEncrypt, TestDemoEncrypt> { |
|||
|
|||
} |
|||
@ -1,60 +0,0 @@ |
|||
package org.dromara.demo.mapper; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.Wrapper; |
|||
import com.baomidou.mybatisplus.core.metadata.IPage; |
|||
import com.baomidou.mybatisplus.core.toolkit.Constants; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import org.apache.ibatis.annotations.Param; |
|||
import org.dromara.common.mybatis.annotation.DataColumn; |
|||
import org.dromara.common.mybatis.annotation.DataPermission; |
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import org.dromara.demo.domain.vo.TestDemoVo; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 测试单表Mapper接口 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> { |
|||
|
|||
@DataPermission({ |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}) |
|||
Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper); |
|||
|
|||
@Override |
|||
@DataPermission({ |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}) |
|||
List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper); |
|||
|
|||
@Override |
|||
@DataPermission({ |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}) |
|||
List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper); |
|||
|
|||
@Override |
|||
@DataPermission(value = { |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}, joinStr = "AND") |
|||
List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList); |
|||
|
|||
@Override |
|||
@DataPermission({ |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}) |
|||
int updateById(@Param(Constants.ENTITY) TestDemo entity); |
|||
|
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
package org.dromara.demo.mapper; |
|||
|
|||
import org.dromara.common.mybatis.annotation.DataColumn; |
|||
import org.dromara.common.mybatis.annotation.DataPermission; |
|||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; |
|||
import org.dromara.demo.domain.TestTree; |
|||
import org.dromara.demo.domain.vo.TestTreeVo; |
|||
|
|||
/** |
|||
* 测试树表Mapper接口 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@DataPermission({ |
|||
@DataColumn(key = "deptName", value = "dept_id"), |
|||
@DataColumn(key = "userName", value = "user_id") |
|||
}) |
|||
public interface TestTreeMapper extends BaseMapperPlus<TestTree, TestTreeVo> { |
|||
|
|||
} |
|||
@ -1 +0,0 @@ |
|||
package org.dromara.demo.mapper; |
|||
@ -1,18 +0,0 @@ |
|||
package org.dromara.demo.service; |
|||
|
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
|
|||
/** |
|||
* 导出下拉框Excel示例 |
|||
* |
|||
* @author Emil.Zhang |
|||
*/ |
|||
public interface IExportExcelService { |
|||
|
|||
/** |
|||
* 导出下拉框 |
|||
* |
|||
* @param response / |
|||
*/ |
|||
void exportWithOptions(HttpServletResponse response); |
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
package org.dromara.demo.service; |
|||
|
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import org.dromara.demo.domain.bo.TestDemoBo; |
|||
import org.dromara.demo.domain.vo.TestDemoVo; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 测试单表Service接口 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
public interface ITestDemoService { |
|||
|
|||
/** |
|||
* 查询单个 |
|||
* |
|||
* @return |
|||
*/ |
|||
TestDemoVo queryById(Long id); |
|||
|
|||
/** |
|||
* 查询列表 |
|||
*/ |
|||
TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery); |
|||
|
|||
/** |
|||
* 自定义分页查询 |
|||
*/ |
|||
TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery); |
|||
|
|||
/** |
|||
* 查询列表 |
|||
*/ |
|||
List<TestDemoVo> queryList(TestDemoBo bo); |
|||
|
|||
/** |
|||
* 根据新增业务对象插入测试单表 |
|||
* |
|||
* @param bo 测试单表新增业务对象 |
|||
* @return |
|||
*/ |
|||
Boolean insertByBo(TestDemoBo bo); |
|||
|
|||
/** |
|||
* 根据编辑业务对象修改测试单表 |
|||
* |
|||
* @param bo 测试单表编辑业务对象 |
|||
* @return |
|||
*/ |
|||
Boolean updateByBo(TestDemoBo bo); |
|||
|
|||
/** |
|||
* 校验并删除数据 |
|||
* |
|||
* @param ids 主键集合 |
|||
* @param isValid 是否校验,true-删除前校验,false-不校验 |
|||
* @return |
|||
*/ |
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
|
|||
/** |
|||
* 批量保存 |
|||
*/ |
|||
Boolean saveBatch(List<TestDemo> list); |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
package org.dromara.demo.service; |
|||
|
|||
import org.dromara.demo.domain.bo.TestTreeBo; |
|||
import org.dromara.demo.domain.vo.TestTreeVo; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 测试树表Service接口 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
public interface ITestTreeService { |
|||
/** |
|||
* 查询单个 |
|||
* |
|||
* @return |
|||
*/ |
|||
TestTreeVo queryById(Long id); |
|||
|
|||
/** |
|||
* 查询列表 |
|||
*/ |
|||
List<TestTreeVo> queryList(TestTreeBo bo); |
|||
|
|||
/** |
|||
* 根据新增业务对象插入测试树表 |
|||
* |
|||
* @param bo 测试树表新增业务对象 |
|||
* @return |
|||
*/ |
|||
Boolean insertByBo(TestTreeBo bo); |
|||
|
|||
/** |
|||
* 根据编辑业务对象修改测试树表 |
|||
* |
|||
* @param bo 测试树表编辑业务对象 |
|||
* @return |
|||
*/ |
|||
Boolean updateByBo(TestTreeBo bo); |
|||
|
|||
/** |
|||
* 校验并删除数据 |
|||
* |
|||
* @param ids 主键集合 |
|||
* @param isValid 是否校验,true-删除前校验,false-不校验 |
|||
* @return |
|||
*/ |
|||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); |
|||
} |
|||
@ -1,222 +0,0 @@ |
|||
package org.dromara.demo.service.impl; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.core.enums.UserStatus; |
|||
import org.dromara.common.core.utils.StreamUtils; |
|||
import org.dromara.common.excel.core.DropDownOptions; |
|||
import org.dromara.common.excel.utils.ExcelUtil; |
|||
import org.dromara.demo.domain.vo.ExportDemoVo; |
|||
import org.dromara.demo.service.IExportExcelService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* 导出下拉框Excel示例 |
|||
* |
|||
* @author Emil.Zhang |
|||
*/ |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class ExportExcelServiceImpl implements IExportExcelService { |
|||
|
|||
@Override |
|||
public void exportWithOptions(HttpServletResponse response) { |
|||
// 创建表格数据,业务中一般通过数据库查询
|
|||
List<ExportDemoVo> excelDataList = new ArrayList<>(); |
|||
for (int i = 0; i < 3; i++) { |
|||
// 模拟数据库中的一条数据
|
|||
ExportDemoVo everyRowData = new ExportDemoVo(); |
|||
everyRowData.setNickName("用户-" + i); |
|||
everyRowData.setUserStatus(UserStatus.OK.getCode()); |
|||
everyRowData.setGender("1"); |
|||
everyRowData.setPhoneNumber(String.format("175%08d", i)); |
|||
everyRowData.setEmail(String.format("175%08d", i) + "@163.com"); |
|||
everyRowData.setProvinceId(i); |
|||
everyRowData.setCityId(i); |
|||
everyRowData.setAreaId(i); |
|||
excelDataList.add(everyRowData); |
|||
} |
|||
|
|||
// 通过@ExcelIgnoreUnannotated配合@ExcelProperty合理显示需要的列
|
|||
// 并通过@DropDown注解指定下拉值,或者通过创建ExcelOptions来指定下拉框
|
|||
// 使用ExcelOptions时建议指定列index,防止出现下拉列解析不对齐
|
|||
|
|||
// 首先从数据库中查询下拉框内的可选项
|
|||
// 这里模拟查询结果
|
|||
List<DemoCityData> provinceList = getProvinceList(), |
|||
cityList = getCityList(provinceList), |
|||
areaList = getAreaList(cityList); |
|||
int provinceIndex = 5, cityIndex = 6, areaIndex = 7; |
|||
|
|||
DropDownOptions provinceToCity = DropDownOptions.buildLinkedOptions( |
|||
provinceList, |
|||
provinceIndex, |
|||
cityList, |
|||
cityIndex, |
|||
DemoCityData::getId, |
|||
DemoCityData::getPid, |
|||
everyOptions -> DropDownOptions.createOptionValue( |
|||
everyOptions.getName(), |
|||
everyOptions.getId() |
|||
) |
|||
); |
|||
|
|||
DropDownOptions cityToArea = DropDownOptions.buildLinkedOptions( |
|||
cityList, |
|||
cityIndex, |
|||
areaList, |
|||
areaIndex, |
|||
DemoCityData::getId, |
|||
DemoCityData::getPid, |
|||
everyOptions -> DropDownOptions.createOptionValue( |
|||
everyOptions.getName(), |
|||
everyOptions.getId() |
|||
) |
|||
); |
|||
|
|||
// 把所有的下拉框存储
|
|||
List<DropDownOptions> options = new ArrayList<>(); |
|||
options.add(provinceToCity); |
|||
options.add(cityToArea); |
|||
|
|||
// 到此为止所有的下拉框可选项已全部配置完毕
|
|||
|
|||
// 接下来需要将Excel中的展示数据转换为对应的下拉选
|
|||
List<ExportDemoVo> outList = StreamUtils.toList(excelDataList, everyRowData -> { |
|||
// 只需要处理没有使用@ExcelDictFormat注解的下拉框
|
|||
// 一般来说,可以直接在数据库查询即查询出省市县信息,这里通过模拟操作赋值
|
|||
everyRowData.setProvince(buildOptions(provinceList, everyRowData.getProvinceId())); |
|||
everyRowData.setCity(buildOptions(cityList, everyRowData.getCityId())); |
|||
everyRowData.setArea(buildOptions(areaList, everyRowData.getAreaId())); |
|||
return everyRowData; |
|||
}); |
|||
|
|||
ExcelUtil.exportExcel(outList, "下拉框示例", ExportDemoVo.class, response, options); |
|||
} |
|||
|
|||
private String buildOptions(List<DemoCityData> cityDataList, Integer id) { |
|||
Map<Integer, List<DemoCityData>> groupByIdMap = |
|||
cityDataList.stream().collect(Collectors.groupingBy(DemoCityData::getId)); |
|||
if (groupByIdMap.containsKey(id)) { |
|||
DemoCityData demoCityData = groupByIdMap.get(id).get(0); |
|||
return DropDownOptions.createOptionValue(demoCityData.getName(), demoCityData.getId()); |
|||
} else { |
|||
return StrUtil.EMPTY; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 模拟查询数据库操作 |
|||
* |
|||
* @return / |
|||
*/ |
|||
private List<DemoCityData> getProvinceList() { |
|||
List<DemoCityData> provinceList = new ArrayList<>(); |
|||
|
|||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
|||
provinceList.add(new DemoCityData(0, null, "安徽省")); |
|||
provinceList.add(new DemoCityData(1, null, "江苏省")); |
|||
|
|||
return provinceList; |
|||
} |
|||
|
|||
/** |
|||
* 模拟查找数据库操作,需要连带查询出省的数据 |
|||
* |
|||
* @param provinceList 模拟的父省数据 |
|||
* @return / |
|||
*/ |
|||
private List<DemoCityData> getCityList(List<DemoCityData> provinceList) { |
|||
List<DemoCityData> cityList = new ArrayList<>(); |
|||
|
|||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
|||
cityList.add(new DemoCityData(0, 0, "合肥市")); |
|||
cityList.add(new DemoCityData(1, 0, "芜湖市")); |
|||
cityList.add(new DemoCityData(2, 1, "南京市")); |
|||
cityList.add(new DemoCityData(3, 1, "无锡市")); |
|||
cityList.add(new DemoCityData(4, 1, "徐州市")); |
|||
|
|||
selectParentData(provinceList, cityList); |
|||
|
|||
return cityList; |
|||
} |
|||
|
|||
/** |
|||
* 模拟查找数据库操作,需要连带查询出市的数据 |
|||
* |
|||
* @param cityList 模拟的父市数据 |
|||
* @return / |
|||
*/ |
|||
private List<DemoCityData> getAreaList(List<DemoCityData> cityList) { |
|||
List<DemoCityData> areaList = new ArrayList<>(); |
|||
|
|||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
|||
areaList.add(new DemoCityData(0, 0, "瑶海区")); |
|||
areaList.add(new DemoCityData(1, 0, "庐江区")); |
|||
areaList.add(new DemoCityData(2, 1, "南宁县")); |
|||
areaList.add(new DemoCityData(3, 1, "镜湖区")); |
|||
areaList.add(new DemoCityData(4, 2, "玄武区")); |
|||
areaList.add(new DemoCityData(5, 2, "秦淮区")); |
|||
areaList.add(new DemoCityData(6, 3, "宜兴市")); |
|||
areaList.add(new DemoCityData(7, 3, "新吴区")); |
|||
areaList.add(new DemoCityData(8, 4, "鼓楼区")); |
|||
areaList.add(new DemoCityData(9, 4, "丰县")); |
|||
|
|||
selectParentData(cityList, areaList); |
|||
|
|||
return areaList; |
|||
} |
|||
|
|||
/** |
|||
* 模拟数据库的查询父数据操作 |
|||
* |
|||
* @param parentList / |
|||
* @param sonList / |
|||
*/ |
|||
private void selectParentData(List<DemoCityData> parentList, List<DemoCityData> sonList) { |
|||
Map<Integer, List<DemoCityData>> parentGroupByIdMap = |
|||
parentList.stream().collect(Collectors.groupingBy(DemoCityData::getId)); |
|||
|
|||
sonList.forEach(everySon -> { |
|||
if (parentGroupByIdMap.containsKey(everySon.getPid())) { |
|||
everySon.setPData(parentGroupByIdMap.get(everySon.getPid()).get(0)); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 模拟的数据库省市县 |
|||
*/ |
|||
@Data |
|||
private static class DemoCityData { |
|||
/** |
|||
* 数据库id字段 |
|||
*/ |
|||
private Integer id; |
|||
/** |
|||
* 数据库pid字段 |
|||
*/ |
|||
private Integer pid; |
|||
/** |
|||
* 数据库name字段 |
|||
*/ |
|||
private String name; |
|||
/** |
|||
* MyBatisPlus连带查询父数据 |
|||
*/ |
|||
private DemoCityData pData; |
|||
|
|||
public DemoCityData(Integer id, Integer pid, String name) { |
|||
this.id = id; |
|||
this.pid = pid; |
|||
this.name = name; |
|||
} |
|||
} |
|||
} |
|||
@ -1,116 +0,0 @@ |
|||
package org.dromara.demo.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.core.exception.ServiceException; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.demo.domain.TestDemo; |
|||
import org.dromara.demo.domain.bo.TestDemoBo; |
|||
import org.dromara.demo.domain.vo.TestDemoVo; |
|||
import org.dromara.demo.mapper.TestDemoMapper; |
|||
import org.dromara.demo.service.ITestDemoService; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 测试单表Service业务层处理 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class TestDemoServiceImpl implements ITestDemoService { |
|||
|
|||
private final TestDemoMapper baseMapper; |
|||
|
|||
@Override |
|||
public TestDemoVo queryById(Long id) { |
|||
return baseMapper.selectVoById(id); |
|||
} |
|||
|
|||
@Override |
|||
public TableDataInfo<TestDemoVo> queryPageList(TestDemoBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo); |
|||
Page<TestDemoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
/** |
|||
* 自定义分页查询 |
|||
*/ |
|||
@Override |
|||
public TableDataInfo<TestDemoVo> customPageList(TestDemoBo bo, PageQuery pageQuery) { |
|||
LambdaQueryWrapper<TestDemo> lqw = buildQueryWrapper(bo); |
|||
Page<TestDemoVo> result = baseMapper.customPageList(pageQuery.build(), lqw); |
|||
return TableDataInfo.build(result); |
|||
} |
|||
|
|||
@Override |
|||
public List<TestDemoVo> queryList(TestDemoBo bo) { |
|||
return baseMapper.selectVoList(buildQueryWrapper(bo)); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<TestDemo> buildQueryWrapper(TestDemoBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<TestDemo> lqw = Wrappers.lambdaQuery(); |
|||
lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); |
|||
lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); |
|||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, |
|||
TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); |
|||
lqw.orderByAsc(TestDemo::getId); |
|||
return lqw; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean insertByBo(TestDemoBo bo) { |
|||
TestDemo add = MapstructUtils.convert(bo, TestDemo.class); |
|||
validEntityBeforeSave(add); |
|||
boolean flag = baseMapper.insert(add) > 0; |
|||
if (flag) { |
|||
bo.setId(add.getId()); |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateByBo(TestDemoBo bo) { |
|||
TestDemo update = MapstructUtils.convert(bo, TestDemo.class); |
|||
validEntityBeforeSave(update); |
|||
return baseMapper.updateById(update) > 0; |
|||
} |
|||
|
|||
/** |
|||
* 保存前的数据校验 |
|||
* |
|||
* @param entity 实体类数据 |
|||
*/ |
|||
private void validEntityBeforeSave(TestDemo entity) { |
|||
//TODO 做一些数据校验,如唯一约束
|
|||
} |
|||
|
|||
@Override |
|||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
// 做一些业务上的校验,判断是否需要校验
|
|||
List<TestDemo> list = baseMapper.selectByIds(ids); |
|||
if (list.size() != ids.size()) { |
|||
throw new ServiceException("您没有删除权限!"); |
|||
} |
|||
} |
|||
return baseMapper.deleteByIds(ids) > 0; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean saveBatch(List<TestDemo> list) { |
|||
return baseMapper.insertBatch(list); |
|||
} |
|||
} |
|||
@ -1,88 +0,0 @@ |
|||
package org.dromara.demo.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
|||
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|||
import org.dromara.common.core.utils.MapstructUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.dromara.demo.domain.TestTree; |
|||
import org.dromara.demo.domain.bo.TestTreeBo; |
|||
import org.dromara.demo.domain.vo.TestTreeVo; |
|||
import org.dromara.demo.mapper.TestTreeMapper; |
|||
import org.dromara.demo.service.ITestTreeService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 测试树表Service业务层处理 |
|||
* |
|||
* @author Lion Li |
|||
* @date 2021-07-26 |
|||
*/ |
|||
// @DS("slave") // 切换从库查询
|
|||
@RequiredArgsConstructor |
|||
@Service |
|||
public class TestTreeServiceImpl implements ITestTreeService { |
|||
|
|||
private final TestTreeMapper baseMapper; |
|||
|
|||
@Override |
|||
public TestTreeVo queryById(Long id) { |
|||
return baseMapper.selectVoById(id); |
|||
} |
|||
|
|||
// @DS("slave") // 切换从库查询
|
|||
@Override |
|||
public List<TestTreeVo> queryList(TestTreeBo bo) { |
|||
LambdaQueryWrapper<TestTree> lqw = buildQueryWrapper(bo); |
|||
return baseMapper.selectVoList(lqw); |
|||
} |
|||
|
|||
private LambdaQueryWrapper<TestTree> buildQueryWrapper(TestTreeBo bo) { |
|||
Map<String, Object> params = bo.getParams(); |
|||
LambdaQueryWrapper<TestTree> lqw = Wrappers.lambdaQuery(); |
|||
lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); |
|||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, |
|||
TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); |
|||
lqw.orderByAsc(TestTree::getId); |
|||
return lqw; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean insertByBo(TestTreeBo bo) { |
|||
TestTree add = MapstructUtils.convert(bo, TestTree.class); |
|||
validEntityBeforeSave(add); |
|||
boolean flag = baseMapper.insert(add) > 0; |
|||
if (flag) { |
|||
bo.setId(add.getId()); |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
@Override |
|||
public Boolean updateByBo(TestTreeBo bo) { |
|||
TestTree update = MapstructUtils.convert(bo, TestTree.class); |
|||
validEntityBeforeSave(update); |
|||
return baseMapper.updateById(update) > 0; |
|||
} |
|||
|
|||
/** |
|||
* 保存前的数据校验 |
|||
* |
|||
* @param entity 实体类数据 |
|||
*/ |
|||
private void validEntityBeforeSave(TestTree entity) { |
|||
//TODO 做一些数据校验,如唯一约束
|
|||
} |
|||
|
|||
@Override |
|||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { |
|||
if (isValid) { |
|||
//TODO 做一些业务上的校验,判断是否需要校验
|
|||
} |
|||
return baseMapper.deleteByIds(ids) > 0; |
|||
} |
|||
} |
|||
@ -1 +0,0 @@ |
|||
package org.dromara.demo.service.impl; |
|||
@ -1 +0,0 @@ |
|||
package org.dromara.demo.service; |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,11 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!DOCTYPE mapper |
|||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
|||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="org.dromara.demo.mapper.TestDemoMapper"> |
|||
|
|||
<select id="customPageList" resultType="org.dromara.demo.domain.vo.TestDemoVo"> |
|||
SELECT * FROM test_demo ${ew.customSqlSegment} |
|||
</select> |
|||
|
|||
</mapper> |
|||
@ -1,7 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!DOCTYPE mapper |
|||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
|||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
|||
<mapper namespace="org.dromara.demo.mapper.TestTreeMapper"> |
|||
|
|||
</mapper> |
|||
@ -1,3 +0,0 @@ |
|||
java包使用 `.` 分割 resource 目录使用 `/` 分割 |
|||
<br> |
|||
此文件目的 防止文件夹粘连找不到 `xml` 文件 |
|||
@ -1,34 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-modules</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<packaging>jar</packaging> |
|||
<artifactId>ruoyi-job</artifactId> |
|||
|
|||
<description> |
|||
任务调度 |
|||
</description> |
|||
|
|||
<dependencies> |
|||
|
|||
<!-- 通用工具--> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-json</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-job</artifactId> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
|
|||
</project> |
|||
|
|||
@ -1 +0,0 @@ |
|||
package org.dromara.job; |
|||
@ -1,23 +0,0 @@ |
|||
package org.dromara.job.snailjob; |
|||
|
|||
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; |
|||
import com.aizuda.snailjob.client.job.core.dto.JobArgs; |
|||
import com.aizuda.snailjob.client.model.ExecuteResult; |
|||
import com.aizuda.snailjob.common.core.util.JsonUtil; |
|||
import com.aizuda.snailjob.common.log.SnailJobLog; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author opensnail |
|||
* @date 2024-05-17 |
|||
*/ |
|||
@Component |
|||
@JobExecutor(name = "testJobExecutor") |
|||
public class TestAnnoJobExecutor { |
|||
|
|||
public ExecuteResult jobExecute(JobArgs jobArgs) { |
|||
SnailJobLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); |
|||
SnailJobLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); |
|||
return ExecuteResult.success("测试成功"); |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
package org.dromara.job.snailjob; |
|||
|
|||
import com.aizuda.snailjob.client.job.core.dto.JobArgs; |
|||
import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor; |
|||
import com.aizuda.snailjob.client.model.ExecuteResult; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author opensnail |
|||
* @date 2024-05-17 |
|||
*/ |
|||
@Component |
|||
public class TestClassJobExecutor extends AbstractJobExecutor { |
|||
|
|||
@Override |
|||
protected ExecuteResult doJobExecute(JobArgs jobArgs) { |
|||
return ExecuteResult.success("TestJobExecutor测试成功"); |
|||
} |
|||
} |
|||
@ -1,3 +0,0 @@ |
|||
# 工作流说明 |
|||
|
|||
工作流目前在未成熟阶段 后续仍会经历重构 甚至重写(生产使用前请慎重考虑后续是否要更新维护) |
|||
@ -1,119 +0,0 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-modules</artifactId> |
|||
<version>${revision}</version> |
|||
<relativePath>../pom.xml</relativePath> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<packaging>jar</packaging> |
|||
<artifactId>ruoyi-workflow</artifactId> |
|||
|
|||
<description> |
|||
工作流模块 |
|||
</description> |
|||
|
|||
<dependencies> |
|||
|
|||
<!--引入flowable依赖--> |
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-spring-boot-autoconfigure</artifactId> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-spring-security</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-spring-configurator</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-spring-boot-starter-actuator</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- 绘制flowable流程图 --> |
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-image-generator</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- flowable json 转换 --> |
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-json-converter</artifactId> |
|||
<version>6.8.0</version> |
|||
</dependency> |
|||
|
|||
<!-- svg转png图片工具--> |
|||
<dependency> |
|||
<groupId>org.apache.xmlgraphics</groupId> |
|||
<artifactId>batik-all</artifactId> |
|||
<version>1.17</version> |
|||
<exclusions> |
|||
<exclusion> |
|||
<groupId>xalan</groupId> |
|||
<artifactId>xalan</artifactId> |
|||
</exclusion> |
|||
</exclusions> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-websocket</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-mail</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-sms</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-mybatis</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-web</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-log</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-idempotent</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-excel</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-translation</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-tenant</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.dromara</groupId> |
|||
<artifactId>ruoyi-common-security</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
|
|||
</project> |
|||
|
|||
@ -1,137 +0,0 @@ |
|||
package org.dromara.workflow.common.constant; |
|||
|
|||
|
|||
/** |
|||
* 工作流常量 |
|||
* |
|||
* @author may |
|||
*/ |
|||
public interface FlowConstant { |
|||
|
|||
String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人!"; |
|||
|
|||
String MESSAGE_SUSPENDED = "当前任务已挂起不可审批!"; |
|||
|
|||
/** |
|||
* 连线 |
|||
*/ |
|||
String SEQUENCE_FLOW = "sequenceFlow"; |
|||
|
|||
/** |
|||
* 并行网关 |
|||
*/ |
|||
String PARALLEL_GATEWAY = "parallelGateway"; |
|||
|
|||
/** |
|||
* 排它网关 |
|||
*/ |
|||
String EXCLUSIVE_GATEWAY = "exclusiveGateway"; |
|||
|
|||
/** |
|||
* 包含网关 |
|||
*/ |
|||
String INCLUSIVE_GATEWAY = "inclusiveGateway"; |
|||
|
|||
/** |
|||
* 结束节点 |
|||
*/ |
|||
String END_EVENT = "endEvent"; |
|||
|
|||
|
|||
/** |
|||
* 流程委派标识 |
|||
*/ |
|||
String PENDING = "PENDING"; |
|||
|
|||
/** |
|||
* 候选人标识 |
|||
*/ |
|||
String CANDIDATE = "candidate"; |
|||
|
|||
/** |
|||
* 会签任务总数 |
|||
*/ |
|||
String NUMBER_OF_INSTANCES = "nrOfInstances"; |
|||
|
|||
/** |
|||
* 正在执行的会签总数 |
|||
*/ |
|||
String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances"; |
|||
|
|||
/** |
|||
* 已完成的会签任务总数 |
|||
*/ |
|||
String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances"; |
|||
|
|||
/** |
|||
* 循环的索引值,可以使用elementIndexVariable属性修改loopCounter的变量名 |
|||
*/ |
|||
String LOOP_COUNTER = "loopCounter"; |
|||
|
|||
String ZIP = "ZIP"; |
|||
|
|||
/** |
|||
* 业务与流程实例关联对象 |
|||
*/ |
|||
String BUSINESS_INSTANCE_DTO = "businessInstanceDTO"; |
|||
|
|||
/** |
|||
* 流程定义配置 |
|||
*/ |
|||
String WF_DEFINITION_CONFIG_VO = "wfDefinitionConfigVo"; |
|||
|
|||
/** |
|||
* 节点配置 |
|||
*/ |
|||
String WF_NODE_CONFIG_VO = "wfNodeConfigVo"; |
|||
|
|||
/** |
|||
* 流程发起人 |
|||
*/ |
|||
String INITIATOR = "initiator"; |
|||
|
|||
/** |
|||
* 流程实例id |
|||
*/ |
|||
String PROCESS_INSTANCE_ID = "processInstanceId"; |
|||
|
|||
/** |
|||
* 业务id |
|||
*/ |
|||
String BUSINESS_KEY = "businessKey"; |
|||
|
|||
/** |
|||
* 流程定义id |
|||
*/ |
|||
String PROCESS_DEFINITION_ID = "processDefinitionId"; |
|||
|
|||
/** |
|||
* 开启跳过表达式变量 |
|||
*/ |
|||
String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; |
|||
|
|||
/** |
|||
* 模型标识key命名规范正则表达式 |
|||
*/ |
|||
String MODEL_KEY_PATTERN = "^[a-zA-Z][a-zA-Z0-9_]{0,254}$"; |
|||
|
|||
/** |
|||
* 用户任务 |
|||
*/ |
|||
String USER_TASK = "userTask"; |
|||
|
|||
/** |
|||
* 会签 |
|||
*/ |
|||
String MULTI_INSTANCE = "multiInstance"; |
|||
|
|||
/** |
|||
* 是 |
|||
*/ |
|||
String TRUE = "0"; |
|||
|
|||
/** |
|||
* 否 |
|||
*/ |
|||
String FALSE = "1"; |
|||
} |
|||
@ -1,54 +0,0 @@ |
|||
package org.dromara.workflow.common.enums; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
|
|||
import java.util.Arrays; |
|||
|
|||
/** |
|||
* 任务状态枚举 |
|||
* |
|||
* @author may |
|||
*/ |
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum FormTypeEnum { |
|||
/** |
|||
* 自定义表单 |
|||
*/ |
|||
STATIC("static", "自定义表单"), |
|||
/** |
|||
* 动态表单 |
|||
*/ |
|||
DYNAMIC("dynamic", "动态表单"); |
|||
|
|||
/** |
|||
* 类型 |
|||
*/ |
|||
private final String type; |
|||
|
|||
/** |
|||
* 描述 |
|||
*/ |
|||
private final String desc; |
|||
|
|||
/** |
|||
* 表单类型 |
|||
* |
|||
* @param formType 表单类型 |
|||
*/ |
|||
public static String findByType(String formType) { |
|||
if (StringUtils.isBlank(formType)) { |
|||
return StrUtil.EMPTY; |
|||
} |
|||
|
|||
return Arrays.stream(FormTypeEnum.values()) |
|||
.filter(statusEnum -> statusEnum.getType().equals(formType)) |
|||
.findFirst() |
|||
.map(FormTypeEnum::getDesc) |
|||
.orElse(StrUtil.EMPTY); |
|||
} |
|||
} |
|||
|
|||
@ -1,51 +0,0 @@ |
|||
package org.dromara.workflow.common.enums; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
|
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
/** |
|||
* 消息类型枚举 |
|||
* |
|||
* @author may |
|||
*/ |
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum MessageTypeEnum { |
|||
/** |
|||
* 站内信 |
|||
*/ |
|||
SYSTEM_MESSAGE("1", "站内信"), |
|||
/** |
|||
* 邮箱 |
|||
*/ |
|||
EMAIL_MESSAGE("2", "邮箱"), |
|||
/** |
|||
* 短信 |
|||
*/ |
|||
SMS_MESSAGE("3", "短信"); |
|||
|
|||
private final String code; |
|||
|
|||
private final String desc; |
|||
|
|||
private final static Map<String, MessageTypeEnum> MESSAGE_TYPE_ENUM_MAP = new ConcurrentHashMap<>(MessageTypeEnum.values().length); |
|||
|
|||
static { |
|||
for (MessageTypeEnum messageType : MessageTypeEnum.values()) { |
|||
MESSAGE_TYPE_ENUM_MAP.put(messageType.code, messageType); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据消息类型 code 获取 MessageTypeEnum |
|||
* @param code 消息类型code |
|||
* @return MessageTypeEnum |
|||
*/ |
|||
public static MessageTypeEnum getByCode(String code) { |
|||
return MESSAGE_TYPE_ENUM_MAP.get(code); |
|||
} |
|||
} |
|||
|
|||
@ -1,94 +0,0 @@ |
|||
package org.dromara.workflow.common.enums; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
|
|||
import java.util.Arrays; |
|||
|
|||
/** |
|||
* 任务状态枚举 |
|||
* |
|||
* @author may |
|||
*/ |
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum TaskStatusEnum { |
|||
/** |
|||
* 撤销 |
|||
*/ |
|||
CANCEL("cancel", "撤销"), |
|||
/** |
|||
* 通过 |
|||
*/ |
|||
PASS("pass", "通过"), |
|||
/** |
|||
* 待审核 |
|||
*/ |
|||
WAITING("waiting", "待审核"), |
|||
/** |
|||
* 作废 |
|||
*/ |
|||
INVALID("invalid", "作废"), |
|||
/** |
|||
* 退回 |
|||
*/ |
|||
BACK("back", "退回"), |
|||
/** |
|||
* 终止 |
|||
*/ |
|||
TERMINATION("termination", "终止"), |
|||
/** |
|||
* 转办 |
|||
*/ |
|||
TRANSFER("transfer", "转办"), |
|||
/** |
|||
* 委托 |
|||
*/ |
|||
PENDING("pending", "委托"), |
|||
/** |
|||
* 抄送 |
|||
*/ |
|||
COPY("copy", "抄送"), |
|||
/** |
|||
* 加签 |
|||
*/ |
|||
SIGN("sign", "加签"), |
|||
/** |
|||
* 减签 |
|||
*/ |
|||
SIGN_OFF("sign_off", "减签"), |
|||
/** |
|||
* 超时 |
|||
*/ |
|||
TIMEOUT("timeout", "超时"); |
|||
|
|||
/** |
|||
* 状态 |
|||
*/ |
|||
private final String status; |
|||
|
|||
/** |
|||
* 描述 |
|||
*/ |
|||
private final String desc; |
|||
|
|||
/** |
|||
* 任务业务状态 |
|||
* |
|||
* @param status 状态 |
|||
*/ |
|||
public static String findByStatus(String status) { |
|||
if (StringUtils.isBlank(status)) { |
|||
return StrUtil.EMPTY; |
|||
} |
|||
|
|||
return Arrays.stream(TaskStatusEnum.values()) |
|||
.filter(statusEnum -> statusEnum.getStatus().equals(status)) |
|||
.findFirst() |
|||
.map(TaskStatusEnum::getDesc) |
|||
.orElse(StrUtil.EMPTY); |
|||
} |
|||
} |
|||
|
|||
@ -1,148 +0,0 @@ |
|||
package org.dromara.workflow.controller; |
|||
|
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
import jakarta.validation.constraints.NotBlank; |
|||
import jakarta.validation.constraints.NotEmpty; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.core.validate.AddGroup; |
|||
import org.dromara.common.core.validate.EditGroup; |
|||
import org.dromara.common.idempotent.annotation.RepeatSubmit; |
|||
import org.dromara.common.log.annotation.Log; |
|||
import org.dromara.common.log.enums.BusinessType; |
|||
import org.dromara.common.mybatis.core.page.PageQuery; |
|||
import org.dromara.common.mybatis.core.page.TableDataInfo; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.dromara.workflow.domain.bo.ModelBo; |
|||
import org.dromara.workflow.domain.vo.ModelVo; |
|||
import org.dromara.workflow.service.IActModelService; |
|||
import org.flowable.engine.RepositoryService; |
|||
import org.flowable.engine.repository.Model; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 模型管理 控制层 |
|||
* |
|||
* @author may |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/workflow/model") |
|||
public class ActModelController extends BaseController { |
|||
|
|||
@Autowired(required = false) |
|||
private RepositoryService repositoryService; |
|||
private final IActModelService actModelService; |
|||
|
|||
|
|||
/** |
|||
* 分页查询模型 |
|||
* |
|||
* @param modelBo 模型参数 |
|||
*/ |
|||
@GetMapping("/list") |
|||
public TableDataInfo<Model> page(ModelBo modelBo, PageQuery pageQuery) { |
|||
return actModelService.page(modelBo, pageQuery); |
|||
} |
|||
|
|||
/** |
|||
* 新增模型 |
|||
* |
|||
* @param modelBo 模型请求对象 |
|||
*/ |
|||
@Log(title = "模型管理", businessType = BusinessType.INSERT) |
|||
@RepeatSubmit() |
|||
@PostMapping("/save") |
|||
public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) { |
|||
return toAjax(actModelService.saveNewModel(modelBo)); |
|||
} |
|||
|
|||
/** |
|||
* 查询模型 |
|||
* |
|||
* @param id 模型id |
|||
*/ |
|||
@GetMapping("/getInfo/{id}") |
|||
public R<ModelVo> getInfo(@NotBlank(message = "模型id不能为空") @PathVariable String id) { |
|||
return R.ok(actModelService.getInfo(id)); |
|||
} |
|||
|
|||
/** |
|||
* 修改模型信息 |
|||
* |
|||
* @param modelBo 模型数据 |
|||
*/ |
|||
@Log(title = "模型管理", businessType = BusinessType.UPDATE) |
|||
@RepeatSubmit() |
|||
@PutMapping(value = "/update") |
|||
public R<Void> update(@RequestBody ModelBo modelBo) { |
|||
return toAjax(actModelService.update(modelBo)); |
|||
} |
|||
|
|||
/** |
|||
* 编辑XMl模型 |
|||
* |
|||
* @param modelBo 模型数据 |
|||
*/ |
|||
@Log(title = "模型管理", businessType = BusinessType.UPDATE) |
|||
@RepeatSubmit() |
|||
@PutMapping(value = "/editModelXml") |
|||
public R<Void> editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) { |
|||
return toAjax(actModelService.editModelXml(modelBo)); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程模型 |
|||
* |
|||
* @param ids 模型id |
|||
*/ |
|||
@Log(title = "模型管理", businessType = BusinessType.DELETE) |
|||
@RepeatSubmit() |
|||
@DeleteMapping("/{ids}") |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public R<Void> delete(@NotEmpty(message = "主键不能为空") @PathVariable String[] ids) { |
|||
Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel); |
|||
return R.ok(); |
|||
} |
|||
|
|||
/** |
|||
* 模型部署 |
|||
* |
|||
* @param id 模型id |
|||
*/ |
|||
@Log(title = "模型管理", businessType = BusinessType.INSERT) |
|||
@RepeatSubmit() |
|||
@PostMapping("/modelDeploy/{id}") |
|||
public R<Void> deploy(@NotBlank(message = "模型id不能为空") @PathVariable("id") String id) { |
|||
return toAjax(actModelService.modelDeploy(id)); |
|||
} |
|||
|
|||
/** |
|||
* 导出模型zip压缩包 |
|||
* |
|||
* @param modelIds 模型id |
|||
* @param response 相应 |
|||
*/ |
|||
@GetMapping("/export/zip/{modelIds}") |
|||
public void exportZip(@NotEmpty(message = "模型id不能为空") @PathVariable List<String> modelIds, |
|||
HttpServletResponse response) { |
|||
actModelService.exportZip(modelIds, response); |
|||
} |
|||
|
|||
/** |
|||
* 复制模型 |
|||
* |
|||
* @param modelBo 模型数据 |
|||
*/ |
|||
@PostMapping("/copyModel") |
|||
public R<Void> copyModel(@RequestBody ModelBo modelBo) { |
|||
return toAjax(actModelService.copyModel(modelBo)); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue