33 Commits

Author SHA1 Message Date
RuoYi
b16d50390e 若依 v4.8.2 2025-12-13 12:24:16 +08:00
RuoYi
6e3a3f7864 升级oshi到最新版本6.9.1 2025-12-11 10:53:08 +08:00
RuoYi
7f32e481aa 升级commons.io到最新版本2.21.0 2025-12-11 10:52:43 +08:00
RuoYi
9dbf6a5152 update sqlkeyword 2025-12-11 10:52:29 +08:00
RuoYi
ebd91619a4 修复异步树表查询条件无法带入分页问题 2025-12-10 11:26:11 +08:00
RuoYi
bfbaca1e30 使用yauaa代替bitwalker 2025-12-09 14:00:53 +08:00
RuoYi
e16e2be36d 使用yauaa代替bitwalker 2025-12-09 13:55:49 +08:00
RuoYi
e73d4918d3 优化日志记录参数拼装提升效率 2025-12-04 17:55:27 +08:00
若依
075d603ed0 !571 优化数据权限控制逻辑,放开permission限制
Merge pull request !571 from 长江游泳鱼/master
2025-12-04 09:53:41 +00:00
LianTao
226b2e54c0 优化数据权限控制逻辑,放开permission限制 2025-12-04 17:52:46 +08:00
RuoYi
ccf62d2893 支持Excel导出对象的多个子列表 2025-12-04 16:09:18 +08:00
RuoYi
c4760e0a78 支持Excel导出对象的多个子列表 2025-12-02 19:11:35 +08:00
RuoYi
43fa384418 升级tomcat到最新版本9.0.112 2025-12-02 11:17:47 +08:00
RuoYi
92df588297 优化代码 2025-12-02 11:17:15 +08:00
RuoYi
8601a91e34 修复comboReadDict属性下多个sheet出现的报错 2025-11-13 11:48:28 +08:00
RuoYi
4d8d04d58e 升级Bootstrap版本到v3.4.1 2025-11-12 10:48:49 +08:00
RuoYi
27f2082a64 优化代码 2025-11-12 10:03:16 +08:00
RuoYi
ae1ab1037d 升级druid到最新版本1.2.27 2025-10-14 13:32:00 +08:00
RuoYi
32bcd170cd 优化代码 2025-08-28 12:57:10 +08:00
RuoYi
7420a4a39d 升级oshi到最新版本6.8.3 2025-08-28 12:41:52 +08:00
RuoYi
b5ec0bd9ba 优化代码 2025-08-28 12:41:10 +08:00
RuoYi
0f1fe06195 优化代码 2025-08-27 15:17:28 +08:00
RuoYi
477f439b7f 用户归属部门新增清除按钮 2025-08-21 14:07:37 +08:00
RuoYi
609f9236fb 升级tomcat到最新版本9.0.108 2025-08-07 12:38:24 +08:00
RuoYi
a9bef0a1bc 修复菜单栏收起后下级菜单无法滚动问题 2025-07-31 13:44:18 +08:00
RuoYi
70194aee09 添加新群号:140284548 2025-06-20 11:20:35 +08:00
RuoYi
323d74fd2e 优化定时任务包名白名单匹配方式 2025-06-20 11:18:54 +08:00
RuoYi
029d4e3233 优化Excel统计行数值的单元格样式显示 2025-06-19 12:03:18 +08:00
RuoYi
9e264a9692 升级oshi到最新版本6.8.2 2025-06-18 13:49:36 +08:00
RuoYi
434ab81e22 升级tomcat到最新版本9.0.105 2025-06-18 13:39:54 +08:00
RuoYi
bcbb4ac994 用户头像更换后移除旧头像文件 2025-06-06 14:01:45 +08:00
RuoYi
4c74687ca2 优化密码策略提示优先顺序 2025-05-28 09:47:29 +08:00
RuoYi
9f48d2bbe8 update bootstrap-table-custom-view icon 2025-05-28 09:45:09 +08:00
49 changed files with 658 additions and 157 deletions

View File

@@ -1,11 +1,11 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-dd77653d7c9f197dd9d93684f3c8dcfbab6.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v4.8.1</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v4.8.2</h1>
<h4 align="center">基于SpringBoot开发的轻量级Java快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi/stargazers"><img src="https://gitee.com/y_project/RuoYi/badge/star.svg?theme=gvp"></a>
<a href="https://gitee.com/y_project/RuoYi"><img src="https://img.shields.io/badge/RuoYi-v4.8.1-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi"><img src="https://img.shields.io/badge/RuoYi-v4.8.2-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
@@ -98,4 +98,4 @@
## 若依交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/已满-130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr) [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/已满-175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [![加入QQ群](https://img.shields.io/badge/已满-174942938-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938) [![加入QQ群](https://img.shields.io/badge/已满-287843737-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=blYlRDmwZXSXI5pVrPPU7ZJ1stFJ6Q2Q&authKey=ForGBWffHVlPt9NE3d7g4DoOIouBh%2BqvAj2lp1CLReHfZAUaK7SRrdwsChKpRJDJ&noverify=0&group_code=287843737) [![加入QQ群](https://img.shields.io/badge/已满-232896766-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=KTVAIhggR3rR3uZWK9A8kR4yYNREQ4jo&authKey=An4DUV9e7uK8I8VgBbp949z0ypQoDrOoqvVg%2FWOr2vuNNDMZUAMPvqHor6TFMIgz&noverify=0&group_code=232896766) [![加入QQ群](https://img.shields.io/badge/180208928-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XwhV8deuZXt__yteR1clNanVSXzA-ugq&authKey=ezgwKqEZPdP%2FgC9I03OBkJb%2Biii8yvVfwrcQuu0%2FL6ILXcRdHYDBFKCXeoeBT0E6&noverify=0&group_code=180208928)
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/已满-130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) [![加入QQ群](https://img.shields.io/badge/已满-143151071-blue.svg)](https://jq.qq.com/?_wv=1027&k=4NsjKbtU) [![加入QQ群](https://img.shields.io/badge/已满-158781320-blue.svg)](https://jq.qq.com/?_wv=1027&k=VD2pkz2G) [![加入QQ群](https://img.shields.io/badge/已满-201531282-blue.svg)](https://jq.qq.com/?_wv=1027&k=HlshFwkJ) [![加入QQ群](https://img.shields.io/badge/已满-101526938-blue.svg)](https://jq.qq.com/?_wv=1027&k=0ARRrO9V) [![加入QQ群](https://img.shields.io/badge/已满-264355400-blue.svg)](https://jq.qq.com/?_wv=1027&k=up9k3ZXJ) [![加入QQ群](https://img.shields.io/badge/已满-298522656-blue.svg)](https://jq.qq.com/?_wv=1027&k=540WfdEr) [![加入QQ群](https://img.shields.io/badge/已满-139845794-blue.svg)](https://jq.qq.com/?_wv=1027&k=ss91fC4t) [![加入QQ群](https://img.shields.io/badge/已满-185760789-blue.svg)](https://jq.qq.com/?_wv=1027&k=Cqd66IKe) [![加入QQ群](https://img.shields.io/badge/已满-175104288-blue.svg)](https://jq.qq.com/?_wv=1027&k=7FplYUnR) [![加入QQ群](https://img.shields.io/badge/已满-174942938-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=lqMHu_5Fskm7H2S1vNAQTtzAUokVydwc&authKey=ptw0Fpch5pbNocML3CIJKKqZBaq2DI7cusKuzIgfMNiY3t9Pvd9hP%2BA8WYx3yaY1&noverify=0&group_code=174942938) [![加入QQ群](https://img.shields.io/badge/已满-287843737-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=blYlRDmwZXSXI5pVrPPU7ZJ1stFJ6Q2Q&authKey=ForGBWffHVlPt9NE3d7g4DoOIouBh%2BqvAj2lp1CLReHfZAUaK7SRrdwsChKpRJDJ&noverify=0&group_code=287843737) [![加入QQ群](https://img.shields.io/badge/已满-232896766-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=KTVAIhggR3rR3uZWK9A8kR4yYNREQ4jo&authKey=An4DUV9e7uK8I8VgBbp949z0ypQoDrOoqvVg%2FWOr2vuNNDMZUAMPvqHor6TFMIgz&noverify=0&group_code=232896766) [![加入QQ群](https://img.shields.io/badge/已满-180208928-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XwhV8deuZXt__yteR1clNanVSXzA-ugq&authKey=ezgwKqEZPdP%2FgC9I03OBkJb%2Biii8yvVfwrcQuu0%2FL6ILXcRdHYDBFKCXeoeBT0E6&noverify=0&group_code=180208928) [![加入QQ群](https://img.shields.io/badge/140284548-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=WqsGDxpGkqOPeWGOf3I32f_rXxdhqYNr&authKey=kvdF5df7PO9bzWxmixKhZN6ShsECBiuGUmmzTZBWVr2MVOfJ8%2F4oD0Gws0rbgYfz&noverify=0&group_code=140284548)

20
pom.xml
View File

@@ -5,14 +5,14 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>4.8.1</version>
<version>4.8.2</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>4.8.1</ruoyi.version>
<ruoyi.version>4.8.2</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
@@ -20,18 +20,18 @@
<spring-boot.version>2.5.15</spring-boot.version>
<shiro.version>1.13.0</shiro.version>
<thymeleaf.extras.shiro.version>2.1.0</thymeleaf.extras.shiro.version>
<druid.version>1.2.23</druid.version>
<bitwalker.version>1.21</bitwalker.version>
<druid.version>1.2.27</druid.version>
<yauaa.version>7.32.0</yauaa.version>
<kaptcha.version>2.3.3</kaptcha.version>
<swagger.version>3.0.0</swagger.version>
<pagehelper.boot.version>1.4.7</pagehelper.boot.version>
<fastjson.version>1.2.83</fastjson.version>
<oshi.version>6.8.1</oshi.version>
<commons.io.version>2.19.0</commons.io.version>
<oshi.version>6.9.1</oshi.version>
<commons.io.version>2.21.0</commons.io.version>
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<!-- override dependency version -->
<tomcat.version>9.0.105</tomcat.version>
<tomcat.version>9.0.112</tomcat.version>
<logback.version>1.2.13</logback.version>
<spring-framework.version>5.3.39</spring-framework.version>
</properties>
@@ -134,9 +134,9 @@
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${bitwalker.version}</version>
<groupId>nl.basjes.parse.useragent</groupId>
<artifactId>yauaa</artifactId>
<version>${yauaa.version}</version>
</dependency>
<!-- pagehelper 分页插件 -->

View File

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

View File

@@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.config.ServerConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
@@ -150,7 +149,7 @@ public class CommonController
// 本地资源路径
String localPath = RuoYiConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
String downloadPath = localPath + FileUtils.stripPrefix(resource);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

View File

@@ -168,7 +168,7 @@ public class SysDictTypeController extends BaseController
* 选择字典树
*/
@GetMapping("/selectDictTree/{columnId}/{dictType}")
public String selectDeptTree(@PathVariable("columnId") Long columnId, @PathVariable("dictType") String dictType, ModelMap mmap)
public String selectDictTree(@PathVariable("columnId") Long columnId, @PathVariable("dictType") String dictType, ModelMap mmap)
{
mmap.put("columnId", columnId);
mmap.put("dict", dictTypeService.selectDictTypeByType(dictType));

View File

@@ -17,10 +17,10 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.framework.shiro.service.SysPasswordService;
import com.ruoyi.system.service.ISysUserService;
@@ -89,7 +89,6 @@ public class SysProfileController extends BaseController
}
user.setSalt(ShiroUtils.randomSalt());
user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt()));
user.setPwdUpdateDate(DateUtils.getNowDate());
if (userService.resetUserPwd(user) > 0)
{
setSysUser(userService.selectUserById(user.getUserId()));
@@ -157,16 +156,21 @@ public class SysProfileController extends BaseController
@ResponseBody
public AjaxResult updateAvatar(@RequestParam("avatarfile") MultipartFile file)
{
SysUser currentUser = getSysUser();
try
{
if (!file.isEmpty())
{
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
currentUser.setAvatar(avatar);
if (userService.updateUserInfo(currentUser) > 0)
SysUser currentUser = getSysUser();
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);
if (userService.updateUserAvatar(currentUser.getUserId(), avatar))
{
setSysUser(userService.selectUserById(currentUser.getUserId()));
String oldAvatar = currentUser.getAvatar();
if (StringUtils.isNotEmpty(oldAvatar))
{
FileUtils.deleteFile(RuoYiConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));
}
currentUser.setAvatar(avatar);
setSysUser(currentUser);
return success();
}
}

View File

@@ -3,7 +3,7 @@ ruoyi:
# 名称
name: RuoYi
# 版本
version: 4.8.1
version: 4.8.2
# 版权年份
copyrightYear: 2025
# 实例演示开关

View File

@@ -20,7 +20,7 @@ Utils.assignIcons($.fn.bootstrapTable.icons, 'customViewOn', {
})
Utils.assignIcons($.fn.bootstrapTable.icons, 'customViewOff', {
glyphicon: 'glyphicon-thumbnails',
glyphicon: 'glyphicon glyphicon-eye-open',
fa: 'fa-th',
bi: 'bi-grid',
icon: 'grid_on',

View File

@@ -171,6 +171,9 @@
target.data_obj = {};
// 设置请求分页参数
if (options.pagination) {
if (target.lastAjaxParams) {
parms = $.extend({}, target.lastAjaxParams, parms);
}
var params = {};
params.offset = options.pageSize * (options.pageNumber - 1);
params.limit = options.pageSize;

View File

@@ -119,9 +119,9 @@ body .layer-ext-moon .layui-layer-btn .layui-layer-btn1 {
border-radius: 3px;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn2 {
background: #f60;
color: #fff;
border: 1px solid #f60;
background: #fff;
color: #404a58;
border: 1px solid #c0c4cd;
border-radius: 3px;
}
body .layer-ext-moon .layui-layer-btn .layui-layer-btn3 {

File diff suppressed because one or more lines are too long

View File

@@ -476,6 +476,28 @@ body.body-small.fixed-sidebar.mini-navbar .navbar-static-side {
top: 40px;
font-size: 12px;
background-color: #2f4050;
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
}
.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level {
position: relative;
overflow-y: overlay;
scrollbar-width: thin;
scrollbar-color: #555 #2f4050;
}
.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level::-webkit-scrollbar {
width: 8px;
background: transparent;
position: absolute;
right: 0;
}
.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.fixed-sidebar.mini-navbar .nav li:hover>.nav-second-level, .fixed-sidebar.mini-navbar .nav li:hover>a> span.nav-label {
@@ -7044,4 +7066,4 @@ nav .logo {
top: 0px;
z-index: 9998;
margin: 0;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -15,9 +15,9 @@
<div class="ibox-content no-padding">
<div class="summernote">
<h2>若依后台管理系统</h2>
<p>ruoyi是一个完全响应式基于Bootstrap3.3.7最新版本开发的扁平化主题她采用了主流的左右两栏式布局使用了Html5+CSS3等现代技术她提供了诸多的强大的可以重新组合的UI组件并集成了最新的jQuery版本(v2.1.1)当然也集成了很多功能强大用途广泛的就jQuery插件她可以用于所有的Web应用程序<b>网站管理后台</b><b>网站会员中心</b><b>CMS</b><b>CRM</b><b>OA</b>等等,当然,您也可以对她进行深度定制,以做出更强系统。</p>
<p>ruoyi是一个完全响应式基于Bootstrap3.4.1最新版本开发的扁平化主题她采用了主流的左右两栏式布局使用了Html5+CSS3等现代技术她提供了诸多的强大的可以重新组合的UI组件并集成了最新的jQuery版本(v2.1.1)当然也集成了很多功能强大用途广泛的就jQuery插件她可以用于所有的Web应用程序<b>网站管理后台</b><b>网站会员中心</b><b>CMS</b><b>CRM</b><b>OA</b>等等,当然,您也可以对她进行深度定制,以做出更强系统。</p>
<p>
<b>当前版本:</b>v4.8.1
<b>当前版本:</b>v4.8.2
</p>
<p>
<span class="label label-warning">免费开源</span>
@@ -54,9 +54,9 @@
<div class="click2edit wrapper">
<h3>你好,若依 </h3>
<p>H+是一个完全响应式基于Bootstrap3.3.7最新版本开发的扁平化主题她采用了主流的左右两栏式布局使用了Html5+CSS3等现代技术她提供了诸多的强大的可以重新组合的UI组件并集成了最新的jQuery版本(v2.1.1)当然也集成了很多功能强大用途广泛的就jQuery插件她可以用于所有的Web应用程序<b>网站管理后台</b><b>网站会员中心</b><b>CMS</b><b>CRM</b><b>OA</b>等等,当然,您也可以对她进行深度定制,以做出更强系统。</p>
<p>H+是一个完全响应式基于Bootstrap3.4.1最新版本开发的扁平化主题她采用了主流的左右两栏式布局使用了Html5+CSS3等现代技术她提供了诸多的强大的可以重新组合的UI组件并集成了最新的jQuery版本(v2.1.1)当然也集成了很多功能强大用途广泛的就jQuery插件她可以用于所有的Web应用程序<b>网站管理后台</b><b>网站会员中心</b><b>CMS</b><b>CRM</b><b>OA</b>等等,当然,您也可以对她进行深度定制,以做出更强系统。</p>
<p>
<b>当前版本:</b>v4.8.1
<b>当前版本:</b>v4.8.2
</p>
<p>
<span class="label label-warning">开源免费</span>

View File

@@ -7,13 +7,13 @@
<meta name="description" content="">
<meta th:content="${session.csrf_token}" name="csrf-token"/>
<title th:text="${title}"></title>
<link th:href="@{/css/bootstrap.min.css?v=3.3.7}" rel="stylesheet"/>
<link th:href="@{/css/bootstrap.min.css?v=3.4.1}" rel="stylesheet"/>
<link th:href="@{/css/font-awesome.min.css?v=4.7.0}" rel="stylesheet"/>
<!-- bootstrap-table 表格插件样式 -->
<link th:href="@{/ajax/libs/bootstrap-table/bootstrap-table.min.css?v=1.24.1}" rel="stylesheet"/>
<link th:href="@{/css/animate.min.css?v=20210831}" rel="stylesheet"/>
<link th:href="@{/css/style.min.css?v=20210831}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.1}" rel="stylesheet"/>
<link th:href="@{/css/style.min.css?v=20250731}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.2}" rel="stylesheet"/>
</head>
<!-- 通用JS -->
@@ -21,7 +21,7 @@
<script th:inline="javascript"> var ctx = [[@{/}]]; var lockscreen = [[${session.lockscreen}]]; if(lockscreen){window.top.location=ctx+"lockscreen";} </script>
<a id="scroll-up" href="javascript:;" class="btn btn-sm display"><i class="fa fa-angle-double-up"></i></a>
<script th:src="@{/js/jquery.min.js?v=3.7.1}"></script>
<script th:src="@{/js/bootstrap.min.js?v=3.3.7}"></script>
<script th:src="@{/js/bootstrap.min.js?v=3.4.1}"></script>
<!-- bootstrap-table 表格插件 -->
<script th:src="@{/ajax/libs/bootstrap-table/bootstrap-table.min.js?v=1.24.1}"></script>
<script th:src="@{/ajax/libs/bootstrap-table/locale/bootstrap-table-zh-CN.min.js?v=1.24.1}"></script>
@@ -37,8 +37,8 @@
<script th:src="@{/ajax/libs/iCheck/icheck.min.js?v=1.0.3}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js?v=3.7.0}"></script>
<script th:src="@{/ajax/libs/layui/layui.min.js?v=2.8.18}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.2}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
</div>
<!-- ztree树插件 -->

View File

@@ -14,7 +14,7 @@
<link th:href="@{/css/animate.min.css}" rel="stylesheet"/>
<link th:href="@{/css/style.min.css}" rel="stylesheet"/>
<link th:href="@{/css/skins.css?v=20200902}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.1}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.2}" rel="stylesheet"/>
<style type="text/css">.fixed-sidebar .nav:not(.navbar-toolbar)>li.active{border-left:0px!important;}</style>
</head>
<body class="fixed-sidebar full-height-layout gray-bg" th:classappend="${isMobile} ? 'canvas-menu'" style="overflow: hidden">
@@ -321,8 +321,8 @@
<script th:src="@{/js/jquery.contextMenu.min.js}"></script>
<script th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.2}"></script>
<script th:src="@{/ruoyi/index.js?v=20201208}"></script>
<script th:src="@{/ajax/libs/fullscreen/jquery.fullscreen.js}"></script>
<script th:src="@{/js/resize-tabs.js}"></script>
@@ -438,7 +438,7 @@ $(function() {
}
/* 过期密码提示 */
if([[${isPasswordExpired}]]) {
if(![[${isDefaultModifyPwd}]] && [[${isPasswordExpired}]]) {
layer.confirm("您的密码已过期,请尽快修改密码!", {
icon: 0,
title: "安全提示",

View File

@@ -14,7 +14,7 @@
<link th:href="@{/css/animate.min.css}" rel="stylesheet"/>
<link th:href="@{/css/style.min.css}" rel="stylesheet"/>
<link th:href="@{/css/skins.css}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.1}" rel="stylesheet"/>
<link th:href="@{/ruoyi/css/ry-ui.css?v=4.8.2}" rel="stylesheet"/>
</head>
<body class="fixed-sidebar full-height-layout gray-bg" th:classappend="${isMobile} ? 'canvas-menu'" style="overflow: hidden">
<div id="wrapper">
@@ -267,8 +267,8 @@
<script th:src="@{/js/jquery.contextMenu.min.js}"></script>
<script th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.2}"></script>
<script th:src="@{/ruoyi/index.js?v=20201208}"></script>
<script th:src="@{/ajax/libs/fullscreen/jquery.fullscreen.js}"></script>
<script th:inline="javascript">
@@ -374,7 +374,7 @@ $(function() {
}
/* 过期密码提示 */
if([[${isPasswordExpired}]]) {
if(![[${isDefaultModifyPwd}]] && [[${isPasswordExpired}]]) {
layer.confirm("您的密码已过期,请尽快修改密码!", {
icon: 0,
title: "安全提示",

View File

@@ -39,7 +39,7 @@
<script src="../static/js/bootstrap.min.js" th:src="@{/js/bootstrap.min.js}"></script>
<script src="../static/js/three.min.js" th:src="@{/js/three.min.js}"></script>
<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
</body>
<script th:inline="javascript">
var ctx = [[@{/}]];

View File

@@ -9,7 +9,7 @@
<link href="../static/css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
<link href="../static/css/style.min.css" th:href="@{/css/style.min.css}" rel="stylesheet"/>
<link href="../static/css/login.min.css" th:href="@{/css/login.min.css}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=4.8.1}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=4.8.2}" rel="stylesheet"/>
<!-- 360浏览器急速模式 -->
<meta name="renderer" content="webkit">
<!-- 避免IE使用兼容模式 -->
@@ -76,7 +76,7 @@
<script src="../static/ajax/libs/validate/jquery.validate.min.js" th:src="@{/ajax/libs/validate/jquery.validate.min.js}"></script>
<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="../static/ajax/libs/blockUI/jquery.blockUI.js" th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
<script src="../static/ruoyi/login.js" th:src="@{/ruoyi/login.js}"></script>
</body>
</html>

View File

@@ -67,7 +67,7 @@
<div class="ibox-content">
<p><i class="fa fa-send-o"></i> 官网:<a href="http://www.ruoyi.vip" target="_blank">http://www.ruoyi.vip</a>
</p>
<p><i class="fa fa-qq"></i> QQ群<s>满1389287</s> <s>满1679294</s> <s>满1529866</s> <s>满1772718</s> <s>满1366522</s> <s>满1382251</s> <s>满1145125</s> <s>满86752435</s> <s>满134072510</s> <s>满210336300</s> <s>满339522636</s> <s>满130035985</s> <s>满143151071</s> <s>满158781320</s> <s>满201531282</s> <s>满101526938</s> <s>满264355400</s> <s>满298522656</s> <s>满139845794</s> <s>满185760789</s> <s>满175104288</s> <s>满174942938</s> <s>满287843737</s> <s>满232896766</s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XwhV8deuZXt__yteR1clNanVSXzA-ugq&authKey=ezgwKqEZPdP%2FgC9I03OBkJb%2Biii8yvVfwrcQuu0%2FL6ILXcRdHYDBFKCXeoeBT0E6&noverify=0&group_code=180208928" target="_blank">180208928</a>
<p><i class="fa fa-qq"></i> QQ群<s>满1389287</s> <s>满1679294</s> <s>满1529866</s> <s>满1772718</s> <s>满1366522</s> <s>满1382251</s> <s>满1145125</s> <s>满86752435</s> <s>满134072510</s> <s>满210336300</s> <s>满339522636</s> <s>满130035985</s> <s>满143151071</s> <s>满158781320</s> <s>满201531282</s> <s>满101526938</s> <s>满264355400</s> <s>满298522656</s> <s>满139845794</s> <s>满185760789</s> <s>满175104288</s> <s>满174942938</s> <s>满287843737</s> <s>满232896766</s> <s>满180208928</s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=WqsGDxpGkqOPeWGOf3I32f_rXxdhqYNr&authKey=kvdF5df7PO9bzWxmixKhZN6ShsECBiuGUmmzTZBWVr2MVOfJ8%2F4oD0Gws0rbgYfz&noverify=0&group_code=140284548" target="_blank">140284548</a>
</p>
<p><i class="fa fa-weixin"></i> 微信:<a href="javascript:;">/ *若依</a>
</p>
@@ -84,13 +84,46 @@
<div class="ibox-content no-padding">
<div class="panel-body">
<div class="panel-group" id="version">
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#version" href="#v482">v4.8.2</a><code class="pull-right">2025.12.13</code>
</h5>
</div>
<div id="v482" class="panel-collapse collapse in">
<div class="panel-body">
<ol>
<li>使用yauaa代替bitwalker</li>
<li>用户归属部门新增清除按钮</li>
<li>用户头像更换后移除旧头像文件</li>
<li>支持Excel导出对象的多个子列表</li>
<li>升级bootstrap版本到3.4.1</li>
<li>升级oshi到最新版本6.9.1</li>
<li>升级druid到最新版本1.2.27</li>
<li>升级tomcat到最新版本9.0.112</li>
<li>升级commons.io到最新版本2.21.0</li>
<li>修复用户归属部门无法修改为空问题</li>
<li>修复菜单栏收起后下级菜单无法滚动问题</li>
<li>修复异步树表查询条件无法带入分页问题</li>
<li>修复comboReadDict属性下多个sheet出现的报错</li>
<li>优化密码策略提示优先顺序</li>
<li>优化日志记录参数拼装提升效率</li>
<li>优化导入文件检查标题行不能为空</li>
<li>优化定时任务包名白名单匹配方式</li>
<li>优化Excel统计行数值的单元格样式显示</li>
<li>优化数据权限控制逻辑放开permission限制</li>
<li>其他细节优化</li>
</ol>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#version" href="#v481">v4.8.1</a><code class="pull-right">2025.05.20</code>
</h5>
</div>
<div id="v481" class="panel-collapse collapse in">
<div id="v481" class="panel-collapse collapse">
<div class="panel-body">
<ol>
<li>新增CSRF防护功能</li>

View File

@@ -9,7 +9,7 @@
<link href="../static/css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
<link href="../static/css/style.min.css" th:href="@{/css/style.min.css}" rel="stylesheet"/>
<link href="../static/css/login.min.css" th:href="@{/css/login.min.css}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=4.8.1}" rel="stylesheet"/>
<link href="../static/ruoyi/css/ry-ui.css" th:href="@{/ruoyi/css/ry-ui.css?v=4.8.2}" rel="stylesheet"/>
<!-- 360浏览器急速模式 -->
<meta name="renderer" content="webkit">
<!-- 避免IE使用兼容模式 -->
@@ -75,7 +75,7 @@
<script src="../static/ajax/libs/validate/jquery.validate.extend.js" th:src="@{/ajax/libs/validate/jquery.validate.extend.js}"></script>
<script src="../static/ajax/libs/layer/layer.min.js" th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script src="../static/ajax/libs/blockUI/jquery.blockUI.js" th:src="@{/ajax/libs/blockUI/jquery.blockUI.js}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script src="../static/ruoyi/js/ry-ui.js" th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
<script src="../static/ruoyi/register.js" th:src="@{/ruoyi/register.js}"></script>
</body>
</html>

View File

@@ -140,7 +140,7 @@
</ul>
</body>
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/common.js?v=4.8.2}"></script>
<script type="text/javascript">
//皮肤样式列表
var skins = ["skin-blue", "skin-green", "skin-purple", "skin-red", "skin-yellow"];

View File

@@ -3,8 +3,8 @@
<head>
<meta charset="UTF-8">
<title>Font Awesome Ico list</title>
<link href="/css/font-awesome.min.css" th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
<script src="/js/jquery.min.js"></script>
<link th:href="@{/css/font-awesome.min.css}" rel="stylesheet"/>
<script th:src="@{/js/jquery.min.js}"></script>
<style type="text/css">
.ico-list .fa{
margin: 5px;

View File

@@ -232,10 +232,17 @@
var treeId = $("#treeId").val();
var deptId = $.common.isEmpty(treeId) ? "100" : $("#treeId").val();
var url = ctx + "system/user/selectDeptTree/" + deptId;
var btn = ['<i class="fa fa-check"></i> 确认', '<i class="fa fa-trash-o"></i> 清除', '<i class="fa fa-close"></i> 关闭'];
var options = {
title: '选择部门',
width: "380",
url: url,
btn: btn,
btn2: function(index, layero) {
$("#treeId").val("");
$("#treeName").val("");
$.modal.close(index);
},
callBack: doSubmit
};
$.modal.openOptions(options);

View File

@@ -198,10 +198,17 @@
function selectDeptTree() {
var deptId = $.common.isEmpty($("#treeId").val()) ? "100" : $("#treeId").val();
var url = ctx + "system/user/selectDeptTree/" + deptId;
var btn = ['<i class="fa fa-check"></i> 确认', '<i class="fa fa-trash-o"></i> 清除', '<i class="fa fa-close"></i> 关闭'];
var options = {
title: '选择部门',
width: "380",
url: url,
btn: btn,
btn2: function(index, layero) {
$("#treeId").val("");
$("#treeName").val("");
$.modal.close(index);
},
callBack: doSubmit
};
$.modal.openOptions(options);

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.1</version>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -83,10 +83,10 @@
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- yml解析器 -->
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<groupId>nl.basjes.parse.useragent</groupId>
<artifactId>yauaa</artifactId>
</dependency>
<!-- servlet包 -->

View File

@@ -13,6 +13,7 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.common.utils.uuid.Seq;
/**
@@ -101,6 +102,26 @@ public class FileUploadUtils
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
return upload(baseDir, file, allowedExtension, false);
}
/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param useCustomNaming 系统自定义文件名
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean useCustomNaming)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
@@ -110,7 +131,7 @@ public class FileUploadUtils
assertAllowed(file, allowedExtension);
String fileName = extractFilename(file);
String fileName = useCustomNaming ? uuidFilename(file) : extractFilename(file);
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
@@ -118,12 +139,19 @@ public class FileUploadUtils
}
/**
* 编码文件名
* 编码文件名(日期格式目录 + 原文件名 + 序列值 + 后缀)
*/
public static final String extractFilename(MultipartFile file)
{
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
}
/**
* 编编码文件名(日期格式目录 + UUID + 后缀)
*/
public static final String uuidFilename(MultipartFile file)
{
return StringUtils.format("{}/{}.{}", DateUtils.datePath(), IdUtils.fastSimpleUUID(), getExtension(file));
}
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException

View File

@@ -15,6 +15,7 @@ import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
@@ -103,6 +104,17 @@ public class FileUtils
return FileUploadUtils.getPathFileName(uploadDir, pathName);
}
/**
* 移除路径中的请求前缀片段
*
* @param filePath 文件路径
* @return 移除后的文件路径
*/
public static String stripPrefix(String filePath)
{
return StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX);
}
/**
* 删除文件
*
@@ -288,4 +300,3 @@ public class FileUtils
return baseName;
}
}

View File

@@ -0,0 +1,254 @@
package com.ruoyi.common.utils.http;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.ruoyi.common.utils.StringUtils;
import nl.basjes.parse.useragent.UserAgent;
import nl.basjes.parse.useragent.UserAgentAnalyzer;
/**
* UserAgent解析工具类
*
* @author ruoyi
*/
public class UserAgentUtils
{
public static final String UNKNOWN = "";
// 浏览器正则表达式模式
private static final Pattern CHROME_PATTERN = Pattern.compile("Chrome/(\\d+)(?:\\.\\d+)*");
private static final Pattern FIREFOX_PATTERN = Pattern.compile("Firefox/(\\d+)(?:\\.\\d+)*");
private static final Pattern EDGE_PATTERN = Pattern.compile("Edg(?:e)?/(\\d+)(?:\\.\\d+)*");
private static final Pattern SAFARI_PATTERN = Pattern.compile("Version/(\\d+)(?:\\.\\d+)*");
private static final Pattern OPERA_PATTERN = Pattern.compile("Opera/(\\d+)(?:\\.\\d+)*");
private static final Pattern IE_PATTERN = Pattern.compile("(?:MSIE |Trident/.*rv:)(\\d+)(?:\\.\\d+)*");
private static final Pattern SAMSUNG_PATTERN = Pattern.compile("SamsungBrowser/(\\d+)(?:\\.\\d+)*");
private static final Pattern UC_PATTERN = Pattern.compile("UCBrowser/(\\d+)(?:\\.\\d+)*");
private static final Pattern QQ_PATTERN = Pattern.compile("QQBrowser/(\\d+)(?:\\.\\d+)*");
private static final Pattern WECHAT_PATTERN = Pattern.compile("MicroMessenger/(\\d+)(?:\\.\\d+)*");
private static final Pattern BAIDU_PATTERN = Pattern.compile("baidubrowser/(\\d+)(?:\\.\\d+)*");
// 操作系统正则表达式模式
private static final Pattern WINDOWS_PATTERN = Pattern.compile("Windows NT (\\d+\\.\\d+)");
private static final Pattern MACOS_PATTERN = Pattern.compile("Mac OS X (\\d+[_\\d]*)");
private static final Pattern ANDROID_PATTERN = Pattern.compile("Android (\\d+)(?:\\.\\d+)*");
private static final Pattern IOS_PATTERN = Pattern.compile("OS[\\s_](\\d+)(?:_\\d+)*");
private static final Pattern LINUX_PATTERN = Pattern.compile("Linux");
private static final Pattern CHROMEOS_PATTERN = Pattern.compile("CrOS");
private static final UserAgentAnalyzer userAgentAnalyzer = UserAgentAnalyzer
.newBuilder().hideMatcherLoadStats()
.withCache(5000)
.showMinimalVersion()
.withField(UserAgent.AGENT_NAME_VERSION)
.withField(UserAgent.OPERATING_SYSTEM_NAME_VERSION)
.build();
/**
* 获取客户端浏览器
*/
public static String getBrowser(String userAgent)
{
UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);
String agentNameVersion = iua.get(UserAgent.AGENT_NAME_VERSION).getValue();
if (StringUtils.isBlank(agentNameVersion) || agentNameVersion.contains("??"))
{
return formatBrowser(userAgent);
}
return agentNameVersion;
}
/**
* 获取客户端操作系统
*/
public static String getOperatingSystem(String userAgent)
{
UserAgent.ImmutableUserAgent iua = userAgentAnalyzer.parse(userAgent);
String operatingSystemNameVersion = iua.get(UserAgent.OPERATING_SYSTEM_NAME_VERSION).getValue();
if (StringUtils.isBlank(operatingSystemNameVersion) || operatingSystemNameVersion.contains("??"))
{
return formatOperatingSystem(userAgent);
}
return operatingSystemNameVersion;
}
/**
* 全面浏览器检测
*/
private static String formatBrowser(String browser)
{
// Chrome系列浏览器
Matcher chromeMatcher = CHROME_PATTERN.matcher(browser);
if (chromeMatcher.find() && (browser.contains("Chrome") || browser.contains("CriOS")))
{
return "Chrome" + chromeMatcher.group(1);
}
// Firefox
Matcher firefoxMatcher = FIREFOX_PATTERN.matcher(browser);
if (firefoxMatcher.find())
{
return "Firefox" + firefoxMatcher.group(1);
}
// Edge浏览器
Matcher edgeMatcher = EDGE_PATTERN.matcher(browser);
if (edgeMatcher.find())
{
return "Edge" + edgeMatcher.group(1);
}
// Safari浏览器需排除Chrome
Matcher safariMatcher = SAFARI_PATTERN.matcher(browser);
if (safariMatcher.find() && !browser.contains("Chrome"))
{
return "Safari" + safariMatcher.group(1);
}
// 微信内置浏览器
Matcher wechatMatcher = WECHAT_PATTERN.matcher(browser);
if (wechatMatcher.find())
{
return "WeChat" + wechatMatcher.group(1);
}
// UC浏览器
Matcher ucMatcher = UC_PATTERN.matcher(browser);
if (ucMatcher.find())
{
return "UC Browser" + ucMatcher.group(1);
}
// QQ浏览器
Matcher qqMatcher = QQ_PATTERN.matcher(browser);
if (qqMatcher.find())
{
return "QQ Browser" + qqMatcher.group(1);
}
// 百度浏览器
Matcher baiduMatcher = BAIDU_PATTERN.matcher(browser);
if (baiduMatcher.find())
{
return "Baidu Browser" + baiduMatcher.group(1);
}
// Samsung浏览器
Matcher samsungMatcher = SAMSUNG_PATTERN.matcher(browser);
if (samsungMatcher.find())
{
return "Samsung Browser" + samsungMatcher.group(1);
}
// Opera浏览器
Matcher operaMatcher = OPERA_PATTERN.matcher(browser);
if (operaMatcher.find())
{
return "Opera" + operaMatcher.group(1);
}
// IE浏览器
Matcher ieMatcher = IE_PATTERN.matcher(browser);
if (ieMatcher.find())
{
return "Internet Explorer" + ieMatcher.group(1);
}
return UNKNOWN;
}
/**
* 检测操作系统
*/
private static String formatOperatingSystem(String operatingSystem)
{
// Windows系统
Matcher windowsMatcher = WINDOWS_PATTERN.matcher(operatingSystem);
if (windowsMatcher.find())
{
return "Windows" + getWindowsVersionDisplay(windowsMatcher.group(1));
}
// macOS系统
Matcher macMatcher = MACOS_PATTERN.matcher(operatingSystem);
if (macMatcher.find())
{
String version = macMatcher.group(1).replace("_", ".");
return "macOS" + extractMajorVersion(version);
}
// Android系统
Matcher androidMatcher = ANDROID_PATTERN.matcher(operatingSystem);
if (androidMatcher.find())
{
return "Android" + extractMajorVersion(androidMatcher.group(1));
}
// iOS系统
Matcher iosMatcher = IOS_PATTERN.matcher(operatingSystem);
if (iosMatcher.find() && (operatingSystem.contains("iPhone") || operatingSystem.contains("iPad")))
{
return "iOS" + extractMajorVersion(iosMatcher.group(1));
}
// Linux系统
if (LINUX_PATTERN.matcher(operatingSystem).find() && !operatingSystem.contains("Android"))
{
return "Linux";
}
// Chrome OS
if (CHROMEOS_PATTERN.matcher(operatingSystem).find())
{
return "Chrome OS";
}
return UNKNOWN;
}
/**
* 提取优化的主版本号
*/
private static String extractMajorVersion(String fullVersion)
{
if (StringUtils.isEmpty(fullVersion))
{
return StringUtils.EMPTY;
}
try
{
// 清理版本号中的非数字字符
String cleanVersion = fullVersion.replaceAll("[^0-9.]", "");
String[] parts = cleanVersion.split("\\.");
if (parts.length > 0)
{
String firstPart = parts[0];
if (firstPart.matches("\\d+"))
{
int version = Integer.parseInt(firstPart);
// 处理三位数版本号如142 -> 14
if (version >= 100)
{
return String.valueOf(version / 10);
}
return firstPart;
}
}
}
catch (NumberFormatException e)
{
// 版本号解析失败,返回原始值
}
return fullVersion;
}
/**
* Windows版本号显示优化
*/
private static String getWindowsVersionDisplay(String version)
{
switch (version)
{
case "10.0":
return "10";
case "6.3":
return "8.1";
case "6.2":
return "8";
case "6.1":
return "7";
case "6.0":
return "Vista";
case "5.1":
return "XP";
case "5.0":
return "2000";
default:
return extractMajorVersion(version);
}
}
}

View File

@@ -174,23 +174,18 @@ public class ExcelUtil<T>
/**
* 对象的子列表方法
*/
private Method subMethod;
private Map<String, Method> subMethods;
/**
* 对象的子列表属性
*/
private List<Field> subFields;
private Map<String, List<Field>> subFieldsMap;
/**
* 统计列表
*/
private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
/**
* 数字格式
*/
private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
/**
* 实体对象
*/
@@ -257,7 +252,10 @@ public class ExcelUtil<T>
int titleLastCol = this.fields.size() - 1;
if (isSubList())
{
titleLastCol = titleLastCol + subFields.size() - 1;
for (List<Field> currentSubFields : subFieldsMap.values())
{
titleLastCol = titleLastCol + currentSubFields.size() - 1;
}
}
Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
titleRow.setHeightInPoints(30);
@@ -277,16 +275,17 @@ public class ExcelUtil<T>
{
Row subRow = sheet.createRow(rownum);
int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields)
{
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1];
CellStyle cellStyle = styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()));
if (Collection.class.isAssignableFrom(field.getType()))
{
Cell cell = subRow.createCell(column);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
cell.setCellStyle(cellStyle);
int subFieldSize = subFieldsMap != null ? subFieldsMap.get(field.getName()).size() : 0;
if (subFieldSize > 1)
{
CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
@@ -298,7 +297,7 @@ public class ExcelUtil<T>
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
cell.setCellStyle(cellStyle);
}
}
rownum++;
@@ -379,7 +378,11 @@ public class ExcelUtil<T>
Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头
Row heard = sheet.getRow(titleNum);
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
if (heard == null)
{
throw new UtilException("文件标题行为空请检查Excel文件格式");
}
for (int i = 0; i < heard.getLastCellNum(); i++)
{
Cell cell = heard.getCell(i);
if (StringUtils.isNotNull(cell))
@@ -387,10 +390,6 @@ public class ExcelUtil<T>
String value = this.getCellValue(heard, i).toString();
cellMap.put(value, i);
}
else
{
cellMap.put(null, i);
}
}
// 有数据时才处理 得到类的所有field.
List<Object[]> fields = this.getFields();
@@ -702,7 +701,8 @@ public class ExcelUtil<T>
Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()))
{
for (Field subField : subFields)
List<Field> currentSubFields = subFieldsMap.get(field.getName());
for (Field subField : currentSubFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
this.createHeadCell(subExcel, row, column++);
@@ -715,7 +715,7 @@ public class ExcelUtil<T>
}
if (Type.EXPORT.equals(type))
{
fillExcelData(index, row);
fillExcelData(index);
addStatisticsRow();
}
}
@@ -725,10 +725,9 @@ public class ExcelUtil<T>
* 填充excel数据
*
* @param index 序号
* @param row 单元格行
*/
@SuppressWarnings("unchecked")
public void fillExcelData(int index, Row row)
public void fillExcelData(int index)
{
int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size());
@@ -736,7 +735,7 @@ public class ExcelUtil<T>
for (int i = startNo; i < endNo; i++)
{
row = sheet.createRow(currentRowNum);
Row row = sheet.createRow(currentRowNum);
T vo = (T) list.get(i);
int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
@@ -749,6 +748,7 @@ public class ExcelUtil<T>
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
List<Field> currentSubFields = subFieldsMap.get(field.getName());
if (subList != null && !subList.isEmpty())
{
int subIndex = 0;
@@ -761,15 +761,15 @@ public class ExcelUtil<T>
}
int subColumn = column;
for (Field subField : subFields)
for (Field subField : currentSubFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
}
subIndex++;
}
column += subFields.size();
}
column += currentSubFields.size();
}
catch (Exception e)
{
@@ -861,6 +861,7 @@ public class ExcelUtil<T>
style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setDataFormat(dataFormat.getFormat("######0.00"));
Font totalFont = wb.createFont();
totalFont.setFontName("Arial");
totalFont.setFontHeightInPoints((short) 10);
@@ -1135,7 +1136,7 @@ public class ExcelUtil<T>
{
// 创建cell
cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
if (isSubListValue(vo) && getListCellValue(vo) > 1 && attr.needMerge())
{
if (subMergedLastRowNum >= subMergedFirstRowNum)
{
@@ -1242,18 +1243,36 @@ public class ExcelUtil<T>
public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)
{
String hideSheetName = "combo_" + firstCol + "_" + endCol;
Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
for (int i = 0; i < textlist.length; i++)
Sheet hideSheet = null;
String hideSheetDataName = hideSheetName + "_data";
Name name = wb.getName(hideSheetDataName);
if (name != null)
{
hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
// 名称已存在尝试从名称的引用中找到sheet名称
String refersToFormula = name.getRefersToFormula();
if (StringUtils.isNotEmpty(refersToFormula) && refersToFormula.contains("!"))
{
String sheetNameFromFormula = refersToFormula.substring(0, refersToFormula.indexOf("!"));
hideSheet = wb.getSheet(sheetNameFromFormula);
}
}
// 创建名称,可被其他单元格引用
Name name = wb.createName();
name.setNameName(hideSheetName + "_data");
name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
if (hideSheet == null)
{
hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
for (int i = 0; i < textlist.length; i++)
{
hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
}
// 创建名称,可被其他单元格引用
name = wb.createName();
name.setNameName(hideSheetDataName);
name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
}
DataValidationHelper helper = sheet.getDataValidationHelper();
// 加载下拉列表内容
DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data");
DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetDataName);
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
// 数据有效性对象
@@ -1442,7 +1461,7 @@ public class ExcelUtil<T>
{
cell = row.createCell(key);
cell.setCellStyle(styles.get("total"));
cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));
cell.setCellValue(statistics.get(key));
}
statistics.clear();
}
@@ -1541,6 +1560,8 @@ public class ExcelUtil<T>
{
List<Object[]> fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
subFieldsMap = new HashMap<>();
subMethods = new HashMap<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
if (StringUtils.isNotEmpty(includeFields))
@@ -1588,10 +1609,11 @@ public class ExcelUtil<T>
}
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
String fieldName = field.getName();
subMethods.put(fieldName, getSubMethod(fieldName, clazz));
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
subFieldsMap.put(fieldName, FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class));
}
}
@@ -1660,7 +1682,8 @@ public class ExcelUtil<T>
{
this.sheet = wb.createSheet();
this.createTitle();
wb.setSheetName(index, sheetName + index);
int actualIndex = wb.getSheetIndex(this.sheet);
wb.setSheetName(actualIndex, sheetName + index);
}
}
@@ -1843,7 +1866,7 @@ public class ExcelUtil<T>
*/
public boolean isSubList()
{
return StringUtils.isNotNull(subFields) && subFields.size() > 0;
return !StringUtils.isEmpty(subFieldsMap);
}
/**
@@ -1851,24 +1874,32 @@ public class ExcelUtil<T>
*/
public boolean isSubListValue(T vo)
{
return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0;
return !StringUtils.isEmpty(subFieldsMap) && getListCellValue(vo) > 0;
}
/**
* 获取集合的值
*/
public Collection<?> getListCellValue(Object obj)
public int getListCellValue(Object obj)
{
Object value;
Collection<?> value;
int max = 0;
try
{
value = subMethod.invoke(obj, new Object[] {});
for (String s : subMethods.keySet())
{
value = (Collection<?>) subMethods.get(s).invoke(obj);
if (value.size() > max)
{
max = value.size();
}
}
}
catch (Exception e)
{
return new ArrayList<Object>();
return 0;
}
return (Collection<?>) value;
return max;
}
/**

View File

@@ -13,7 +13,7 @@ public class SqlUtil
/**
* 定义常用的 sql关键字
*/
public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|information_schema|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>4.8.1</version>
<version>4.8.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -59,12 +59,6 @@
<artifactId>thymeleaf-extras-shiro</artifactId>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>

View File

@@ -92,7 +92,7 @@ public class DataScopeAspect
List<String> conditions = new ArrayList<String>();
List<String> scopeCustomIds = new ArrayList<String>();
user.getRoles().forEach(role -> {
if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && (StringUtils.isEmpty(permission) || StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))))
{
scopeCustomIds.add(Convert.toStr(role.getRoleId()));
}
@@ -105,7 +105,7 @@ public class DataScopeAspect
{
continue;
}
if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
if (StringUtils.isNotEmpty(permission) && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{
continue;
}

View File

@@ -47,6 +47,9 @@ public class LogAspect
/** 计算操作消耗时间 */
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
/** 参数最大长度限制 */
private static final int PARAM_MAX_LENGTH = 2000;
/**
* 处理请求前执行
*/
@@ -173,7 +176,7 @@ public class LogAspect
if (StringUtils.isNotEmpty(map))
{
String params = JSONObject.toJSONString(map, excludePropertyPreFilter(excludeParamNames));
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
operLog.setOperParam(StringUtils.substring(params, 0, PARAM_MAX_LENGTH));
}
else
{
@@ -181,7 +184,7 @@ public class LogAspect
if (StringUtils.isNotNull(args))
{
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
operLog.setOperParam(params);
}
}
}
@@ -199,7 +202,7 @@ public class LogAspect
*/
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
{
String params = "";
StringBuilder params = new StringBuilder();
if (paramsArray != null && paramsArray.length > 0)
{
for (Object o : paramsArray)
@@ -209,15 +212,20 @@ public class LogAspect
try
{
Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
params += jsonObj.toString() + " ";
params.append(jsonObj).append(" ");
if (params.length() >= PARAM_MAX_LENGTH)
{
return StringUtils.substring(params.toString(), 0, PARAM_MAX_LENGTH);
}
}
catch (Exception e)
{
log.error("请求参数拼装异常 msg:{}, 参数:{}", e.getMessage(), paramsArray, e);
}
}
}
}
return params.trim();
return params.toString();
}
/**

View File

@@ -9,6 +9,7 @@ import com.ruoyi.common.utils.LogUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.UserAgentUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.shiro.session.OnlineSession;
import com.ruoyi.system.domain.SysLogininfor;
@@ -17,7 +18,6 @@ import com.ruoyi.system.domain.SysUserOnline;
import com.ruoyi.system.service.ISysOperLogService;
import com.ruoyi.system.service.ISysUserOnlineService;
import com.ruoyi.system.service.impl.SysLogininforServiceImpl;
import eu.bitwalker.useragentutils.UserAgent;
/**
* 异步工厂(产生任务用)
@@ -91,7 +91,7 @@ public class AsyncFactory
*/
public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args)
{
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
final String userAgent = ServletUtils.getRequest().getHeader("User-Agent");
final String ip = ShiroUtils.getIp();
return new TimerTask()
{
@@ -108,9 +108,9 @@ public class AsyncFactory
// 打印信息到日志
sys_user_logger.info(s.toString(), args);
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
String os = UserAgentUtils.getOperatingSystem(userAgent);
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
String browser = UserAgentUtils.getBrowser(userAgent);
// 封装对象
SysLogininfor logininfor = new SysLogininfor();
logininfor.setLoginName(username);

View File

@@ -179,10 +179,6 @@ public class SysLoginService
*/
public void recordLoginInfo(Long userId)
{
SysUser user = new SysUser();
user.setUserId(userId);
user.setLoginIp(ShiroUtils.getIp());
user.setLoginDate(DateUtils.getNowDate());
userService.updateUserInfo(user);
userService.updateLoginInfo(userId, ShiroUtils.getIp(), DateUtils.getNowDate());
}
}

View File

@@ -7,7 +7,7 @@ import org.apache.shiro.session.mgt.SessionFactory;
import org.apache.shiro.web.session.mgt.WebSessionContext;
import org.springframework.stereotype.Component;
import com.ruoyi.common.utils.IpUtils;
import eu.bitwalker.useragentutils.UserAgent;
import com.ruoyi.common.utils.http.UserAgentUtils;
/**
* 自定义sessionFactory会话
@@ -27,11 +27,11 @@ public class OnlineSessionFactory implements SessionFactory
HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();
if (request != null)
{
UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
String userAgent = request.getHeader("User-Agent");
// 获取客户端操作系统
String os = userAgent.getOperatingSystem().getName();
String os = UserAgentUtils.getOperatingSystem(userAgent);
// 获取客户端浏览器
String browser = userAgent.getBrowser().getName();
String browser = UserAgentUtils.getBrowser(userAgent);
session.setHost(IpUtils.getIpAddr(request));
session.setBrowser(browser);
session.setOs(os);

View File

@@ -56,9 +56,10 @@ public class OnlineSessionFilter extends AccessControlFilter
{
onlineSession.setUserId(user.getUserId());
onlineSession.setLoginName(user.getLoginName());
onlineSession.setAvatar(user.getAvatar());
onlineSession.setAvatar(user.getAvatar());
onlineSession.setDeptName(user.getDept().getDeptName());
onlineSession.markAttributeChanged();
onlineSessionDAO.update(onlineSession);
}
}

View File

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

View File

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

View File

@@ -131,11 +131,11 @@ public class ScheduleUtils
int count = StringUtils.countMatches(packageName, ".");
if (count > 1)
{
return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
return StringUtils.startsWithAny(invokeTarget, Constants.JOB_WHITELIST_STR);
}
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
String beanPackageName = obj.getClass().getPackage().getName();
return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
&& !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
return StringUtils.startsWithAny(beanPackageName, Constants.JOB_WHITELIST_STR)
&& !StringUtils.startsWithAny(beanPackageName, Constants.JOB_ERROR_STR);
}
}

View File

@@ -1131,7 +1131,7 @@
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/js/bootstrap.min.js}"></script>
<script th:src="@{/ajax/libs/layer/layer.min.js}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.1}"></script>
<script th:src="@{/ruoyi/js/ry-ui.js?v=4.8.2}"></script>
<script th:src="@{/js/cron.js}"></script>
<script th:inline="javascript">
var prefix = [[@{/}]] + "monitor/job";

View File

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

View File

@@ -1,6 +1,8 @@
package com.ruoyi.system.mapper;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.common.core.domain.entity.SysUser;
/**
@@ -90,6 +92,44 @@ public interface SysUserMapper
*/
public int updateUser(SysUser user);
/**
* 修改用户头像
*
* @param userId 用户ID
* @param avatar 头像地址
* @return 结果
*/
public int updateUserAvatar(@Param("userId") Long userId, @Param("avatar") String avatar);
/**
* 修改用户状态
*
* @param userId 用户ID
* @param status 状态
* @return 结果
*/
public int updateUserStatus(@Param("userId") Long userId, @Param("status") String status);
/**
* 重置用户密码
*
* @param userId 用户ID
* @param password 密码
* @param salt 盐
* @return 结果
*/
public int resetUserPwd(@Param("userId") Long userId, @Param("password") String password, @Param("salt") String salt);
/**
* 更新用户登录信息IP和登录时间
*
* @param userId 用户ID
* @param loginIp 登录IP地址
* @param loginDate 登录时间
* @return 结果
*/
public int updateLoginInfo(@Param("userId") Long userId, @Param("loginIp") String loginIp, @Param("loginDate") Date loginDate);
/**
* 新增用户信息
*

View File

@@ -1,5 +1,6 @@
package com.ruoyi.system.service;
import java.util.Date;
import java.util.List;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.domain.SysUserRole;
@@ -124,6 +125,25 @@ public interface ISysUserService
*/
public int updateUserInfo(SysUser user);
/**
* 修改用户头像
*
* @param userId 用户ID
* @param avatar 头像地址
* @return 结果
*/
public boolean updateUserAvatar(Long userId, String avatar);
/**
* 更新用户登录信息IP和登录时间
*
* @param userId 用户ID
* @param loginIp 登录IP地址
* @param loginDate 登录时间
* @return 结果
*/
public void updateLoginInfo(Long userId, String loginIp, Date loginDate);
/**
* 用户授权角色
*

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolationException;
@@ -275,6 +276,31 @@ public class SysUserServiceImpl implements ISysUserService
return userMapper.updateUser(user);
}
/**
* 修改用户头像
*
* @param userId 用户ID
* @param avatar 头像地址
* @return 结果
*/
public boolean updateUserAvatar(Long userId, String avatar)
{
return userMapper.updateUserAvatar(userId, avatar) > 0;
}
/**
* 更新用户登录信息IP和登录时间
*
* @param userId 用户ID
* @param loginIp 登录IP地址
* @param loginDate 登录时间
* @return 结果
*/
public void updateLoginInfo(Long userId, String loginIp, Date loginDate)
{
userMapper.updateLoginInfo(userId, loginIp, loginDate);
}
/**
* 用户授权角色
*
@@ -298,7 +324,7 @@ public class SysUserServiceImpl implements ISysUserService
@Override
public int resetUserPwd(SysUser user)
{
return updateUserInfo(user);
return userMapper.resetUserPwd(user.getUserId(), user.getPassword(), user.getSalt());
}
/**
@@ -518,6 +544,7 @@ public class SysUserServiceImpl implements ISysUserService
checkUserDataScope(u.getUserId());
deptService.checkDeptDataScope(user.getDeptId());
user.setUserId(u.getUserId());
user.setDeptId(u.getDeptId());
user.setUpdateBy(operName);
userMapper.updateUser(user);
successNum++;
@@ -563,6 +590,6 @@ public class SysUserServiceImpl implements ISysUserService
@Override
public int changeStatus(SysUser user)
{
return userMapper.updateUser(user);
return userMapper.updateUserStatus(user.getUserId(), user.getStatus());
}
}

View File

@@ -166,10 +166,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</delete>
<update id="updateUserAvatar" parameterType="SysUser">
update sys_user set avatar = #{avatar} where user_id = #{userId}
</update>
<update id="resetUserPwd" parameterType="SysUser">
update sys_user SET pwd_update_date = sysdate(), password = #{password}, salt = #{salt}, update_time = sysdate() where user_id = #{userId}
</update>
<update id="updateUserStatus" parameterType="SysUser">
update sys_user SET status = #{status}, update_time = sysdate() where user_id = #{userId}
</update>
<update id="updateLoginInfo" parameterType="SysUser">
update sys_user set login_ip = #{loginIp}, login_date = #{loginDate} where user_id = #{userId}
</update>
<update id="updateUser" parameterType="SysUser">
update sys_user
<set>
<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
<if test="deptId != 0">dept_id = #{deptId},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="userType != null and userType != ''">user_type = #{userType},</if>
<if test="email != null and email != ''">email = #{email},</if>