mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 18:15:56 +08:00
Merge branch 'dev' into future/flowable
This commit is contained in:
commit
db834bfbd0
@ -9,17 +9,16 @@ RUN mkdir -p /ruoyi/server/logs \
|
||||
|
||||
WORKDIR /ruoyi/server
|
||||
|
||||
ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8
|
||||
ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
|
||||
|
||||
EXPOSE ${SERVER_PORT}
|
||||
|
||||
ADD ./target/ruoyi-admin.jar ./app.jar
|
||||
|
||||
ENTRYPOINT ["java", \
|
||||
"-Djava.security.egd=file:/dev/./urandom", \
|
||||
"-Dserver.port=${SERVER_PORT}", \
|
||||
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
|
||||
# "-Dskywalking.agent.service_name=ruoyi-server", \
|
||||
# "-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar", \
|
||||
"-jar", "app.jar",
|
||||
"-XX:+HeapDumpOnOutOfMemoryError", "-Xlog:gc*,:time,tags,level", "-XX:+UseZGC"]
|
||||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
|
||||
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
|
||||
#-Dskywalking.agent.service_name=ruoyi-server \
|
||||
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
|
||||
-jar app.jar \
|
||||
-XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ import org.dromara.common.core.domain.model.LoginBody;
|
||||
import org.dromara.common.core.domain.model.RegisterBody;
|
||||
import org.dromara.common.core.domain.model.SocialLoginBody;
|
||||
import org.dromara.common.core.utils.*;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
|
||||
@ -73,6 +74,7 @@ public class AuthController {
|
||||
* @param body 登录信息
|
||||
* @return 结果
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@PostMapping("/login")
|
||||
public R<LoginVo> login(@Validated @RequestBody String body) {
|
||||
LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
|
||||
@ -163,6 +165,7 @@ public class AuthController {
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@PostMapping("/register")
|
||||
public R<Void> register(@Validated @RequestBody RegisterBody user) {
|
||||
if (!configService.selectRegisterEnabled(user.getTenantId())) {
|
||||
|
||||
@ -171,8 +171,11 @@ api-decrypt:
|
||||
enabled: true
|
||||
# AES 加密头标识
|
||||
headerFlag: encrypt-key
|
||||
# 公私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
|
||||
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
|
||||
# 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
|
||||
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
|
||||
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
|
||||
# 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
|
||||
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
|
||||
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
|
||||
|
||||
springdoc:
|
||||
|
||||
@ -37,6 +37,11 @@
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package org.dromara.common.encrypt.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 强制加密注解
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ApiEncrypt {
|
||||
|
||||
/**
|
||||
* 响应加密忽略,默认不加密,为 true 时加密
|
||||
*/
|
||||
boolean response() default false;
|
||||
|
||||
}
|
||||
@ -3,10 +3,19 @@ package org.dromara.common.encrypt.filter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import jakarta.servlet.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.dromara.common.core.constant.HttpStatus;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.encrypt.properties.ApiDecryptProperties;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -25,8 +34,14 @@ public class CryptoFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
ServletRequest requestWrapper = null;
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) request;
|
||||
HttpServletResponse servletResponse = (HttpServletResponse) response;
|
||||
|
||||
boolean encryptFlag = false;
|
||||
ServletRequest requestWrapper = null;
|
||||
ServletResponse responseWrapper = null;
|
||||
EncryptResponseBodyWrapper responseBodyWrapper = null;
|
||||
|
||||
// 是否为 json 请求
|
||||
if (StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
|
||||
// 是否为 put 或者 post 请求
|
||||
@ -34,16 +49,67 @@ public class CryptoFilter implements Filter {
|
||||
// 是否存在加密标头
|
||||
String headerValue = servletRequest.getHeader(properties.getHeaderFlag());
|
||||
if (StringUtils.isNotBlank(headerValue)) {
|
||||
requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPublicKey(), properties.getPrivateKey(), properties.getHeaderFlag());
|
||||
// 请求解密
|
||||
requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag());
|
||||
// 获取加密注解
|
||||
ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest);
|
||||
if (ObjectUtil.isNotNull(apiEncrypt)) {
|
||||
// 响应加密标志
|
||||
encryptFlag = apiEncrypt.response();
|
||||
} else {
|
||||
// 是否有注解,有就报错,没有放行
|
||||
HandlerExceptionResolver exceptionResolver = SpringUtils.getBean(HandlerExceptionResolver.class);
|
||||
exceptionResolver.resolveException(
|
||||
servletRequest, servletResponse, null,
|
||||
new ServiceException("没有访问权限,请联系管理员授权", HttpStatus.FORBIDDEN));
|
||||
}
|
||||
}
|
||||
// 判断是否响应加密
|
||||
if (encryptFlag) {
|
||||
responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse);
|
||||
responseWrapper = responseBodyWrapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(ObjectUtil.defaultIfNull(requestWrapper, request), response);
|
||||
chain.doFilter(
|
||||
ObjectUtil.defaultIfNull(requestWrapper, request),
|
||||
ObjectUtil.defaultIfNull(responseWrapper, response));
|
||||
|
||||
if (encryptFlag) {
|
||||
servletResponse.reset();
|
||||
// 对原始内容加密
|
||||
String encryptContent = responseBodyWrapper.getEncryptContent(
|
||||
servletResponse, properties.getPublicKey(), properties.getHeaderFlag());
|
||||
// 对加密后的内容写出
|
||||
servletResponse.getWriter().write(encryptContent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ApiEncrypt 注解
|
||||
*/
|
||||
private ApiEncrypt getApiEncryptAnnotation(HttpServletRequest servletRequest) {
|
||||
RequestMappingHandlerMapping handlerMapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
|
||||
// 获取注解
|
||||
try {
|
||||
HandlerExecutionChain mappingHandler = handlerMapping.getHandler(servletRequest);
|
||||
if (ObjectUtil.isNotNull(mappingHandler)) {
|
||||
Object handler = mappingHandler.getHandler();
|
||||
if (ObjectUtil.isNotNull(handler)) {
|
||||
// 从handler获取注解
|
||||
if (handler instanceof HandlerMethod handlerMethod) {
|
||||
return handlerMethod.getMethodAnnotation(ApiEncrypt.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper {
|
||||
|
||||
private final byte[] body;
|
||||
|
||||
public DecryptRequestBodyWrapper(HttpServletRequest request, String publicKey, String privateKey, String headerFlag) throws IOException {
|
||||
public DecryptRequestBodyWrapper(HttpServletRequest request, String privateKey, String headerFlag) throws IOException {
|
||||
super(request);
|
||||
// 获取 AES 密码 采用 RSA 加密
|
||||
String headerRsa = request.getHeader(headerFlag);
|
||||
|
||||
@ -0,0 +1,120 @@
|
||||
package org.dromara.common.encrypt.filter;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import jakarta.servlet.WriteListener;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponseWrapper;
|
||||
import org.dromara.common.encrypt.utils.EncryptUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 加密响应参数包装类
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
public class EncryptResponseBodyWrapper extends HttpServletResponseWrapper {
|
||||
|
||||
private final ByteArrayOutputStream byteArrayOutputStream;
|
||||
private final ServletOutputStream servletOutputStream;
|
||||
private final PrintWriter printWriter;
|
||||
|
||||
public EncryptResponseBodyWrapper(HttpServletResponse response) throws IOException {
|
||||
super(response);
|
||||
this.byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
this.servletOutputStream = this.getOutputStream();
|
||||
this.printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getWriter() {
|
||||
return printWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBuffer() throws IOException {
|
||||
if (servletOutputStream != null) {
|
||||
servletOutputStream.flush();
|
||||
}
|
||||
if (printWriter != null) {
|
||||
printWriter.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
byteArrayOutputStream.reset();
|
||||
}
|
||||
|
||||
public byte[] getResponseData() throws IOException {
|
||||
flushBuffer();
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
public String getContent() throws IOException {
|
||||
flushBuffer();
|
||||
return byteArrayOutputStream.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取加密内容
|
||||
*
|
||||
* @param servletResponse response
|
||||
* @param publicKey RSA公钥 (用于加密 AES 秘钥)
|
||||
* @param headerFlag 请求头标志
|
||||
* @return 加密内容
|
||||
* @throws IOException
|
||||
*/
|
||||
public String getEncryptContent(HttpServletResponse servletResponse, String publicKey, String headerFlag) throws IOException {
|
||||
// 生成秘钥
|
||||
String aesPassword = RandomUtil.randomString(32);
|
||||
// 秘钥使用 Base64 编码
|
||||
String encryptAes = EncryptUtils.encryptByBase64(aesPassword);
|
||||
// Rsa 公钥加密 Base64 编码
|
||||
String encryptPassword = EncryptUtils.encryptByRsa(encryptAes, publicKey);
|
||||
|
||||
// 设置响应头
|
||||
servletResponse.setHeader(headerFlag, encryptPassword);
|
||||
servletResponse.setHeader("Access-Control-Allow-Origin", "*");
|
||||
servletResponse.setHeader("Access-Control-Allow-Methods", "*");
|
||||
servletResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString());
|
||||
|
||||
// 获取原始内容
|
||||
String originalBody = this.getContent();
|
||||
// 对内容进行加密
|
||||
return EncryptUtils.encryptByAes(originalBody, aesPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() throws IOException {
|
||||
return new ServletOutputStream() {
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener writeListener) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
byteArrayOutputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
byteArrayOutputStream.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
byteArrayOutputStream.write(b, off, len);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -21,14 +21,14 @@ public class ApiDecryptProperties {
|
||||
*/
|
||||
private String headerFlag;
|
||||
|
||||
|
||||
/**
|
||||
* 公钥
|
||||
* 响应加密公钥
|
||||
*/
|
||||
private String publicKey;
|
||||
|
||||
/**
|
||||
* 私钥
|
||||
* 请求解密私钥
|
||||
*/
|
||||
private String privateKey;
|
||||
|
||||
}
|
||||
|
||||
@ -269,6 +269,26 @@ public class ExcelUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多sheet模板导出 模板格式为 {key.属性}
|
||||
*
|
||||
* @param filename 文件名
|
||||
* @param templatePath 模板路径 resource 目录下的路径包括模板文件名
|
||||
* 例如: excel/temp.xlsx
|
||||
* 重点: 模板文件必须放置到启动类对应的 resource 目录下
|
||||
* @param data 模板需要的数据
|
||||
* @param response 响应体
|
||||
*/
|
||||
public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String filename, String templatePath, HttpServletResponse response) {
|
||||
try {
|
||||
resetResponse(filename, response);
|
||||
ServletOutputStream os = response.getOutputStream();
|
||||
exportTemplateMultiSheet(data, templatePath, os);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("导出Excel异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 多表多数据模板导出 模板格式为 {key.属性}
|
||||
*
|
||||
@ -303,6 +323,42 @@ public class ExcelUtil {
|
||||
excelWriter.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多sheet模板导出 模板格式为 {key.属性}
|
||||
*
|
||||
* @param templatePath 模板路径 resource 目录下的路径包括模板文件名
|
||||
* 例如: excel/temp.xlsx
|
||||
* 重点: 模板文件必须放置到启动类对应的 resource 目录下
|
||||
* @param data 模板需要的数据
|
||||
* @param os 输出流
|
||||
*/
|
||||
public static void exportTemplateMultiSheet(List<Map<String, Object>> data, String templatePath, OutputStream os) {
|
||||
ClassPathResource templateResource = new ClassPathResource(templatePath);
|
||||
ExcelWriter excelWriter = EasyExcel.write(os)
|
||||
.withTemplate(templateResource.getStream())
|
||||
.autoCloseStream(false)
|
||||
// 大数值自动转换 防止失真
|
||||
.registerConverter(new ExcelBigNumberConvert())
|
||||
.build();
|
||||
if (CollUtil.isEmpty(data)) {
|
||||
throw new IllegalArgumentException("数据为空");
|
||||
}
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
WriteSheet writeSheet = EasyExcel.writerSheet(i).build();
|
||||
for (Map.Entry<String, Object> map : data.get(i).entrySet()) {
|
||||
// 设置列表后续还有数据
|
||||
FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
|
||||
if (map.getValue() instanceof Collection) {
|
||||
// 多表导出必须使用 FillWrapper
|
||||
excelWriter.fill(new FillWrapper(map.getKey(), (Collection<?>) map.getValue()), fillConfig, writeSheet);
|
||||
} else {
|
||||
excelWriter.fill(map.getValue(), writeSheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
excelWriter.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置响应体
|
||||
*/
|
||||
|
||||
@ -39,7 +39,7 @@ public class OssFactory {
|
||||
/**
|
||||
* 根据类型获取实例
|
||||
*/
|
||||
public static OssClient instance(String configKey) {
|
||||
public static synchronized OssClient instance(String configKey) {
|
||||
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
|
||||
if (json == null) {
|
||||
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
|
||||
|
||||
@ -10,7 +10,6 @@ import org.dromara.common.satoken.core.service.SaPermissionImpl;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* sa-token 配置
|
||||
@ -19,7 +18,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
|
||||
public class SaTokenConfig implements WebMvcConfigurer {
|
||||
public class SaTokenConfig {
|
||||
|
||||
@Bean
|
||||
public StpLogic getStpLogicJwt() {
|
||||
|
||||
@ -98,7 +98,7 @@ public class WebSocketUtils {
|
||||
|
||||
private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
|
||||
if (session == null || !session.isOpen()) {
|
||||
log.error("[send] session会话已经关闭");
|
||||
log.warn("[send] session会话已经关闭");
|
||||
} else {
|
||||
try {
|
||||
session.sendMessage(message);
|
||||
|
||||
@ -7,11 +7,11 @@ RUN mkdir -p /ruoyi/monitor/logs
|
||||
|
||||
WORKDIR /ruoyi/monitor
|
||||
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
|
||||
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", "-jar", "app.jar",
|
||||
"-XX:+HeapDumpOnOutOfMemoryError", "-Xlog:gc*,:time,tags,level", "-XX:+UseZGC"]
|
||||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar app.jar \
|
||||
-XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
|
||||
|
||||
@ -7,11 +7,11 @@ RUN mkdir -p /ruoyi/powerjob/logs
|
||||
|
||||
WORKDIR /ruoyi/powerjob
|
||||
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
|
||||
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="-Xms512m -Xmx1024m"
|
||||
|
||||
EXPOSE 7700
|
||||
|
||||
ADD ./target/ruoyi-powerjob-server.jar ./app.jar
|
||||
|
||||
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar",
|
||||
"-XX:+HeapDumpOnOutOfMemoryError", "-Xlog:gc*,:time,tags,level", "-XX:+UseZGC"]
|
||||
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar app.jar \
|
||||
-XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
|
||||
|
||||
@ -94,6 +94,41 @@ public class TestExcelController {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入表格
|
||||
*/
|
||||
|
||||
BIN
ruoyi-modules/ruoyi-demo/src/main/resources/excel/多sheet列表.xlsx
Normal file
BIN
ruoyi-modules/ruoyi-demo/src/main/resources/excel/多sheet列表.xlsx
Normal file
Binary file not shown.
@ -6,6 +6,7 @@ import cn.hutool.core.io.FileUtil;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.file.MimeTypeUtils;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
@ -79,6 +80,7 @@ public class SysProfileController extends BaseController {
|
||||
*
|
||||
* @param bo 新旧密码
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updatePwd")
|
||||
public R<Void> updatePwd(@Validated @RequestBody SysUserPasswordBo bo) {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package org.dromara.system.controller.system;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
@ -9,7 +8,6 @@ import org.dromara.system.domain.vo.SysSocialVo;
|
||||
import org.dromara.system.service.ISysSocialService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@ -37,16 +35,4 @@ public class SysSocialController extends BaseController {
|
||||
return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取社会化关系详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public R<SysSocialVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable String id) {
|
||||
return R.ok(socialUserService.queryById(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
@ -13,6 +12,7 @@ import org.dromara.common.core.constant.TenantConstants;
|
||||
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.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
@ -25,14 +25,7 @@ import org.dromara.system.domain.bo.SysTenantBo;
|
||||
import org.dromara.system.domain.vo.SysTenantVo;
|
||||
import org.dromara.system.service.ISysTenantService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -87,6 +80,7 @@ public class SysTenantController extends BaseController {
|
||||
/**
|
||||
* 新增租户
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
|
||||
@SaCheckPermission("system:tenant:add")
|
||||
@Log(title = "租户", businessType = BusinessType.INSERT)
|
||||
|
||||
@ -14,6 +14,7 @@ import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.encrypt.annotation.ApiEncrypt;
|
||||
import org.dromara.common.excel.core.ExcelResult;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
@ -209,6 +210,7 @@ public class SysUserController extends BaseController {
|
||||
/**
|
||||
* 重置密码
|
||||
*/
|
||||
@ApiEncrypt
|
||||
@SaCheckPermission("system:user:resetPwd")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
|
||||
@ -108,7 +108,7 @@ http {
|
||||
}
|
||||
|
||||
# 解决 powerjob 代理之后静态文件无法访问的问题 请勿修改乱动
|
||||
location .*\.(js|css|jpg|png|svg|woff|ttf|ico)?$ {
|
||||
location ~ ^/(js|css|jpg|png|svg|woff|ttf|ico|img)/ {
|
||||
proxy_pass http://powerjob-server;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user