feat(ruoyi版本同步): ruoyi-3.8.9版本同步

This commit is contained in:
zhuangpeng.li
2025-04-17 09:44:10 +08:00
parent e404cd26d4
commit ff51ea78af
62 changed files with 1814 additions and 1579 deletions

View File

@@ -84,7 +84,7 @@
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version> <version>2.5.15</version>
<configuration> <configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 --> <fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration> </configuration>

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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) if (dictTypeService.checkDictTypeUnique(dict))
{ {
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
} }

View File

@@ -1,32 +1,30 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List;
import java.util.Set;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.domain.AjaxResult; import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysMenu; import com.fastbee.common.core.domain.entity.SysMenu;
import com.fastbee.common.core.domain.entity.SysUser; import com.fastbee.common.core.domain.entity.SysUser;
import com.fastbee.common.core.domain.model.LoginBody; import com.fastbee.common.core.domain.model.LoginBody;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.framework.web.service.SysLoginService; import com.fastbee.framework.web.service.SysLoginService;
import com.fastbee.framework.web.service.SysPermissionService; import com.fastbee.framework.web.service.SysPermissionService;
import com.fastbee.framework.web.service.TokenService;
import com.fastbee.system.service.ISysMenuService; import com.fastbee.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Set;
/** /**
* 登录验证 * 登录验证
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "登录验证")
@RestController @RestController
public class SysLoginController public class SysLoginController
{ {
@@ -38,8 +36,9 @@ public class SysLoginController
@Autowired @Autowired
private SysPermissionService permissionService; private SysPermissionService permissionService;
@Value("${server.broker.enabled}")
private Boolean enabled; @Autowired
private TokenService tokenService;
/** /**
* 登录方法 * 登录方法
@@ -47,7 +46,6 @@ public class SysLoginController
* @param loginBody 登录信息 * @param loginBody 登录信息
* @return 结果 * @return 结果
*/ */
@ApiOperation("用户登录")
@PostMapping("/login") @PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) public AjaxResult login(@RequestBody LoginBody loginBody)
{ {
@@ -64,20 +62,24 @@ public class SysLoginController
* *
* @return 用户信息 * @return 用户信息
*/ */
@ApiOperation("获取用户信息")
@GetMapping("getInfo") @GetMapping("getInfo")
public AjaxResult getInfo() public AjaxResult getInfo()
{ {
SysUser user = SecurityUtils.getLoginUser().getUser(); LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser user = loginUser.getUser();
// 角色集合 // 角色集合
Set<String> roles = permissionService.getRolePermission(user); Set<String> roles = permissionService.getRolePermission(user);
// 权限集合 // 权限集合
Set<String> permissions = permissionService.getMenuPermission(user); Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("user", user); ajax.put("user", user);
ajax.put("roles", roles); ajax.put("roles", roles);
ajax.put("permissions", permissions); ajax.put("permissions", permissions);
ajax.put("mqtt",enabled);
return ajax; return ajax;
} }
@@ -86,7 +88,6 @@ public class SysLoginController
* *
* @return 路由信息 * @return 路由信息
*/ */
@ApiOperation("获取路由信息")
@GetMapping("getRouters") @GetMapping("getRouters")
public AjaxResult getRouters() public AjaxResult getRouters()
{ {

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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (postService.checkPostNameUnique(post))
{ {
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) if (postService.checkPostNameUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) else if (postService.checkPostCodeUnique(post))
{ {
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
} }

View File

@@ -81,12 +81,12 @@ public class SysProfileController extends BaseController
SysUser sysUser = loginUser.getUser(); SysUser sysUser = loginUser.getUser();
user.setUserName(sysUser.getUserName()); user.setUserName(sysUser.getUserName());
if (StringUtils.isNotEmpty(user.getPhonenumber()) if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) && userService.checkPhoneUnique(user))
{ {
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
if (StringUtils.isNotEmpty(user.getEmail()) if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) && userService.checkEmailUnique(user))
{ {
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }

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 (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (roleService.checkRoleNameUnique(role))
{ {
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(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 (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) if (roleService.checkRoleNameUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) else if (roleService.checkRoleKeyUnique(role))
{ {
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
} }

View File

@@ -1,26 +1,6 @@
package com.fastbee.web.controller.system; package com.fastbee.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.fastbee.common.annotation.Log; import com.fastbee.common.annotation.Log;
import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.controller.BaseController; import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult; import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.entity.SysDept; import com.fastbee.common.core.domain.entity.SysDept;
@@ -35,13 +15,22 @@ import com.fastbee.system.service.ISysDeptService;
import com.fastbee.system.service.ISysPostService; import com.fastbee.system.service.ISysPostService;
import com.fastbee.system.service.ISysRoleService; import com.fastbee.system.service.ISysRoleService;
import com.fastbee.system.service.ISysUserService; import com.fastbee.system.service.ISysUserService;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* 用户信息 * 用户信息
* *
* @author ruoyi * @author ruoyi
*/ */
@Api(tags = "用户管理")
@RestController @RestController
@RequestMapping("/system/user") @RequestMapping("/system/user")
public class SysUserController extends BaseController public class SysUserController extends BaseController
@@ -61,7 +50,6 @@ public class SysUserController extends BaseController
/** /**
* 获取用户列表 * 获取用户列表
*/ */
@ApiOperation("获取用户分页列表")
@PreAuthorize("@ss.hasPermi('system:user:list')") @PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo list(SysUser user) public TableDataInfo list(SysUser user)
@@ -71,7 +59,6 @@ public class SysUserController extends BaseController
return getDataTable(list); return getDataTable(list);
} }
@ApiOperation("导出用户列表")
@Log(title = "用户管理", businessType = BusinessType.EXPORT) @Log(title = "用户管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:user:export')") @PreAuthorize("@ss.hasPermi('system:user:export')")
@PostMapping("/export") @PostMapping("/export")
@@ -82,7 +69,6 @@ public class SysUserController extends BaseController
util.exportExcel(response, list, "用户数据"); util.exportExcel(response, list, "用户数据");
} }
@ApiOperation("批量导入用户")
@Log(title = "用户管理", businessType = BusinessType.IMPORT) @Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')") @PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData") @PostMapping("/importData")
@@ -95,8 +81,6 @@ public class SysUserController extends BaseController
return success(message); return success(message);
} }
@ApiOperation("下载用户导入模板")
@PostMapping("/importTemplate") @PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) public void importTemplate(HttpServletResponse response)
{ {
@@ -107,46 +91,44 @@ public class SysUserController extends BaseController
/** /**
* 根据用户编号获取详细信息 * 根据用户编号获取详细信息
*/ */
@ApiOperation("根据用户编号获取详细信息")
@PreAuthorize("@ss.hasPermi('system:user:query')") @PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = { "/", "/{userId}" }) @GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{ {
userService.checkUserDataScope(userId);
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {
userService.checkUserDataScope(userId);
SysUser sysUser = userService.selectUserById(userId); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser); ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
return ajax; return ajax;
} }
/** /**
* 新增用户 * 新增用户
*/ */
@ApiOperation("新增用户")
@PreAuthorize("@ss.hasPermi('system:user:add')") @PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT) @Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping @PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user) public AjaxResult add(@Validated @RequestBody SysUser user)
{ {
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{ {
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (StringUtils.isNotEmpty(user.getPhonenumber()) else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -158,7 +140,6 @@ public class SysUserController extends BaseController
/** /**
* 修改用户 * 修改用户
*/ */
@ApiOperation("修改用户")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping @PutMapping
@@ -166,17 +147,17 @@ public class SysUserController extends BaseController
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId()); userService.checkUserDataScope(user.getUserId());
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{ {
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (StringUtils.isNotEmpty(user.getPhonenumber()) else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (StringUtils.isNotEmpty(user.getEmail()) else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -187,7 +168,6 @@ public class SysUserController extends BaseController
/** /**
* 删除用户 * 删除用户
*/ */
@ApiOperation("删除用户")
@PreAuthorize("@ss.hasPermi('system:user:remove')") @PreAuthorize("@ss.hasPermi('system:user:remove')")
@Log(title = "用户管理", businessType = BusinessType.DELETE) @Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}") @DeleteMapping("/{userIds}")
@@ -203,7 +183,6 @@ public class SysUserController extends BaseController
/** /**
* 重置密码 * 重置密码
*/ */
@ApiOperation("重置用户密码")
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')") @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd") @PutMapping("/resetPwd")
@@ -219,7 +198,6 @@ public class SysUserController extends BaseController
/** /**
* 状态修改 * 状态修改
*/ */
@ApiOperation("修改用户状态")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus") @PutMapping("/changeStatus")
@@ -234,7 +212,6 @@ public class SysUserController extends BaseController
/** /**
* 根据用户编号获取授权角色 * 根据用户编号获取授权角色
*/ */
@ApiOperation("根据用户编号获取授权角色")
@PreAuthorize("@ss.hasPermi('system:user:query')") @PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}") @GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId) public AjaxResult authRole(@PathVariable("userId") Long userId)
@@ -250,13 +227,13 @@ public class SysUserController extends BaseController
/** /**
* 用户授权角色 * 用户授权角色
*/ */
@ApiOperation("为用户授权角色")
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT) @Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole") @PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds) public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{ {
userService.checkUserDataScope(userId); userService.checkUserDataScope(userId);
roleService.checkRoleDataScope(roleIds);
userService.insertUserAuth(userId, roleIds); userService.insertUserAuth(userId, roleIds);
return success(); return success();
} }
@@ -264,7 +241,6 @@ public class SysUserController extends BaseController
/** /**
* 获取部门树列表 * 获取部门树列表
*/ */
@ApiOperation("获取部门树列表")
@PreAuthorize("@ss.hasPermi('system:user:list')") @PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/deptTree") @GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept) public AjaxResult deptTree(SysDept dept)

View File

@@ -1,13 +1,14 @@
package com.fastbee.common.annotation; package com.fastbee.common.annotation;
import com.fastbee.common.utils.poi.ExcelHandlerAdapter;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.fastbee.common.utils.poi.ExcelHandlerAdapter;
/** /**
* 自定义导出Excel数据注解 * 自定义导出Excel数据注解
@@ -59,12 +60,12 @@ public @interface Excel
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/** /**
* 导出时在excel中每个列的高度 单位为字符 * 导出时在excel中每个列的高度
*/ */
public double height() default 14; public double height() default 14;
/** /**
* 导出时在excel中每个列的宽 单位为字符 * 导出时在excel中每个列的宽
*/ */
public double width() default 16; public double width() default 16;
@@ -83,11 +84,21 @@ public @interface Excel
*/ */
public String prompt() default ""; public String prompt() default "";
/**
* 是否允许内容换行
*/
public boolean wrapText() default false;
/** /**
* 设置只能选择不能输入的列内容. * 设置只能选择不能输入的列内容.
*/ */
public String[] combo() default {}; public String[] combo() default {};
/**
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
*/
public boolean comboReadDict() default false;
/** /**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格) * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/ */
@@ -114,7 +125,7 @@ public @interface Excel
public ColumnType cellType() default ColumnType.STRING; public ColumnType cellType() default ColumnType.STRING;
/** /**
* 导出列头背景色 * 导出列头背景
*/ */
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT; public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
@@ -124,7 +135,7 @@ public @interface Excel
public IndexedColors headerColor() default IndexedColors.WHITE; public IndexedColors headerColor() default IndexedColors.WHITE;
/** /**
* 导出单元格背景色 * 导出单元格背景
*/ */
public IndexedColors backgroundColor() default IndexedColors.WHITE; public IndexedColors backgroundColor() default IndexedColors.WHITE;
@@ -171,7 +182,7 @@ public @interface Excel
public enum ColumnType public enum ColumnType
{ {
NUMERIC(0), STRING(1), IMAGE(2); NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
private final int value; private final int value;
ColumnType(int value) ColumnType(int value)

View File

@@ -1,13 +1,10 @@
package com.fastbee.common.annotation; package com.fastbee.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fastbee.common.enums.BusinessType; import com.fastbee.common.enums.BusinessType;
import com.fastbee.common.enums.OperatorType; import com.fastbee.common.enums.OperatorType;
import java.lang.annotation.*;
/** /**
* 自定义操作日志记录注解 * 自定义操作日志记录注解
* *
@@ -43,4 +40,9 @@ public @interface Log
* 是否保存响应的参数 * 是否保存响应的参数
*/ */
public boolean isSaveResponseData() default true; public boolean isSaveResponseData() default true;
/**
* 排除指定的请求参数
*/
public String[] excludeParamNames() default {};
} }

View File

@@ -2,6 +2,8 @@ package com.fastbee.common.constant;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import java.util.Locale;
/** /**
* 通用常量信息 * 通用常量信息
* *
@@ -19,6 +21,11 @@ public class Constants
*/ */
public static final String GBK = "GBK"; public static final String GBK = "GBK";
/**
* 系统语言
*/
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
/** /**
* www主域 * www主域
*/ */
@@ -64,6 +71,26 @@ public class Constants
*/ */
public static final String LOGIN_FAIL = "Error"; public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMETER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMETER = ",";
/** /**
* 验证码有效期(分钟) * 验证码有效期(分钟)
*/ */
@@ -129,14 +156,19 @@ public class Constants
*/ */
public static final String LOOKUP_LDAPS = "ldaps:"; public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置仅允许解析的包名范围越小越安全
*/
public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.ruoyi" };
/** /**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加) * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/ */
public static final String[] JOB_WHITELIST_STR = { "com.fastbee" }; public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
/** /**
* 定时任务违规的字符 * 定时任务违规的字符
*/ */
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.fastbee.common.utils.file", "com.fastbee.common.config" }; "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
} }

View File

@@ -60,9 +60,9 @@ public class UserConstants
/** InnerLink组件标识 */ /** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink"; public final static String INNER_LINK = "InnerLink";
/** 校验返回结果码 */ /** 校验是否唯一的返回标识 */
public final static String UNIQUE = "0"; public final static boolean UNIQUE = true;
public final static String NOT_UNIQUE = "1"; public final static boolean NOT_UNIQUE = false;
/** /**
* 用户名长度限制 * 用户名长度限制

View File

@@ -1,13 +1,14 @@
package com.fastbee.common.core.text; package com.fastbee.common.core.text;
import com.fastbee.common.utils.StringUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Set; import java.util.Set;
import com.fastbee.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
/** /**
* 类型转换器 * 类型转换器
@@ -364,6 +365,10 @@ public class Convert
*/ */
public static String[] toStrArray(String str) public static String[] toStrArray(String str)
{ {
if (StringUtils.isEmpty(str))
{
return new String[] {};
}
return toStrArray(",", str); return toStrArray(",", str);
} }
@@ -536,7 +541,7 @@ public class Convert
/** /**
* 转换为boolean<br> * 转换为boolean<br>
* String支持的值为true、false、yes、ok、no1,0 如果给定的值为空,或者转换失败,返回默认值<br> * String支持的值为true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错 * 转换失败不会报错
* *
* @param value 被转换的值 * @param value 被转换的值
@@ -565,10 +570,12 @@ public class Convert
case "yes": case "yes":
case "ok": case "ok":
case "1": case "1":
case "":
return true; return true;
case "false": case "false":
case "no": case "no":
case "0": case "0":
case "":
return false; return false;
default: default:
return defaultValue; return defaultValue;
@@ -791,14 +798,23 @@ public class Convert
{ {
return (String) obj; return (String) obj;
} }
else if (obj instanceof byte[]) else if (obj instanceof byte[] || obj instanceof Byte[])
{
if (obj instanceof byte[])
{ {
return str((byte[]) obj, charset); return str((byte[]) obj, charset);
} }
else if (obj instanceof Byte[]) else
{ {
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj); Byte[] bytes = (Byte[]) obj;
return str(bytes, charset); int length = bytes.length;
byte[] dest = new byte[length];
for (int i = 0; i < length; i++)
{
dest[i] = bytes[i];
}
return str(dest, charset);
}
} }
else if (obj instanceof ByteBuffer) else if (obj instanceof ByteBuffer)
{ {
@@ -954,9 +970,7 @@ public class Convert
c[i] = (char) (c[i] - 65248); c[i] = (char) (c[i] - 65248);
} }
} }
String returnString = new String(c); return new String(c);
return returnString;
} }
/** /**
@@ -977,7 +991,12 @@ public class Convert
String s = ""; String s = "";
for (int i = 0; i < fraction.length; i++) for (int i = 0; i < fraction.length; i++)
{ {
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); // 优化double计算精度丢失问题
BigDecimal nNum = new BigDecimal(n);
BigDecimal decimal = new BigDecimal(10);
BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
double d = scale.doubleValue();
s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
} }
if (s.length() < 1) if (s.length() < 1)
{ {

View File

@@ -0,0 +1,60 @@
package com.fastbee.common.enums;
import com.fastbee.common.utils.DesensitizedUtil;
import java.util.function.Function;
/**
* 脱敏类型
*
* @author ruoyi
*/
public enum DesensitizedType
{
/**
* 姓名第2位星号替换
*/
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
/**
* 密码,全部字符都用*代替
*/
PASSWORD(DesensitizedUtil::password),
/**
* 身份证中间10位星号替换
*/
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
/**
* 手机号中间4位星号替换
*/
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
/**
* 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
*/
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
/**
* 银行卡号保留最后4位其他星号替换
*/
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
/**
* 车牌号码,包含普通车辆、新能源车辆
*/
CAR_LICENSE(DesensitizedUtil::carLicense);
private final Function<String, String> desensitizer;
DesensitizedType(Function<String, String> desensitizer)
{
this.desensitizer = desensitizer;
}
public Function<String, String> desensitizer()
{
return desensitizer;
}
}

View File

@@ -0,0 +1,49 @@
package com.fastbee.common.utils;
/**
* 脱敏工具类
*
* @author ruoyi
*/
public class DesensitizedUtil
{
/**
* 密码的全部字符都用*代替,比如:******
*
* @param password 密码
* @return 脱敏后的密码
*/
public static String password(String password)
{
if (StringUtils.isBlank(password))
{
return StringUtils.EMPTY;
}
return StringUtils.repeat('*', password.length());
}
/**
* 车牌中间用*代替,如果是错误的车牌,不处理
*
* @param carLicense 完整的车牌号
* @return 脱敏后的车牌
*/
public static String carLicense(String carLicense)
{
if (StringUtils.isBlank(carLicense))
{
return StringUtils.EMPTY;
}
// 普通车牌
if (carLicense.length() == 7)
{
carLicense = StringUtils.hide(carLicense, 3, 6);
}
else if (carLicense.length() == 8)
{
// 新能源车牌
carLicense = StringUtils.hide(carLicense, 3, 7);
}
return carLicense;
}
}

View File

@@ -1,13 +1,14 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import java.util.Collection;
import java.util.List;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.fastbee.common.constant.CacheConstants; import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.core.domain.entity.SysDictData; import com.fastbee.common.core.domain.entity.SysDictData;
import com.fastbee.common.core.redis.RedisCache; import com.fastbee.common.core.redis.RedisCache;
import com.fastbee.common.utils.spring.SpringUtils; import com.fastbee.common.utils.spring.SpringUtils;
import java.util.Collection;
import java.util.List;
/** /**
* 字典工具类 * 字典工具类
* *
@@ -56,6 +57,10 @@ public class DictUtils
*/ */
public static String getDictLabel(String dictType, String dictValue) public static String getDictLabel(String dictType, String dictValue)
{ {
if (StringUtils.isEmpty(dictValue))
{
return StringUtils.EMPTY;
}
return getDictLabel(dictType, dictValue, SEPARATOR); return getDictLabel(dictType, dictValue, SEPARATOR);
} }
@@ -68,6 +73,10 @@ public class DictUtils
*/ */
public static String getDictValue(String dictType, String dictLabel) public static String getDictValue(String dictType, String dictLabel)
{ {
if (StringUtils.isEmpty(dictLabel))
{
return StringUtils.EMPTY;
}
return getDictValue(dictType, dictLabel, SEPARATOR); return getDictValue(dictType, dictLabel, SEPARATOR);
} }
@@ -83,9 +92,10 @@ public class DictUtils
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType); List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
if (StringUtils.isNotNull(datas))
{ {
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictValue)) if (StringUtils.containsAny(separator, dictValue))
{ {
for (SysDictData dict : datas) for (SysDictData dict : datas)
@@ -110,7 +120,6 @@ public class DictUtils
} }
} }
} }
}
return StringUtils.stripEnd(propertyString.toString(), separator); return StringUtils.stripEnd(propertyString.toString(), separator);
} }
@@ -126,8 +135,11 @@ public class DictUtils
{ {
StringBuilder propertyString = new StringBuilder(); StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType); List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) {
return StringUtils.EMPTY;
}
if (StringUtils.containsAny(separator, dictLabel))
{ {
for (SysDictData dict : datas) for (SysDictData dict : datas)
{ {
@@ -154,6 +166,48 @@ public class DictUtils
return StringUtils.stripEnd(propertyString.toString(), separator); return StringUtils.stripEnd(propertyString.toString(), separator);
} }
/**
* 根据字典类型获取字典所有值
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictValues(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictValue()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/**
* 根据字典类型获取字典所有标签
*
* @param dictType 字典类型
* @return 字典值
*/
public static String getDictLabels(String dictType)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNull(datas))
{
return StringUtils.EMPTY;
}
for (SysDictData dict : datas)
{
propertyString.append(dict.getDictLabel()).append(SEPARATOR);
}
return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
}
/** /**
* 删除指定字典缓存 * 删除指定字典缓存
* *

View File

@@ -1,11 +1,18 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import com.fastbee.common.constant.Constants;
import com.fastbee.common.constant.HttpStatus;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.fastbee.common.constant.HttpStatus; import org.springframework.util.PatternMatchUtils;
import com.fastbee.common.core.domain.model.LoginUser;
import com.fastbee.common.exception.ServiceException; import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* 安全服务工具类 * 安全服务工具类
@@ -14,6 +21,7 @@ import com.fastbee.common.exception.ServiceException;
*/ */
public class SecurityUtils public class SecurityUtils
{ {
/** /**
* 用户ID * 用户ID
**/ **/
@@ -117,4 +125,55 @@ public class SecurityUtils
{ {
return userId != null && 1L == userId; return userId != null && 1L == userId;
} }
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(String permission)
{
return hasPermi(getLoginUser().getPermissions(), permission);
}
/**
* 判断是否包含权限
*
* @param authorities 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(Collection<String> authorities, String permission)
{
return authorities.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
}
/**
* 验证用户是否拥有某个角色
*
* @param role 角色标识
* @return 用户是否具备某角色
*/
public static boolean hasRole(String role)
{
List<SysRole> roleList = getLoginUser().getUser().getRoles();
Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
return hasRole(roles, role);
}
/**
* 判断是否包含角色
*
* @param roles 角色列表
* @param role 角色
* @return 用户是否具备某角色权限
*/
public static boolean hasRole(Collection<String> roles, String role)
{
return roles.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
}
} }

View File

@@ -1,43 +1,35 @@
package com.fastbee.common.utils; package com.fastbee.common.utils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import org.springframework.util.AntPathMatcher;
import com.fastbee.common.constant.Constants; import com.fastbee.common.constant.Constants;
import com.fastbee.common.core.text.StrFormatter; import com.fastbee.common.core.text.StrFormatter;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/** /**
* 字符串工具类 * 字符串工具类
* *
* @author ruoyi * @author ruoyi
*/ */
public class StringUtils extends org.apache.commons.lang3.StringUtils { public class StringUtils extends org.apache.commons.lang3.StringUtils
/** {
* 空字符串 /** 空字符串 */
*/
private static final String NULLSTR = ""; private static final String NULLSTR = "";
/** /** 下划线 */
* 下划线
*/
private static final char SEPARATOR = '_'; private static final char SEPARATOR = '_';
/** 星号 */
private static final char ASTERISK = '*';
/** /**
* 获取参数不为空值 * 获取参数不为空值
* *
* @param value defaultValue 要判断的value * @param value defaultValue 要判断的value
* @return value 返回值 * @return value 返回值
*/ */
public static <T> T nvl(T value, T defaultValue) { public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue; return value != null ? value : defaultValue;
} }
@@ -47,7 +39,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection * @param coll 要判断的Collection
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(Collection<?> coll) { public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty(); return isNull(coll) || coll.isEmpty();
} }
@@ -57,7 +50,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param coll 要判断的Collection * @param coll 要判断的Collection
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Collection<?> coll) { public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll); return !isEmpty(coll);
} }
@@ -67,7 +61,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param objects 要判断的对象数组 * @param objects 要判断的对象数组
** @return true为空 false非空 ** @return true为空 false非空
*/ */
public static boolean isEmpty(Object[] objects) { public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0); return isNull(objects) || (objects.length == 0);
} }
@@ -77,7 +72,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param objects 要判断的对象数组 * @param objects 要判断的对象数组
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Object[] objects) { public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects); return !isEmpty(objects);
} }
@@ -87,7 +83,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map * @param map 要判断的Map
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(Map<?, ?> map) { public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty(); return isNull(map) || map.isEmpty();
} }
@@ -97,7 +94,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param map 要判断的Map * @param map 要判断的Map
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotEmpty(Map<?, ?> map) { public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map); return !isEmpty(map);
} }
@@ -107,7 +105,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String * @param str String
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isEmpty(String str) { public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim()); return isNull(str) || NULLSTR.equals(str.trim());
} }
@@ -117,7 +116,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param str String * @param str String
* @return true非空串 false空串 * @return true非空串 false空串
*/ */
public static boolean isNotEmpty(String str) { public static boolean isNotEmpty(String str)
{
return !isEmpty(str); return !isEmpty(str);
} }
@@ -127,7 +127,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object * @param object Object
* @return true为空 false非空 * @return true为空 false非空
*/ */
public static boolean isNull(Object object) { public static boolean isNull(Object object)
{
return object == null; return object == null;
} }
@@ -137,7 +138,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object Object * @param object Object
* @return true非空 false * @return true非空 false
*/ */
public static boolean isNotNull(Object object) { public static boolean isNotNull(Object object)
{
return !isNull(object); return !isNull(object);
} }
@@ -147,17 +149,62 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param object 对象 * @param object 对象
* @return true是数组 false不是数组 * @return true是数组 false不是数组
*/ */
public static boolean isArray(Object object) { public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray(); return isNotNull(object) && object.getClass().isArray();
} }
/** /**
* 去空格 * 去空格
*/ */
public static String trim(String str) { public static String trim(String str)
{
return (str == null ? "" : str.trim()); return (str == null ? "" : str.trim());
} }
/**
* 替换指定字符串的指定区间内字符为"*"
*
* @param str 字符串
* @param startInclude 开始位置(包含)
* @param endExclude 结束位置(不包含)
* @return 替换后的字符串
*/
public static String hide(CharSequence str, int startInclude, int endExclude)
{
if (isEmpty(str))
{
return NULLSTR;
}
final int strLength = str.length();
if (startInclude > strLength)
{
return NULLSTR;
}
if (endExclude > strLength)
{
endExclude = strLength;
}
if (startInclude > endExclude)
{
// 如果起始位置大于结束位置,不替换
return NULLSTR;
}
final char[] chars = new char[strLength];
for (int i = 0; i < strLength; i++)
{
if (i >= startInclude && i < endExclude)
{
chars[i] = ASTERISK;
}
else
{
chars[i] = str.charAt(i);
}
}
return new String(chars);
}
/** /**
* 截取字符串 * 截取字符串
* *
@@ -165,19 +212,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param start 开始 * @param start 开始
* @return 结果 * @return 结果
*/ */
public static String substring(final String str, int start) { public static String substring(final String str, int start)
if (str == null) { {
if (str == null)
{
return NULLSTR; return NULLSTR;
} }
if (start < 0) { if (start < 0)
{
start = str.length() + start; start = str.length() + start;
} }
if (start < 0) { if (start < 0)
{
start = 0; start = 0;
} }
if (start > str.length()) { if (start > str.length())
{
return NULLSTR; return NULLSTR;
} }
@@ -192,36 +244,94 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param end 结束 * @param end 结束
* @return 结果 * @return 结果
*/ */
public static String substring(final String str, int start, int end) { public static String substring(final String str, int start, int end)
if (str == null) { {
if (str == null)
{
return NULLSTR; return NULLSTR;
} }
if (end < 0) { if (end < 0)
{
end = str.length() + end; end = str.length() + end;
} }
if (start < 0) { if (start < 0)
{
start = str.length() + start; start = str.length() + start;
} }
if (end > str.length()) { if (end > str.length())
{
end = str.length(); end = str.length();
} }
if (start > end) { if (start > end)
{
return NULLSTR; return NULLSTR;
} }
if (start < 0) { if (start < 0)
{
start = 0; start = 0;
} }
if (end < 0) { if (end < 0)
{
end = 0; end = 0;
} }
return str.substring(start, end); return str.substring(start, end);
} }
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str)
{
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str)
{
int strLen = str.length();
for (int i = 0; i < strLen; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return true;
}
}
return false;
}
/** /**
* 格式化文本, {} 表示占位符<br> * 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
@@ -235,8 +345,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param params 参数值 * @param params 参数值
* @return 格式化后的文本 * @return 格式化后的文本
*/ */
public static String format(String template, Object... params) { public static String format(String template, Object... params)
if (isEmpty(params) || isEmpty(template)) { {
if (isEmpty(params) || isEmpty(template))
{
return template; return template;
} }
return StrFormatter.format(template, params); return StrFormatter.format(template, params);
@@ -248,7 +360,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param link 链接 * @param link 链接
* @return 结果 * @return 结果
*/ */
public static boolean ishttp(String link) { public static boolean ishttp(String link)
{
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS); return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
} }
@@ -259,7 +372,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param sep 分隔符 * @param sep 分隔符
* @return set集合 * @return set集合
*/ */
public static final Set<String> str2Set(String str, String sep) { public static final Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false)); return new HashSet<String>(str2List(str, sep, true, false));
} }
@@ -272,22 +386,28 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param trim 去掉首尾空白 * @param trim 去掉首尾空白
* @return list集合 * @return list集合
*/ */
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) { public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>(); List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str)) { if (StringUtils.isEmpty(str))
{
return list; return list;
} }
// 过滤空白字符串 // 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str)) { if (filterBlank && StringUtils.isBlank(str))
{
return list; return list;
} }
String[] split = str.split(sep); String[] split = str.split(sep);
for (String string : split) { for (String string : split)
if (filterBlank && StringUtils.isBlank(string)) { {
if (filterBlank && StringUtils.isBlank(string))
{
continue; continue;
} }
if (trim) { if (trim)
{
string = string.trim(); string = string.trim();
} }
list.add(string); list.add(string);
@@ -297,18 +417,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
/** /**
* 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
* *
* @param set 给定的集合 * @param collection 给定的集合
* @param array 给定的数组 * @param array 给定的数组
* @return boolean 结果 * @return boolean 结果
*/ */
public static boolean containsAny(Collection<String> collection, String... array) { public static boolean containsAny(Collection<String> collection, String... array)
if (isEmpty(collection) || isEmpty(array)) { {
if (isEmpty(collection) || isEmpty(array))
{
return false; return false;
} else { }
for (String str : array) { else
if (collection.contains(str)) { {
for (String str : array)
{
if (collection.contains(str))
{
return true; return true;
} }
} }
@@ -323,12 +449,16 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param searchCharSequences 需要检查的字符串数组 * @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串 * @return 是否包含任意一个字符串
*/ */
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
if (isEmpty(cs) || isEmpty(searchCharSequences)) { {
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false; return false;
} }
for (CharSequence testStr : searchCharSequences) { for (CharSequence testStr : searchCharSequences)
if (containsIgnoreCase(cs, testStr)) { {
if (containsIgnoreCase(cs, testStr))
{
return true; return true;
} }
} }
@@ -338,8 +468,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** /**
* 驼峰转下划线命名 * 驼峰转下划线命名
*/ */
public static String toUnderScoreCase(String str) { public static String toUnderScoreCase(String str)
if (str == null) { {
if (str == null)
{
return null; return null;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -349,23 +481,31 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
boolean curreCharIsUpperCase = true; boolean curreCharIsUpperCase = true;
// 下一字符是否大写 // 下一字符是否大写
boolean nexteCharIsUpperCase = true; boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i); char c = str.charAt(i);
if (i > 0) { if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else { }
else
{
preCharIsUpperCase = false; preCharIsUpperCase = false;
} }
curreCharIsUpperCase = Character.isUpperCase(c); curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) { if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
} }
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR); sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { }
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR); sb.append(SEPARATOR);
} }
sb.append(Character.toLowerCase(c)); sb.append(Character.toLowerCase(c));
@@ -381,10 +521,14 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param strs 字符串组 * @param strs 字符串组
* @return 包含返回true * @return 包含返回true
*/ */
public static boolean inStringIgnoreCase(String str, String... strs) { public static boolean inStringIgnoreCase(String str, String... strs)
if (str != null && strs != null) { {
for (String s : strs) { if (str != null && strs != null)
if (str.equalsIgnoreCase(trim(s))) { {
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true; return true;
} }
} }
@@ -398,21 +542,27 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param name 转换前的下划线大写方式命名的字符串 * @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串 * @return 转换后的驼峰式命名的字符串
*/ */
public static String convertToCamelCase(String name) { public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
// 快速检查 // 快速检查
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty())
{
// 没必要转换 // 没必要转换
return ""; return "";
} else if (!name.contains("_")) { }
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写 // 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1); return name.substring(0, 1).toUpperCase() + name.substring(1);
} }
// 用下划线将原始字符串分割 // 用下划线将原始字符串分割
String[] camels = name.split("_"); String[] camels = name.split("_");
for (String camel : camels) { for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线 // 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty()) { if (camel.isEmpty())
{
continue; continue;
} }
// 首字母大写 // 首字母大写
@@ -423,24 +573,37 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
} }
/** /**
* 驼峰式命名法 例如user_name->userName * 驼峰式命名法
* 例如user_name->userName
*/ */
public static String toCamelCase(String s) { public static String toCamelCase(String s)
if (s == null) { {
if (s == null)
{
return null; return null;
} }
if (s.indexOf(SEPARATOR) == -1)
{
return s;
}
s = s.toLowerCase(); s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length()); StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false; boolean upperCase = false;
for (int i = 0; i < s.length(); i++) { for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i); char c = s.charAt(i);
if (c == SEPARATOR) { if (c == SEPARATOR)
{
upperCase = true; upperCase = true;
} else if (upperCase) { }
else if (upperCase)
{
sb.append(Character.toUpperCase(c)); sb.append(Character.toUpperCase(c));
upperCase = false; upperCase = false;
} else { }
else
{
sb.append(c); sb.append(c);
} }
} }
@@ -454,12 +617,16 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param strs 需要检查的字符串数组 * @param strs 需要检查的字符串数组
* @return 是否匹配 * @return 是否匹配
*/ */
public static boolean matches(String str, List<String> strs) { public static boolean matches(String str, List<String> strs)
if (isEmpty(str) || isEmpty(strs)) { {
if (isEmpty(str) || isEmpty(strs))
{
return false; return false;
} }
for (String pattern : strs) { for (String pattern : strs)
if (isMatch(pattern, str)) { {
if (isMatch(pattern, str))
{
return true; return true;
} }
} }
@@ -476,13 +643,15 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param url 需要匹配的url * @param url 需要匹配的url
* @return * @return
*/ */
public static boolean isMatch(String pattern, String url) { public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher(); AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url); return matcher.match(pattern, url);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T cast(Object obj) { public static <T> T cast(Object obj)
{
return (T) obj; return (T) obj;
} }
@@ -493,7 +662,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param size 字符串指定长度 * @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。 * @return 返回数字的字符串格式,该字符串为指定长度。
*/ */
public static final String padl(final Number num, final int size) { public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0'); return padl(num.toString(), size, '0');
} }
@@ -505,170 +675,32 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
* @param c 用于补齐的字符 * @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/ */
public static final String padl(final String s, final int size, final char c) { public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size); final StringBuilder sb = new StringBuilder(size);
if (s != null) { if (s != null)
{
final int len = s.length(); final int len = s.length();
if (s.length() <= size) { if (s.length() <= size)
for (int i = size - len; i > 0; i--) { {
for (int i = size - len; i > 0; i--)
{
sb.append(c); sb.append(c);
} }
sb.append(s); sb.append(s);
} else { }
else
{
return s.substring(len - size, len); return s.substring(len - size, len);
} }
} else { }
for (int i = size; i > 0; i--) { else
{
for (int i = size; i > 0; i--)
{
sb.append(c); sb.append(c);
} }
} }
return sb.toString(); return sb.toString();
} }
/*将字符串转小写,首字母大写,其他小写*/
public static String upperCase(String str) {
char[] ch = str.toLowerCase().toCharArray();
if (ch[0] >= 'a' && ch[0] <= 'z') {
ch[0] = (char) (ch[0] - 32);
}
return new String(ch);
}
public static String toString(Object value) {
if (value == null) {
return "null";
}
if (value instanceof ByteBuf) {
return ByteBufUtil.hexDump((ByteBuf) value);
}
if (!value.getClass().isArray()) {
return value.toString();
}
StringBuilder root = new StringBuilder(32);
toString(value, root);
return root.toString();
}
public static StringBuilder toString(Object value, StringBuilder builder) {
if (value == null) {
return builder;
}
builder.append('[');
int start = builder.length();
if (value instanceof long[]) {
long[] array = (long[]) value;
for (long t : array) {
builder.append(t).append(',');
}
} else if (value instanceof int[]) {
int[] array = (int[]) value;
for (int t : array) {
builder.append(t).append(',');
}
} else if (value instanceof short[]) {
short[] array = (short[]) value;
for (short t : array) {
builder.append(t).append(',');
}
} else if (value instanceof byte[]) {
byte[] array = (byte[]) value;
for (byte t : array) {
builder.append(t).append(',');
}
} else if (value instanceof char[]) {
char[] array = (char[]) value;
for (char t : array) {
builder.append(t).append(',');
}
} else if (value instanceof double[]) {
double[] array = (double[]) value;
for (double t : array) {
builder.append(t).append(',');
}
} else if (value instanceof float[]) {
float[] array = (float[]) value;
for (float t : array) {
builder.append(t).append(',');
}
} else if (value instanceof boolean[]) {
boolean[] array = (boolean[]) value;
for (boolean t : array) {
builder.append(t).append(',');
}
} else if (value instanceof String[]) {
String[] array = (String[]) value;
for (String t : array) {
builder.append(t).append(',');
}
} else if (isArray1(value)) {
Object[] array = (Object[]) value;
for (Object t : array) {
toString(t, builder).append(',');
}
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
for (Object t : array) {
builder.append(t).append(',');
}
}
int end = builder.length();
if (end <= start) {
builder.append(']');
} else {
builder.setCharAt(end - 1, ']');
}
return builder;
}
private static boolean isArray1(Object value) {
Class<?> componentType = value.getClass().getComponentType();
if (componentType == null) {
return false;
}
return componentType.isArray();
}
public static String leftPad(String str, int size, char ch) {
int length = str.length();
int pads = size - length;
if (pads > 0) {
char[] result = new char[size];
str.getChars(0, length, result, pads);
while (pads > 0) {
result[--pads] = ch;
}
return new String(result);
}
return str;
}
/**
* 获取字符串中的数字
* @param str
* @return
*/
public static Integer matcherNum(String str){
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(str);
while (matcher.find()){
return Integer.parseInt(matcher.group());
}
return 0;
}
} }

View File

@@ -1,9 +1,11 @@
package com.fastbee.common.utils.ip; package com.fastbee.common.utils.ip;
import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import com.fastbee.common.utils.StringUtils;
/** /**
* 获取IP方法 * 获取IP方法
@@ -12,6 +14,23 @@ import com.fastbee.common.utils.StringUtils;
*/ */
public class IpUtils public class IpUtils
{ {
public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
// 匹配 ip
public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
// 匹配网段
public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
/**
* 获取客户端IP
*
* @return IP地址
*/
public static String getIpAddr()
{
return getIpAddr(ServletUtils.getRequest());
}
/** /**
* 获取客户端IP * 获取客户端IP
* *
@@ -248,7 +267,7 @@ public class IpUtils
} }
} }
} }
return ip; return StringUtils.substring(ip, 0, 255);
} }
/** /**
@@ -261,4 +280,104 @@ public class IpUtils
{ {
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString); return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
} }
/**
* 是否为IP
*/
public static boolean isIP(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
}
/**
* 是否为IP或 *为间隔的通配符地址
*/
public static boolean isIpWildCard(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
}
/**
* 检测参数是否在ip通配符里
*/
public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
{
String[] s1 = ipWildCard.split("\\.");
String[] s2 = ip.split("\\.");
boolean isMatchedSeg = true;
for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
{
if (!s1[i].equals(s2[i]))
{
isMatchedSeg = false;
break;
}
}
return isMatchedSeg;
}
/**
* 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
*/
public static boolean isIPSegment(String ipSeg)
{
return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
}
/**
* 判断ip是否在指定网段中
*/
public static boolean ipIsInNetNoCheck(String iparea, String ip)
{
int idx = iparea.indexOf('-');
String[] sips = iparea.substring(0, idx).split("\\.");
String[] sipe = iparea.substring(idx + 1).split("\\.");
String[] sipt = ip.split("\\.");
long ips = 0L, ipe = 0L, ipt = 0L;
for (int i = 0; i < 4; ++i)
{
ips = ips << 8 | Integer.parseInt(sips[i]);
ipe = ipe << 8 | Integer.parseInt(sipe[i]);
ipt = ipt << 8 | Integer.parseInt(sipt[i]);
}
if (ips > ipe)
{
long t = ips;
ips = ipe;
ipe = t;
}
return ips <= ipt && ipt <= ipe;
}
/**
* 校验ip是否符合过滤串规则
*
* @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
* @param ip 校验IP地址
* @return boolean 结果
*/
public static boolean isMatchedIp(String filter, String ip)
{
if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
{
return false;
}
String[] ips = filter.split(";");
for (String iStr : ips)
{
if (isIP(iStr) && iStr.equals(ip))
{
return true;
}
else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
{
return true;
}
else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
{
return true;
}
}
return false;
}
} }

View File

@@ -1,5 +1,8 @@
package com.fastbee.common.utils.poi; package com.fastbee.common.utils.poi;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
/** /**
* Excel数据格式处理适配器 * Excel数据格式处理适配器
* *
@@ -12,8 +15,10 @@ public interface ExcelHandlerAdapter
* *
* @param value 单元格数据值 * @param value 单元格数据值
* @param args excel注解args参数组 * @param args excel注解args参数组
* @param cell 单元格对象
* @param wb 工作簿对象
* *
* @return 处理后的值 * @return 处理后的值
*/ */
Object format(Object value, String[] args); Object format(Object value, String[] args, Cell cell, Workbook wb);
} }

View File

@@ -1,74 +1,5 @@
package com.fastbee.common.utils.poi; package com.fastbee.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fastbee.common.annotation.Excel; import com.fastbee.common.annotation.Excel;
import com.fastbee.common.annotation.Excel.ColumnType; import com.fastbee.common.annotation.Excel.ColumnType;
import com.fastbee.common.annotation.Excel.Type; import com.fastbee.common.annotation.Excel.Type;
@@ -84,6 +15,32 @@ import com.fastbee.common.utils.file.FileTypeUtils;
import com.fastbee.common.utils.file.FileUtils; import com.fastbee.common.utils.file.FileUtils;
import com.fastbee.common.utils.file.ImageUtils; import com.fastbee.common.utils.file.ImageUtils;
import com.fastbee.common.utils.reflect.ReflectUtils; import com.fastbee.common.utils.reflect.ReflectUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/** /**
* Excel相关处理 * Excel相关处理
@@ -98,6 +55,11 @@ public class ExcelUtil<T>
public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/**
* 用于dictType属性数据存储避免重复查缓存
*/
public Map<String, String> sysDictMap = new HashMap<String, String>();
/** /**
* Excel sheet最大行数默认65536 * Excel sheet最大行数默认65536
*/ */
@@ -188,6 +150,11 @@ public class ExcelUtil<T>
*/ */
public Class<T> clazz; public Class<T> clazz;
/**
* 需要显示列属性
*/
public String[] includeFields;
/** /**
* 需要排除列属性 * 需要排除列属性
*/ */
@@ -198,11 +165,20 @@ public class ExcelUtil<T>
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 仅在Excel中显示列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
*/
public void showColumn(String... fields)
{
this.includeFields = fields;
}
/** /**
* 隐藏Excel中列属性 * 隐藏Excel中列属性
* *
* @param fields 列属性名 示例[单个"name"/多个"id","name"] * @param fields 列属性名 示例[单个"name"/多个"id","name"]
* @throws Exception
*/ */
public void hideColumn(String... fields) public void hideColumn(String... fields)
{ {
@@ -232,8 +208,6 @@ public class ExcelUtil<T>
{ {
if (StringUtils.isNotEmpty(title)) if (StringUtils.isNotEmpty(title))
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1; int titleLastCol = this.fields.size() - 1;
if (isSubList()) if (isSubList())
{ {
@@ -244,7 +218,7 @@ public class ExcelUtil<T>
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title")); titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title); titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
} }
} }
@@ -255,23 +229,31 @@ public class ExcelUtil<T>
{ {
if (isSubList()) if (isSubList())
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum); Row subRow = sheet.createRow(rownum);
int excelNum = 0; int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields) for (Object[] objects : fields)
{ {
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1]; Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum); if (Collection.class.isAssignableFrom(field.getType()))
headCell1.setCellValue(attr.name());
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
excelNum++;
}
int headFirstRow = excelNum - 1;
int headLastRow = headFirstRow + subFields.size() - 1;
if (headLastRow > headFirstRow)
{ {
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); Cell cell = subRow.createCell(column);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
if (subFieldSize > 1)
{
CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
sheet.addMergedRegion(cellAddress);
}
column += subFieldSize;
}
else
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
}
} }
rownum++; rownum++;
} }
@@ -283,7 +265,7 @@ public class ExcelUtil<T>
* @param is 输入流 * @param is 输入流
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(InputStream is) throws Exception public List<T> importExcel(InputStream is)
{ {
return importExcel(is, 0); return importExcel(is, 0);
} }
@@ -295,9 +277,23 @@ public class ExcelUtil<T>
* @param titleNum 标题占用行数 * @param titleNum 标题占用行数
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(InputStream is, int titleNum) throws Exception public List<T> importExcel(InputStream is, int titleNum)
{ {
return importExcel(StringUtils.EMPTY, is, titleNum); List<T> list = null;
try
{
list = importExcel(StringUtils.EMPTY, is, titleNum);
}
catch (Exception e)
{
log.error("导入Excel异常{}", e.getMessage());
throw new UtilException(e.getMessage());
}
finally
{
IOUtils.closeQuietly(is);
}
return list;
} }
/** /**
@@ -331,7 +327,6 @@ public class ExcelUtil<T>
} }
// 获取最后一个非空行的行下标比如总行数为n则返回的为n-1 // 获取最后一个非空行的行下标比如总行数为n则返回的为n-1
int rows = sheet.getLastRowNum(); int rows = sheet.getLastRowNum();
if (rows > 0) if (rows > 0)
{ {
// 定义一个map用于存放excel列的序号和field. // 定义一个map用于存放excel列的序号和field.
@@ -446,17 +441,22 @@ public class ExcelUtil<T>
{ {
propertyName = field.getName() + "." + attr.targetAttr(); propertyName = field.getName() + "." + attr.targetAttr();
} }
else if (StringUtils.isNotEmpty(attr.readConverterExp())) if (StringUtils.isNotEmpty(attr.readConverterExp()))
{ {
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
} }
else if (StringUtils.isNotEmpty(attr.dictType())) else if (StringUtils.isNotEmpty(attr.dictType()))
{ {
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); if (!sysDictMap.containsKey(attr.dictType() + val))
{
String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
sysDictMap.put(attr.dictType() + val, dictValue);
}
val = sysDictMap.get(attr.dictType() + val);
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class)) else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{ {
val = dataFormatHandlerAdapter(val, attr); val = dataFormatHandlerAdapter(val, attr, null);
} }
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{ {
@@ -687,64 +687,91 @@ public class ExcelUtil<T>
{ {
int startNo = index * sheetSize; int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size()); int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo; int currentRowNum = rownum + 1; // 从标题行后开始
for (int i = startNo; i < endNo; i++) for (int i = startNo; i < endNo; i++)
{ {
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; row = sheet.createRow(currentRowNum);
row = sheet.createRow(rowNo);
// 得到导出对象.
T vo = (T) list.get(i); T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0; int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0]; Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) if (Collection.class.isAssignableFrom(field.getType()))
{ {
boolean subFirst = false; try
for (Object obj : subList)
{ {
if (subFirst) Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
if (subList != null && !subList.isEmpty())
{ {
rowNo++;
row = sheet.createRow(rowNo);
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0; int subIndex = 0;
for (Object subVo : subList)
{
Row subRow = sheet.getRow(currentRowNum + subIndex);
if (subRow == null)
{
subRow = sheet.createRow(currentRowNum + subIndex);
}
int subColumn = column;
for (Field subField : subFields) for (Field subField : subFields)
{ {
if (subField.isAnnotationPresent(Excel.class)) Excel subExcel = subField.getAnnotation(Excel.class);
{ addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
subField.setAccessible(true);
Excel attr = subField.getAnnotation(Excel.class);
this.addCell(attr, row, (T) obj, subField, column + subIndex);
} }
subIndex++; subIndex++;
} }
subFirst = true; column += subFields.size();
}
}
catch (Exception e)
{
log.error("填充集合数据失败", e);
} }
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size();
} }
else else
{ {
this.addCell(excel, row, vo, field, column++); // 创建单元格并设置值
addCell(excel, row, vo, field, column);
if (maxSubListSize > 1 && excel.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
}
column++;
}
}
currentRowNum += maxSubListSize;
}
}
/**
* 获取子列表最大数
*/
private int getCurrentMaxSubListSize(T vo)
{
int maxSubListSize = 1;
for (Object[] os : fields)
{
Field field = (Field) os[0];
if (Collection.class.isAssignableFrom(field.getType()))
{
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
if (subList != null && !subList.isEmpty())
{
maxSubListSize = Math.max(maxSubListSize, subList.size());
}
}
catch (Exception e)
{
log.error("获取集合大小失败", e);
} }
} }
} }
return maxSubListSize;
} }
/** /**
@@ -765,6 +792,8 @@ public class ExcelUtil<T>
titleFont.setFontHeightInPoints((short) 16); titleFont.setFontHeightInPoints((short) 16);
titleFont.setBold(true); titleFont.setBold(true);
style.setFont(titleFont); style.setFont(titleFont);
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
styles.put("title", style); styles.put("title", style);
style = wb.createCellStyle(); style = wb.createCellStyle();
@@ -827,6 +856,9 @@ public class ExcelUtil<T>
headerFont.setBold(true); headerFont.setBold(true);
headerFont.setColor(excel.headerColor().index); headerFont.setColor(excel.headerColor().index);
style.setFont(headerFont); style.setFont(headerFont);
// 设置表格头单元格文本形式
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
headerStyles.put(key, style); headerStyles.put(key, style);
} }
} }
@@ -844,8 +876,37 @@ public class ExcelUtil<T>
Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); if (Collection.class.isAssignableFrom(field.getType()))
{
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
for (Field subField : subFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
annotationDataStyles(styles, subField, subExcel);
}
}
else
{
annotationDataStyles(styles, field, excel);
}
}
return styles;
}
/**
* 根据Excel注解创建表格列样式
*
* @param styles 自定义样式列表
* @param field 属性列信息
* @param excel 注解信息
*/
public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
{
String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
if (!styles.containsKey(key)) if (!styles.containsKey(key))
{ {
CellStyle style = wb.createCellStyle(); CellStyle style = wb.createCellStyle();
@@ -861,16 +922,20 @@ public class ExcelUtil<T>
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex()); style.setFillForegroundColor(excel.backgroundColor().getIndex());
style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont(); Font dataFont = wb.createFont();
dataFont.setFontName("Arial"); dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10); dataFont.setFontHeightInPoints((short) 10);
dataFont.setColor(excel.color().index); dataFont.setColor(excel.color().index);
style.setFont(dataFont); style.setFont(dataFont);
if (ColumnType.TEXT == excel.cellType())
{
DataFormat dataFormat = wb.createDataFormat();
style.setDataFormat(dataFormat.getFormat("@"));
}
styles.put(key, style); styles.put(key, style);
} }
} }
return styles;
}
/** /**
* 创建单元格 * 创建单元格
@@ -886,7 +951,7 @@ public class ExcelUtil<T>
if (isSubList()) if (isSubList())
{ {
// 填充默认样式,防止合并单元格样式失效 // 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
if (attr.needMerge()) if (attr.needMerge())
{ {
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@@ -904,7 +969,7 @@ public class ExcelUtil<T>
*/ */
public void setCellVo(Object value, Excel attr, Cell cell) public void setCellVo(Object value, Excel attr, Cell cell)
{ {
if (ColumnType.STRING == attr.cellType()) if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())
{ {
String cellValue = Convert.toStr(value); String cellValue = Convert.toStr(value);
// 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入。 // 对于任何以表达式触发字符 =-+@开头的单元格直接使用tab字符作为前缀防止CSV注入。
@@ -981,17 +1046,28 @@ public class ExcelUtil<T>
// 设置列宽 // 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
} }
if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
{ {
if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) String[] comboArray = attr.combo();
if (attr.comboReadDict())
{
if (!sysDictMap.containsKey("combo_" + attr.dictType()))
{
String labels = DictUtils.getDictLabels(attr.dictType());
sysDictMap.put("combo_" + attr.dictType(), labels);
}
String val = sysDictMap.get("combo_" + attr.dictType());
comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
}
if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
{ {
// 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到 // 如果下拉数大于15或字符串长度大于255则使用一个新sheet存储避免生成的模板下拉值获取不到
setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
} }
else else
{ {
// 提示信息或只能选择不能输入的列内容. // 提示信息或只能选择不能输入的列内容.
setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
} }
} }
} }
@@ -1013,10 +1089,12 @@ public class ExcelUtil<T>
cell = row.createCell(column); cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{ {
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); if (subMergedLastRowNum >= subMergedFirstRowNum)
sheet.addMergedRegion(cellAddress); {
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
} }
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); }
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@@ -1026,6 +1104,7 @@ public class ExcelUtil<T>
String dictType = attr.dictType(); String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
cell.setCellValue(parseDateToStr(dateFormat, value)); cell.setCellValue(parseDateToStr(dateFormat, value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
@@ -1034,7 +1113,12 @@ public class ExcelUtil<T>
} }
else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); if (!sysDictMap.containsKey(dictType + value))
{
String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
sysDictMap.put(dictType + value, lable);
}
cell.setCellValue(sysDictMap.get(dictType + value));
} }
else if (value instanceof BigDecimal && -1 != attr.scale()) else if (value instanceof BigDecimal && -1 != attr.scale())
{ {
@@ -1042,7 +1126,7 @@ public class ExcelUtil<T>
} }
else if (!attr.handler().equals(ExcelHandlerAdapter.class)) else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{ {
cell.setCellValue(dataFormatHandlerAdapter(value, attr)); cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
} }
else else
{ {
@@ -1255,13 +1339,13 @@ public class ExcelUtil<T>
* @param excel 数据注解 * @param excel 数据注解
* @return * @return
*/ */
public String dataFormatHandlerAdapter(Object value, Excel excel) public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
{ {
try try
{ {
Object instance = excel.handler().newInstance(); Object instance = excel.handler().newInstance();
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class }); Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
value = formatMethod.invoke(instance, value, excel.args()); value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -1321,8 +1405,7 @@ public class ExcelUtil<T>
*/ */
public String encodingFilename(String filename) public String encodingFilename(String filename)
{ {
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; return UUID.randomUUID() + "_" + filename + ".xlsx";
return filename;
} }
/** /**
@@ -1352,6 +1435,7 @@ public class ExcelUtil<T>
*/ */
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{ {
field.setAccessible(true);
Object o = field.get(vo); Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
@@ -1411,9 +1495,40 @@ public class ExcelUtil<T>
List<Field> tempFields = new ArrayList<>(); List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
if (StringUtils.isNotEmpty(includeFields))
{
for (Field field : tempFields)
{
if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
{
addField(fields, field);
}
}
}
else if (StringUtils.isNotEmpty(excludeFields))
{
for (Field field : tempFields) for (Field field : tempFields)
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName())) if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
addField(fields, field);
}
}
}
else
{
for (Field field : tempFields)
{
addField(fields, field);
}
}
return fields;
}
/**
* 添加字段信息
*/
public void addField(List<Object[]> fields, Field field)
{ {
// 单注解 // 单注解
if (field.isAnnotationPresent(Excel.class)) if (field.isAnnotationPresent(Excel.class))
@@ -1421,7 +1536,6 @@ public class ExcelUtil<T>
Excel attr = field.getAnnotation(Excel.class); Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
if (Collection.class.isAssignableFrom(field.getType())) if (Collection.class.isAssignableFrom(field.getType()))
@@ -1440,17 +1554,25 @@ public class ExcelUtil<T>
Excel[] excels = attrs.value(); Excel[] excels = attrs.value();
for (Excel attr : excels) for (Excel attr : excels)
{ {
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) if (StringUtils.isNotEmpty(includeFields))
{
if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{
fields.add(new Object[] { field, attr });
}
}
else
{
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
} }
} }
} }
} }
return fields;
}
/** /**
* 根据注解获取最大行高 * 根据注解获取最大行高
@@ -1598,7 +1720,7 @@ public class ExcelUtil<T>
HSSFPicture pic = (HSSFPicture) shape; HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1; int pictureIndex = pic.getPictureIndex() - 1;
HSSFPictureData picData = pictures.get(pictureIndex); HSSFPictureData picData = pictures.get(pictureIndex);
String picIndex = String.valueOf(anchor.getRow1()) + "_" + String.valueOf(anchor.getCol1()); String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
sheetIndexPicMap.put(picIndex, picData); sheetIndexPicMap.put(picIndex, picData);
} }
} }

View File

@@ -13,13 +13,18 @@ public class SqlUtil
/** /**
* 定义常用的 sql关键字 * 定义常用的 sql关键字
*/ */
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; 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_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 限制orderBy最大长度
*/
private static final int ORDER_BY_MAX_LENGTH = 500;
/** /**
* 检查字符,防止注入绕过 * 检查字符,防止注入绕过
*/ */
@@ -29,6 +34,10 @@ public class SqlUtil
{ {
throw new UtilException("参数不符合规范,不能进行查询"); throw new UtilException("参数不符合规范,不能进行查询");
} }
if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
{
throw new UtilException("参数已超过最大限制,不能进行查询");
}
return value; return value;
} }

View File

@@ -1,24 +1,14 @@
package com.fastbee.framework.aspectj; package com.fastbee.framework.aspectj;
import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.fastbee.common.annotation.Log; import com.fastbee.common.annotation.Log;
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.text.Convert;
import com.fastbee.common.enums.BusinessStatus; import com.fastbee.common.enums.BusinessStatus;
import com.fastbee.common.enums.HttpMethod; import com.fastbee.common.enums.HttpMethod;
import com.fastbee.common.filter.PropertyPreExcludeFilter; import com.fastbee.common.filter.PropertyPreExcludeFilter;
import com.fastbee.common.utils.ExceptionUtil;
import com.fastbee.common.utils.SecurityUtils; import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.common.utils.ServletUtils; import com.fastbee.common.utils.ServletUtils;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
@@ -26,6 +16,23 @@ import com.fastbee.common.utils.ip.IpUtils;
import com.fastbee.framework.manager.AsyncManager; import com.fastbee.framework.manager.AsyncManager;
import com.fastbee.framework.manager.factory.AsyncFactory; import com.fastbee.framework.manager.factory.AsyncFactory;
import com.fastbee.system.domain.SysOperLog; import com.fastbee.system.domain.SysOperLog;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Map;
/** /**
* 操作日志记录处理 * 操作日志记录处理
@@ -41,6 +48,18 @@ public class LogAspect
/** 排除敏感属性字段 */ /** 排除敏感属性字段 */
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/** 计算操作消耗时间 */
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
/**
* 处理请求前执行
*/
@Before(value = "@annotation(controllerLog)")
public void doBefore(JoinPoint joinPoint, Log controllerLog)
{
TIME_THREADLOCAL.set(System.currentTimeMillis());
}
/** /**
* 处理完请求后执行 * 处理完请求后执行
* *
@@ -75,18 +94,23 @@ public class LogAspect
SysOperLog operLog = new SysOperLog(); SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址 // 请求的地址
String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); String ip = IpUtils.getIpAddr();
operLog.setOperIp(ip); operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
if (loginUser != null) if (loginUser != null)
{ {
operLog.setOperName(loginUser.getUsername()); operLog.setOperName(loginUser.getUsername());
SysUser currentUser = loginUser.getUser();
if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
{
operLog.setDeptName(currentUser.getDept().getDeptName());
}
} }
if (e != null) if (e != null)
{ {
operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000));
} }
// 设置方法名称 // 设置方法名称
String className = joinPoint.getTarget().getClass().getName(); String className = joinPoint.getTarget().getClass().getName();
@@ -96,6 +120,8 @@ public class LogAspect
operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数 // 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
// 保存数据库 // 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
} }
@@ -105,6 +131,10 @@ public class LogAspect
log.error("异常信息:{}", exp.getMessage()); log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace(); exp.printStackTrace();
} }
finally
{
TIME_THREADLOCAL.remove();
}
} }
/** /**
@@ -126,7 +156,7 @@ public class LogAspect
if (log.isSaveRequestData()) if (log.isSaveRequestData())
{ {
// 获取参数的信息,传入到数据库中。 // 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog); setRequestValue(joinPoint, operLog, log.excludeParamNames());
} }
// 是否需要保存response参数和值 // 是否需要保存response参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
@@ -141,25 +171,25 @@ public class LogAspect
* @param operLog 操作日志 * @param operLog 操作日志
* @throws Exception 异常 * @throws Exception 异常
*/ */
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{ {
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod(); String requestMethod = operLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
{ {
String params = argsArrayToString(joinPoint.getArgs()); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} }
else else
{ {
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter()), 0, 2000));
} }
} }
/** /**
* 参数拼装 * 参数拼装
*/ */
private String argsArrayToString(Object[] paramsArray) private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
{ {
String params = ""; String params = "";
if (paramsArray != null && paramsArray.length > 0) if (paramsArray != null && paramsArray.length > 0)
@@ -170,7 +200,7 @@ public class LogAspect
{ {
try try
{ {
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter()); String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
params += jsonObj.toString() + " "; params += jsonObj.toString() + " ";
} }
catch (Exception e) catch (Exception e)
@@ -185,9 +215,9 @@ public class LogAspect
/** /**
* 忽略敏感属性 * 忽略敏感属性
*/ */
public PropertyPreExcludeFilter excludePropertyPreFilter() public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
{ {
return new PropertyPreExcludeFilter().addExcludes(EXCLUDE_PROPERTIES); return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
} }
/** /**

View File

@@ -1,20 +1,5 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
@@ -23,6 +8,18 @@ import com.fastbee.common.enums.DataSourceType;
import com.fastbee.common.utils.spring.SpringUtils; import com.fastbee.common.utils.spring.SpringUtils;
import com.fastbee.framework.config.properties.DruidProperties; import com.fastbee.framework.config.properties.DruidProperties;
import com.fastbee.framework.datasource.DynamicDataSource; import com.fastbee.framework.datasource.DynamicDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.servlet.*;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/** /**
* druid 配置多数据源 * druid 配置多数据源

View File

@@ -1,11 +1,14 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.nio.charset.Charset;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import com.fastbee.common.constant.Constants;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.nio.charset.Charset;
/** /**
* Redis使用FastJson序列化 * Redis使用FastJson序列化
@@ -16,6 +19,8 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{ {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
private Class<T> clazz; private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz) public FastJson2JsonRedisSerializer(Class<T> clazz)
@@ -43,6 +48,6 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
} }
String str = new String(bytes, DEFAULT_CHARSET); String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType); return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER);
} }
} }

View File

@@ -1,16 +1,17 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import java.util.HashMap; import com.fastbee.common.filter.RepeatableFilter;
import java.util.Map; import com.fastbee.common.filter.XssFilter;
import javax.servlet.DispatcherType; import com.fastbee.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
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 com.fastbee.common.filter.RepeatableFilter;
import com.fastbee.common.filter.XssFilter; import javax.servlet.DispatcherType;
import com.fastbee.common.utils.StringUtils; import java.util.HashMap;
import java.util.Map;
/** /**
* Filter配置 * Filter配置

View File

@@ -1,32 +1,35 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import com.fastbee.framework.config.properties.PermitAllUrlProperties; import com.fastbee.framework.config.properties.PermitAllUrlProperties;
import com.fastbee.framework.security.filter.JwtAuthenticationTokenFilter; import com.fastbee.framework.security.filter.JwtAuthenticationTokenFilter;
import com.fastbee.framework.security.handle.AuthenticationEntryPointImpl; import com.fastbee.framework.security.handle.AuthenticationEntryPointImpl;
import com.fastbee.framework.security.handle.LogoutSuccessHandlerImpl; import com.fastbee.framework.security.handle.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
/** /**
* spring security配置 * spring security配置
* *
* @author ruoyi * @author ruoyi
*/ */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) @EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter @Configuration
public class SecurityConfig
{ {
/** /**
* 自定义用户认证逻辑 * 自定义用户认证逻辑
@@ -65,16 +68,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
private PermitAllUrlProperties permitAllUrl; private PermitAllUrlProperties permitAllUrl;
/** /**
* 解决 无法直接注入 AuthenticationManager * 身份验证实现
*
* @return
* @throws Exception
*/ */
@Bean @Bean
@Override public AuthenticationManager authenticationManager()
public AuthenticationManager authenticationManagerBean() throws Exception
{ {
return super.authenticationManagerBean(); DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
return new ProviderManager(daoAuthenticationProvider);
} }
/** /**
@@ -92,26 +94,27 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
* rememberMe | 允许通过remember-me登录的用户访问 * rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问 * authenticated | 用户登录后可访问
*/ */
@Override @Bean
protected void configure(HttpSecurity httpSecurity) throws Exception @Primary
protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
{ {
// 注解标记允许匿名访问的url return httpSecurity
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
httpSecurity
// CSRF禁用因为不使用session // CSRF禁用因为不使用session
.csrf().disable() .csrf(csrf -> csrf.disable())
// 禁用HTTP响应标头 // 禁用HTTP响应标头
.headers().cacheControl().disable().and() .headers((headersCustomizer) -> {
headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
})
// 认证失败处理类 // 认证失败处理类
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
// 基于token所以不需要session // 基于token所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// 过滤请求 // 注解标记允许匿名访问的url
.authorizeRequests() .authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage","/iot/tool/register","/iot/tool/ntp","/iot/tool/download", // 静态资源,可匿名访问
requests.antMatchers("/login", "/register", "/captchaImage","/iot/tool/register","/iot/tool/ntp","/iot/tool/download",
"/iot/tool/mqtt/auth","/iot/tool/mqtt/authv5","/iot/tool/mqtt/webhook","/iot/tool/mqtt/webhookv5","/auth/**/**", "/iot/tool/mqtt/auth","/iot/tool/mqtt/authv5","/iot/tool/mqtt/webhook","/iot/tool/mqtt/webhookv5","/auth/**/**",
"/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll() "/wechat/mobileLogin", "/wechat/miniLogin", "/wechat/wxBind/callback").permitAll()
.antMatchers("/zlmhook/**").permitAll() .antMatchers("/zlmhook/**").permitAll()
@@ -120,16 +123,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证 // 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated() .anyRequest().authenticated();
.and() })
.headers().frameOptions().disable();
// 添加Logout filter // 添加Logout filter
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler); .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
// 添加JWT filter // 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
// 添加CORS filter // 添加CORS filter
httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); .addFilterBefore(corsFilter, LogoutFilter.class)
.build();
} }
/** /**
@@ -140,13 +143,4 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
{ {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
} }
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
} }

View File

@@ -1,8 +1,9 @@
package com.fastbee.framework.config; package com.fastbee.framework.config;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.fastbee.common.utils.ServletUtils; import com.fastbee.common.utils.ServletUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/** /**
* 服务相关配置 * 服务相关配置

View File

@@ -1,7 +1,5 @@
package com.fastbee.framework.web.service; package com.fastbee.framework.web.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
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.constant.UserConstants;
@@ -17,6 +15,8 @@ import com.fastbee.framework.manager.AsyncManager;
import com.fastbee.framework.manager.factory.AsyncFactory; import com.fastbee.framework.manager.factory.AsyncFactory;
import com.fastbee.system.service.ISysConfigService; import com.fastbee.system.service.ISysConfigService;
import com.fastbee.system.service.ISysUserService; import com.fastbee.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/** /**
* 注册校验方法 * 注册校验方法
@@ -69,7 +69,7 @@ public class SysRegisterService
{ {
msg = "密码长度必须在5到20个字符之间"; msg = "密码长度必须在5到20个字符之间";
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser))) else if (!userService.checkUserNameUnique(sysUser))
{ {
msg = "保存用户'" + username + "'失败,注册账号已存在"; msg = "保存用户'" + username + "'失败,注册账号已存在";
} }

View File

@@ -46,12 +46,7 @@
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId> <artifactId>commons-text</artifactId>
</dependency> </dependency>
<!-- oauth2-->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.1.RELEASE</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId> <artifactId>spring-boot-starter-thymeleaf</artifactId>

View File

@@ -1,119 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
/**
* 授权服务器配置配置客户端id密钥和令牌的过期时间
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
/**
* 用来配置令牌端点(Token Endpoint)的安全约束
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint());
}
/**
* 用来配置客户端详情服务
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(getClientDetailsService());
}
/**
* 用来配置授权authorization以及令牌token的访问端点和令牌服务(token services)。
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 查询用户、授权、分组,可以被重写
endpoints.userDetailsService(userDetailsService)
// 审批客户端的授权
.userApprovalHandler(userApprovalHandler())
// 授权审批
.approvalStore(approvalStore())
// 获取授权码
.authorizationCodeServices(new JdbcAuthorizationCodeServices(dataSource))
// 验证token
.authenticationManager(authenticationManager)
// 查询、保存、刷新token
.tokenStore(this.getJdbcTokenStore());
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public UserApprovalHandler userApprovalHandler() {
return new SpeakerApprovalHandler(getClientDetailsService(), approvalStore(), oAuth2RequestFactory());
}
@Bean
public JdbcClientDetailsService getClientDetailsService() {
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
jdbcClientDetailsService.setPasswordEncoder(passwordEncoder());
return jdbcClientDetailsService;
}
@Bean
public OAuth2RequestFactory oAuth2RequestFactory() {
return new DefaultOAuth2RequestFactory(getClientDetailsService());
}
@Bean
public TokenStore getJdbcTokenStore(){
TokenStore tokenStore = new JdbcTokenStore(dataSource);
return tokenStore;
}
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}

View File

@@ -1,50 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
TokenStore tokenStore = jdbcTokenStore();
OAuth2AuthenticationManager auth2AuthenticationManager= new OAuth2AuthenticationManager();
resources.authenticationManager(auth2AuthenticationManager);
resources.resourceId("speaker-service").tokenStore(tokenStore).stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
// 限制资源服务器只接管匹配的资源
http.requestMatchers().antMatchers("/oauth/speaker/**")
.and()
//授权的请求
.authorizeRequests()
.anyRequest().authenticated()
//关闭跨站请求防护
.and()
.csrf().disable();
}
public TokenStore jdbcTokenStore(){
TokenStore tokenStore = new JdbcTokenStore(dataSource);
return tokenStore;
}
}

View File

@@ -1,83 +0,0 @@
package com.fastbee.iot.oauth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import java.util.*;
/**
* kerwincui
*/
public class SpeakerApprovalHandler extends ApprovalStoreUserApprovalHandler {
private int approvalExpirySeconds = -1;
@Autowired
private ApprovalStore approvalStore;
public SpeakerApprovalHandler(JdbcClientDetailsService clientDetailsService, ApprovalStore approvalStore, OAuth2RequestFactory oAuth2RequestFactory) {
this.setApprovalStore(approvalStore);
this.setClientDetailsService(clientDetailsService);
this.setRequestFactory(oAuth2RequestFactory);
}
@Override
public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
// 获取授权过的范围
Set<String> requestedScopes = authorizationRequest.getScope();
Set<String> approvedScopes = new HashSet<String>();
Set<Approval> approvals = new HashSet<Approval>();
Date expiry = computeExpiry();
// 存储授权或拒绝的范围
Map<String, String> approvalParameters = authorizationRequest.getApprovalParameters();
for (String requestedScope : requestedScopes) {
String approvalParameter = OAuth2Utils.SCOPE_PREFIX + requestedScope;
String value = approvalParameters.get(approvalParameter);
value = value == null ? "" : value.toLowerCase();
if ("true".equals(value) || value.startsWith("approve")||value.equals("on")) {
approvedScopes.add(requestedScope);
approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
requestedScope, expiry, Approval.ApprovalStatus.APPROVED));
}
else {
approvals.add(new Approval(userAuthentication.getName(), authorizationRequest.getClientId(),
requestedScope, expiry, Approval.ApprovalStatus.DENIED));
}
}
approvalStore.addApprovals(approvals);
boolean approved;
authorizationRequest.setScope(approvedScopes);
if (approvedScopes.isEmpty() && !requestedScopes.isEmpty()) {
approved = false;
}
else {
approved = true;
}
authorizationRequest.setApproved(approved);
return authorizationRequest;
}
private Date computeExpiry() {
Calendar expiresAt = Calendar.getInstance();
// 默认一个月
if (approvalExpirySeconds == -1) {
expiresAt.add(Calendar.MONTH, 1);
}
else {
expiresAt.add(Calendar.SECOND, approvalExpirySeconds);
}
return expiresAt.getTime();
}
}

View File

@@ -1,49 +0,0 @@
package com.fastbee.iot.oauth.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import java.security.Principal;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* kerwincui
*/
@Controller
@SessionAttributes("authorizationRequest")
public class ConfirmAccessController {
@Autowired
private JdbcClientDetailsService clientDetailsService;
@Autowired
private ApprovalStore approvalStore;
@RequestMapping("/oauth/confirm_access")
public String getAccessConfirmation(Map<String, Object> model, Principal principal ) {
AuthorizationRequest clientAuth = (AuthorizationRequest) model.remove("authorizationRequest");
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
Map<String, String> scopes = new LinkedHashMap<String, String>();
for (String scope : clientAuth.getScope()) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + scope, "false");
}
for (Approval approval : approvalStore.getApprovals(principal.getName(), client.getClientId())) {
if (clientAuth.getScope().contains(approval.getScope())) {
scopes.put(OAuth2Utils.SCOPE_PREFIX + approval.getScope(),
approval.getStatus() == Approval.ApprovalStatus.APPROVED ? "true" : "false");
}
}
model.put("auth_request", clientAuth);
model.put("client", client);
model.put("scopes", scopes);
return "oauth/access_confirmation";
}
}

View File

@@ -1,55 +0,0 @@
package com.fastbee.iot.oauth.api;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.core.domain.model.LoginBody;
import com.fastbee.common.utils.SecurityUtils;
import com.fastbee.framework.web.service.SysLoginService;
import com.fastbee.framework.web.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Controller
public class LoginController {
@Autowired
private TokenStore tokenStore;
@Autowired
private SysLoginService loginService;
@Autowired
private TokenService tokenService;
@RequestMapping("/oauth/login")
public String login() {
return "oauth/login";
}
@RequestMapping("/oauth/index")
public String index() {
return "oauth/index";
}
@GetMapping("/oauth/logout")
@ResponseBody
public String logout(@RequestHeader String Authorization) {
if (!Authorization.isEmpty()){
String token=Authorization.split(" ")[1];
OAuth2AccessToken auth2AccessToken = tokenStore.readAccessToken(token);
tokenStore.removeAccessToken(auth2AccessToken);
return "SUCCESS";
}else{
return "FAIL";
}
}
}

View File

@@ -1,33 +0,0 @@
package com.fastbee.iot.oauth.api;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* kerwincui
*/
@RestController
public class SpeakerController {
@GetMapping("/oauth/speaker/get")
public JSONObject getSpeaker() {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JSONObject Json = new JSONObject();
Json.put("1", "1");
Json.put("2", "2");
Json.put("3", "3");
System.out.println("调用了接口get");
return Json;
}
@PostMapping("/oauth/speaker/post")
public JSONObject postSpeaker() {
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
JSONObject bookJson = new JSONObject();
bookJson.put("1", "1");
System.out.println("调用了接口post");
return bookJson;
}
}

View File

@@ -144,10 +144,10 @@ public class ToolServiceImpl implements IToolService
{ {
msg = "密码长度必须在5到20个字符之间"; msg = "密码长度必须在5到20个字符之间";
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser))) else if (userService.checkUserNameUnique(sysUser))
{ {
msg = "保存用户'" + username + "'失败,注册账号已存在"; msg = "保存用户'" + username + "'失败,注册账号已存在";
}else if (UserConstants.NOT_UNIQUE.equals(checkPhoneUnique(phonenumber))) }else if (checkPhoneUnique(phonenumber))
{ {
msg = "保存用户'" + username + "'失败,注册手机号码已存在"; msg = "保存用户'" + username + "'失败,注册手机号码已存在";
} }
@@ -203,10 +203,10 @@ public class ToolServiceImpl implements IToolService
{ {
msg = "密码长度必须在5到20个字符之间"; msg = "密码长度必须在5到20个字符之间";
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser))) else if (userService.checkUserNameUnique(sysUser))
{ {
msg = "保存用户'" + username + "'失败,注册账号已存在"; msg = "保存用户'" + username + "'失败,注册账号已存在";
}else if (UserConstants.NOT_UNIQUE.equals(checkPhoneUnique(phonenumber))) }else if (checkPhoneUnique(phonenumber))
{ {
msg = "保存用户'" + username + "'失败,注册手机号码已存在"; msg = "保存用户'" + username + "'失败,注册手机号码已存在";
} }
@@ -252,7 +252,7 @@ public class ToolServiceImpl implements IToolService
* @param phonenumber 手机号码 * @param phonenumber 手机号码
* @return * @return
*/ */
public String checkPhoneUnique(String phonenumber) public boolean checkPhoneUnique(String phonenumber)
{ {
SysUser info = userMapper.checkPhoneUnique(phonenumber); SysUser info = userMapper.checkPhoneUnique(phonenumber);
if (StringUtils.isNotNull(info)) if (StringUtils.isNotNull(info))

View File

@@ -1,19 +1,18 @@
package com.fastbee.system.domain; package com.fastbee.system.domain;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fastbee.common.annotation.Excel; import com.fastbee.common.annotation.Excel;
import com.fastbee.common.annotation.Excel.ColumnType; import com.fastbee.common.annotation.Excel.ColumnType;
import com.fastbee.common.core.domain.BaseEntity; import com.fastbee.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
/** /**
* 操作日志记录表 oper_log * 操作日志记录表 oper_log
* *
* @author ruoyi * @author ruoyi
*/ */
@ApiModel(value = "SysOperLog", description = "操作日志记录表 oper_log")
public class SysOperLog extends BaseEntity public class SysOperLog extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -103,6 +102,10 @@ public class SysOperLog extends BaseEntity
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date operTime; private Date operTime;
/** 消耗时间 */
@Excel(name = "消耗时间", suffix = "毫秒")
private Long costTime;
public Long getOperId() public Long getOperId()
{ {
return operId; return operId;
@@ -272,4 +275,14 @@ public class SysOperLog extends BaseEntity
{ {
this.operTime = operTime; this.operTime = operTime;
} }
public Long getCostTime()
{
return costTime;
}
public void setCostTime(Long costTime)
{
this.costTime = costTime;
}
} }

View File

@@ -1,8 +1,9 @@
package com.fastbee.system.mapper; package com.fastbee.system.mapper;
import java.util.List;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
import java.util.List;
/** /**
* 角色表 数据层 * 角色表 数据层
* *

View File

@@ -1,8 +1,9 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import java.util.List;
import com.fastbee.system.domain.SysConfig; import com.fastbee.system.domain.SysConfig;
import java.util.List;
/** /**
* 参数配置 服务层 * 参数配置 服务层
* *
@@ -85,5 +86,5 @@ public interface ISysConfigService
* @param config 参数信息 * @param config 参数信息
* @return 结果 * @return 结果
*/ */
public String checkConfigKeyUnique(SysConfig config); public boolean checkConfigKeyUnique(SysConfig config);
} }

View File

@@ -1,9 +1,10 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import java.util.List;
import com.fastbee.common.core.domain.TreeSelect; import com.fastbee.common.core.domain.TreeSelect;
import com.fastbee.common.core.domain.entity.SysDept; import com.fastbee.common.core.domain.entity.SysDept;
import java.util.List;
/** /**
* 部门管理 服务层 * 部门管理 服务层
* *
@@ -89,7 +90,7 @@ public interface ISysDeptService
* @param dept 部门信息 * @param dept 部门信息
* @return 结果 * @return 结果
*/ */
public String checkDeptNameUnique(SysDept dept); public boolean checkDeptNameUnique(SysDept dept);
/** /**
* 校验部门是否有数据权限 * 校验部门是否有数据权限

View File

@@ -1,9 +1,10 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import java.util.List;
import com.fastbee.common.core.domain.entity.SysDictData; import com.fastbee.common.core.domain.entity.SysDictData;
import com.fastbee.common.core.domain.entity.SysDictType; import com.fastbee.common.core.domain.entity.SysDictType;
import java.util.List;
/** /**
* 字典 业务层 * 字典 业务层
* *
@@ -94,5 +95,5 @@ public interface ISysDictTypeService
* @param dictType 字典类型 * @param dictType 字典类型
* @return 结果 * @return 结果
*/ */
public String checkDictTypeUnique(SysDictType dictType); public boolean checkDictTypeUnique(SysDictType dictType);
} }

View File

@@ -140,5 +140,5 @@ public interface ISysMenuService
* @param menu 菜单信息 * @param menu 菜单信息
* @return 结果 * @return 结果
*/ */
public String checkMenuNameUnique(SysMenu menu); public boolean checkMenuNameUnique(SysMenu menu);
} }

View File

@@ -1,8 +1,9 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import java.util.List;
import com.fastbee.system.domain.SysOperLog; import com.fastbee.system.domain.SysOperLog;
import java.util.List;
/** /**
* 操作日志 服务层 * 操作日志 服务层
* *

View File

@@ -1,8 +1,9 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import java.util.List;
import com.fastbee.system.domain.SysPost; import com.fastbee.system.domain.SysPost;
import java.util.List;
/** /**
* 岗位信息 服务层 * 岗位信息 服务层
* *
@@ -47,7 +48,7 @@ public interface ISysPostService
* @param post 岗位信息 * @param post 岗位信息
* @return 结果 * @return 结果
*/ */
public String checkPostNameUnique(SysPost post); public boolean checkPostNameUnique(SysPost post);
/** /**
* 校验岗位编码 * 校验岗位编码
@@ -55,7 +56,7 @@ public interface ISysPostService
* @param post 岗位信息 * @param post 岗位信息
* @return 结果 * @return 结果
*/ */
public String checkPostCodeUnique(SysPost post); public boolean checkPostCodeUnique(SysPost post);
/** /**
* 通过岗位ID查询岗位使用数量 * 通过岗位ID查询岗位使用数量

View File

@@ -1,9 +1,10 @@
package com.fastbee.system.service; package com.fastbee.system.service;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.system.domain.SysUserRole;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import com.fastbee.common.core.domain.entity.SysRole;
import com.fastbee.system.domain.SysUserRole;
/** /**
* 角色业务层 * 角色业务层
@@ -65,7 +66,7 @@ public interface ISysRoleService
* @param role 角色信息 * @param role 角色信息
* @return 结果 * @return 结果
*/ */
public String checkRoleNameUnique(SysRole role); public boolean checkRoleNameUnique(SysRole role);
/** /**
* 校验角色权限是否唯一 * 校验角色权限是否唯一
@@ -73,7 +74,7 @@ public interface ISysRoleService
* @param role 角色信息 * @param role 角色信息
* @return 结果 * @return 结果
*/ */
public String checkRoleKeyUnique(SysRole role); public boolean checkRoleKeyUnique(SysRole role);
/** /**
* 校验角色是否允许操作 * 校验角色是否允许操作
@@ -85,9 +86,9 @@ public interface ISysRoleService
/** /**
* 校验角色是否有数据权限 * 校验角色是否有数据权限
* *
* @param roleId 角色id * @param roleIds 角色id
*/ */
public void checkRoleDataScope(Long roleId); public void checkRoleDataScope(Long... roleIds);
/** /**
* 通过角色ID查询角色使用数量 * 通过角色ID查询角色使用数量

View File

@@ -73,7 +73,7 @@ public interface ISysUserService
* @param user 用户信息 * @param user 用户信息
* @return 结果 * @return 结果
*/ */
public String checkUserNameUnique(SysUser user); public boolean checkUserNameUnique(SysUser user);
/** /**
* 校验手机号码是否唯一 * 校验手机号码是否唯一
@@ -81,7 +81,7 @@ public interface ISysUserService
* @param user 用户信息 * @param user 用户信息
* @return 结果 * @return 结果
*/ */
public String checkPhoneUnique(SysUser user); public boolean checkPhoneUnique(SysUser user);
/** /**
* 校验email是否唯一 * 校验email是否唯一
@@ -89,7 +89,7 @@ public interface ISysUserService
* @param user 用户信息 * @param user 用户信息
* @return 结果 * @return 结果
*/ */
public String checkEmailUnique(SysUser user); public boolean checkEmailUnique(SysUser user);
/** /**
* 校验用户是否允许操作 * 校验用户是否允许操作

View File

@@ -1,10 +1,5 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.Collection;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fastbee.common.annotation.DataSource; import com.fastbee.common.annotation.DataSource;
import com.fastbee.common.constant.CacheConstants; import com.fastbee.common.constant.CacheConstants;
import com.fastbee.common.constant.UserConstants; import com.fastbee.common.constant.UserConstants;
@@ -16,6 +11,12 @@ import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.domain.SysConfig; import com.fastbee.system.domain.SysConfig;
import com.fastbee.system.mapper.SysConfigMapper; import com.fastbee.system.mapper.SysConfigMapper;
import com.fastbee.system.service.ISysConfigService; import com.fastbee.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
/** /**
* 参数配置 服务层实现 * 参数配置 服务层实现
@@ -208,7 +209,7 @@ public class SysConfigServiceImpl implements ISysConfigService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkConfigKeyUnique(SysConfig config) public boolean checkConfigKeyUnique(SysConfig config)
{ {
Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId(); Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey()); SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());

View File

@@ -1,11 +1,5 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fastbee.common.annotation.DataScope; import com.fastbee.common.annotation.DataScope;
import com.fastbee.common.constant.UserConstants; import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.TreeSelect; import com.fastbee.common.core.domain.TreeSelect;
@@ -20,6 +14,13 @@ import com.fastbee.common.utils.spring.SpringUtils;
import com.fastbee.system.mapper.SysDeptMapper; import com.fastbee.system.mapper.SysDeptMapper;
import com.fastbee.system.mapper.SysRoleMapper; import com.fastbee.system.mapper.SysRoleMapper;
import com.fastbee.system.service.ISysDeptService; import com.fastbee.system.service.ISysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/** /**
* 部门管理 服务实现 * 部门管理 服务实现
@@ -171,7 +172,7 @@ public class SysDeptServiceImpl implements ISysDeptService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkDeptNameUnique(SysDept dept) public boolean checkDeptNameUnique(SysDept dept)
{ {
Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId(); Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId()); SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
@@ -190,7 +191,7 @@ public class SysDeptServiceImpl implements ISysDeptService
@Override @Override
public void checkDeptDataScope(Long deptId) public void checkDeptDataScope(Long deptId)
{ {
if (!SysUser.isAdmin(SecurityUtils.getUserId())) if (!SysUser.isAdmin(SecurityUtils.getUserId()) && StringUtils.isNotNull(deptId))
{ {
SysDept dept = new SysDept(); SysDept dept = new SysDept();
dept.setDeptId(deptId); dept.setDeptId(deptId);

View File

@@ -1,13 +1,5 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fastbee.common.constant.UserConstants; import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.entity.SysDictData; import com.fastbee.common.core.domain.entity.SysDictData;
import com.fastbee.common.core.domain.entity.SysDictType; import com.fastbee.common.core.domain.entity.SysDictType;
@@ -17,6 +9,15 @@ import com.fastbee.common.utils.StringUtils;
import com.fastbee.system.mapper.SysDictDataMapper; import com.fastbee.system.mapper.SysDictDataMapper;
import com.fastbee.system.mapper.SysDictTypeMapper; import com.fastbee.system.mapper.SysDictTypeMapper;
import com.fastbee.system.service.ISysDictTypeService; import com.fastbee.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* 字典 业务层处理 * 字典 业务层处理
@@ -210,7 +211,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkDictTypeUnique(SysDictType dict) public boolean checkDictTypeUnique(SysDictType dict)
{ {
Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId(); Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType()); SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());

View File

@@ -335,7 +335,7 @@ public class SysMenuServiceImpl implements ISysMenuService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkMenuNameUnique(SysMenu menu) public boolean checkMenuNameUnique(SysMenu menu)
{ {
Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId(); Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId()); SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());

View File

@@ -1,11 +1,12 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fastbee.system.domain.SysOperLog; import com.fastbee.system.domain.SysOperLog;
import com.fastbee.system.mapper.SysOperLogMapper; import com.fastbee.system.mapper.SysOperLogMapper;
import com.fastbee.system.service.ISysOperLogService; import com.fastbee.system.service.ISysOperLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/** /**
* 操作日志 服务层处理 * 操作日志 服务层处理

View File

@@ -1,8 +1,5 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fastbee.common.constant.UserConstants; import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.exception.ServiceException; import com.fastbee.common.exception.ServiceException;
import com.fastbee.common.utils.StringUtils; import com.fastbee.common.utils.StringUtils;
@@ -10,6 +7,10 @@ import com.fastbee.system.domain.SysPost;
import com.fastbee.system.mapper.SysPostMapper; import com.fastbee.system.mapper.SysPostMapper;
import com.fastbee.system.mapper.SysUserPostMapper; import com.fastbee.system.mapper.SysUserPostMapper;
import com.fastbee.system.service.ISysPostService; import com.fastbee.system.service.ISysPostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/** /**
* 岗位信息 服务层处理 * 岗位信息 服务层处理
@@ -79,7 +80,7 @@ public class SysPostServiceImpl implements ISysPostService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkPostNameUnique(SysPost post) public boolean checkPostNameUnique(SysPost post)
{ {
Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
SysPost info = postMapper.checkPostNameUnique(post.getPostName()); SysPost info = postMapper.checkPostNameUnique(post.getPostName());
@@ -97,7 +98,7 @@ public class SysPostServiceImpl implements ISysPostService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkPostCodeUnique(SysPost post) public boolean checkPostCodeUnique(SysPost post)
{ {
Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId(); Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
SysPost info = postMapper.checkPostCodeUnique(post.getPostCode()); SysPost info = postMapper.checkPostCodeUnique(post.getPostCode());

View File

@@ -1,13 +1,5 @@
package com.fastbee.system.service.impl; package com.fastbee.system.service.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fastbee.common.annotation.DataScope; import com.fastbee.common.annotation.DataScope;
import com.fastbee.common.constant.UserConstants; import com.fastbee.common.constant.UserConstants;
import com.fastbee.common.core.domain.entity.SysRole; import com.fastbee.common.core.domain.entity.SysRole;
@@ -24,6 +16,11 @@ import com.fastbee.system.mapper.SysRoleMapper;
import com.fastbee.system.mapper.SysRoleMenuMapper; import com.fastbee.system.mapper.SysRoleMenuMapper;
import com.fastbee.system.mapper.SysUserRoleMapper; import com.fastbee.system.mapper.SysUserRoleMapper;
import com.fastbee.system.service.ISysRoleService; import com.fastbee.system.service.ISysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/** /**
* 角色 业务层处理 * 角色 业务层处理
@@ -146,7 +143,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkRoleNameUnique(SysRole role) public boolean checkRoleNameUnique(SysRole role)
{ {
Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName()); SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
@@ -164,7 +161,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkRoleKeyUnique(SysRole role) public boolean checkRoleKeyUnique(SysRole role)
{ {
Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId(); Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey()); SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
@@ -192,12 +189,14 @@ public class SysRoleServiceImpl implements ISysRoleService
/** /**
* 校验角色是否有数据权限 * 校验角色是否有数据权限
* *
* @param roleId 角色id * @param roleIds 角色id
*/ */
@Override @Override
public void checkRoleDataScope(Long roleId) public void checkRoleDataScope(Long... roleIds)
{ {
if (!SysUser.isAdmin(SecurityUtils.getUserId())) if (!SysUser.isAdmin(SecurityUtils.getUserId()))
{
for (Long roleId : roleIds)
{ {
SysRole role = new SysRole(); SysRole role = new SysRole();
role.setRoleId(roleId); role.setRoleId(roleId);
@@ -208,6 +207,7 @@ public class SysRoleServiceImpl implements ISysRoleService
} }
} }
} }
}
/** /**
* 通过角色ID查询角色使用数量 * 通过角色ID查询角色使用数量

View File

@@ -13,12 +13,9 @@ import com.fastbee.common.utils.spring.SpringUtils;
import com.fastbee.system.domain.SysPost; import com.fastbee.system.domain.SysPost;
import com.fastbee.system.domain.SysUserPost; import com.fastbee.system.domain.SysUserPost;
import com.fastbee.system.domain.SysUserRole; import com.fastbee.system.domain.SysUserRole;
import com.fastbee.system.mapper.SysPostMapper; import com.fastbee.system.mapper.*;
import com.fastbee.system.mapper.SysRoleMapper;
import com.fastbee.system.mapper.SysUserMapper;
import com.fastbee.system.mapper.SysUserPostMapper;
import com.fastbee.system.mapper.SysUserRoleMapper;
import com.fastbee.system.service.ISysConfigService; import com.fastbee.system.service.ISysConfigService;
import com.fastbee.system.service.ISysDeptService;
import com.fastbee.system.service.ISysUserService; import com.fastbee.system.service.ISysUserService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -60,6 +57,9 @@ public class SysUserServiceImpl implements ISysUserService
@Autowired @Autowired
private ISysConfigService configService; private ISysConfigService configService;
@Autowired
private ISysDeptService deptService;
@Autowired @Autowired
protected Validator validator; protected Validator validator;
@@ -167,7 +167,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果 * @return 结果
*/ */
@Override @Override
public String checkUserNameUnique(SysUser user) public boolean checkUserNameUnique(SysUser user)
{ {
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkUserNameUnique(user.getUserName()); SysUser info = userMapper.checkUserNameUnique(user.getUserName());
@@ -185,7 +185,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return * @return
*/ */
@Override @Override
public String checkPhoneUnique(SysUser user) public boolean checkPhoneUnique(SysUser user)
{ {
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
@@ -203,7 +203,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return * @return
*/ */
@Override @Override
public String checkEmailUnique(SysUser user) public boolean checkEmailUnique(SysUser user)
{ {
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkEmailUnique(user.getEmail()); SysUser info = userMapper.checkEmailUnique(user.getEmail());
@@ -495,7 +495,6 @@ public class SysUserServiceImpl implements ISysUserService
int failureNum = 0; int failureNum = 0;
StringBuilder successMsg = new StringBuilder(); StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder(); StringBuilder failureMsg = new StringBuilder();
String password = configService.selectConfigByKey("sys.user.initPassword");
for (SysUser user : userList) for (SysUser user : userList)
{ {
try try
@@ -505,19 +504,23 @@ public class SysUserServiceImpl implements ISysUserService
if (StringUtils.isNull(u)) if (StringUtils.isNull(u))
{ {
BeanValidators.validateWithException(validator, user); BeanValidators.validateWithException(validator, user);
deptService.checkDeptDataScope(user.getDeptId());
String password = configService.selectConfigByKey("sys.user.initPassword");
user.setPassword(SecurityUtils.encryptPassword(password)); user.setPassword(SecurityUtils.encryptPassword(password));
user.setCreateBy(operName); user.setCreateBy(operName);
this.insertUser(user); userMapper.insertUser(user);
successNum++; successNum++;
successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功"); successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
} }
else if (isUpdateSupport) else if (isUpdateSupport)
{ {
BeanValidators.validateWithException(validator, user); BeanValidators.validateWithException(validator, user);
checkUserAllowed(user); checkUserAllowed(u);
checkUserDataScope(user.getUserId()); checkUserDataScope(u.getUserId());
deptService.checkDeptDataScope(user.getDeptId());
user.setUserId(u.getUserId());
user.setUpdateBy(operName); user.setUpdateBy(operName);
this.updateUser(user); userMapper.updateUser(user);
successNum++; successNum++;
successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功"); successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
} }

View File

@@ -21,21 +21,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" /> <result property="status" column="status" />
<result property="errorMsg" column="error_msg" /> <result property="errorMsg" column="error_msg" />
<result property="operTime" column="oper_time" /> <result property="operTime" column="oper_time" />
<result property="costTime" column="cost_time" />
</resultMap> </resultMap>
<sql id="selectOperLogVo"> <sql id="selectOperLogVo">
select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time
from sys_oper_log from sys_oper_log
</sql> </sql>
<insert id="insertOperlog" parameterType="SysOperLog"> <insert id="insertOperlog" parameterType="SysOperLog">
insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time) insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, cost_time, oper_time)
values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, sysdate()) values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())
</insert> </insert>
<select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult"> <select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
<include refid="selectOperLogVo"/> <include refid="selectOperLogVo"/>
<where> <where>
<if test="operIp != null and operIp != ''">
AND oper_ip like concat('%', #{operIp}, '%')
</if>
<if test="title != null and title != ''"> <if test="title != null and title != ''">
AND title like concat('%', #{title}, '%') AND title like concat('%', #{title}, '%')
</if> </if>
@@ -55,10 +59,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND oper_name like concat('%', #{operName}, '%') AND oper_name like concat('%', #{operName}, '%')
</if> </if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(oper_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d') AND oper_time &gt;= #{params.beginTime}
</if> </if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(oper_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d') AND oper_time &lt;= #{params.endTime}
</if> </if>
</where> </where>
order by oper_id desc order by oper_id desc

View File

@@ -46,10 +46,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND r.role_key like concat('%', #{roleKey}, '%') AND r.role_key like concat('%', #{roleKey}, '%')
</if> </if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d') and date_format(r.create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
</if> </if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d') and date_format(r.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
</if> </if>
<!-- 数据范围过滤 --> <!-- 数据范围过滤 -->
${params.dataScope} ${params.dataScope}

View File

@@ -23,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateBy" column="update_by" /> <result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" /> <result property="updateTime" column="update_time" />
<result property="remark" column="remark" /> <result property="remark" column="remark" />
<association property="dept" column="dept_id" javaType="SysDept" resultMap="deptResult" /> <association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> <collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
</resultMap> </resultMap>
@@ -73,10 +73,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND u.phonenumber like concat('%', #{phonenumber}, '%') AND u.phonenumber like concat('%', #{phonenumber}, '%')
</if> </if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d') AND date_format(u.create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
</if> </if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d') AND date_format(u.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
</if> </if>
<if test="deptId != null and deptId != 0"> <if test="deptId != null and deptId != 0">
AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) )) AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
@@ -142,11 +142,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
</select> </select>
<select id="selectUserByPhoneNumber" parameterType="String" resultMap="SysUserResult">
<include refid="selectUserVo"/>
where u.phonenumber = #{phoneNumber} and u.del_flag = '0'
</select>
<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId"> <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
insert into sys_user( insert into sys_user(
<if test="userId != null and userId != 0">user_id,</if> <if test="userId != null and userId != 0">user_id,</if>
@@ -183,7 +178,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update sys_user update sys_user
<set> <set>
<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
<if test="email != null ">email = #{email},</if> <if test="email != null ">email = #{email},</if>
<if test="phonenumber != null ">phonenumber = #{phonenumber},</if> <if test="phonenumber != null ">phonenumber = #{phonenumber},</if>
@@ -223,29 +217,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
<delete id="deleteBySysUserIdAndSourceClient">
update iot_social_user
set del_flag = 1,
update_time = now()
where sys_user_id = #{sysUserId}
and source_client in
<foreach item="sourceClient" collection="sourceClientList" open="(" separator="," close=")">
#{sourceClient}
</foreach>
</delete>
<delete id="deleteBySysUserIdsAndSourceClient">
update iot_social_user
set del_flag = 1,
update_time = now()
where sys_user_id in
<foreach item="sysUserId" collection="sysUserIds" open="(" separator="," close=")">
#{sysUserId}
</foreach>
and source_client in
<foreach item="sourceClient" collection="sourceClientList" open="(" separator="," close=")">
#{sourceClient}
</foreach>
</delete>
</mapper> </mapper>

View File

@@ -13,7 +13,7 @@
<description>FastBee物联网平台</description> <description>FastBee物联网平台</description>
<properties> <properties>
<ruoyi.version>3.8.5</ruoyi.version> <ruoyi.version>3.8.9</ruoyi.version>
<fastbee.version>2.1.0</fastbee.version> <fastbee.version>2.1.0</fastbee.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -66,15 +66,65 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- SpringFramework的依赖配置-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring-framework.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringSecurity的依赖配置-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>${spring-security.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringBoot的依赖配置--> <!-- SpringBoot的依赖配置-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>2.5.14</version> <version>${spring-boot.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<!-- 覆盖logback的依赖配置-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 覆盖tomcat的依赖配置-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- 阿里数据库连接池 --> <!-- 阿里数据库连接池 -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>