70 Commits

Author SHA1 Message Date
valarchie
b920a748ed refactor: 使用final修饰符取代 @NonNull注解 进行bean注入 2023-08-14 23:22:11 +08:00
valarchie
4e0c6b80b7 refactor: 规范全局事务管理器 2023-08-14 22:47:41 +08:00
valarchie
16a06edb89 refactor: 移除orm模块 以及xml内容 2023-08-14 22:28:09 +08:00
valarchie
53e63c8b8e refactor: 修改数据类服务切面 2023-08-14 22:14:41 +08:00
valarchie
00f65d91ab refactor: 将orm包中数据相关类 挪到domain包中 2023-08-14 22:10:24 +08:00
valarchie
f3aaa771f6 refactor: 修复addTimeCondition方法 2023-08-14 20:45:27 +08:00
valarchie
5f31b9c27e refactor: 将orm包中的common类挪到common模块 2023-08-14 20:44:09 +08:00
valarchie
01afc4505f refactor: 将enum接口挪到common包 2023-08-14 17:16:23 +08:00
valarchie
b340bff225 refactor: 将RoleInfo与orm包解耦 2023-08-14 17:11:04 +08:00
valarchie
74c71156f0 refactor: 把MapCache挪到domain包 2023-08-14 17:03:42 +08:00
valarchie
90c231221f refactor: 把GuavaCacheService挪到domain包 2023-08-14 16:56:51 +08:00
valarchie
58b0d14340 refactor: 把RedisCacheService挪到domain包 2023-08-14 16:46:57 +08:00
valarchie
d72be1a446 refactor: 清理RoleInfo缓存 2023-08-14 16:21:26 +08:00
valarchie
157afb3673 refactor: 将异步工厂类挪到admin模块 2023-08-14 16:10:16 +08:00
valarchie
0ae219e942 refactor: 将操作日志AOP挪到 2023-08-14 16:00:46 +08:00
valarchie
377afbb8fc Merge remote-tracking branch 'origin/For-Pure' into For-Pure 2023-08-14 15:13:33 +08:00
valarchie
64e2fc9912 refactor: 新增dev 配置文件 2023-08-14 14:55:56 +08:00
valarchie
3e25d18463 refactor: 将集成测试模块挪到领域逻辑domain模块中 2023-08-14 14:35:52 +08:00
valarchie
37e052ef62 refactor: 上传dev配置文件 2023-08-08 19:19:37 +08:00
valarchie
aa0e1f91c5 refactor: 调整包结构以便二次开发 2023-08-05 14:33:08 +08:00
valarchie
242f536986 feature: 新增filter填入requestId方便跟踪日志 2023-08-01 20:25:43 +08:00
valarchie
df7f6950d1 refactor: 新增API的请求拦截 2023-08-01 14:02:27 +08:00
valarchie
3f384fbe79 refactor: 去掉返回类中的requestId API模块使用undertow服务器 2023-08-01 13:44:43 +08:00
valarchie
7c9b86a304 refactor: 把配置文件挪到admin和api模块 2023-07-30 16:07:08 +08:00
valarchie
917050e543 refactor: 把登录用户 拆分为系统用户和App用户 2023-07-30 13:44:43 +08:00
valarchie
6f96216248 refactor: 把登录逻辑移到admin 因为不同项目的登录 可能是不一样的 2023-07-30 13:32:25 +08:00
valarchie
fcb88e5a94 refactor: 把登录逻辑移到admin 因为不同项目的登录 可能是不一样的 2023-07-30 12:55:54 +08:00
valarchie
37f2b63038 refactor: 调整基础设施模块 2023-07-30 12:03:23 +08:00
valarchie
b59ed7d7d6 refactor: 将请求重复提交和请求限流重构区分为App和Web 2023-07-30 11:49:05 +08:00
valarchie
3a9fbb563e refactor: 将请求重复提交和请求限流重构区分为App和Web 2023-07-30 11:35:05 +08:00
valarchie
ec8dda127a fix: 调整common包 2023-07-30 00:45:09 +08:00
valarchie
59f6693005 refactor: 重构错误码的设计以及错误处理 2023-07-26 22:12:23 +08:00
valarchie
7a570300b5 refactor: 重构个人中心功能 2023-07-25 19:50:43 +08:00
valarchie
4174c15934 refactor: 新增用户页面 2023-07-24 21:46:55 +08:00
Lyp
891f908522 fix: 修改新增角色参数的序号类型 2023-07-23 20:52:16 +08:00
valarchie
d52a5bcbe5 refactor: 重构路由菜单功能 2023-07-22 17:22:10 +08:00
valarchie
7da7481887 refactor: 重构路由菜单功能 2023-07-22 17:15:43 +08:00
valarchie
71c9a7589d refactor: 重构部门页面 2023-07-20 22:53:47 +08:00
valarchie
f148232f0a refactor: 重构配置页面 2023-07-20 15:07:26 +08:00
valarchie
2318ce903d refactor: 重构缓存监控页面 2023-07-19 23:02:12 +08:00
valarchie
83df81583c refactor: 重构在线用户页面 2023-07-19 10:35:07 +08:00
valarchie
aa3b050b3f fix: 修复DB层异常捕获失败 2023-07-18 22:21:05 +08:00
valarchie
4605289348 feat: 更新数据库 2023-07-18 21:35:43 +08:00
valarchie
fc0a41a4e6 feat: 重构接口文档页面 2023-07-18 15:15:34 +08:00
valarchie
1382d2a32d refactor: 适配pure-admin登录日志页面 2023-07-16 21:39:07 +08:00
valarchie
97fc6d0367 refactor: 修改操作日志的后台导出excel 2023-07-16 14:04:22 +08:00
valarchie
52890e6e6e feat: 重构操作日志 2023-07-15 17:51:28 +08:00
valarchie
259e948325 Merge remote-tracking branch 'origin/For-Pure' into For-Pure 2023-07-15 08:18:01 +08:00
valarchie
9859bb1360 fix: 重构日志模块 2023-07-15 08:16:45 +08:00
valarchie
f03f441cb4 Merge pull request #42 from burningimlam/For-Pure
补充缺少的javadoc&消除部分代码检查警告
2023-07-14 22:05:29 +08:00
imlam
92782b9407 消除部分Sonar代码检查警告 2023-07-14 20:17:40 +08:00
imlam
0573b66ddc 补充缺少的javadoc&消除部分代码检查警告 2023-07-14 17:08:39 +08:00
valarchie
32e95e858e Merge pull request #41 from burningimlam/For-Pure
fix: 补充缺少的javadoc注释
2023-07-14 15:50:59 +08:00
imlam
92b698a313 补充缺少的javadoc注释 2023-07-14 14:20:20 +08:00
valarchie
2401ec2c62 refactor: 通知公告模块重构为更严格的restful风格 2023-07-13 12:13:08 +08:00
valarchie
7fdd8ef871 refactor: 规范字典类的名称 2023-07-12 21:03:32 +08:00
valarchie
4f7ada223a factor: 适配新的前端pure admin. 重构query基础类 2023-07-12 16:53:22 +08:00
valarchie
19f4eb29bb factor: 适配新的前端pure admin. 重构query基础类 2023-07-12 16:01:18 +08:00
valarchie
0b0edfa7a5 docs: 添加关于securityConfig的注释 2023-07-07 18:20:50 +08:00
valarchie
c56dd18064 feat: 实现登录登出的逻辑,拆分配置接口 2023-07-04 21:55:41 +08:00
valarchie
d6bb477219 refactor: 拆分一个getConfig接口用于返回系统的配置参数,重构错误码类,使其可以跳转到i18n文件 2023-07-02 20:55:30 +08:00
valarchie
aea62eb6e2 feat: 新增pure项目对应的sql文件 2023-07-01 16:45:51 +08:00
valarchie
76d5cccf95 refactor: 新增路由代码 2023-06-29 23:01:20 +08:00
valarchie
d27352ecbc Merge branch 'main' into For-Pure 2023-06-29 19:29:20 +08:00
valarchie
c46dbc512b refactor: 使用固定的版本号, revision会导致子module install不成功 2023-06-27 21:23:12 +08:00
valarchie
aeb3576be6 Merge branch 'main' into For-Pure 2023-06-27 15:22:02 +08:00
valarchie
afddd03fda feat: 新增密码加密登录操作,重构登录代码 2023-06-25 21:44:02 +08:00
valarchie
a37997583a doc: 添加内置redis关于macos启动失败的说明 2023-06-20 22:32:38 +08:00
valarchie
8976a867e3 refactor: 把前端端口从80改成3000,避免有些用户启用不了80端口 2023-06-20 22:30:14 +08:00
valarchie
fdef3ed7ad refactor: 修改mysql启动步骤 2023-06-17 21:54:02 +08:00
284 changed files with 5143 additions and 2835 deletions

View File

@@ -177,7 +177,7 @@ git clone https://github.com/valarchie/AgileBoot-Front-End
vite v2.6.14 dev server running at:
> Local: http://127.0.0.1:80/
> Local: http://127.0.0.1:3000/
ready in 4376ms.
@@ -202,6 +202,8 @@ agileboot.embedded.redis: false
agileboot.embedded.mysql: true
agileboot.embedded.redis: true
请注意:高版本的MacOS系统无法启动内置的Redis
3. 找到agileboot-admin模块中的AgileBootAdminApplication启动类直接启动即可
```

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>agileboot</artifactId>
<groupId>com.agileboot</groupId>
<version>${revision}</version>
<version>1.0.0</version>
</parent>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>

View File

@@ -30,7 +30,7 @@ import org.springframework.web.multipart.MultipartFile;
/**
* 通用请求处理
*
* TODO 需要重构
* @author valarchie
*/
@Tag(name = "上传API", description = "上传相关接口")
@@ -52,7 +52,7 @@ public class FileController {
if (!FileUploadUtils.isAllowDownload(fileName)) {
// 返回类型是ResponseEntity 不能捕获异常, 需要手动将错误填到 ResponseEntity
ResponseDTO<Object> fail = ResponseDTO.fail(
new ApiException(Business.FILE_NOT_ALLOWED_TO_DOWNLOAD, fileName));
new ApiException(Business.COMMON_FILE_NOT_ALLOWED_TO_DOWNLOAD, fileName));
return new ResponseEntity<>(JacksonUtil.to(fail).getBytes(), null, HttpStatus.OK);
}

View File

@@ -3,24 +3,24 @@ package com.agileboot.admin.controller.common;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.domain.common.cache.CacheCenter;
import com.agileboot.domain.common.dto.UserPermissionDTO;
import com.agileboot.domain.common.dto.CurrentLoginUserDTO;
import com.agileboot.domain.common.dto.TokenDTO;
import com.agileboot.domain.system.menu.MenuApplicationService;
import com.agileboot.domain.system.menu.dto.RouterDTO;
import com.agileboot.domain.system.user.UserApplicationService;
import com.agileboot.domain.system.user.command.AddUserCommand;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.RateLimit;
import com.agileboot.infrastructure.annotations.RateLimit.CacheType;
import com.agileboot.infrastructure.annotations.RateLimit.LimitType;
import com.agileboot.infrastructure.cache.map.MapCache;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.CaptchaDTO;
import com.agileboot.infrastructure.web.domain.login.LoginDTO;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.TokenDTO;
import com.agileboot.infrastructure.web.domain.ratelimit.RateLimitKey;
import com.agileboot.infrastructure.web.service.LoginService;
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit;
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit.CacheType;
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit.LimitType;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.admin.customize.service.login.dto.CaptchaDTO;
import com.agileboot.admin.customize.service.login.dto.ConfigDTO;
import com.agileboot.admin.customize.service.login.command.LoginCommand;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.annotations.ratelimit.RateLimitKey;
import com.agileboot.admin.customize.service.login.LoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -41,14 +41,13 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class LoginController {
@NonNull
private LoginService loginService;
private final LoginService loginService;
@NonNull
private MenuApplicationService menuApplicationService;
private final MenuApplicationService menuApplicationService;
@NonNull
private AgileBootConfig agileBootConfig;
private final UserApplicationService userApplicationService;
private final AgileBootConfig agileBootConfig;
/**
* 访问首页,提示语
@@ -62,6 +61,18 @@ public class LoginController {
agileBootConfig.getName(), agileBootConfig.getVersion());
}
/**
* 获取系统的内置配置
*
* @return 配置信息
*/
@GetMapping("/getConfig")
public ResponseDTO<ConfigDTO> getConfig() {
ConfigDTO configDTO = loginService.getConfig();
return ResponseDTO.ok(configDTO);
}
/**
* 生成验证码
*/
@@ -77,16 +88,18 @@ public class LoginController {
/**
* 登录方法
*
* @param loginDTO 登录信息
* @param loginCommand 登录信息
* @return 结果
*/
@Operation(summary = "登录")
@PostMapping("/login")
public ResponseDTO<TokenDTO> login(@RequestBody LoginDTO loginDTO) {
public ResponseDTO<TokenDTO> login(@RequestBody LoginCommand loginCommand) {
// 生成令牌
String token = loginService.login(loginDTO);
String token = loginService.login(loginCommand);
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
CurrentLoginUserDTO currentUserDTO = userApplicationService.getLoginUserInfo(loginUser);
return ResponseDTO.ok(new TokenDTO(token));
return ResponseDTO.ok(new TokenDTO(token, currentUserDTO));
}
/**
@@ -96,28 +109,23 @@ public class LoginController {
*/
@Operation(summary = "获取当前登录用户信息")
@GetMapping("/getLoginUserInfo")
public ResponseDTO<UserPermissionDTO> getLoginUserInfo() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
public ResponseDTO<CurrentLoginUserDTO> getLoginUserInfo() {
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
UserPermissionDTO permissionDTO = new UserPermissionDTO();
CurrentLoginUserDTO currentUserDTO = userApplicationService.getLoginUserInfo(loginUser);
permissionDTO.setUser(new UserDTO(CacheCenter.userCache.getObjectById(loginUser.getUserId())));
permissionDTO.setRoleKey(loginUser.getRoleInfo().getRoleKey());
permissionDTO.setPermissions(loginUser.getRoleInfo().getMenuPermissions());
permissionDTO.setDictTypes(MapCache.dictionaryCache());
return ResponseDTO.ok(permissionDTO);
return ResponseDTO.ok(currentUserDTO);
}
/**
* 获取路由信息
*
* TODO 如果要在前端开启路由缓存的话 需要在ServerConfig.json 中 设置CachingAsyncRoutes=true 避免一直重复请求路由接口
* @return 路由信息
*/
@Operation(summary = "获取用户对应的菜单路由", description = "用于动态生成路由")
@GetMapping("/getRouters")
public ResponseDTO<List<RouterDTO>> getRouters() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
List<RouterDTO> routerTree = menuApplicationService.getRouterTree(loginUser);
return ResponseDTO.ok(routerTree);
}
@@ -126,7 +134,7 @@ public class LoginController {
@Operation(summary = "注册接口", description = "暂未实现")
@PostMapping("/register")
public ResponseDTO<Void> register(@RequestBody AddUserCommand command) {
return ResponseDTO.fail(Business.UNSUPPORTED_OPERATION);
return ResponseDTO.fail(new ApiException(Business.COMMON_UNSUPPORTED_OPERATION));
}
}

View File

@@ -1,15 +1,15 @@
package com.agileboot.admin.controller.monitor;
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.domain.common.cache.CacheCenter;
import com.agileboot.domain.system.monitor.MonitorApplicationService;
import com.agileboot.domain.system.monitor.dto.OnlineUserInfo;
import com.agileboot.domain.system.monitor.dto.OnlineUserDTO;
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO;
import com.agileboot.domain.system.monitor.dto.ServerInfo;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -33,8 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class MonitorController extends BaseController {
@NonNull
private MonitorApplicationService monitorApplicationService;
private final MonitorApplicationService monitorApplicationService;
@Operation(summary = "Redis信息")
@PreAuthorize("@permission.has('monitor:cache:list')")
@@ -55,15 +54,16 @@ public class MonitorController extends BaseController {
/**
* 获取在线用户列表
* @param ipaddr
* @param userName
* @return
*
* @param ipAddress ip地址
* @param username 用户名
* @return 分页处理后的在线用户信息
*/
@Operation(summary = "在线用户列表")
@PreAuthorize("@permission.has('monitor:online:list')")
@GetMapping("/onlineUser/list")
public ResponseDTO<PageDTO<OnlineUserInfo>> list(String ipaddr, String userName) {
List<OnlineUserInfo> onlineUserList = monitorApplicationService.getOnlineUserList(userName, ipaddr);
@GetMapping("/onlineUsers")
public ResponseDTO<PageDTO<OnlineUserDTO>> onlineUsers(String ipAddress, String username) {
List<OnlineUserDTO> onlineUserList = monitorApplicationService.getOnlineUserList(username, ipAddress);
return ResponseDTO.ok(new PageDTO<>(onlineUserList));
}
@@ -74,7 +74,7 @@ public class MonitorController extends BaseController {
@PreAuthorize("@permission.has('monitor:online:forceLogout')")
@AccessLog(title = "在线用户", businessType = BusinessTypeEnum.FORCE_LOGOUT)
@DeleteMapping("/onlineUser/{tokenId}")
public ResponseDTO<Void> forceLogout(@PathVariable String tokenId) {
public ResponseDTO<Void> logoutOnlineUser(@PathVariable String tokenId) {
CacheCenter.loginUserCache.delete(tokenId);
return ResponseDTO.ok();
}

View File

@@ -8,14 +8,10 @@ import com.agileboot.domain.system.config.ConfigApplicationService;
import com.agileboot.domain.system.config.command.ConfigUpdateCommand;
import com.agileboot.domain.system.config.dto.ConfigDTO;
import com.agileboot.domain.system.config.query.ConfigQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.cache.map.MapCache;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.orm.common.result.DictionaryData;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import lombok.NonNull;
@@ -35,44 +31,30 @@ import org.springframework.web.bind.annotation.RestController;
* @author valarchie
*/
@RestController
@RequestMapping("/system/config")
@RequestMapping("/system")
@Validated
@RequiredArgsConstructor
@Tag(name = "配置API", description = "配置相关的增删查改")
public class SysConfigController extends BaseController {
@NonNull
private ConfigApplicationService configApplicationService;
private final ConfigApplicationService configApplicationService;
/**
* 获取参数配置列表
*/
@Operation(summary = "参数列表", description = "分页获取配置参数列表")
@PreAuthorize("@permission.has('system:config:list')")
@GetMapping("/list")
@GetMapping("/configs")
public ResponseDTO<PageDTO<ConfigDTO>> list(ConfigQuery query) {
PageDTO<ConfigDTO> page = configApplicationService.getConfigList(query);
return ResponseDTO.ok(page);
}
/**
* 根据字典类型查询字典数据信息
* 换成用Enum
*/
@GetMapping(value = "/dict/{dictType}")
@Operation(summary = "字典数据", description = "获取字典列表")
@Parameter(name = "dictType", description = "字典对应类别")
public ResponseDTO<List<DictionaryData>> dictType(@PathVariable String dictType) {
List<DictionaryData> dictionaryData = MapCache.dictionaryCache().get(dictType);
return ResponseDTO.ok(dictionaryData);
}
/**
* 根据参数编号获取详细信息
*/
@PreAuthorize("@permission.has('system:config:query')")
@GetMapping(value = "/{configId}")
@GetMapping(value = "/config/{configId}")
@Operation(summary = "配置信息", description = "配置的详细信息")
public ResponseDTO<ConfigDTO> getInfo(@NotNull @Positive @PathVariable Long configId) {
ConfigDTO config = configApplicationService.getConfigInfo(configId);
@@ -86,8 +68,9 @@ public class SysConfigController extends BaseController {
@PreAuthorize("@permission.has('system:config:edit')")
@AccessLog(title = "参数管理", businessType = BusinessTypeEnum.MODIFY)
@Operation(summary = "配置修改", description = "配置修改")
@PutMapping
public ResponseDTO<Void> edit(@RequestBody ConfigUpdateCommand config) {
@PutMapping(value = "/config/{configId}")
public ResponseDTO<Void> edit(@NotNull @Positive @PathVariable Long configId, @RequestBody ConfigUpdateCommand config) {
config.setConfigId(configId);
configApplicationService.updateConfig(config);
return ResponseDTO.ok();
}
@@ -98,7 +81,7 @@ public class SysConfigController extends BaseController {
@Operation(summary = "刷新配置缓存")
@PreAuthorize("@permission.has('system:config:remove')")
@AccessLog(title = "参数管理", businessType = BusinessTypeEnum.CLEAN)
@DeleteMapping("/refreshCache")
@DeleteMapping("/configs/cache")
public ResponseDTO<Void> refreshCache() {
CacheCenter.configCache.invalidateAll();
return ResponseDTO.ok();

View File

@@ -8,8 +8,8 @@ import com.agileboot.domain.system.dept.command.AddDeptCommand;
import com.agileboot.domain.system.dept.command.UpdateDeptCommand;
import com.agileboot.domain.system.dept.dto.DeptDTO;
import com.agileboot.domain.system.dept.query.DeptQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -33,21 +33,20 @@ import org.springframework.web.bind.annotation.RestController;
* @author valarchie
*/
@RestController
@RequestMapping("/system/dept")
@RequestMapping("/system")
@Validated
@RequiredArgsConstructor
@Tag(name = "部门API", description = "部门相关的增删查改")
public class SysDeptController extends BaseController {
@NonNull
private DeptApplicationService deptApplicationService;
private final DeptApplicationService deptApplicationService;
/**
* 获取部门列表
*/
@Operation(summary = "部门列表")
@PreAuthorize("@permission.has('system:dept:list')")
@GetMapping("/list")
@GetMapping("/depts")
public ResponseDTO<List<DeptDTO>> list(DeptQuery query) {
List<DeptDTO> deptList = deptApplicationService.getDeptList(query);
return ResponseDTO.ok(deptList);
@@ -58,7 +57,7 @@ public class SysDeptController extends BaseController {
*/
@Operation(summary = "部门详情")
@PreAuthorize("@permission.has('system:dept:query')")
@GetMapping(value = "/{deptId}")
@GetMapping(value = "/dept/{deptId}")
public ResponseDTO<DeptDTO> getInfo(@PathVariable Long deptId) {
DeptDTO dept = deptApplicationService.getDeptInfo(deptId);
return ResponseDTO.ok(dept);
@@ -68,7 +67,7 @@ public class SysDeptController extends BaseController {
* 获取部门下拉树列表
*/
@Operation(summary = "获取部门树级结构")
@GetMapping("/dropdownList")
@GetMapping("/depts/dropdown")
public ResponseDTO<List<Tree<Long>>> dropdownList() {
List<Tree<Long>> deptTree = deptApplicationService.getDeptTree();
return ResponseDTO.ok(deptTree);
@@ -80,7 +79,7 @@ public class SysDeptController extends BaseController {
@Operation(summary = "新增部门")
@PreAuthorize("@permission.has('system:dept:add')")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.ADD)
@PostMapping
@PostMapping("/dept")
public ResponseDTO<Void> add(@RequestBody AddDeptCommand addCommand) {
deptApplicationService.addDept(addCommand);
return ResponseDTO.ok();
@@ -92,8 +91,9 @@ public class SysDeptController extends BaseController {
@Operation(summary = "修改部门")
@PreAuthorize("@permission.has('system:dept:edit') AND @dataScope.checkDeptId(#updateCommand.deptId)")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody UpdateDeptCommand updateCommand) {
@PutMapping("/dept/{deptId}")
public ResponseDTO<Void> edit(@PathVariable("deptId")Long deptId, @RequestBody UpdateDeptCommand updateCommand) {
updateCommand.setDeptId(deptId);
deptApplicationService.updateDept(updateCommand);
return ResponseDTO.ok();
}
@@ -104,7 +104,7 @@ public class SysDeptController extends BaseController {
@Operation(summary = "删除部门")
@PreAuthorize("@permission.has('system:dept:remove') AND @dataScope.checkDeptId(#deptId)")
@AccessLog(title = "部门管理", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{deptId}")
@DeleteMapping("/dept/{deptId}")
public ResponseDTO<Void> remove(@PathVariable @NotNull Long deptId) {
deptApplicationService.removeDept(deptId);
return ResponseDTO.ok();

View File

@@ -1,80 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.logininfo.LoginInfoApplicationService;
import com.agileboot.domain.system.logininfo.dto.LoginInfoDTO;
import com.agileboot.domain.system.logininfo.query.LoginInfoQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统访问记录
*
* @author valarchie
*/
@Tag(name = "登录日志API", description = "登录日志相关API")
@RestController
@RequestMapping("/loginInfo")
@Validated
@RequiredArgsConstructor
public class SysLoginInfoController extends BaseController {
@NonNull
private LoginInfoApplicationService loginInfoApplicationService;
@Operation(summary = "日志列表")
@PreAuthorize("@permission.has('monitor:logininfor:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<LoginInfoDTO>> list(LoginInfoQuery query) {
PageDTO<LoginInfoDTO> pageDTO = loginInfoApplicationService.getLoginInfoList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "日志列表导出", description = "将登录日志导出到excel")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:logininfor:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, LoginInfoQuery query) {
PageDTO<LoginInfoDTO> pageDTO = loginInfoApplicationService.getLoginInfoList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), LoginInfoDTO.class, response);
}
@Operation(summary = "删除登录日志")
@PreAuthorize("@permission.has('monitor:logininfor:remove')")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{infoIds}")
public ResponseDTO<Void> remove(@PathVariable @NotNull @NotEmpty List<Long> infoIds) {
loginInfoApplicationService.deleteLoginInfo(new BulkOperationCommand<>(infoIds));
return ResponseDTO.ok();
}
@Operation(summary = "清空登录日志", description = "暂时不支持")
@PreAuthorize("@permission.has('monitor:logininfor:remove')")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.CLEAN)
@DeleteMapping("/clean")
public ResponseDTO<Void> clean() {
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
}
}

View File

@@ -0,0 +1,120 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.log.LogApplicationService;
import com.agileboot.domain.system.log.dto.LoginLogDTO;
import com.agileboot.domain.system.log.query.LoginLogQuery;
import com.agileboot.domain.system.log.dto.OperationLogDTO;
import com.agileboot.domain.system.log.dto.OperationLogQuery;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统访问记录
*
* @author valarchie
*/
@Tag(name = "日志API", description = "日志相关API")
@RestController
@RequestMapping("/logs")
@Validated
@RequiredArgsConstructor
public class SysLogsController extends BaseController {
private final LogApplicationService logApplicationService;
@Operation(summary = "登录日志列表")
@PreAuthorize("@permission.has('monitor:logininfor:list')")
@GetMapping("/loginLogs")
public ResponseDTO<PageDTO<LoginLogDTO>> loginInfoList(LoginLogQuery query) {
PageDTO<LoginLogDTO> pageDTO = logApplicationService.getLoginInfoList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "登录日志导出", description = "将登录日志导出到excel")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:logininfor:export')")
@GetMapping("/loginLogs/excel")
public void loginInfosExcel(HttpServletResponse response, LoginLogQuery query) {
PageDTO<LoginLogDTO> pageDTO = logApplicationService.getLoginInfoList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), LoginLogDTO.class, response);
}
@Operation(summary = "删除登录日志")
@PreAuthorize("@permission.has('monitor:logininfor:remove')")
@AccessLog(title = "登录日志", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/loginLogs")
public ResponseDTO<Void> removeLoginInfos(@RequestParam @NotNull @NotEmpty List<Long> ids) {
logApplicationService.deleteLoginInfo(new BulkOperationCommand<>(ids));
return ResponseDTO.ok();
}
@Operation(summary = "操作日志列表")
@PreAuthorize("@permission.has('monitor:operlog:list')")
@GetMapping("/operationLogs")
public ResponseDTO<PageDTO<OperationLogDTO>> operationLogs(OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = logApplicationService.getOperationLogList(query);
return ResponseDTO.ok(pageDTO);
}
// @GetMapping("/download")
// public ResponseEntity<InputStreamResource> downloadFile() throws IOException {
// // 从文件系统或其他位置获取文件输入流
// File file = new File("path/to/file");
// InputStream inputStream = new FileInputStream(file);
// CustomExcelUtil.wri
//
// // 创建一个 InputStreamResource 对象,将文件输入流包装在其中
// InputStreamResource resource = new InputStreamResource(inputStream);
//
// // 返回 ResponseEntity 对象,其中包含 InputStreamResource 对象和文件名
// return ResponseEntity.ok()
// .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName())
// .contentType(MediaType.APPLICATION_OCTET_STREAM)
// .contentLength(file.length())
// .body(resource);
// }
/**
* 可否改成以上的形式 TODO
* @param response
* @param query
*/
@Operation(summary = "操作日志导出")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:operlog:export')")
@GetMapping("/operationLogs/excel")
public void operationLogsExcel(HttpServletResponse response, OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = logApplicationService.getOperationLogList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), OperationLogDTO.class, response);
}
@Operation(summary = "删除操作日志")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.DELETE)
@PreAuthorize("@permission.has('monitor:operlog:remove')")
@DeleteMapping("/operationLogs")
public ResponseDTO<Void> removeOperationLogs(@RequestParam List<Long> operationIds) {
logApplicationService.deleteOperationLog(new BulkOperationCommand<>(operationIds));
return ResponseDTO.ok();
}
}

View File

@@ -7,11 +7,12 @@ import com.agileboot.domain.system.menu.MenuApplicationService;
import com.agileboot.domain.system.menu.command.AddMenuCommand;
import com.agileboot.domain.system.menu.command.UpdateMenuCommand;
import com.agileboot.domain.system.menu.dto.MenuDTO;
import com.agileboot.domain.system.menu.dto.MenuDetailDTO;
import com.agileboot.domain.system.menu.query.MenuQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -37,22 +38,21 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Tag(name = "菜单API", description = "菜单相关的增删查改")
@RestController
@RequestMapping("/system/menu")
@RequestMapping("/system/menus")
@Validated
@RequiredArgsConstructor
public class SysMenuController extends BaseController {
@NonNull
MenuApplicationService menuApplicationService;
private final MenuApplicationService menuApplicationService;
/**
* 获取菜单列表
*/
@Operation(summary = "菜单列表")
@PreAuthorize("@permission.has('system:menu:list')")
@GetMapping("/list")
public ResponseDTO<List<MenuDTO>> list(MenuQuery query) {
List<MenuDTO> menuList = menuApplicationService.getMenuList(query);
@GetMapping
public ResponseDTO<List<MenuDTO>> menuList(MenuQuery menuQuery) {
List<MenuDTO> menuList = menuApplicationService.getMenuList(menuQuery);
return ResponseDTO.ok(menuList);
}
@@ -62,8 +62,8 @@ public class SysMenuController extends BaseController {
@Operation(summary = "菜单详情")
@PreAuthorize("@permission.has('system:menu:query')")
@GetMapping(value = "/{menuId}")
public ResponseDTO<MenuDTO> getInfo(@PathVariable @NotNull @PositiveOrZero Long menuId) {
MenuDTO menu = menuApplicationService.getMenuInfo(menuId);
public ResponseDTO<MenuDetailDTO> menuInfo(@PathVariable @NotNull @PositiveOrZero Long menuId) {
MenuDetailDTO menu = menuApplicationService.getMenuInfo(menuId);
return ResponseDTO.ok(menu);
}
@@ -71,15 +71,18 @@ public class SysMenuController extends BaseController {
* 获取菜单下拉树列表
*/
@Operation(summary = "菜单列表(树级)", description = "菜单树级下拉框")
@GetMapping("/dropdownList")
@GetMapping("/dropdown")
public ResponseDTO<List<Tree<Long>>> dropdownList() {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
List<Tree<Long>> dropdownList = menuApplicationService.getDropdownList(loginUser);
return ResponseDTO.ok(dropdownList);
}
/**
* 新增菜单
* 需支持一级菜单以及 多级菜单 子菜单为一个 或者 多个的情况
* 隐藏菜单不显示 以及rank排序
* 内链 和 外链
*/
@Operation(summary = "添加菜单")
@PreAuthorize("@permission.has('system:menu:add')")
@@ -96,8 +99,9 @@ public class SysMenuController extends BaseController {
@Operation(summary = "编辑菜单")
@PreAuthorize("@permission.has('system:menu:edit')")
@AccessLog(title = "菜单管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody UpdateMenuCommand updateCommand) {
@PutMapping("/{menuId}")
public ResponseDTO<Void> edit(@PathVariable("menuId") Long menuId, @RequestBody UpdateMenuCommand updateCommand) {
updateCommand.setMenuId(menuId);
menuApplicationService.updateMenu(updateCommand);
return ResponseDTO.ok();
}
@@ -114,5 +118,4 @@ public class SysMenuController extends BaseController {
return ResponseDTO.ok();
}
}

View File

@@ -9,9 +9,10 @@ import com.agileboot.domain.system.notice.command.NoticeAddCommand;
import com.agileboot.domain.system.notice.command.NoticeUpdateCommand;
import com.agileboot.domain.system.notice.dto.NoticeDTO;
import com.agileboot.domain.system.notice.query.NoticeQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.annotations.Unrepeatable;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.infrastructure.annotations.unrepeatable.Unrepeatable;
import com.agileboot.infrastructure.annotations.unrepeatable.Unrepeatable.CheckType;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import com.baomidou.dynamic.datasource.annotation.DS;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -29,6 +30,7 @@ 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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
@@ -38,20 +40,19 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Tag(name = "公告API", description = "公告相关的增删查改")
@RestController
@RequestMapping("/system/notice")
@RequestMapping("/system/notices")
@Validated
@RequiredArgsConstructor
public class SysNoticeController extends BaseController {
@NonNull
private NoticeApplicationService noticeApplicationService;
private final NoticeApplicationService noticeApplicationService;
/**
* 获取通知公告列表
*/
@Operation(summary = "公告列表")
@PreAuthorize("@permission.has('system:notice:list')")
@GetMapping("/list")
@GetMapping
public ResponseDTO<PageDTO<NoticeDTO>> list(NoticeQuery query) {
PageDTO<NoticeDTO> pageDTO = noticeApplicationService.getNoticeList(query);
return ResponseDTO.ok(pageDTO);
@@ -64,7 +65,7 @@ public class SysNoticeController extends BaseController {
@Operation(summary = "公告列表(从数据库从库获取)", description = "演示主从库的例子")
@DS("slave")
@PreAuthorize("@permission.has('system:notice:list')")
@GetMapping("/listFromSlave")
@GetMapping("/database/slave")
public ResponseDTO<PageDTO<NoticeDTO>> listFromSlave(NoticeQuery query) {
PageDTO<NoticeDTO> pageDTO = noticeApplicationService.getNoticeList(query);
return ResponseDTO.ok(pageDTO);
@@ -84,7 +85,7 @@ public class SysNoticeController extends BaseController {
* 新增通知公告
*/
@Operation(summary = "添加公告")
@Unrepeatable(interval = 60)
@Unrepeatable(interval = 60, checkType = CheckType.SYSTEM_USER)
@PreAuthorize("@permission.has('system:notice:add')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.ADD)
@PostMapping
@@ -99,8 +100,9 @@ public class SysNoticeController extends BaseController {
@Operation(summary = "修改公告")
@PreAuthorize("@permission.has('system:notice:edit')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> edit(@RequestBody NoticeUpdateCommand updateCommand) {
@PutMapping("/{noticeId}")
public ResponseDTO<Void> edit(@PathVariable Long noticeId, @RequestBody NoticeUpdateCommand updateCommand) {
updateCommand.setNoticeId(noticeId);
noticeApplicationService.updateNotice(updateCommand);
return ResponseDTO.ok();
}
@@ -111,8 +113,8 @@ public class SysNoticeController extends BaseController {
@Operation(summary = "删除公告")
@PreAuthorize("@permission.has('system:notice:remove')")
@AccessLog(title = "通知公告", businessType = BusinessTypeEnum.DELETE)
@DeleteMapping("/{noticeIds}")
public ResponseDTO<Void> remove(@PathVariable List<Integer> noticeIds) {
@DeleteMapping
public ResponseDTO<Void> remove(@RequestParam List<Integer> noticeIds) {
noticeApplicationService.deleteNotice(new BulkOperationCommand<>(noticeIds));
return ResponseDTO.ok();
}

View File

@@ -1,75 +0,0 @@
package com.agileboot.admin.controller.system;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.core.page.PageDTO;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.utils.poi.CustomExcelUtil;
import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.system.operationlog.OperationLogApplicationService;
import com.agileboot.domain.system.operationlog.dto.OperationLogDTO;
import com.agileboot.domain.system.operationlog.query.OperationLogQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 操作日志记录
*
* @author valarchie
*/
@Tag(name = "操作日志API", description = "操作日志相关接口")
@RestController
@RequestMapping("/operationLog")
@RequiredArgsConstructor
public class SysOperationLogController extends BaseController {
@NonNull
private OperationLogApplicationService operationLogApplicationService;
@Operation(summary = "操作日志列表")
@PreAuthorize("@permission.has('monitor:operlog:list')")
@GetMapping("/list")
public ResponseDTO<PageDTO<OperationLogDTO>> list(OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = operationLogApplicationService.getOperationLogList(query);
return ResponseDTO.ok(pageDTO);
}
@Operation(summary = "操作日志导出")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('monitor:operlog:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, OperationLogQuery query) {
PageDTO<OperationLogDTO> pageDTO = operationLogApplicationService.getOperationLogList(query);
CustomExcelUtil.writeToResponse(pageDTO.getRows(), OperationLogDTO.class, response);
}
@Operation(summary = "删除操作日志")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.DELETE)
@PreAuthorize("@permission.has('monitor:operlog:remove')")
@DeleteMapping("/{operationIds}")
public ResponseDTO<Void> remove(@PathVariable List<Long> operationIds) {
operationLogApplicationService.deleteOperationLog(new BulkOperationCommand<>(operationIds));
return ResponseDTO.ok();
}
@Operation(summary = "清空操作日志", description = "暂未支持")
@AccessLog(title = "操作日志", businessType = BusinessTypeEnum.CLEAN)
@PreAuthorize("@permission.has('monitor:operlog:remove')")
@DeleteMapping("/clean")
public ResponseDTO<Void> clean() {
return ResponseDTO.fail(ErrorCode.Business.UNSUPPORTED_OPERATION);
}
}

View File

@@ -10,8 +10,8 @@ import com.agileboot.domain.system.post.command.AddPostCommand;
import com.agileboot.domain.system.post.command.UpdatePostCommand;
import com.agileboot.domain.system.post.dto.PostDTO;
import com.agileboot.domain.system.post.query.PostQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -41,8 +41,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class SysPostController extends BaseController {
@NonNull
private PostApplicationService postApplicationService;
private final PostApplicationService postApplicationService;
/**
* 获取岗位列表

View File

@@ -12,10 +12,10 @@ import com.agileboot.domain.system.user.command.UpdateProfileCommand;
import com.agileboot.domain.system.user.command.UpdateUserAvatarCommand;
import com.agileboot.domain.system.user.command.UpdateUserPasswordCommand;
import com.agileboot.domain.system.user.dto.UserProfileDTO;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.NonNull;
@@ -40,8 +40,7 @@ import org.springframework.web.multipart.MultipartFile;
@RequiredArgsConstructor
public class SysProfileController extends BaseController {
@NonNull
private UserApplicationService userApplicationService;
private final UserApplicationService userApplicationService;
/**
* 个人信息
@@ -49,7 +48,7 @@ public class SysProfileController extends BaseController {
@Operation(summary = "获取个人信息")
@GetMapping
public ResponseDTO<UserProfileDTO> profile() {
LoginUser user = AuthenticationUtils.getLoginUser();
SystemLoginUser user = AuthenticationUtils.getSystemLoginUser();
UserProfileDTO userProfile = userApplicationService.getUserProfile(user.getUserId());
return ResponseDTO.ok(userProfile);
}
@@ -61,7 +60,7 @@ public class SysProfileController extends BaseController {
@AccessLog(title = "个人信息", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
public ResponseDTO<Void> updateProfile(@RequestBody UpdateProfileCommand command) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
command.setUserId(loginUser.getUserId());
userApplicationService.updateUserProfile(command);
return ResponseDTO.ok();
@@ -74,7 +73,7 @@ public class SysProfileController extends BaseController {
@AccessLog(title = "个人信息", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/password")
public ResponseDTO<Void> updatePassword(@RequestBody UpdateUserPasswordCommand command) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
command.setUserId(loginUser.getUserId());
userApplicationService.updatePasswordBySelf(loginUser, command);
return ResponseDTO.ok();
@@ -90,7 +89,7 @@ public class SysProfileController extends BaseController {
if (file.isEmpty()) {
throw new ApiException(ErrorCode.Business.USER_UPLOAD_FILE_FAILED);
}
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
String avatarUrl = FileUploadUtils.upload(UploadSubDir.AVATAR_PATH, file);
userApplicationService.updateUserAvatar(new UpdateUserAvatarCommand(loginUser.getUserId(), avatarUrl));

View File

@@ -14,8 +14,8 @@ import com.agileboot.domain.system.role.query.AllocatedRoleQuery;
import com.agileboot.domain.system.role.query.RoleQuery;
import com.agileboot.domain.system.role.query.UnallocatedRoleQuery;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -46,8 +46,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class SysRoleController extends BaseController {
@NonNull
private RoleApplicationService roleApplicationService;
private final RoleApplicationService roleApplicationService;
@Operation(summary = "角色列表")
@PreAuthorize("@permission.has('system:role:list')")

View File

@@ -14,11 +14,11 @@ import com.agileboot.domain.system.user.command.UpdateUserCommand;
import com.agileboot.domain.system.user.dto.UserDTO;
import com.agileboot.domain.system.user.dto.UserDetailDTO;
import com.agileboot.domain.system.user.query.SearchUserQuery;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.orm.system.result.SearchUserDO;
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import com.agileboot.domain.system.user.db.SearchUserDO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
@@ -39,25 +39,23 @@ import org.springframework.web.multipart.MultipartFile;
/**
* 用户信息
*
* @author ruoyi
* @author valarchie
*/
@Tag(name = "用户API", description = "用户相关的增删查改")
@RestController
@RequestMapping("/system/user")
@RequestMapping("/system/users")
@RequiredArgsConstructor
public class SysUserController extends BaseController {
@NonNull
private UserApplicationService userApplicationService;
private final UserApplicationService userApplicationService;
/**
* 获取用户列表
*/
@Operation(summary = "用户列表")
@PreAuthorize("@permission.has('system:user:list') AND @dataScope.checkDeptId(#query.deptId)")
@GetMapping("/list")
public ResponseDTO<PageDTO<UserDTO>> list(SearchUserQuery<SearchUserDO> query) {
@GetMapping
public ResponseDTO<PageDTO<UserDTO>> userList(SearchUserQuery<SearchUserDO> query) {
PageDTO<UserDTO> page = userApplicationService.getUserList(query);
return ResponseDTO.ok(page);
}
@@ -65,8 +63,8 @@ public class SysUserController extends BaseController {
@Operation(summary = "用户列表导出")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.EXPORT)
@PreAuthorize("@permission.has('system:user:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SearchUserQuery<SearchUserDO> query) {
@GetMapping("/excel")
public void exportUserByExcel(HttpServletResponse response, SearchUserQuery<SearchUserDO> query) {
PageDTO<UserDTO> userList = userApplicationService.getUserList(query);
CustomExcelUtil.writeToResponse(userList.getRows(), UserDTO.class, response);
}
@@ -74,8 +72,8 @@ public class SysUserController extends BaseController {
@Operation(summary = "用户列表导入")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.IMPORT)
@PreAuthorize("@permission.has('system:user:import')")
@PostMapping("/importData")
public ResponseDTO<Void> importData(MultipartFile file) {
@PostMapping("/excel")
public ResponseDTO<Void> importUserByExcel(MultipartFile file) {
List<AddUserCommand> commands = CustomExcelUtil.readFromRequest(AddUserCommand.class, file);
for (AddUserCommand command : commands) {
@@ -88,8 +86,8 @@ public class SysUserController extends BaseController {
* 下载批量导入模板
*/
@Operation(summary = "用户导入excel下载")
@PostMapping("/downloadTemplate")
public void downloadTemplate(HttpServletResponse response) {
@GetMapping("/excelTemplate")
public void downloadExcelTemplate(HttpServletResponse response) {
CustomExcelUtil.writeToResponse(ListUtil.toList(new AddUserCommand()), AddUserCommand.class, response);
}
@@ -98,7 +96,7 @@ public class SysUserController extends BaseController {
*/
@Operation(summary = "用户详情")
@PreAuthorize("@permission.has('system:user:query')")
@GetMapping(value = {"/", "/{userId}"})
@GetMapping("/{userId}")
public ResponseDTO<UserDetailDTO> getUserDetailInfo(@PathVariable(value = "userId", required = false) Long userId) {
UserDetailDTO userDetailInfo = userApplicationService.getUserDetailInfo(userId);
return ResponseDTO.ok(userDetailInfo);
@@ -122,7 +120,7 @@ public class SysUserController extends BaseController {
@Operation(summary = "修改用户")
@PreAuthorize("@permission.has('system:user:edit') AND @dataScope.checkUserId(#command.userId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping
@PutMapping("/{userId}")
public ResponseDTO<Void> edit(@Validated @RequestBody UpdateUserCommand command) {
userApplicationService.updateUser(command);
return ResponseDTO.ok();
@@ -137,7 +135,7 @@ public class SysUserController extends BaseController {
@DeleteMapping("/{userIds}")
public ResponseDTO<Void> remove(@PathVariable List<Long> userIds) {
BulkOperationCommand<Long> bulkDeleteCommand = new BulkOperationCommand<>(userIds);
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
userApplicationService.deleteUsers(loginUser, bulkDeleteCommand);
return ResponseDTO.ok();
}
@@ -148,7 +146,7 @@ public class SysUserController extends BaseController {
@Operation(summary = "重置用户密码")
@PreAuthorize("@permission.has('system:user:resetPwd') AND @dataScope.checkUserId(#userId)")
@AccessLog(title = "用户管理", businessType = BusinessTypeEnum.MODIFY)
@PutMapping("/{userId}/password/reset")
@PutMapping("/{userId}/password")
public ResponseDTO<Void> resetPassword(@PathVariable Long userId, @RequestBody ResetPasswordCommand command) {
command.setUserId(userId);
userApplicationService.resetUserPassword(command);

View File

@@ -1,46 +0,0 @@
package com.agileboot.admin.controller.tool;
import cn.hutool.core.net.URLEncodeUtil;
import cn.hutool.core.util.CharsetUtil;
import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.core.base.BaseController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* swagger 接口
* TODO Swagger这边权限拦截并没有生效需要改进
* PreAuthorize注解加在transfer接口上 获取不到登录用户 iframe请求header中没有token
* @author valarchie
*/
@Tag(name = "文档API", description = "角色相关接口")
@RestController
public class SwaggerController extends BaseController {
/**
* TODO 这个接口没有触发, 后续看如何改进, 应该把权限拦截放在下面的接口
*/
@Operation(summary = "文档首页")
@PreAuthorize("@permission.has('tool:swagger:view')")
@GetMapping("/tool/swagger")
public String index() {
return redirect("/doc.html");
}
/**
* 访问首页,提示语
*/
@Operation(summary = "文档接口数据")
@GetMapping("/v3/api-docs/{url}")
public void transfer(HttpServletResponse response, @PathVariable String url) throws IOException {
response.sendRedirect(AgileBootConfig.getApiDocsPathPrefix() + "/v3/api-docs/" + URLEncodeUtil.encode(url,
CharsetUtil.CHARSET_UTF_8));
}
}

View File

@@ -1,7 +1,7 @@
package com.agileboot.infrastructure.annotations;
package com.agileboot.admin.customize.aop.accessLog;
import com.agileboot.orm.common.enums.BusinessTypeEnum;
import com.agileboot.orm.common.enums.OperatorTypeEnum;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import com.agileboot.common.enums.common.OperatorTypeEnum;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,9 +1,7 @@
package com.agileboot.infrastructure.aspectj;
package com.agileboot.admin.customize.aop.accessLog;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.thread.AsyncTaskFactory;
import com.agileboot.admin.customize.async.AsyncTaskFactory;
import com.agileboot.infrastructure.thread.ThreadPoolManager;
import com.agileboot.infrastructure.web.domain.operationLog.OperationLogModel;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
@@ -53,9 +51,7 @@ public class AccessLogAspect {
// 保存数据库
ThreadPoolManager.execute(AsyncTaskFactory.recordOperationLog(operationLog));
} catch (Exception exp) {
// 记录本地异常日志
log.error("生成操作日志异常,异常信息:{}", exp.getMessage());
exp.printStackTrace();
log.error("写入操作日式失败", exp);
}
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.domain.operationLog;
package com.agileboot.admin.customize.aop.accessLog;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EnumUtil;
@@ -6,13 +6,12 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.infrastructure.annotations.AccessLog;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.OperationStatusEnum;
import com.agileboot.orm.common.enums.RequestMethodEnum;
import com.agileboot.orm.common.util.BasicEnumUtil;
import com.agileboot.orm.system.entity.SysOperationLogEntity;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.common.enums.common.OperationStatusEnum;
import com.agileboot.common.enums.common.RequestMethodEnum;
import com.agileboot.common.enums.BasicEnumUtil;
import com.agileboot.domain.system.log.db.SysOperationLogEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.springframework.validation.BindingResult;
@@ -38,7 +37,7 @@ public class OperationLogModel extends SysOperationLogEntity {
// 获取当前的用户
String ip = ServletUtil.getClientIP(request);
setOperatorIp(ip);
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
if (loginUser != null) {
this.setUsername(loginUser.getUsername());
}

View File

@@ -1,15 +1,15 @@
package com.agileboot.infrastructure.thread;
package com.agileboot.admin.customize.async;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.common.utils.ip.IpRegionUtil;
import com.agileboot.orm.common.enums.LoginStatusEnum;
import com.agileboot.orm.system.entity.SysLoginInfoEntity;
import com.agileboot.orm.system.entity.SysOperationLogEntity;
import com.agileboot.orm.system.service.ISysLoginInfoService;
import com.agileboot.orm.system.service.ISysOperationLogService;
import com.agileboot.common.enums.common.LoginStatusEnum;
import com.agileboot.domain.system.log.db.SysLoginInfoEntity;
import com.agileboot.domain.system.log.db.SysOperationLogEntity;
import com.agileboot.domain.system.log.db.SysLoginInfoService;
import com.agileboot.domain.system.log.db.SysOperationLogService;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
@@ -57,7 +57,7 @@ public class AsyncTaskFactory {
loginInfo.setLoginTime(DateUtil.date());
loginInfo.setStatus(loginStatusEnum.getValue());
// 插入数据
SpringUtil.getBean(ISysLoginInfoService.class).save(loginInfo);
SpringUtil.getBean(SysLoginInfoService.class).save(loginInfo);
};
}
@@ -71,7 +71,7 @@ public class AsyncTaskFactory {
return () -> {
// 远程查询操作地点
operationLog.setOperatorLocation(IpRegionUtil.getBriefLocationByIp(operationLog.getOperatorIp()));
SpringUtil.getBean(ISysOperationLogService.class).save(operationLog);
SpringUtil.getBean(SysOperationLogService.class).save(operationLog);
};
}

View File

@@ -1,8 +1,8 @@
package com.agileboot.infrastructure.filter;
package com.agileboot.admin.customize.config;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.service.TokenService;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.login.TokenService;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -27,13 +27,12 @@ import org.springframework.web.filter.OncePerRequestFilter;
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@NonNull
private TokenService tokenService;
private final TokenService tokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
LoginUser loginUser = tokenService.getLoginUser(request);
SystemLoginUser loginUser = tokenService.getLoginUser(request);
if (loginUser != null && AuthenticationUtils.getAuthentication() == null) {
tokenService.refreshToken(loginUser);
// 如果没有将当前登录用户放入到上下文中的话会认定用户未授权返回用户未登陆的错误
@@ -45,7 +44,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
}
private void putCurrentLoginUserIntoContext(HttpServletRequest request, LoginUser loginUser) {
private void putCurrentLoginUserIntoContext(HttpServletRequest request, SystemLoginUser loginUser) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(loginUser,
null, loginUser.getAuthorities());
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

View File

@@ -1,17 +1,17 @@
package com.agileboot.infrastructure.config;
package com.agileboot.admin.customize.config;
import cn.hutool.json.JSONUtil;
import com.agileboot.admin.customize.service.login.LoginService;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Client;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
import com.agileboot.infrastructure.filter.JwtAuthenticationTokenFilter;
import com.agileboot.infrastructure.thread.AsyncTaskFactory;
import com.agileboot.domain.common.cache.RedisCacheService;
import com.agileboot.admin.customize.async.AsyncTaskFactory;
import com.agileboot.infrastructure.thread.ThreadPoolManager;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.service.TokenService;
import com.agileboot.infrastructure.web.service.UserDetailsServiceImpl;
import com.agileboot.orm.common.enums.LoginStatusEnum;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.login.TokenService;
import com.agileboot.common.enums.common.LoginStatusEnum;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
@@ -38,7 +38,7 @@ import org.springframework.web.filter.CorsFilter;
* @see this#unauthorizedHandler() 用于用户未授权或登录失败处理
* @see this#logOutSuccessHandler 用于退出登录成功后的逻辑
* @see JwtAuthenticationTokenFilter#doFilter token的校验和刷新
* @see com.agileboot.infrastructure.web.service.LoginService#login 登录逻辑
* @see LoginService#login 登录逻辑
* @author valarchie
*/
@Configuration
@@ -47,26 +47,21 @@ import org.springframework.web.filter.CorsFilter;
@RequiredArgsConstructor
public class SecurityConfig {
@NonNull
private TokenService tokenService;
private final TokenService tokenService;
@NonNull
private RedisCacheService redisCache;
private final RedisCacheService redisCache;
/**
* token认证过滤器
*/
@NonNull
private JwtAuthenticationTokenFilter jwtTokenFilter;
private final JwtAuthenticationTokenFilter jwtTokenFilter;
@NonNull
private UserDetailsService userDetailsService;
private final UserDetailsService userDetailsService;
/**
* 跨域过滤器
*/
@NonNull
private CorsFilter corsFilter;
private final CorsFilter corsFilter;
/**
@@ -76,7 +71,9 @@ public class SecurityConfig {
@Bean
public AuthenticationEntryPoint unauthorizedHandler() {
return (request, response, exception) -> {
ResponseDTO<Object> responseDTO = ResponseDTO.fail(Client.COMMON_NO_AUTHORIZATION, request.getRequestURI());
ResponseDTO<Object> responseDTO = ResponseDTO.fail(
new ApiException(Client.COMMON_NO_AUTHORIZATION, request.getRequestURI())
);
ServletHolderUtil.renderString(response, JSONUtil.toJsonStr(responseDTO));
};
}
@@ -89,7 +86,7 @@ public class SecurityConfig {
@Bean
public LogoutSuccessHandler logOutSuccessHandler() {
return (request, response, authentication) -> {
LoginUser loginUser = tokenService.getLoginUser(request);
SystemLoginUser loginUser = tokenService.getLoginUser(request);
if (loginUser != null) {
String userName = loginUser.getUsername();
// 删除用户缓存记录
@@ -137,14 +134,16 @@ public class SecurityConfig {
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 以及公共Api的请求允许匿名访问
.antMatchers("/login", "/register", "/captchaImage","/api/**").anonymous()
// 注意 当携带token请求以下这几个接口时 会返回403的错误
.antMatchers("/login", "/register", "/getConfig", "/captchaImage", "/api/**").anonymous()
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js",
"/profile/**").permitAll()
// TODO this is danger.
.antMatchers("/swagger-ui.html").anonymous()
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/**/api-docs/**" ).anonymous()
.antMatchers("/*/api-docs","/*/api-docs/swagger-config").anonymous()
.antMatchers("/**/api-docs.yaml" ).anonymous()
.antMatchers("/druid/**").anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.service;
package com.agileboot.admin.customize.service.login;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.convert.Convert;
@@ -14,18 +14,21 @@ import com.agileboot.common.config.AgileBootConfig;
import com.agileboot.common.constant.Constants.Captcha;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCode.Business;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.common.utils.i18n.MessageUtils;
import com.agileboot.infrastructure.cache.guava.GuavaCacheService;
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
import com.agileboot.infrastructure.thread.AsyncTaskFactory;
import com.agileboot.domain.common.cache.GuavaCacheService;
import com.agileboot.domain.common.cache.MapCache;
import com.agileboot.domain.common.cache.RedisCacheService;
import com.agileboot.admin.customize.async.AsyncTaskFactory;
import com.agileboot.infrastructure.thread.ThreadPoolManager;
import com.agileboot.infrastructure.web.domain.login.CaptchaDTO;
import com.agileboot.infrastructure.web.domain.login.LoginDTO;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.orm.common.enums.ConfigKeyEnum;
import com.agileboot.orm.common.enums.LoginStatusEnum;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.admin.customize.service.login.dto.CaptchaDTO;
import com.agileboot.admin.customize.service.login.dto.ConfigDTO;
import com.agileboot.admin.customize.service.login.command.LoginCommand;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.common.enums.common.ConfigKeyEnum;
import com.agileboot.common.enums.common.LoginStatusEnum;
import com.agileboot.domain.system.user.db.SysUserEntity;
import com.google.code.kaptcha.Producer;
import java.awt.image.BufferedImage;
import javax.annotation.Resource;
@@ -36,6 +39,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
@@ -50,17 +54,13 @@ import org.springframework.util.FastByteArrayOutputStream;
@RequiredArgsConstructor
public class LoginService {
@NonNull
private TokenService tokenService;
private final TokenService tokenService;
@NonNull
private RedisCacheService redisCache;
private final RedisCacheService redisCache;
@NonNull
private GuavaCacheService guavaCache;
private final GuavaCacheService guavaCache;
@NonNull
private AuthenticationManager authenticationManager;
private final AuthenticationManager authenticationManager;
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@@ -71,35 +71,36 @@ public class LoginService {
/**
* 登录验证
*
* @param loginDTO 登录参数
* @param loginCommand 登录参数
* @return 结果
*/
public String login(LoginDTO loginDTO) {
public String login(LoginCommand loginCommand) {
// 验证码开关
if (isCaptchaOn()) {
validateCaptcha(loginDTO.getUsername(), loginDTO.getCode(), loginDTO.getUuid());
validateCaptcha(loginCommand.getUsername(), loginCommand.getCaptchaCode(), loginCommand.getCaptchaCodeKey());
}
// 用户验证
Authentication authentication;
String decryptPassword = decryptPassword(loginDTO.getPassword());
String decryptPassword = decryptPassword(loginCommand.getPassword());
try {
// 该方法会去调用UserDetailsServiceImpl#loadUserByUsername 校验用户名和密码 认证鉴权
authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
loginDTO.getUsername(), decryptPassword));
loginCommand.getUsername(), decryptPassword));
} catch (BadCredentialsException e) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginCommand.getUsername(), LoginStatusEnum.LOGIN_FAIL,
MessageUtils.message("Business.LOGIN_WRONG_USER_PASSWORD")));
throw new ApiException(e, ErrorCode.Business.LOGIN_WRONG_USER_PASSWORD);
} catch (AuthenticationException e) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginCommand.getUsername(), LoginStatusEnum.LOGIN_FAIL, e.getMessage()));
throw new ApiException(e, ErrorCode.Business.LOGIN_ERROR, e.getMessage());
} catch (Exception e) {
if (e instanceof BadCredentialsException) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginDTO.getUsername(), LoginStatusEnum.LOGIN_FAIL,
MessageUtils.message("user.password.not.match")));
throw new ApiException(ErrorCode.Business.LOGIN_WRONG_USER_PASSWORD);
} else {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginDTO.getUsername(), LoginStatusEnum.LOGIN_FAIL, e.getMessage()));
throw new ApiException(e.getCause(), ErrorCode.Business.LOGIN_ERROR, e.getMessage());
}
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginCommand.getUsername(), LoginStatusEnum.LOGIN_FAIL, e.getMessage()));
throw new ApiException(e, Business.LOGIN_ERROR, e.getMessage());
}
// 把当前登录用户 放入上下文中
SecurityContextHolder.getContext().setAuthentication(authentication);
// 这里获取的loginUser是UserDetailsServiceImpl#loadUserByUsername方法返回的LoginUser
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
SystemLoginUser loginUser = (SystemLoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser);
// 生成token
return tokenService.createTokenAndPutUserInCache(loginUser);
@@ -107,7 +108,22 @@ public class LoginService {
/**
* 获取验证码 data
* @return
*
* @return {@link ConfigDTO}
*/
public ConfigDTO getConfig() {
ConfigDTO configDTO = new ConfigDTO();
boolean isCaptchaOn = isCaptchaOn();
configDTO.setIsCaptchaOn(isCaptchaOn);
configDTO.setDictionary(MapCache.dictionaryCache());
return configDTO;
}
/**
* 获取验证码 data
*
* @return 验证码
*/
public CaptchaDTO generateCaptchaImg() {
CaptchaDTO captchaDTO = new CaptchaDTO();
@@ -116,7 +132,8 @@ public class LoginService {
captchaDTO.setIsCaptchaOn(isCaptchaOn);
if (isCaptchaOn) {
String expression, answer = null;
String expression;
String answer = null;
BufferedImage image = null;
// 生成验证码
@@ -139,15 +156,15 @@ public class LoginService {
}
// 保存验证码信息
String uuid = IdUtil.simpleUUID();
String imgKey = IdUtil.simpleUUID();
redisCache.captchaCache.set(uuid, answer);
redisCache.captchaCache.set(imgKey, answer);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
ImgUtil.writeJpg(image, os);
captchaDTO.setUuid(uuid);
captchaDTO.setImg(Base64.encode(os.toByteArray()));
captchaDTO.setCaptchaCodeKey(imgKey);
captchaDTO.setCaptchaCodeImg(Base64.encode(os.toByteArray()));
}
@@ -159,18 +176,18 @@ public class LoginService {
* 校验验证码
*
* @param username 用户名
* @param code 验证码
* @param uuid 唯一标识
* @param captchaCode 验证码
* @param captchaCodeKey 验证码对应的缓存key
*/
public void validateCaptcha(String username, String code, String uuid) {
String captcha = redisCache.captchaCache.getObjectById(uuid);
redisCache.captchaCache.delete(uuid);
public void validateCaptcha(String username, String captchaCode, String captchaCodeKey) {
String captcha = redisCache.captchaCache.getObjectById(captchaCodeKey);
redisCache.captchaCache.delete(captchaCodeKey);
if (captcha == null) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(username, LoginStatusEnum.LOGIN_FAIL,
ErrorCode.Business.LOGIN_CAPTCHA_CODE_EXPIRE.message()));
throw new ApiException(ErrorCode.Business.LOGIN_CAPTCHA_CODE_EXPIRE);
}
if (!code.equalsIgnoreCase(captcha)) {
if (!captchaCode.equalsIgnoreCase(captcha)) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(username, LoginStatusEnum.LOGIN_FAIL,
ErrorCode.Business.LOGIN_CAPTCHA_CODE_WRONG.message()));
throw new ApiException(ErrorCode.Business.LOGIN_CAPTCHA_CODE_WRONG);
@@ -179,9 +196,9 @@ public class LoginService {
/**
* 记录登录信息
* @param loginUser
* @param loginUser 登录用户
*/
public void recordLoginInfo(LoginUser loginUser) {
public void recordLoginInfo(SystemLoginUser loginUser) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginUser.getUsername(), LoginStatusEnum.LOGIN_SUCCESS,
LoginStatusEnum.LOGIN_SUCCESS.description()));

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.service;
package com.agileboot.admin.customize.service.login;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
@@ -6,8 +6,8 @@ import cn.hutool.core.util.StrUtil;
import com.agileboot.common.constant.Constants.Token;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.domain.common.cache.RedisCacheService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
@@ -55,15 +55,14 @@ public class TokenService {
@Value("${token.autoRefreshTime}")
private long autoRefreshTime;
@NonNull
private RedisCacheService redisCache;
private final RedisCacheService redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public LoginUser getLoginUser(HttpServletRequest request) {
public SystemLoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getTokenFromRequest(request);
if (StrUtil.isNotEmpty(token)) {
@@ -74,11 +73,11 @@ public class TokenService {
return redisCache.loginUserCache.getObjectOnlyInCacheById(uuid);
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) {
log.error("parse token failed. due to:{}", jwtException.getMessage());
throw new ApiException(jwtException, ErrorCode.Internal.INVALID_TOKEN);
log.error("parse token failed.", jwtException);
throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN);
} catch (Exception e) {
log.error("fail to get cached user from redis", e);
throw new ApiException(e, ErrorCode.UNKNOWN_ERROR);
throw new ApiException(e, ErrorCode.Client.TOKEN_PROCESS_FAILED, e.getMessage());
}
}
@@ -91,7 +90,7 @@ public class TokenService {
* @param loginUser 用户信息
* @return 令牌
*/
public String createTokenAndPutUserInCache(LoginUser loginUser) {
public String createTokenAndPutUserInCache(SystemLoginUser loginUser) {
loginUser.setCachedKey(IdUtil.fastUUID());
redisCache.loginUserCache.set(loginUser.getCachedKey(), loginUser);
@@ -103,7 +102,7 @@ public class TokenService {
* 当超过20分钟自动刷新token
* @param loginUser 登录用户
*/
public void refreshToken(LoginUser loginUser) {
public void refreshToken(SystemLoginUser loginUser) {
long currentTime = System.currentTimeMillis();
if (currentTime > loginUser.getAutoRefreshCacheTime()) {
loginUser.setAutoRefreshCacheTime(currentTime + TimeUnit.MINUTES.toMillis(autoRefreshTime));
@@ -156,8 +155,8 @@ public class TokenService {
*/
private String getTokenFromRequest(HttpServletRequest request) {
String token = request.getHeader(header);
if (StrUtil.isNotEmpty(token) && token.startsWith(Token.TOKEN_PREFIX)) {
token = StrUtil.stripIgnoreCase(token, Token.TOKEN_PREFIX, null);
if (StrUtil.isNotEmpty(token) && token.startsWith(Token.PREFIX)) {
token = StrUtil.stripIgnoreCase(token, Token.PREFIX, null);
}
return token;
}

View File

@@ -1,20 +1,20 @@
package com.agileboot.infrastructure.web.service;
package com.agileboot.admin.customize.service.login;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.orm.common.enums.DataScopeEnum;
import com.agileboot.orm.common.enums.UserStatusEnum;
import com.agileboot.orm.common.util.BasicEnumUtil;
import com.agileboot.orm.system.entity.SysMenuEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysMenuService;
import com.agileboot.orm.system.service.ISysRoleService;
import com.agileboot.orm.system.service.ISysUserService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.user.web.RoleInfo;
import com.agileboot.infrastructure.user.web.DataScopeEnum;
import com.agileboot.common.enums.common.UserStatusEnum;
import com.agileboot.common.enums.BasicEnumUtil;
import com.agileboot.domain.system.menu.db.SysMenuEntity;
import com.agileboot.domain.system.role.db.SysRoleEntity;
import com.agileboot.domain.system.user.db.SysUserEntity;
import com.agileboot.domain.system.menu.db.SysMenuService;
import com.agileboot.domain.system.role.db.SysRoleService;
import com.agileboot.domain.system.user.db.SysUserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List;
@@ -35,6 +35,7 @@ import org.springframework.stereotype.Service;
/**
* 自定义加载用户信息通过用户名
* 用于SpringSecurity 登录流程
* 没有办法把这个类 放进loginService中 会在SecurityConfig中造成循环依赖
* @see com.agileboot.infrastructure.config.SecurityConfig#filterChain(HttpSecurity)
* @author valarchie
*/
@@ -43,17 +44,13 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
@NonNull
private ISysUserService userService;
private final SysUserService userService;
@NonNull
private ISysMenuService menuService;
private final SysMenuService menuService;
@NonNull
private ISysRoleService roleService;
private final SysRoleService roleService;
@NonNull
private TokenService tokenService;
private final TokenService tokenService;
@Override
@@ -67,20 +64,23 @@ public class UserDetailsServiceImpl implements UserDetailsService {
log.info("登录用户:{} 已被停用.", username);
throw new ApiException(ErrorCode.Business.USER_IS_DISABLE, username);
}
LoginUser loginUser = new LoginUser(userEntity.getUserId(), userEntity.getIsAdmin(), userEntity.getUsername(),
userEntity.getPassword());
loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setAutoRefreshCacheTime(loginUser.getLoginTime() + TimeUnit.MINUTES.toMillis(tokenService.getAutoRefreshTime()));
loginUser.fillUserAgent();
RoleInfo roleInfo = getRoleInfo(userEntity.getRoleId(), userEntity.getIsAdmin());
SystemLoginUser loginUser = new SystemLoginUser(userEntity.getUserId(), userEntity.getIsAdmin(), userEntity.getUsername(),
userEntity.getPassword(), roleInfo, userEntity.getDeptId());
loginUser.fillLoginInfo();
loginUser.setAutoRefreshCacheTime(loginUser.getLoginInfo().getLoginTime()
+ TimeUnit.MINUTES.toMillis(tokenService.getAutoRefreshTime()));
return loginUser;
}
public RoleInfo getRoleInfo(Long roleId) {
public RoleInfo getRoleInfo(Long roleId, boolean isAdmin) {
if (roleId == null) {
return RoleInfo.EMPTY_ROLE;
}
if (roleId == RoleInfo.ADMIN_ROLE_ID) {
if (isAdmin) {
LambdaQueryWrapper<SysMenuEntity> menuQuery = Wrappers.lambdaQuery();
menuQuery.select(SysMenuEntity::getMenuId);
List<SysMenuEntity> allMenus = menuService.list(menuQuery);
@@ -101,7 +101,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
List<SysMenuEntity> menuList = roleService.getMenuListByRoleId(roleId);
Set<Long> menuIds = menuList.stream().map(SysMenuEntity::getMenuId).collect(Collectors.toSet());
Set<String> permissions = menuList.stream().map(SysMenuEntity::getPerms).collect(Collectors.toSet());
Set<String> permissions = menuList.stream().map(SysMenuEntity::getPermission).collect(Collectors.toSet());
DataScopeEnum dataScopeEnum = BasicEnumUtil.fromValue(DataScopeEnum.class, roleEntity.getDataScope());
@@ -115,5 +115,4 @@ public class UserDetailsServiceImpl implements UserDetailsService {
}
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.domain.login;
package com.agileboot.admin.customize.service.login.command;
import lombok.Data;
@@ -8,7 +8,7 @@ import lombok.Data;
* @author valarchie
*/
@Data
public class LoginDTO {
public class LoginCommand {
/**
* 用户名
@@ -23,11 +23,11 @@ public class LoginDTO {
/**
* 验证码
*/
private String code;
private String captchaCode;
/**
* 唯一标识
*/
private String uuid;
private String captchaCodeKey;
}

View File

@@ -0,0 +1,15 @@
package com.agileboot.admin.customize.service.login.dto;
import lombok.Data;
/**
* @author valarchie
*/
@Data
public class CaptchaDTO {
private Boolean isCaptchaOn;
private String captchaCodeKey;
private String captchaCodeImg;
}

View File

@@ -0,0 +1,18 @@
package com.agileboot.admin.customize.service.login.dto;
import com.agileboot.common.enums.dictionary.DictionaryData;
import java.util.List;
import java.util.Map;
import lombok.Data;
/**
* @author valarchie
*/
@Data
public class ConfigDTO {
private Boolean isCaptchaOn;
private Map<String, List<DictionaryData>> dictionary;
}

View File

@@ -1,15 +1,16 @@
package com.agileboot.infrastructure.web.domain.permission;
package com.agileboot.admin.customize.service.permission;
import cn.hutool.extra.spring.SpringUtil;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.checker.AllDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.checker.CustomDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.checker.DefaultDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.checker.DeptTreeDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.checker.OnlySelfDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.checker.SingleDeptDataPermissionChecker;
import com.agileboot.orm.common.enums.DataScopeEnum;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.checker.AllDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.checker.CustomDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.checker.DefaultDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.checker.DeptTreeDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.checker.OnlySelfDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.checker.SingleDeptDataPermissionChecker;
import com.agileboot.infrastructure.user.web.DataScopeEnum;
import com.agileboot.domain.system.dept.db.SysDeptService;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
@@ -29,7 +30,7 @@ public class DataPermissionCheckerFactory {
@PostConstruct
public void initAllChecker() {
ISysDeptService deptService = SpringUtil.getBean(ISysDeptService.class);
SysDeptService deptService = SpringUtil.getBean(SysDeptService.class);
allChecker = new AllDataPermissionChecker();
customChecker = new CustomDataPermissionChecker(deptService);
@@ -40,7 +41,7 @@ public class DataPermissionCheckerFactory {
}
public static AbstractDataPermissionChecker getChecker(LoginUser loginUser) {
public static AbstractDataPermissionChecker getChecker(SystemLoginUser loginUser) {
if (loginUser == null) {
return deptTreeChecker;
}

View File

@@ -1,13 +1,12 @@
package com.agileboot.infrastructure.web.service;
package com.agileboot.admin.customize.service.permission;
import cn.hutool.core.collection.CollUtil;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.infrastructure.web.domain.permission.DataPermissionCheckerFactory;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.orm.system.service.ISysUserService;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.domain.system.user.db.SysUserEntity;
import com.agileboot.domain.system.user.db.SysUserService;
import java.util.List;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@@ -21,16 +20,16 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class DataPermissionService {
@NonNull
private ISysUserService userService;
private final SysUserService userService;
/**
* 通过userId 校验当前用户 目标用户是否有操作权限
* @param userId
*
* @param userId 用户id
* @return 检验结果
*/
public boolean checkUserId(Long userId) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
SysUserEntity targetUser = userService.getById(userId);
if (targetUser == null) {
return true;
@@ -40,8 +39,8 @@ public class DataPermissionService {
/**
* 通过userId 校验当前用户 目标用户是否有操作权限
* @param userIds
* @return
* @param userIds 用户id列表
* @return 校验结果
*/
public boolean checkUserIds(List<Long> userIds) {
if (CollUtil.isNotEmpty(userIds)) {
@@ -56,12 +55,12 @@ public class DataPermissionService {
}
public boolean checkDeptId(Long deptId) {
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
return checkDataScope(loginUser, deptId, null);
}
public boolean checkDataScope(LoginUser loginUser, Long targetDeptId, Long targetUserId) {
public boolean checkDataScope(SystemLoginUser loginUser, Long targetDeptId, Long targetUserId) {
DataCondition dataCondition = DataCondition.builder().targetDeptId(targetDeptId).targetUserId(targetUserId).build();
AbstractDataPermissionChecker checker = DataPermissionCheckerFactory.getChecker(loginUser);
return checker.check(loginUser, dataCondition);

View File

@@ -1,10 +1,10 @@
package com.agileboot.infrastructure.web.service;
package com.agileboot.admin.customize.service.permission;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.agileboot.infrastructure.security.AuthenticationUtils;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.user.AuthenticationUtils;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.user.web.RoleInfo;
import java.util.Set;
import org.springframework.stereotype.Service;
@@ -26,7 +26,7 @@ public class MenuPermissionService {
if (StrUtil.isEmpty(permission)) {
return false;
}
LoginUser loginUser = AuthenticationUtils.getLoginUser();
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
if (loginUser == null || CollUtil.isEmpty(loginUser.getRoleInfo().getMenuPermissions())) {
return false;
}

View File

@@ -0,0 +1,25 @@
package com.agileboot.admin.customize.service.permission.model;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.domain.system.dept.db.SysDeptService;
import lombok.Data;
/**
* 数据权限测试接口
* @author valarchie
*/
@Data
public abstract class AbstractDataPermissionChecker {
private SysDeptService deptService;
/**
* 检测当前用户对于 给定条件的数据 是否有权限
*
* @param loginUser 登录用户
* @param condition 条件
* @return 校验结果
*/
public abstract boolean check(SystemLoginUser loginUser, DataCondition condition);
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.domain.permission;
package com.agileboot.admin.customize.service.permission.model;
import lombok.AllArgsConstructor;
import lombok.Builder;

View File

@@ -0,0 +1,25 @@
package com.agileboot.admin.customize.service.permission.model.checker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class AllDataPermissionChecker extends AbstractDataPermissionChecker {
private SysDeptService deptService;
@Override
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
return true;
}
}

View File

@@ -1,29 +1,31 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission.model.checker;
import cn.hutool.core.collection.CollUtil;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomDataPermissionChecker extends AbstractDataPermissionChecker {
private ISysDeptService deptService;
private SysDeptService deptService;
@Override
public boolean check(LoginUser loginUser, DataCondition condition) {
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
if (condition == null || loginUser == null) {
return false;
}

View File

@@ -0,0 +1,25 @@
package com.agileboot.admin.customize.service.permission.model.checker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class DefaultDataPermissionChecker extends AbstractDataPermissionChecker {
private SysDeptService deptService;
@Override
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
return false;
}
}

View File

@@ -1,27 +1,29 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission.model.checker;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeptTreeDataPermissionChecker extends AbstractDataPermissionChecker {
private ISysDeptService deptService;
private SysDeptService deptService;
@Override
public boolean check(LoginUser loginUser, DataCondition condition) {
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
if (condition == null || loginUser == null) {
return false;
}

View File

@@ -1,27 +1,29 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission.model.checker;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OnlySelfDataPermissionChecker extends AbstractDataPermissionChecker {
private ISysDeptService deptService;
private SysDeptService deptService;
@Override
public boolean check(LoginUser loginUser, DataCondition condition) {
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
if (condition == null || loginUser == null) {
return false;
}

View File

@@ -1,27 +1,29 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission.model.checker;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.AbstractDataPermissionChecker;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.AbstractDataPermissionChecker;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* 数据权限测试接口
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SingleDeptDataPermissionChecker extends AbstractDataPermissionChecker {
private ISysDeptService deptService;
private SysDeptService deptService;
@Override
public boolean check(LoginUser loginUser, DataCondition condition) {
public boolean check(SystemLoginUser loginUser, DataCondition condition) {
if (condition == null || loginUser == null) {
return false;
}

View File

@@ -50,7 +50,7 @@ spring:
datasource:
# 主库数据源
master:
url: jdbc:mysql://localhost:33067/agileboot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://localhost:33067/agileboot-pure?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: 12345
# 从库数据源
@@ -88,13 +88,18 @@ logging:
springdoc:
api-docs:
path: ${agileboot.api-docs-path-prefix}/v3/api-docs
swagger-ui:
# ***注意*** 开启Swagger UI界面 **安全考虑的话生产环境需要关掉**
# 因为knife4j的一些配置不灵活 所以重新改回springdoc+swagger的组合 真实开发的时候 使用apifox这种工具效率更高
enabled: true
url: ${agileboot.api-prefix}/v3/api-docs
config-url: ${agileboot.api-prefix}/v3/api-docs/swagger-config
# 项目相关配置
agileboot:
# 文件基路径 示例( Windows配置D:\agilebootLinux配置 /home/agileboot
file-base-dir: D:\agileboot
# 因为knife4j不能给configUrl 配置前缀, 所以只能自己配置一个,然后通过转发来实现
api-docs-path-prefix: /dev-api
# 前端url请求转发前缀
api-prefix: /dev-api
demo-enabled: false

View File

@@ -38,12 +38,9 @@ springdoc:
groups:
enabled: true
group-configs:
- group: '公共管理API'
- group: '公共API'
packages-to-scan: com.agileboot.admin.controller.common
- group: '监控管理API'
packages-to-scan: com.agileboot.admin.controller.monitor
- group: '系统管理API'
- group: '内置系统API'
packages-to-scan: com.agileboot.admin.controller.system
- group: '工具管理API'
packages-to-scan: com.agileboot.admin.controller.tool

View File

@@ -1,22 +1,23 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.admin.customize.service.permission.model.checker.CustomDataPermissionChecker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.user.web.RoleInfo;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import org.apache.commons.collections4.SetUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class CustomDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
private final SysDeptService deptService = mock(SysDeptService.class);
public SystemLoginUser loginUser = mock(SystemLoginUser.class);
@BeforeEach
public void mockBefore() {

View File

@@ -1,4 +1,4 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -6,19 +6,19 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.admin.customize.service.permission.model.checker.DeptTreeDataPermissionChecker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.user.web.RoleInfo;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
class DeptTreeDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
private final SysDeptService deptService = mock(SysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
public SystemLoginUser loginUser = mock(SystemLoginUser.class);
@BeforeEach
public void mockBefore() {
@@ -30,7 +30,7 @@ class DeptTreeDataPermissionCheckerTest {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
boolean check1 = checker.check(null, null);
boolean check2 = checker.check(new LoginUser(), null);
boolean check2 = checker.check(new SystemLoginUser(), null);
boolean check3 = checker.check(null, new DataCondition());
boolean check4 = checker.check(loginUser, new DataCondition());
@@ -61,7 +61,7 @@ class DeptTreeDataPermissionCheckerTest {
void testCheckWhenIsSameDept() {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
Mockito.when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(1L);
@@ -76,7 +76,7 @@ class DeptTreeDataPermissionCheckerTest {
void testCheckWhenFailed() {
DeptTreeDataPermissionChecker checker = new DeptTreeDataPermissionChecker(deptService);
Mockito.when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
when(deptService.isChildOfTheDept(any(), any())).thenReturn(false);
when(loginUser.getDeptId()).thenReturn(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(2L);

View File

@@ -1,26 +1,27 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.admin.customize.service.permission.model.checker.OnlySelfDataPermissionChecker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import org.junit.jupiter.api.Test;
class OnlySelfDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
private final SysDeptService deptService = mock(SysDeptService.class);
@Test
void testCheckWhenParameterNull() {
OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService);
boolean check1 = checker.check(null, null);
boolean check2 = checker.check(new LoginUser(), null);
boolean check2 = checker.check(new SystemLoginUser(), null);
boolean check3 = checker.check(null, new DataCondition());
boolean check4 = checker.check(new LoginUser(), new DataCondition());
boolean check4 = checker.check(new SystemLoginUser(), new DataCondition());
assertFalse(check1);
assertFalse(check2);
@@ -31,7 +32,7 @@ class OnlySelfDataPermissionCheckerTest {
@Test
void testCheckWhenSameUserId() {
OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
SystemLoginUser loginUser = new SystemLoginUser();
loginUser.setUserId(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetUserId(1L);
@@ -45,7 +46,7 @@ class OnlySelfDataPermissionCheckerTest {
@Test
void testCheckWhenDifferentUserId() {
OnlySelfDataPermissionChecker checker = new OnlySelfDataPermissionChecker(deptService);
LoginUser loginUser = new LoginUser();
SystemLoginUser loginUser = new SystemLoginUser();
loginUser.setUserId(1L);
DataCondition dataCondition = new DataCondition();
dataCondition.setTargetDeptId(2L);

View File

@@ -1,22 +1,23 @@
package com.agileboot.infrastructure.web.domain.permission.checker;
package com.agileboot.admin.customize.service.permission;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.infrastructure.web.domain.permission.DataCondition;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.admin.customize.service.permission.model.checker.SingleDeptDataPermissionChecker;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.infrastructure.user.web.RoleInfo;
import com.agileboot.admin.customize.service.permission.model.DataCondition;
import com.agileboot.domain.system.dept.db.SysDeptService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class SingleDeptDataPermissionCheckerTest {
private final ISysDeptService deptService = mock(ISysDeptService.class);
private final SysDeptService deptService = mock(SysDeptService.class);
public LoginUser loginUser = mock(LoginUser.class);
public SystemLoginUser loginUser = mock(SystemLoginUser.class);
@BeforeEach
public void mockBefore() {
@@ -29,7 +30,7 @@ class SingleDeptDataPermissionCheckerTest {
SingleDeptDataPermissionChecker checker = new SingleDeptDataPermissionChecker(deptService);
boolean check1 = checker.check(null, null);
boolean check2 = checker.check(new LoginUser(), null);
boolean check2 = checker.check(new SystemLoginUser(), null);
boolean check3 = checker.check(null, new DataCondition());
boolean check4 = checker.check(loginUser, new DataCondition());

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>agileboot</artifactId>
<groupId>com.agileboot</groupId>
<version>${revision}</version>
<version>1.0.0</version>
</parent>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
@@ -22,6 +22,18 @@
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-infrastructure</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--使用undertow依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- 业务领域 -->

View File

@@ -6,12 +6,12 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
/**
* 启动程序
* 定制banner.txt的网站
* http://patorjk.com/software/taag
* http://www.network-science.de/ascii/
* http://www.degraeve.com/img2txt.php
* http://life.chacuo.net/convertfont2char
* 启动程序 定制banner.txt的网站
* <a href="http://patorjk.com/software/taag">http://patorjk.com/software/taag</a>
* <a href="http://www.network-science.de/ascii/">http://www.network-science.de/ascii/</a>
* <a href="http://www.degraeve.com/img2txt.php">http://www.degraeve.com/img2txt.php</a>
* <a href="http://life.chacuo.net/convertfont2char">http://life.chacuo.net/convertfont2char</a>
*
* @author valarchie
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

View File

@@ -7,7 +7,7 @@ import org.springframework.web.bind.annotation.RestController;
/**
* 调度日志操作处理
*
* @author ruoyi
* @author valarchie
*/
@RestController
@RequestMapping("/api/order")

View File

@@ -0,0 +1,39 @@
package com.agileboot.api.controller.app;
import com.agileboot.api.customize.service.JwtTokenService;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 调度日志操作处理
*
* @author ruoyi
*/
@RestController
@RequestMapping("/app")
@AllArgsConstructor
public class AppController extends BaseController {
private final JwtTokenService jwtTokenService;
/**
* 访问首页,提示语
*/
@PreAuthorize("hasAuthority('annie')")
@GetMapping("/list")
public ResponseDTO<?> appLogin() {
return ResponseDTO.ok();
}
}

View File

@@ -0,0 +1,38 @@
package com.agileboot.api.controller.common;
import cn.hutool.core.map.MapUtil;
import com.agileboot.api.customize.service.JwtTokenService;
import com.agileboot.common.core.base.BaseController;
import com.agileboot.common.core.dto.ResponseDTO;
import java.util.Map;
import lombok.AllArgsConstructor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 调度日志操作处理
*
* @author ruoyi
*/
@RestController
@RequestMapping("/common")
@AllArgsConstructor
public class LoginController extends BaseController {
private final JwtTokenService jwtTokenService;
/**
* 访问首页,提示语
*/
@PostMapping("/app/{appId}/login")
public ResponseDTO<String> appLogin() {
String token = jwtTokenService.generateToken(MapUtil.of("token", "user1"));
return ResponseDTO.ok(token);
}
}

View File

@@ -0,0 +1,52 @@
package com.agileboot.api.customize.config;
import com.agileboot.api.customize.service.JwtTokenService;
import com.agileboot.infrastructure.user.app.AppLoginUser;
import io.jsonwebtoken.Claims;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* token过滤器 验证token有效性
* 继承OncePerRequestFilter类的话 可以确保只执行filter一次 避免执行多次
* @author valarchie
*/
@Component
@Slf4j
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenService jwtTokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String tokenFromRequest = jwtTokenService.getTokenFromRequest(request);
if (tokenFromRequest != null) {
Claims claims = jwtTokenService.parseToken(tokenFromRequest);
String token = (String) claims.get("token");
// 根据token去查缓存里面 有没有对应的App用户
// 没有的话 再去数据库中查询
if (token != null && token.equals("user1")) {
AppLoginUser loginUser = new AppLoginUser(23232323L, false, "dasdsadsds");
loginUser.grantAppPermission("annie");
UsernamePasswordAuthenticationToken suer1 = new UsernamePasswordAuthenticationToken(loginUser, null,
loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(suer1);
}
}
filterChain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,86 @@
package com.agileboot.api.customize.config;
import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Client;
import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.common.utils.jackson.JacksonUtil;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
/**
* 主要配置登录流程逻辑涉及以下几个类
* @author valarchie
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class SecurityConfig {
/**
* token认证过滤器
*/
private final JwtAuthenticationFilter jwtTokenFilter;
/**
* 跨域过滤器
*/
private final CorsFilter corsFilter;
/**
* 登录异常处理类
* 用户未登陆的话 在这个Bean中处理
*/
@Bean
public AuthenticationEntryPoint customAuthenticationEntryPoint() {
return (request, response, exception) -> {
ResponseDTO<Void> responseDTO = ResponseDTO.fail(
new ApiException(Client.COMMON_NO_AUTHORIZATION, request.getRequestURI())
);
ServletHolderUtil.renderString(response, JacksonUtil.to(responseDTO));
};
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
// 不配这个错误处理的话 会直接返回403
.exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用 session
.and()
.authorizeRequests()
.antMatchers("/common/**").permitAll()
.anyRequest().authenticated()
.and()
// 禁用 X-Frame-Options 响应头。下面是具体解释:
// X-Frame-Options 是一个 HTTP 响应头,用于防止网页被嵌入到其他网页的 <frame>、<iframe> 或 <object> 标签中,从而可以减少点击劫持攻击的风险
.headers().frameOptions().disable()
.and()
.formLogin().disable();
httpSecurity.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加CORS filter
httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationFilter.class);
return httpSecurity.build();
}
}

View File

@@ -0,0 +1,128 @@
package com.agileboot.api.customize.service;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.constant.Constants.Token;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.domain.common.cache.RedisCacheService;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* token验证处理
*
* @author valarchie
*/
@Component
@Slf4j
@Data
@RequiredArgsConstructor
public class JwtTokenService {
/**
* 自定义令牌标识
*/
@Value("${token.header}")
private String header;
/**
* 令牌秘钥
*/
@Value("${token.secret}")
private String secret;
private final RedisCacheService redisCache;
/**
* 获取用户身份信息
*
* @return 用户信息
*/
public SystemLoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getTokenFromRequest(request);
if (StrUtil.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Token.LOGIN_USER_KEY);
return redisCache.loginUserCache.getObjectOnlyInCacheById(uuid);
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) {
log.error("parse token failed.", jwtException);
throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN);
} catch (Exception e) {
log.error("fail to get cached user from redis", e);
throw new ApiException(e, ErrorCode.Client.TOKEN_PROCESS_FAILED, e.getMessage());
}
}
return null;
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
public String generateToken(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户名
*
* @param token 令牌
* @return 用户名
*/
private String getUsernameFromToken(String token) {
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @return token
*/
public String getTokenFromRequest(HttpServletRequest request) {
String token = request.getHeader(header);
if (StrUtil.isNotEmpty(token) && token.startsWith(Token.PREFIX)) {
token = StrUtil.stripIgnoreCase(token, Token.PREFIX, null);
}
return token;
}
}

View File

@@ -0,0 +1,12 @@
package com.agileboot.api.customize.util;
public class ApiEncryptor {
public static void main(String[] args) {
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>agileboot</artifactId>
<groupId>com.agileboot</groupId>
<version>${revision}</version>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -8,7 +8,7 @@ import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* TODO 移走 不合适放在这里common包底下
* @author valarchie
*/
@Component
@@ -56,7 +56,7 @@ public class AgileBootConfig {
*/
private static String rsaPrivateKey;
private static String apiDocsPathPrefix;
private static String apiPrefix;
public static String getFileBaseDir() {
return fileBaseDir;
@@ -66,12 +66,12 @@ public class AgileBootConfig {
AgileBootConfig.fileBaseDir = fileBaseDir + File.separator + Constants.RESOURCE_PREFIX;
}
public static String getApiDocsPathPrefix() {
return apiDocsPathPrefix;
public static String getApiPrefix() {
return apiPrefix;
}
public void setApiDocsPathPrefix(String apiDocsPathPrefix) {
AgileBootConfig.apiDocsPathPrefix = apiDocsPathPrefix;
public void setApiPrefix(String apiDocsPathPrefix) {
AgileBootConfig.apiPrefix = apiDocsPathPrefix;
}
public static boolean isAddressEnabled() {

View File

@@ -35,7 +35,7 @@ public class Constants {
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
public static final String PREFIX = "Bearer ";
/**
* 令牌前缀

View File

@@ -1,9 +1,8 @@
package com.agileboot.common.core.dto;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.common.exception.error.ErrorCodeInterface;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -20,43 +19,41 @@ public class ResponseDTO<T> {
private String msg;
@JsonInclude
private T data;
public static <T> ResponseDTO<T> ok() {
return build(null, ErrorCode.SUCCESS);
return build(null, ErrorCode.SUCCESS.code(), ErrorCode.SUCCESS.message());
}
public static <T> ResponseDTO<T> ok(T data) {
return build(data, ErrorCode.SUCCESS);
return build(data, ErrorCode.SUCCESS.code(), ErrorCode.SUCCESS.message());
}
public static <T> ResponseDTO<T> fail() {
return build(null, ErrorCode.FAIL);
return build(null, ErrorCode.FAILED.code(), ErrorCode.FAILED.message());
}
public static <T> ResponseDTO<T> fail(T data) {
return build(data, ErrorCode.FAIL);
}
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code) {
return build(null, code);
}
public static <T> ResponseDTO<T> fail(ErrorCodeInterface code, Object... args) {
return build(null, code, args);
return build(data, ErrorCode.FAILED.code(), ErrorCode.FAILED.message());
}
public static <T> ResponseDTO<T> fail(ApiException exception) {
return build(exception.getErrorCode().code(), exception.getMessage());
return build(null, exception.getErrorCode().code(), exception.getMessage());
}
public static <T> ResponseDTO<T> build(T data, ErrorCodeInterface code, Object... args) {
return new ResponseDTO<>(code.code(), StrUtil.format(code.message(), args), data);
public static <T> ResponseDTO<T> fail(ApiException exception, T data) {
return build(data, exception.getErrorCode().code(), exception.getMessage());
}
public static <T> ResponseDTO<T> build(Integer code, String msg) {
return new ResponseDTO<>(code, msg, null);
public static <T> ResponseDTO<T> build(T data, Integer code, String msg) {
return new ResponseDTO<>(code, msg, data);
}
// 去掉直接填充错误码的方式, 这种方式不能拿到i18n的错误消息 统一通过ApiException来构造错误消息
// public static <T> ResponseDTO<T> fail(ErrorCodeInterface code, Object... args) {
// return build(null, code, args);
// }
}

View File

@@ -1,12 +1,15 @@
package com.agileboot.orm.common.query;
package com.agileboot.common.core.page;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import javax.validation.constraints.Max;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.Max;
/**
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Data
public abstract class AbstractPageQuery<T> extends AbstractQuery<T> {

View File

@@ -0,0 +1,90 @@
package com.agileboot.common.core.page;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.utils.time.DatePickUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import java.util.Date;
import lombok.Data;
/**
* 如果是简单的排序 和 时间范围筛选 可以使用内置的这几个字段
* @author valarchie
*/
@Data
public abstract class AbstractQuery<T> {
protected String orderColumn;
protected String orderDirection;
protected String timeRangeColumn;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private Date beginTime;
@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd")
private Date endTime;
private static final String ASC = "ascending";
private static final String DESC = "descending";
/**
* 生成query conditions
*
* @return 添加条件后的QueryWrapper
*/
public QueryWrapper<T> toQueryWrapper() {
QueryWrapper<T> queryWrapper = addQueryCondition();
addSortCondition(queryWrapper);
addTimeCondition(queryWrapper);
return queryWrapper;
}
public abstract QueryWrapper<T> addQueryCondition();
public void addSortCondition(QueryWrapper<T> queryWrapper) {
if (queryWrapper == null || StrUtil.isEmpty(orderColumn)) {
return;
}
Boolean sortDirection = convertSortDirection();
if (sortDirection != null) {
queryWrapper.orderBy(StrUtil.isNotEmpty(orderColumn), sortDirection,
StrUtil.toUnderlineCase(orderColumn));
}
}
public void addTimeCondition(QueryWrapper<T> queryWrapper) {
if (queryWrapper != null
&& StrUtil.isNotEmpty(this.timeRangeColumn)) {
queryWrapper
.ge(beginTime != null, StrUtil.toUnderlineCase(timeRangeColumn),
DatePickUtil.getBeginOfTheDay(beginTime))
.le(endTime != null, StrUtil.toUnderlineCase(timeRangeColumn), DatePickUtil.getEndOfTheDay(endTime));
}
}
/**
* 获取前端传来的排序方向 转换成MyBatisPlus所需的排序参数 boolean=isAsc
* @return 排序顺序, null为无排序
*/
public Boolean convertSortDirection() {
Boolean isAsc = null;
if (StrUtil.isEmpty(this.orderDirection)) {
return isAsc;
}
if (ASC.equals(this.orderDirection)) {
isAsc = true;
}
if (DESC.equals(this.orderDirection)) {
isAsc = false;
}
return isAsc;
}
}

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.interfaces;
package com.agileboot.common.enums;
/**
* @author valarchie

View File

@@ -1,9 +1,9 @@
package com.agileboot.orm.common.util;
package com.agileboot.common.enums;
import cn.hutool.core.convert.Convert;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.BasicEnum;
import java.util.Objects;

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.interfaces;
package com.agileboot.common.enums;
/**
* 字典类型 接口

View File

@@ -1,23 +1,23 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_operation_log的business_type
*
* @author valarchie
*/
@Dictionary(name = "sys_operation_type")
@Dictionary(name = "sysOperationLog.businessType")
public enum BusinessTypeEnum implements DictionaryEnum<Integer> {
/**
* 操作类型
*/
OTHER(0, "其他操作", CssTag.INFO),
ADD(1, "添加", CssTag.INFO),
MODIFY(2, "修改", CssTag.INFO),
ADD(1, "添加", CssTag.PRIMARY),
MODIFY(2, "修改", CssTag.PRIMARY),
DELETE(3, "删除", CssTag.DANGER),
GRANT(4, "授权", CssTag.PRIMARY),
EXPORT(5, "导出", CssTag.WARNING),

View File

@@ -1,6 +1,6 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.BasicEnum;
/**
* 系统配置

View File

@@ -1,23 +1,23 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_user的sex字段
*
* @author valarchie
*/
@Dictionary(name = "sys_user_sex")
@Dictionary(name = "sysUser.sex")
public enum GenderEnum implements DictionaryEnum<Integer> {
/**
* 用户性别
*/
MALE(1, "", CssTag.NONE),
FEMALE(2, "", CssTag.NONE),
UNKNOWN(0, "未知", CssTag.NONE);
MALE(1, "", CssTag.PRIMARY),
FEMALE(2, "", CssTag.PRIMARY),
UNKNOWN(0, "未知", CssTag.PRIMARY);
private final int value;
private final String description;

View File

@@ -1,15 +1,15 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 用户状态
*
* @author valarchie
*/
@Dictionary(name = "sys_login_status")
// TODO 表记得改成LoginLog
@Dictionary(name = "sysLoginLog.status")
public enum LoginStatusEnum implements DictionaryEnum<Integer> {
/**
* status of user

View File

@@ -1,10 +1,12 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.BasicEnum;
/**
*
* @author valarchie
*/
@Deprecated
public enum MenuComponentEnum implements BasicEnum<Integer> {
/**

View File

@@ -1,6 +1,6 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.BasicEnum;
/**
* @author valarchie
@@ -11,9 +11,10 @@ public enum MenuTypeEnum implements BasicEnum<Integer> {
/**
* 菜单类型
*/
DIRECTORY(1, "目录"),
MENU(2, "菜单"),
BUTTON(3, "按钮");
MENU(1, "页面"),
CATALOG(2, "目录"),
IFRAME(3, "内嵌Iframe"),
OUTSIDE_LINK_REDIRECT(4, "外链跳转");
private final int value;
private final String description;

View File

@@ -1,14 +1,14 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_notice的 status字段
* @author valarchie
*/
@Dictionary(name = "sys_notice_status")
@Dictionary(name = "sysNotice.status")
public enum NoticeStatusEnum implements DictionaryEnum<Integer> {
/**

View File

@@ -1,14 +1,16 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_notice的 notice_type字段
* 名称一般由对应的表名.字段构成
* 全局的话使用common作为表名
* @author valarchie
*/
@Dictionary(name = "sys_notice_type")
@Dictionary(name = "sysNotice.noticeType")
public enum NoticeTypeEnum implements DictionaryEnum<Integer> {
/**

View File

@@ -1,14 +1,14 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_operation_log的status字段
* @author valarchie
*/
@Dictionary(name = "sys_operation_status")
@Dictionary(name = "sysOperationLog.status")
public enum OperationStatusEnum implements DictionaryEnum<Integer> {
/**

View File

@@ -1,11 +1,13 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.BasicEnum;
/**
* 操作者类型
* @author valarchie
*/
@Dictionary(name = "sysOperationLog.operatorType")
public enum OperatorTypeEnum implements BasicEnum<Integer> {
/**

View File

@@ -1,6 +1,6 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.interfaces.BasicEnum;
import com.agileboot.common.enums.BasicEnum;
/**
* Http Method

View File

@@ -1,14 +1,14 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 除非表有特殊指明的话一般用这个枚举代表 status字段
* @author valarchie
*/
@Dictionary(name = "sys_status")
@Dictionary(name = "common.status")
public enum StatusEnum implements DictionaryEnum<Integer> {
/**
* 开关状态

View File

@@ -0,0 +1,49 @@
package com.agileboot.common.enums.common;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_user的status字段
* @author valarchie
*/
@Dictionary(name = "sysUser.status")
public enum UserStatusEnum implements DictionaryEnum<Integer> {
/**
* 用户账户状态
*/
NORMAL(1, "正常", CssTag.PRIMARY),
DISABLED(2, "禁用", CssTag.DANGER),
FROZEN(3, "冻结", CssTag.WARNING);
private final int value;
private final String description;
private final String cssTag;
UserStatusEnum(int value, String description, String cssTag) {
this.value = value;
this.description = description;
this.cssTag = cssTag;
}
public Integer getValue() {
return value;
}
@Override
public String description() {
return this.description;
}
public String getDescription() {
return description;
}
@Override
public String cssTag() {
return null;
}
}

View File

@@ -1,14 +1,15 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
/**
* 对应sys_menu表的is_visible字段
* @author valarchie
*/
@Dictionary(name = "sys_visible")
@Deprecated
@Dictionary(name = "sysMenu.isVisible")
public enum VisibleStatusEnum implements DictionaryEnum<Integer> {
/**

View File

@@ -1,14 +1,14 @@
package com.agileboot.orm.common.enums;
package com.agileboot.common.enums.common;
import com.agileboot.orm.common.CssTag;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.DictionaryEnum;
import com.agileboot.common.enums.dictionary.CssTag;
import com.agileboot.common.enums.dictionary.Dictionary;
/**
* 系统内代表是与否的枚举
* @author valarchie
*/
@Dictionary(name = "sys_yes_no")
@Dictionary(name = "common.yesOrNo")
public enum YesOrNoEnum implements DictionaryEnum<Integer> {
/**
* 是与否

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common;
package com.agileboot.common.enums.dictionary;
/**
* Css 样式
@@ -6,8 +6,7 @@ package com.agileboot.orm.common;
*/
public class CssTag {
public static final String NONE = "";
public static final String PRIMARY = "primary";
public static final String PRIMARY = "";
public static final String DANGER = "danger";
public static final String WARNING = "warning";
public static final String SUCCESS = "success";

View File

@@ -1,4 +1,4 @@
package com.agileboot.orm.common.annotations;
package com.agileboot.common.enums.dictionary;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@@ -1,6 +1,6 @@
package com.agileboot.orm.common.result;
package com.agileboot.common.enums.dictionary;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.common.enums.DictionaryEnum;
import lombok.Data;
/**

View File

@@ -3,64 +3,73 @@ package com.agileboot.common.exception;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.exception.error.ErrorCodeInterface;
import com.agileboot.common.utils.i18n.MessageUtils;
import java.util.HashMap;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
/**
* 统一异常类
*
* @author valarchie
*/
@EqualsAndHashCode(callSuper = true)
@Slf4j
@Data
public class ApiException extends RuntimeException{
public class ApiException extends RuntimeException {
protected ErrorCodeInterface errorCode;
protected String message;
protected Object[] args;
protected String i18nMessage;
protected String formattedMessage;
protected String i18nFormattedMessage;
/**
* 如果有一些特殊的数据 可以放在这个payload里面
* 有时候错误的返回信息太少 不便前端处理的话 可以放在这个payload字段当中
* 比如你做了一个大批量操作操作ID为1~10的实体 其中1~5成功 6~10失败
* 你可以将这些相关信息放在这个payload中
*/
protected HashMap<String, Object> payload;
public ApiException(Throwable e, ErrorCodeInterface errorCode, Object... args) {
super(e);
fillErrorCode(errorCode, args);
public ApiException(ErrorCodeInterface errorCode) {
fillErrorCode(errorCode);
}
public ApiException(ErrorCodeInterface errorCode, Object... args) {
fillErrorCode(errorCode, args);
}
public ApiException(ErrorCodeInterface errorCode) {
fillErrorCode(errorCode);
/**
* 注意 如果是try catch的情况下捕获异常 并转为ApiException的话 一定要填入Throwable e
* @param e 捕获到的原始异常
* @param errorCode 错误码
* @param args 错误详细信息参数
*/
public ApiException(Throwable e, ErrorCodeInterface errorCode, Object... args) {
super(e);
fillErrorCode(errorCode, args);
}
private void fillErrorCode(ErrorCodeInterface errorCode, Object... args) {
this.errorCode = errorCode;
this.message = errorCode.message();
this.args = args;
this.formattedMessage = StrUtil.format(this.message, args);
this.message = StrUtil.format(errorCode.message(), args);
try {
this.i18nFormattedMessage = MessageUtils.message(errorCode.i18nKey(), args);
this.i18nMessage = MessageUtils.message(errorCode.i18nKey(), args);
} catch (Exception e) {
log.error("could not found i18nMessage entry for key: " + errorCode.i18nKey());
}
}
@Override
public String getMessage() {
return i18nFormattedMessage != null ? i18nFormattedMessage : formattedMessage;
return i18nMessage != null ? i18nMessage : message;
}
@Override
public String getLocalizedMessage() {
return i18nFormattedMessage;
return i18nMessage != null ? i18nMessage : message;
}
}

View File

@@ -1,5 +1,7 @@
package com.agileboot.common.exception.error;
import org.springframework.util.Assert;
/**
* 错误码集合
*
@@ -9,25 +11,41 @@ public enum ErrorCode implements ErrorCodeInterface {
/**
* 错误码集合
* ******以下是旧的设计****
* 1~9999 为保留错误码 或者 常用错误码
* 10000~19999 为内部错误码
* 20000~29999 客户端错误码 (客户端异常调用之类的错误)
* 30000~39999 为第三方错误码 (代码正常,但是第三方异常)
* 40000~49999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
* 由于系统内的错误码都是独一无二的所以错误码应该放在common包集中管理
* ---------------------------
* 旧的设计的缺陷,比如内部错误码其实并不会很多 但是占用了1~9999的序列其实是不必要的。
* 而且错误码不一定位数一定要相同。比如腾讯的微信接口错误码的位数就并不相同。按照常理错误码的数量大小应该是:
* 内部错误码< 客户端错误码< 第三方错误码< 业务错误码
* 所以我们应该尽可能的把错误码的数量留给业务错误码
* ---------------------------
* *******新的设计**********
* 1~99 为内部错误码(框架本身的错误)
* 100~999 客户端错误码 (客户端异常调用之类的错误)
* 1000~9999为第三方错误码 (代码正常,但是第三方异常)
* 10000~99999 为业务逻辑 错误码 (无异常,代码正常流转,并返回提示给用户)
* 由于系统内的错误码都是独一无二的所以错误码应该放在common包集中管理
* ---------------------------
* 总体设计就是值越小 错误严重性越高
* 目前10000~19999是初始系统内嵌功能使用的错误码后续开发者可以直接使用20000以上的错误码作为业务错误码
*/
// -------------- 普通错误码 及保留错误码 ---------------
SUCCESS(0, "操作成功"),
FAIL(9999, "操作失败"),
UNKNOWN_ERROR(99999, "未知错误");
SUCCESS(0, "操作成功", "SUCCESS"),
FAILED(99999, "操作失败", "FAILED");
private final int code;
private final String msg;
private final String i18nKey;
ErrorCode(int code, String msg) {
ErrorCode(int code, String msg, String i18nKey) {
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
@@ -40,138 +58,151 @@ public enum ErrorCode implements ErrorCodeInterface {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
/**
* 40000~49999 为业务逻辑 错误码 (无代码异常,代码正常流转,并返回提示给用户)
* 10000~99999 为业务逻辑 错误码 (无代码异常,代码正常流转,并返回提示给用户)
* 1XX01 XX是代表模块的意思 比如10101 01是Permission模块
* 错误码的命名最好以模块为开头 比如 NOT_ALLOWED_TO_OPERATE前面加上PERMISSION = PERMISSION_NOT_ALLOWED_TO_OPERATE
*/
public enum Business implements ErrorCodeInterface {
// ----------------------------- Common --------------------------------------
// ----------------------------- COMMON --------------------------------------
OBJECT_NOT_FOUND(Module.COMMON, 1, "找不到ID为 {} 的 {}"),
COMMON_OBJECT_NOT_FOUND(10001, "找不到ID为 {} 的 {}", "Business.OBJECT_NOT_FOUND"),
UNSUPPORTED_OPERATION(Module.COMMON, 2, "不支持的操作"),
COMMON_UNSUPPORTED_OPERATION(10002, "不支持的操作", "Business.UNSUPPORTED_OPERATION"),
BULK_DELETE_IDS_IS_INVALID(Module.COMMON, 3, "批量参数ID列表为空"),
COMMON_BULK_DELETE_IDS_IS_INVALID(10003, "批量参数ID列表为空", "Business.BULK_DELETE_IDS_IS_INVALID"),
FILE_NOT_ALLOWED_TO_DOWNLOAD(Module.COMMON, 3, "文件名称({})非法,不允许下载"),
COMMON_FILE_NOT_ALLOWED_TO_DOWNLOAD(10004, "文件名称({})非法,不允许下载", "Business.FILE_NOT_ALLOWED_TO_DOWNLOAD"),
// ----------------------------- Permission -----------------------------------
// ----------------------------- PERMISSION -----------------------------------
FORBIDDEN_TO_MODIFY_ADMIN(Module.PERMISSION, 1, "不允许修改管理员的信息"),
PERMISSION_FORBIDDEN_TO_MODIFY_ADMIN(10101, "不允许修改管理员的信息", "Business.FORBIDDEN_TO_MODIFY_ADMIN"),
NO_PERMISSION_TO_OPERATE(Module.PERMISSION, 2, "没有权限进行此操作,请联系管理员"),
PERMISSION_NOT_ALLOWED_TO_OPERATE(10202, "没有权限进行此操作,请联系管理员", "Business.NO_PERMISSION_TO_OPERATE"),
// ----------------------------- Login -----------------------------------------
// ----------------------------- LOGIN -----------------------------------------
LOGIN_WRONG_USER_PASSWORD(Module.LOGIN, 1, "用户密码错误,请重输"),
LOGIN_WRONG_USER_PASSWORD(10201, "用户密码错误,请重输", "Business.LOGIN_WRONG_USER_PASSWORD"),
LOGIN_ERROR(Module.LOGIN, 2, "登录失败:{}"),
LOGIN_ERROR(10202, "登录失败:{}", "Business.LOGIN_ERROR"),
LOGIN_CAPTCHA_CODE_WRONG(Module.LOGIN, 3, "验证码错误"),
LOGIN_CAPTCHA_CODE_WRONG(10203, "验证码错误", "Business.LOGIN_CAPTCHA_CODE_WRONG"),
LOGIN_CAPTCHA_CODE_EXPIRE(Module.LOGIN, 4, "验证码过期"),
LOGIN_CAPTCHA_CODE_EXPIRE(10204, "验证码过期", "Business.LOGIN_CAPTCHA_CODE_EXPIRE"),
LOGIN_CAPTCHA_CODE_NULL(Module.LOGIN, 5, "验证码为空"),
LOGIN_CAPTCHA_CODE_NULL(10205, "验证码为空", "Business.LOGIN_CAPTCHA_CODE_NULL"),
// ----------------------------- Upload -----------------------------------------
// ----------------------------- UPLOAD -----------------------------------------
UPLOAD_FILE_TYPE_NOT_ALLOWED(Module.UPLOAD, 1, "不允许上传的文件类型,仅允许:{}"),
UPLOAD_FILE_TYPE_NOT_ALLOWED(10401, "不允许上传的文件类型,仅允许:{}", "Business.UPLOAD_FILE_TYPE_NOT_ALLOWED"),
UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH(Module.UPLOAD, 2, "文件名长度超过:{} "),
UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH(10402, "文件名长度超过:{} ", "Business.UPLOAD_FILE_NAME_EXCEED_MAX_LENGTH"),
UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE(Module.UPLOAD, 3, "文件名大小超过:{} MB"),
UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE(10403, "文件名大小超过:{} MB", "Business.UPLOAD_FILE_SIZE_EXCEED_MAX_SIZE"),
UPLOAD_IMPORT_EXCEL_FAILED(Module.UPLOAD, 4, "导入excel失败{}"),
UPLOAD_IMPORT_EXCEL_FAILED(10404, "导入excel失败{}", "Business.UPLOAD_IMPORT_EXCEL_FAILED"),
UPLOAD_FILE_IS_EMPTY(Module.UPLOAD, 5, "上传文件为空"),
UPLOAD_FILE_IS_EMPTY(10405, "上传文件为空", "Business.UPLOAD_FILE_IS_EMPTY"),
UPLOAD_FILE_FAILED(Module.UPLOAD, 6, "上传文件失败:{}"),
UPLOAD_FILE_FAILED(10406, "上传文件失败:{}", "Business.UPLOAD_FILE_FAILED"),
// ----------------------------- Config -----------------------------------------
// ----------------------------- CONFIG -----------------------------------------
CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY(Module.CONFIG, 1, "参数键值不允许为空"),
CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY(10601, "参数键值不允许为空", "Business.CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY"),
CONFIG_VALUE_IS_NOT_IN_OPTIONS(Module.CONFIG, 2, "参数键值不存在列表中"),
CONFIG_VALUE_IS_NOT_IN_OPTIONS(10602, "参数键值不存在列表中", "Business.CONFIG_VALUE_IS_NOT_IN_OPTIONS"),
// ------------------------------- Post --------------------------------------------
// ------------------------------- POST --------------------------------------------
POST_NAME_IS_NOT_UNIQUE(Module.POST, 1, "岗位名称:{}, 已存在"),
POST_NAME_IS_NOT_UNIQUE(10701, "岗位名称:{}, 已存在", "Business.POST_NAME_IS_NOT_UNIQUE"),
POST_CODE_IS_NOT_UNIQUE(Module.POST, 2, "岗位编号:{}, 已存在"),
POST_CODE_IS_NOT_UNIQUE(10702, "岗位编号:{}, 已存在", "Business.POST_CODE_IS_NOT_UNIQUE"),
POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(Module.POST, 3, "职位已分配给用户,请先取消分配再删除"),
POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED(10703, "职位已分配给用户,请先取消分配再删除", "Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED"),
// ------------------------------- Dept ---------------------------------------------
// ------------------------------- DEPT ---------------------------------------------
DEPT_NAME_IS_NOT_UNIQUE(Module.DEPT, 1, "部门名称:{}, 已存在"),
DEPT_NAME_IS_NOT_UNIQUE(10801, "部门名称:{}, 已存在", "Business.DEPT_NAME_IS_NOT_UNIQUE"),
DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(Module.DEPT, 2, "父级部门不能选择自己"),
DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF(10802, "父级部门不能选择自己", "Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF"),
DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(Module.DEPT, 3, "子部门还有正在启用的部门,暂时不能停用该部门"),
DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE(10803, "子部门还有正在启用的部门,暂时不能停用该部门", "Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE"),
DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(Module.DEPT, 4, "该部门存在下级部门不允许删除"),
DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE(10804, "该部门存在下级部门不允许删除", "Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE"),
DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(Module.DEPT, 5, "该部门存在关联的用户不允许删除"),
DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE(10805, "该部门存在关联的用户不允许删除", "Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE"),
DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(Module.DEPT, 6, "该父级部门不存在或已停用"),
DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED(10806, "该父级部门不存在或已停用", "Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED"),
// ------------------------------- Menu -------------------------------------------------
// ------------------------------- MENU -------------------------------------------------
MENU_NAME_IS_NOT_UNIQUE(Module.MENU, 1, "新增菜单:{} 失败,菜单名称已存在"),
MENU_NAME_IS_NOT_UNIQUE(10901, "新增菜单:{} 失败,菜单名称已存在", "Business.MENU_NAME_IS_NOT_UNIQUE"),
MENU_EXTERNAL_LINK_MUST_BE_HTTP(Module.MENU, 2, "菜单外链必须以 http(s)://开头"),
MENU_EXTERNAL_LINK_MUST_BE_HTTP(10902, "菜单外链必须以 http(s)://开头", "Business.MENU_EXTERNAL_LINK_MUST_BE_HTTP"),
MENU_PARENT_ID_NOT_ALLOW_SELF(Module.MENU, 3, "父级菜单不能选择自身"),
MENU_PARENT_ID_NOT_ALLOW_SELF(10903, "父级菜单不能选择自身", "Business.MENU_PARENT_ID_NOT_ALLOW_SELF"),
MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE(Module.MENU, 4, "存在子菜单不允许删除"),
MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE(10904, "存在子菜单不允许删除", "Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE"),
MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE(Module.MENU, 5, "菜单已分配给角色,不允许"),
MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE(10905, "菜单已分配给角色,不允许", "Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE"),
// -------------------------------- Role -------------------------------------------------
MENU_NOT_ALLOWED_TO_CREATE_BUTTON_ON_IFRAME_OR_OUT_LINK(10906, "不允许在Iframe和外链跳转类型下创建按钮", "Business.MENU_ONLY_ALLOWED_TO_CREATE_BUTTON_ON_PAGE"),
ROLE_NAME_IS_NOT_UNIQUE(Module.ROLE, 1, "角色名称:{}, 已存在"),
MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG(10907, "只允许在目录类型底下创建子菜单", "Business.MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG"),
ROLE_KEY_IS_NOT_UNIQUE(Module.ROLE, 2, "角色标识:{}, 已存在"),
MENU_CAN_NOT_CHANGE_MENU_TYPE(10908, "不允许更改菜单的类型", "Business.MENU_CAN_NOT_CHANGE_MENU_TYPE"),
ROLE_DATA_SCOPE_DUPLICATED_DEPT(Module.ROLE, 3, "重复的部门id"),
// -------------------------------- ROLE -------------------------------------------------
ROLE_ALREADY_ASSIGN_TO_USER(Module.ROLE, 4, "角色已分配给用户,请先取消分配,再删除角色"),
ROLE_NAME_IS_NOT_UNIQUE(11001, "角色名称:{}, 已存在", "Business.ROLE_NAME_IS_NOT_UNIQUE"),
ROLE_IS_NOT_AVAILABLE(Module.ROLE, 5, "角色:{} 已禁用,无法分配给用户"),
ROLE_KEY_IS_NOT_UNIQUE(11002, "角色标识{},存在", "Business.ROLE_KEY_IS_NOT_UNIQUE"),
// ---------------------------------- User -----------------------------------------------
ROLE_DATA_SCOPE_DUPLICATED_DEPT(11003, "重复的部门id", "Business.ROLE_DATA_SCOPE_DUPLICATED_DEPT"),
USER_NON_EXIST(Module.USER, 1, "登录用户:{} 不存在"),
ROLE_ALREADY_ASSIGN_TO_USER(11004, "角色已分配给用户,请先取消分配,再删除角色", "Business.ROLE_ALREADY_ASSIGN_TO_USER"),
USER_IS_DISABLE(Module.USER, 2, "对不起, 您的账号:{} 已停用"),
ROLE_IS_NOT_AVAILABLE(11005, "角色:{} 已禁用,无法分配给用户", "Business.ROLE_IS_NOT_AVAILABLE"),
USER_CACHE_IS_EXPIRE(Module.USER, 3, "用户缓存信息已经过期"),
// ---------------------------------- USER -----------------------------------------------
USER_FAIL_TO_GET_USER_ID(Module.USER, 3, "获取用户ID失败"),
USER_NON_EXIST(10501, "登录用户:{} 不存在", "Business.USER_NON_EXIST"),
USER_FAIL_TO_GET_DEPT_ID(Module.USER, 4, "获取用户部门ID失败"),
USER_IS_DISABLE(10502, "对不起, 您的账号:{} 已停用", "Business.USER_IS_DISABLE"),
USER_FAIL_TO_GET_ACCOUNT(Module.USER, 5, "获取用户账户失败"),
USER_CACHE_IS_EXPIRE(11003, "用户缓存信息已经过期", "Business.USER_CACHE_IS_EXPIRE"),
USER_FAIL_TO_GET_USER_INFO(Module.USER, 6, "获取用户信息失败"),
USER_FAIL_TO_GET_USER_ID(11004, "获取用户ID失败", "Business.USER_FAIL_TO_GET_USER_ID"),
USER_IMPORT_DATA_IS_NULL(Module.USER, 7, "导入的用户为空"),
USER_FAIL_TO_GET_DEPT_ID(10504, "获取用户部门ID失败", "Business.USER_FAIL_TO_GET_DEPT_ID"),
USER_PHONE_NUMBER_IS_NOT_UNIQUE(Module.USER, 8, "该电话号码已被其他用户占用"),
USER_FAIL_TO_GET_ACCOUNT(10505, "获取用户账户失败", "Business.USER_FAIL_TO_GET_ACCOUNT"),
USER_EMAIL_IS_NOT_UNIQUE(Module.USER, 9, "该邮件地址已被其他用户占用"),
USER_FAIL_TO_GET_USER_INFO(10506, "获取用户信息失败", "Business.USER_FAIL_TO_GET_USER_INFO"),
USER_PASSWORD_IS_NOT_CORRECT(Module.USER, 10, "用户密码错误"),
USER_IMPORT_DATA_IS_NULL(10507, "导入的用户为空", "Business.USER_IMPORT_DATA_IS_NULL"),
USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD(Module.USER, 11, "用户新密码与旧密码相同"),
USER_PHONE_NUMBER_IS_NOT_UNIQUE(10508, "该电话号码已被其他用户占用", "Business.USER_PHONE_NUMBER_IS_NOT_UNIQUE"),
USER_UPLOAD_FILE_FAILED(Module.USER, 12, "用户上传文件失败"),
USER_EMAIL_IS_NOT_UNIQUE(10509, "该邮件地址已被其他用户占用", "Business.USER_EMAIL_IS_NOT_UNIQUE"),
USER_NAME_IS_NOT_UNIQUE(Module.USER, 13, "用户名已被其他用户占用"),
USER_PASSWORD_IS_NOT_CORRECT(10510, "用户密码错误", "Business.USER_PASSWORD_IS_NOT_CORRECT"),
USER_CURRENT_USER_CAN_NOT_BE_DELETE(Module.USER, 14, "当前用户不允许被删除"),
USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD(10511, "用户新密码与旧密码相同", "Business.USER_NEW_PASSWORD_IS_THE_SAME_AS_OLD"),
USER_ADMIN_CAN_NOT_BE_MODIFY(Module.USER, 15, "管理员不允许做任何修改"),
USER_UPLOAD_FILE_FAILED(10512, "用户上传文件失败", "Business.USER_UPLOAD_FILE_FAILED"),
USER_NAME_IS_NOT_UNIQUE(10513, "用户名已被其他用户占用", "Business.USER_NAME_IS_NOT_UNIQUE"),
USER_CURRENT_USER_CAN_NOT_BE_DELETE(10514, "当前用户不允许被删除", "Business.USER_CURRENT_USER_CAN_NOT_BE_DELETE"),
USER_ADMIN_CAN_NOT_BE_MODIFY(10515, "管理员不允许做任何修改", "Business.USER_ADMIN_CAN_NOT_BE_MODIFY"),
;
@@ -179,11 +210,18 @@ public enum ErrorCode implements ErrorCodeInterface {
private final int code;
private final String msg;
private static final int BASE_CODE = 40000;
private final String i18nKey;
Business(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
Business(int code, String msg, String i18nKey) {
Assert.isTrue(code > 10000 && code < 99999,
"错误码code值定义失败Business错误码code值范围在10000~99099之间请查看ErrorCode.Business类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
@@ -196,28 +234,39 @@ public enum ErrorCode implements ErrorCodeInterface {
return this.msg;
}
@Override
public String i18nKey() {
return i18nKey;
}
}
/**
* 30000~39999是外部错误码 比如调用支付失败
* 1000~9999是外部错误码 比如调用支付失败
*/
public enum External implements ErrorCodeInterface {
/**
* 支付宝调用失败
*/
FAIL_TO_PAY_ON_ALIPAY(Module.COMMON, 1, "支付宝调用失败");
FAIL_TO_PAY_ON_ALIPAY(1001, "支付宝调用失败", "External.FAIL_TO_PAY_ON_ALIPAY");
private final int code;
private final String msg;
private static final int BASE_CODE = 30000;
private final String i18nKey;
External(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
External(int code, String msg, String i18nKey) {
Assert.isTrue(code > 1000 && code < 9999,
"错误码code值定义失败External错误码code值范围在1000~9999之间请查看ErrorCode.External类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
@@ -230,39 +279,54 @@ public enum ErrorCode implements ErrorCodeInterface {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
/**
* 20000~29999是客户端错误码
* 100~999是客户端错误码
* 客户端如 Web+小程序+手机端 调用出错
* 可能由于参数问题或者授权问题或者调用过去频繁
*/
public enum Client implements ErrorCodeInterface {
/**
* 客户端错误码
*/
COMMON_FORBIDDEN_TO_CALL(Module.COMMON, 1, "禁止调用"),
COMMON_FORBIDDEN_TO_CALL(101, "禁止调用", "Client.COMMON_FORBIDDEN_TO_CALL"),
COMMON_REQUEST_TOO_OFTEN(Module.COMMON, 2, "调用太过频繁"),
COMMON_REQUEST_TOO_OFTEN(102, "调用太过频繁", "Client.COMMON_REQUEST_TOO_OFTEN"),
COMMON_REQUEST_PARAMETERS_INVALID(Module.COMMON, 3, "请求参数异常,{}"),
COMMON_REQUEST_PARAMETERS_INVALID(103, "请求参数异常,{}", "Client.COMMON_REQUEST_PARAMETERS_INVALID"),
COMMON_REQUEST_METHOD_INVALID(Module.COMMON, 4, "请求方式: {} 不支持"),
COMMON_REQUEST_METHOD_INVALID(104, "请求方式: {} 不支持", "Client.COMMON_REQUEST_METHOD_INVALID"),
COMMON_REQUEST_RESUBMIT(Module.COMMON, 5, "请求重复提交"),
COMMON_REQUEST_RESUBMIT(105, "请求重复提交", "Client.COMMON_REQUEST_RESUBMIT"),
COMMON_NO_AUTHORIZATION(Module.PERMISSION, 1, "请求接口:{} 失败,用户未授权"),
COMMON_NO_AUTHORIZATION(106, "请求接口:{} 失败,用户未授权", "Client.COMMON_NO_AUTHORIZATION"),
INVALID_TOKEN(107, "token异常", "Client.INVALID_TOKEN"),
TOKEN_PROCESS_FAILED(108, "token处理失败{}", "Client.TOKEN_PROCESS_FAILED"),
;
private final int code;
private final String msg;
private final String i18nKey;
private static final int BASE_CODE = 20000;
Client(int code, String msg, String i18nKey) {
Assert.isTrue(code > 100 && code < 999,
"错误码code值定义失败Client错误码code值范围在100~999之间请查看ErrorCode.Client类当前错误码码为" + name());
Client(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
@@ -275,42 +339,55 @@ public enum ErrorCode implements ErrorCodeInterface {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
/**
* 10000~19999是内部错误码 例如 框架问题之类的
* 0~99是内部错误码 例如 框架内部问题之类的
*/
public enum Internal implements ErrorCodeInterface {
/**
* 内部错误码
*/
INVALID_PARAMETER(Module.COMMON, 1, "参数异常:{}"),
INVALID_PARAMETER(1, "参数异常:{}", "Internal.INVALID_PARAMETER"),
UNKNOWN_ERROR(Module.COMMON, 2, "未知异常, 请查看系统日志"),
/**
* 该错误主要用于返回 未知的异常大部分是RuntimeException 程序未能捕获 未能预料的错误
*/
INTERNAL_ERROR(2, "系统内部错误:{}", "Internal.INTERNAL_ERROR"),
GET_ENUM_FAILED(Module.COMMON, 3, "获取枚举类型失败, 枚举类: {}"),
GET_ENUM_FAILED(3, "获取枚举类型失败, 枚举类:{}", "Internal.GET_ENUM_FAILED"),
GET_CACHE_FAILED(Module.COMMON, 4, "获取缓存失败"),
GET_CACHE_FAILED(4, "获取缓存失败{}", "Internal.GET_CACHE_FAILED"),
INTERNAL_ERROR(Module.COMMON, 5, "系统内部错误:{}"),
DB_INTERNAL_ERROR(5, "数据库异常", "Internal.DB_INTERNAL_ERROR"),
LOGIN_CAPTCHA_GENERATE_FAIL(Module.LOGIN, 1, "验证码生成失败"),
LOGIN_CAPTCHA_GENERATE_FAIL(7, "验证码生成失败", "Internal.LOGIN_CAPTCHA_GENERATE_FAIL"),
INVALID_TOKEN(Module.PERMISSION, 1, "token异常"),
DB_INTERNAL_ERROR(Module.DB, 1, "数据库异常: {}"),
EXCEL_PROCESS_ERROR(8, "excel处理失败{}", "Internal.EXCEL_PROCESS_ERROR"),
;
private final int code;
private final String msg;
private static final int BASE_CODE = 10000;
private final String i18nKey;
Internal(Module module, int code, String msg) {
this.code = BASE_CODE + module.code() + code;
Internal(int code, String msg, String i18nKey) {
Assert.isTrue(code < 100,
"错误码code值定义失败Internal错误码code值范围在100~999之间请查看ErrorCode.Internal类当前错误码码为" + name());
String errorTypeName = this.getClass().getSimpleName();
Assert.isTrue(i18nKey != null && i18nKey.startsWith(errorTypeName),
String.format("错误码i18nKey值定义失败%s错误码i18nKey值必须以%s开头当前错误码为%s", errorTypeName, errorTypeName, name()));
this.code = code;
this.msg = msg;
this.i18nKey = i18nKey;
}
@Override
@@ -323,6 +400,11 @@ public enum ErrorCode implements ErrorCodeInterface {
return this.msg;
}
@Override
public String i18nKey() {
return this.i18nKey;
}
}
}

View File

@@ -5,12 +5,6 @@ package com.agileboot.common.exception.error;
*/
public interface ErrorCodeInterface {
/**
* 返回错误码名称
* @return 枚举名称
*/
String name();
/**
* 返回错误码
* @return 错误码
@@ -27,8 +21,6 @@ public interface ErrorCodeInterface {
* i18n资源文件的key, 详见messages.properties文件
* @return key
*/
default String i18nKey() {
return code() + "_" + name();
}
String i18nKey();
}

View File

@@ -1,73 +0,0 @@
package com.agileboot.common.exception.error;
/**
* 系统内的模块
* @author valarchie
*/
public enum Module {
/**
* 普通模块
*/
COMMON(0),
/**
* 权限模块
*/
PERMISSION(1),
/**
* 登录模块
*/
LOGIN(2),
/**
* 数据库模块
*/
DB(3),
/**
* 上传
*/
UPLOAD(4),
/**
* 用户
*/
USER(5),
/**
* 配置
*/
CONFIG(6),
/**
* 职位
*/
POST(7),
/**
* 部门
*/
DEPT(8),
/**
* 菜单
*/
MENU(9),
/**
* 角色
*/
ROLE(10),
;
private final int code;
Module(int code) { this.code = code * 100; }
public int code() {return code; }
}

View File

@@ -1,6 +1,7 @@
package com.agileboot.common.utils;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -14,6 +15,7 @@ import java.io.IOException;
*
* @author ruoyi
*/
@Slf4j
public class ServletHolderUtil {
private ServletHolderUtil() {
@@ -52,7 +54,7 @@ public class ServletHolderUtil {
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
} catch (IOException e) {
e.printStackTrace();
log.error("返回response失败", e);
}
}

View File

@@ -7,7 +7,7 @@ import org.springframework.context.i18n.LocaleContextHolder;
/**
* 获取i18n资源文件
*
* @author ruoyi
* @author valarchie
*/
public class MessageUtils {

View File

@@ -5,12 +5,14 @@ import cn.hutool.core.lang.Validator;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
/**
* ip校验器
*
* @author valarchie
*/
@Slf4j
public class IpUtil {
public static final String INNER_IP_REGEX = "^(127\\.0\\.0\\.\\d{1,3})|(localhost)|(10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(172\\.((1[6-9])|(2\\d)|(3[01]))\\.\\d{1,3}\\.\\d{1,3})|(192\\.168\\.\\d{1,3}\\.\\d{1,3})$";
@@ -30,6 +32,7 @@ public class IpUtil {
byte[] ip = ad.getAddress();
ia = InetAddress.getByAddress(ip);
} catch (UnknownHostException e) {
log.error("解析Ip失败", e);
e.printStackTrace();
}
if (ia == null) {

View File

@@ -55,7 +55,7 @@ public class OfflineIpRegionUtil {
return new IpRegion(split[0], split[1], split[2], split[3], split[4]);
} catch (Exception e) {
e.printStackTrace();
log.error("获取IP地理位置失败", e);
}
return null;
}

View File

@@ -35,6 +35,7 @@ import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -266,7 +267,7 @@ public class JacksonUtil {
*/
public static <V> List<V> fromList(String json, Class<V> type) {
if (StringUtils.isEmpty(json)) {
return null;
return Collections.emptyList();
}
try {
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
@@ -281,7 +282,7 @@ public class JacksonUtil {
*/
public static Map<String, Object> fromMap(String json) {
if (StringUtils.isEmpty(json)) {
return null;
return Collections.emptyMap();
}
try {
MapType mapType = mapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
@@ -497,12 +498,12 @@ public class JacksonUtil {
*/
public static byte[] getAsBytes(String json, String key) {
if (StringUtils.isEmpty(json)) {
return null;
return new byte[0];
}
try {
JsonNode jsonNode = getAsJsonObject(json, key);
if (null == jsonNode) {
return null;
return new byte[0];
}
return jsonNode.isBinary() ? jsonNode.binaryValue() : getAsString(jsonNode).getBytes();
} catch (Exception e) {
@@ -540,12 +541,12 @@ public class JacksonUtil {
*/
public static <V> List<V> getAsList(String json, String key, Class<V> type) {
if (StringUtils.isEmpty(json)) {
return null;
return Collections.emptyList();
}
try {
JsonNode jsonNode = getAsJsonObject(json, key);
if (null == jsonNode) {
return null;
return Collections.emptyList();
}
CollectionType collectionType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, type);
return from(getAsString(jsonNode), collectionType);

View File

@@ -7,6 +7,7 @@ import com.agileboot.common.annotation.ExcelColumn;
import com.agileboot.common.annotation.ExcelSheet;
import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Internal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
@@ -21,6 +22,7 @@ import java.util.List;
*
* @author valarchie
*/
@Slf4j
public class CustomExcelUtil {
private CustomExcelUtil() {
@@ -30,8 +32,7 @@ public class CustomExcelUtil {
try {
writeToOutputStream(list, clazz, response.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
throw new ApiException(Internal.UNKNOWN_ERROR);
throw new ApiException(e, Internal.EXCEL_PROCESS_ERROR, e.getMessage());
}
}
@@ -39,8 +40,8 @@ public class CustomExcelUtil {
try {
return readFromInputStream(clazz, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
throw new ApiException(Internal.UNKNOWN_ERROR);
// 注意如果是捕获到的错误 一定要放进ApiException当中
throw new ApiException(e, Internal.EXCEL_PROCESS_ERROR, e.getMessage());
}
}

View File

@@ -1,9 +1,8 @@
package com.agileboot.common.utils.time;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import lombok.extern.slf4j.Slf4j;
/**
* @author valarchie
@@ -15,11 +14,10 @@ public class DatePickUtil {
}
/**
* 安全地获取日期的一天开始时间, date为null 则返回null
* DateUtil.beginOfDay(date) 如果传null 会NPE
* 安全地获取日期的一天开始时间, date为null 则返回null DateUtil.beginOfDay(date) 如果传null 会NPE
*
* @param date
* @return
* @param date 当前日期
* @return 日期的一天开始时间
*/
public static Date getBeginOfTheDay(Date date) {
if (date == null) {
@@ -37,7 +35,7 @@ public class DatePickUtil {
* 安全地获取日期的一天结束时间, date为null 则返回null。 避免NPE
* DateUtil.endOfDay(date) 如果传null 会NPE
* @param date 23:59:59
* @return
* @return 日期的一天结束时间
*/
public static Date getEndOfTheDay(Date date) {
if (date == null) {

View File

@@ -1,8 +1,7 @@
package com.agileboot.orm.enums.interfaces;
package com.agileboot.common.enums;
import com.agileboot.orm.common.enums.YesOrNoEnum;
import com.agileboot.orm.common.util.BasicEnumUtil;
import com.agileboot.common.enums.common.YesOrNoEnum;
import org.junit.Assert;
import org.junit.Test;

View File

@@ -1,7 +1,7 @@
package com.agileboot.orm.query;
package com.agileboot.common.query;
import com.agileboot.orm.common.query.AbstractQuery;
import com.agileboot.common.core.page.AbstractQuery;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import java.util.Date;
import org.junit.jupiter.api.Assertions;
@@ -14,10 +14,10 @@ class AbstractQueryTest {
@BeforeEach
public void getNewQuery() {
query = new AbstractQuery() {
query = new AbstractQuery<Object>() {
@Override
public QueryWrapper toQueryWrapper() {
return null;
public QueryWrapper addQueryCondition() {
return new QueryWrapper();
}
};
}
@@ -25,8 +25,8 @@ class AbstractQueryTest {
@Test
void addTimeConditionWithNull() {
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
query.addTimeCondition(queryWrapper, "login_time");
query.setTimeRangeColumn("loginTime");
QueryWrapper<Object> queryWrapper = query.toQueryWrapper();
String targetSql = queryWrapper.getTargetSql();
Assertions.assertEquals("", targetSql);
@@ -37,9 +37,9 @@ class AbstractQueryTest {
void addTimeConditionWithBothValue() {
query.setBeginTime(new Date());
query.setEndTime(new Date());
query.setTimeRangeColumn("loginTime");
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
query.addTimeCondition(queryWrapper, "login_time");
QueryWrapper<Object> queryWrapper = query.toQueryWrapper();
String targetSql = queryWrapper.getTargetSql();
Assertions.assertEquals("(login_time >= ? AND login_time <= ?)", targetSql);
@@ -49,9 +49,9 @@ class AbstractQueryTest {
@Test
void addTimeConditionWithBeginValueOnly() {
query.setBeginTime(new Date());
query.setTimeRangeColumn("loginTime");
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
query.addTimeCondition(queryWrapper, "login_time");
QueryWrapper<Object> queryWrapper = query.toQueryWrapper();
String targetSql = queryWrapper.getTargetSql();
Assertions.assertEquals("(login_time >= ?)", targetSql);
@@ -61,11 +61,17 @@ class AbstractQueryTest {
@Test
void testConvertSortDirection() {
query.setIsAsc("ascending");
query.setOrderDirection("ascending");
Assertions.assertTrue(query.convertSortDirection());
query.setIsAsc("descending");
query.setOrderDirection("descending");
Assertions.assertFalse(query.convertSortDirection());
query.setOrderDirection("");
Assertions.assertNull(query.convertSortDirection());
query.setOrderDirection(null);
Assertions.assertNull(query.convertSortDirection());
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>agileboot</artifactId>
<groupId>com.agileboot</groupId>
<version>${revision}</version>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -24,12 +24,6 @@
<artifactId>agileboot-common</artifactId>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-orm</artifactId>
</dependency>
<dependency>
<groupId>com.agileboot</groupId>
<artifactId>agileboot-infrastructure</artifactId>

View File

@@ -2,14 +2,12 @@ package com.agileboot.domain.common.cache;
import cn.hutool.extra.spring.SpringUtil;
import com.agileboot.infrastructure.cache.guava.AbstractGuavaCacheTemplate;
import com.agileboot.infrastructure.cache.guava.GuavaCacheService;
import com.agileboot.infrastructure.cache.redis.RedisCacheService;
import com.agileboot.infrastructure.cache.redis.RedisCacheTemplate;
import com.agileboot.infrastructure.web.domain.login.LoginUser;
import com.agileboot.infrastructure.web.domain.login.RoleInfo;
import com.agileboot.orm.system.entity.SysDeptEntity;
import com.agileboot.orm.system.entity.SysRoleEntity;
import com.agileboot.orm.system.entity.SysUserEntity;
import com.agileboot.infrastructure.user.web.SystemLoginUser;
import com.agileboot.domain.system.dept.db.SysDeptEntity;
import com.agileboot.domain.system.post.db.SysPostEntity;
import com.agileboot.domain.system.role.db.SysRoleEntity;
import com.agileboot.domain.system.user.db.SysUserEntity;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
@@ -28,13 +26,13 @@ public class CacheCenter {
public static RedisCacheTemplate<String> captchaCache;
public static RedisCacheTemplate<LoginUser> loginUserCache;
public static RedisCacheTemplate<SystemLoginUser> loginUserCache;
public static RedisCacheTemplate<SysUserEntity> userCache;
public static RedisCacheTemplate<SysRoleEntity> roleCache;
public static RedisCacheTemplate<RoleInfo> roleModelInfoCache;
public static RedisCacheTemplate<SysPostEntity> postCache;
@PostConstruct
public void init() {
@@ -48,7 +46,7 @@ public class CacheCenter {
loginUserCache = redisCache.loginUserCache;
userCache = redisCache.userCache;
roleCache = redisCache.roleCache;
roleModelInfoCache = redisCache.roleModelInfoCache;
postCache = redisCache.postCache;
}
}

View File

@@ -1,9 +1,10 @@
package com.agileboot.infrastructure.cache.guava;
package com.agileboot.domain.common.cache;
import com.agileboot.orm.system.entity.SysDeptEntity;
import com.agileboot.orm.system.service.ISysConfigService;
import com.agileboot.orm.system.service.ISysDeptService;
import com.agileboot.infrastructure.cache.guava.AbstractGuavaCacheTemplate;
import com.agileboot.domain.system.dept.db.SysDeptEntity;
import com.agileboot.domain.system.config.db.SysConfigService;
import com.agileboot.domain.system.dept.db.SysDeptService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -17,11 +18,9 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
public class GuavaCacheService {
@NonNull
private ISysConfigService configService;
private final SysConfigService configService;
@NonNull
private ISysDeptService deptService;
private final SysDeptService deptService;
public final AbstractGuavaCacheTemplate<String> configCache = new AbstractGuavaCacheTemplate<String>() {
@Override

View File

@@ -1,12 +1,21 @@
package com.agileboot.infrastructure.cache.map;
package com.agileboot.domain.common.cache;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import com.agileboot.orm.common.annotations.Dictionary;
import com.agileboot.orm.common.enums.*;
import com.agileboot.orm.common.interfaces.DictionaryEnum;
import com.agileboot.orm.common.result.DictionaryData;
import com.agileboot.common.enums.common.BusinessTypeEnum;
import com.agileboot.common.enums.common.GenderEnum;
import com.agileboot.common.enums.common.LoginStatusEnum;
import com.agileboot.common.enums.common.NoticeStatusEnum;
import com.agileboot.common.enums.common.NoticeTypeEnum;
import com.agileboot.common.enums.common.OperationStatusEnum;
import com.agileboot.common.enums.common.StatusEnum;
import com.agileboot.common.enums.common.UserStatusEnum;
import com.agileboot.common.enums.common.VisibleStatusEnum;
import com.agileboot.common.enums.common.YesOrNoEnum;
import com.agileboot.common.enums.dictionary.Dictionary;
import com.agileboot.common.enums.DictionaryEnum;
import com.agileboot.common.enums.dictionary.DictionaryData;
import java.util.Arrays;
import java.util.List;
@@ -31,7 +40,7 @@ public class MapCache {
}
private static void initDictionaryCache() {
// TODO 这个可以做成自动扫描
loadInCache(BusinessTypeEnum.values());
loadInCache(YesOrNoEnum.values());
loadInCache(StatusEnum.values());
@@ -41,7 +50,7 @@ public class MapCache {
loadInCache(OperationStatusEnum.values());
loadInCache(LoginStatusEnum.values());
loadInCache(VisibleStatusEnum.values());
loadInCache(UserStatusEnum.values());
}

Some files were not shown because too many files have changed in this diff Show More