upgrade to v3.8.2

This commit is contained in:
shaingsense 2022-05-09 12:48:40 +08:00
parent 581ddfd527
commit 9e96ccf463
295 changed files with 35182 additions and 34590 deletions

View File

@ -45,6 +45,8 @@ https://gitee.com/whiteshader/images/raw/master/demo.mp4
## 前端开发注意事项 ## 前端开发注意事项
安装依赖yarn
正常启动请运行: npm run start:dev 正常启动请运行: npm run start:dev
Mock测试模式请运行: npm run start Mock测试模式请运行: npm run start

View File

@ -1,6 +1,6 @@
@echo off @echo off
echo. echo.
echo [信息] 清理工程target生成路径。 echo [信息] 清理工程target生成路径。
echo. echo.
%~d0 %~d0

View File

@ -1,6 +1,6 @@
@echo off @echo off
echo. echo.
echo [信息] 使用Jar命令运行Web工程。 echo [信息] 使用Jar命令运行Web工程。
echo. echo.
cd %~dp0 cd %~dp0

30
pom.xml
View File

@ -6,14 +6,14 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.8.0</version> <version>3.8.2</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依管理系统</description> <description>若依管理系统</description>
<properties> <properties>
<ruoyi.version>3.8.0</ruoyi.version> <ruoyi.version>3.8.2</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
@ -22,18 +22,17 @@
<bitwalker.version>1.21</bitwalker.version> <bitwalker.version>1.21</bitwalker.version>
<swagger.version>3.0.0</swagger.version> <swagger.version>3.0.0</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version> <kaptcha.version>2.3.2</kaptcha.version>
<mybatis-spring-boot.version>2.2.0</mybatis-spring-boot.version> <mybatis-spring-boot.version>2.2.2</mybatis-spring-boot.version>
<pagehelper.boot.version>1.4.0</pagehelper.boot.version> <pagehelper.boot.version>1.4.1</pagehelper.boot.version>
<fastjson.version>1.2.78</fastjson.version> <fastjson.version>1.2.80</fastjson.version>
<oshi.version>5.8.2</oshi.version> <oshi.version>6.1.2</oshi.version>
<jna.version>5.9.0</jna.version> <jna.version>5.10.0</jna.version>
<commons.io.version>2.11.0</commons.io.version> <commons.io.version>2.11.0</commons.io.version>
<commons.fileupload.version>1.4</commons.fileupload.version> <commons.fileupload.version>1.4</commons.fileupload.version>
<commons.collections.version>3.2.2</commons.collections.version> <commons.collections.version>3.2.2</commons.collections.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version> <jwt.version>0.9.1</jwt.version>
<log4j2.version>2.16.0</log4j2.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
@ -44,7 +43,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>2.5.6</version> <version>2.5.13</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -151,19 +150,6 @@
<version>${fastjson.version}</version> <version>${fastjson.version}</version>
</dependency> </dependency>
<!-- log4j日志组件 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- Token生成与解析--> <!-- Token生成与解析-->
<dependency> <dependency>
<groupId>io.jsonwebtoken</groupId> <groupId>io.jsonwebtoken</groupId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,7 @@
package com.ruoyi.web.controller.common; package com.ruoyi.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -8,6 +10,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
@ -24,6 +27,7 @@ import com.ruoyi.framework.config.ServerConfig;
* @author ruoyi * @author ruoyi
*/ */
@RestController @RestController
@RequestMapping("/common")
public class CommonController public class CommonController
{ {
private static final Logger log = LoggerFactory.getLogger(CommonController.class); private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@ -31,13 +35,15 @@ public class CommonController
@Autowired @Autowired
private ServerConfig serverConfig; private ServerConfig serverConfig;
private static final String FILE_DELIMETER = ",";
/** /**
* 通用下载请求 * 通用下载请求
* *
* @param fileName 文件名称 * @param fileName 文件名称
* @param delete 是否删除 * @param delete 是否删除
*/ */
@GetMapping("common/download") @GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{ {
try try
@ -64,9 +70,9 @@ public class CommonController
} }
/** /**
* 通用上传请求 * 通用上传请求单个
*/ */
@PostMapping("/common/upload") @PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception public AjaxResult uploadFile(MultipartFile file) throws Exception
{ {
try try
@ -77,8 +83,47 @@ public class CommonController
String fileName = FileUploadUtils.upload(filePath, file); String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName; String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("fileName", fileName);
ajax.put("url", url); ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求多个
*/
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
return ajax; return ajax;
} }
catch (Exception e) catch (Exception e)
@ -90,7 +135,7 @@ public class CommonController
/** /**
* 本地资源通用下载 * 本地资源通用下载
*/ */
@GetMapping("/common/download/resource") @GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception throws Exception
{ {

View File

@ -125,16 +125,17 @@ public class SysDeptController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept) public AjaxResult edit(@Validated @RequestBody SysDept dept)
{ {
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{ {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
else if (dept.getParentId().equals(dept.getDeptId())) else if (dept.getParentId().equals(deptId))
{ {
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
} }
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
&& deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0)
{ {
return AjaxResult.error("该部门包含未停用的子部门!"); return AjaxResult.error("该部门包含未停用的子部门!");
} }
@ -158,6 +159,7 @@ public class SysDeptController extends BaseController
{ {
return AjaxResult.error("部门存在用户,不允许删除"); return AjaxResult.error("部门存在用户,不允许删除");
} }
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId)); return toAjax(deptService.deleteDeptById(deptId));
} }
} }

View File

@ -111,6 +111,7 @@ public class SysRoleController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysRole role) public AjaxResult edit(@Validated @RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
{ {
return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); return AjaxResult.error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
@ -145,6 +146,7 @@ public class SysRoleController extends BaseController
public AjaxResult dataScope(@RequestBody SysRole role) public AjaxResult dataScope(@RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
return toAjax(roleService.authDataScope(role)); return toAjax(roleService.authDataScope(role));
} }
@ -157,6 +159,7 @@ public class SysRoleController extends BaseController
public AjaxResult changeStatus(@RequestBody SysRole role) public AjaxResult changeStatus(@RequestBody SysRole role)
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
role.setUpdateBy(getUsername()); role.setUpdateBy(getUsername());
return toAjax(roleService.updateRoleStatus(role)); return toAjax(roleService.updateRoleStatus(role));
} }
@ -236,6 +239,7 @@ public class SysRoleController extends BaseController
@PutMapping("/authUser/selectAll") @PutMapping("/authUser/selectAll")
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
{ {
roleService.checkRoleDataScope(roleId);
return toAjax(roleService.insertAuthUsers(roleId, userIds)); return toAjax(roleService.insertAuthUsers(roleId, userIds));
} }
} }

View File

@ -104,9 +104,10 @@ public class SysUserController extends BaseController
ajax.put("posts", postService.selectPostAll()); ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {
ajax.put(AjaxResult.DATA_TAG, userService.selectUserById(userId)); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", roleService.selectRoleListByUserId(userId)); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
return ajax; return ajax;
} }
@ -147,6 +148,7 @@ public class SysUserController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysUser user) public AjaxResult edit(@Validated @RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
if (StringUtils.isNotEmpty(user.getPhonenumber()) if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
@ -185,6 +187,7 @@ public class SysUserController extends BaseController
public AjaxResult resetPwd(@RequestBody SysUser user) public AjaxResult resetPwd(@RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
user.setUpdateBy(getUsername()); user.setUpdateBy(getUsername());
return toAjax(userService.resetPwd(user)); return toAjax(userService.resetPwd(user));
@ -199,6 +202,7 @@ public class SysUserController extends BaseController
public AjaxResult changeStatus(@RequestBody SysUser user) public AjaxResult changeStatus(@RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setUpdateBy(getUsername()); user.setUpdateBy(getUsername());
return toAjax(userService.updateUserStatus(user)); return toAjax(userService.updateUserStatus(user));
} }
@ -226,6 +230,7 @@ public class SysUserController extends BaseController
@PutMapping("/authRole") @PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds) public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{ {
userService.checkUserDataScope(userId);
userService.insertUserAuth(userId, roleIds); userService.insertUserAuth(userId, roleIds);
return success(); return success();
} }

View File

@ -3,9 +3,9 @@ ruoyi:
# 名称 # 名称
name: RuoYi name: RuoYi
# 版本 # 版本
version: 3.8.0 version: 3.8.2
# 版权年份 # 版权年份
copyrightYear: 2021 copyrightYear: 2022
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -5,6 +5,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.ruoyi.common.utils.poi.ExcelHandlerAdapter; import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
/** /**
@ -56,11 +58,6 @@ public @interface Excel
*/ */
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出类型0数字 1字符串
*/
public ColumnType cellType() default ColumnType.STRING;
/** /**
* 导出时在excel中每个列的高度 单位为字符 * 导出时在excel中每个列的高度 单位为字符
*/ */
@ -107,9 +104,19 @@ public @interface Excel
public boolean isStatistics() default false; public boolean isStatistics() default false;
/** /**
* 导出字段对齐方式0默认1靠左2居中3靠右 * 导出类型0数字 1字符串
*/ */
public Align align() default Align.AUTO; public ColumnType cellType() default ColumnType.STRING;
/**
* 导出字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
/** /**
* 自定义数据处理器 * 自定义数据处理器

View File

@ -142,16 +142,26 @@ public class Constants
/** /**
* RMI 远程方法调用 * RMI 远程方法调用
*/ */
public static final String LOOKUP_RMI = "rmi://"; public static final String LOOKUP_RMI = "rmi:";
/** /**
* LDAP 远程方法调用 * LDAP 远程方法调用
*/ */
public static final String LOOKUP_LDAP = "ldap://"; public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 定时任务白名单配置仅允许访问的包名如其他需要可以自行添加
*/
public static final String[] JOB_WHITELIST_STR = { "com.ruoyi" };
/** /**
* 定时任务违规的字符 * 定时任务违规的字符
*/ */
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework.jndi" }; "org.springframework", "org.apache", "com.ruoyi.common.utils.file" };
} }

View File

@ -109,6 +109,9 @@ public class GenConstants
/** 模糊查询 */ /** 模糊查询 */
public static final String QUERY_LIKE = "LIKE"; public static final String QUERY_LIKE = "LIKE";
/** 相等查询 */
public static final String QUERY_EQ = "EQ";
/** 需要 */ /** 需要 */
public static final String REQUIRE = "1"; public static final String REQUIRE = "1";
} }

View File

@ -16,6 +16,7 @@ import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.page.TableSupport; import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sql.SqlUtil; import com.ruoyi.common.utils.sql.SqlUtil;
@ -51,15 +52,7 @@ public class BaseController
*/ */
protected void startPage() protected void startPage()
{ {
PageDomain pageDomain = TableSupport.buildPageRequest(); PageUtils.startPage();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
} }
/** /**
@ -75,6 +68,14 @@ public class BaseController
} }
} }
/**
* 清理分页的线程变量
*/
protected void clearPage()
{
PageUtils.clearPage();
}
/** /**
* 响应请求分页数据 * 响应请求分页数据
*/ */

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.Email; import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -31,7 +32,7 @@ public class SysDept extends BaseEntity
private String deptName; private String deptName;
/** 显示顺序 */ /** 显示顺序 */
private String orderNum; private Integer orderNum;
/** 负责人 */ /** 负责人 */
private String leader; private String leader;
@ -96,13 +97,13 @@ public class SysDept extends BaseEntity
this.deptName = deptName; this.deptName = deptName;
} }
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
public String getOrderNum() public Integer getOrderNum()
{ {
return orderNum; return orderNum;
} }
public void setOrderNum(String orderNum) public void setOrderNum(Integer orderNum)
{ {
this.orderNum = orderNum; this.orderNum = orderNum;
} }

View File

@ -1,6 +1,7 @@
package com.ruoyi.common.core.domain.entity; package com.ruoyi.common.core.domain.entity;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -57,6 +58,7 @@ public class SysDictType extends BaseEntity
@NotBlank(message = "字典类型不能为空") @NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
@Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
public String getDictType() public String getDictType()
{ {
return dictType; return dictType;

View File

@ -3,6 +3,7 @@ package com.ruoyi.common.core.domain.entity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
@ -30,7 +31,7 @@ public class SysMenu extends BaseEntity
private Long parentId; private Long parentId;
/** 显示顺序 */ /** 显示顺序 */
private String orderNum; private Integer orderNum;
/** 路由地址 */ /** 路由地址 */
private String path; private String path;
@ -107,13 +108,13 @@ public class SysMenu extends BaseEntity
this.parentId = parentId; this.parentId = parentId;
} }
@NotBlank(message = "显示顺序不能为空") @NotNull(message = "显示顺序不能为空")
public String getOrderNum() public Integer getOrderNum()
{ {
return orderNum; return orderNum;
} }
public void setOrderNum(String orderNum) public void setOrderNum(Integer orderNum)
{ {
this.orderNum = orderNum; this.orderNum = orderNum;
} }

View File

@ -25,7 +25,7 @@ public class LoginBody
/** /**
* 唯一标识 * 唯一标识
*/ */
private String uuid = ""; private String uuid;
public String getUsername() public String getUsername()
{ {

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.core.page; package com.ruoyi.common.core.page;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
/** /**
@ -40,8 +41,8 @@ public class TableSupport
public static PageDomain getPageDomain() public static PageDomain getPageDomain()
{ {
PageDomain pageDomain = new PageDomain(); PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM)); pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE)); pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN)); pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC)); pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE)); pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));

View File

@ -213,12 +213,12 @@ public class RedisCache
* 删除Hash中的数据 * 删除Hash中的数据
* *
* @param key * @param key
* @param mapkey * @param hKey
*/ */
public void delCacheMapValue(final String key, final String hkey) public void delCacheMapValue(final String key, final String hKey)
{ {
HashOperations hashOperations = redisTemplate.opsForHash(); HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hkey); hashOperations.delete(key, hKey);
} }
/** /**

View File

@ -3,6 +3,11 @@ package com.ruoyi.common.utils;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Date; import java.util.Date;
import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateFormatUtils;
@ -131,6 +136,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return new Date(time); return new Date(time);
} }
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/** /**
* 计算两个时间差 * 计算两个时间差
*/ */
@ -152,4 +165,23 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
// long sec = diff % nd % nh % nm / ns; // long sec = diff % nd % nh % nm / ns;
return day + "" + hour + "小时" + min + "分钟"; return day + "" + hour + "小时" + min + "分钟";
} }
/**
* 增加 LocalDateTime ==> Date
*/
public static Date toDate(LocalDateTime temporalAccessor)
{
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
/**
* 增加 LocalDate ==> Date
*/
public static Date toDate(LocalDate temporalAccessor)
{
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
return Date.from(zdt.toInstant());
}
} }

View File

@ -41,8 +41,7 @@ public class DictUtils
Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj)) if (StringUtils.isNotNull(cacheObj))
{ {
List<SysDictData> dictDatas = StringUtils.cast(cacheObj); return StringUtils.cast(cacheObj);
return dictDatas;
} }
return null; return null;
} }
@ -92,7 +91,7 @@ public class DictUtils
{ {
if (value.equals(dict.getDictValue())) if (value.equals(dict.getDictValue()))
{ {
propertyString.append(dict.getDictLabel() + separator); propertyString.append(dict.getDictLabel()).append(separator);
break; break;
} }
} }
@ -132,7 +131,7 @@ public class DictUtils
{ {
if (label.equals(dict.getDictLabel())) if (label.equals(dict.getDictLabel()))
{ {
propertyString.append(dict.getDictValue() + separator); propertyString.append(dict.getDictValue()).append(separator);
break; break;
} }
} }

View File

@ -18,8 +18,7 @@ public class ExceptionUtil
{ {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw, true)); e.printStackTrace(new PrintWriter(sw, true));
String str = sw.toString(); return sw.toString();
return str;
} }
public static String getRootErrorMessage(Exception e) public static String getRootErrorMessage(Exception e)

View File

@ -0,0 +1,35 @@
package com.ruoyi.common.utils;
import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.utils.sql.SqlUtil;
/**
* 分页工具类
*
* @author ruoyi
*/
public class PageUtils extends PageHelper
{
/**
* 设置请求分页数据
*/
public static void startPage()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
/**
* 清理分页的线程变量
*/
public static void clearPage()
{
PageHelper.clearPage();
}
}

View File

@ -99,9 +99,8 @@ public class ServletUtils
* *
* @param response 渲染对象 * @param response 渲染对象
* @param string 待渲染的字符串 * @param string 待渲染的字符串
* @return null
*/ */
public static String renderString(HttpServletResponse response, String string) public static void renderString(HttpServletResponse response, String string)
{ {
try try
{ {
@ -114,7 +113,6 @@ public class ServletUtils
{ {
e.printStackTrace(); e.printStackTrace();
} }
return null;
} }
/** /**
@ -125,13 +123,13 @@ public class ServletUtils
public static boolean isAjaxRequest(HttpServletRequest request) public static boolean isAjaxRequest(HttpServletRequest request)
{ {
String accept = request.getHeader("accept"); String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1) if (accept != null && accept.contains("application/json"))
{ {
return true; return true;
} }
String xRequestedWith = request.getHeader("X-Requested-With"); String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
{ {
return true; return true;
} }
@ -143,10 +141,6 @@ public class ServletUtils
} }
String ajax = request.getParameter("__ajax"); String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
{
return true;
}
return false;
} }
} }

View File

@ -531,4 +531,53 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
{ {
return (T) obj; return (T) obj;
} }
/**
* 数字左边补齐0使之达到指定长度注意如果数字转换为字符串后长度大于size则只保留 最后size个字符
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式该字符串为指定长度
*/
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐如果原始字符串s长度大于size则只保留最后size个字符
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串由原字符串左补齐或截取得到
*/
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
} }

View File

@ -2,6 +2,8 @@ package com.ruoyi.common.utils.file;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
@ -11,7 +13,7 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException; import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.common.utils.uuid.Seq;
/** /**
* 文件上传工具类 * 文件上传工具类
@ -100,7 +102,7 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException InvalidExtensionException
{ {
int fileNamelength = file.getOriginalFilename().length(); int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{ {
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
@ -110,10 +112,9 @@ public class FileUploadUtils
String fileName = extractFilename(file); String fileName = extractFilename(file);
File desc = getAbsoluteFile(baseDir, fileName); String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(desc); file.transferTo(Paths.get(absPath));
String pathFileName = getPathFileName(baseDir, fileName); return getPathFileName(baseDir, fileName);
return pathFileName;
} }
/** /**
@ -121,10 +122,8 @@ public class FileUploadUtils
*/ */
public static final String extractFilename(MultipartFile file) public static final String extractFilename(MultipartFile file)
{ {
String fileName = file.getOriginalFilename(); return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
String extension = getExtension(file); FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
return fileName;
} }
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
@ -145,8 +144,7 @@ public class FileUploadUtils
{ {
int dirLastIndex = RuoYiConfig.getProfile().length() + 1; int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex); String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
return pathFileName;
} }
/** /**
@ -161,7 +159,7 @@ public class FileUploadUtils
throws FileSizeLimitExceededException, InvalidExtensionException throws FileSizeLimitExceededException, InvalidExtensionException
{ {
long size = file.getSize(); long size = file.getSize();
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) if (size > DEFAULT_MAX_SIZE)
{ {
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
} }
@ -228,7 +226,7 @@ public class FileUploadUtils
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (StringUtils.isEmpty(extension)) if (StringUtils.isEmpty(extension))
{ {
extension = MimeTypeUtils.getExtension(file.getContentType()); extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
} }
return extension; return extension;
} }

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils; import com.ruoyi.common.utils.uuid.IdUtils;
import org.apache.commons.io.FilenameUtils;
/** /**
* 文件处理工具类 * 文件处理工具类
@ -196,7 +197,6 @@ public class FileUtils
* *
* @param response 响应对象 * @param response 响应对象
* @param realFileName 真实文件名 * @param realFileName 真实文件名
* @return
*/ */
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
{ {
@ -210,7 +210,6 @@ public class FileUtils
.append("utf-8''") .append("utf-8''")
.append(percentEncodedFileName); .append(percentEncodedFileName);
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
response.setHeader("Content-disposition", contentDispositionValue.toString()); response.setHeader("Content-disposition", contentDispositionValue.toString());
response.setHeader("download-filename", percentEncodedFileName); response.setHeader("download-filename", percentEncodedFileName);
@ -256,4 +255,39 @@ public class FileUtils
} }
return strFileExtendName; return strFileExtendName;
} }
/**
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
*
* @param fileName 路径名称
* @return 没有文件路径的名称
*/
public static String getName(String fileName)
{
if (fileName == null)
{
return null;
}
int lastUnixPos = fileName.lastIndexOf('/');
int lastWindowsPos = fileName.lastIndexOf('\\');
int index = Math.max(lastUnixPos, lastWindowsPos);
return fileName.substring(index + 1);
}
/**
* 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
*
* @param fileName 路径名称
* @return 没有文件路径和后缀的名称
*/
public static String getNameNotSuffix(String fileName)
{
if (fileName == null)
{
return null;
}
String baseName = FilenameUtils.getBaseName(fileName);
return baseName;
}
} }

View File

@ -1,7 +1,6 @@
package com.ruoyi.common.utils.file; package com.ruoyi.common.utils.file;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@ -59,13 +58,12 @@ public class ImageUtils
/** /**
* 读取文件为字节数据 * 读取文件为字节数据
* *
* @param key 地址 * @param url 地址
* @return 字节数据 * @return 字节数据
*/ */
public static byte[] readFile(String url) public static byte[] readFile(String url)
{ {
InputStream in = null; InputStream in = null;
ByteArrayOutputStream baos = null;
try try
{ {
if (url.startsWith("http")) if (url.startsWith("http"))
@ -95,7 +93,6 @@ public class ImageUtils
finally finally
{ {
IOUtils.closeQuietly(in); IOUtils.closeQuietly(in);
IOUtils.closeQuietly(baos);
} }
} }
} }

View File

@ -4,7 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.StandardCharsets;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -25,7 +25,7 @@ public class HttpHelper
BufferedReader reader = null; BufferedReader reader = null;
try (InputStream inputStream = request.getInputStream()) try (InputStream inputStream = request.getInputStream())
{ {
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = ""; String line = "";
while ((line = reader.readLine()) != null) while ((line = reader.readLine()) != null)
{ {

View File

@ -9,6 +9,7 @@ import java.net.ConnectException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -130,9 +131,8 @@ public class HttpUtils
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
try try
{ {
String urlNameString = url; log.info("sendPost - {}", url);
log.info("sendPost - {}", urlNameString); URL realUrl = new URL(url);
URL realUrl = new URL(urlNameString);
URLConnection conn = realUrl.openConnection(); URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
@ -144,7 +144,7 @@ public class HttpUtils
out = new PrintWriter(conn.getOutputStream()); out = new PrintWriter(conn.getOutputStream());
out.print(param); out.print(param);
out.flush(); out.flush();
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
String line; String line;
while ((line = in.readLine()) != null) while ((line = in.readLine()) != null)
{ {
@ -218,7 +218,7 @@ public class HttpUtils
{ {
if (ret != null && !"".equals(ret.trim())) if (ret != null && !"".equals(ret.trim()))
{ {
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
} }
} }
log.info("recv - {}", result); log.info("recv - {}", result);

View File

@ -25,7 +25,6 @@ public class AddressUtils
public static String getRealAddressByIP(String ip) public static String getRealAddressByIP(String ip)
{ {
String address = UNKNOWN;
// 内网不查询 // 内网不查询
if (IpUtils.internalIp(ip)) if (IpUtils.internalIp(ip))
{ {
@ -51,6 +50,6 @@ public class AddressUtils
log.error("获取地理位置异常 {}", ip); log.error("获取地理位置异常 {}", ip);
} }
} }
return address; return UNKNOWN;
} }
} }

View File

@ -4,7 +4,6 @@ import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.html.EscapeUtil;
/** /**
* 获取IP方法 * 获取IP方法
@ -13,6 +12,12 @@ import com.ruoyi.common.utils.html.EscapeUtil;
*/ */
public class IpUtils public class IpUtils
{ {
/**
* 获取客户端IP
*
* @param request 请求对象
* @return IP地址
*/
public static String getIpAddr(HttpServletRequest request) public static String getIpAddr(HttpServletRequest request)
{ {
if (request == null) if (request == null)
@ -41,15 +46,28 @@ public class IpUtils
{ {
ip = request.getRemoteAddr(); ip = request.getRemoteAddr();
} }
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : EscapeUtil.clean(ip);
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
} }
/**
* 检查是否为内部IP地址
*
* @param ip IP地址
* @return 结果
*/
public static boolean internalIp(String ip) public static boolean internalIp(String ip)
{ {
byte[] addr = textToNumericFormatV4(ip); byte[] addr = textToNumericFormatV4(ip);
return internalIp(addr) || "127.0.0.1".equals(ip); return internalIp(addr) || "127.0.0.1".equals(ip);
} }
/**
* 检查是否为内部IP地址
*
* @param addr byte地址
* @return 结果
*/
private static boolean internalIp(byte[] addr) private static boolean internalIp(byte[] addr)
{ {
if (StringUtils.isNull(addr) || addr.length < 2) if (StringUtils.isNull(addr) || addr.length < 2)
@ -110,7 +128,8 @@ public class IpUtils
{ {
case 1: case 1:
l = Long.parseLong(elements[0]); l = Long.parseLong(elements[0]);
if ((l < 0L) || (l > 4294967295L)) { if ((l < 0L) || (l > 4294967295L))
{
return null; return null;
} }
bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[0] = (byte) (int) (l >> 24 & 0xFF);
@ -120,12 +139,14 @@ public class IpUtils
break; break;
case 2: case 2:
l = Integer.parseInt(elements[0]); l = Integer.parseInt(elements[0]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[0] = (byte) (int) (l & 0xFF); bytes[0] = (byte) (int) (l & 0xFF);
l = Integer.parseInt(elements[1]); l = Integer.parseInt(elements[1]);
if ((l < 0L) || (l > 16777215L)) { if ((l < 0L) || (l > 16777215L))
{
return null; return null;
} }
bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[1] = (byte) (int) (l >> 16 & 0xFF);
@ -136,13 +157,15 @@ public class IpUtils
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
} }
l = Integer.parseInt(elements[2]); l = Integer.parseInt(elements[2]);
if ((l < 0L) || (l > 65535L)) { if ((l < 0L) || (l > 65535L))
{
return null; return null;
} }
bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[2] = (byte) (int) (l >> 8 & 0xFF);
@ -152,7 +175,8 @@ public class IpUtils
for (i = 0; i < 4; ++i) for (i = 0; i < 4; ++i)
{ {
l = Integer.parseInt(elements[i]); l = Integer.parseInt(elements[i]);
if ((l < 0L) || (l > 255L)) { if ((l < 0L) || (l > 255L))
{
return null; return null;
} }
bytes[i] = (byte) (int) (l & 0xFF); bytes[i] = (byte) (int) (l & 0xFF);
@ -169,6 +193,11 @@ public class IpUtils
return bytes; return bytes;
} }
/**
* 获取IP地址
*
* @return 本地IP地址
*/
public static String getHostIp() public static String getHostIp()
{ {
try try
@ -181,6 +210,11 @@ public class IpUtils
return "127.0.0.1"; return "127.0.0.1";
} }
/**
* 获取主机名
*
* @return 本地主机名
*/
public static String getHostName() public static String getHostName()
{ {
try try
@ -192,4 +226,39 @@ public class IpUtils
} }
return "未知"; return "未知";
} }
/**
* 从多级反向代理中获得第一个非unknown IP地址
*
* @param ip 获得的IP地址
* @return 第一个非unknown IP地址
*/
public static String getMultistageReverseProxyIp(String ip)
{
// 多级反向代理检测
if (ip != null && ip.indexOf(",") > 0)
{
final String[] ips = ip.trim().split(",");
for (String subIp : ips)
{
if (false == isUnknown(subIp))
{
ip = subIp;
break;
}
}
}
return ip;
}
/**
* 检测给定字符串是否为未知多用于检测HTTP请求相关
*
* @param checkString 被检测的字符串
* @return 是否未知
*/
public static boolean isUnknown(String checkString)
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
} }

View File

@ -9,6 +9,8 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@ -20,6 +22,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.RegExUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture; import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData; import org.apache.poi.hssf.usermodel.HSSFPictureData;
@ -86,6 +89,10 @@ public class ExcelUtil<T>
{ {
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/** /**
* Excel sheet最大行数默认65536 * Excel sheet最大行数默认65536
*/ */
@ -312,7 +319,7 @@ public class ExcelUtil<T>
String dateFormat = field.getAnnotation(Excel.class).dateFormat(); String dateFormat = field.getAnnotation(Excel.class).dateFormat();
if (StringUtils.isNotEmpty(dateFormat)) if (StringUtils.isNotEmpty(dateFormat))
{ {
val = DateUtils.parseDateToStr(dateFormat, (Date) val); val = parseDateToStr(dateFormat, val);
} }
else else
{ {
@ -324,7 +331,7 @@ public class ExcelUtil<T>
{ {
val = Convert.toInt(val); val = Convert.toInt(val);
} }
else if (Long.TYPE == fieldType || Long.class == fieldType) else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
{ {
val = Convert.toLong(val); val = Convert.toLong(val);
} }
@ -429,7 +436,6 @@ public class ExcelUtil<T>
* @param list 导出数据集合 * @param list 导出数据集合
* @param sheetName 工作表的名称 * @param sheetName 工作表的名称
* @return 结果 * @return 结果
* @throws IOException
*/ */
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
{ {
@ -444,7 +450,6 @@ public class ExcelUtil<T>
* @param sheetName 工作表的名称 * @param sheetName 工作表的名称
* @param title 标题 * @param title 标题
* @return 结果 * @return 结果
* @throws IOException
*/ */
public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
{ {
@ -667,21 +672,6 @@ public class ExcelUtil<T>
style.setFont(totalFont); style.setFont(totalFont);
styles.put("total", style); styles.put("total", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.LEFT);
styles.put("data1", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
styles.put("data2", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.RIGHT);
styles.put("data3", style);
return styles; return styles;
} }
@ -710,7 +700,13 @@ public class ExcelUtil<T>
{ {
if (ColumnType.STRING == attr.cellType()) if (ColumnType.STRING == attr.cellType())
{ {
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); String cellValue = Convert.toStr(value);
// 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入
if (StringUtils.startsWithAny(cellValue, FORMULA_STR))
{
cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
}
cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
} }
else if (ColumnType.NUMERIC == attr.cellType()) else if (ColumnType.NUMERIC == attr.cellType())
{ {
@ -775,17 +771,10 @@ public class ExcelUtil<T>
// 设置列宽 // 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
} }
// 如果设置了提示信息则鼠标放上去提示. if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0)
if (StringUtils.isNotEmpty(attr.prompt()))
{ {
// 这里默认设了2-101列提示. // 提示信息或只能选择不能输入的列内容.
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column);
}
// 如果设置了combo属性则本列只能选择不能输入
if (attr.combo().length > 0)
{
// 这里默认设了2-101列只能选择不能输入.
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
} }
} }
@ -804,8 +793,7 @@ public class ExcelUtil<T>
{ {
// 创建cell // 创建cell
cell = row.createCell(column); cell = row.createCell(column);
int align = attr.align().value(); setDataCell(cell, attr);
cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : "")));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@ -815,7 +803,7 @@ public class ExcelUtil<T>
String dictType = attr.dictType(); String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); cell.setCellValue(parseDateToStr(dateFormat, value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{ {
@ -849,48 +837,57 @@ public class ExcelUtil<T>
} }
/** /**
* 设置 POI XSSFSheet 单元格提示 * 设置单元格样式
*
* @param cell 单元格
* @param excel 注解信息
*/
public void setDataCell(Cell cell, Excel excel)
{
CellStyle 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);
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setAlignment(excel.align());
Font dataFont = wb.createFont();
dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10);
dataFont.setColor(excel.color().index);
style.setFont(dataFont);
cell.setCellStyle(style);
}
/**
* 设置 POI XSSFSheet 单元格提示或选择框
* *
* @param sheet 表单 * @param sheet 表单
* @param promptTitle 提示标题 * @param textlist 下拉框显示的内容
* @param promptContent 提示内容 * @param promptContent 提示内容
* @param firstRow 开始行 * @param firstRow 开始行
* @param endRow 结束行 * @param endRow 结束行
* @param firstCol 开始列 * @param firstCol 开始列
* @param endCol 结束列 * @param endCol 结束列
*/ */
public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,
int firstCol, int endCol) int firstCol, int endCol)
{ {
DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationHelper helper = sheet.getDataValidationHelper();
DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1");
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
DataValidation dataValidation = helper.createValidation(constraint, regions); DataValidation dataValidation = helper.createValidation(constraint, regions);
dataValidation.createPromptBox(promptTitle, promptContent); if (StringUtils.isNotEmpty(promptContent))
dataValidation.setShowPromptBox(true);
sheet.addValidationData(dataValidation);
}
/**
* 设置某些列的值只能输入预制的数据,显示下拉框.
*
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param firstRow 开始行
* @param endRow 结束行
* @param firstCol 开始列
* @param endCol 结束列
* @return 设置好的sheet.
*/
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
{ {
DataValidationHelper helper = sheet.getDataValidationHelper(); // 如果设置了提示信息则鼠标放上去提示
// 加载下拉列表内容 dataValidation.createPromptBox("", promptContent);
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); dataValidation.setShowPromptBox(true);
// 设置数据有效性加载在哪个单元格上,四个参数分别是起始行终止行起始列终止列 }
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
DataValidation dataValidation = helper.createValidation(constraint, regions);
// 处理Excel兼容性问题 // 处理Excel兼容性问题
if (dataValidation instanceof XSSFDataValidation) if (dataValidation instanceof XSSFDataValidation)
{ {
@ -901,7 +898,6 @@ public class ExcelUtil<T>
{ {
dataValidation.setSuppressDropDownArrow(false); dataValidation.setSuppressDropDownArrow(false);
} }
sheet.addValidationData(dataValidation); sheet.addValidationData(dataValidation);
} }
@ -1113,7 +1109,7 @@ public class ExcelUtil<T>
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
String target = excel.targetAttr(); String target = excel.targetAttr();
if (target.indexOf(".") > -1) if (target.contains("."))
{ {
String[] targets = target.split("[.]"); String[] targets = target.split("[.]");
for (String name : targets) for (String name : targets)
@ -1208,7 +1204,7 @@ public class ExcelUtil<T>
for (Object[] os : this.fields) for (Object[] os : this.fields)
{ {
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
maxHeight = maxHeight > excel.height() ? maxHeight : excel.height(); maxHeight = Math.max(maxHeight, excel.height());
} }
return (short) (maxHeight * 20); return (short) (maxHeight * 20);
} }
@ -1388,4 +1384,37 @@ public class ExcelUtil<T>
} }
return sheetIndexPicMap; return sheetIndexPicMap;
} }
/**
* 格式化不同类型的日期对象
*
* @param dateFormat 日期格式
* @param val 被格式化的日期对象
* @return 格式化后的日期字符
*/
public String parseDateToStr(String dateFormat, Object val)
{
if (val == null)
{
return "";
}
String str;
if (val instanceof Date)
{
str = DateUtils.parseDateToStr(dateFormat, (Date) val);
}
else if (val instanceof LocalDateTime)
{
str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));
}
else if (val instanceof LocalDate)
{
str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));
}
else
{
str = val.toString();
}
return str;
}
} }

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.utils.sign; package com.ruoyi.common.utils.sign;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,7 +56,7 @@ public class Md5Utils
{ {
try try
{ {
return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8"); return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -10,6 +10,11 @@ import com.ruoyi.common.utils.StringUtils;
*/ */
public class SqlUtil public class SqlUtil
{ {
/**
* 定义常用的 sql关键字
*/
public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
/** /**
* 仅支持字母数字下划线空格逗号小数点支持多个字段排序 * 仅支持字母数字下划线空格逗号小数点支持多个字段排序
*/ */
@ -34,4 +39,23 @@ public class SqlUtil
{ {
return value.matches(SQL_PATTERN); return value.matches(SQL_PATTERN);
} }
/**
* SQL关键字检查
*/
public static void filterKeyword(String value)
{
if (StringUtils.isEmpty(value))
{
return;
}
String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
for (String sqlKeyword : sqlKeywords)
{
if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
{
throw new UtilException("参数存在SQL注入风险");
}
}
}
} }

View File

@ -0,0 +1,86 @@
package com.ruoyi.common.utils.uuid;
import java.util.concurrent.atomic.AtomicInteger;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
/**
* @author ruoyi 序列生成类
*/
public class Seq
{
// 通用序列类型
public static final String commSeqType = "COMMON";
// 上传序列类型
public static final String uploadSeqType = "UPLOAD";
// 通用接口序列数
private static AtomicInteger commSeq = new AtomicInteger(1);
// 上传接口序列数
private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识
private static String machineCode = "A";
/**
* 获取通用序列号
*
* @return 序列值
*/
public static String getId()
{
return getId(commSeqType);
}
/**
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
*
* @return 序列值
*/
public static String getId(String type)
{
AtomicInteger atomicInt = commSeq;
if (uploadSeqType.equals(type))
{
atomicInt = uploadSeq;
}
return getId(atomicInt, 3);
}
/**
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
*
* @param atomicInt 序列数
* @param length 数值长度
* @return 序列值
*/
public static String getId(AtomicInteger atomicInt, int length)
{
String result = DateUtils.dateTimeNow();
result += machineCode;
result += getSeq(atomicInt, length);
return result;
}
/**
* 序列循环递增字符串[1, 10 (length)幂次方), 用0左补齐length位数
*
* @return 序列值
*/
private synchronized static String getSeq(AtomicInteger atomicInt, int length)
{
// 先取值再+1
int value = atomicInt.getAndIncrement();
// 如果更新后值>=10 (length)幂次方则重置为1
int maxSeq = (int) Math.pow(10, length);
if (atomicInt.get() >= maxSeq)
{
atomicInt.set(1);
}
// 转字符串用0左补齐
return StringUtils.padl(value, length);
}
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.xss; package com.ruoyi.common.xss;
import com.ruoyi.common.utils.StringUtils;
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -12,15 +13,19 @@ import java.util.regex.Pattern;
*/ */
public class XssValidator implements ConstraintValidator<Xss, String> public class XssValidator implements ConstraintValidator<Xss, String>
{ {
private final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
@Override @Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
{ {
if (StringUtils.isBlank(value))
{
return true;
}
return !containsHtml(value); return !containsHtml(value);
} }
public boolean containsHtml(String value) public static boolean containsHtml(String value)
{ {
Pattern pattern = Pattern.compile(HTML_PATTERN); Pattern pattern = Pattern.compile(HTML_PATTERN);
Matcher matcher = pattern.matcher(value); Matcher matcher = pattern.matcher(value);

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -65,7 +65,6 @@ public class LogAspect
{ {
try try
{ {
// 获取当前的用户 // 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser(); LoginUser loginUser = SecurityUtils.getLoginUser();

View File

@ -1,13 +1,13 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import java.util.concurrent.ScheduledExecutorService; import com.ruoyi.common.utils.Threads;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.ruoyi.common.utils.Threads; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/** /**
* 线程池配置 * 线程池配置
@ -49,7 +49,8 @@ public class ThreadPoolConfig
protected ScheduledExecutorService scheduledExecutorService() protected ScheduledExecutorService scheduledExecutorService()
{ {
return new ScheduledThreadPoolExecutor(corePoolSize, return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
new ThreadPoolExecutor.CallerRunsPolicy())
{ {
@Override @Override
protected void afterExecute(Runnable r, Throwable t) protected void afterExecute(Runnable r, Throwable t)

View File

@ -60,14 +60,10 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
String url = request.getRequestURI(); String url = request.getRequestURI();
// 唯一值没有消息头则使用请求地址 // 唯一值没有消息头则使用请求地址
String submitKey = request.getHeader(header); String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
if (StringUtils.isEmpty(submitKey))
{
submitKey = url;
}
// 唯一标识指定key + 消息头 // 唯一标识指定key + url + 消息头
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey; String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey;
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey); Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
if (sessionObj != null) if (sessionObj != null)

View File

@ -119,4 +119,12 @@ public class Jvm
{ {
return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate()); return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
} }
/**
* 运行参数
*/
public String getInputArgs()
{
return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
}
} }

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils; import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.AsyncManager;
@ -102,7 +103,7 @@ public class SysLoginService
*/ */
public void validateCaptcha(String username, String code, String uuid) public void validateCaptcha(String username, String code, String uuid)
{ {
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = Constants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey); String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey); redisCache.deleteObject(verifyKey);
if (captcha == null) if (captcha == null)

View File

@ -100,7 +100,7 @@ public class SysRegisterService
*/ */
public void validateCaptcha(String username, String code, String uuid) public void validateCaptcha(String username, String code, String uuid)
{ {
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String verifyKey = Constants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey); String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey); redisCache.deleteObject(verifyKey);
if (captcha == null) if (captcha == null)

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -59,12 +59,12 @@ public class GenController extends BaseController
* 修改代码生成业务 * 修改代码生成业务
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:query')") @PreAuthorize("@ss.hasPermi('tool:gen:query')")
@GetMapping(value = "/{talbleId}") @GetMapping(value = "/{tableId}")
public AjaxResult getInfo(@PathVariable Long talbleId) public AjaxResult getInfo(@PathVariable Long tableId)
{ {
GenTable table = genTableService.selectGenTableById(talbleId); GenTable table = genTableService.selectGenTableById(tableId);
List<GenTable> tables = genTableService.selectGenTableAll(); List<GenTable> tables = genTableService.selectGenTableAll();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId); List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table); map.put("info", table);
map.put("rows", list); map.put("rows", list);
@ -88,7 +88,7 @@ public class GenController extends BaseController
* 查询数据表字段列表 * 查询数据表字段列表
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:list')") @PreAuthorize("@ss.hasPermi('tool:gen:list')")
@GetMapping(value = "/column/{talbleId}") @GetMapping(value = "/column/{tableId}")
public TableDataInfo columnList(Long tableId) public TableDataInfo columnList(Long tableId)
{ {
TableDataInfo dataInfo = new TableDataInfo(); TableDataInfo dataInfo = new TableDataInfo();

View File

@ -7,6 +7,7 @@ import java.io.StringWriter;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -286,7 +287,7 @@ public class GenTableServiceImpl implements IGenTableService
{ {
GenTable table = genTableMapper.selectGenTableByName(tableName); GenTable table = genTableMapper.selectGenTableByName(tableName);
List<GenTableColumn> tableColumns = table.getColumns(); List<GenTableColumn> tableColumns = table.getColumns();
List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
if (StringUtils.isEmpty(dbTableColumns)) if (StringUtils.isEmpty(dbTableColumns))
@ -296,9 +297,29 @@ public class GenTableServiceImpl implements IGenTableService
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
dbTableColumns.forEach(column -> { dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName()))
{
GenUtils.initColumnField(column, table); GenUtils.initColumnField(column, table);
if (tableColumnMap.containsKey(column.getColumnName()))
{
GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
column.setColumnId(prevColumn.getColumnId());
if (column.isList())
{
// 如果是列表继续保留查询方式/字典类型选项
column.setDictType(prevColumn.getDictType());
column.setQueryType(prevColumn.getQueryType());
}
if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
&& (column.isInsert() || column.isEdit())
&& ((column.isUsableColumn()) || (!column.isSuperColumn())))
{
// 如果是(新增/修改&非主键/非忽略及父属性)继续保留必填/显示类型选项
column.setIsRequired(prevColumn.getIsRequired());
column.setHtmlType(prevColumn.getHtmlType());
}
genTableColumnMapper.updateGenTableColumn(column);
}
else
{
genTableColumnMapper.insertGenTableColumn(column); genTableColumnMapper.insertGenTableColumn(column);
} }
}); });

View File

@ -42,6 +42,7 @@ public class GenUtils
column.setJavaField(StringUtils.toCamelCase(columnName)); column.setJavaField(StringUtils.toCamelCase(columnName));
// 设置默认类型 // 设置默认类型
column.setJavaType(GenConstants.TYPE_STRING); column.setJavaType(GenConstants.TYPE_STRING);
column.setQueryType(GenConstants.QUERY_EQ);
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
{ {
@ -151,8 +152,7 @@ public class GenUtils
{ {
int lastIndex = packageName.lastIndexOf("."); int lastIndex = packageName.lastIndexOf(".");
int nameLength = packageName.length(); int nameLength = packageName.length();
String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); return StringUtils.substring(packageName, lastIndex + 1, nameLength);
return moduleName;
} }
/** /**
@ -165,8 +165,7 @@ public class GenUtils
{ {
int lastIndex = tableName.lastIndexOf("_"); int lastIndex = tableName.lastIndexOf("_");
int nameLength = tableName.length(); int nameLength = tableName.length();
String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); return StringUtils.substring(tableName, lastIndex + 1, nameLength);
return businessName;
} }
/** /**

View File

@ -3,6 +3,7 @@ package com.ruoyi.generator.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.apache.velocity.VelocityContext; import org.apache.velocity.VelocityContext;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.constant.GenConstants;
@ -227,8 +228,7 @@ public class VelocityUtils
public static String getPackagePrefix(String packageName) public static String getPackagePrefix(String packageName)
{ {
int lastIndex = packageName.lastIndexOf("."); int lastIndex = packageName.lastIndexOf(".");
String basePackage = StringUtils.substring(packageName, 0, lastIndex); return StringUtils.substring(packageName, 0, lastIndex);
return basePackage;
} }
/** /**
@ -270,7 +270,24 @@ public class VelocityUtils
public static String getDicts(GenTable genTable) public static String getDicts(GenTable genTable)
{ {
List<GenTableColumn> columns = genTable.getColumns(); List<GenTableColumn> columns = genTable.getColumns();
List<String> dicts = new ArrayList<String>(); Set<String> dicts = new HashSet<String>();
addDicts(dicts, columns);
if (StringUtils.isNotNull(genTable.getSubTable()))
{
List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
addDicts(dicts, subColumns);
}
return StringUtils.join(dicts, ", ");
}
/**
* 添加字典列表
*
* @param dicts 字典列表
* @param columns 列集合
*/
public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
{
for (GenTableColumn column : columns) for (GenTableColumn column : columns)
{ {
if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
@ -280,7 +297,6 @@ public class VelocityUtils
dicts.add("'" + column.getDictType() + "'"); dicts.add("'" + column.getDictType() + "'");
} }
} }
return StringUtils.join(dicts, ", ");
} }
/** /**

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -51,7 +50,6 @@
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -80,14 +78,24 @@
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-sort"
size="mini"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -105,6 +113,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope"> <template slot-scope="scope">
@ -174,11 +188,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -238,7 +252,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -289,6 +303,10 @@ export default {
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
open: false, open: false,
// 是否展开,默认全部展开
isExpandAll: true,
// 重新渲染表格状态
refreshTable: true,
#foreach ($column in $columns) #foreach ($column in $columns)
#if($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)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -419,6 +437,14 @@ export default {
this.open = true; this.open = true;
this.title = "添加${functionName}"; this.title = "添加${functionName}";
}, },
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns) #foreach($column in $columns)
#if($column.query) #if($column.query)
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in dict.type.${dictType}" v-for="dict in dict.type.${dictType}"
:key="dict.value" :key="dict.value"
@ -34,24 +33,23 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
type="daterange" type="daterange"
@ -133,6 +131,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template slot-scope="scope"> <template slot-scope="scope">
@ -195,11 +199,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -259,11 +263,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "textarea") #elseif($column.htmlType == "textarea")
@ -296,12 +300,39 @@
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#if($column.pk || $javaField == ${subTableFkclassName}) #if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && $column.htmlType == "input")
<el-table-column label="$comment" prop="${javaField}"> <el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
<el-table-column label="$comment" prop="${javaField}" width="240">
<template slot-scope="scope">
<el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option
v-for="dict in dict.type.$column.dictType"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template slot-scope="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option label="请选择字典生成" value="" />
</el-select>
</template>
</el-table-column>
#end #end
#end #end
</el-table> </el-table>

View File

@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
@ -34,13 +33,13 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@ -48,11 +47,9 @@
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}" style="width: 308px">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
type="daterange" type="daterange"
range-separator="-" range-separator="-"
@ -64,8 +61,8 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -75,19 +72,27 @@
type="primary" type="primary"
plain plain
icon="Plus" icon="Plus"
size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="Sort"
@click="toggleExpandAll"
>展开/折叠</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
v-if="refreshTable"
v-loading="loading" v-loading="loading"
:data="${businessName}List" :data="${businessName}List"
row-key="${treeCode}" row-key="${treeCode}"
default-expand-all :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
#foreach($column in $columns) #foreach($column in $columns)
@ -105,6 +110,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template #default="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope"> <template #default="scope">
@ -126,21 +137,18 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
size="mini"
type="text" type="text"
icon="Edit" icon="Edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Plus" icon="Plus"
@click="handleAdd(scope.row)" @click="handleAdd(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Delete" icon="Delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
@ -166,11 +174,13 @@
#set($dictType=$column.dictType) #set($dictType=$column.dictType)
#if("" != $treeParentCode && $column.javaField == $treeParentCode) #if("" != $treeParentCode && $column.javaField == $treeParentCode)
<el-form-item label="${comment}" prop="${treeParentCode}"> <el-form-item label="${comment}" prop="${treeParentCode}">
<tree-select <el-tree-select
v-model:value="form.${treeParentCode}" v-model="form.${treeParentCode}"
:options="${businessName}Options" :data="${businessName}Options"
:objMap="{ value: '${treeCode}', label: '${treeName}', children: 'children' }" :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
value-key="${treeCode}"
placeholder="请选择${comment}" placeholder="请选择${comment}"
check-strictly
/> />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "input") #elseif($column.htmlType == "input")
@ -179,11 +189,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -243,7 +253,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@ -284,6 +294,8 @@ const open = ref(false);
const loading = ref(true); const loading = ref(true);
const showSearch = ref(true); const showSearch = ref(true);
const title = ref(""); const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
#foreach ($column in $columns) #foreach ($column in $columns)
#if($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)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
@ -344,8 +356,8 @@ function getList() {
} }
/** 查询${functionName}下拉树结构 */ /** 查询${functionName}下拉树结构 */
async function getTreeselect() { function getTreeselect() {
await list${BusinessName}().then(response => { list${BusinessName}().then(response => {
${businessName}Options.value = []; ${businessName}Options.value = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
@ -394,9 +406,9 @@ function resetQuery() {
} }
/** 新增按钮操作 */ /** 新增按钮操作 */
async function handleAdd(row) { function handleAdd(row) {
reset(); reset();
await getTreeselect(); getTreeselect();
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeCode}; form.value.${treeParentCode} = row.${treeCode};
} else { } else {
@ -406,6 +418,15 @@ async function handleAdd(row) {
title.value = "添加${functionName}"; title.value = "添加${functionName}";
} }
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true;
});
}
/** 修改按钮操作 */ /** 修改按钮操作 */
async function handleUpdate(row) { async function handleUpdate(row) {
reset(); reset();

View File

@ -17,13 +17,12 @@
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
placeholder="请输入${comment}" placeholder="请输入${comment}"
clearable clearable
size="small"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option <el-option
v-for="dict in ${dictType}" v-for="dict in ${dictType}"
:key="dict.value" :key="dict.value"
@ -34,25 +33,23 @@
</el-form-item> </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small"> <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}"> <el-form-item label="${comment}" style="width: 308px">
<el-date-picker <el-date-picker
v-model="daterange${AttrName}" v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
type="daterange" type="daterange"
range-separator="-" range-separator="-"
@ -64,8 +61,8 @@
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -75,7 +72,6 @@
type="primary" type="primary"
plain plain
icon="Plus" icon="Plus"
size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
@ -85,7 +81,6 @@
type="success" type="success"
plain plain
icon="Edit" icon="Edit"
size="mini"
:disabled="single" :disabled="single"
@click="handleUpdate" @click="handleUpdate"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
@ -96,7 +91,6 @@
type="danger" type="danger"
plain plain
icon="Delete" icon="Delete"
size="mini"
:disabled="multiple" :disabled="multiple"
@click="handleDelete" @click="handleDelete"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${moduleName}:${businessName}:remove']"
@ -107,7 +101,6 @@
type="warning" type="warning"
plain plain
icon="Download" icon="Download"
size="mini"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button> >导出</el-button>
@ -133,6 +126,12 @@
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
<template #default="scope">
<image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}"> <el-table-column label="${comment}" align="center" prop="${javaField}">
<template #default="scope"> <template #default="scope">
@ -150,14 +149,12 @@
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button <el-button
size="mini"
type="text" type="text"
icon="Edit" icon="Edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini"
type="text" type="text"
icon="Delete" icon="Delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
@ -170,8 +167,8 @@
<pagination <pagination
v-show="total>0" v-show="total>0"
:total="total" :total="total"
v-model:p:page="queryParams.pageNum" v-model:page="queryParams.pageNum"
v-model:p:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
@ -195,11 +192,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "imageUpload") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<imageUpload v-model="form.${field}"/> <image-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "fileUpload") #elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/> <file-upload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -259,11 +256,11 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" <el-date-picker clearable
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "textarea") #elseif($column.htmlType == "textarea")
@ -278,10 +275,10 @@
<el-divider content-position="center">${subTable.functionName}信息</el-divider> <el-divider content-position="center">${subTable.functionName}信息</el-divider>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" icon="Plus" size="mini" @click="handleAdd${subClassName}">添加</el-button> <el-button type="primary" icon="Plus" @click="handleAdd${subClassName}">添加</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" icon="Delete" size="mini" @click="handleDelete${subClassName}">删除</el-button> <el-button type="danger" icon="Delete" @click="handleDelete${subClassName}">删除</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}"> <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
@ -296,12 +293,44 @@
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#if($column.pk || $javaField == ${subTableFkclassName}) #if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && $column.htmlType == "input")
<el-table-column label="$comment" prop="${javaField}"> <el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope"> <template #default="scope">
<el-input v-model="scope.row.$javaField" placeholder="请输入$comment" /> <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
</template> </template>
</el-table-column> </el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
<el-table-column label="$comment" prop="${javaField}" width="240">
<template #default="scope">
<el-date-picker clearable
v-model="scope.row.$javaField"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择$comment">
</el-date-picker>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option
v-for="dict in $column.dictType"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</template>
</el-table-column>
#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
<el-table-column label="$comment" prop="${javaField}" width="150">
<template #default="scope">
<el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
<el-option label="请选择字典生成" value="" />
</el-select>
</template>
</el-table-column>
#end #end
#end #end
</el-table> </el-table>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,57 +1,57 @@
package com.ruoyi.quartz.config; //package com.ruoyi.quartz.config;
//
import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; //import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean; //import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource; //import javax.sql.DataSource;
import java.util.Properties; //import java.util.Properties;
//
/** ///**
* 定时任务配置单机部署建议删除此类和qrtz数据库表默认走内存会最高效 // * 定时任务配置单机部署建议删除此类和qrtz数据库表默认走内存会最高效
* // *
* @author ruoyi // * @author ruoyi
*/ // */
@Configuration //@Configuration
public class ScheduleConfig //public class ScheduleConfig
{ //{
@Bean // @Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) // public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
{ // {
SchedulerFactoryBean factory = new SchedulerFactoryBean(); // SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource); // factory.setDataSource(dataSource);
//
// quartz参数 // // quartz参数
Properties prop = new Properties(); // Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler"); // prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO"); // prop.put("org.quartz.scheduler.instanceId", "AUTO");
// 线程池配置 // // 线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); // prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20"); // prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5"); // prop.put("org.quartz.threadPool.threadPriority", "5");
// JobStore配置 // // JobStore配置
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); // prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
// 集群配置 // // 集群配置
prop.put("org.quartz.jobStore.isClustered", "true"); // prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); // prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); // prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); // prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
//
// sqlserver 启用 // // sqlserver 启用
// prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); // // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
prop.put("org.quartz.jobStore.misfireThreshold", "12000"); // prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); // prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
factory.setQuartzProperties(prop); // factory.setQuartzProperties(prop);
//
factory.setSchedulerName("RuoyiScheduler"); // factory.setSchedulerName("RuoyiScheduler");
// 延时启动 // // 延时启动
factory.setStartupDelay(1); // factory.setStartupDelay(1);
factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // factory.setApplicationContextSchedulerContextKey("applicationContextKey");
// 可选QuartzScheduler // // 可选QuartzScheduler
// 启动时更新己存在的Job这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 // // 启动时更新己存在的Job这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true); // factory.setOverwriteExistingJobs(true);
// 设置自动启动默认为true // // 设置自动启动默认为true
factory.setAutoStartup(true); // factory.setAutoStartup(true);
//
return factory; // return factory;
} // }
} //}

View File

@ -25,6 +25,7 @@ import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.quartz.domain.SysJob; import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.service.ISysJobService; import com.ruoyi.quartz.service.ISysJobService;
import com.ruoyi.quartz.util.CronUtils; import com.ruoyi.quartz.util.CronUtils;
import com.ruoyi.quartz.util.ScheduleUtils;
/** /**
* 调度任务信息操作处理 * 调度任务信息操作处理
@ -87,20 +88,24 @@ public class SysJobController extends BaseController
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
{ {
return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规"); return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
} }
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
{
return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
}
job.setCreateBy(getUsername()); job.setCreateBy(getUsername());
return toAjax(jobService.insertJob(job)); return toAjax(jobService.insertJob(job));
} }
@ -119,20 +124,24 @@ public class SysJobController extends BaseController
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI)) else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
} }
else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_LDAP)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap://'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS })) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
} }
else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR)) else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
{ {
return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规"); return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
} }
else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
{
return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
}
job.setUpdateBy(getUsername()); job.setUpdateBy(getUsername());
return toAjax(jobService.updateJob(job)); return toAjax(jobService.updateJob(job));
} }

View File

@ -10,9 +10,12 @@ import org.quartz.Scheduler;
import org.quartz.SchedulerException; import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder; import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey; import org.quartz.TriggerKey;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.ScheduleConstants; import com.ruoyi.common.constant.ScheduleConstants;
import com.ruoyi.common.exception.job.TaskException; import com.ruoyi.common.exception.job.TaskException;
import com.ruoyi.common.exception.job.TaskException.Code; import com.ruoyi.common.exception.job.TaskException.Code;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.quartz.domain.SysJob; import com.ruoyi.quartz.domain.SysJob;
/** /**
@ -110,4 +113,22 @@ public class ScheduleUtils
+ "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
} }
} }
/**
* 检查包名是否为白名单配置
*
* @param invokeTarget 目标字符串
* @return 结果
*/
public static boolean whiteList(String invokeTarget)
{
String packageName = StringUtils.substringBefore(invokeTarget, "(");
int count = StringUtils.countMatches(packageName, ".");
if (count > 1)
{
return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
}
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
return StringUtils.containsAnyIgnoreCase(obj.getClass().getPackage().getName(), Constants.JOB_WHITELIST_STR);
}
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.8.0</version> <version>3.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -20,7 +20,7 @@ public interface SysUserMapper
public List<SysUser> selectUserList(SysUser sysUser); public List<SysUser> selectUserList(SysUser sysUser);
/** /**
* 根据条件分页查询已配用户角色列表 * 根据条件分页查询已配用户角色列表
* *
* @param user 用户信息 * @param user 用户信息
* @return 用户信息集合信息 * @return 用户信息集合信息

View File

@ -61,7 +61,6 @@ public interface ISysConfigService
* 批量删除参数信息 * 批量删除参数信息
* *
* @param configIds 需要删除的参数ID * @param configIds 需要删除的参数ID
* @return 结果
*/ */
public void deleteConfigByIds(Long[] configIds); public void deleteConfigByIds(Long[] configIds);

View File

@ -39,7 +39,6 @@ public interface ISysDictDataService
* 批量删除字典数据信息 * 批量删除字典数据信息
* *
* @param dictCodes 需要删除的字典数据ID * @param dictCodes 需要删除的字典数据ID
* @return 结果
*/ */
public void deleteDictDataByIds(Long[] dictCodes); public void deleteDictDataByIds(Long[] dictCodes);

View File

@ -54,7 +54,6 @@ public interface ISysDictTypeService
* 批量删除字典信息 * 批量删除字典信息
* *
* @param dictIds 需要删除的字典ID * @param dictIds 需要删除的字典ID
* @return 结果
*/ */
public void deleteDictTypeByIds(Long[] dictIds); public void deleteDictTypeByIds(Long[] dictIds);

View File

@ -29,7 +29,7 @@ public interface ISysLogininforService
* 批量删除系统登录日志 * 批量删除系统登录日志
* *
* @param infoIds 需要删除的登录日志ID * @param infoIds 需要删除的登录日志ID
* @return * @return 结果
*/ */
public int deleteLogininforByIds(Long[] infoIds); public int deleteLogininforByIds(Long[] infoIds);

View File

@ -78,7 +78,6 @@ public interface ISysPostService
* *
* @param postIds 需要删除的岗位ID * @param postIds 需要删除的岗位ID
* @return 结果 * @return 结果
* @throws Exception 异常
*/ */
public int deletePostByIds(Long[] postIds); public int deletePostByIds(Long[] postIds);

View File

@ -146,7 +146,6 @@ public class SysConfigServiceImpl implements ISysConfigService
* 批量删除参数信息 * 批量删除参数信息
* *
* @param configIds 需要删除的参数ID * @param configIds 需要删除的参数ID
* @return 结果
*/ */
@Override @Override
public void deleteConfigByIds(Long[] configIds) public void deleteConfigByIds(Long[] configIds)

View File

@ -63,9 +63,8 @@ public class SysDeptServiceImpl implements ISysDeptService
{ {
tempList.add(dept.getDeptId()); tempList.add(dept.getDeptId());
} }
for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();) for (SysDept dept : depts)
{ {
SysDept dept = (SysDept) iterator.next();
// 如果是顶级节点, 遍历该父节点的所有子节点 // 如果是顶级节点, 遍历该父节点的所有子节点
if (!tempList.contains(dept.getParentId())) if (!tempList.contains(dept.getParentId()))
{ {

View File

@ -60,7 +60,6 @@ public class SysDictDataServiceImpl implements ISysDictDataService
* 批量删除字典数据信息 * 批量删除字典数据信息
* *
* @param dictCodes 需要删除的字典数据ID * @param dictCodes 需要删除的字典数据ID
* @return 结果
*/ */
@Override @Override
public void deleteDictDataByIds(Long[] dictCodes) public void deleteDictDataByIds(Long[] dictCodes)

View File

@ -1,5 +1,13 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysDictType; import com.ruoyi.common.core.domain.entity.SysDictType;
@ -9,11 +17,6 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDictDataMapper; import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.mapper.SysDictTypeMapper; import com.ruoyi.system.mapper.SysDictTypeMapper;
import com.ruoyi.system.service.ISysDictTypeService; import com.ruoyi.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.List;
/** /**
* 字典 业务层处理 * 字典 业务层处理
@ -112,7 +115,6 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* 批量删除字典类型信息 * 批量删除字典类型信息
* *
* @param dictIds 需要删除的字典ID * @param dictIds 需要删除的字典ID
* @return 结果
*/ */
@Override @Override
public void deleteDictTypeByIds(Long[] dictIds) public void deleteDictTypeByIds(Long[] dictIds)
@ -135,11 +137,12 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
@Override @Override
public void loadingDictCache() public void loadingDictCache()
{ {
List<SysDictType> dictTypeList = dictTypeMapper.selectDictTypeAll(); SysDictData dictData = new SysDictData();
for (SysDictType dictType : dictTypeList) dictData.setStatus("0");
Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())
{ {
List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dictType.getDictType()); DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
DictUtils.setDictCache(dictType.getDictType(), dictDatas);
} }
} }

View File

@ -46,7 +46,7 @@ public class SysLogininforServiceImpl implements ISysLogininforService
* 批量删除系统登录日志 * 批量删除系统登录日志
* *
* @param infoIds 需要删除的登录日志ID * @param infoIds 需要删除的登录日志ID
* @return * @return 结果
*/ */
@Override @Override
public int deleteLogininforByIds(Long[] infoIds) public int deleteLogininforByIds(Long[] infoIds)

View File

@ -176,7 +176,7 @@ public class SysMenuServiceImpl implements ISysMenuService
else if (menu.getParentId().intValue() == 0 && isInnerLink(menu)) else if (menu.getParentId().intValue() == 0 && isInnerLink(menu))
{ {
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
router.setPath("/inner"); router.setPath("/");
List<RouterVo> childrenList = new ArrayList<RouterVo>(); List<RouterVo> childrenList = new ArrayList<RouterVo>();
RouterVo children = new RouterVo(); RouterVo children = new RouterVo();
String routerPath = innerLinkReplaceEach(menu.getPath()); String routerPath = innerLinkReplaceEach(menu.getPath());
@ -498,7 +498,7 @@ public class SysMenuServiceImpl implements ISysMenuService
*/ */
private boolean hasChild(List<SysMenu> list, SysMenu t) private boolean hasChild(List<SysMenu> list, SysMenu t)
{ {
return getChildList(list, t).size() > 0 ? true : false; return getChildList(list, t).size() > 0;
} }
/** /**

View File

@ -137,7 +137,6 @@ public class SysPostServiceImpl implements ISysPostService
* *
* @param postIds 需要删除的岗位ID * @param postIds 需要删除的岗位ID
* @return 结果 * @return 结果
* @throws Exception 异常
*/ */
@Override @Override
public int deletePostByIds(Long[] postIds) public int deletePostByIds(Long[] postIds)

View File

@ -361,6 +361,7 @@ public class SysRoleServiceImpl implements ISysRoleService
for (Long roleId : roleIds) for (Long roleId : roleIds)
{ {
checkRoleAllowed(new SysRole(roleId)); checkRoleAllowed(new SysRole(roleId));
checkRoleDataScope(roleId);
SysRole role = selectRoleById(roleId); SysRole role = selectRoleById(roleId);
if (countUserRoleByRoleId(roleId) > 0) if (countUserRoleByRoleId(roleId) > 0)
{ {
@ -403,7 +404,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* 批量选择授权用户角色 * 批量选择授权用户角色
* *
* @param roleId 角色ID * @param roleId 角色ID
* @param userIds 需要删除的用户数据ID * @param userIds 需要授权的用户数据ID
* @return 结果 * @return 结果
*/ */
@Override @Override

View File

@ -482,6 +482,7 @@ public class SysUserServiceImpl implements ISysUserService
for (Long userId : userIds) for (Long userId : userIds)
{ {
checkUserAllowed(new SysUser(userId)); checkUserAllowed(new SysUser(userId));
checkUserDataScope(userId);
} }
// 删除用户与角色关联 // 删除用户与角色关联
userRoleMapper.deleteUserRole(userIds); userRoleMapper.deleteUserRole(userIds);

View File

@ -91,7 +91,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="parentId != null and parentId != 0">parent_id,</if> <if test="parentId != null and parentId != 0">parent_id,</if>
<if test="deptName != null and deptName != ''">dept_name,</if> <if test="deptName != null and deptName != ''">dept_name,</if>
<if test="ancestors != null and ancestors != ''">ancestors,</if> <if test="ancestors != null and ancestors != ''">ancestors,</if>
<if test="orderNum != null and orderNum != ''">order_num,</if> <if test="orderNum != null">order_num,</if>
<if test="leader != null and leader != ''">leader,</if> <if test="leader != null and leader != ''">leader,</if>
<if test="phone != null and phone != ''">phone,</if> <if test="phone != null and phone != ''">phone,</if>
<if test="email != null and email != ''">email,</if> <if test="email != null and email != ''">email,</if>
@ -103,7 +103,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="parentId != null and parentId != 0">#{parentId},</if> <if test="parentId != null and parentId != 0">#{parentId},</if>
<if test="deptName != null and deptName != ''">#{deptName},</if> <if test="deptName != null and deptName != ''">#{deptName},</if>
<if test="ancestors != null and ancestors != ''">#{ancestors},</if> <if test="ancestors != null and ancestors != ''">#{ancestors},</if>
<if test="orderNum != null and orderNum != ''">#{orderNum},</if> <if test="orderNum != null">#{orderNum},</if>
<if test="leader != null and leader != ''">#{leader},</if> <if test="leader != null and leader != ''">#{leader},</if>
<if test="phone != null and phone != ''">#{phone},</if> <if test="phone != null and phone != ''">#{phone},</if>
<if test="email != null and email != ''">#{email},</if> <if test="email != null and email != ''">#{email},</if>
@ -119,7 +119,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if> <if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
<if test="deptName != null and deptName != ''">dept_name = #{deptName},</if> <if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
<if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if> <if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if>
<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if> <if test="orderNum != null">order_num = #{orderNum},</if>
<if test="leader != null">leader = #{leader},</if> <if test="leader != null">leader = #{leader},</if>
<if test="phone != null">phone = #{phone},</if> <if test="phone != null">phone = #{phone},</if>
<if test="email != null">email = #{email},</if> <if test="email != null">email = #{email},</if>

View File

@ -28,7 +28,7 @@
</resultMap> </resultMap>
<sql id="selectMenuVo"> <sql id="selectMenuVo">
select menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time select menu_id, menu_name, parent_id, order_num, path, component, `query`, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time
from sys_menu from sys_menu
</sql> </sql>
@ -49,13 +49,13 @@
</select> </select>
<select id="selectMenuTreeAll" resultMap="SysMenuResult"> <select id="selectMenuTreeAll" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0 from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
order by m.parent_id, m.order_num order by m.parent_id, m.order_num
</select> </select>
<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult"> <select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id left join sys_user_role ur on rm.role_id = ur.role_id
@ -74,7 +74,7 @@
</select> </select>
<select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult"> <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id left join sys_user_role ur on rm.role_id = ur.role_id
@ -130,10 +130,10 @@
<set> <set>
<if test="menuName != null and menuName != ''">menu_name = #{menuName},</if> <if test="menuName != null and menuName != ''">menu_name = #{menuName},</if>
<if test="parentId != null">parent_id = #{parentId},</if> <if test="parentId != null">parent_id = #{parentId},</if>
<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if> <if test="orderNum != null">order_num = #{orderNum},</if>
<if test="path != null and path != ''">path = #{path},</if> <if test="path != null and path != ''">path = #{path},</if>
<if test="component != null">component = #{component},</if> <if test="component != null">component = #{component},</if>
<if test="query != null">query = #{query},</if> <if test="query != null">`query` = #{query},</if>
<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if> <if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
<if test="isCache != null and isCache != ''">is_cache = #{isCache},</if> <if test="isCache != null and isCache != ''">is_cache = #{isCache},</if>
<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if> <if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
@ -153,10 +153,10 @@
<if test="menuId != null and menuId != 0">menu_id,</if> <if test="menuId != null and menuId != 0">menu_id,</if>
<if test="parentId != null and parentId != 0">parent_id,</if> <if test="parentId != null and parentId != 0">parent_id,</if>
<if test="menuName != null and menuName != ''">menu_name,</if> <if test="menuName != null and menuName != ''">menu_name,</if>
<if test="orderNum != null and orderNum != ''">order_num,</if> <if test="orderNum != null">order_num,</if>
<if test="path != null and path != ''">path,</if> <if test="path != null and path != ''">path,</if>
<if test="component != null and component != ''">component,</if> <if test="component != null and component != ''">component,</if>
<if test="query != null and query != ''">query,</if> <if test="query != null and query != ''">`query`,</if>
<if test="isFrame != null and isFrame != ''">is_frame,</if> <if test="isFrame != null and isFrame != ''">is_frame,</if>
<if test="isCache != null and isCache != ''">is_cache,</if> <if test="isCache != null and isCache != ''">is_cache,</if>
<if test="menuType != null and menuType != ''">menu_type,</if> <if test="menuType != null and menuType != ''">menu_type,</if>
@ -171,7 +171,7 @@
<if test="menuId != null and menuId != 0">#{menuId},</if> <if test="menuId != null and menuId != 0">#{menuId},</if>
<if test="parentId != null and parentId != 0">#{parentId},</if> <if test="parentId != null and parentId != 0">#{parentId},</if>
<if test="menuName != null and menuName != ''">#{menuName},</if> <if test="menuName != null and menuName != ''">#{menuName},</if>
<if test="orderNum != null and orderNum != ''">#{orderNum},</if> <if test="orderNum != null">#{orderNum},</if>
<if test="path != null and path != ''">#{path},</if> <if test="path != null and path != ''">#{path},</if>
<if test="component != null and component != ''">#{component},</if> <if test="component != null and component != ''">#{component},</if>
<if test="query != null and query != ''">#{query},</if> <if test="query != null and query != ''">#{query},</if>

View File

@ -31,6 +31,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<id property="deptId" column="dept_id" /> <id property="deptId" column="dept_id" />
<result property="parentId" column="parent_id" /> <result property="parentId" column="parent_id" />
<result property="deptName" column="dept_name" /> <result property="deptName" column="dept_name" />
<result property="ancestors" column="ancestors" />
<result property="orderNum" column="order_num" /> <result property="orderNum" column="order_num" />
<result property="leader" column="leader" /> <result property="leader" column="leader" />
<result property="status" column="dept_status" /> <result property="status" column="dept_status" />
@ -47,7 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<sql id="selectUserVo"> <sql id="selectUserVo">
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
d.dept_id, d.parent_id, d.dept_name, d.order_num, d.leader, d.status as dept_status, d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
from sys_user u from sys_user u
left join sys_dept d on u.dept_id = d.dept_id left join sys_dept d on u.dept_id = d.dept_id

28
ry.bat
View File

@ -1,21 +1,21 @@
@echo off @echo off
rem jar平级目录 rem jar平级目录
set AppName=ruoyi-admin.jar set AppName=ruoyi-admin.jar
rem JVM参数 rem JVM参数
set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
ECHO. ECHO.
ECHO. [1] 启动%AppName% ECHO. [1] 启动%AppName%
ECHO. [2] 关闭%AppName% ECHO. [2] 关闭%AppName%
ECHO. [3] 重启%AppName% ECHO. [3] 重启%AppName%
ECHO. [4] 启动状态 %AppName% ECHO. [4] 启动状态 %AppName%
ECHO. [5] 退 出 ECHO. [5] 退 出
ECHO. ECHO.
ECHO.请输入选择项目的序号: ECHO.请输入选择项目的序号:
set /p ID= set /p ID=
IF "%id%"=="1" GOTO start IF "%id%"=="1" GOTO start
IF "%id%"=="2" GOTO stop IF "%id%"=="2" GOTO stop
@ -33,13 +33,13 @@ PAUSE
PAUSE PAUSE
) )
start javaw -jar %JAVA_OPTS% ruoyi-admin.jar start javaw %JVM_OPTS% -jar %AppName%
echo starting…… echo starting……
echo Start %AppName% success... echo Start %AppName% success...
goto:eof goto:eof
rem 函数stop通过jps命令查找pid并结束进程 rem 函数stop通过jps命令查找pid并结束进程
:stop :stop
for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
set pid=%%a set pid=%%a
@ -48,7 +48,7 @@ rem
if not defined pid (echo process %AppName% does not exists) else ( if not defined pid (echo process %AppName% does not exists) else (
echo prepare to kill %image_name% echo prepare to kill %image_name%
echo start kill %pid% ... echo start kill %pid% ...
rem 根据进程IDkill进程 rem 根据进程IDkill进程
taskkill /f /pid %pid% taskkill /f /pid %pid%
) )
goto:eof goto:eof

10
ry.sh
View File

@ -1,13 +1,9 @@
#!/bin/sh #!/bin/sh
# author ruoyi # ./ry.sh start 启动 stop 停止 restart 重启 status 状态
# ./ry.sh start 启动
# ./ry.sh stop 停止
# ./ry.sh restart 重启
# ./ry.sh status 状态
AppName=ruoyi-admin.jar AppName=ruoyi-admin.jar
# JVM参数 # JVM参数
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
APP_HOME=`pwd` APP_HOME=`pwd`
LOG_PATH=$APP_HOME/logs/$AppName.log LOG_PATH=$APP_HOME/logs/$AppName.log
@ -30,7 +26,7 @@ function start()
if [ x"$PID" != x"" ]; then if [ x"$PID" != x"" ]; then
echo "$AppName is running..." echo "$AppName is running..."
else else
nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 & nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &
echo "Start $AppName success..." echo "Start $AppName success..."
fi fi
} }