fix(ruoyi3.8.9): 后端代码同步

This commit is contained in:
zhuangpeng.li
2025-04-27 11:21:09 +08:00
parent f545198645
commit 5b6ec185c4
47 changed files with 685 additions and 309 deletions

View File

@@ -7,6 +7,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.TreeSet;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@@ -26,7 +27,7 @@ import com.fastbee.system.domain.SysCache;
/** /**
* 缓存监控 * 缓存监控
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "缓存监控") @Api(tags = "缓存监控")
@@ -87,7 +88,7 @@ public class CacheController
public AjaxResult getCacheKeys(@PathVariable String cacheName) public AjaxResult getCacheKeys(@PathVariable String cacheName)
{ {
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*"); Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(cacheKeys); return AjaxResult.success(new TreeSet<>(cacheKeys));
} }
@ApiOperation("缓存内容") @ApiOperation("缓存内容")

View File

@@ -28,7 +28,7 @@ import com.fastbee.system.service.ISysUserOnlineService;
/** /**
* 在线用户监控 * 在线用户监控
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "在线用户监控") @Api(tags = "在线用户监控")
@@ -54,24 +54,15 @@ public class SysUserOnlineController extends BaseController
LoginUser user = redisCache.getCacheObject(key); LoginUser user = redisCache.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
{ {
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
} }
else if (StringUtils.isNotEmpty(ipaddr)) else if (StringUtils.isNotEmpty(ipaddr))
{ {
if (StringUtils.equals(ipaddr, user.getIpaddr())) userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
} }
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
{ {
if (StringUtils.equals(userName, user.getUsername())) userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
} }
else else
{ {

View File

@@ -93,7 +93,7 @@ public class SysConfigController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysConfig config) public AjaxResult add(@Validated @RequestBody SysConfig config)
{ {
if (configService.checkConfigKeyUnique(config)) if (!configService.checkConfigKeyUnique(config))
{ {
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }
@@ -110,7 +110,7 @@ public class SysConfigController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config) public AjaxResult edit(@Validated @RequestBody SysConfig config)
{ {
if (configService.checkConfigKeyUnique(config)) if (!configService.checkConfigKeyUnique(config))
{ {
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
} }

View File

@@ -84,7 +84,7 @@ public class SysDeptController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept) public AjaxResult add(@Validated @RequestBody SysDept dept)
{ {
if (deptService.checkDeptNameUnique(dept)) if (!deptService.checkDeptNameUnique(dept))
{ {
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }
@@ -103,7 +103,7 @@ public class SysDeptController extends BaseController
{ {
Long deptId = dept.getDeptId(); Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId); deptService.checkDeptDataScope(deptId);
if (deptService.checkDeptNameUnique(dept)) if (!deptService.checkDeptNameUnique(dept))
{ {
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
} }

View File

@@ -80,7 +80,7 @@ public class SysDictTypeController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysDictType dict) public AjaxResult add(@Validated @RequestBody SysDictType dict)
{ {
if (dictTypeService.checkDictTypeUnique(dict)) if (!dictTypeService.checkDictTypeUnique(dict))
{ {
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }
@@ -97,7 +97,7 @@ public class SysDictTypeController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictType dict) public AjaxResult edit(@Validated @RequestBody SysDictType dict)
{ {
if (dictTypeService.checkDictTypeUnique(dict)) if (!dictTypeService.checkDictTypeUnique(dict))
{ {
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }

View File

@@ -94,7 +94,7 @@ public class SysMenuController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu) public AjaxResult add(@Validated @RequestBody SysMenu menu)
{ {
if (menuService.checkMenuNameUnique(menu)) if (!menuService.checkMenuNameUnique(menu))
{ {
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }
@@ -115,7 +115,7 @@ public class SysMenuController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu) public AjaxResult edit(@Validated @RequestBody SysMenu menu)
{ {
if (menuService.checkMenuNameUnique(menu)) if (!menuService.checkMenuNameUnique(menu))
{ {
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} }

View File

@@ -83,11 +83,11 @@ public class SysPostController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysPost post) public AjaxResult add(@Validated @RequestBody SysPost post)
{ {
if (postService.checkPostNameUnique(post)) if (!postService.checkPostNameUnique(post))
{ {
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (postService.checkPostCodeUnique(post)) else if (!postService.checkPostCodeUnique(post))
{ {
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }
@@ -104,11 +104,11 @@ public class SysPostController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post) public AjaxResult edit(@Validated @RequestBody SysPost post)
{ {
if (postService.checkPostNameUnique(post)) if (!postService.checkPostNameUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (postService.checkPostCodeUnique(post)) else if (!postService.checkPostCodeUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }

View File

@@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 个人信息 业务处理 * 个人信息 业务处理
@@ -78,29 +79,22 @@ public class SysProfileController extends BaseController
public AjaxResult updateProfile(@RequestBody SysUser user) public AjaxResult updateProfile(@RequestBody SysUser user)
{ {
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
SysUser sysUser = loginUser.getUser(); SysUser currentUser = loginUser.getUser();
user.setUserName(sysUser.getUserName()); currentUser.setNickName(user.getNickName());
if (StringUtils.isNotEmpty(user.getPhonenumber()) currentUser.setEmail(user.getEmail());
&& userService.checkPhoneUnique(user)) currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
{ {
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
if (StringUtils.isNotEmpty(user.getEmail()) if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
&& userService.checkEmailUnique(user))
{ {
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
} }
user.setUserId(sysUser.getUserId()); if (userService.updateUserProfile(currentUser) > 0)
user.setPassword(null);
user.setAvatar(null);
user.setDeptId(null);
if (userService.updateUserProfile(user) > 0)
{ {
// 更新缓存用户信息 // 更新缓存用户信息
sysUser.setNickName(user.getNickName());
sysUser.setPhonenumber(user.getPhonenumber());
sysUser.setEmail(user.getEmail());
sysUser.setSex(user.getSex());
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return success(); return success();
} }
@@ -113,8 +107,10 @@ public class SysProfileController extends BaseController
@ApiOperation("重置密码") @ApiOperation("重置密码")
@Log(title = "个人信息", businessType = BusinessType.UPDATE) @Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd") @PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword) public AjaxResult updatePwd(@RequestBody Map<String, String> params)
{ {
String oldPassword = params.get("oldPassword");
String newPassword = params.get("newPassword");
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername(); String userName = loginUser.getUsername();
String password = loginUser.getPassword(); String password = loginUser.getPassword();
@@ -126,10 +122,11 @@ public class SysProfileController extends BaseController
{ {
return error("新密码不能与旧密码相同"); return error("新密码不能与旧密码相同");
} }
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userName, newPassword) > 0)
{ {
// 更新缓存用户密码 // 更新缓存用户密码
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); loginUser.getUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return success(); return success();
} }

View File

@@ -102,11 +102,11 @@ public class SysRoleController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysRole role) public AjaxResult add(@Validated @RequestBody SysRole role)
{ {
if (roleService.checkRoleNameUnique(role)) if (!roleService.checkRoleNameUnique(role))
{ {
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (roleService.checkRoleKeyUnique(role)) else if (!roleService.checkRoleKeyUnique(role))
{ {
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
@@ -126,11 +126,11 @@ public class SysRoleController extends BaseController
{ {
roleService.checkRoleAllowed(role); roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId()); roleService.checkRoleDataScope(role.getRoleId());
if (roleService.checkRoleNameUnique(role)) if (!roleService.checkRoleNameUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (roleService.checkRoleKeyUnique(role)) else if (!roleService.checkRoleKeyUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }
@@ -142,8 +142,8 @@ public class SysRoleController extends BaseController
LoginUser loginUser = getLoginUser(); LoginUser loginUser = getLoginUser();
if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
{ {
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
} }
return success(); return success();

View File

@@ -9,13 +9,14 @@ user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分
user.password.delete=对不起,您的账号已被删除 user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员 user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员 role.blocked=角色已封禁,请联系管理员
login.blocked=很遗憾访问IP已被列入系统黑名单
user.logout.success=退出成功 user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间 length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头 user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成且必须以非数字开头
user.password.not.valid=* 5-50个字符 user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误 user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误 user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功 user.login.success=登录成功

View File

@@ -0,0 +1,24 @@
package com.fastbee.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fastbee.common.config.serializer.SensitiveJsonSerializer;
import com.fastbee.common.enums.DesensitizedType;
/**
* 数据脱敏注解
*
* @author ruoyi
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive
{
DesensitizedType desensitizedType();
}

View File

@@ -0,0 +1,67 @@
package com.fastbee.common.config.serializer;
import java.io.IOException;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fastbee.common.annotation.Sensitive;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.enums.DesensitizedType;
import com.fastbee.common.utils.SecurityUtils;
/**
* 数据脱敏序列化过滤
*
* @author ruoyi
*/
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
{
private DesensitizedType desensitizedType;
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
{
if (desensitization())
{
gen.writeString(desensitizedType.desensitizer().apply(value));
}
else
{
gen.writeString(value);
}
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
throws JsonMappingException
{
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
{
this.desensitizedType = annotation.desensitizedType();
return this;
}
return prov.findValueSerializer(property.getType(), property);
}
/**
* 是否需要脱敏处理
*/
private boolean desensitization()
{
try
{
LoginUser securityUser = SecurityUtils.getLoginUser();
// 管理员不脱敏
return !securityUser.getUser().isAdmin();
}
catch (Exception e)
{
return true;
}
}
}

View File

@@ -21,6 +21,9 @@ public class UserConstants
/** 用户封禁状态 */ /** 用户封禁状态 */
public static final String USER_DISABLE = "1"; public static final String USER_DISABLE = "1";
/** 角色正常状态 */
public static final String ROLE_NORMAL = "0";
/** 角色封禁状态 */ /** 角色封禁状态 */
public static final String ROLE_DISABLE = "1"; public static final String ROLE_DISABLE = "1";

View File

@@ -1,12 +1,13 @@
package com.fastbee.common.core.domain; package com.fastbee.common.core.domain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects;
import com.fastbee.common.constant.HttpStatus; import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
/** /**
* 操作消息提醒 * 操作消息提醒
* *
* @author ruoyi * @author ruoyi
*/ */
public class AjaxResult extends HashMap<String, Object> public class AjaxResult extends HashMap<String, Object>
@@ -31,7 +32,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 初始化一个新创建的 AjaxResult 对象 * 初始化一个新创建的 AjaxResult 对象
* *
* @param code 状态码 * @param code 状态码
* @param msg 返回内容 * @param msg 返回内容
*/ */
@@ -43,7 +44,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 初始化一个新创建的 AjaxResult 对象 * 初始化一个新创建的 AjaxResult 对象
* *
* @param code 状态码 * @param code 状态码
* @param msg 返回内容 * @param msg 返回内容
* @param data 数据对象 * @param data 数据对象
@@ -79,7 +80,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回成功消息 * 返回成功消息
* *
* @return 成功消息 * @return 成功消息
*/ */
public static AjaxResult success() public static AjaxResult success()
@@ -89,7 +90,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回成功数据 * 返回成功数据
* *
* @return 成功消息 * @return 成功消息
*/ */
public static AjaxResult success(Object data) public static AjaxResult success(Object data)
@@ -109,7 +110,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回成功消息 * 返回成功消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @return 成功消息 * @return 成功消息
*/ */
@@ -120,7 +121,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回成功消息 * 返回成功消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @param data 数据对象 * @param data 数据对象
* @return 成功消息 * @return 成功消息
@@ -155,7 +156,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回错误消息 * 返回错误消息
* *
* @return 错误消息 * @return 错误消息
*/ */
public static AjaxResult error() public static AjaxResult error()
@@ -165,7 +166,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回错误消息 * 返回错误消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @return 错误消息 * @return 错误消息
*/ */
@@ -176,7 +177,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回错误消息 * 返回错误消息
* *
* @param msg 返回内容 * @param msg 返回内容
* @param data 数据对象 * @param data 数据对象
* @return 错误消息 * @return 错误消息
@@ -188,7 +189,7 @@ public class AjaxResult extends HashMap<String, Object>
/** /**
* 返回错误消息 * 返回错误消息
* *
* @param code 状态码 * @param code 状态码
* @param msg 返回内容 * @param msg 返回内容
* @return 错误消息 * @return 错误消息
@@ -198,6 +199,36 @@ public class AjaxResult extends HashMap<String, Object>
return new AjaxResult(code, msg, null); return new AjaxResult(code, msg, null);
} }
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess()
{
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn()
{
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError()
{
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/** /**
* 方便链式调用 * 方便链式调用
* *

View File

@@ -14,7 +14,7 @@ import com.fastbee.common.core.domain.BaseEntity;
/** /**
* 菜单权限表 sys_menu * 菜单权限表 sys_menu
* *
* @author ruoyi * @author ruoyi
*/ */
@ApiModel(value = "SysMenu", description = "菜单权限表 sys_menu") @ApiModel(value = "SysMenu", description = "菜单权限表 sys_menu")
@@ -54,6 +54,9 @@ public class SysMenu extends BaseEntity
@ApiModelProperty("路由参数") @ApiModelProperty("路由参数")
private String query; private String query;
/** 路由名称默认和路由地址相同的驼峰格式注意因为vue3版本的router会删除名称相同路由为避免名字的冲突特殊情况可以自定义 */
private String routeName;
/** 是否为外链0是 1否 */ /** 是否为外链0是 1否 */
@ApiModelProperty("是否为外链0是 1否") @ApiModelProperty("是否为外链0是 1否")
private String isFrame; private String isFrame;
@@ -69,7 +72,7 @@ public class SysMenu extends BaseEntity
/** 显示状态0显示 1隐藏 */ /** 显示状态0显示 1隐藏 */
@ApiModelProperty("显示状态0显示 1隐藏") @ApiModelProperty("显示状态0显示 1隐藏")
private String visible; private String visible;
/** 菜单状态0正常 1停用 */ /** 菜单状态0正常 1停用 */
@ApiModelProperty("菜单状态0正常 1停用") @ApiModelProperty("菜单状态0正常 1停用")
private String status; private String status;
@@ -171,6 +174,16 @@ public class SysMenu extends BaseEntity
this.query = query; this.query = query;
} }
public String getRouteName()
{
return routeName;
}
public void setRouteName(String routeName)
{
this.routeName = routeName;
}
public String getIsFrame() public String getIsFrame()
{ {
return isFrame; return isFrame;
@@ -252,7 +265,7 @@ public class SysMenu extends BaseEntity
{ {
this.children = children; this.children = children;
} }
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -262,6 +275,8 @@ public class SysMenu extends BaseEntity
.append("orderNum", getOrderNum()) .append("orderNum", getOrderNum())
.append("path", getPath()) .append("path", getPath())
.append("component", getComponent()) .append("component", getComponent())
.append("query", getQuery())
.append("routeName", getRouteName())
.append("isFrame", getIsFrame()) .append("isFrame", getIsFrame())
.append("IsCache", getIsCache()) .append("IsCache", getIsCache())
.append("menuType", getMenuType()) .append("menuType", getMenuType())

View File

@@ -17,7 +17,7 @@ import com.fastbee.common.xss.Xss;
/** /**
* 用户对象 sys_user * 用户对象 sys_user
* *
* @author ruoyi * @author ruoyi
*/ */
@ApiModel(value = "SysUser", description = "用户对象 sys_user") @ApiModel(value = "SysUser", description = "用户对象 sys_user")
@@ -27,7 +27,7 @@ public class SysUser extends BaseEntity
/** 用户ID */ /** 用户ID */
@ApiModelProperty("用户ID") @ApiModelProperty("用户ID")
@Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
private Long userId; private Long userId;
/** 部门ID */ /** 部门ID */
@@ -52,7 +52,7 @@ public class SysUser extends BaseEntity
/** 手机号码 */ /** 手机号码 */
@ApiModelProperty("手机号码") @ApiModelProperty("手机号码")
@Excel(name = "手机号码") @Excel(name = "手机号码", cellType = ColumnType.TEXT)
private String phonenumber; private String phonenumber;
/** 用户性别 */ /** 用户性别 */

View File

@@ -13,8 +13,7 @@ import java.util.Set;
* *
* @author ruoyi * @author ruoyi
*/ */
public class LoginUser implements UserDetails public class LoginUser implements UserDetails {
{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /**
@@ -81,6 +80,29 @@ public class LoginUser implements UserDetails
private Boolean neverExpire = Boolean.FALSE; private Boolean neverExpire = Boolean.FALSE;
public LoginUser() {
}
public LoginUser(SysUser user, Set<String> permissions) {
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, String language, SysUser user, Set<String> permissions) {
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.language = language;
this.permissions = permissions;
}
public Boolean getNeverExpire() { public Boolean getNeverExpire() {
return neverExpire; return neverExpire;
} }
@@ -105,33 +127,27 @@ public class LoginUser implements UserDetails
this.language = language; this.language = language;
} }
public Long getUserId() public Long getUserId() {
{
return userId; return userId;
} }
public void setUserId(Long userId) public void setUserId(Long userId) {
{
this.userId = userId; this.userId = userId;
} }
public Long getDeptId() public Long getDeptId() {
{
return deptId; return deptId;
} }
public void setDeptId(Long deptId) public void setDeptId(Long deptId) {
{
this.deptId = deptId; this.deptId = deptId;
} }
public String getToken() public String getToken() {
{
return token; return token;
} }
public void setToken(String token) public void setToken(String token) {
{
this.token = token; this.token = token;
} }
@@ -143,43 +159,15 @@ public class LoginUser implements UserDetails
this.requestToken = requestToken; this.requestToken = requestToken;
} }
public LoginUser()
{
}
public LoginUser(SysUser user, Set<String> permissions)
{
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, String language, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.language = language;
this.permissions = permissions;
}
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public String getPassword() public String getPassword() {
{
return user.getPassword(); return user.getPassword();
} }
@Override @Override
public String getUsername() public String getUsername() {
{
return user.getUserName(); return user.getUserName();
} }
@@ -188,8 +176,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isAccountNonExpired() public boolean isAccountNonExpired() {
{
return true; return true;
} }
@@ -200,8 +187,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isAccountNonLocked() public boolean isAccountNonLocked() {
{
return true; return true;
} }
@@ -212,8 +198,7 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isCredentialsNonExpired() public boolean isCredentialsNonExpired() {
{
return true; return true;
} }
@@ -224,94 +209,76 @@ public class LoginUser implements UserDetails
*/ */
@JSONField(serialize = false) @JSONField(serialize = false)
@Override @Override
public boolean isEnabled() public boolean isEnabled() {
{
return true; return true;
} }
public Long getLoginTime() public Long getLoginTime() {
{
return loginTime; return loginTime;
} }
public void setLoginTime(Long loginTime) public void setLoginTime(Long loginTime) {
{
this.loginTime = loginTime; this.loginTime = loginTime;
} }
public String getIpaddr() public String getIpaddr() {
{
return ipaddr; return ipaddr;
} }
public void setIpaddr(String ipaddr) public void setIpaddr(String ipaddr) {
{
this.ipaddr = ipaddr; this.ipaddr = ipaddr;
} }
public String getLoginLocation() public String getLoginLocation() {
{
return loginLocation; return loginLocation;
} }
public void setLoginLocation(String loginLocation) public void setLoginLocation(String loginLocation) {
{
this.loginLocation = loginLocation; this.loginLocation = loginLocation;
} }
public String getBrowser() public String getBrowser() {
{
return browser; return browser;
} }
public void setBrowser(String browser) public void setBrowser(String browser) {
{
this.browser = browser; this.browser = browser;
} }
public String getOs() public String getOs() {
{
return os; return os;
} }
public void setOs(String os) public void setOs(String os) {
{
this.os = os; this.os = os;
} }
public Long getExpireTime() public Long getExpireTime() {
{
return expireTime; return expireTime;
} }
public void setExpireTime(Long expireTime) public void setExpireTime(Long expireTime) {
{
this.expireTime = expireTime; this.expireTime = expireTime;
} }
public Set<String> getPermissions() public Set<String> getPermissions() {
{
return permissions; return permissions;
} }
public void setPermissions(Set<String> permissions) public void setPermissions(Set<String> permissions) {
{
this.permissions = permissions; this.permissions = permissions;
} }
public SysUser getUser() public SysUser getUser() {
{
return user; return user;
} }
public void setUser(SysUser user) public void setUser(SysUser user) {
{
this.user = user; this.user = user;
} }
@Override @Override
public Collection<? extends GrantedAuthority> getAuthorities() public Collection<? extends GrantedAuthority> getAuthorities() {
{
return null; return null;
} }
} }

View File

@@ -0,0 +1,61 @@
package com.fastbee.common.exception.file;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 文件上传异常类
*
* @author ruoyi
*/
public class FileUploadException extends Exception
{
private static final long serialVersionUID = 1L;
private final Throwable cause;
public FileUploadException()
{
this(null, null);
}
public FileUploadException(final String msg)
{
this(msg, null);
}
public FileUploadException(String msg, Throwable cause)
{
super(msg);
this.cause = cause;
}
@Override
public void printStackTrace(PrintStream stream)
{
super.printStackTrace(stream);
if (cause != null)
{
stream.println("Caused by:");
cause.printStackTrace(stream);
}
}
@Override
public void printStackTrace(PrintWriter writer)
{
super.printStackTrace(writer);
if (cause != null)
{
writer.println("Caused by:");
cause.printStackTrace(writer);
}
}
@Override
public Throwable getCause()
{
return cause;
}
}

View File

@@ -0,0 +1,16 @@
package com.fastbee.common.exception.user;
/**
* 黑名单IP异常类
*
* @author ruoyi
*/
public class BlackListException extends UserException
{
private static final long serialVersionUID = 1L;
public BlackListException()
{
super("login.blocked", null);
}
}

View File

@@ -0,0 +1,16 @@
package com.fastbee.common.exception.user;
/**
* 用户不存在异常类
*
* @author ruoyi
*/
public class UserNotExistsException extends UserException
{
private static final long serialVersionUID = 1L;
public UserNotExistsException()
{
super("user.not.exists", null);
}
}

View File

@@ -16,7 +16,7 @@ import com.fastbee.common.enums.HttpMethod;
/** /**
* 防止XSS攻击的过滤器 * 防止XSS攻击的过滤器
* *
* @author ruoyi * @author ruoyi
*/ */
public class XssFilter implements Filter public class XssFilter implements Filter
@@ -32,10 +32,10 @@ public class XssFilter implements Filter
String tempExcludes = filterConfig.getInitParameter("excludes"); String tempExcludes = filterConfig.getInitParameter("excludes");
if (StringUtils.isNotEmpty(tempExcludes)) if (StringUtils.isNotEmpty(tempExcludes))
{ {
String[] url = tempExcludes.split(","); String[] urls = tempExcludes.split(",");
for (int i = 0; url != null && i < url.length; i++) for (String url : urls)
{ {
excludes.add(url[i]); excludes.add(url);
} }
} }
} }
@@ -72,4 +72,4 @@ public class XssFilter implements Filter
{ {
} }
} }

View File

@@ -5,7 +5,7 @@ import java.math.RoundingMode;
/** /**
* 精确的浮点数运算 * 精确的浮点数运算
* *
* @author ruoyi * @author ruoyi
*/ */
public class Arith public class Arith
@@ -108,7 +108,6 @@ public class Arith
"The scale must be a positive integer or zero"); "The scale must be a positive integer or zero");
} }
BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = BigDecimal.ONE; return b.divide(BigDecimal.ONE, scale, RoundingMode.HALF_UP).doubleValue();
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
} }
} }

View File

@@ -379,6 +379,18 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return new HashSet<String>(str2List(str, sep, true, false)); return new HashSet<String>(str2List(str, sep, true, false));
} }
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @return list集合
*/
public static final List<String> str2List(String str, String sep)
{
return str2List(str, sep, true, false);
}
/** /**
* 字符串转list * 字符串转list
* *

View File

@@ -21,6 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import org.springframework.http.MediaType;
/** /**
* 通用http发送方法 * 通用http发送方法
@@ -74,7 +75,7 @@ public class HttpUtils
URLConnection connection = realUrl.openConnection(); URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
connection.connect(); connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
String line; String line;
@@ -121,10 +122,23 @@ public class HttpUtils
* 向指定 URL 发送POST方法的请求 * 向指定 URL 发送POST方法的请求
* *
* @param url 发送请求的 URL * @param url 发送请求的 URL
* @param param 请求参数,请求参数应该是 JSON String格式 的形式。 * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果 * @return 所代表远程资源的响应结果
*/ */
public static String sendPost(String url, String param) public static String sendPost(String url, String param)
{
return sendPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param param 请求参数
* @param contentType 内容类型
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param, String contentType)
{ {
PrintWriter out = null; PrintWriter out = null;
BufferedReader in = null; BufferedReader in = null;
@@ -136,9 +150,9 @@ public class HttpUtils
URLConnection conn = realUrl.openConnection(); URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8"); conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true); conn.setDoOutput(true);
conn.setDoInput(true); conn.setDoInput(true);
out = new PrintWriter(conn.getOutputStream()); out = new PrintWriter(conn.getOutputStream());
@@ -190,6 +204,11 @@ public class HttpUtils
} }
public static String sendSSLPost(String url, String param) public static String sendSSLPost(String url, String param)
{
return sendSSLPost(url, param, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
}
public static String sendSSLPost(String url, String param, String contentType)
{ {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
String urlNameString = url + "?" + param; String urlNameString = url + "?" + param;
@@ -202,9 +221,9 @@ public class HttpUtils
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("contentType", "utf-8"); conn.setRequestProperty("Content-Type", contentType);
conn.setDoOutput(true); conn.setDoOutput(true);
conn.setDoInput(true); conn.setDoInput(true);

View File

@@ -51,6 +51,8 @@ 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 SEPARATOR = ",";
public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
@@ -316,7 +318,7 @@ public class ExcelUtil<T>
throw new IOException("文件sheet不存在"); throw new IOException("文件sheet不存在");
} }
boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
Map<String, PictureData> pictures; Map<String, List<PictureData>> pictures = null;
if (isXSSFWorkbook) if (isXSSFWorkbook)
{ {
pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
@@ -460,16 +462,15 @@ public class ExcelUtil<T>
} }
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{ {
PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); StringBuilder propertyString = new StringBuilder();
if (image == null) List<PictureData> images = pictures.get(row.getRowNum() + "_" + entry.getKey());
for (PictureData picture : images)
{ {
val = ""; byte[] data = picture.getData();
} String fileName = FileUtils.writeImportBytes(data);
else propertyString.append(fileName).append(SEPARATOR);
{
byte[] data = image.getData();
val = FileUtils.writeImportBytes(data);
} }
val = StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
} }
ReflectUtils.invokeSetter(entity, propertyName, val); ReflectUtils.invokeSetter(entity, propertyName, val);
} }
@@ -993,12 +994,15 @@ public class ExcelUtil<T>
else if (ColumnType.IMAGE == attr.cellType()) else if (ColumnType.IMAGE == attr.cellType())
{ {
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
String imagePath = Convert.toStr(value); String propertyValue = Convert.toStr(value);
if (StringUtils.isNotEmpty(imagePath)) if (StringUtils.isNotEmpty(propertyValue))
{ {
byte[] data = ImageUtils.getImage(imagePath); List<String> imagePaths = StringUtils.str2List(propertyValue, SEPARATOR);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor, for (String imagePath : imagePaths)
cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); {
byte[] data = ImageUtils.getImage(imagePath);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
}
} }
} }
} }
@@ -1243,7 +1247,7 @@ public class ExcelUtil<T>
public static String convertByExp(String propertyValue, String converterExp, String separator) public static String convertByExp(String propertyValue, String converterExp, String separator)
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
@@ -1280,7 +1284,7 @@ public class ExcelUtil<T>
public static String reverseByExp(String propertyValue, String converterExp, String separator) public static String reverseByExp(String propertyValue, String converterExp, String separator)
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(SEPARATOR);
for (String item : convertSource) for (String item : convertSource)
{ {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
@@ -1706,30 +1710,24 @@ public class ExcelUtil<T>
* @param workbook 工作簿对象 * @param workbook 工作簿对象
* @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData * @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData
*/ */
public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) public static Map<String, List<PictureData>> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
{ {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
List<HSSFPictureData> pictures = workbook.getAllPictures(); List<HSSFPictureData> pictures = workbook.getAllPictures();
if (!pictures.isEmpty()) if (!pictures.isEmpty() && sheet.getDrawingPatriarch() != null)
{ {
for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())
{ {
HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
if (shape instanceof HSSFPicture) if (shape instanceof HSSFPicture)
{ {
HSSFPicture pic = (HSSFPicture) shape; HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1; HSSFClientAnchor anchor = (HSSFClientAnchor) pic.getAnchor();
HSSFPictureData picData = pictures.get(pictureIndex);
String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
sheetIndexPicMap.put(picIndex, picData); sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
} }
} }
return sheetIndexPicMap;
}
else
{
return sheetIndexPicMap;
} }
return sheetIndexPicMap;
} }
/** /**
@@ -1739,16 +1737,15 @@ public class ExcelUtil<T>
* @param workbook 工作簿对象 * @param workbook 工作簿对象
* @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData * @return Map key:图片单元格索引1_1Stringvalue:图片流PictureData
*/ */
public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) public static Map<String, List<PictureData>> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
{ {
Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); Map<String, List<PictureData>> sheetIndexPicMap = new HashMap<>();
for (POIXMLDocumentPart dr : sheet.getRelations()) for (POIXMLDocumentPart dr : sheet.getRelations())
{ {
if (dr instanceof XSSFDrawing) if (dr instanceof XSSFDrawing)
{ {
XSSFDrawing drawing = (XSSFDrawing) dr; XSSFDrawing drawing = (XSSFDrawing) dr;
List<XSSFShape> shapes = drawing.getShapes(); for (XSSFShape shape : drawing.getShapes())
for (XSSFShape shape : shapes)
{ {
if (shape instanceof XSSFPicture) if (shape instanceof XSSFPicture)
{ {
@@ -1756,7 +1753,7 @@ public class ExcelUtil<T>
XSSFClientAnchor anchor = pic.getPreferredSize(); XSSFClientAnchor anchor = pic.getPreferredSize();
CTMarker ctMarker = anchor.getFrom(); CTMarker ctMarker = anchor.getFrom();
String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
sheetIndexPicMap.put(picIndex, pic.getPictureData()); sheetIndexPicMap.computeIfAbsent(picIndex, k -> new ArrayList<>()).add(pic.getPictureData());
} }
} }
} }

View File

@@ -1,5 +1,6 @@
package com.fastbee.common.utils.spring; package com.fastbee.common.utils.spring;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopContext; import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -18,11 +19,11 @@ import java.util.Map;
/** /**
* spring工具类 方便在非spring管理环境中获取bean * spring工具类 方便在非spring管理环境中获取bean
* *
* @author ruoyi * @author ruoyi
*/ */
@Component @Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
{ {
/** Spring应用上下文环境 */ /** Spring应用上下文环境 */
private static ConfigurableListableBeanFactory beanFactory; private static ConfigurableListableBeanFactory beanFactory;
@@ -30,13 +31,13 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
private static ApplicationContext applicationContext; private static ApplicationContext applicationContext;
@Override @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
{ {
SpringUtils.beanFactory = beanFactory; SpringUtils.beanFactory = beanFactory;
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{ {
SpringUtils.applicationContext = applicationContext; SpringUtils.applicationContext = applicationContext;
} }
@@ -119,14 +120,19 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
/** /**
* 获取aop代理对象 * 获取aop代理对象
* *
* @param invoker * @param invoker
* @return * @return
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) public static <T> T getAopProxy(T invoker)
{ {
return (T) AopContext.currentProxy(); Object proxy = AopContext.currentProxy();
if (((Advised) proxy).getTargetSource().getTargetClass() == invoker.getClass())
{
return (T) proxy;
}
return invoker;
} }
/** /**

View File

@@ -22,21 +22,21 @@ public class Seq
private static AtomicInteger uploadSeq = new AtomicInteger(1); private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识 // 机器标识
private static String machineCode = "A"; private static final String machineCode = "A";
/** /**
* 获取通用序列号 * 获取通用序列号
* *
* @return 序列值 * @return 序列值
*/ */
public static String getId() public static String getId()
{ {
return getId(commSeqType); return getId(commSeqType);
} }
/** /**
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串 * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
* *
* @return 序列值 * @return 序列值
*/ */
public static String getId(String type) public static String getId(String type)
@@ -51,7 +51,7 @@ public class Seq
/** /**
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串 * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
* *
* @param atomicInt 序列数 * @param atomicInt 序列数
* @param length 数值长度 * @param length 数值长度
* @return 序列值 * @return 序列值
@@ -66,7 +66,7 @@ public class Seq
/** /**
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数 * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
* *
* @return 序列值 * @return 序列值
*/ */
private synchronized static String getSeq(AtomicInteger atomicInt, int length) private synchronized static String getSeq(AtomicInteger atomicInt, int length)

View File

@@ -8,7 +8,7 @@ import java.util.regex.Pattern;
/** /**
* 自定义xss校验注解实现 * 自定义xss校验注解实现
* *
* @author ruoyi * @author ruoyi
*/ */
public class XssValidator implements ConstraintValidator<Xss, String> public class XssValidator implements ConstraintValidator<Xss, String>
@@ -27,8 +27,13 @@ public class XssValidator implements ConstraintValidator<Xss, String>
public static boolean containsHtml(String value) public static boolean containsHtml(String value)
{ {
StringBuilder sHtml = new StringBuilder();
Pattern pattern = Pattern.compile(HTML_PATTERN); Pattern pattern = Pattern.compile(HTML_PATTERN);
Matcher matcher = pattern.matcher(value); Matcher matcher = pattern.matcher(value);
return matcher.matches(); while (matcher.find())
{
sHtml.append(matcher.group());
}
return pattern.matcher(sHtml).matches();
} }
} }

View File

@@ -7,6 +7,7 @@ import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.fastbee.common.annotation.DataScope; import com.fastbee.common.annotation.DataScope;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.BaseEntity; import com.fastbee.common.core.domain.BaseEntity;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
@@ -73,8 +74,7 @@ public class DataScopeAspect
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext()); String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
controllerDataScope.userAlias(), permission);
} }
} }
} }
@@ -92,29 +92,42 @@ public class DataScopeAspect
{ {
StringBuilder sqlString = new StringBuilder(); StringBuilder sqlString = new StringBuilder();
List<String> conditions = new ArrayList<String>(); 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)))
{
scopeCustomIds.add(Convert.toStr(role.getRoleId()));
}
});
for (SysRole role : user.getRoles()) for (SysRole role : user.getRoles())
{ {
String dataScope = role.getDataScope(); String dataScope = role.getDataScope();
if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope)) if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
{ {
continue; continue;
} }
if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions()) if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{ {
continue; continue;
} }
if (DATA_SCOPE_ALL.equals(dataScope)) if (DATA_SCOPE_ALL.equals(dataScope))
{ {
sqlString = new StringBuilder(); sqlString = new StringBuilder();
conditions.add(dataScope);
break; break;
} }
else if (DATA_SCOPE_CUSTOM.equals(dataScope)) else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{ {
sqlString.append(StringUtils.format( if (scopeCustomIds.size() > 1)
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, {
role.getRoleId())); // 多个自定数据权限使用in查询避免多次拼接。
sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
}
else
{
sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
}
} }
else if (DATA_SCOPE_DEPT.equals(dataScope)) else if (DATA_SCOPE_DEPT.equals(dataScope))
{ {
@@ -122,9 +135,7 @@ public class DataScopeAspect
} }
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{ {
sqlString.append(StringUtils.format( sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, user.getDeptId(), user.getDeptId()));
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getDeptId(), user.getDeptId()));
} }
else if (DATA_SCOPE_SELF.equals(dataScope)) else if (DATA_SCOPE_SELF.equals(dataScope))
{ {
@@ -141,6 +152,12 @@ public class DataScopeAspect
conditions.add(dataScope); conditions.add(dataScope);
} }
// 角色都不包含传递过来的权限字符这个时候sqlString也会为空所以要限制一下,不查询任何数据
if (StringUtils.isEmpty(conditions))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
if (StringUtils.isNotBlank(sqlString.toString())) if (StringUtils.isNotBlank(sqlString.toString()))
{ {
Object params = joinPoint.getArgs()[0]; Object params = joinPoint.getArgs()[0];

View File

@@ -79,7 +79,7 @@ public class RateLimiterAspect
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key()); StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP) if (rateLimiter.limitType() == LimitType.IP)
{ {
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-"); stringBuffer.append(IpUtils.getIpAddr()).append("-");
} }
MethodSignature signature = (MethodSignature) point.getSignature(); MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod(); Method method = signature.getMethod();

View File

@@ -0,0 +1,43 @@
package com.fastbee.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import com.fastbee.common.constant.Constants;
/**
* 资源文件配置加载
*
* @author ruoyi
*/
@Configuration
public class I18nConfig implements WebMvcConfigurer
{
@Bean
public LocaleResolver localeResolver()
{
SessionLocaleResolver slr = new SessionLocaleResolver();
// 默认语言
slr.setDefaultLocale(Constants.DEFAULT_LOCALE);
return slr;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor()
{
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
// 参数名
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(localeChangeInterceptor());
}
}

View File

@@ -1,6 +1,7 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
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.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -14,6 +15,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport public class RedisConfig extends CachingConfigurerSupport
{ {
@Bean @Bean

View File

@@ -17,7 +17,7 @@ import com.fastbee.framework.interceptor.RepeatSubmitInterceptor;
/** /**
* 通用配置 * 通用配置
* *
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@@ -36,7 +36,7 @@ public class ResourcesConfig implements WebMvcConfigurer
/** swagger配置 */ /** swagger配置 */
registry.addResourceHandler("/swagger-ui/**") registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/") .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());; .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());
} }
/** /**
@@ -70,4 +70,4 @@ public class ResourcesConfig implements WebMvcConfigurer
// 返回新的CorsFilter // 返回新的CorsFilter
return new CorsFilter(source); return new CorsFilter(source);
} }
} }

View File

@@ -3,6 +3,7 @@ package com.fastbee.framework.config.properties;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.RegExUtils;
@@ -19,7 +20,7 @@ import com.fastbee.common.annotation.Anonymous;
/** /**
* 设置Anonymous注解允许匿名访问的url * 设置Anonymous注解允许匿名访问的url
* *
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@@ -44,12 +45,12 @@ public class PermitAllUrlProperties implements InitializingBean, ApplicationCont
// 获取方法上边的注解 替代path variable 为 * // 获取方法上边的注解 替代path variable 为 *
Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class); Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
Optional.ofNullable(method).ifPresent(anonymous -> info.getPatternsCondition().getPatterns() Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
// 获取类上边的注解, 替代path variable 为 * // 获取类上边的注解, 替代path variable 为 *
Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class); Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns() Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK)))); .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
}); });
} }

View File

@@ -5,7 +5,7 @@ import org.slf4j.LoggerFactory;
/** /**
* 数据源切换处理 * 数据源切换处理
* *
* @author ruoyi * @author ruoyi
*/ */
public class DynamicDataSourceContextHolder public class DynamicDataSourceContextHolder
@@ -14,7 +14,7 @@ public class DynamicDataSourceContextHolder
/** /**
* 使用ThreadLocal维护变量ThreadLocal为每个使用该变量的线程提供独立的变量副本 * 使用ThreadLocal维护变量ThreadLocal为每个使用该变量的线程提供独立的变量副本
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/ */
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

View File

@@ -47,8 +47,9 @@ public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
/** /**
* 验证是否重复提交由子类实现具体的防重复提交的规则 * 验证是否重复提交由子类实现具体的防重复提交的规则
* *
* @param request * @param request 请求信息
* @return * @param annotation 防重复注解参数
* @return 结果
* @throws Exception * @throws Exception
*/ */
public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation); public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);

View File

@@ -18,7 +18,7 @@ import eu.bitwalker.useragentutils.UserAgent;
/** /**
* 异步工厂(产生任务用) * 异步工厂(产生任务用)
* *
* @author ruoyi * @author ruoyi
*/ */
public class AsyncFactory public class AsyncFactory
@@ -27,7 +27,7 @@ public class AsyncFactory
/** /**
* 记录登录信息 * 记录登录信息
* *
* @param username 用户名 * @param username 用户名
* @param status 状态 * @param status 状态
* @param message 消息 * @param message 消息
@@ -38,7 +38,7 @@ public class AsyncFactory
final Object... args) final Object... args)
{ {
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
final String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); final String ip = IpUtils.getIpAddr();
return new TimerTask() return new TimerTask()
{ {
@Override @Override
@@ -82,7 +82,7 @@ public class AsyncFactory
/** /**
* 操作日志记录 * 操作日志记录
* *
* @param operLog 操作日志信息 * @param operLog 操作日志信息
* @return 任务task * @return 任务task
*/ */

View File

@@ -4,6 +4,8 @@ import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.fastbee.common.utils.MessageUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -20,7 +22,7 @@ import com.fastbee.framework.web.service.TokenService;
/** /**
* 自定义退出处理类 返回成功 * 自定义退出处理类 返回成功
* *
* @author ruoyi * @author ruoyi
*/ */
@Configuration @Configuration
@@ -31,7 +33,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
/** /**
* 退出处理 * 退出处理
* *
* @return * @return
*/ */
@Override @Override
@@ -45,8 +47,8 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
// 删除用户缓存记录 // 删除用户缓存记录
tokenService.delLoginUser(loginUser.getToken()); tokenService.delLoginUser(loginUser.getToken());
// 记录用户退出日志 // 记录用户退出日志
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功")); AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
} }
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success("退出成功"))); ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
} }
} }

View File

@@ -7,17 +7,21 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import com.fastbee.common.constant.HttpStatus; import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.core.domain.AjaxResult; import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.text.Convert;
import com.fastbee.common.exception.DemoModeException; import com.fastbee.common.exception.DemoModeException;
import com.fastbee.common.exception.ServiceException; import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.html.EscapeUtil;
/** /**
* 全局异常处理器 * 全局异常处理器
* *
* @author ruoyi * @author ruoyi
*/ */
@RestControllerAdvice @RestControllerAdvice
@@ -59,6 +63,33 @@ public class GlobalExceptionHandler
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage()); return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
} }
/**
* 请求路径中缺少必需的路径变量
*/
@ExceptionHandler(MissingPathVariableException.class)
public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
}
/**
* 请求参数类型不匹配
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
String value = Convert.toStr(e.getValue());
if (StringUtils.isNotEmpty(value))
{
value = EscapeUtil.clean(value);
}
log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value));
}
/** /**
* 拦截未知的运行时异常 * 拦截未知的运行时异常
*/ */

View File

@@ -3,6 +3,7 @@ package com.fastbee.framework.web.service;
import java.util.Set; import java.util.Set;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.model.LoginUser; import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.SecurityUtils;
@@ -11,25 +12,15 @@ import com.fastbee.framework.security.context.PermissionContextHolder;
/** /**
* RuoYi首创 自定义权限实现ss取自SpringSecurity首字母 * RuoYi首创 自定义权限实现ss取自SpringSecurity首字母
* *
* @author ruoyi * @author ruoyi
*/ */
@Service("ss") @Service("ss")
public class PermissionService public class PermissionService
{ {
/** 所有权限标识 */
private static final String ALL_PERMISSION = "*:*:*";
/** 管理员角色权限标识 */
private static final String SUPER_ADMIN = "admin";
private static final String ROLE_DELIMETER = ",";
private static final String PERMISSION_DELIMETER = ",";
/** /**
* 验证用户是否具备某权限 * 验证用户是否具备某权限
* *
* @param permission 权限字符串 * @param permission 权限字符串
* @return 用户是否具备某权限 * @return 用户是否具备某权限
*/ */
@@ -78,7 +69,7 @@ public class PermissionService
} }
PermissionContextHolder.setContext(permissions); PermissionContextHolder.setContext(permissions);
Set<String> authorities = loginUser.getPermissions(); Set<String> authorities = loginUser.getPermissions();
for (String permission : permissions.split(PERMISSION_DELIMETER)) for (String permission : permissions.split(Constants.PERMISSION_DELIMETER))
{ {
if (permission != null && hasPermissions(authorities, permission)) if (permission != null && hasPermissions(authorities, permission))
{ {
@@ -90,7 +81,7 @@ public class PermissionService
/** /**
* 判断用户是否拥有某个角色 * 判断用户是否拥有某个角色
* *
* @param role 角色字符串 * @param role 角色字符串
* @return 用户是否具备某角色 * @return 用户是否具备某角色
*/ */
@@ -108,7 +99,7 @@ public class PermissionService
for (SysRole sysRole : loginUser.getUser().getRoles()) for (SysRole sysRole : loginUser.getUser().getRoles())
{ {
String roleKey = sysRole.getRoleKey(); String roleKey = sysRole.getRoleKey();
if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
{ {
return true; return true;
} }
@@ -144,7 +135,7 @@ public class PermissionService
{ {
return false; return false;
} }
for (String role : roles.split(ROLE_DELIMETER)) for (String role : roles.split(Constants.ROLE_DELIMETER))
{ {
if (hasRole(role)) if (hasRole(role))
{ {
@@ -156,13 +147,13 @@ public class PermissionService
/** /**
* 判断是否包含权限 * 判断是否包含权限
* *
* @param permissions 权限列表 * @param permissions 权限列表
* @param permission 权限字符串 * @param permission 权限字符串
* @return 用户是否具备某权限 * @return 用户是否具备某权限
*/ */
private boolean hasPermissions(Set<String> permissions, String permission) private boolean hasPermissions(Set<String> permissions, String permission)
{ {
return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
} }
} }

View File

@@ -2,17 +2,15 @@ package com.fastbee.framework.web.service;
import com.fastbee.common.constant.CacheConstants; import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser; import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.core.redis.RedisCache; import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.enums.UserStatus; import com.fastbee.common.enums.UserStatus;
import com.fastbee.common.exception.ServiceException; import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.exception.user.CaptchaException; import com.fastbee.common.exception.user.*;
import com.fastbee.common.exception.user.CaptchaExpireException;
import com.fastbee.common.exception.user.UserPasswordNotMatchException;
import com.fastbee.common.utils.DateUtils; import com.fastbee.common.utils.DateUtils;
import com.fastbee.common.utils.MessageUtils; import com.fastbee.common.utils.MessageUtils;
import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.common.utils.ip.IpUtils; import com.fastbee.common.utils.ip.IpUtils;
import com.fastbee.framework.manager.AsyncManager; import com.fastbee.framework.manager.AsyncManager;
@@ -70,12 +68,10 @@ public class SysLoginService
*/ */
public String login(String username, String password, String code, String uuid) public String login(String username, String password, String code, String uuid)
{ {
boolean captchaEnabled = configService.selectCaptchaEnabled(); // 验证码校验
// 验证码开关 validateCaptcha(username, code, uuid);
if (captchaEnabled) // 登录前置校验
{ loginPreCheck(username, password);
validateCaptcha(username, code, uuid);
}
// 用户验证 // 用户验证
Authentication authentication = null; Authentication authentication = null;
try try
@@ -186,18 +182,58 @@ public class SysLoginService
*/ */
public void validateCaptcha(String username, String code, String uuid) public void validateCaptcha(String username, String code, String uuid)
{ {
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); boolean captchaEnabled = configService.selectCaptchaEnabled();
String captcha = redisCache.getCacheObject(verifyKey); if (captchaEnabled)
redisCache.deleteObject(verifyKey);
if (captcha == null)
{ {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
throw new CaptchaExpireException(); String captcha = redisCache.getCacheObject(verifyKey);
if (captcha == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
redisCache.deleteObject(verifyKey);
if (!code.equalsIgnoreCase(captcha))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
} }
if (!code.equalsIgnoreCase(captcha)) }
/**
* 登录前置校验
* @param username 用户名
* @param password 用户密码
*/
public void loginPreCheck(String username, String password)
{
// 用户名或密码为空 错误
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{ {
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new CaptchaException(); throw new UserNotExistsException();
}
// 密码如果不在指定范围内 错误
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 用户名不在指定范围内 错误
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// IP黑名单校验
String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
throw new BlackListException();
} }
} }
@@ -210,7 +246,7 @@ public class SysLoginService
{ {
SysUser sysUser = new SysUser(); SysUser sysUser = new SysUser();
sysUser.setUserId(userId); sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest())); sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate()); sysUser.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(sysUser); userService.updateUserProfile(sysUser);
} }

View File

@@ -5,14 +5,17 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.service.ISysMenuService; import com.fastbee.system.service.ISysMenuService;
import com.fastbee.system.service.ISysRoleService; import com.fastbee.system.service.ISysRoleService;
/** /**
* 用户权限处理 * 用户权限处理
* *
* @author ruoyi * @author ruoyi
*/ */
@Component @Component
@@ -26,7 +29,7 @@ public class SysPermissionService
/** /**
* 获取角色数据权限 * 获取角色数据权限
* *
* @param user 用户信息 * @param user 用户信息
* @return 角色权限信息 * @return 角色权限信息
*/ */
@@ -47,7 +50,7 @@ public class SysPermissionService
/** /**
* 获取菜单数据权限 * 获取菜单数据权限
* *
* @param user 用户信息 * @param user 用户信息
* @return 菜单权限信息 * @return 菜单权限信息
*/ */
@@ -62,14 +65,17 @@ public class SysPermissionService
else else
{ {
List<SysRole> roles = user.getRoles(); List<SysRole> roles = user.getRoles();
if (!roles.isEmpty() && roles.size() > 1) if (!CollectionUtils.isEmpty(roles))
{ {
// 多角色设置permissions属性以便数据权限匹配权限 // 多角色设置permissions属性以便数据权限匹配权限
for (SysRole role : roles) for (SysRole role : roles)
{ {
Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && !role.isAdmin())
role.setPermissions(rolePerms); {
perms.addAll(rolePerms); Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
role.setPermissions(rolePerms);
perms.addAll(rolePerms);
}
} }
} }
else else

View File

@@ -53,7 +53,7 @@ public class TokenService {
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L; private static final Long MILLIS_MINUTE_TWENTY = 20 * 60 * 1000L;
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
@@ -160,6 +160,7 @@ public class TokenService {
Map<String, Object> claims = new HashMap<>(); Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token); claims.put(Constants.LOGIN_USER_KEY, token);
claims.put(Constants.JWT_USERNAME, loginUser.getUsername());
return createToken(claims); return createToken(claims);
} }
@@ -217,7 +218,7 @@ public class TokenService {
public void verifyToken(LoginUser loginUser) { public void verifyToken(LoginUser loginUser) {
long expireTime = loginUser.getExpireTime(); long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY) {
refreshToken(loginUser); refreshToken(loginUser);
} }
} }

View File

@@ -11,6 +11,7 @@ import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginUser; import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.enums.UserStatus; import com.fastbee.common.enums.UserStatus;
import com.fastbee.common.exception.ServiceException; import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.utils.MessageUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.service.ISysUserService; import com.fastbee.system.service.ISysUserService;
@@ -26,7 +27,7 @@ public class UserDetailsServiceImpl implements UserDetailsService
@Autowired @Autowired
private ISysUserService userService; private ISysUserService userService;
@Autowired @Autowired
private SysPasswordService passwordService; private SysPasswordService passwordService;
@@ -40,17 +41,17 @@ public class UserDetailsServiceImpl implements UserDetailsService
if (StringUtils.isNull(user)) if (StringUtils.isNull(user))
{ {
log.info("登录用户:{} 不存在.", username); log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在"); throw new ServiceException(MessageUtils.message("user.not.exists"));
} }
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{ {
log.info("登录用户:{} 已被删除.", username); log.info("登录用户:{} 已被删除.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); throw new ServiceException(MessageUtils.message("user.password.delete"));
} }
else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{ {
log.info("登录用户:{} 已被停用.", username); log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用"); throw new ServiceException(MessageUtils.message("user.blocked"));
} }
passwordService.validate(user); passwordService.validate(user);

View File

@@ -16,7 +16,7 @@ public class MqttClientConfig {
public MqttClientConfig() { public MqttClientConfig() {
this.username = "fastbee"; this.username = "fastbee";
this.password = "fastbee"; this.password = "fastbee";
this.hostUrl = "tcp://127.0.0.1:1883"; this.hostUrl = "tcp://127.0.0.1:1884";
this.clientId = UUID.randomUUID().toString(); this.clientId = UUID.randomUUID().toString();
this.defaultTopic = "test"; this.defaultTopic = "test";
this.timeout = 30; this.timeout = 30;

View File

@@ -175,7 +175,7 @@ public class SysMenuServiceImpl implements ISysMenuService
router.setQuery(menu.getQuery()); router.setQuery(menu.getQuery());
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
List<SysMenu> cMenus = menu.getChildren(); List<SysMenu> cMenus = menu.getChildren();
if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
{ {
router.setAlwaysShow(true); router.setAlwaysShow(true);
router.setRedirect("noRedirect"); router.setRedirect("noRedirect");
@@ -188,7 +188,7 @@ public class SysMenuServiceImpl implements ISysMenuService
RouterVo children = new RouterVo(); RouterVo children = new RouterVo();
children.setPath(menu.getPath()); children.setPath(menu.getPath());
children.setComponent(menu.getComponent()); children.setComponent(menu.getComponent());
children.setName(StringUtils.capitalize(menu.getPath())); children.setName(getRouteName(menu.getRouteName(), menu.getPath()));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
children.setQuery(menu.getQuery()); children.setQuery(menu.getQuery());
childrenList.add(children); childrenList.add(children);
@@ -203,7 +203,7 @@ public class SysMenuServiceImpl implements ISysMenuService
String routerPath = innerLinkReplaceEach(menu.getPath()); String routerPath = innerLinkReplaceEach(menu.getPath());
children.setPath(routerPath); children.setPath(routerPath);
children.setComponent(UserConstants.INNER_LINK); children.setComponent(UserConstants.INNER_LINK);
children.setName(StringUtils.capitalize(routerPath)); children.setName(getRouteName(menu.getRouteName(), routerPath));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
childrenList.add(children); childrenList.add(children);
router.setChildren(childrenList); router.setChildren(childrenList);
@@ -354,13 +354,25 @@ public class SysMenuServiceImpl implements ISysMenuService
*/ */
public String getRouteName(SysMenu menu) public String getRouteName(SysMenu menu)
{ {
String routerName = StringUtils.capitalize(menu.getPath());
// 非外链并且是一级目录(类型为目录) // 非外链并且是一级目录(类型为目录)
if (isMenuFrame(menu)) if (isMenuFrame(menu))
{ {
routerName = StringUtils.EMPTY; return StringUtils.EMPTY;
} }
return routerName; return getRouteName(menu.getRouteName(), menu.getPath());
}
/**
* 获取路由名称,如没有配置路由名称则取路由地址
*
* @param name 路由名称
* @param path 路由地址
* @return 路由名称(驼峰格式)
*/
public String getRouteName(String name, String path)
{
String routerName = StringUtils.isNotEmpty(name) ? name : path;
return StringUtils.capitalize(routerName);
} }
/** /**
@@ -525,7 +537,7 @@ public class SysMenuServiceImpl implements ISysMenuService
*/ */
public String innerLinkReplaceEach(String path) public String innerLinkReplaceEach(String path)
{ {
return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, "." }, return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":" },
new String[] { "", "", "", "/" }); new String[] { "", "", "", "/", "/" });
} }
} }

View File

@@ -2437,7 +2437,11 @@ CREATE TABLE `sys_oper_log` (
`status` int(1) NULL DEFAULT 0 COMMENT '操作状态0正常 1异常', `status` int(1) NULL DEFAULT 0 COMMENT '操作状态0正常 1异常',
`error_msg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '错误消息', `error_msg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '错误消息',
`oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间', `oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (`oper_id`) USING BTREE `cost_time` bigint(20) DEFAULT 0 COMMENT '消耗时间',
PRIMARY KEY (`oper_id`) USING BTREE,
KEY idx_sys_oper_log_bt (business_type),
KEY idx_sys_oper_log_s (status),
KEY idx_sys_oper_log_ot (oper_time)
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志记录' ROW_FORMAT = DYNAMIC; ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志记录' ROW_FORMAT = DYNAMIC;
-- ---------------------------- -- ----------------------------