mirror of
https://gitee.com/y_project/RuoYi-Cloud.git
synced 2026-01-27 04:01:56 +08:00
Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af1b557bc8 | ||
|
|
e6c3bd1ce5 | ||
|
|
046d25f35d | ||
|
|
d20d4ffa16 | ||
|
|
76f2273d0b | ||
|
|
dda78c95b7 | ||
|
|
ebbeb047be | ||
|
|
ebd7fd59d0 | ||
|
|
c20c2c221f | ||
|
|
ee33dbdc0e | ||
|
|
5d8d4fa530 | ||
|
|
2021028cad | ||
|
|
7fcb1b2e0a | ||
|
|
f4a2f909a7 | ||
|
|
328630fe5d | ||
|
|
f7ae7e29d1 | ||
|
|
e46ea3ebac | ||
|
|
d565fa4883 | ||
|
|
a627108dfe | ||
|
|
829451f05e | ||
|
|
cae41a8da2 | ||
|
|
a4099cf645 | ||
|
|
0a104689ed | ||
|
|
97d0226c78 | ||
|
|
3a04dda55d | ||
|
|
94310c4f3d | ||
|
|
39e7d8a84b | ||
|
|
e1037ac125 | ||
|
|
a10384c009 | ||
|
|
ab8215d1ce | ||
|
|
524982c7bd | ||
|
|
d6188aa009 | ||
|
|
7e8b08a58c | ||
|
|
14771f0ab4 | ||
|
|
97c0603269 | ||
|
|
a58c430858 | ||
|
|
cd4119b26a | ||
|
|
ea20fa3ce2 | ||
|
|
3b54208ac9 | ||
|
|
d2de744c3f | ||
|
|
655249d67a | ||
|
|
80a890549d | ||
|
|
5da1979ce6 | ||
|
|
642512aa91 | ||
|
|
4a32a8e725 | ||
|
|
bb30ae7086 | ||
|
|
34a6f2e1f1 | ||
|
|
0e51d1e7b1 | ||
|
|
40bdf7b100 | ||
|
|
57f51249b6 | ||
|
|
dcc5dc0d16 | ||
|
|
e87a818706 | ||
|
|
67df97d5a7 | ||
|
|
3f8fd0a0f8 | ||
|
|
961fe9a5f1 | ||
|
|
22f156bbb7 | ||
|
|
22c22c4246 | ||
|
|
994cd62c7a | ||
|
|
1e4ed04a65 | ||
|
|
139b25639e | ||
|
|
13800738cb | ||
|
|
98c538c9e3 | ||
|
|
0e7c45173c | ||
|
|
132b23dc33 | ||
|
|
c3f1dd846c | ||
|
|
7b7abde756 | ||
|
|
aeeb0eb26b | ||
|
|
265a181891 | ||
|
|
22663e1b43 | ||
|
|
24be1a436e | ||
|
|
370c53edfa | ||
|
|
f112133ddf | ||
|
|
93ee021b6e | ||
|
|
e57d2ea17c | ||
|
|
ea038a5437 | ||
|
|
329aa68644 | ||
|
|
887430874d | ||
|
|
52f8693e1d | ||
|
|
8057dcc4fc | ||
|
|
66e0f9a53d | ||
|
|
7a35c474d6 | ||
|
|
892065003d | ||
|
|
ede8353503 | ||
|
|
60796ca8fb | ||
|
|
25e9112ccc | ||
|
|
f6c5c91eb1 | ||
|
|
740da06972 | ||
|
|
2a363f9c17 | ||
|
|
3c649a8814 | ||
|
|
a144bf2bff | ||
|
|
83ee4223be | ||
|
|
8f6c864e96 | ||
|
|
12209ae5a4 | ||
|
|
4e0301a7b2 | ||
|
|
00fa1c3158 | ||
|
|
04edd66199 | ||
|
|
d8896c9054 | ||
|
|
dd70c1950e | ||
|
|
954d208ac6 | ||
|
|
98d25fa16e | ||
|
|
3af7af265b | ||
|
|
436c2154ad | ||
|
|
42e8baa85c | ||
|
|
0dff71bd4d | ||
|
|
20ce9da509 | ||
|
|
a044b0d205 | ||
|
|
698200ecc2 | ||
|
|
883d89ee0b | ||
|
|
fb9a480f3c | ||
|
|
e288710251 | ||
|
|
1019aa58ce | ||
|
|
e9621469b2 | ||
|
|
57c4910605 | ||
|
|
9920957796 | ||
|
|
e798f46876 | ||
|
|
caa7537607 | ||
|
|
8b23c97fdb | ||
|
|
af49ad54f6 | ||
|
|
816479e092 | ||
|
|
7e72849d05 | ||
|
|
99206a5d65 | ||
|
|
114c9f3af6 | ||
|
|
e14fb70c26 | ||
|
|
201149a131 | ||
|
|
2bc80c4c07 | ||
|
|
ee7607bcca | ||
|
|
7e2dbc5608 | ||
|
|
8eac239e48 | ||
|
|
6650397e38 | ||
|
|
1ca4c26d81 | ||
|
|
0b0da91139 | ||
|
|
3d47ec2e73 | ||
|
|
1f21102204 | ||
|
|
58b4600144 | ||
|
|
6146d63f2c | ||
|
|
dbf42739ca | ||
|
|
57f56c2769 | ||
|
|
5c130cfda6 | ||
|
|
df284ff6f5 | ||
|
|
1b7550f9a2 | ||
|
|
195df24b4b | ||
|
|
68de85aa5f | ||
|
|
8b6784d8e2 | ||
|
|
b73c14400c | ||
|
|
54922af7db | ||
|
|
23944b2f9c | ||
|
|
9d0240b831 | ||
|
|
1aef90d506 | ||
|
|
41b7e62b02 |
@@ -115,4 +115,4 @@ com.ruoyi
|
||||
|
||||
## 若依微服务交流群
|
||||
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=yqInfq0S) [](https://jq.qq.com/?_wv=1027&k=Oy1mb3p8) [](https://jq.qq.com/?_wv=1027&k=rvxkJtXK) [](https://jq.qq.com/?_wv=1027&k=0Ck3PvTe) 点击按钮入群。
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=yqInfq0S) [](https://jq.qq.com/?_wv=1027&k=Oy1mb3p8) [](https://jq.qq.com/?_wv=1027&k=rvxkJtXK) [](https://jq.qq.com/?_wv=1027&k=0Ck3PvTe) [](https://jq.qq.com/?_wv=1027&k=FnHHP4TT) 点击按钮入群。
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 清理生成路径。
|
||||
echo [信息] 清理工程target生成路径。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行auth工程。
|
||||
echo [信息] 使用Jar命令运行Auth工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行gateway工程。
|
||||
echo [信息] 使用Jar命令运行Gateway工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行modules-file工程。
|
||||
echo [信息] 使用Jar命令运行Modules-File工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行modules-gen工程。
|
||||
echo [信息] 使用Jar命令运行Modules-Gen工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行modules-job工程。
|
||||
echo [信息] 使用Jar命令运行Modules-Job工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行modules-system工程。
|
||||
echo [信息] 使用Jar命令运行Modules-System工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 运行monitor工程。
|
||||
echo [信息] 使用Jar命令运行Monitor工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
|
||||
76
pom.xml
76
pom.xml
@@ -6,37 +6,37 @@
|
||||
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
|
||||
<name>ruoyi</name>
|
||||
<url>http://www.ruoyi.vip</url>
|
||||
<description>若依微服务系统</description>
|
||||
|
||||
<properties>
|
||||
<ruoyi.version>3.0.0</ruoyi.version>
|
||||
<ruoyi.version>3.2.0</ruoyi.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-boot.version>2.5.0</spring-boot.version>
|
||||
<spring-cloud.version>2020.0.3</spring-cloud.version>
|
||||
<spring-boot.version>2.5.5</spring-boot.version>
|
||||
<spring-cloud.version>2020.0.4</spring-cloud.version>
|
||||
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
|
||||
<alibaba.nacos.version>2.0.1</alibaba.nacos.version>
|
||||
<spring-boot-admin.version>2.4.1</spring-boot-admin.version>
|
||||
<spring-boot.mybatis>2.1.4</spring-boot.mybatis>
|
||||
<alibaba.nacos.version>2.0.3</alibaba.nacos.version>
|
||||
<spring-boot-admin.version>2.5.2</spring-boot-admin.version>
|
||||
<spring-boot.mybatis>2.2.0</spring-boot.mybatis>
|
||||
<swagger.fox.version>3.0.0</swagger.fox.version>
|
||||
<swagger.core.version>1.6.2</swagger.core.version>
|
||||
<tobato.version>1.26.5</tobato.version>
|
||||
<tobato.version>1.27.2</tobato.version>
|
||||
<kaptcha.version>2.3.2</kaptcha.version>
|
||||
<pagehelper.boot.version>1.3.0</pagehelper.boot.version>
|
||||
<druid.version>1.2.6</druid.version>
|
||||
<dynamic-ds.version>3.3.2</dynamic-ds.version>
|
||||
<commons.io.version>2.5</commons.io.version>
|
||||
<commons.fileupload.version>1.3.3</commons.fileupload.version>
|
||||
<pagehelper.boot.version>1.4.0</pagehelper.boot.version>
|
||||
<druid.version>1.2.8</druid.version>
|
||||
<dynamic-ds.version>3.4.1</dynamic-ds.version>
|
||||
<commons.io.version>2.11.0</commons.io.version>
|
||||
<commons.fileupload.version>1.4</commons.fileupload.version>
|
||||
<velocity.version>1.7</velocity.version>
|
||||
<fastjson.version>1.2.76</fastjson.version>
|
||||
<minio.version>8.2.1</minio.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<common-pool.version>2.6.2</common-pool.version>
|
||||
<fastjson.version>1.2.78</fastjson.version>
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<common-pool.version>2.10.0</common-pool.version>
|
||||
<commons-collections.version>3.2.2</commons-collections.version>
|
||||
</properties>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba 微服务 -->
|
||||
<!-- SpringCloud Alibaba 微服务 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
@@ -77,28 +77,28 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- SpringBoot 监控客户端 -->
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- FastDFS 分布式文件系统 -->
|
||||
<dependency>
|
||||
<groupId>com.github.tobato</groupId>
|
||||
<artifactId>fastdfs-client</artifactId>
|
||||
<version>${tobato.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Mybatis 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${spring-boot.mybatis}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Swagger 依赖配置 -->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
@@ -172,7 +172,7 @@
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 公共资源池 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -181,71 +181,71 @@
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 接口模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-swagger</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 安全模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 权限范围 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datascope</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 多数据源 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-datasource</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 日志记录 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 缓存服务 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common-redis</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- 系统接口 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-api-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-auth</module>
|
||||
<module>ruoyi-gateway</module>
|
||||
<module>ruoyi-visual</module>
|
||||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-api</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-auth</module>
|
||||
<module>ruoyi-gateway</module>
|
||||
<module>ruoyi-visual</module>
|
||||
<module>ruoyi-modules</module>
|
||||
<module>ruoyi-api</module>
|
||||
<module>ruoyi-common</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@ package com.ruoyi.system.api;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.ServiceNameConstants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.api.domain.SysLogininfor;
|
||||
import com.ruoyi.system.api.domain.SysOperLog;
|
||||
import com.ruoyi.system.api.factory.RemoteLogFallbackFactory;
|
||||
|
||||
@@ -21,20 +23,19 @@ public interface RemoteLogService
|
||||
* 保存系统日志
|
||||
*
|
||||
* @param sysOperLog 日志实体
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/operlog")
|
||||
R<Boolean> saveLog(@RequestBody SysOperLog sysOperLog);
|
||||
public R<Boolean> saveLog(@RequestBody SysOperLog sysOperLog, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 保存访问记录
|
||||
*
|
||||
* @param username 用户名称
|
||||
* @param status 状态
|
||||
* @param message 消息
|
||||
* @param sysLogininfor 访问实体
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/logininfor")
|
||||
R<Boolean> saveLogininfor(@RequestParam("username") String username, @RequestParam("status") String status,
|
||||
@RequestParam("message") String message);
|
||||
public R<Boolean> saveLogininfor(@RequestBody SysLogininfor sysLogininfor, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,13 @@ package com.ruoyi.system.api;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.ServiceNameConstants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
import com.ruoyi.system.api.factory.RemoteUserFallbackFactory;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
|
||||
@@ -20,8 +25,19 @@ public interface RemoteUserService
|
||||
* 通过用户名查询用户信息
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@GetMapping(value = "/user/info/{username}")
|
||||
public R<LoginUser> getUserInfo(@PathVariable("username") String username);
|
||||
@GetMapping("/user/info/{username}")
|
||||
public R<LoginUser> getUserInfo(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
|
||||
/**
|
||||
* 注册用户信息
|
||||
*
|
||||
* @param sysUser 用户信息
|
||||
* @param source 请求来源
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/user/register")
|
||||
public R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ruoyi.system.domain;
|
||||
package com.ruoyi.system.api.domain;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ruoyi.system.domain;
|
||||
package com.ruoyi.system.api.domain;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ruoyi.system.domain;
|
||||
package com.ruoyi.system.api.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
@@ -203,7 +203,8 @@ public class SysRole extends BaseEntity
|
||||
{
|
||||
this.deptIds = deptIds;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("roleId", getRoleId())
|
||||
|
||||
@@ -57,9 +57,6 @@ public class SysUser extends BaseEntity
|
||||
/** 密码 */
|
||||
private String password;
|
||||
|
||||
/** 盐加密 */
|
||||
private String salt;
|
||||
|
||||
/** 帐号状态(0正常 1停用) */
|
||||
@Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
|
||||
private String status;
|
||||
@@ -91,6 +88,9 @@ public class SysUser extends BaseEntity
|
||||
/** 岗位组 */
|
||||
private Long[] postIds;
|
||||
|
||||
/** 角色ID */
|
||||
private Long roleId;
|
||||
|
||||
public SysUser()
|
||||
{
|
||||
|
||||
@@ -208,16 +208,6 @@ public class SysUser extends BaseEntity
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getSalt()
|
||||
{
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(String salt)
|
||||
{
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public String getStatus()
|
||||
{
|
||||
return status;
|
||||
@@ -297,7 +287,16 @@ public class SysUser extends BaseEntity
|
||||
{
|
||||
this.postIds = postIds;
|
||||
}
|
||||
|
||||
|
||||
public Long getRoleId()
|
||||
{
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(Long roleId)
|
||||
{
|
||||
this.roleId = roleId;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
@@ -310,7 +309,6 @@ public class SysUser extends BaseEntity
|
||||
.append("sex", getSex())
|
||||
.append("avatar", getAvatar())
|
||||
.append("password", getPassword())
|
||||
.append("salt", getSalt())
|
||||
.append("status", getStatus())
|
||||
.append("delFlag", getDelFlag())
|
||||
.append("loginIp", getLoginIp())
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.api.RemoteLogService;
|
||||
import com.ruoyi.system.api.domain.SysLogininfor;
|
||||
import com.ruoyi.system.api.domain.SysOperLog;
|
||||
|
||||
/**
|
||||
@@ -25,13 +26,13 @@ public class RemoteLogFallbackFactory implements FallbackFactory<RemoteLogServic
|
||||
return new RemoteLogService()
|
||||
{
|
||||
@Override
|
||||
public R<Boolean> saveLog(SysOperLog sysOperLog)
|
||||
public R<Boolean> saveLog(SysOperLog sysOperLog, String source)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> saveLogininfor(String username, String status, String message)
|
||||
public R<Boolean> saveLogininfor(SysLogininfor sysLogininfor, String source)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.system.api.RemoteUserService;
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
|
||||
/**
|
||||
@@ -25,10 +26,16 @@ public class RemoteUserFallbackFactory implements FallbackFactory<RemoteUserServ
|
||||
return new RemoteUserService()
|
||||
{
|
||||
@Override
|
||||
public R<LoginUser> getUserInfo(String username)
|
||||
public R<LoginUser> getUserInfo(String username, String source)
|
||||
{
|
||||
return R.fail("获取用户失败:" + throwable.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<Boolean> registerUserInfo(SysUser sysUser, String source)
|
||||
{
|
||||
return R.fail("注册用户失败:" + throwable.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.auth.form.LoginBody;
|
||||
import com.ruoyi.auth.form.RegisterBody;
|
||||
import com.ruoyi.auth.service.SysLoginService;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
@@ -63,4 +64,12 @@ public class TokenController
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@PostMapping("register")
|
||||
public R<?> register(@RequestBody RegisterBody registerBody)
|
||||
{
|
||||
// 用户注册
|
||||
sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.ruoyi.auth.form;
|
||||
|
||||
/**
|
||||
* 用户注册对象
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class RegisterBody extends LoginBody
|
||||
{
|
||||
|
||||
}
|
||||
@@ -3,14 +3,18 @@ package com.ruoyi.auth.service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.constant.UserConstants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.enums.UserStatus;
|
||||
import com.ruoyi.common.core.exception.BaseException;
|
||||
import com.ruoyi.common.core.exception.ServiceException;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.ip.IpUtils;
|
||||
import com.ruoyi.system.api.RemoteLogService;
|
||||
import com.ruoyi.system.api.RemoteUserService;
|
||||
import com.ruoyi.system.api.domain.SysLogininfor;
|
||||
import com.ruoyi.system.api.domain.SysUser;
|
||||
import com.ruoyi.system.api.model.LoginUser;
|
||||
|
||||
@@ -36,60 +40,120 @@ public class SysLoginService
|
||||
// 用户名或密码为空 错误
|
||||
if (StringUtils.isAnyBlank(username, password))
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
|
||||
throw new BaseException("用户/密码必须填写");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "用户/密码必须填写");
|
||||
throw new ServiceException("用户/密码必须填写");
|
||||
}
|
||||
// 密码如果不在指定范围内 错误
|
||||
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
|
||||
throw new BaseException("用户密码不在指定范围");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码不在指定范围");
|
||||
throw new ServiceException("用户密码不在指定范围");
|
||||
}
|
||||
// 用户名不在指定范围内 错误
|
||||
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|
||||
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
|
||||
throw new BaseException("用户名不在指定范围");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "用户名不在指定范围");
|
||||
throw new ServiceException("用户名不在指定范围");
|
||||
}
|
||||
// 查询用户信息
|
||||
R<LoginUser> userResult = remoteUserService.getUserInfo(username);
|
||||
R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
|
||||
|
||||
if (R.FAIL == userResult.getCode())
|
||||
{
|
||||
throw new BaseException(userResult.getMsg());
|
||||
throw new ServiceException(userResult.getMsg());
|
||||
}
|
||||
|
||||
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
|
||||
throw new BaseException("登录用户:" + username + " 不存在");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
|
||||
throw new ServiceException("登录用户:" + username + " 不存在");
|
||||
}
|
||||
LoginUser userInfo = userResult.getData();
|
||||
SysUser user = userResult.getData().getSysUser();
|
||||
if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除");
|
||||
|
||||
throw new BaseException("对不起,您的账号:" + username + " 已被删除");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "对不起,您的账号已被删除");
|
||||
throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
|
||||
}
|
||||
if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员");
|
||||
throw new BaseException("对不起,您的账号:" + username + " 已停用");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "用户已停用,请联系管理员");
|
||||
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
|
||||
}
|
||||
if (!SecurityUtils.matchesPassword(password, user.getPassword()))
|
||||
{
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_FAIL, "用户密码错误");
|
||||
throw new BaseException("用户不存在/密码错误");
|
||||
recordLogininfor(username, Constants.LOGIN_FAIL, "用户密码错误");
|
||||
throw new ServiceException("用户不存在/密码错误");
|
||||
}
|
||||
remoteLogService.saveLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
|
||||
recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功");
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public void logout(String loginName)
|
||||
{
|
||||
remoteLogService.saveLogininfor(loginName, Constants.LOGOUT, "退出成功");
|
||||
recordLogininfor(loginName, Constants.LOGOUT, "退出成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
public void register(String username, String password)
|
||||
{
|
||||
// 用户名或密码为空 错误
|
||||
if (StringUtils.isAnyBlank(username, password))
|
||||
{
|
||||
throw new ServiceException("用户/密码必须填写");
|
||||
}
|
||||
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|
||||
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
|
||||
{
|
||||
throw new ServiceException("账户长度必须在2到20个字符之间");
|
||||
}
|
||||
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||
{
|
||||
throw new ServiceException("密码长度必须在5到20个字符之间");
|
||||
}
|
||||
|
||||
// 注册用户信息
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserName(username);
|
||||
sysUser.setNickName(username);
|
||||
sysUser.setPassword(SecurityUtils.encryptPassword(password));
|
||||
R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);
|
||||
|
||||
if (R.FAIL == registerResult.getCode())
|
||||
{
|
||||
throw new ServiceException(registerResult.getMsg());
|
||||
}
|
||||
recordLogininfor(username, Constants.REGISTER, "注册成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录登录信息
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param status 状态
|
||||
* @param message 消息内容
|
||||
* @return
|
||||
*/
|
||||
public void recordLogininfor(String username, String status, String message)
|
||||
{
|
||||
SysLogininfor logininfor = new SysLogininfor();
|
||||
logininfor.setUserName(username);
|
||||
logininfor.setIpaddr(IpUtils.getIpAddr(ServletUtils.getRequest()));
|
||||
logininfor.setMsg(message);
|
||||
// 日志状态
|
||||
if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
|
||||
{
|
||||
logininfor.setStatus("0");
|
||||
}
|
||||
else if (Constants.LOGIN_FAIL.equals(status))
|
||||
{
|
||||
logininfor.setStatus("1");
|
||||
}
|
||||
remoteLogService.saveLogininfor(logininfor, SecurityConstants.INNER);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.math.BigDecimal;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelHandlerAdapter;
|
||||
|
||||
/**
|
||||
* 自定义导出Excel数据注解
|
||||
@@ -103,7 +104,17 @@ public @interface Excel
|
||||
/**
|
||||
* 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)
|
||||
*/
|
||||
Align align() default Align.AUTO;
|
||||
public Align align() default Align.AUTO;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器
|
||||
*/
|
||||
public Class<?> handler() default ExcelHandlerAdapter.class;
|
||||
|
||||
/**
|
||||
* 自定义数据处理器参数
|
||||
*/
|
||||
public String[] args() default {};
|
||||
|
||||
public enum Align
|
||||
{
|
||||
|
||||
@@ -7,33 +7,8 @@ package com.ruoyi.common.core.constant;
|
||||
*/
|
||||
public class CacheConstants
|
||||
{
|
||||
/**
|
||||
* 令牌自定义标识
|
||||
*/
|
||||
public static final String HEADER = "Authorization";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 权限缓存前缀
|
||||
*/
|
||||
public final static String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 用户ID字段
|
||||
*/
|
||||
public static final String DETAILS_USER_ID = "user_id";
|
||||
|
||||
/**
|
||||
* 用户名字段
|
||||
*/
|
||||
public static final String DETAILS_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* 授权信息字段
|
||||
*/
|
||||
public static final String AUTHORIZATION_HEADER = "authorization";
|
||||
}
|
||||
|
||||
@@ -17,6 +17,16 @@ public class Constants
|
||||
*/
|
||||
public static final String GBK = "GBK";
|
||||
|
||||
/**
|
||||
* RMI 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_RMI = "rmi://";
|
||||
|
||||
/**
|
||||
* LDAP 远程方法调用
|
||||
*/
|
||||
public static final String LOOKUP_LDAP = "ldap://";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.ruoyi.common.core.constant;
|
||||
|
||||
/**
|
||||
* 权限相关通用常量
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class SecurityConstants
|
||||
{
|
||||
/**
|
||||
* 令牌自定义标识
|
||||
*/
|
||||
public static final String TOKEN_AUTHENTICATION = "Authorization";
|
||||
|
||||
/**
|
||||
* 令牌前缀
|
||||
*/
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
/**
|
||||
* 用户ID字段
|
||||
*/
|
||||
public static final String DETAILS_USER_ID = "user_id";
|
||||
|
||||
/**
|
||||
* 用户名字段
|
||||
*/
|
||||
public static final String DETAILS_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* 授权信息字段
|
||||
*/
|
||||
public static final String AUTHORIZATION_HEADER = "authorization";
|
||||
|
||||
/**
|
||||
* 请求来源
|
||||
*/
|
||||
public static final String FROM_SOURCE = "from-source";
|
||||
|
||||
/**
|
||||
* 内部请求
|
||||
*/
|
||||
public static final String INNER = "inner";
|
||||
}
|
||||
@@ -57,6 +57,9 @@ public class UserConstants
|
||||
/** ParentView组件标识 */
|
||||
public final static String PARENT_VIEW = "ParentView";
|
||||
|
||||
/** InnerLink组件标识 */
|
||||
public final static String INNER_LINK = "InnerLink";
|
||||
|
||||
/** 校验返回结果码 */
|
||||
public final static String UNIQUE = "0";
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 自定义异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class CustomException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String message;
|
||||
|
||||
public CustomException(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public CustomException(String message, Integer code)
|
||||
{
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public CustomException(String message, Throwable e)
|
||||
{
|
||||
super(message, e);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public Integer getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 全局异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class GlobalException extends RuntimeException
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 错误明细,内部调试错误
|
||||
*
|
||||
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
|
||||
*/
|
||||
private String detailMessage;
|
||||
|
||||
/**
|
||||
* 空构造方法,避免反序列化问题
|
||||
*/
|
||||
public GlobalException()
|
||||
{
|
||||
}
|
||||
|
||||
public GlobalException(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getDetailMessage()
|
||||
{
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
public GlobalException setDetailMessage(String detailMessage)
|
||||
{
|
||||
this.detailMessage = detailMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public GlobalException setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 内部认证异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class InnerAuthException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InnerAuthException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public final class ServiceException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 错误明细,内部调试错误
|
||||
*
|
||||
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
|
||||
*/
|
||||
private String detailMessage;
|
||||
|
||||
/**
|
||||
* 空构造方法,避免反序列化问题
|
||||
*/
|
||||
public ServiceException()
|
||||
{
|
||||
}
|
||||
|
||||
public ServiceException(String message)
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ServiceException(String message, Integer code)
|
||||
{
|
||||
this.message = message;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getDetailMessage()
|
||||
{
|
||||
return detailMessage;
|
||||
}
|
||||
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public Integer getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public ServiceException setMessage(String message)
|
||||
{
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServiceException setDetailMessage(String detailMessage)
|
||||
{
|
||||
this.detailMessage = detailMessage;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +1,79 @@
|
||||
package com.ruoyi.common.core.exception;
|
||||
|
||||
/**
|
||||
* 基础异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class BaseException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 所属模块
|
||||
*/
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 错误码对应的参数
|
||||
*/
|
||||
private Object[] args;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String defaultMessage;
|
||||
|
||||
public BaseException(String module, String code, Object[] args, String defaultMessage)
|
||||
{
|
||||
this.module = module;
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
this.defaultMessage = defaultMessage;
|
||||
}
|
||||
|
||||
public BaseException(String module, String code, Object[] args)
|
||||
{
|
||||
this(module, code, args, null);
|
||||
}
|
||||
|
||||
public BaseException(String module, String defaultMessage)
|
||||
{
|
||||
this(module, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public BaseException(String code, Object[] args)
|
||||
{
|
||||
this(null, code, args, null);
|
||||
}
|
||||
|
||||
public BaseException(String defaultMessage)
|
||||
{
|
||||
this(null, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public String getModule()
|
||||
{
|
||||
return module;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Object[] getArgs()
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getDefaultMessage()
|
||||
{
|
||||
return defaultMessage;
|
||||
}
|
||||
}
|
||||
package com.ruoyi.common.core.exception.base;
|
||||
|
||||
/**
|
||||
* 基础异常
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class BaseException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 所属模块
|
||||
*/
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 错误码对应的参数
|
||||
*/
|
||||
private Object[] args;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String defaultMessage;
|
||||
|
||||
public BaseException(String module, String code, Object[] args, String defaultMessage)
|
||||
{
|
||||
this.module = module;
|
||||
this.code = code;
|
||||
this.args = args;
|
||||
this.defaultMessage = defaultMessage;
|
||||
}
|
||||
|
||||
public BaseException(String module, String code, Object[] args)
|
||||
{
|
||||
this(module, code, args, null);
|
||||
}
|
||||
|
||||
public BaseException(String module, String defaultMessage)
|
||||
{
|
||||
this(module, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public BaseException(String code, Object[] args)
|
||||
{
|
||||
this(null, code, args, null);
|
||||
}
|
||||
|
||||
public BaseException(String defaultMessage)
|
||||
{
|
||||
this(null, null, null, defaultMessage);
|
||||
}
|
||||
|
||||
public String getModule()
|
||||
{
|
||||
return module;
|
||||
}
|
||||
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public Object[] getArgs()
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
public String getDefaultMessage()
|
||||
{
|
||||
return defaultMessage;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.ruoyi.common.core.exception.file;
|
||||
|
||||
import com.ruoyi.common.core.exception.BaseException;
|
||||
import com.ruoyi.common.core.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* 文件信息异常类
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.ruoyi.common.core.exception.user;
|
||||
|
||||
import com.ruoyi.common.core.exception.BaseException;
|
||||
import com.ruoyi.common.core.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* 用户信息异常类
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.ruoyi.common.core.utils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
|
||||
/**
|
||||
@@ -17,7 +17,7 @@ public class SecurityUtils
|
||||
*/
|
||||
public static String getUsername()
|
||||
{
|
||||
String username = ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USERNAME);
|
||||
String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME);
|
||||
return ServletUtils.urlDecode(username);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class SecurityUtils
|
||||
*/
|
||||
public static Long getUserId()
|
||||
{
|
||||
return Convert.toLong(ServletUtils.getRequest().getHeader(CacheConstants.DETAILS_USER_ID));
|
||||
return Convert.toLong(ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,10 +42,18 @@ public class SecurityUtils
|
||||
*/
|
||||
public static String getToken(HttpServletRequest request)
|
||||
{
|
||||
String token = ServletUtils.getRequest().getHeader(CacheConstants.HEADER);
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
String token = request.getHeader(SecurityConstants.TOKEN_AUTHENTICATION);
|
||||
return replaceTokenPrefix(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换token前缀
|
||||
*/
|
||||
public static String replaceTokenPrefix(String token)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(SecurityConstants.TOKEN_PREFIX))
|
||||
{
|
||||
token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
token = token.replace(SecurityConstants.TOKEN_PREFIX, "");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,19 @@ import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 客户端工具类
|
||||
@@ -55,6 +63,22 @@ public class ServletUtils
|
||||
return Convert.toInt(getRequest().getParameter(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean参数
|
||||
*/
|
||||
public static Boolean getParameterToBool(String name)
|
||||
{
|
||||
return Convert.toBool(getRequest().getParameter(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Boolean参数
|
||||
*/
|
||||
public static Boolean getParameterToBool(String name, Boolean defaultValue)
|
||||
{
|
||||
return Convert.toBool(getRequest().getParameter(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
@@ -213,4 +237,62 @@ public class ServletUtils
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value)
|
||||
{
|
||||
return webFluxResponseWriter(response, HttpStatus.OK, value, R.FAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, Object value, int code)
|
||||
{
|
||||
return webFluxResponseWriter(response, HttpStatus.OK, value, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param status http状态码
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, int code)
|
||||
{
|
||||
return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置webflux模型响应
|
||||
*
|
||||
* @param response ServerHttpResponse
|
||||
* @param contentType content-type
|
||||
* @param status http状态码
|
||||
* @param code 响应状态码
|
||||
* @param value 响应内容
|
||||
* @return Mono<Void>
|
||||
*/
|
||||
public static Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, Object value, int code)
|
||||
{
|
||||
response.setStatusCode(status);
|
||||
response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType);
|
||||
R<?> result = R.fail(code, value.toString());
|
||||
DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(result).getBytes());
|
||||
return response.writeWith(Mono.just(dataBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.text.StrFormatter;
|
||||
|
||||
/**
|
||||
@@ -282,6 +283,17 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||
return StrFormatter.format(template, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为http(s)://开头
|
||||
*
|
||||
* @param link 链接
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean ishttp(String link)
|
||||
{
|
||||
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线命名
|
||||
*/
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.ruoyi.common.core.utils.StringUtils;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class FileUtils extends org.apache.commons.io.FileUtils
|
||||
public class FileUtils
|
||||
{
|
||||
/** 字符常量:斜杠 {@code '/'} */
|
||||
public static final char SLASH = '/';
|
||||
@@ -244,6 +244,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
|
||||
.append(percentEncodedFileName);
|
||||
|
||||
response.setHeader("Content-disposition", contentDispositionValue.toString());
|
||||
response.setHeader("download-filename", percentEncodedFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.ruoyi.common.core.utils.html;
|
||||
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 转义和反转义工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class EscapeUtil
|
||||
{
|
||||
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
||||
|
||||
private static final char[][] TEXT = new char[64][];
|
||||
|
||||
static
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
TEXT[i] = new char[] { (char) i };
|
||||
}
|
||||
|
||||
// special HTML characters
|
||||
TEXT['\''] = "'".toCharArray(); // 单引号
|
||||
TEXT['"'] = """.toCharArray(); // 双引号
|
||||
TEXT['&'] = "&".toCharArray(); // &符
|
||||
TEXT['<'] = "<".toCharArray(); // 小于号
|
||||
TEXT['>'] = ">".toCharArray(); // 大于号
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义文本中的HTML字符为安全的字符
|
||||
*
|
||||
* @param text 被转义的文本
|
||||
* @return 转义后的文本
|
||||
*/
|
||||
public static String escape(String text)
|
||||
{
|
||||
return encode(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原被转义的HTML特殊字符
|
||||
*
|
||||
* @param content 包含转义符的HTML内容
|
||||
* @return 转换后的字符串
|
||||
*/
|
||||
public static String unescape(String content)
|
||||
{
|
||||
return decode(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有HTML标签,但是不删除标签内的内容
|
||||
*
|
||||
* @param content 文本
|
||||
* @return 清除标签后的文本
|
||||
*/
|
||||
public static String clean(String content)
|
||||
{
|
||||
return new HTMLFilter().filter(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape编码
|
||||
*
|
||||
* @param text 被编码的文本
|
||||
* @return 编码后的字符
|
||||
*/
|
||||
private static String encode(String text)
|
||||
{
|
||||
int len;
|
||||
if ((text == null) || ((len = text.length()) == 0))
|
||||
{
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
StringBuilder buffer = new StringBuilder(len + (len >> 2));
|
||||
char c;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
c = text.charAt(i);
|
||||
if (c < 64)
|
||||
{
|
||||
buffer.append(TEXT[c]);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.append(c);
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape解码
|
||||
*
|
||||
* @param content 被转义的内容
|
||||
* @return 解码后的字符串
|
||||
*/
|
||||
public static String decode(String content)
|
||||
{
|
||||
if (StringUtils.isEmpty(content))
|
||||
{
|
||||
return content;
|
||||
}
|
||||
|
||||
StringBuilder tmp = new StringBuilder(content.length());
|
||||
int lastPos = 0, pos = 0;
|
||||
char ch;
|
||||
while (lastPos < content.length())
|
||||
{
|
||||
pos = content.indexOf("%", lastPos);
|
||||
if (pos == lastPos)
|
||||
{
|
||||
if (content.charAt(pos + 1) == 'u')
|
||||
{
|
||||
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
|
||||
tmp.append(ch);
|
||||
lastPos = pos + 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
|
||||
tmp.append(ch);
|
||||
lastPos = pos + 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos == -1)
|
||||
{
|
||||
tmp.append(content.substring(lastPos));
|
||||
lastPos = content.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.append(content.substring(lastPos, pos));
|
||||
lastPos = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
String html = "<script>alert(1);</script>";
|
||||
// String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
|
||||
// String html = "<123";
|
||||
// String html = "123>";
|
||||
System.out.println(EscapeUtil.clean(html));
|
||||
System.out.println(EscapeUtil.escape(html));
|
||||
System.out.println(EscapeUtil.unescape(html));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,570 @@
|
||||
package com.ruoyi.common.core.utils.html;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* HTML过滤器,用于去除XSS漏洞隐患。
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public final class HTMLFilter
|
||||
{
|
||||
/**
|
||||
* regex flag union representing /si modifiers in php
|
||||
**/
|
||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
||||
private static final Pattern P_AMP = Pattern.compile("&");
|
||||
private static final Pattern P_QUOTE = Pattern.compile("\"");
|
||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
||||
|
||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* set of allowed html elements, along with allowed attributes for each element
|
||||
**/
|
||||
private final Map<String, List<String>> vAllowed;
|
||||
/**
|
||||
* counts of open tags for each (allowable) html element
|
||||
**/
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
* set of disallowed html elements
|
||||
**/
|
||||
private final String[] vDisallowed;
|
||||
/**
|
||||
* attributes which should be checked for valid protocols
|
||||
**/
|
||||
private final String[] vProtocolAtts;
|
||||
/**
|
||||
* allowed protocols
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
* entities allowed within html markup
|
||||
**/
|
||||
private final String[] vAllowedEntities;
|
||||
/**
|
||||
* flag determining whether comments are allowed in input String.
|
||||
*/
|
||||
private final boolean stripComment;
|
||||
private final boolean encodeQuotes;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
|
||||
* becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public HTMLFilter()
|
||||
{
|
||||
vAllowed = new HashMap<>();
|
||||
|
||||
final ArrayList<String> a_atts = new ArrayList<>();
|
||||
a_atts.add("href");
|
||||
a_atts.add("target");
|
||||
vAllowed.put("a", a_atts);
|
||||
|
||||
final ArrayList<String> img_atts = new ArrayList<>();
|
||||
img_atts.add("src");
|
||||
img_atts.add("width");
|
||||
img_atts.add("height");
|
||||
img_atts.add("alt");
|
||||
vAllowed.put("img", img_atts);
|
||||
|
||||
final ArrayList<String> no_atts = new ArrayList<>();
|
||||
vAllowed.put("b", no_atts);
|
||||
vAllowed.put("strong", no_atts);
|
||||
vAllowed.put("i", no_atts);
|
||||
vAllowed.put("em", no_atts);
|
||||
|
||||
vSelfClosingTags = new String[] { "img" };
|
||||
vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
|
||||
vDisallowed = new String[] {};
|
||||
vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
|
||||
vProtocolAtts = new String[] { "src", "href" };
|
||||
vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
|
||||
vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
|
||||
stripComment = true;
|
||||
encodeQuotes = true;
|
||||
alwaysMakeTags = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map-parameter configurable constructor.
|
||||
*
|
||||
* @param conf map containing configuration. keys match field names.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public HTMLFilter(final Map<String, Object> conf)
|
||||
{
|
||||
|
||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
||||
|
||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
vTagCounts.clear();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// my versions of some PHP library functions
|
||||
public static String chr(final int decimal)
|
||||
{
|
||||
return String.valueOf((char) decimal);
|
||||
}
|
||||
|
||||
public static String htmlSpecialChars(final String s)
|
||||
{
|
||||
String result = s;
|
||||
result = regexReplace(P_AMP, "&", result);
|
||||
result = regexReplace(P_QUOTE, """, result);
|
||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* given a user submitted input String, filter out any invalid or restricted html.
|
||||
*
|
||||
* @param input text (i.e. submitted by a user) than may contain html
|
||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
||||
*/
|
||||
public String filter(final String input)
|
||||
{
|
||||
reset();
|
||||
String s = input;
|
||||
|
||||
s = escapeComments(s);
|
||||
|
||||
s = balanceHTML(s);
|
||||
|
||||
s = checkTags(s);
|
||||
|
||||
s = processRemoveBlanks(s);
|
||||
|
||||
// s = validateEntities(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public boolean isAlwaysMakeTags()
|
||||
{
|
||||
return alwaysMakeTags;
|
||||
}
|
||||
|
||||
public boolean isStripComments()
|
||||
{
|
||||
return stripComment;
|
||||
}
|
||||
|
||||
private String escapeComments(final String s)
|
||||
{
|
||||
final Matcher m = P_COMMENTS.matcher(s);
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
if (m.find())
|
||||
{
|
||||
final String match = m.group(1); // (.*?)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String balanceHTML(String s)
|
||||
{
|
||||
if (alwaysMakeTags)
|
||||
{
|
||||
//
|
||||
// try and form html
|
||||
//
|
||||
s = regexReplace(P_END_ARROW, "", s);
|
||||
// 不追加结束标签
|
||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// escape stray brackets
|
||||
//
|
||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
||||
|
||||
//
|
||||
// the last regexp causes '<>' entities to appear
|
||||
// (we need to do a lookahead assertion so that the last bracket can
|
||||
// be used in the next pass of the regexp)
|
||||
//
|
||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String checkTags(String s)
|
||||
{
|
||||
Matcher m = P_TAGS.matcher(s);
|
||||
|
||||
final StringBuffer buf = new StringBuffer();
|
||||
while (m.find())
|
||||
{
|
||||
String replaceStr = m.group(1);
|
||||
replaceStr = processTag(replaceStr);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
// these get tallied in processTag
|
||||
// (remember to reset before subsequent calls to filter method)
|
||||
final StringBuilder sBuilder = new StringBuilder(buf.toString());
|
||||
for (String key : vTagCounts.keySet())
|
||||
{
|
||||
for (int ii = 0; ii < vTagCounts.get(key); ii++)
|
||||
{
|
||||
sBuilder.append("</").append(key).append(">");
|
||||
}
|
||||
}
|
||||
s = sBuilder.toString();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String processRemoveBlanks(final String s)
|
||||
{
|
||||
String result = s;
|
||||
for (String tag : vRemoveBlanks)
|
||||
{
|
||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
|
||||
{
|
||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
|
||||
{
|
||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
||||
}
|
||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
|
||||
{
|
||||
Matcher m = regex_pattern.matcher(s);
|
||||
return m.replaceAll(replacement);
|
||||
}
|
||||
|
||||
private String processTag(final String s)
|
||||
{
|
||||
// ending tags
|
||||
Matcher m = P_END_TAG.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String name = m.group(1).toLowerCase();
|
||||
if (allowed(name))
|
||||
{
|
||||
if (false == inArray(name, vSelfClosingTags))
|
||||
{
|
||||
if (vTagCounts.containsKey(name))
|
||||
{
|
||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
||||
return "</" + name + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// starting tags
|
||||
m = P_START_TAG.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String name = m.group(1).toLowerCase();
|
||||
final String body = m.group(2);
|
||||
String ending = m.group(3);
|
||||
|
||||
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
||||
if (allowed(name))
|
||||
{
|
||||
final StringBuilder params = new StringBuilder();
|
||||
|
||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
||||
final List<String> paramNames = new ArrayList<>();
|
||||
final List<String> paramValues = new ArrayList<>();
|
||||
while (m2.find())
|
||||
{
|
||||
paramNames.add(m2.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m2.group(3)); // (.*?)
|
||||
}
|
||||
while (m3.find())
|
||||
{
|
||||
paramNames.add(m3.group(1)); // ([a-z0-9]+)
|
||||
paramValues.add(m3.group(3)); // ([^\"\\s']+)
|
||||
}
|
||||
|
||||
String paramName, paramValue;
|
||||
for (int ii = 0; ii < paramNames.size(); ii++)
|
||||
{
|
||||
paramName = paramNames.get(ii).toLowerCase();
|
||||
paramValue = paramValues.get(ii);
|
||||
|
||||
// debug( "paramName='" + paramName + "'" );
|
||||
// debug( "paramValue='" + paramValue + "'" );
|
||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
||||
|
||||
if (allowedAttribute(name, paramName))
|
||||
{
|
||||
if (inArray(paramName, vProtocolAtts))
|
||||
{
|
||||
paramValue = processParamProtocol(paramValue);
|
||||
}
|
||||
params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\"");
|
||||
}
|
||||
}
|
||||
|
||||
if (inArray(name, vSelfClosingTags))
|
||||
{
|
||||
ending = " /";
|
||||
}
|
||||
|
||||
if (inArray(name, vNeedClosingTags))
|
||||
{
|
||||
ending = "";
|
||||
}
|
||||
|
||||
if (ending == null || ending.length() < 1)
|
||||
{
|
||||
if (vTagCounts.containsKey(name))
|
||||
{
|
||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
vTagCounts.put(name, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ending = " /";
|
||||
}
|
||||
return "<" + name + params + ending + ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// comments
|
||||
m = P_COMMENT.matcher(s);
|
||||
if (!stripComment && m.find())
|
||||
{
|
||||
return "<" + m.group() + ">";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String processParamProtocol(String s)
|
||||
{
|
||||
s = decodeEntities(s);
|
||||
final Matcher m = P_PROTOCOL.matcher(s);
|
||||
if (m.find())
|
||||
{
|
||||
final String protocol = m.group(1);
|
||||
if (!inArray(protocol, vAllowedProtocols))
|
||||
{
|
||||
// bad protocol, turn into local anchor link instead
|
||||
s = "#" + s.substring(protocol.length() + 1);
|
||||
if (s.startsWith("#//"))
|
||||
{
|
||||
s = "#" + s.substring(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private String decodeEntities(String s)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
buf = new StringBuffer();
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
s = buf.toString();
|
||||
|
||||
s = validateEntities(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
private String validateEntities(final String s)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
// validate entities throughout the string
|
||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String one = m.group(1); // ([^&;]*)
|
||||
final String two = m.group(2); // (?=(;|&|$))
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
||||
return encodeQuotes(buf.toString());
|
||||
}
|
||||
|
||||
private String encodeQuotes(final String s)
|
||||
{
|
||||
if (encodeQuotes)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
||||
while (m.find())
|
||||
{
|
||||
final String one = m.group(1); // (>|^)
|
||||
final String two = m.group(2); // ([^<]+?)
|
||||
final String three = m.group(3); // (<|$)
|
||||
// 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two)
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
return buf.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private String checkEntity(final String preamble, final String term)
|
||||
{
|
||||
|
||||
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble;
|
||||
}
|
||||
|
||||
private boolean isValidEntity(final String entity)
|
||||
{
|
||||
return inArray(entity, vAllowedEntities);
|
||||
}
|
||||
|
||||
private static boolean inArray(final String s, final String[] array)
|
||||
{
|
||||
for (String item : array)
|
||||
{
|
||||
if (item != null && item.equals(s))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowed(final String name)
|
||||
{
|
||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
||||
}
|
||||
|
||||
private boolean allowedAttribute(final String name, final String paramName)
|
||||
{
|
||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.common.core.utils.poi;
|
||||
|
||||
/**
|
||||
* Excel数据格式处理适配器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ExcelHandlerAdapter
|
||||
{
|
||||
/**
|
||||
* 格式化
|
||||
*
|
||||
* @param value 单元格数据值
|
||||
* @param args excel注解args参数组
|
||||
*
|
||||
* @return 处理后的值
|
||||
*/
|
||||
Object format(Object value, String[] args);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
@@ -35,6 +36,7 @@ import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
||||
@@ -102,6 +104,16 @@ public class ExcelUtil<T>
|
||||
*/
|
||||
private List<Object[]> fields;
|
||||
|
||||
/**
|
||||
* 当前行号
|
||||
*/
|
||||
private int rownum;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 最大高度
|
||||
*/
|
||||
@@ -127,7 +139,7 @@ public class ExcelUtil<T>
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public void init(List<T> list, String sheetName, Type type)
|
||||
public void init(List<T> list, String sheetName, String title, Type type)
|
||||
{
|
||||
if (list == null)
|
||||
{
|
||||
@@ -136,8 +148,27 @@ public class ExcelUtil<T>
|
||||
this.list = list;
|
||||
this.sheetName = sheetName;
|
||||
this.type = type;
|
||||
this.title = title;
|
||||
createExcelField();
|
||||
createWorkbook();
|
||||
createTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建excel第一行标题
|
||||
*/
|
||||
public void createTitle()
|
||||
{
|
||||
if (StringUtils.isNotEmpty(title))
|
||||
{
|
||||
Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
|
||||
titleRow.setHeightInPoints(30);
|
||||
Cell titleCell = titleRow.createCell(0);
|
||||
titleCell.setCellStyle(styles.get("title"));
|
||||
titleCell.setCellValue(title);
|
||||
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
|
||||
this.fields.size() - 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,33 +179,36 @@ public class ExcelUtil<T>
|
||||
*/
|
||||
public List<T> importExcel(InputStream is) throws Exception
|
||||
{
|
||||
return importExcel(StringUtils.EMPTY, is);
|
||||
return importExcel(is, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对excel表单默认第一个索引名转换成list
|
||||
*
|
||||
* @param is 输入流
|
||||
* @param titleNum 标题占用行数
|
||||
* @return 转换后集合
|
||||
*/
|
||||
public List<T> importExcel(InputStream is, int titleNum) throws Exception
|
||||
{
|
||||
return importExcel(StringUtils.EMPTY, is, titleNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对excel表单指定表格索引名转换成list
|
||||
*
|
||||
* @param sheetName 表格索引名
|
||||
* @param titleNum 标题占用行数
|
||||
* @param is 输入流
|
||||
* @return 转换后集合
|
||||
*/
|
||||
public List<T> importExcel(String sheetName, InputStream is) throws Exception
|
||||
public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
|
||||
{
|
||||
this.type = Type.IMPORT;
|
||||
this.wb = WorkbookFactory.create(is);
|
||||
List<T> list = new ArrayList<T>();
|
||||
Sheet sheet = null;
|
||||
if (StringUtils.isNotEmpty(sheetName))
|
||||
{
|
||||
// 如果指定sheet名,则取指定sheet中的内容.
|
||||
sheet = wb.getSheet(sheetName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果传入的sheet名不存在则默认指向第1个sheet.
|
||||
sheet = wb.getSheetAt(0);
|
||||
}
|
||||
|
||||
// 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
|
||||
Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
|
||||
if (sheet == null)
|
||||
{
|
||||
throw new IOException("文件sheet不存在");
|
||||
@@ -188,7 +222,7 @@ public class ExcelUtil<T>
|
||||
// 定义一个map用于存放excel列的序号和field.
|
||||
Map<String, Integer> cellMap = new HashMap<String, Integer>();
|
||||
// 获取表头
|
||||
Row heard = sheet.getRow(0);
|
||||
Row heard = sheet.getRow(titleNum);
|
||||
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
|
||||
{
|
||||
Cell cell = heard.getCell(i);
|
||||
@@ -203,25 +237,18 @@ public class ExcelUtil<T>
|
||||
}
|
||||
}
|
||||
// 有数据时才处理 得到类的所有field.
|
||||
Field[] allFields = clazz.getDeclaredFields();
|
||||
// 定义一个map用于存放列的序号和field.
|
||||
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
|
||||
for (int col = 0; col < allFields.length; col++)
|
||||
List<Object[]> fields = this.getFields();
|
||||
Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
|
||||
for (Object[] objects : fields)
|
||||
{
|
||||
Field field = allFields[col];
|
||||
Excel attr = field.getAnnotation(Excel.class);
|
||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
||||
Excel attr = (Excel) objects[1];
|
||||
Integer column = cellMap.get(attr.name());
|
||||
if (column != null)
|
||||
{
|
||||
// 设置类的私有字段属性可访问.
|
||||
field.setAccessible(true);
|
||||
Integer column = cellMap.get(attr.name());
|
||||
if (column != null)
|
||||
{
|
||||
fieldsMap.put(column, field);
|
||||
}
|
||||
fieldsMap.put(column, objects);
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= rows; i++)
|
||||
for (int i = titleNum + 1; i <= rows; i++)
|
||||
{
|
||||
// 从第2行开始取数据,默认第一行是表头.
|
||||
Row row = sheet.getRow(i);
|
||||
@@ -231,14 +258,15 @@ public class ExcelUtil<T>
|
||||
continue;
|
||||
}
|
||||
T entity = null;
|
||||
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
|
||||
for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
|
||||
{
|
||||
Object val = this.getCellValue(row, entry.getKey());
|
||||
|
||||
// 如果不存在实例则新建.
|
||||
entity = (entity == null ? clazz.newInstance() : entity);
|
||||
// 从map中得到对应列的field.
|
||||
Field field = fieldsMap.get(entry.getKey());
|
||||
Field field = (Field) entry.getValue()[0];
|
||||
Excel attr = (Excel) entry.getValue()[1];
|
||||
// 取得类型,并根据对象类型设置值.
|
||||
Class<?> fieldType = field.getType();
|
||||
if (String.class == fieldType)
|
||||
@@ -298,7 +326,6 @@ public class ExcelUtil<T>
|
||||
}
|
||||
if (StringUtils.isNotNull(fieldType))
|
||||
{
|
||||
Excel attr = field.getAnnotation(Excel.class);
|
||||
String propertyName = field.getName();
|
||||
if (StringUtils.isNotEmpty(attr.targetAttr()))
|
||||
{
|
||||
@@ -308,6 +335,10 @@ public class ExcelUtil<T>
|
||||
{
|
||||
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
|
||||
}
|
||||
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
|
||||
{
|
||||
val = dataFormatHandlerAdapter(val, attr);
|
||||
}
|
||||
ReflectUtils.invokeSetter(entity, propertyName, val);
|
||||
}
|
||||
}
|
||||
@@ -326,14 +357,35 @@ public class ExcelUtil<T>
|
||||
* @return 结果
|
||||
* @throws IOException
|
||||
*/
|
||||
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) throws IOException
|
||||
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)throws IOException
|
||||
{
|
||||
exportExcel(response, list, sheetName, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对list数据源将其里面的数据导入到excel表单
|
||||
*
|
||||
* @param response 返回数据
|
||||
* @param list 导出数据集合
|
||||
* @param sheetName 工作表的名称
|
||||
* @param title 标题
|
||||
* @return 结果
|
||||
* @throws IOException
|
||||
*/
|
||||
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) throws IOException
|
||||
{
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
this.init(list, sheetName, Type.EXPORT);
|
||||
this.init(list, sheetName, title, Type.EXPORT);
|
||||
exportExcel(response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* 对list数据源将其里面的数据导入到excel表单
|
||||
*
|
||||
* @param sheetName 工作表的名称
|
||||
* @return 结果
|
||||
*/
|
||||
/**
|
||||
* 对list数据源将其里面的数据导入到excel表单
|
||||
*
|
||||
@@ -341,10 +393,22 @@ public class ExcelUtil<T>
|
||||
* @return 结果
|
||||
*/
|
||||
public void importTemplateExcel(HttpServletResponse response, String sheetName) throws IOException
|
||||
{
|
||||
importTemplateExcel(response, sheetName, StringUtils.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对list数据源将其里面的数据导入到excel表单
|
||||
*
|
||||
* @param sheetName 工作表的名称
|
||||
* @param title 标题
|
||||
* @return 结果
|
||||
*/
|
||||
public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) throws IOException
|
||||
{
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
this.init(null, sheetName, Type.IMPORT);
|
||||
this.init(null, sheetName, title, Type.IMPORT);
|
||||
exportExcel(response.getOutputStream());
|
||||
}
|
||||
|
||||
@@ -377,13 +441,13 @@ public class ExcelUtil<T>
|
||||
public void writeSheet()
|
||||
{
|
||||
// 取出一共有多少个sheet.
|
||||
double sheetNo = Math.ceil(list.size() / sheetSize);
|
||||
for (int index = 0; index <= sheetNo; index++)
|
||||
int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
|
||||
for (int index = 0; index < sheetNo; index++)
|
||||
{
|
||||
createSheet(sheetNo, index);
|
||||
|
||||
// 产生一行
|
||||
Row row = sheet.createRow(0);
|
||||
Row row = sheet.createRow(rownum);
|
||||
int column = 0;
|
||||
// 写入各个字段的列头名称
|
||||
for (Object[] os : fields)
|
||||
@@ -411,7 +475,7 @@ public class ExcelUtil<T>
|
||||
int endNo = Math.min(startNo + sheetSize, list.size());
|
||||
for (int i = startNo; i < endNo; i++)
|
||||
{
|
||||
row = sheet.createRow(i + 1 - startNo);
|
||||
row = sheet.createRow(i + 1 + rownum - startNo);
|
||||
// 得到导出对象.
|
||||
T vo = (T) list.get(i);
|
||||
int column = 0;
|
||||
@@ -419,8 +483,6 @@ public class ExcelUtil<T>
|
||||
{
|
||||
Field field = (Field) os[0];
|
||||
Excel excel = (Excel) os[1];
|
||||
// 设置实体类私有属性可访问
|
||||
field.setAccessible(true);
|
||||
this.addCell(excel, row, vo, field, column++);
|
||||
}
|
||||
}
|
||||
@@ -439,6 +501,16 @@ public class ExcelUtil<T>
|
||||
CellStyle style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
Font titleFont = wb.createFont();
|
||||
titleFont.setFontName("Arial");
|
||||
titleFont.setFontHeightInPoints((short) 16);
|
||||
titleFont.setBold(true);
|
||||
style.setFont(titleFont);
|
||||
styles.put("title", style);
|
||||
|
||||
style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
style.setBorderRight(BorderStyle.THIN);
|
||||
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
@@ -466,7 +538,7 @@ public class ExcelUtil<T>
|
||||
headerFont.setColor(IndexedColors.WHITE.getIndex());
|
||||
style.setFont(headerFont);
|
||||
styles.put("header", style);
|
||||
|
||||
|
||||
style = wb.createCellStyle();
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
@@ -633,6 +705,10 @@ public class ExcelUtil<T>
|
||||
{
|
||||
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
|
||||
}
|
||||
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
|
||||
{
|
||||
cell.setCellValue(dataFormatHandlerAdapter(value, attr));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 设置列类型
|
||||
@@ -779,6 +855,28 @@ public class ExcelUtil<T>
|
||||
return StringUtils.stripEnd(propertyString.toString(), separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据处理器
|
||||
*
|
||||
* @param value 数据值
|
||||
* @param excel 数据注解
|
||||
* @return
|
||||
*/
|
||||
public String dataFormatHandlerAdapter(Object value, Excel excel)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object instance = excel.handler().newInstance();
|
||||
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class });
|
||||
value = formatMethod.invoke(instance, value, excel.args());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("不能格式化数据 " + excel.handler(), e.getMessage());
|
||||
}
|
||||
return Convert.toStr(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合计统计信息
|
||||
*/
|
||||
@@ -809,10 +907,9 @@ public class ExcelUtil<T>
|
||||
{
|
||||
if (statistics.size() > 0)
|
||||
{
|
||||
Cell cell = null;
|
||||
Row row = sheet.createRow(sheet.getLastRowNum() + 1);
|
||||
Set<Integer> keys = statistics.keySet();
|
||||
cell = row.createCell(0);
|
||||
Cell cell = row.createCell(0);
|
||||
cell.setCellStyle(styles.get("total"));
|
||||
cell.setCellValue("合计");
|
||||
|
||||
@@ -882,7 +979,17 @@ public class ExcelUtil<T>
|
||||
*/
|
||||
private void createExcelField()
|
||||
{
|
||||
this.fields = new ArrayList<Object[]>();
|
||||
this.fields = getFields();
|
||||
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
|
||||
this.maxHeight = getRowHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段注解信息
|
||||
*/
|
||||
public List<Object[]> getFields()
|
||||
{
|
||||
List<Object[]> fields = new ArrayList<Object[]>();
|
||||
List<Field> tempFields = new ArrayList<>();
|
||||
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
|
||||
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
||||
@@ -891,7 +998,12 @@ public class ExcelUtil<T>
|
||||
// 单注解
|
||||
if (field.isAnnotationPresent(Excel.class))
|
||||
{
|
||||
putToField(field, field.getAnnotation(Excel.class));
|
||||
Excel attr = field.getAnnotation(Excel.class);
|
||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
||||
{
|
||||
field.setAccessible(true);
|
||||
fields.add(new Object[] { field, attr });
|
||||
}
|
||||
}
|
||||
|
||||
// 多注解
|
||||
@@ -899,16 +1011,19 @@ public class ExcelUtil<T>
|
||||
{
|
||||
Excels attrs = field.getAnnotation(Excels.class);
|
||||
Excel[] excels = attrs.value();
|
||||
for (Excel excel : excels)
|
||||
for (Excel attr : excels)
|
||||
{
|
||||
putToField(field, excel);
|
||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
||||
{
|
||||
field.setAccessible(true);
|
||||
fields.add(new Object[] { field, attr });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
|
||||
this.maxHeight = getRowHeight();
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据注解获取最大行高
|
||||
*/
|
||||
@@ -923,23 +1038,15 @@ public class ExcelUtil<T>
|
||||
return (short) (maxHeight * 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* 放到字段集合中
|
||||
*/
|
||||
private void putToField(Field field, Excel attr)
|
||||
{
|
||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
||||
{
|
||||
this.fields.add(new Object[] { field, attr });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个工作簿
|
||||
*/
|
||||
public void createWorkbook()
|
||||
{
|
||||
this.wb = new SXSSFWorkbook(500);
|
||||
this.sheet = wb.createSheet();
|
||||
wb.setSheetName(0, sheetName);
|
||||
this.styles = createStyles(wb);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -948,17 +1055,13 @@ public class ExcelUtil<T>
|
||||
* @param sheetNo sheet数量
|
||||
* @param index 序号
|
||||
*/
|
||||
public void createSheet(double sheetNo, int index)
|
||||
public void createSheet(int sheetNo, int index)
|
||||
{
|
||||
this.sheet = wb.createSheet();
|
||||
this.styles = createStyles(wb);
|
||||
// 设置工作表的名称.
|
||||
if (sheetNo == 0)
|
||||
{
|
||||
wb.setSheetName(index, sheetName);
|
||||
}
|
||||
else
|
||||
if (sheetNo > 1 && index > 0)
|
||||
{
|
||||
this.sheet = wb.createSheet();
|
||||
this.createTitle();
|
||||
wb.setSheetName(index, sheetName + index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.ruoyi.common.core.utils.sql;
|
||||
|
||||
import com.ruoyi.common.core.exception.BaseException;
|
||||
import com.ruoyi.common.core.exception.UtilException;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -22,7 +22,7 @@ public class SqlUtil
|
||||
{
|
||||
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
|
||||
{
|
||||
throw new BaseException("参数不符合规范,不能进行查询");
|
||||
throw new UtilException("参数不符合规范,不能进行查询");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ public class BaseController
|
||||
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
|
||||
{
|
||||
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
|
||||
PageHelper.startPage(pageNum, pageSize, orderBy);
|
||||
Boolean reasonable = pageDomain.getReasonable();
|
||||
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ public class PageDomain
|
||||
/** 排序的方向desc或者asc */
|
||||
private String isAsc = "asc";
|
||||
|
||||
/** 分页参数合理化 */
|
||||
private Boolean reasonable = true;
|
||||
|
||||
public String getOrderBy()
|
||||
{
|
||||
if (StringUtils.isEmpty(orderByColumn))
|
||||
@@ -67,6 +70,32 @@ public class PageDomain
|
||||
|
||||
public void setIsAsc(String isAsc)
|
||||
{
|
||||
this.isAsc = isAsc;
|
||||
if (StringUtils.isNotEmpty(isAsc))
|
||||
{
|
||||
// 兼容前端排序类型
|
||||
if ("ascending".equals(isAsc))
|
||||
{
|
||||
isAsc = "asc";
|
||||
}
|
||||
else if ("descending".equals(isAsc))
|
||||
{
|
||||
isAsc = "desc";
|
||||
}
|
||||
this.isAsc = isAsc;
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean getReasonable()
|
||||
{
|
||||
if (StringUtils.isNull(reasonable))
|
||||
{
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return reasonable;
|
||||
}
|
||||
|
||||
public void setReasonable(Boolean reasonable)
|
||||
{
|
||||
this.reasonable = reasonable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ public class TableSupport
|
||||
*/
|
||||
public static final String IS_ASC = "isAsc";
|
||||
|
||||
/**
|
||||
* 分页参数合理化
|
||||
*/
|
||||
public static final String REASONABLE = "reasonable";
|
||||
|
||||
/**
|
||||
* 封装分页对象
|
||||
*/
|
||||
@@ -39,6 +44,7 @@ public class TableSupport
|
||||
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
|
||||
pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
|
||||
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
|
||||
pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
|
||||
return pageDomain;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package com.ruoyi.common.datascope.aspect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
@@ -59,27 +55,15 @@ public class DataScopeAspect
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
// 配置织入点
|
||||
@Pointcut("@annotation(com.ruoyi.common.datascope.annotation.DataScope)")
|
||||
public void dataScopePointCut()
|
||||
{
|
||||
}
|
||||
|
||||
@Before("dataScopePointCut()")
|
||||
public void doBefore(JoinPoint point) throws Throwable
|
||||
@Before("@annotation(controllerDataScope)")
|
||||
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
|
||||
{
|
||||
clearDataScope(point);
|
||||
handleDataScope(point);
|
||||
handleDataScope(point, controllerDataScope);
|
||||
}
|
||||
|
||||
protected void handleDataScope(final JoinPoint joinPoint)
|
||||
protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
|
||||
{
|
||||
// 获得注解
|
||||
DataScope controllerDataScope = getAnnotationLog(joinPoint);
|
||||
if (controllerDataScope == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 获取当前的用户
|
||||
LoginUser loginUser = tokenService.getLoginUser();
|
||||
if (StringUtils.isNotNull(loginUser))
|
||||
@@ -155,22 +139,6 @@ public class DataScopeAspect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在注解,如果存在就获取
|
||||
*/
|
||||
private DataScope getAnnotationLog(JoinPoint joinPoint)
|
||||
{
|
||||
Signature signature = joinPoint.getSignature();
|
||||
MethodSignature methodSignature = (MethodSignature) signature;
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
return method.getAnnotation(DataScope.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接权限sql前先清空params.dataScope参数防止注入
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -38,4 +38,9 @@ public @interface Log
|
||||
* 是否保存请求的参数
|
||||
*/
|
||||
public boolean isSaveRequestData() default true;
|
||||
|
||||
/**
|
||||
* 是否保存响应的参数
|
||||
*/
|
||||
public boolean isSaveResponseData() default true;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
package com.ruoyi.common.log.aspect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -44,21 +39,15 @@ public class LogAspect
|
||||
@Autowired
|
||||
private AsyncLogService asyncLogService;
|
||||
|
||||
// 配置织入点
|
||||
@Pointcut("@annotation(com.ruoyi.common.log.annotation.Log)")
|
||||
public void logPointCut()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理完请求后执行
|
||||
*
|
||||
* @param joinPoint 切点
|
||||
*/
|
||||
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
|
||||
@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
|
||||
{
|
||||
handleLog(joinPoint, null, jsonResult);
|
||||
handleLog(joinPoint, controllerLog, null, jsonResult);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,32 +56,22 @@ public class LogAspect
|
||||
* @param joinPoint 切点
|
||||
* @param e 异常
|
||||
*/
|
||||
@AfterThrowing(value = "logPointCut()", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Exception e)
|
||||
@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
|
||||
{
|
||||
handleLog(joinPoint, e, null);
|
||||
handleLog(joinPoint, controllerLog, e, null);
|
||||
}
|
||||
|
||||
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
|
||||
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获得注解
|
||||
Log controllerLog = getAnnotationLog(joinPoint);
|
||||
if (controllerLog == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// *========数据库日志=========*//
|
||||
SysOperLog operLog = new SysOperLog();
|
||||
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
|
||||
// 请求的地址
|
||||
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
||||
operLog.setOperIp(ip);
|
||||
// 返回参数
|
||||
operLog.setJsonResult(JSON.toJSONString(jsonResult));
|
||||
|
||||
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
|
||||
String username = SecurityUtils.getUsername();
|
||||
if (StringUtils.isNotBlank(username))
|
||||
@@ -112,7 +91,7 @@ public class LogAspect
|
||||
// 设置请求方式
|
||||
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
|
||||
// 处理设置注解上的参数
|
||||
getControllerMethodDescription(joinPoint, controllerLog, operLog);
|
||||
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
|
||||
// 保存数据库
|
||||
asyncLogService.saveSysLog(operLog);
|
||||
}
|
||||
@@ -132,7 +111,7 @@ public class LogAspect
|
||||
* @param operLog 操作日志
|
||||
* @throws Exception
|
||||
*/
|
||||
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
|
||||
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
|
||||
{
|
||||
// 设置action动作
|
||||
operLog.setBusinessType(log.businessType().ordinal());
|
||||
@@ -146,6 +125,11 @@ public class LogAspect
|
||||
// 获取参数的信息,传入到数据库中。
|
||||
setRequestValue(joinPoint, operLog);
|
||||
}
|
||||
// 是否需要保存response,参数和值
|
||||
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
|
||||
{
|
||||
operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,22 +148,6 @@ public class LogAspect
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否存在注解,如果存在就获取
|
||||
*/
|
||||
private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
|
||||
{
|
||||
Signature signature = joinPoint.getSignature();
|
||||
MethodSignature methodSignature = (MethodSignature) signature;
|
||||
Method method = methodSignature.getMethod();
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
return method.getAnnotation(Log.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数拼装
|
||||
*/
|
||||
@@ -188,13 +156,13 @@ public class LogAspect
|
||||
String params = "";
|
||||
if (paramsArray != null && paramsArray.length > 0)
|
||||
{
|
||||
for (int i = 0; i < paramsArray.length; i++)
|
||||
for (Object o : paramsArray)
|
||||
{
|
||||
if (StringUtils.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i]))
|
||||
if (StringUtils.isNotNull(o) && !isFilterObject(o))
|
||||
{
|
||||
try
|
||||
{
|
||||
Object jsonObj = JSON.toJSON(paramsArray[i]);
|
||||
Object jsonObj = JSON.toJSON(o);
|
||||
params += jsonObj.toString() + " ";
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -223,17 +191,17 @@ public class LogAspect
|
||||
else if (Collection.class.isAssignableFrom(clazz))
|
||||
{
|
||||
Collection collection = (Collection) o;
|
||||
for (Iterator iter = collection.iterator(); iter.hasNext();)
|
||||
for (Object value : collection)
|
||||
{
|
||||
return iter.next() instanceof MultipartFile;
|
||||
return value instanceof MultipartFile;
|
||||
}
|
||||
}
|
||||
else if (Map.class.isAssignableFrom(clazz))
|
||||
{
|
||||
Map map = (Map) o;
|
||||
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
|
||||
for (Object value : map.entrySet())
|
||||
{
|
||||
Map.Entry entry = (Map.Entry) iter.next();
|
||||
Map.Entry entry = (Map.Entry) value;
|
||||
return entry.getValue() instanceof MultipartFile;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.common.log.service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.system.api.RemoteLogService;
|
||||
import com.ruoyi.system.api.domain.SysOperLog;
|
||||
|
||||
@@ -23,6 +24,6 @@ public class AsyncLogService
|
||||
@Async
|
||||
public void saveSysLog(SysOperLog sysOperLog)
|
||||
{
|
||||
remoteLogService.saveLog(sysOperLog);
|
||||
remoteLogService.saveLog(sysOperLog, SecurityConstants.INNER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -74,6 +74,17 @@ public class RedisService
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public Boolean hasKey(String key)
|
||||
{
|
||||
return redisTemplate.hasKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.common.security.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 内部认证注解
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface InnerAuth
|
||||
{
|
||||
/**
|
||||
* 是否校验用户信息
|
||||
*/
|
||||
boolean isUser() default false;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.ruoyi.common.security.aspect;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.exception.InnerAuthException;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.security.annotation.InnerAuth;
|
||||
|
||||
/**
|
||||
* 内部服务调用验证处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class InnerAuthAspect implements Ordered
|
||||
{
|
||||
@Around("@annotation(innerAuth)")
|
||||
public Object innerAround(ProceedingJoinPoint point, InnerAuth innerAuth) throws Throwable
|
||||
{
|
||||
String source = ServletUtils.getRequest().getHeader(SecurityConstants.FROM_SOURCE);
|
||||
// 内部请求验证
|
||||
if (!StringUtils.equals(SecurityConstants.INNER, source))
|
||||
{
|
||||
throw new InnerAuthException("没有内部访问权限,不允许访问");
|
||||
}
|
||||
|
||||
String userid = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USER_ID);
|
||||
String username = ServletUtils.getRequest().getHeader(SecurityConstants.DETAILS_USERNAME);
|
||||
// 用户信息验证
|
||||
if (innerAuth.isUser() && (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)))
|
||||
{
|
||||
throw new InnerAuthException("没有设置用户信息,不允许访问 ");
|
||||
}
|
||||
return point.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保在权限认证aop执行前执行
|
||||
*/
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return Ordered.HIGHEST_PRECEDENCE + 1;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@ package com.ruoyi.common.security.feign;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import com.ruoyi.common.core.utils.ip.IpUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.ip.IpUtils;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
|
||||
@@ -26,20 +26,20 @@ public class FeignRequestInterceptor implements RequestInterceptor
|
||||
{
|
||||
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
|
||||
// 传递用户信息请求头,防止丢失
|
||||
String userId = headers.get(CacheConstants.DETAILS_USER_ID);
|
||||
String userId = headers.get(SecurityConstants.DETAILS_USER_ID);
|
||||
if (StringUtils.isNotEmpty(userId))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId);
|
||||
requestTemplate.header(SecurityConstants.DETAILS_USER_ID, userId);
|
||||
}
|
||||
String userName = headers.get(CacheConstants.DETAILS_USERNAME);
|
||||
String userName = headers.get(SecurityConstants.DETAILS_USERNAME);
|
||||
if (StringUtils.isNotEmpty(userName))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName);
|
||||
requestTemplate.header(SecurityConstants.DETAILS_USERNAME, userName);
|
||||
}
|
||||
String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER);
|
||||
String authentication = headers.get(SecurityConstants.AUTHORIZATION_HEADER);
|
||||
if (StringUtils.isNotEmpty(authentication))
|
||||
{
|
||||
requestTemplate.header(CacheConstants.AUTHORIZATION_HEADER, authentication);
|
||||
requestTemplate.header(SecurityConstants.AUTHORIZATION_HEADER, authentication);
|
||||
}
|
||||
|
||||
// 配置客户端IP
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package com.ruoyi.common.security.handler;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import com.ruoyi.common.core.exception.BaseException;
|
||||
import com.ruoyi.common.core.exception.CustomException;
|
||||
import com.ruoyi.common.core.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.exception.DemoModeException;
|
||||
import com.ruoyi.common.core.exception.InnerAuthException;
|
||||
import com.ruoyi.common.core.exception.PreAuthorizeException;
|
||||
import com.ruoyi.common.core.exception.ServiceException;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
|
||||
@@ -24,31 +27,58 @@ public class GlobalExceptionHandler
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
||||
|
||||
/**
|
||||
* 基础异常
|
||||
* 权限异常
|
||||
*/
|
||||
@ExceptionHandler(BaseException.class)
|
||||
public AjaxResult baseException(BaseException e)
|
||||
@ExceptionHandler(PreAuthorizeException.class)
|
||||
public AjaxResult handlePreAuthorizeException(PreAuthorizeException e, HttpServletRequest request)
|
||||
{
|
||||
return AjaxResult.error(e.getDefaultMessage());
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
|
||||
return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方式不支持
|
||||
*/
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
|
||||
HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(CustomException.class)
|
||||
public AjaxResult businessException(CustomException e)
|
||||
{
|
||||
if (StringUtils.isNull(e.getCode()))
|
||||
{
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
return AjaxResult.error(e.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public AjaxResult handleException(Exception e)
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
Integer code = e.getCode();
|
||||
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public AjaxResult handleException(Exception e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生系统异常.", requestURI, e);
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
@@ -56,7 +86,7 @@ public class GlobalExceptionHandler
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public AjaxResult validatedBindException(BindException e)
|
||||
public AjaxResult handleBindException(BindException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||
@@ -67,27 +97,27 @@ public class GlobalExceptionHandler
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Object validExceptionHandler(MethodArgumentNotValidException e)
|
||||
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getBindingResult().getFieldError().getDefaultMessage();
|
||||
return AjaxResult.error(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 权限异常
|
||||
* 内部认证异常
|
||||
*/
|
||||
@ExceptionHandler(PreAuthorizeException.class)
|
||||
public AjaxResult preAuthorizeException(PreAuthorizeException e)
|
||||
@ExceptionHandler(InnerAuthException.class)
|
||||
public AjaxResult handleInnerAuthException(InnerAuthException e)
|
||||
{
|
||||
return AjaxResult.error("没有权限,请联系管理员授权");
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 演示模式异常
|
||||
*/
|
||||
@ExceptionHandler(DemoModeException.class)
|
||||
public AjaxResult demoModeException(DemoModeException e)
|
||||
public AjaxResult handleDemoModeException(DemoModeException e)
|
||||
{
|
||||
return AjaxResult.error("演示模式,不允许操作");
|
||||
}
|
||||
|
||||
@@ -73,6 +73,16 @@ public class TokenService
|
||||
{
|
||||
// 获取请求携带的令牌
|
||||
String token = SecurityUtils.getToken(request);
|
||||
return getLoginUser(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户身份信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
public LoginUser getLoginUser(String token)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(token))
|
||||
{
|
||||
String userKey = getTokenKey(token);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.ruoyi.system.utils;
|
||||
package com.ruoyi.common.security.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -6,7 +6,7 @@ import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.utils.SpringUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
import com.ruoyi.system.domain.SysDictData;
|
||||
import com.ruoyi.system.api.domain.SysDictData;
|
||||
|
||||
/**
|
||||
* 字典工具类
|
||||
@@ -1,4 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.ruoyi.common.security.service.TokenService,\
|
||||
com.ruoyi.common.security.aspect.PreAuthorizeAspect,\
|
||||
com.ruoyi.common.security.aspect.InnerAuthAspect,\
|
||||
com.ruoyi.common.security.handler.GlobalExceptionHandler
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.ruoyi.gateway.config.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.captcha")
|
||||
public class CaptchaProperties
|
||||
{
|
||||
/**
|
||||
* 验证码开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 验证码类型(math 数组计算 char 字符)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "ignore")
|
||||
@ConfigurationProperties(prefix = "security.ignore")
|
||||
public class IgnoreWhiteProperties
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.ruoyi.gateway.config.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* XSS跨站脚本配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@RefreshScope
|
||||
@ConfigurationProperties(prefix = "security.xss")
|
||||
public class XssProperties
|
||||
{
|
||||
/**
|
||||
* Xss开关
|
||||
*/
|
||||
private Boolean enabled;
|
||||
|
||||
/**
|
||||
* 排除路径
|
||||
*/
|
||||
private List<String> excludeUrls = new ArrayList<>();
|
||||
|
||||
public Boolean getEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public List<String> getExcludeUrls()
|
||||
{
|
||||
return excludeUrls;
|
||||
}
|
||||
|
||||
public void setExcludeUrls(List<String> excludeUrls)
|
||||
{
|
||||
this.excludeUrls = excludeUrls;
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,16 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.constant.SecurityConstants;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
@@ -35,7 +32,7 @@ import reactor.core.publisher.Mono;
|
||||
public class AuthFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
|
||||
|
||||
|
||||
private final static long EXPIRE_TIME = Constants.TOKEN_EXPIRE * 60;
|
||||
|
||||
// 排除过滤的 uri 地址,nacos自行添加
|
||||
@@ -44,61 +41,75 @@ public class AuthFilter implements GlobalFilter, Ordered
|
||||
|
||||
@Resource(name = "stringRedisTemplate")
|
||||
private ValueOperations<String, String> sops;
|
||||
|
||||
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
String url = exchange.getRequest().getURI().getPath();
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpRequest.Builder mutate = request.mutate();
|
||||
|
||||
String url = request.getURI().getPath();
|
||||
// 跳过不需要验证的路径
|
||||
if (StringUtils.matches(url, ignoreWhite.getWhites()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
String token = getToken(exchange.getRequest());
|
||||
if (StringUtils.isBlank(token))
|
||||
String token = getToken(request);
|
||||
if (StringUtils.isEmpty(token))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "令牌不能为空");
|
||||
return unauthorizedResponse(exchange, "令牌不能为空");
|
||||
}
|
||||
String userStr = sops.get(getTokenKey(token));
|
||||
if (StringUtils.isNull(userStr))
|
||||
if (StringUtils.isEmpty(userStr))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "登录状态已过期");
|
||||
return unauthorizedResponse(exchange, "登录状态已过期");
|
||||
}
|
||||
JSONObject obj = JSONObject.parseObject(userStr);
|
||||
String userid = obj.getString("userid");
|
||||
String username = obj.getString("username");
|
||||
if (StringUtils.isBlank(userid) || StringUtils.isBlank(username))
|
||||
JSONObject cacheObj = JSONObject.parseObject(userStr);
|
||||
String userid = cacheObj.getString("userid");
|
||||
String username = cacheObj.getString("username");
|
||||
if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username))
|
||||
{
|
||||
return setUnauthorizedResponse(exchange, "令牌验证失败");
|
||||
return unauthorizedResponse(exchange, "令牌验证失败");
|
||||
}
|
||||
|
||||
|
||||
// 设置过期时间
|
||||
redisService.expire(getTokenKey(token), EXPIRE_TIME);
|
||||
// 设置用户信息到请求
|
||||
ServerHttpRequest mutableReq = exchange.getRequest().mutate().header(CacheConstants.DETAILS_USER_ID, userid)
|
||||
.header(CacheConstants.DETAILS_USERNAME, ServletUtils.urlEncode(username)).build();
|
||||
ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();
|
||||
|
||||
return chain.filter(mutableExchange);
|
||||
addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
|
||||
addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
|
||||
// 内部请求来源参数清除
|
||||
removeHeader(mutate, SecurityConstants.FROM_SOURCE);
|
||||
return chain.filter(exchange.mutate().request(mutate.build()).build());
|
||||
}
|
||||
|
||||
private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value)
|
||||
{
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
|
||||
return response.writeWith(Mono.fromSupplier(() -> {
|
||||
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||
return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
|
||||
}));
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
String valueStr = value.toString();
|
||||
String valueEncode = ServletUtils.urlEncode(valueStr);
|
||||
mutate.header(name, valueEncode);
|
||||
}
|
||||
|
||||
private void removeHeader(ServerHttpRequest.Builder mutate, String name)
|
||||
{
|
||||
mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
|
||||
}
|
||||
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
|
||||
{
|
||||
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存key
|
||||
*/
|
||||
private String getTokenKey(String token)
|
||||
{
|
||||
return CacheConstants.LOGIN_TOKEN_KEY + token;
|
||||
@@ -109,12 +120,8 @@ public class AuthFilter implements GlobalFilter, Ordered
|
||||
*/
|
||||
private String getToken(ServerHttpRequest request)
|
||||
{
|
||||
String token = request.getHeaders().getFirst(CacheConstants.HEADER);
|
||||
if (StringUtils.isNotEmpty(token) && token.startsWith(CacheConstants.TOKEN_PREFIX))
|
||||
{
|
||||
token = token.replace(CacheConstants.TOKEN_PREFIX, "");
|
||||
}
|
||||
return token;
|
||||
String token = request.getHeaders().getFirst(SecurityConstants.TOKEN_AUTHENTICATION);
|
||||
return SecurityUtils.replaceTokenPrefix(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,11 +5,8 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
import reactor.core.publisher.Mono;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
|
||||
/**
|
||||
* 黑名单过滤器
|
||||
@@ -27,10 +24,7 @@ public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUr
|
||||
String url = exchange.getRequest().getURI().getPath();
|
||||
if (config.matchBlacklist(url))
|
||||
{
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||
return exchange.getResponse().writeWith(
|
||||
Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error("请求地址不允许访问")))));
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
|
||||
}
|
||||
|
||||
return chain.filter(exchange);
|
||||
|
||||
@@ -16,6 +16,11 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 获取body请求数据(解决流不能重复读取问题)
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
|
||||
{
|
||||
|
||||
@@ -9,15 +9,13 @@ import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFac
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
import com.ruoyi.gateway.config.properties.CaptchaProperties;
|
||||
import com.ruoyi.gateway.service.ValidateCodeService;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 验证码过滤器
|
||||
@@ -27,11 +25,14 @@ import reactor.core.publisher.Mono;
|
||||
@Component
|
||||
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
|
||||
{
|
||||
private final static String AUTH_URL = "/auth/login";
|
||||
private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" };
|
||||
|
||||
@Autowired
|
||||
private ValidateCodeService validateCodeService;
|
||||
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
private static final String CODE = "code";
|
||||
|
||||
private static final String UUID = "uuid";
|
||||
@@ -42,8 +43,8 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
|
||||
return (exchange, chain) -> {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
|
||||
// 非登录请求,不处理
|
||||
if (!StringUtils.containsIgnoreCase(request.getURI().getPath(), AUTH_URL))
|
||||
// 非登录/注册请求或验证码关闭,不处理
|
||||
if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled())
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
@@ -56,10 +57,7 @@ public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||
return exchange.getResponse().writeWith(
|
||||
Mono.just(response.bufferFactory().wrap(JSON.toJSONBytes(AjaxResult.error(e.getMessage())))));
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
|
||||
}
|
||||
return chain.filter(exchange);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package com.ruoyi.gateway.filter;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.html.EscapeUtil;
|
||||
import com.ruoyi.gateway.config.properties.XssProperties;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* 跨站脚本过滤器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true")
|
||||
public class XssFilter implements GlobalFilter, Ordered
|
||||
{
|
||||
// 跨站脚本的 xss 配置,nacos自行添加
|
||||
@Autowired
|
||||
private XssProperties xss;
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||
{
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
// GET DELETE 不过滤
|
||||
HttpMethod method = request.getMethod();
|
||||
if (method == null || method.matches("GET") || method.matches("DELETE"))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// 非json类型,不过滤
|
||||
if (!isJsonRequest(exchange))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// excludeUrls 不过滤
|
||||
String url = request.getURI().getPath();
|
||||
if (StringUtils.matches(url, xss.getExcludeUrls()))
|
||||
{
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
|
||||
return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
|
||||
|
||||
}
|
||||
|
||||
private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange)
|
||||
{
|
||||
ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest())
|
||||
{
|
||||
@Override
|
||||
public Flux<DataBuffer> getBody()
|
||||
{
|
||||
Flux<DataBuffer> body = super.getBody();
|
||||
return body.map(dataBuffer -> {
|
||||
byte[] content = new byte[dataBuffer.readableByteCount()];
|
||||
dataBuffer.read(content);
|
||||
DataBufferUtils.release(dataBuffer);
|
||||
String bodyStr = new String(content, StandardCharsets.UTF_8);
|
||||
// 防xss攻击过滤
|
||||
bodyStr = EscapeUtil.clean(bodyStr);
|
||||
// 转成字节
|
||||
byte[] bytes = bodyStr.getBytes();
|
||||
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
|
||||
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
|
||||
buffer.write(bytes);
|
||||
return buffer;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders()
|
||||
{
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(super.getHeaders());
|
||||
// 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
|
||||
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
|
||||
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
|
||||
return httpHeaders;
|
||||
}
|
||||
|
||||
};
|
||||
return serverHttpRequestDecorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是Json请求
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
public boolean isJsonRequest(ServerWebExchange exchange)
|
||||
{
|
||||
String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder()
|
||||
{
|
||||
return -100;
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,10 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.ruoyi.common.core.domain.R;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
@@ -55,12 +51,6 @@ public class GatewayExceptionHandler implements ErrorWebExceptionHandler
|
||||
|
||||
log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
|
||||
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
|
||||
return response.writeWith(Mono.fromSupplier(() -> {
|
||||
DataBufferFactory bufferFactory = response.bufferFactory();
|
||||
return bufferFactory.wrap(JSON.toJSONBytes(R.fail(msg)));
|
||||
}));
|
||||
return ServletUtils.webFluxResponseWriter(response, msg);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.ruoyi.gateway.handler;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
@@ -19,11 +17,7 @@ public class SentinelFallbackHandler implements WebExceptionHandler
|
||||
{
|
||||
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
|
||||
{
|
||||
ServerHttpResponse serverHttpResponse = exchange.getResponse();
|
||||
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
|
||||
byte[] datas = "{\"code\":429,\"msg\":\"请求超过最大数,请稍后再试\"}".getBytes(StandardCharsets.UTF_8);
|
||||
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
|
||||
return serverHttpResponse.writeWith(Mono.just(buffer));
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍后再试");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.sign.Base64;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
import com.ruoyi.gateway.config.properties.CaptchaProperties;
|
||||
import com.ruoyi.gateway.service.ValidateCodeService;
|
||||
|
||||
/**
|
||||
@@ -35,8 +36,8 @@ public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||
@Autowired
|
||||
private RedisService redisService;
|
||||
|
||||
// 验证码类型
|
||||
private String captchaType = "math";
|
||||
@Autowired
|
||||
private CaptchaProperties captchaProperties;
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
@@ -44,6 +45,14 @@ public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||
@Override
|
||||
public AjaxResult createCapcha() throws IOException, CaptchaException
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
boolean captchaOnOff = captchaProperties.getEnabled();
|
||||
ajax.put("captchaOnOff", captchaOnOff);
|
||||
if (!captchaOnOff)
|
||||
{
|
||||
return ajax;
|
||||
}
|
||||
|
||||
// 保存验证码信息
|
||||
String uuid = IdUtils.simpleUUID();
|
||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
||||
@@ -51,6 +60,7 @@ public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||
String capStr = null, code = null;
|
||||
BufferedImage image = null;
|
||||
|
||||
String captchaType = captchaProperties.getType();
|
||||
// 生成验证码
|
||||
if ("math".equals(captchaType))
|
||||
{
|
||||
@@ -77,7 +87,6 @@ public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put("uuid", uuid);
|
||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||
return ajax;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
package com.ruoyi.file;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@EnableCustomSwagger2
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
public class RuoYFileApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(RuoYFileApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 文件服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
package com.ruoyi.file;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@EnableCustomSwagger2
|
||||
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
|
||||
public class RuoYiFileApplication
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
SpringApplication.run(RuoYiFileApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 文件服务模块启动成功 ლ(´ڡ`ლ)゙ \n" +
|
||||
" .-------. ____ __ \n" +
|
||||
" | _ _ \\ \\ \\ / / \n" +
|
||||
" | ( ' ) | \\ _. / ' \n" +
|
||||
" |(_ o _) / _( )_ .' \n" +
|
||||
" | (_,_).' __ ___(_ o _)' \n" +
|
||||
" | |\\ \\ | || |(_,_)' \n" +
|
||||
" | | \\ `' /| `-' / \n" +
|
||||
" | | \\ / \\ / \n" +
|
||||
" ''-' `'-' `-..-' ");
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.ruoyi.file.config;
|
||||
import java.io.File;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@@ -33,4 +34,17 @@ public class ResourcesConfig implements WebMvcConfigurer
|
||||
registry.addResourceHandler(localFilePrefix + "/**")
|
||||
.addResourceLocations("file:" + localFilePath + File.separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启跨域
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
// 设置允许跨域的路由
|
||||
registry.addMapping(localFilePrefix + "/**")
|
||||
// 设置允许跨域请求的域名
|
||||
.allowedOrigins("*")
|
||||
// 设置允许的方法
|
||||
.allowedMethods("GET");
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.velocity.Template;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
@@ -23,11 +24,10 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.constant.GenConstants;
|
||||
import com.ruoyi.common.core.exception.CustomException;
|
||||
import com.ruoyi.common.core.exception.ServiceException;
|
||||
import com.ruoyi.common.core.text.CharsetKit;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.file.FileUtils;
|
||||
import com.ruoyi.gen.domain.GenTable;
|
||||
import com.ruoyi.gen.domain.GenTableColumn;
|
||||
import com.ruoyi.gen.mapper.GenTableColumnMapper;
|
||||
@@ -180,7 +180,7 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new CustomException("导入失败:" + e.getMessage());
|
||||
throw new ServiceException("导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new CustomException("渲染模板失败,表名:" + table.getTableName());
|
||||
throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,7 +291,7 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
|
||||
if (StringUtils.isEmpty(dbTableColumns))
|
||||
{
|
||||
throw new CustomException("同步数据失败,原表结构不存在");
|
||||
throw new ServiceException("同步数据失败,原表结构不存在");
|
||||
}
|
||||
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
|
||||
|
||||
@@ -383,25 +383,25 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
JSONObject paramsObj = JSONObject.parseObject(options);
|
||||
if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
|
||||
{
|
||||
throw new CustomException("树编码字段不能为空");
|
||||
throw new ServiceException("树编码字段不能为空");
|
||||
}
|
||||
else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
|
||||
{
|
||||
throw new CustomException("树父编码字段不能为空");
|
||||
throw new ServiceException("树父编码字段不能为空");
|
||||
}
|
||||
else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
|
||||
{
|
||||
throw new CustomException("树名称字段不能为空");
|
||||
throw new ServiceException("树名称字段不能为空");
|
||||
}
|
||||
else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
|
||||
{
|
||||
if (StringUtils.isEmpty(genTable.getSubTableName()))
|
||||
{
|
||||
throw new CustomException("关联子表的表名不能为空");
|
||||
throw new ServiceException("关联子表的表名不能为空");
|
||||
}
|
||||
else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
|
||||
{
|
||||
throw new CustomException("子表关联的外键名不能为空");
|
||||
throw new ServiceException("子表关联的外键名不能为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ public class VelocityUtils
|
||||
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
|
||||
velocityContext.put("columns", genTable.getColumns());
|
||||
velocityContext.put("table", genTable);
|
||||
velocityContext.put("dicts", getDicts(genTable));
|
||||
setMenuVelocityContext(velocityContext, genTable);
|
||||
if (GenConstants.TPL_TREE.equals(tplCategory))
|
||||
{
|
||||
@@ -260,6 +261,27 @@ public class VelocityUtils
|
||||
return importList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列类型获取字典组
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 返回字典组
|
||||
*/
|
||||
public static String getDicts(GenTable genTable)
|
||||
{
|
||||
List<GenTableColumn> columns = genTable.getColumns();
|
||||
List<String> dicts = new ArrayList<String>();
|
||||
for (GenTableColumn column : columns)
|
||||
{
|
||||
if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
|
||||
column.getHtmlType(), new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO }))
|
||||
{
|
||||
dicts.add("'" + column.getDictType() + "'");
|
||||
}
|
||||
}
|
||||
return StringUtils.join(dicts, ", ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限前缀
|
||||
*
|
||||
@@ -280,7 +302,8 @@ public class VelocityUtils
|
||||
*/
|
||||
public static String getParentMenuId(JSONObject paramsObj)
|
||||
{
|
||||
if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID))
|
||||
if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
|
||||
&& StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
|
||||
{
|
||||
return paramsObj.getString(GenConstants.PARENT_MENU_ID);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
|
||||
AND date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<select id="selectDbTableListByNames" resultMap="GenTableResult">
|
||||
|
||||
@@ -78,7 +78,7 @@ public class ${ClassName}Controller extends BaseController
|
||||
@GetMapping(value = "/{${pkColumn.javaField}}")
|
||||
public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
|
||||
{
|
||||
return AjaxResult.success(${className}Service.select${ClassName}ById(${pkColumn.javaField}));
|
||||
return AjaxResult.success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,6 +111,6 @@ public class ${ClassName}Controller extends BaseController
|
||||
@DeleteMapping("/{${pkColumn.javaField}s}")
|
||||
public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
|
||||
{
|
||||
return toAjax(${className}Service.delete${ClassName}ByIds(${pkColumn.javaField}s));
|
||||
return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@ public interface ${ClassName}Mapper
|
||||
/**
|
||||
* 查询${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return ${functionName}
|
||||
*/
|
||||
public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
|
||||
/**
|
||||
* 查询${functionName}列表
|
||||
@@ -49,24 +49,24 @@ public interface ${ClassName}Mapper
|
||||
/**
|
||||
* 删除${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
|
||||
/**
|
||||
* 批量删除${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField}s 需要删除的数据ID
|
||||
* @param ${pkColumn.javaField}s 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s);
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
|
||||
#if($table.sub)
|
||||
|
||||
/**
|
||||
* 批量删除${subTable.functionName}
|
||||
*
|
||||
* @param customerIds 需要删除的数据ID
|
||||
* @param ${pkColumn.javaField}s 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
|
||||
@@ -81,7 +81,7 @@ public interface ${ClassName}Mapper
|
||||
|
||||
|
||||
/**
|
||||
* 通过${functionName}ID删除${subTable.functionName}信息
|
||||
* 通过${functionName}主键删除${subTable.functionName}信息
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @return 结果
|
||||
|
||||
@@ -14,10 +14,10 @@ public interface I${ClassName}Service
|
||||
/**
|
||||
* 查询${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return ${functionName}
|
||||
*/
|
||||
public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
|
||||
/**
|
||||
* 查询${functionName}列表
|
||||
@@ -46,16 +46,16 @@ public interface I${ClassName}Service
|
||||
/**
|
||||
* 批量删除${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField}s 需要删除的${functionName}ID
|
||||
* @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s);
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
|
||||
|
||||
/**
|
||||
* 删除${functionName}信息
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
|
||||
/**
|
||||
* 查询${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return ${functionName}
|
||||
*/
|
||||
@Override
|
||||
public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField})
|
||||
public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
|
||||
{
|
||||
return ${className}Mapper.select${ClassName}ById(${pkColumn.javaField});
|
||||
return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,34 +108,34 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
|
||||
/**
|
||||
* 批量删除${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField}s 需要删除的${functionName}ID
|
||||
* @param ${pkColumn.javaField}s 需要删除的${functionName}主键
|
||||
* @return 结果
|
||||
*/
|
||||
#if($table.sub)
|
||||
@Transactional
|
||||
#end
|
||||
@Override
|
||||
public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s)
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
|
||||
{
|
||||
#if($table.sub)
|
||||
${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
|
||||
#end
|
||||
return ${className}Mapper.delete${ClassName}ByIds(${pkColumn.javaField}s);
|
||||
return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除${functionName}信息
|
||||
*
|
||||
* @param ${pkColumn.javaField} ${functionName}ID
|
||||
* @param ${pkColumn.javaField} ${functionName}主键
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField})
|
||||
public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
|
||||
{
|
||||
#if($table.sub)
|
||||
${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
|
||||
#end
|
||||
return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField});
|
||||
return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
|
||||
}
|
||||
#if($table.sub)
|
||||
|
||||
@@ -147,7 +147,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
|
||||
public void insert${subClassName}(${ClassName} ${className})
|
||||
{
|
||||
List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
|
||||
Long ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
|
||||
${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
|
||||
if (StringUtils.isNotNull(${subclassName}List))
|
||||
{
|
||||
List<${subClassName}> list = new ArrayList<${subClassName}>();
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
|
||||
<el-option
|
||||
v-for="dict in ${column.javaField}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictLabel"
|
||||
:value="dict.dictValue"
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -106,7 +106,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $column.dictType)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" />
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $javaField)
|
||||
#if(${foreach.index} == 1)
|
||||
<el-table-column label="${comment}" prop="${javaField}" />
|
||||
@@ -180,10 +184,10 @@
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictLabel"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.dictValue)"#else:value="dict.dictValue"#end
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
|
||||
|
||||
></el-option>
|
||||
</el-select>
|
||||
@@ -198,10 +202,10 @@
|
||||
<el-form-item label="${comment}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictValue">
|
||||
{{dict.dictLabel}}
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.value">
|
||||
{{dict.label}}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
@@ -215,11 +219,11 @@
|
||||
<el-form-item label="${comment}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.dictValue)"#else:label="dict.dictValue"#end
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
|
||||
|
||||
>{{dict.dictLabel}}</el-radio>
|
||||
>{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && $dictType)
|
||||
@@ -258,46 +262,13 @@
|
||||
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
|
||||
import Treeselect from "@riophae/vue-treeselect";
|
||||
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
|
||||
import ImageUpload from '@/components/ImageUpload';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
|
||||
import Editor from '@/components/Editor';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
|
||||
export default {
|
||||
name: "${BusinessName}",
|
||||
#if(${dicts} != '')
|
||||
dicts: [${dicts}],
|
||||
#end
|
||||
components: {
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
|
||||
ImageUpload,
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
|
||||
FileUpload,
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
|
||||
Editor,
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
Treeselect
|
||||
},
|
||||
data() {
|
||||
@@ -315,16 +286,7 @@ export default {
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
#foreach ($column in $columns)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if(${column.dictType} != '')
|
||||
// $comment字典
|
||||
${column.javaField}Options: [],
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
// $comment时间范围
|
||||
daterange${AttrName}: [],
|
||||
@@ -362,13 +324,6 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
this.getDicts("${column.dictType}").then(response => {
|
||||
this.${column.javaField}Options = response.data;
|
||||
});
|
||||
#end
|
||||
#end
|
||||
},
|
||||
methods: {
|
||||
/** 查询${functionName}列表 */
|
||||
@@ -414,20 +369,6 @@ export default {
|
||||
this.${businessName}Options.push(data);
|
||||
});
|
||||
},
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
// $comment字典翻译
|
||||
${column.javaField}Format(row, column) {
|
||||
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
|
||||
},
|
||||
#end
|
||||
#end
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
@@ -507,13 +448,13 @@ export default {
|
||||
#end
|
||||
if (this.form.${pkColumn.javaField} != null) {
|
||||
update${BusinessName}(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.#[[$modal]]#.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
add${BusinessName}(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.#[[$modal]]#.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
@@ -523,16 +464,12 @@ export default {
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
this.$confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return del${BusinessName}(row.${pkColumn.javaField});
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
|
||||
return del${BusinessName}(row.${pkColumn.javaField});
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.#[[$modal]]#.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
|
||||
<el-option
|
||||
v-for="dict in ${column.javaField}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictLabel"
|
||||
:value="dict.dictValue"
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -134,7 +134,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $column.dictType)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" />
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $javaField)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" />
|
||||
#end
|
||||
@@ -201,10 +205,10 @@
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictLabel"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.dictValue)"#else:value="dict.dictValue"#end
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
|
||||
|
||||
></el-option>
|
||||
</el-select>
|
||||
@@ -219,10 +223,10 @@
|
||||
<el-form-item label="${comment}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
:label="dict.dictValue">
|
||||
{{dict.dictLabel}}
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.value">
|
||||
{{dict.label}}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
@@ -236,11 +240,11 @@
|
||||
<el-form-item label="${comment}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio
|
||||
v-for="dict in ${field}Options"
|
||||
:key="dict.dictValue"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.dictValue)"#else:label="dict.dictValue"#end
|
||||
v-for="dict in dict.type.${dictType}"
|
||||
:key="dict.value"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
|
||||
|
||||
>{{dict.dictLabel}}</el-radio>
|
||||
>{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && $dictType)
|
||||
@@ -309,47 +313,12 @@
|
||||
|
||||
<script>
|
||||
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
|
||||
import ImageUpload from '@/components/ImageUpload';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
|
||||
import FileUpload from '@/components/FileUpload';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
|
||||
import Editor from '@/components/Editor';
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
|
||||
export default {
|
||||
name: "${BusinessName}",
|
||||
components: {
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
|
||||
ImageUpload,
|
||||
#break
|
||||
#if(${dicts} != '')
|
||||
dicts: [${dicts}],
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
|
||||
FileUpload,
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
|
||||
Editor,
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
@@ -379,16 +348,7 @@ export default {
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
#foreach ($column in $columns)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if(${column.dictType} != '')
|
||||
// $comment字典
|
||||
${column.javaField}Options: [],
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
// $comment时间范围
|
||||
daterange${AttrName}: [],
|
||||
@@ -428,13 +388,6 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
this.getDicts("${column.dictType}").then(response => {
|
||||
this.${column.javaField}Options = response.data;
|
||||
});
|
||||
#end
|
||||
#end
|
||||
},
|
||||
methods: {
|
||||
/** 查询${functionName}列表 */
|
||||
@@ -461,20 +414,6 @@ export default {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
// $comment字典翻译
|
||||
${column.javaField}Format(row, column) {
|
||||
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
|
||||
},
|
||||
#end
|
||||
#end
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false;
|
||||
@@ -561,13 +500,13 @@ export default {
|
||||
#end
|
||||
if (this.form.${pkColumn.javaField} != null) {
|
||||
update${BusinessName}(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.#[[$modal]]#.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
} else {
|
||||
add${BusinessName}(this.form).then(response => {
|
||||
this.msgSuccess("新增成功");
|
||||
this.#[[$modal]]#.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
@@ -578,16 +517,12 @@ export default {
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
|
||||
this.$confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(function() {
|
||||
return del${BusinessName}(${pkColumn.javaField}s);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
|
||||
return del${BusinessName}(${pkColumn.javaField}s);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.#[[$modal]]#.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
#if($table.sub)
|
||||
/** ${subTable.functionName}序号 */
|
||||
@@ -608,19 +543,18 @@ export default {
|
||||
/** ${subTable.functionName}删除按钮操作 */
|
||||
handleDelete${subClassName}() {
|
||||
if (this.checked${subClassName}.length == 0) {
|
||||
this.$alert("请先选择要删除的${subTable.functionName}数据", "提示", { confirmButtonText: "确定", });
|
||||
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
|
||||
} else {
|
||||
this.${subclassName}List.splice(this.checked${subClassName}[0].index - 1, 1);
|
||||
const ${subclassName}List = this.${subclassName}List;
|
||||
const checked${subClassName} = this.checked${subClassName};
|
||||
this.${subclassName}List = ${subclassName}List.filter(function(item) {
|
||||
return checked${subClassName}.indexOf(item.index) == -1
|
||||
});
|
||||
}
|
||||
},
|
||||
/** 单选框选中数据 */
|
||||
/** 复选框选中数据 */
|
||||
handle${subClassName}SelectionChange(selection) {
|
||||
if (selection.length > 1) {
|
||||
this.$refs.${subclassName}.clearSelection();
|
||||
this.$refs.${subclassName}.toggleRowSelection(selection.pop());
|
||||
} else {
|
||||
this.checked${subClassName} = selection;
|
||||
}
|
||||
this.checked${subClassName} = selection.map(item => item.index)
|
||||
},
|
||||
#end
|
||||
/** 导出按钮操作 */
|
||||
|
||||
@@ -58,7 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
|
||||
<select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
|
||||
#if($table.crud || $table.tree)
|
||||
<include refid="select${ClassName}Vo"/>
|
||||
where ${pkColumn.columnName} = #{${pkColumn.javaField}}
|
||||
@@ -102,11 +102,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
where ${pkColumn.columnName} = #{${pkColumn.javaField}}
|
||||
</update>
|
||||
|
||||
<delete id="delete${ClassName}ById" parameterType="${pkColumn.javaType}">
|
||||
<delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
|
||||
delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
|
||||
</delete>
|
||||
|
||||
<delete id="delete${ClassName}ByIds" parameterType="String">
|
||||
<delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
|
||||
delete from ${tableName} where ${pkColumn.columnName} in
|
||||
<foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
|
||||
#{${pkColumn.javaField}}
|
||||
@@ -121,7 +121,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="delete${subClassName}By${subTableFkClassName}" parameterType="Long">
|
||||
<delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}">
|
||||
delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
|
||||
</delete>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -13,8 +13,10 @@ 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 com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.exception.job.TaskException;
|
||||
import com.ruoyi.common.core.utils.SecurityUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.web.controller.BaseController;
|
||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||
@@ -79,14 +81,26 @@ public class SysJobController extends BaseController
|
||||
@PreAuthorize(hasPermi = "monitor:job:add")
|
||||
@Log(title = "定时任务", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
|
||||
public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
|
||||
{
|
||||
if (!CronUtils.isValid(sysJob.getCronExpression()))
|
||||
if (!CronUtils.isValid(job.getCronExpression()))
|
||||
{
|
||||
return AjaxResult.error("cron表达式不正确");
|
||||
return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
|
||||
}
|
||||
sysJob.setCreateBy(SecurityUtils.getUsername());
|
||||
return toAjax(jobService.insertJob(sysJob));
|
||||
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
|
||||
{
|
||||
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用");
|
||||
}
|
||||
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP))
|
||||
{
|
||||
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用");
|
||||
}
|
||||
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
|
||||
{
|
||||
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");
|
||||
}
|
||||
job.setCreateBy(SecurityUtils.getUsername());
|
||||
return toAjax(jobService.insertJob(job));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,14 +109,26 @@ public class SysJobController extends BaseController
|
||||
@PreAuthorize(hasPermi = "monitor:job:edit")
|
||||
@Log(title = "定时任务", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysJob sysJob) throws SchedulerException, TaskException
|
||||
public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
|
||||
{
|
||||
if (!CronUtils.isValid(sysJob.getCronExpression()))
|
||||
if (!CronUtils.isValid(job.getCronExpression()))
|
||||
{
|
||||
return AjaxResult.error("cron表达式不正确");
|
||||
return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
|
||||
}
|
||||
sysJob.setUpdateBy(SecurityUtils.getUsername());
|
||||
return toAjax(jobService.updateJob(sysJob));
|
||||
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
|
||||
{
|
||||
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用");
|
||||
}
|
||||
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP))
|
||||
{
|
||||
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用");
|
||||
}
|
||||
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
|
||||
{
|
||||
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");
|
||||
}
|
||||
job.setUpdateBy(SecurityUtils.getUsername());
|
||||
return toAjax(jobService.updateJob(job));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int pauseJob(SysJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
@@ -94,7 +94,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int resumeJob(SysJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
@@ -114,7 +114,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int deleteJob(SysJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
@@ -134,7 +134,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteJobByIds(Long[] jobIds) throws SchedulerException
|
||||
{
|
||||
for (Long jobId : jobIds)
|
||||
@@ -150,7 +150,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int changeStatus(SysJob job) throws SchedulerException
|
||||
{
|
||||
int rows = 0;
|
||||
@@ -172,7 +172,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void run(SysJob job) throws SchedulerException
|
||||
{
|
||||
Long jobId = job.getJobId();
|
||||
@@ -190,7 +190,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int insertJob(SysJob job) throws SchedulerException, TaskException
|
||||
{
|
||||
job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
|
||||
@@ -208,7 +208,7 @@ public class SysJobServiceImpl implements ISysJobService
|
||||
* @param job 调度信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int updateJob(SysJob job) throws SchedulerException, TaskException
|
||||
{
|
||||
SysJob properties = selectJobById(job.getJobId());
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.2.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user