release v7.1

This commit is contained in:
xiaopeng
2024-07-14 21:17:26 +08:00
parent 9425517d6e
commit 14f9897569
195 changed files with 11269 additions and 2 deletions
@@ -0,0 +1,98 @@
package com.cool.modules.base.controller.admin;
import cn.hutool.core.lang.Dict;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.eps.CoolEps;
import com.cool.core.file.FileUploadStrategyFactory;
import com.cool.core.request.R;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysLoginService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.cool.modules.base.service.sys.BaseSysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
/**
* 系统通用接口, 每个人都有权限操作
*/
@RequiredArgsConstructor
@Tag(name = "系统通用", description = "系统通用")
@CoolRestController()
public class AdminBaseCommController {
final private BaseSysPermsService baseSysPermsService;
final private BaseSysUserService baseSysUserService;
final private BaseSysLoginService baseSysLoginService;
final private CoolEps coolEps;
final private FileUploadStrategyFactory fileUploadStrategyFactory;
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
return R.ok(coolEps.getAdmin());
}
@Operation(summary = "个人信息")
@GetMapping("/person")
public R person(@RequestAttribute() Long adminUserId) {
BaseSysUserEntity baseSysUserEntity = baseSysUserService.getById(adminUserId);
baseSysUserEntity.setPassword(null);
baseSysUserEntity.setPasswordV(null);
return R.ok(baseSysUserEntity);
}
@Operation(summary = "修改个人信息")
@PostMapping("/personUpdate")
public R personUpdate(@RequestAttribute Long adminUserId, @RequestBody Dict body) {
baseSysUserService.personUpdate(adminUserId, body);
return R.ok();
}
@Operation(summary = "权限与菜单")
@GetMapping("/permmenu")
public R permmenu(@RequestAttribute() Long adminUserId) {
return R.ok(baseSysPermsService.permmenu(adminUserId));
}
@Operation(summary = "文件上传")
@PostMapping(value = "/upload", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.ALL_VALUE})
public R upload(
@RequestPart(value = "file", required = false) @Parameter(description = "文件") MultipartFile[] files,
HttpServletRequest request) {
return R.ok(fileUploadStrategyFactory.upload(files, request));
}
@Operation(summary = "文件上传模式")
@GetMapping("/uploadMode")
public R uploadMode() {
return R.ok(fileUploadStrategyFactory.getMode());
}
@Operation(summary = "退出")
@PostMapping("/logout")
public R logout(@RequestAttribute Long adminUserId, @RequestAttribute String adminUsername) {
baseSysLoginService.logout(adminUserId, adminUsername);
return R.ok();
}
@Operation(summary = "编程")
@GetMapping("/program")
public R program() {
return R.ok("Java");
}
}
@@ -0,0 +1,77 @@
package com.cool.modules.base.controller.admin;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.eps.CoolEps;
import com.cool.core.file.FileUploadStrategyFactory;
import com.cool.core.request.R;
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
import com.cool.modules.base.service.sys.BaseSysLoginService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
/**
* 系统开放接口,无需权限校验
*/
@RequiredArgsConstructor
@Tag(name = "系统开放", description = "系统开放")
@CoolRestController()
public class AdminBaseOpenController {
final private BaseSysLoginService baseSysLoginService;
final private CoolEps coolEps;
final private FileUploadStrategyFactory fileUploadStrategyFactory;
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
return R.ok(coolEps.getAdmin());
}
@Operation(summary = "获得网页内容的参数值")
@GetMapping("/html")
public R html() {
return R.ok();
}
@Operation(summary = "登录")
@PostMapping("/login")
public R login(@RequestBody BaseSysLoginDto baseSysLoginDto) {
return R.ok(baseSysLoginService.login(baseSysLoginDto));
}
@Operation(summary = "验证码")
@GetMapping("/captcha")
public R captcha(@Parameter(description = "类型:svg|base64") @RequestParam(defaultValue = "base64") String type,
@Parameter(description = "宽度") @RequestParam(defaultValue = "150") Integer width,
@Parameter(description = "高度") @RequestParam(defaultValue = "50") Integer height) {
return R.ok(baseSysLoginService.captcha(type, width, height));
}
@Operation(summary = "刷新token")
@GetMapping("/refreshToken")
public R refreshToken(String refreshToken) {
return R.ok(baseSysLoginService.refreshToken(refreshToken));
}
@Operation(summary = "文件上传")
@PostMapping(value = "/upload", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.ALL_VALUE })
public R upload(@RequestPart(value = "file", required = false) @Parameter(description = "文件") MultipartFile[] files,
HttpServletRequest request) {
return R.ok(fileUploadStrategyFactory.upload(files, request));
}
@Operation(summary = "文件上传模式")
@GetMapping("/uploadMode")
public R uploadMode() {
return R.ok(fileUploadStrategyFactory.getMode());
}
}
@@ -0,0 +1,35 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 系统部门
*/
@Tag(name = "系统部门", description = "系统部门")
@CoolRestController(api = { "add", "delete", "update", "list" })
public class AdminBaseSysDepartmentController
extends BaseController<BaseSysDepartmentService, BaseSysDepartmentEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@Operation(summary = "排序")
@PostMapping("/order")
public R order(@RequestBody List<BaseSysDepartmentEntity> list) {
this.service.order(list);
return R.ok();
}
}
@@ -0,0 +1,57 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.base.entity.sys.BaseSysLogEntity;
import com.cool.modules.base.entity.sys.table.BaseSysLogEntityTableDef;
import com.cool.modules.base.entity.sys.table.BaseSysUserEntityTableDef;
import com.cool.modules.base.service.sys.BaseSysConfService;
import com.cool.modules.base.service.sys.BaseSysLogService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
/**
* 系统日志
*/
@RequiredArgsConstructor
@Tag(name = "系统日志", description = "系统日志")
@CoolRestController(api = {"page"})
public class AdminBaseSysLogController extends BaseController<BaseSysLogService, BaseSysLogEntity> {
private final BaseSysConfService baseSysConfService;
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setPageOption(
createOp()
.keyWordLikeFields(
BaseSysUserEntityTableDef.BASE_SYS_USER_ENTITY.NAME,
BaseSysLogEntityTableDef.BASE_SYS_LOG_ENTITY.PARAMS));
}
@Operation(summary = "清理日志")
@PostMapping("/clear")
public R clear() {
service.clear(true);
return R.ok();
}
@Operation(summary = "设置日志保存时间")
@PostMapping("/setKeep")
public R setKeep(@RequestAttribute JSONObject requestParams) {
baseSysConfService.updateValue("logKeep", requestParams.getStr("value"));
return R.ok();
}
@Operation(summary = "获得日志报错时间")
@PostMapping("/getKeep")
public R getKeep() {
return R.ok(baseSysConfService.getValue("logKeep"));
}
}
@@ -0,0 +1,56 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.request.R;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import com.cool.modules.base.service.sys.BaseSysMenuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
/**
* 系统菜单
*/
@Tag(name = "系统菜单", description = "系统菜单")
@CoolRestController(api = {"add", "delete", "update", "page", "list", "info"})
public class AdminBaseSysMenuController extends
BaseController<BaseSysMenuService, BaseSysMenuEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@Operation(summary = "创建代码", description = "创建代码")
@PostMapping("/create")
public R create(@RequestBody() Map<String, Object> params) {
CoolPreconditions.checkEmpty(params.get("module"), "module参数不能为空");
CoolPreconditions.checkEmpty(params.get("entity"), "entity参数不能为空");
CoolPreconditions.checkEmpty(params.get("controller"), "controller参数不能为空");
CoolPreconditions.checkEmpty(params.get("service"), "service参数不能为空");
CoolPreconditions.checkEmpty(params.get("service-impl"), "service-impl参数不能为空");
CoolPreconditions.checkEmpty(params.get("mapper"), "mapper参数不能为空");
CoolPreconditions.checkEmpty(params.get("fileName"), "fileName参数不能为空");
this.service.create(params);
return R.ok();
}
@Operation(summary = "导出", description = "导出")
@PostMapping("/export")
public R export(@RequestBody Map<String, Object> params) {
return R.ok(this.service.export(getIds(params)));
}
@Operation(summary = "导入", description = "导入")
@PostMapping("/import")
public R importMenu(@RequestBody Map<String, List<BaseSysMenuEntity>> params) {
CoolPreconditions.checkEmpty(params.get("menus"), "参数不能为空");
return R.ok(this.service.importMenu(params.get("menus")));
}
}
@@ -0,0 +1,30 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.modules.base.entity.sys.BaseSysParamEntity;
import com.cool.modules.base.service.sys.BaseSysParamService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import jakarta.servlet.http.HttpServletRequest;
/**
* 系统参数配置
*/
@Tag(name = "系统参数配置", description = "系统参数配置")
@CoolRestController(api = { "add", "delete", "update", "page", "info" })
public class AdminBaseSysParamController extends BaseController<BaseSysParamService, BaseSysParamEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@Operation(summary = "根据键返回网页的参数值")
@GetMapping("/html")
public String html(String key) {
return service.htmlByKey(key);
}
}
@@ -0,0 +1,32 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
import static com.cool.modules.base.entity.sys.table.BaseSysRoleEntityTableDef.BASE_SYS_ROLE_ENTITY;
import com.cool.modules.base.service.sys.BaseSysRoleService;
import com.mybatisflex.core.query.QueryWrapper;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
/**
* 系统角色
*/
@Tag(name = "系统角色", description = "系统角色")
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
public class AdminBaseSysRoleController extends BaseController<BaseSysRoleService, BaseSysRoleEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
boolean isAdmin = tokenInfo.getStr("username").equals("admin");
setPageOption(createOp().keyWordLikeFields(BASE_SYS_ROLE_ENTITY.NAME, BASE_SYS_ROLE_ENTITY.LABEL).queryWrapper(QueryWrapper.create().and(qw -> {
qw.eq(BASE_SYS_ROLE_ENTITY.USER_ID.getName(), tokenInfo.get("userId")).or(w -> {
w.in(BASE_SYS_ROLE_ENTITY.ID.getName(), tokenInfo.get("roleIds"));
});
}, !isAdmin).and(BASE_SYS_ROLE_ENTITY.LABEL.ne("admin"))));
}
}
@@ -0,0 +1,34 @@
package com.cool.modules.base.controller.admin.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import jakarta.servlet.http.HttpServletRequest;
/**
* 系统用户
*/
@Tag(name = "系统用户", description = "系统用户")
@CoolRestController(api = { "add", "delete", "update", "page", "info" })
public class AdminBaseSysUserController extends BaseController<BaseSysUserService, BaseSysUserEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@Operation(summary = "移动部门")
@PostMapping("/move")
public R move(@RequestAttribute JSONObject requestParams) {
service.move(requestParams.getLong("departmentId"), requestParams.get("userIds", Long[].class));
return R.ok();
}
}
@@ -0,0 +1,26 @@
package com.cool.modules.base.controller.app;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.eps.CoolEps;
import com.cool.core.request.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
/**
* app通用接口
*/
@RequiredArgsConstructor
@Tag(name = "应用通用", description = "应用通用")
@CoolRestController
public class AppBaseCommController {
final private CoolEps coolEps;
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
return R.ok(coolEps.getApp());
}
}
@@ -0,0 +1,30 @@
package com.cool.modules.base.dto.sys;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
/**
* 登录
*/
@Data
@Schema(description = "登录参数")
public class BaseSysLoginDto {
@Schema(description = "用户名")
@NotBlank
private String username;
@Schema(description = "密码")
@NotBlank
private String password;
@Schema(description = "验证码ID")
@NotBlank
private String captchaId;
@Schema(description = "验证码")
@NotBlank
private String verifyCode;
}
@@ -0,0 +1,25 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.tangzc.autotable.annotation.enums.IndexTypeEnum;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import com.tangzc.autotable.annotation.Index;
import lombok.Getter;
import lombok.Setter;
/**
* 系统配置
*/
@Getter
@Setter
@Table(value = "base_sys_conf", comment = "系统配置表")
public class BaseSysConfEntity extends BaseEntity<BaseSysConfEntity> {
@Index(type = IndexTypeEnum.UNIQUE)
@ColumnDefine(comment = "配置键", notNull = true)
private String cKey;
@ColumnDefine(comment = "值", notNull = true, type = "text")
private String cValue;
}
@@ -0,0 +1,30 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
/**
* 系统部门
*/
@Getter
@Setter
@Table(value = "base_sys_department", comment = "系统部门")
public class BaseSysDepartmentEntity extends BaseEntity<BaseSysDepartmentEntity> {
@ColumnDefine(comment = "部门名称", notNull = true)
private String name;
@ColumnDefine(comment = "上级部门ID", type = "bigint")
private Long parentId;
@ColumnDefine(comment = "排序", defaultValue = "0")
private Integer orderNum;
// 父菜单名称
@Column(ignore = true)
private String parentName;
}
@@ -0,0 +1,34 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_log", comment = "系统日志表")
public class BaseSysLogEntity extends BaseEntity<BaseSysLogEntity> {
@Index
@ColumnDefine(comment = "用户ID", type = "bigint")
private Long userId;
@ColumnDefine(comment = "行为", length = 1000)
private String action;
@ColumnDefine(comment = "IP", length = 50)
private String ip;
@ColumnDefine(comment = "参数", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private Object params;
// 用户名称
@Column(ignore = true)
private String name;
}
@@ -0,0 +1,54 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@Table(value = "base_sys_menu", comment = "系统菜单表")
public class BaseSysMenuEntity extends BaseEntity<BaseSysMenuEntity> {
@Index
@ColumnDefine(comment = "父菜单ID", type = "bigint")
private Long parentId;
@ColumnDefine(comment = "菜单名称")
private String name;
@ColumnDefine(comment = "权限")
private String perms;
@ColumnDefine(comment = "类型 0:目录 1:菜单 2:按钮", type = "tinyint", defaultValue = "0")
private Integer type;
@ColumnDefine(comment = "图标")
private String icon;
@ColumnDefine(comment = "排序", defaultValue = "0")
private Integer orderNum;
@ColumnDefine(comment = "菜单地址")
private String router;
@ColumnDefine(comment = "视图地址")
private String viewPath;
@ColumnDefine(comment = "路由缓存", defaultValue = "true")
private Boolean keepAlive;
@ColumnDefine(comment = "是否显示", defaultValue = "true")
private Boolean isShow;
@Column(ignore = true)
private String parentName;
@Column(ignore = true)
private List<BaseSysMenuEntity> childMenus;
}
@@ -0,0 +1,30 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_param", comment = "系统参数配置")
public class BaseSysParamEntity extends BaseEntity<BaseSysParamEntity> {
@Index
@ColumnDefine(comment = "键", notNull = true)
private String keyName;
@ColumnDefine(comment = "名称")
private String name;
@ColumnDefine(comment = "数据", type = "text")
private String data;
@ColumnDefine(comment = "数据类型 0:字符串 1:数组 2:键值对", defaultValue = "0", type = "tinyint")
private Integer dataType;
@ColumnDefine(comment = "备注")
private String remark;
}
@@ -0,0 +1,20 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_role_department", comment = "系统角色部门")
public class BaseSysRoleDepartmentEntity extends BaseEntity<BaseSysRoleDepartmentEntity> {
@ColumnDefine(comment = "角色ID", type = "bigint")
private Long roleId;
@ColumnDefine(comment = "部门ID", type = "bigint")
private Long departmentId;
}
@@ -0,0 +1,43 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.autotable.annotation.enums.IndexTypeEnum;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_role", comment = "系统角色表")
public class BaseSysRoleEntity extends BaseEntity<BaseSysRoleEntity> {
@Index
@ColumnDefine(comment = "用户ID", notNull = true, type = "bigint")
private Long userId;
@ColumnDefine(comment = "名称", notNull = true)
private String name;
@Index(type = IndexTypeEnum.UNIQUE)
@ColumnDefine(comment = "角色标签", notNull = true)
private String label;
@ColumnDefine(comment = "备注")
private String remark;
@ColumnDefine(comment = "数据权限是否关联上下级", defaultValue = "1")
private Integer relevance;
@ColumnDefine(comment = "菜单权限", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private List<Long> menuIdList;
@ColumnDefine(comment = "部门权限", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private List<Long> departmentIdList;
}
@@ -0,0 +1,19 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_role_menu", comment = "系统角色菜单表")
public class BaseSysRoleMenuEntity extends BaseEntity<BaseSysRoleMenuEntity> {
@ColumnDefine(comment = "菜单", type = "bigint")
private Long menuId;
@ColumnDefine(comment = "角色ID", type = "bigint")
private Long roleId;
}
@@ -0,0 +1,63 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.autotable.annotation.enums.IndexTypeEnum;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import com.tangzc.autotable.annotation.Index;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_user", comment = "系统用户表")
public class BaseSysUserEntity extends BaseEntity<BaseSysUserEntity> {
@Index
@ColumnDefine(comment = "部门ID", type = "bigint")
private Long departmentId;
@ColumnDefine(comment = "姓名")
private String name;
@Index(type = IndexTypeEnum.UNIQUE)
@ColumnDefine(comment = "用户名", length = 100, notNull = true)
private String username;
@ColumnDefine(comment = "密码", notNull = true)
private String password;
@ColumnDefine(comment = "密码版本", defaultValue = "1")
private Integer passwordV;
@ColumnDefine(comment = "昵称", notNull = true)
private String nickName;
@ColumnDefine(comment = "头像")
private String headImg;
@ColumnDefine(comment = "手机号")
private String phone;
@ColumnDefine(comment = "邮箱")
private String email;
@ColumnDefine(comment = "备注")
private String remark;
@ColumnDefine(comment = "状态 0:禁用 1:启用", defaultValue = "1", type = "tinyint")
private Integer status;
// 部门名称
@Column(ignore = true)
private String departmentName;
// 角色名称
@Column(ignore = true)
private String roleName;
@ColumnDefine(comment = "socketId")
private String socketId;
}
@@ -0,0 +1,19 @@
package com.cool.modules.base.entity.sys;
import com.cool.core.base.BaseEntity;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "base_sys_user_role", comment = "系统用户角色表")
public class BaseSysUserRoleEntity extends BaseEntity<BaseSysUserRoleEntity> {
@ColumnDefine(comment = "用户ID", type = "bigint")
private Long userId;
@ColumnDefine(comment = "角色ID", type = "bigint")
private Long roleId;
}
@@ -0,0 +1,33 @@
package com.cool.modules.base.filter;
import cn.hutool.json.JSONObject;
import com.cool.modules.base.service.sys.BaseSysLogService;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(10)
@RequiredArgsConstructor
public class BaseLogFilter implements Filter {
final private BaseSysLogService baseSysLogService;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
// 记录日志
HttpServletRequest request = (HttpServletRequest) servletRequest;
baseSysLogService.record(request, (JSONObject) request.getAttribute("requestParams"));
filterChain.doFilter(servletRequest, servletResponse);
}
}
@@ -0,0 +1,11 @@
package com.cool.modules.base.mapper.sys;
import com.cool.modules.base.entity.sys.BaseSysConfEntity;
import com.mybatisflex.core.BaseMapper;
/**
* 系统配置
*/
public interface BaseSysConfMapper extends BaseMapper<BaseSysConfEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
/**
* 系统部门
*/
public interface BaseSysDepartmentMapper extends BaseMapper<BaseSysDepartmentEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysLogEntity;
/**
* 系统日志
*/
public interface BaseSysLogMapper extends BaseMapper<BaseSysLogEntity> {
}
@@ -0,0 +1,20 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 系统菜单
*/
public interface BaseSysMenuMapper extends BaseMapper<BaseSysMenuEntity> {
/**
* 根据角色ID获得所有菜单
*
* @param roleIds 角色ID集合
* @return SysMenuEntity
*/
List<BaseSysMenuEntity> getMenus(@Param("roleIds") Long[] roleIds);
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysParamEntity;
/**
* 系统参数配置
*/
public interface BaseSysParamMapper extends BaseMapper<BaseSysParamEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
/**
* 系统角色部门
*/
public interface BaseSysRoleDepartmentMapper extends BaseMapper<BaseSysRoleDepartmentEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
/**
* 系统角色
*/
public interface BaseSysRoleMapper extends BaseMapper<BaseSysRoleEntity> {
}
@@ -0,0 +1,18 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
import org.apache.ibatis.annotations.Param;
/**
* 系统角色菜单
*/
public interface BaseSysRoleMenuMapper extends BaseMapper<BaseSysRoleMenuEntity> {
/**
* 跟菜单关联的所有用户
*
* @param menuId 菜单
* @return 所有用户ID
*/
Long[] userIds(@Param("menuId") Long menuId);
}
@@ -0,0 +1,11 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
/**
* 系统用户
*/
public interface BaseSysUserMapper extends BaseMapper<BaseSysUserEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.mapper.sys;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.base.entity.sys.BaseSysUserRoleEntity;
/**
* 系统用户角色
*/
public interface BaseSysUserRoleMapper extends BaseMapper<BaseSysUserRoleEntity> {
}
@@ -0,0 +1,63 @@
package com.cool.modules.base.security;
import cn.hutool.json.JSONObject;
import com.cool.core.cache.CoolCache;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
/**
* Security 工具类
*/
@Component
@RequiredArgsConstructor
public class CoolSecurityUtil {
final private CoolCache coolCache;
/**
* 登录的用户名
*
* @return 用户名
*/
public String username() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
/**
* 获得jwt中的信息
*
* @param requestParams 请求参数
* @return jwt
*/
public JSONObject userInfo(JSONObject requestParams) {
JSONObject tokenInfo = requestParams.getJSONObject("tokenInfo");
if (tokenInfo != null) {
tokenInfo.set("department",
coolCache.get("admin:department:" + tokenInfo.get("userId")));
tokenInfo.set("roleIds", coolCache.get("admin:roleIds:" + tokenInfo.get("userId")));
}
return tokenInfo;
}
/**
* 退出登录
*
* @param adminUserId 用户ID
* @param username 用户名
*/
public void logout(Long adminUserId, String username) {
coolCache.del("admin:department:" + adminUserId, "admin:passwordVersion:" + adminUserId,
"admin:userInfo:" + adminUserId, "admin:userDetails:" + username);
}
/**
* 退出登录
*
* @param userEntity 用户
*/
public void logout(BaseSysUserEntity userEntity) {
logout(userEntity.getId(), userEntity.getUsername());
}
}
@@ -0,0 +1,65 @@
package com.cool.modules.base.security;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.cool.core.cache.CoolCache;
import com.cool.core.security.jwt.JwtTokenUtil;
import com.cool.core.security.jwt.JwtUser;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Token过滤器
*/
@Order(1)
@Component
@RequiredArgsConstructor
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
final private JwtTokenUtil jwtTokenUtil;
final private CoolCache coolCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
String authToken = request.getHeader("Authorization");
if (!StrUtil.isEmpty(authToken)) {
JWT jwt = jwtTokenUtil.getTokenInfo(authToken);
String username = jwt.getPayload("username").toString();
if (username != null
&& SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = coolCache.get("admin:userDetails:" + username,
JwtUser.class);
Integer passwordV = Convert.toInt(jwt.getPayload("passwordVersion"));
Integer rv = coolCache.get("admin:passwordVersion:" + jwt.getPayload("userId"),
Integer.class);
if (jwtTokenUtil.validateToken(authToken, username) && Objects.equals(passwordV, rv)
&& userDetails != null) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
request.setAttribute("adminUsername", jwt.getPayload("username"));
request.setAttribute("adminUserId", jwt.getPayload("userId"));
request.setAttribute("tokenInfo", jwt);
}
}
}
chain.doFilter(request, response);
}
}
@@ -0,0 +1,57 @@
package com.cool.modules.base.security;
import cn.hutool.core.util.ObjectUtil;
import com.cool.core.cache.CoolCache;
import com.cool.core.security.jwt.JwtUser;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.cool.modules.base.service.sys.BaseSysUserService;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
/**
* 获得用户信息
*/
@Component
@RequiredArgsConstructor
public class JwtUserDetailsServiceImpl implements UserDetailsService {
final private BaseSysUserService baseSysUserService;
final private BaseSysPermsService baseSysPermsService;
final private CoolCache coolCache;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
BaseSysUserEntity sysUserEntity = baseSysUserService.getMapper().selectOneByQuery(
QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username)
.eq(BaseSysUserEntity::getStatus, 1));
if (ObjectUtil.isEmpty(sysUserEntity)) {
throw new UsernameNotFoundException("用户名不存在");
}
List<GrantedAuthority> authority = new ArrayList<>();
String[] perms = baseSysPermsService.getPerms(sysUserEntity.getId());
for (String perm : perms) {
authority.add(new SimpleGrantedAuthority(perm));
}
Long[] departmentIds = baseSysPermsService.getDepartmentIdsByRoleIds(sysUserEntity.getId());
JwtUser jwtUser = new JwtUser(sysUserEntity.getUsername(), sysUserEntity.getPassword(),
authority,
sysUserEntity.getStatus() == 1);
Long[] roleIds = baseSysPermsService.getRoles(sysUserEntity);
coolCache.set("admin:userDetails:" + jwtUser.getUsername(), jwtUser);
coolCache.set("admin:passwordVersion:" + sysUserEntity.getId(),
sysUserEntity.getPasswordV());
coolCache.set("admin:userInfo:" + sysUserEntity.getId(), sysUserEntity);
coolCache.set("admin:department:" + sysUserEntity.getId(), departmentIds);
coolCache.set("admin:roleIds:" + sysUserEntity.getId(), roleIds);
return jwtUser;
}
}
@@ -0,0 +1,74 @@
package com.cool.modules.base.security;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
/**
* 权限资源管理器 为权限决断器提供支持
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
final private BaseSysPermsService baseSysPermsService;
private Map<String, Collection<ConfigAttribute>> map = null;
/**
* 加载权限表中所有操作请求权限
*/
public void loadResourceDefine() {
map = new HashMap<>();
Collection<ConfigAttribute> configAttributes;
ConfigAttribute cfg;
String[] perms = baseSysPermsService.getAllPerms();
// 获取启用的权限操作请求
for (String perm : perms) {
configAttributes = new ArrayList<>();
cfg = new SecurityConfig(perm);
// 作为MyAccessDecisionManager类的decide的第三个参数
configAttributes.add(cfg);
// 用权限的path作为map的key,用ConfigAttribute的集合作为value
map.put(perm.replaceAll(":", "/"), configAttributes);
}
}
/**
* 判定用户请求的url是否在权限表中 如果在权限表中,则返回给decide方法,用来判定用户是否有此权限 如果不在权限表中则放行
*
* @param o
* @return
* @throws IllegalArgumentException
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
if (map == null) {
loadResourceDefine();
}
// Object中包含用户请求request
String url = ((FilterInvocation) o).getRequestUrl();
return map.get(url.replace("/admin/", "").split("[?]")[0]);
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return new ArrayList<>();
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
@@ -0,0 +1,41 @@
package com.cool.modules.base.service.sys;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysConfEntity;
/**
* 系统配置
*/
public interface BaseSysConfService extends BaseService<BaseSysConfEntity> {
/**
* 更新配置
*
* @param key 键
* @param value 值
*/
void updateValue(String key, String value);
/**
* 获得值
*
* @param key 键
* @return 值
*/
String getValue(String key);
/**
* 获得值(带缓存)
*
* @param key 键
* @return 值
*/
String getValueWithCache(String key);
/**
* 设置值
*
* @param key 键
* @param value 值
*/
void setValue(String key, String value);
}
@@ -0,0 +1,18 @@
package com.cool.modules.base.service.sys;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import java.util.List;
/**
* 系统部门
*/
public interface BaseSysDepartmentService extends BaseService<BaseSysDepartmentEntity> {
/**
* 排序
*
* @param list 新的排序
*/
void order(List<BaseSysDepartmentEntity> list);
}
@@ -0,0 +1,27 @@
package com.cool.modules.base.service.sys;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysLogEntity;
import jakarta.servlet.http.HttpServletRequest;
/**
* 系统日志
*/
public interface BaseSysLogService extends BaseService<BaseSysLogEntity> {
/**
* 清理日志
*
* @param isAll 是否全部清除
*/
void clear(boolean isAll);
/**
* 日志记录
*
* @param requestParams 请求参数
* @param request 请求
*/
void record(HttpServletRequest request, JSONObject requestParams);
}
@@ -0,0 +1,42 @@
package com.cool.modules.base.service.sys;
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
/**
* 系统登录
*/
public interface BaseSysLoginService {
/**
* 验证码
*
* @param type 类型 svg base64 svg是node版本的, java版本用base64, svg未实现
* @param width 宽度
* @param height 高度
* @return base64 验证码与ID
*/
Object captcha(String type, Integer width, Integer height);
/**
* 登录
*
* @param baseSysLoginDto 登录必要信息
* @return token与相关的过期信息
*/
Object login(BaseSysLoginDto baseSysLoginDto);
/**
* 退出登录
*
* @param adminUserId 用户ID
* @param username 用户名称
*/
void logout(Long adminUserId, String username);
/**
* 刷新token
*
* @param refreshToken 刷新token
* @return 新的token
*/
Object refreshToken(String refreshToken);
}
@@ -0,0 +1,18 @@
package com.cool.modules.base.service.sys;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import java.util.List;
import java.util.Map;
/**
* 系统菜单
*/
public interface BaseSysMenuService extends BaseService<BaseSysMenuEntity> {
Object export(List<Long> ids);
boolean importMenu(List<BaseSysMenuEntity> menus);
void create(Map<String, Object> params);
}
@@ -0,0 +1,25 @@
package com.cool.modules.base.service.sys;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysParamEntity;
/**
* 系统参数配置
*/
public interface BaseSysParamService extends BaseService<BaseSysParamEntity> {
/**
* 根据key获得网页内容
*
* @param key 键
* @return 网页内容
*/
String htmlByKey(String key);
/**
* 根据key获得数据
*
* @param key 键
* @return 数据
*/
String dataByKey(String key);
}
@@ -0,0 +1,160 @@
package com.cool.modules.base.service.sys;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import java.util.List;
/**
* 权限菜单
*/
public interface BaseSysPermsService {
/**
* 获得权限缓存
*
* @param userId 用户ID
* @return 返回用户相关的权限信息
*/
String[] getPermsCache(Long userId);
/**
* 获得权限
*
* @param userId 用户ID
* @return 返回用户相关的权限信息
*/
String[] getPerms(Long userId);
/**
* 获得权限
*
* @param roleIds 用户角色数组
* @return 返回用户相关的权限信息
*/
String[] getPerms(Long[] roleIds);
/**
* 获得菜单
*
* @param roleIds 角色
* @return 返回菜单
*/
List<BaseSysMenuEntity> getMenus(Long[] roleIds);
/**
* 获得菜单
*
* @param userId 用户ID
* @return 返回菜单
*/
List<BaseSysMenuEntity> getMenus(Long userId);
/**
* 获得菜单
*
* @param username 用户名
* @return 返回菜单
*/
List<BaseSysMenuEntity> getMenus(String username);
/**
* 获得角色数组
*
* @param userId 用户ID
* @return 返回角色数组
*/
Long[] getRoles(Long userId);
/**
* 获得角色数组
*
* @param username 用户名
* @return 返回角色数组
*/
Long[] getRoles(String username);
/**
* 获得登录用户的部门权限
*
* @return 部门ID集合
*/
Long[] loginDepartmentIds();
/**
* 根据角色获得部门ID
*
* @param roleIds 角色ID数组
* @return 部门ID数组
*/
Long[] getDepartmentIdsByRoleIds(Long[] roleIds);
/**
* 根据用户ID获得部门ID
*
* @param userId 角色ID数组
* @return 部门ID数组
*/
Long[] getDepartmentIdsByRoleIds(Long userId);
/**
* 获得角色数组
*
* @param userEntity 用户
* @return 返回角色数组
*/
Long[] getRoles(BaseSysUserEntity userEntity);
/**
* 所有的操作权限
*
* @return 返回所有的操作权限
*/
String[] getAllPerms();
/**
* 用户的权限菜单
*
* @param adminUserId 登录的用户
* @return 权限菜单
*/
Object permmenu(Long adminUserId);
/**
* 更新角色权限
*
* @param roleId 角色ID
* @param menuIdList 菜单ID
* @param departmentIds 部门ID
*/
void updatePerms(Long roleId, Long[] menuIdList, Long[] departmentIds);
/**
* 更新用户角色
*
* @param userId 用户ID
* @param roleIdList 角色集合
*/
void updateUserRole(Long userId, Long[] roleIdList);
/**
* 刷新权限
*
* @param userId 用户ID
*/
void refreshPerms(Long userId);
/**
* 刷新权限
*
* @param menuId 用户ID
*/
void refreshPermsByMenuId(Long menuId);
/**
* 刷新权限
*
* @param roleId 角色ID
*/
void refreshPermsByRoleId(Long roleId);
}
@@ -0,0 +1,10 @@
package com.cool.modules.base.service.sys;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
/**
* 系统角色
*/
public interface BaseSysRoleService extends BaseService<BaseSysRoleEntity> {
}
@@ -0,0 +1,25 @@
package com.cool.modules.base.service.sys;
import cn.hutool.core.lang.Dict;
import com.cool.core.base.BaseService;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
/**
* 系统用户
*/
public interface BaseSysUserService extends BaseService<BaseSysUserEntity> {
/**
* 修改用户信息
*
* @param body 用户信息
*/
void personUpdate(Long userId, Dict body);
/**
* 移动部门
*
* @param departmentId 部门ID
* @param userIds 用户ID集合
*/
void move(Long departmentId, Long[] userIds);
}
@@ -0,0 +1,58 @@
package com.cool.modules.base.service.sys.impl;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.cache.CoolCache;
import com.cool.modules.base.entity.sys.BaseSysConfEntity;
import com.cool.modules.base.mapper.sys.BaseSysConfMapper;
import com.cool.modules.base.service.sys.BaseSysConfService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 系统配置
*/
@Service
@RequiredArgsConstructor
public class BaseSysConfServiceImpl extends BaseServiceImpl<BaseSysConfMapper, BaseSysConfEntity>
implements BaseSysConfService {
private final CoolCache coolCache;
@Override
public void updateValue(String key, String value) {
UpdateChain.of(BaseSysConfEntity.class).set(BaseSysConfEntity::getCValue, value)
.eq(BaseSysConfEntity::getCKey, key).update();
}
@Override
public String getValue(String key) {
BaseSysConfEntity baseSysConfEntity = getOne(QueryWrapper.create().eq(BaseSysConfEntity::getCKey, key));
if (baseSysConfEntity != null) {
return baseSysConfEntity.getCValue();
}
return null;
}
@Override
public String getValueWithCache(String key) {
String value = coolCache.get(key, String.class);
if (value != null) {
return value;
}
value = getValue(key);
if (value != null) {
coolCache.set(key, value);
}
return value;
}
@Override
public void setValue(String key, String value) {
BaseSysConfEntity baseSysConfEntity = new BaseSysConfEntity();
baseSysConfEntity.setCKey(key);
baseSysConfEntity.setCValue(value);
save(baseSysConfEntity);
}
}
@@ -0,0 +1,85 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysDepartmentService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 系统部门
*/
@RequiredArgsConstructor
@Service
public class BaseSysDepartmentServiceImpl extends
BaseServiceImpl<BaseSysDepartmentMapper, BaseSysDepartmentEntity>
implements BaseSysDepartmentService {
final private BaseSysUserMapper baseSysUserMapper;
final private CoolSecurityUtil coolSecurityUtil;
final private BaseSysPermsService baseSysPermsService;
@Override
public void order(List<BaseSysDepartmentEntity> list) {
list.forEach(baseSysDepartmentEntity -> {
UpdateChain.of(BaseSysDepartmentEntity.class)
.set(BaseSysDepartmentEntity::getOrderNum, baseSysDepartmentEntity.getOrderNum())
.eq(BaseSysDepartmentEntity::getId, baseSysDepartmentEntity.getId()).update();
});
}
@Override
public List<BaseSysDepartmentEntity> list(JSONObject requestParams, QueryWrapper queryWrapper) {
String username = coolSecurityUtil.username();
Long[] loginDepartmentIds = baseSysPermsService.loginDepartmentIds();
if (loginDepartmentIds != null && loginDepartmentIds.length == 0) {
return new ArrayList<>();
}
List<BaseSysDepartmentEntity> list = this.list(
QueryWrapper.create()
.in(BaseSysDepartmentEntity::getId, loginDepartmentIds, !username.equals("admin"))
.orderBy(BaseSysDepartmentEntity::getOrderNum, false));
list.forEach(e -> {
List<BaseSysDepartmentEntity> parentDepartment = list.stream()
.filter(sysDepartmentEntity -> e.getParentId() != null
&& e.getParentId().equals(sysDepartmentEntity.getId()))
.toList();
if (!parentDepartment.isEmpty()) {
e.setParentName(parentDepartment.get(0).getName());
}
});
return list;
}
@Override
public boolean delete(JSONObject requestParams, Long... ids) {
super.delete(ids);
// 是否删除对应用户 否则移动到顶层部门
if (requestParams.getBool("deleteUser")) {
return baseSysUserMapper
.deleteByQuery(
QueryWrapper.create().in(BaseSysUserEntity::getDepartmentId, (Object) ids)) > 0;
} else {
BaseSysDepartmentEntity topDepartment = getOne(
QueryWrapper.create().isNull(BaseSysDepartmentEntity::getParentId));
if (topDepartment != null) {
UpdateChain.of(BaseSysUserEntity.class)
.set(BaseSysUserEntity::getDepartmentId, topDepartment.getId())
.in(BaseSysUserEntity::getDepartmentId, (Object) ids).update();
}
}
return false;
}
}
@@ -0,0 +1,95 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.util.IPUtils;
import com.cool.modules.base.entity.sys.BaseSysLogEntity;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.entity.sys.table.BaseSysLogEntityTableDef;
import com.cool.modules.base.entity.sys.table.BaseSysUserEntityTableDef;
import com.cool.modules.base.mapper.sys.BaseSysLogMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysConfService;
import com.cool.modules.base.service.sys.BaseSysLogService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* 系统日志
*/
@RequiredArgsConstructor
@Service
public class BaseSysLogServiceImpl extends BaseServiceImpl<BaseSysLogMapper, BaseSysLogEntity>
implements BaseSysLogService {
private final BaseSysConfService baseSysConfService;
private final CoolSecurityUtil coolSecurityUtil;
private final IPUtils ipUtils;
@Override
public Object page(
JSONObject requestParams, Page<BaseSysLogEntity> page, QueryWrapper queryWrapper) {
queryWrapper
.select(
BaseSysLogEntityTableDef.BASE_SYS_LOG_ENTITY.ALL_COLUMNS,
BaseSysUserEntityTableDef.BASE_SYS_USER_ENTITY.NAME)
.from(BaseSysLogEntityTableDef.BASE_SYS_LOG_ENTITY)
.leftJoin(BaseSysUserEntityTableDef.BASE_SYS_USER_ENTITY)
.on(BaseSysLogEntity::getUserId, BaseSysUserEntity::getId);
return mapper.paginate(page, queryWrapper);
}
@Override
public void clear(boolean isAll) {
if (isAll) {
this.remove(QueryWrapper.create().ge(BaseSysLogEntity::getId, 0));
} else {
String keepDay = baseSysConfService.getValue("logKeep");
int keepDays = Integer.parseInt(StrUtil.isNotEmpty(keepDay) ? keepDay : "30");
Date beforeDate = DateUtil.offsetDay(new Date(), -keepDays);
this.remove(QueryWrapper.create().lt(BaseSysLogEntity::getCreateTime, beforeDate));
}
}
@Override
public void record(HttpServletRequest request, JSONObject requestParams) {
String requestURI = request.getRequestURI();
String ipAddr = ipUtils.getIpAddr(request);
JSONObject userInfo = coolSecurityUtil.userInfo(requestParams);
Long userId = null;
if (userInfo != null) {
userId = userInfo.getLong("userId");
}
JSONObject newJSONObject = JSONUtil.parseObj(JSONUtil.toJsonStr(requestParams));
newJSONObject.remove("tokenInfo");
newJSONObject.remove("refreshToken");
newJSONObject.remove("body");
recordAsync(requestURI, ipAddr, userId, newJSONObject);
}
@Async
public void recordAsync(String requestURI, String ip, Long userId, JSONObject params) {
BaseSysLogEntity logEntity = new BaseSysLogEntity();
logEntity.setAction(requestURI);
logEntity.setIp(ip);
if (userId != null) {
logEntity.setUserId(userId);
}
logEntity.setParams(params);
save(logEntity);
}
}
@@ -0,0 +1,137 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.GifCaptcha;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.cool.core.cache.CoolCache;
import com.cool.core.exception.CoolException;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.security.jwt.JwtTokenUtil;
import com.cool.modules.base.dto.sys.BaseSysLoginDto;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysLoginService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class BaseSysLoginServiceImpl implements BaseSysLoginService {
private final CoolCache coolCache;
private final AuthenticationManager authenticationManager;
private final CoolSecurityUtil coolSecurityUtil;
private final JwtTokenUtil jwtTokenUtil;
private final BaseSysUserMapper baseSysUserMapper;
private final BaseSysPermsService baseSysPermsService;
@Override
public Object captcha(String type, Integer width, Integer height) {
// 1、生成验证码 2、生成对应的ID并设置在缓存中,验证码过期时间30分钟;
Map<String, Object> result = new HashMap<>();
String captchaId = StrUtil.uuid();
result.put("captchaId", captchaId);
RandomGenerator randomGenerator = new RandomGenerator(4);
GifCaptcha gifCaptcha = CaptchaUtil.createGifCaptcha(width, height);
gifCaptcha.setGenerator(randomGenerator);
gifCaptcha.setBackground(new Color(248, 248, 248));
gifCaptcha.setMaxColor(60);
gifCaptcha.setMinColor(55);
result.put("data", "data:image/png;base64," + gifCaptcha.getImageBase64());
coolCache.set("verify:img:" + captchaId, gifCaptcha.getCode(), 1800);
return result;
}
@Override
public Object login(BaseSysLoginDto baseSysLoginDto) {
// 1、检查验证码是否正确 2、执行登录操作
String verifyCode = coolCache.get("verify:img:" + baseSysLoginDto.getCaptchaId(),
String.class);
if (StrUtil.isNotEmpty(verifyCode)
&& verifyCode.equalsIgnoreCase(baseSysLoginDto.getVerifyCode())) {
UsernamePasswordAuthenticationToken upToken =
new UsernamePasswordAuthenticationToken(
baseSysLoginDto.getUsername(), baseSysLoginDto.getPassword());
Authentication authentication = authenticationManager.authenticate(upToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 查询用户信息并生成token
BaseSysUserEntity sysUserEntity =
baseSysUserMapper.selectOneByQuery(
QueryWrapper.create()
.eq(BaseSysUserEntity::getUsername, baseSysLoginDto.getUsername()));
CoolPreconditions.check(
ObjectUtil.isEmpty(sysUserEntity) || sysUserEntity.getStatus() == 0, "用户已禁用");
Long[] roleIds = baseSysPermsService.getRoles(sysUserEntity);
Dict tokenInfo =
Dict.create()
.set("roleIds", roleIds)
.set("username", baseSysLoginDto.getUsername())
.set("userId", sysUserEntity.getId())
.set("passwordVersion", sysUserEntity.getPasswordV());
String token = jwtTokenUtil.generateToken(tokenInfo);
String refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
coolCache.del("verify:img:" + baseSysLoginDto.getCaptchaId());
return Dict.create()
.set("token", token)
.set("expire", jwtTokenUtil.getExpire())
.set("refreshToken", refreshToken)
.set("refreshExpire", jwtTokenUtil.getRefreshExpire());
} else {
coolCache.del("verify:img:" + baseSysLoginDto.getCaptchaId());
throw new CoolException("验证码不正确");
}
}
@Override
public void logout(Long adminUserId, String username) {
coolSecurityUtil.logout(adminUserId, username);
}
@Override
public Object refreshToken(String refreshToken) {
JWT jwt = jwtTokenUtil.getTokenInfo(refreshToken);
try {
CoolPreconditions.check(jwt == null || !(Boolean) jwt.getPayload("isRefresh"),
"错误的token");
BaseSysUserEntity baseSysUserEntity =
baseSysUserMapper.selectOneById(Convert.toLong(jwt.getPayload("userId")));
Long[] roleIds = baseSysPermsService.getRoles(baseSysUserEntity);
Dict tokenInfo =
Dict.create()
.set("roleIds", roleIds)
.set("username", baseSysUserEntity.getUsername())
.set("userId", baseSysUserEntity.getId())
.set("passwordVersion", baseSysUserEntity.getPasswordV());
String token = jwtTokenUtil.generateToken(tokenInfo);
refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
return Dict.create()
.set("token", token)
.set("expire", jwtTokenUtil.getExpire())
.set("refreshToken", refreshToken)
.set("refreshExpire", jwtTokenUtil.getRefreshExpire());
} catch (Exception e) {
throw new CoolException("错误的token", e);
}
}
}
@@ -0,0 +1,170 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.base.ModifyEnum;
import com.cool.core.util.CompilerUtils;
import com.cool.core.util.PathUtils;
import com.cool.modules.base.entity.sys.BaseSysMenuEntity;
import com.cool.modules.base.mapper.sys.BaseSysMenuMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysMenuService;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 系统菜单
*/
@Service
@RequiredArgsConstructor
public class BaseSysMenuServiceImpl extends BaseServiceImpl<BaseSysMenuMapper, BaseSysMenuEntity>
implements BaseSysMenuService {
final private BaseSysPermsService baseSysPermsService;
final private CoolSecurityUtil coolSecurityUtil;
@Override
public Object list(JSONObject requestParams, QueryWrapper queryWrapper) {
List<BaseSysMenuEntity> list = baseSysPermsService.getMenus(coolSecurityUtil.username());
list.forEach(e -> {
List<BaseSysMenuEntity> parent = list.stream()
.filter(sysMenuEntity -> e.getParentId() != null && e.getParentId()
.equals(sysMenuEntity.getId()))
.toList();
if (!parent.isEmpty()) {
e.setParentName(parent.get(0).getName());
}
});
return list;
}
@Override
public void modifyAfter(JSONObject requestParams, BaseSysMenuEntity sysMenuEntity,
ModifyEnum type) {
if (sysMenuEntity != null && sysMenuEntity.getId() != null) {
baseSysPermsService.refreshPermsByMenuId(requestParams.getLong("id"));
}
if (requestParams.get("ids") != null) {
Long[] ids = requestParams.get("ids", Long[].class);
for (Long id : ids) {
baseSysPermsService.refreshPermsByMenuId(id);
}
}
}
@Override
public boolean delete(Long... ids) {
super.delete(ids);
for (Long id : ids) {
this.delChildMenu(id);
}
return true;
}
/**
* 删除子菜单
*
* @param id 删除的菜单ID
*/
private void delChildMenu(Long id) {
List<BaseSysMenuEntity> delMenu = list(
QueryWrapper.create().eq(BaseSysMenuEntity::getParentId, id));
if (CollectionUtil.isEmpty(delMenu)) {
return;
}
Long[] ids = delMenu.stream().map(BaseSysMenuEntity::getId).toArray(Long[]::new);
if (ArrayUtil.isNotEmpty(ids)) {
delete(ids);
for (Long delId : ids) {
this.delChildMenu(delId);
}
}
}
@Override
public Object export(List<Long> ids) {
List<BaseSysMenuEntity> list = list(
QueryWrapper.create().in(BaseSysMenuEntity::getId, ids));
List<BaseSysMenuEntity> parentList = list.stream()
.filter(o -> ObjUtil.isEmpty(o.getParentId())).toList();
Map<Long, List<BaseSysMenuEntity>> map = list.stream()
.filter(o -> ObjUtil.isNotEmpty(o.getParentId()))
.collect(Collectors.groupingBy(BaseSysMenuEntity::getParentId));
parentList.forEach(o -> handler(o, map));
return parentList;
}
private void handler(BaseSysMenuEntity parentBaseSysMenuEntity,
Map<Long, List<BaseSysMenuEntity>> map) {
parentBaseSysMenuEntity.setChildMenus(
map.getOrDefault(parentBaseSysMenuEntity.getId(), new ArrayList<>()));
parentBaseSysMenuEntity.getChildMenus().forEach(o -> {
handler(o, map);
o.setId(null);
o.setParentId(null);
o.setCreateTime(null);
o.setUpdateTime(null);
});
parentBaseSysMenuEntity.setId(null);
parentBaseSysMenuEntity.setParentId(null);
parentBaseSysMenuEntity.setCreateTime(null);
parentBaseSysMenuEntity.setUpdateTime(null);
}
@Override
public boolean importMenu(List<BaseSysMenuEntity> menus) {
menus.forEach(this::importMenu);
return true;
}
private void importMenu(BaseSysMenuEntity sysMenuEntity) {
sysMenuEntity.save();
if (ObjUtil.isNotEmpty(sysMenuEntity.getChildMenus())) {
sysMenuEntity.getChildMenus().forEach(o -> {
o.setParentId(sysMenuEntity.getId());
importMenu(o);
});
}
}
@Override
public void create(Map<String, Object> params) {
String module = (String) params.get("module");
String controller = (String) params.get("controller");
String entity = (String) params.get("entity");
String service = (String) params.get("service");
String serviceImpl = (String) params.get("service-impl");
String mapper = (String) params.get("mapper");
String fileName = (String) params.get("fileName");
String modulesPath = PathUtils.getModulesPath();
// 创建的模块地址
String actModulePath = CompilerUtils.createModule(modulesPath, module);
// 创建 controller
CompilerUtils.createController(actModulePath, fileName, controller);
// 创建 entity
String entityPath = CompilerUtils.createEntity(actModulePath, fileName, entity);
// 创建 service
CompilerUtils.createService(actModulePath, fileName, service);
// 创建 serviceImpl
CompilerUtils.createServiceImpl(actModulePath, fileName, serviceImpl);
// 创建 mapper
CompilerUtils.createMapper(actModulePath, fileName, mapper);
// 关闭springboot
System.exit(0);
// 构建TableDef
// CompilerUtils.compilerEntityTableDef(entityPath);
// 重启
// CoolApplication.restart();
}
}
@@ -0,0 +1,53 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.cache.CoolCache;
import com.cool.modules.base.entity.sys.BaseSysParamEntity;
import com.cool.modules.base.mapper.sys.BaseSysParamMapper;
import com.cool.modules.base.service.sys.BaseSysParamService;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 系统参数配置
*/
@Service
@RequiredArgsConstructor
public class BaseSysParamServiceImpl extends BaseServiceImpl<BaseSysParamMapper, BaseSysParamEntity>
implements BaseSysParamService {
final private CoolCache coolCache;
@Override
public String htmlByKey(String key) {
String data = dataByKey(key);
return "<html><body>" + (StrUtil.isNotEmpty(data) ? data : "key notfound")
+ "</body></html>";
}
@Override
public String dataByKey(String key) {
BaseSysParamEntity baseSysParamEntity = coolCache.get(key, BaseSysParamEntity.class);
if (baseSysParamEntity == null) {
baseSysParamEntity = getOne(
QueryWrapper.create().eq(BaseSysParamEntity::getKeyName, key));
}
if (baseSysParamEntity != null) {
coolCache.set("param:" + baseSysParamEntity.getKeyName(), baseSysParamEntity);
return baseSysParamEntity.getData();
}
return null;
}
@Override
public void modifyAfter(JSONObject requestParams, BaseSysParamEntity baseSysParamEntity) {
List<BaseSysParamEntity> list = this.list();
list.forEach(e -> {
coolCache.set("param:" + e.getKeyName(), e);
});
}
}
@@ -0,0 +1,246 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.cool.core.cache.CoolCache;
import com.cool.core.util.SpringContextUtils;
import com.cool.modules.base.entity.sys.*;
import com.cool.modules.base.mapper.sys.*;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
import java.util.*;
import static com.cool.modules.base.entity.sys.table.BaseSysMenuEntityTableDef.BASE_SYS_MENU_ENTITY;
import static com.cool.modules.base.entity.sys.table.BaseSysRoleMenuEntityTableDef.BASE_SYS_ROLE_MENU_ENTITY;
import static com.cool.modules.base.entity.sys.table.BaseSysUserRoleEntityTableDef.BASE_SYS_USER_ROLE_ENTITY;
@Service
@RequiredArgsConstructor
public class BaseSysPermsServiceImpl implements BaseSysPermsService {
final private CoolCache coolCache;
final private BaseSysUserMapper baseSysUserMapper;
final private BaseSysUserRoleMapper baseSysUserRoleMapper;
final private BaseSysMenuMapper baseSysMenuMapper;
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
final private CoolSecurityUtil coolSecurityUtil;
@Override
public Long[] loginDepartmentIds() {
String username = coolSecurityUtil.username();
if (username.equals("admin")) {
return baseSysDepartmentMapper.selectAll().stream().map(BaseSysDepartmentEntity::getId)
.toArray(Long[]::new);
} else {
Long[] roleIds = getRoles(username);
return baseSysRoleDepartmentMapper
.selectListByQuery(
QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds))
.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new);
}
}
@Override
public Long[] getDepartmentIdsByRoleIds(Long[] roleIds) {
return getLongs(roleIds);
}
private Long[] getLongs(Long[] roleIds) {
return baseSysRoleDepartmentMapper
.selectListByQuery(QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds,
roleIds != null && !CollUtil.toList(roleIds).contains(1L)))
.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new);
}
@Override
public Long[] getDepartmentIdsByRoleIds(Long userId) {
Long[] roleIds = getRoles(userId);
return getLongs(roleIds);
}
@Override
public String[] getPermsCache(Long userId) {
Object result = coolCache.get("admin:perms:" + userId);
if (ObjectUtil.isNotEmpty(result)) {
return Convert.toStrArray(result);
}
return getPerms(userId);
}
@Override
public Long[] getRoles(Long userId) {
return getRoles(baseSysUserMapper.selectOneById(userId));
}
@Override
public Long[] getRoles(String username) {
return getRoles(
baseSysUserMapper.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username)));
}
@Override
public Long[] getRoles(BaseSysUserEntity userEntity) {
Long[] roleIds = null;
if (!userEntity.getUsername().equals("admin")) {
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userEntity.getId()));
roleIds = list.stream().map(BaseSysUserRoleEntity::getRoleId).toArray(Long[]::new);
if (Arrays.asList(roleIds).contains(1L)) {
roleIds = null;
}
}
return roleIds;
}
@Override
public String[] getPerms(Long userId) {
return getPerms(getRoles(userId));
}
@Override
public String[] getPerms(Long[] roleIds) {
List<BaseSysMenuEntity> menus = getMenus(roleIds);
Set<String> perms = new HashSet<>();
String[] permsData = menus.stream().map(BaseSysMenuEntity::getPerms)
.filter(itemPerms -> !StrUtil.isEmpty(itemPerms)).toArray(String[]::new);
for (String permData : permsData) {
perms.addAll(Arrays.asList(permData.split(",")));
}
return ArrayUtil.toArray(perms, String.class);
}
@Override
public List<BaseSysMenuEntity> getMenus(Long[] roleIds) {
if (CollUtil.toList(roleIds).contains(1L)) {
roleIds = null;
}
if (roleIds != null && roleIds.length == 0) {
return new ArrayList<>();
}
QueryWrapper queryWrapper = QueryWrapper.create().select(BASE_SYS_MENU_ENTITY.ALL_COLUMNS).from(BASE_SYS_MENU_ENTITY);
if (ObjectUtil.isNotEmpty(roleIds)) {
queryWrapper.join(BASE_SYS_ROLE_MENU_ENTITY).on(BASE_SYS_MENU_ENTITY.ID.eq(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.in((Object) roleIds));
}
return baseSysMenuMapper.selectListByQuery(queryWrapper.groupBy(BASE_SYS_MENU_ENTITY.ID).orderBy(BASE_SYS_MENU_ENTITY.ORDER_NUM, false));
}
@Override
public List<BaseSysMenuEntity> getMenus(Long userId) {
return getMenus(getRoles(userId));
}
@Override
public List<BaseSysMenuEntity> getMenus(String username) {
BaseSysUserEntity sysUserEntity = baseSysUserMapper
.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username));
return getMenus(sysUserEntity.getId());
}
@Override
public String[] getAllPerms() {
return getPerms((Long[]) null);
}
@Override
public Object permmenu(Long adminUserId) {
return Dict.create().set("menus", getMenus(adminUserId)).set("perms", getPerms(adminUserId));
}
@Override
public void updatePerms(Long roleId, Long[] menuIdList, Long[] departmentIds) {
// 更新菜单权限
baseSysRoleMenuMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, roleId));
for (Long menuId : menuIdList) {
BaseSysRoleMenuEntity roleMenuEntity = new BaseSysRoleMenuEntity();
roleMenuEntity.setRoleId(roleId);
roleMenuEntity.setMenuId(menuId);
baseSysRoleMenuMapper.insert(roleMenuEntity);
}
// 更新部门权限
baseSysRoleDepartmentMapper
.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, roleId));
for (Long departmentId : departmentIds) {
BaseSysRoleDepartmentEntity roleDepartmentEntity = new BaseSysRoleDepartmentEntity();
roleDepartmentEntity.setRoleId(roleId);
roleDepartmentEntity.setDepartmentId(departmentId);
baseSysRoleDepartmentMapper.insert(roleDepartmentEntity);
}
// 刷新对应角色用户的权限
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId));
for (BaseSysUserRoleEntity userRole : userRoles) {
refreshPerms(userRole.getUserId());
}
}
@Override
public void updateUserRole(Long userId, Long[] roleIdList) {
baseSysUserRoleMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userId));
if (roleIdList == null) {
roleIdList = new Long[0];
}
for (Long roleId : roleIdList) {
BaseSysUserRoleEntity sysUserRoleEntity = new BaseSysUserRoleEntity();
sysUserRoleEntity.setRoleId(roleId);
sysUserRoleEntity.setUserId(userId);
baseSysUserRoleMapper.insert(sysUserRoleEntity);
}
refreshPerms(userId);
}
@Override
public void refreshPerms(Long userId) {
BaseSysUserEntity baseSysUserEntity = baseSysUserMapper.selectOneById(userId);
if (baseSysUserEntity != null && baseSysUserEntity.getStatus() != 0) {
SpringContextUtils.getBean(UserDetailsService.class).loadUserByUsername(baseSysUserEntity.getUsername());
}
if (baseSysUserEntity != null && baseSysUserEntity.getStatus() == 0) {
coolSecurityUtil.logout(baseSysUserEntity.getId(), baseSysUserEntity.getUsername());
}
}
@Async
@Override
public void refreshPermsByMenuId(Long menuId) {
// 刷新超管权限、 找出这个菜单的所有用户、 刷新用户权限
BaseSysUserEntity admin = baseSysUserMapper
.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, "admin"));
refreshPerms(admin.getId());
List<Row> list = baseSysRoleMenuMapper.selectRowsByQuery(QueryWrapper.create().select(BASE_SYS_USER_ROLE_ENTITY.USER_ID)
.from(BASE_SYS_ROLE_MENU_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY)
.on(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.eq(BASE_SYS_USER_ROLE_ENTITY.ROLE_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID.eq(menuId, ObjectUtil.isNotEmpty(menuId))).groupBy(BASE_SYS_USER_ROLE_ENTITY.USER_ID));
for (Row row : list) {
refreshPerms(row.getLong("userId"));
}
}
@Override
public void refreshPermsByRoleId(Long roleId) {
// 找出角色对应的所有用户
List<BaseSysUserRoleEntity> list = baseSysUserRoleMapper
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId));
list.forEach(e -> {
refreshPerms(e.getUserId());
});
}
}
@@ -0,0 +1,92 @@
package com.cool.modules.base.service.sys.impl;
import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.base.ModifyEnum;
import com.cool.core.exception.CoolException;
import com.cool.modules.base.entity.sys.BaseSysRoleDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleEntity;
import com.cool.modules.base.entity.sys.BaseSysRoleMenuEntity;
import com.cool.modules.base.mapper.sys.BaseSysRoleDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleMapper;
import com.cool.modules.base.mapper.sys.BaseSysRoleMenuMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.cool.modules.base.service.sys.BaseSysRoleService;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 系统角色
*/
@RequiredArgsConstructor
@Service
public class BaseSysRoleServiceImpl extends BaseServiceImpl<BaseSysRoleMapper, BaseSysRoleEntity>
implements BaseSysRoleService {
final private BaseSysRoleMapper baseSysRoleMapper;
final private BaseSysRoleMenuMapper baseSysRoleMenuMapper;
final private BaseSysRoleDepartmentMapper baseSysRoleDepartmentMapper;
final private BaseSysPermsService baseSysPermsService;
final private CoolSecurityUtil coolSecurityUtil;
@Override
public Object add(JSONObject requestParams, BaseSysRoleEntity entity) {
BaseSysRoleEntity checkLabel = getOne(QueryWrapper.create().eq(BaseSysRoleEntity::getLabel, entity.getLabel()));
if (checkLabel != null) {
throw new CoolException("标识已存在");
}
entity.setUserId((coolSecurityUtil.userInfo(requestParams).getLong("userId")));
return super.add(requestParams, entity);
}
@Override
public Object info(Long id) {
BaseSysRoleEntity roleEntity = getById(id);
Long[] menuIdList = new Long[0];
Long[] departmentIdList = new Long[0];
if (roleEntity != null) {
List<BaseSysRoleMenuEntity> list = baseSysRoleMenuMapper
.selectListByQuery(QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, id, !id.equals(1L)));
menuIdList = list.stream().map(BaseSysRoleMenuEntity::getMenuId).toArray(Long[]::new);
List<BaseSysRoleDepartmentEntity> departmentEntities = baseSysRoleDepartmentMapper.selectListByQuery(
QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, id, !id.equals(1L)));
departmentIdList = departmentEntities.stream().map(BaseSysRoleDepartmentEntity::getDepartmentId)
.toArray(Long[]::new);
}
return Dict.parse(roleEntity).set("menuIdList", menuIdList).set("departmentIdList", departmentIdList);
}
@Override
public void modifyAfter(JSONObject requestParams, BaseSysRoleEntity baseSysRoleEntity, ModifyEnum type) {
if (type == ModifyEnum.DELETE) {
Long[] ids = requestParams.get("ids", Long[].class);
for (Long id : ids) {
baseSysPermsService.refreshPermsByRoleId(id);
}
} else {
baseSysPermsService.updatePerms(baseSysRoleEntity.getId(), requestParams.get("menuIdList", Long[].class),
requestParams.get("departmentIdList", Long[].class));
}
}
@Override
public Object list(JSONObject requestParams, QueryWrapper queryWrapper) {
return baseSysRoleMapper.selectListByQuery(queryWrapper.ne(BaseSysRoleEntity::getId, 1L).and(qw -> {
qw.eq(BaseSysRoleEntity::getUserId, coolSecurityUtil.userInfo(requestParams).get("userId")).or(w -> {
w.in(BaseSysRoleEntity::getId,
(Object) coolSecurityUtil.userInfo(requestParams).get("roleIds", Long[].class));
});
}, !coolSecurityUtil.username().equals("admin")));
}
}
@@ -0,0 +1,161 @@
package com.cool.modules.base.service.sys.impl;
import static com.cool.modules.base.entity.sys.table.BaseSysDepartmentEntityTableDef.BASE_SYS_DEPARTMENT_ENTITY;
import static com.cool.modules.base.entity.sys.table.BaseSysRoleEntityTableDef.BASE_SYS_ROLE_ENTITY;
import static com.cool.modules.base.entity.sys.table.BaseSysUserEntityTableDef.BASE_SYS_USER_ENTITY;
import static com.cool.modules.base.entity.sys.table.BaseSysUserRoleEntityTableDef.BASE_SYS_USER_ROLE_ENTITY;
import static com.mybatisflex.core.query.QueryMethods.groupConcat;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.base.ModifyEnum;
import com.cool.core.cache.CoolCache;
import com.cool.core.exception.CoolPreconditions;
import com.cool.modules.base.entity.sys.BaseSysDepartmentEntity;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.mapper.sys.BaseSysDepartmentMapper;
import com.cool.modules.base.mapper.sys.BaseSysUserMapper;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.cool.modules.base.service.sys.BaseSysUserService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 系统用户
*/
@Service
@RequiredArgsConstructor
public class BaseSysUserServiceImpl extends BaseServiceImpl<BaseSysUserMapper, BaseSysUserEntity>
implements BaseSysUserService {
final private CoolCache coolCache;
final private CoolSecurityUtil coolSecurityUtil;
final private BaseSysPermsService baseSysPermsService;
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
@Override
public Object page(JSONObject requestParams, Page<BaseSysUserEntity> page, QueryWrapper qw) {
String keyWord = requestParams.getStr("keyWord");
Integer status = requestParams.getInt("status");
Long[] departmentIds = requestParams.get("departmentIds", Long[].class);
JSONObject tokenInfo = coolSecurityUtil.userInfo(requestParams);
// 用户的部门权限
Long[] permsDepartmentArr = coolCache.get("admin:department:" + tokenInfo.get("userId"),
Long[].class);
qw.select(BASE_SYS_USER_ENTITY.ALL_COLUMNS,
groupConcat(BASE_SYS_ROLE_ENTITY.NAME).as("roleName"),
BASE_SYS_DEPARTMENT_ENTITY.NAME.as("departmentName"))
.from(BASE_SYS_USER_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY)
.on(BASE_SYS_USER_ENTITY.ID.eq(BASE_SYS_USER_ROLE_ENTITY.USER_ID))
.leftJoin(BASE_SYS_ROLE_ENTITY)
.on(BASE_SYS_USER_ROLE_ENTITY.USER_ID.eq(BASE_SYS_ROLE_ENTITY.ID))
.leftJoin(BASE_SYS_DEPARTMENT_ENTITY)
.on(BASE_SYS_USER_ENTITY.DEPARTMENT_ID.eq(BASE_SYS_DEPARTMENT_ENTITY.ID));
// 不显示admin用户
qw.and(BASE_SYS_USER_ENTITY.USERNAME.ne("admin"));
// 筛选部门
qw.and(BASE_SYS_USER_ENTITY.DEPARTMENT_ID.in(departmentIds,
ArrayUtil.isNotEmpty(departmentIds)));
// 筛选状态
qw.and(BASE_SYS_USER_ENTITY.STATUS.eq(status, status != null));
// 搜索关键字
if (StrUtil.isNotEmpty(keyWord)) {
qw.and(BASE_SYS_USER_ENTITY.NAME.like(keyWord)
.or(BASE_SYS_USER_ENTITY.USERNAME.like(keyWord)));
}
// 过滤部门权限
qw.and(BASE_SYS_USER_ENTITY.DEPARTMENT_ID.in(
permsDepartmentArr == null || permsDepartmentArr.length == 0 ? new Long[]{null}
: permsDepartmentArr,
!coolSecurityUtil.username().equals("admin")));
qw.groupBy(BASE_SYS_USER_ENTITY.ID);
return mapper.paginateWithRelations(page, qw);
}
@Override
public void personUpdate(Long userId, Dict body) {
BaseSysUserEntity userEntity = getById(userId);
CoolPreconditions.checkEmpty(userEntity, "用户不存在");
userEntity.setNickName(body.getStr("nickName"));
// 修改密码
if (StrUtil.isNotEmpty(body.getStr("password"))) {
userEntity.setPassword(MD5.create().digestHex(body.getStr("password")));
userEntity.setPasswordV(userEntity.getPasswordV() + 1);
coolCache.set("admin:passwordVersion:" + userId, userEntity.getPasswordV());
}
updateById(userEntity);
}
@Override
public void move(Long departmentId, Long[] userIds) {
UpdateChain.of(BaseSysUserEntity.class)
.set(BaseSysUserEntity::getDepartmentId, departmentId)
.in(BaseSysUserEntity::getId, (Object) userIds).update();
}
@Override
public Long add(JSONObject requestParams, BaseSysUserEntity entity) {
BaseSysUserEntity check = getOne(
QueryWrapper.create().eq(BaseSysUserEntity::getUsername, entity.getUsername()));
CoolPreconditions.check(check != null, "用户名已存在");
entity.setPassword(MD5.create().digestHex(entity.getPassword()));
super.add(requestParams, entity);
return entity.getId();
}
@Override
public boolean update(JSONObject requestParams, BaseSysUserEntity entity) {
CoolPreconditions.check(
StrUtil.isNotEmpty(entity.getUsername()) && entity.getUsername().equals("admin"),
"非法操作");
BaseSysUserEntity userEntity = getById(entity.getId());
if (StrUtil.isNotEmpty(entity.getPassword())) {
entity.setPasswordV(entity.getPasswordV() + 1);
entity.setPassword(MD5.create().digestHex(entity.getPassword()));
coolCache.set("admin:passwordVersion:" + entity.getId(), entity.getPasswordV());
} else {
entity.setPassword(userEntity.getPassword());
entity.setPasswordV(userEntity.getPasswordV());
}
// 被禁用
if (entity.getStatus() == 0) {
coolSecurityUtil.logout(entity);
}
return super.update(requestParams, entity);
}
@Override
public void modifyAfter(JSONObject requestParams, BaseSysUserEntity baseSysUserEntity,
ModifyEnum type) {
if (type != ModifyEnum.DELETE && requestParams.get("roleIdList", Long[].class) != null) {
// 刷新权限
baseSysPermsService.updateUserRole(baseSysUserEntity.getId(),
requestParams.get("roleIdList", Long[].class));
}
}
@Override
public Object info(Long id) {
BaseSysUserEntity userEntity = getById(id);
Long[] roleIdList = baseSysPermsService.getRoles(id);
BaseSysDepartmentEntity departmentEntity = baseSysDepartmentMapper.selectOneById(
userEntity.getDepartmentId());
userEntity.setPassword(null);
return Dict.parse(userEntity).set("roleIdList", roleIdList).set("departmentName",
departmentEntity != null ? departmentEntity.getName() : null);
}
}
@@ -0,0 +1,37 @@
package com.cool.modules.dict.controller.admin;
import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.dict.entity.DictInfoEntity;
import com.cool.modules.dict.entity.table.DictInfoEntityTableDef;
import com.cool.modules.dict.service.DictInfoService;
import com.mybatisflex.core.query.QueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import jakarta.servlet.http.HttpServletRequest;
/**
* 字典信息
*/
@Tag(name = "字典信息", description = "字典信息")
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
public class AdminDictInfoController extends BaseController<DictInfoService, DictInfoEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setListOption(createOp().fieldEq(DictInfoEntityTableDef.DICT_INFO_ENTITY.TYPE_ID)
.keyWordLikeFields(DictInfoEntityTableDef.DICT_INFO_ENTITY.NAME)
.queryWrapper(QueryWrapper.create().orderBy(DictInfoEntityTableDef.DICT_INFO_ENTITY.CREATE_TIME, false)));
}
@Operation(summary = "获得字典数据", description = "获得字典数据信息")
@PostMapping("/data")
public R data(@RequestBody Dict body) {
return R.ok(this.service.data(body.get("types", null)));
}
}
@@ -0,0 +1,25 @@
package com.cool.modules.dict.controller.admin;
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.modules.dict.entity.DictTypeEntity;
import com.cool.modules.dict.service.DictTypeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
/**
* 字典类型
*/
@Tag(name = "字典类型", description = "字典类型")
@CoolRestController(api = {"add", "delete", "update", "page", "list", "info"})
public class AdminDictTypeController extends BaseController<DictTypeService, DictTypeEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setPageOption(
createOp().select(DICT_TYPE_ENTITY.ID, DICT_TYPE_ENTITY.KEY, DICT_TYPE_ENTITY.NAME));
}
}
@@ -0,0 +1,34 @@
package com.cool.modules.dict.controller.app;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.dict.entity.DictInfoEntity;
import com.cool.modules.dict.service.DictInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import jakarta.servlet.http.HttpServletRequest;
/**
* 字典信息
*/
@Tag(name = "字典信息", description = "字典信息")
@CoolRestController(api = {})
public class AppDictInfoController extends BaseController<DictInfoService, DictInfoEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
@Operation(summary = "获得字典数据", description = "获得字典数据信息")
@PostMapping("/data")
public R data(@RequestBody Dict body) {
return R.ok(this.service.data(Convert.toList(String.class, body.get("types"))));
}
}
@@ -0,0 +1,32 @@
package com.cool.modules.dict.entity;
import com.cool.core.base.BaseEntity;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "dict_info", comment = "字典信息")
public class DictInfoEntity extends BaseEntity<DictInfoEntity> {
@ColumnDefine(comment = "类型ID", notNull = true)
private Long typeId;
@ColumnDefine(comment = "父ID")
private Long parentId;
@ColumnDefine(comment = "名称", notNull = true)
private String name;
@ColumnDefine(comment = "值")
private String value;
@ColumnDefine(comment = "排序", defaultValue = "0")
private Integer orderNum;
@ColumnDefine(comment = "备注")
private String remark;
}
@@ -0,0 +1,21 @@
package com.cool.modules.dict.entity;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Table;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "dict_type", comment = "字典类型")
public class DictTypeEntity extends BaseEntity<DictTypeEntity> {
@ColumnDefine(comment = "名称", notNull = true)
private String name;
@ColumnDefine(comment = "标识", notNull = true)
@UniIndex
private String key;
}
@@ -0,0 +1,10 @@
package com.cool.modules.dict.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.dict.entity.DictInfoEntity;
/**
* 字典信息
*/
public interface DictInfoMapper extends BaseMapper<DictInfoEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.dict.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.dict.entity.DictTypeEntity;
/**
* 字典类型
*/
public interface DictTypeMapper extends BaseMapper<DictTypeEntity> {
}
@@ -0,0 +1,19 @@
package com.cool.modules.dict.service;
import com.cool.core.base.BaseService;
import com.cool.modules.dict.entity.DictInfoEntity;
import java.util.List;
/**
* 字典信息
*/
public interface DictInfoService extends BaseService<DictInfoEntity> {
/**
* 字典数据
*
* @param types 字典类型
* @return
*/
Object data(List<String> types);
}
@@ -0,0 +1,10 @@
package com.cool.modules.dict.service;
import com.cool.core.base.BaseService;
import com.cool.modules.dict.entity.DictTypeEntity;
/**
* 字典类型
*/
public interface DictTypeService extends BaseService<DictTypeEntity> {
}
@@ -0,0 +1,100 @@
package com.cool.modules.dict.service.impl;
import static com.cool.modules.dict.entity.table.DictInfoEntityTableDef.DICT_INFO_ENTITY;
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.dict.entity.DictInfoEntity;
import com.cool.modules.dict.entity.DictTypeEntity;
import com.cool.modules.dict.mapper.DictInfoMapper;
import com.cool.modules.dict.mapper.DictTypeMapper;
import com.cool.modules.dict.service.DictInfoService;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 字典信息
*/
@Service
@RequiredArgsConstructor
public class DictInfoServiceImpl extends BaseServiceImpl<DictInfoMapper, DictInfoEntity> implements
DictInfoService {
final private DictTypeMapper dictTypeMapper;
@Override
public Object data(List<String> types) {
Dict result = Dict.create();
QueryWrapper find = QueryWrapper.create();
find.select(DICT_TYPE_ENTITY.ID, DICT_TYPE_ENTITY.KEY,
DICT_TYPE_ENTITY.NAME);
if (CollectionUtil.isNotEmpty(types)) {
find.and(DICT_TYPE_ENTITY.KEY.in(types));
}
List<DictTypeEntity> typeData = dictTypeMapper.selectListByQuery(find);
if (typeData.isEmpty()) {
return result;
}
List<DictInfoEntity> infos = this.list(QueryWrapper.create()
.select(DictInfoEntity::getId, DictInfoEntity::getName, DictInfoEntity::getTypeId,
DictInfoEntity::getParentId, DictInfoEntity::getValue)
.in(DictInfoEntity::getTypeId,
typeData.stream().map(DictTypeEntity::getId).collect(Collectors.toList()))
.orderBy(DICT_INFO_ENTITY.ORDER_NUM.getName(), DICT_INFO_ENTITY.CREATE_TIME.getName()));
typeData.forEach(item -> {
List<Dict> datas = new ArrayList<>();
infos.stream().filter(d -> d.getTypeId().equals(item.getId())).toList().forEach(d -> {
Dict data = Dict.create();
data.set("typeId", d.getTypeId());
data.set("parentId", d.getParentId());
data.set("name", d.getName());
data.set("id", d.getId());
data.set("value", StrUtil.isEmpty(d.getValue()) ? null : d.getValue());
try {
data.set("value", Integer.parseInt(d.getValue()));
} catch (Exception ignored) {
}
datas.add(data);
});
result.set(item.getKey(), datas);
});
return result;
}
@Override
public boolean delete(Long... ids) {
super.delete(ids);
for (Long id : ids) {
this.delDictChild(id);
}
return true;
}
/**
* 删除子菜单
*
* @param id 删除的菜单ID
*/
private void delDictChild(Long id) {
List<DictInfoEntity> delDict = list(
QueryWrapper.create().eq(DictInfoEntity::getParentId, id));
if (CollectionUtil.isEmpty(delDict)) {
return;
}
Long[] ids = delDict.stream().map(DictInfoEntity::getId).toArray(Long[]::new);
if (ArrayUtil.isNotEmpty(ids)) {
delete(ids);
for (Long delId : ids) {
this.delDictChild(delId);
}
}
}
}
@@ -0,0 +1,39 @@
package com.cool.modules.dict.service.impl;
import static com.cool.modules.dict.entity.table.DictInfoEntityTableDef.DICT_INFO_ENTITY;
import static com.cool.modules.dict.entity.table.DictTypeEntityTableDef.DICT_TYPE_ENTITY;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.dict.entity.DictTypeEntity;
import com.cool.modules.dict.mapper.DictInfoMapper;
import com.cool.modules.dict.mapper.DictTypeMapper;
import com.cool.modules.dict.service.DictTypeService;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 字典类型
*/
@Service
@RequiredArgsConstructor
public class DictTypeServiceImpl extends BaseServiceImpl<DictTypeMapper, DictTypeEntity> implements
DictTypeService {
final private DictInfoMapper dictInfoMapper;
@Override
public List<DictTypeEntity> list(QueryWrapper queryWrapper) {
return super.list(
queryWrapper.select(DICT_TYPE_ENTITY.ID, DICT_TYPE_ENTITY.KEY,
DICT_TYPE_ENTITY.NAME));
}
@Override
public boolean delete(Long... ids) {
super.delete(ids);
return dictInfoMapper.deleteByQuery(
QueryWrapper.create().and(DICT_INFO_ENTITY.TYPE_ID.in((Object) ids))) > 0;
}
}
@@ -0,0 +1,72 @@
package com.cool.modules.plugin.controller.admin;
import static com.cool.modules.plugin.entity.table.PluginInfoEntityTableDef.PLUGIN_INFO_ENTITY;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.annotation.IgnoreRecycleData;
import com.cool.core.base.BaseController;
import com.cool.core.plugin.service.CoolPluginService;
import com.cool.core.request.R;
import com.cool.core.util.EntityUtils;
import com.cool.modules.plugin.entity.PluginInfoEntity;
import com.cool.modules.plugin.service.PluginInfoService;
import com.mybatisflex.core.query.QueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Tag(name = "插件信息", description = "插件信息")
@CoolRestController(api = {"add", "delete", "update", "page", "list", "info"})
@RequiredArgsConstructor
public class AdminPluginInfoController extends BaseController<PluginInfoService, PluginInfoEntity> {
final private CoolPluginService coolPluginService;
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setPageOption(createOp().queryWrapper(
QueryWrapper.create().orderBy(PLUGIN_INFO_ENTITY.UPDATE_TIME, false))
.select(EntityUtils.getFieldNamesWithSuperClass(PLUGIN_INFO_ENTITY.DEFAULT_COLUMNS,
PLUGIN_INFO_ENTITY.JAR_FILE.getName())));
}
@Override
@Operation(summary = "修改", description = "根据ID修改")
@PostMapping("/update")
protected R update(@RequestBody PluginInfoEntity t,
@RequestAttribute() JSONObject requestParams) {
coolPluginService.updatePlugin(t);
return R.ok();
}
@Operation(summary = "安装插件")
@PostMapping(value = "/install", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R install(
@RequestParam(value = "files") @Parameter(description = "文件") MultipartFile[] files,
@RequestParam(value = "force") @Parameter(description = "是否强制安装") boolean force) {
coolPluginService.install(files[0], force);
return R.ok();
}
@Override
@Operation(summary = "卸载插件")
@PostMapping("/delete")
@IgnoreRecycleData()
public R delete(HttpServletRequest request, @RequestBody Map<String, Object> params,
@RequestAttribute() JSONObject requestParams) {
coolPluginService.uninstall(Convert.toLongArray(getIds(params))[0]);
return R.ok();
}
}
@@ -0,0 +1,68 @@
package com.cool.modules.plugin.entity;
import com.cool.core.base.BaseEntity;
import com.cool.core.config.PluginJson;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
import com.tangzc.autotable.annotation.Ignore;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.tangzc.mybatisflex.autotable.annotation.UniIndex;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "plugin_info", comment = "插件信息")
public class PluginInfoEntity extends BaseEntity<PluginInfoEntity> {
@ColumnDefine(comment = "名称")
private String name;
@ColumnDefine(comment = "简介")
private String description;
@UniIndex
@ColumnDefine(comment = "实例对象")
private String key;
@Index
@ColumnDefine(comment = "Hook", length = 50)
private String hook;
@ColumnDefine(comment = "描述", type = "text")
private String readme;
@ColumnDefine(comment = "版本")
private String version;
@ColumnDefine(comment = "Logo(base64)", type = "text", notNull = true)
private String logo;
@ColumnDefine(comment = "作者")
private String author;
@ColumnDefine(comment = "状态 0-禁用 1-启用", defaultValue = "1")
private Integer status;
@ColumnDefine(comment = "插件的plugin.json", type = "json", notNull = true)
@Column(typeHandler = Fastjson2TypeHandler.class)
private PluginJson pluginJson;
@ColumnDefine(comment = "jar二进制文件", type = "longblob", notNull = true)
private byte[] jarFile;
@ColumnDefine(comment = "配置", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private Map<String, Object> config;
@Ignore
@Column(ignore = true)
public String keyName;
public String getKeyName() {
return key;
}
}
@@ -0,0 +1,8 @@
package com.cool.modules.plugin.mapper;
import com.cool.modules.plugin.entity.PluginInfoEntity;
import com.mybatisflex.core.BaseMapper;
public interface PluginInfoMapper extends BaseMapper<PluginInfoEntity> {
}
@@ -0,0 +1,12 @@
package com.cool.modules.plugin.service;
import com.cool.core.base.BaseService;
import com.cool.modules.plugin.entity.PluginInfoEntity;
public interface PluginInfoService extends BaseService<PluginInfoEntity> {
PluginInfoEntity getByKeyNoJarFile(String key);
PluginInfoEntity getPluginInfoEntityByHookNoJarFile(String hook);
PluginInfoEntity getPluginInfoEntityByIdNoJarFile(Long id);
}
@@ -0,0 +1,55 @@
package com.cool.modules.plugin.service.impl;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.util.EntityUtils;
import com.cool.modules.plugin.entity.PluginInfoEntity;
import com.cool.modules.plugin.mapper.PluginInfoMapper;
import com.cool.modules.plugin.service.PluginInfoService;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Service;
import static com.cool.modules.plugin.entity.table.PluginInfoEntityTableDef.PLUGIN_INFO_ENTITY;
/**
* 插件信息服务类
*/
@Service
public class PluginInfoServiceImpl extends BaseServiceImpl<PluginInfoMapper, PluginInfoEntity>
implements PluginInfoService {
/**
* 通过key获取插件信息,不带jar二进制
*/
@Override
public PluginInfoEntity getByKeyNoJarFile(String key) {
QueryWrapper queryWrapper = getPluginInfoEntityQueryWrapper();
queryWrapper.and(PLUGIN_INFO_ENTITY.KEY.eq(key));
return getOne(queryWrapper);
}
/**
* 通过hook获取插件信息,不带jar二进制
*/
@Override
public PluginInfoEntity getPluginInfoEntityByHookNoJarFile(String hook) {
QueryWrapper queryWrapper = getPluginInfoEntityQueryWrapper().and(PLUGIN_INFO_ENTITY.HOOK.eq(hook))
.and(PLUGIN_INFO_ENTITY.STATUS.eq(1)).limit(1);
return getOne(queryWrapper);
}
/**
* 通过id获取插件信息,不带jar二进制
*/
@Override
public PluginInfoEntity getPluginInfoEntityByIdNoJarFile(Long id) {
QueryWrapper queryWrapper = getPluginInfoEntityQueryWrapper().and(PLUGIN_INFO_ENTITY.ID.eq(id));
return getOne(queryWrapper);
}
/**
* 获取查询对象,排除掉 jar二进制
*/
private QueryWrapper getPluginInfoEntityQueryWrapper() {
return QueryWrapper.create().select(EntityUtils.getFieldNamesWithSuperClass(PLUGIN_INFO_ENTITY.DEFAULT_COLUMNS, PLUGIN_INFO_ENTITY.JAR_FILE.getName()));
}
}
@@ -0,0 +1,15 @@
//package com.cool.modules.recycle.aop;
//
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.context.annotation.EnableAspectJAutoProxy;
//
//@Configuration
//@EnableAspectJAutoProxy
//public class AopConfig {
//
// @Bean
// public DeleteAspect deleteAspect() {
// return new DeleteAspect();
// }
//}
@@ -0,0 +1,114 @@
package com.cool.modules.recycle.aop;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.IgnoreRecycleData;
import com.cool.core.base.BaseController;
import com.cool.core.base.BaseService;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.recycle.entity.RecycleDataEntity;
import com.cool.modules.recycle.service.RecycleDataService;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
* 数据删除前拦截
*/
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class DeleteAspect {
final private RecycleDataService recycleDataService;
final private CoolSecurityUtil coolSecurityUtil;
@Around(value = "execution(* com.cool.core.base.BaseController.delete*(..)) && args(request, params, requestParams)", argNames = "joinPoint,request,params,requestParams")
public Object aroundAdvice(ProceedingJoinPoint joinPoint, HttpServletRequest request,
Map<String, Object> params,
JSONObject requestParams) throws Throwable {
Method currentMethod = getCurrentMethod(joinPoint);
if (Objects.nonNull(currentMethod) && currentMethod.isAnnotationPresent(
IgnoreRecycleData.class)) {
// 忽略回收站记录
return joinPoint.proceed();
}
List<Object> list = null;
String className = null;
try {
log.info("数据删除前拦截");
// 可以在目标方法执行前进行一些操作
BaseController baseController = (BaseController) joinPoint.getTarget();
BaseService service = baseController.getService();
className = (baseController.currentEntityClass()).getName();
QueryWrapper queryWrapper = new QueryWrapper();
Object ids = params.get("ids");
if (!(ids instanceof ArrayList)) {
ids = ids.toString().split(",");
}
List<Long> idList = Convert.toList(Long.class, ids);
queryWrapper.in("id", (Object) Convert.toLongArray(idList));
list = service.list(queryWrapper);
} catch (Exception e) {
log.error("数据删除前拦截获取数据详情信息失败", e);
}
Object result = joinPoint.proceed();
if (ObjUtil.isNotEmpty(list)) {
RecycleDataEntity recycleDataEntity = new RecycleDataEntity();
recycleDataEntity.setUrl(request.getRequestURI());
recycleDataEntity.setUserName(coolSecurityUtil.username());
recycleDataEntity
.setUserId(Long.parseLong(
String.valueOf(coolSecurityUtil.userInfo(requestParams).get("userId"))));
recycleDataEntity.setParams(params);
recycleDataEntity.setData(list);
recycleDataEntity.setParams(params);
RecycleDataEntity.EntityInfo entityInfo = new RecycleDataEntity.EntityInfo();
entityInfo.setEntityClassName(className);
recycleDataEntity.setEntityInfo(entityInfo);
recycleDataEntity.setCount(recycleDataEntity.getData().size());
log.info("数据进入回收站 {}", recycleDataService.add(recycleDataEntity));
}
return result;
}
private Method getCurrentMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
Method[] methods = joinPoint.getTarget().getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterCount() == args.length) {
boolean isSameMethod = true;
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
isSameMethod = false;
break;
}
}
if (isSameMethod) {
return method;
}
}
}
return null;
}
}
@@ -0,0 +1,40 @@
package com.cool.modules.recycle.controller.admin;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.recycle.entity.RecycleDataEntity;
import com.cool.modules.recycle.entity.table.RecycleDataEntityTableDef;
import com.cool.modules.recycle.service.RecycleDataService;
import com.mybatisflex.core.query.QueryWrapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.Map;
/**
* 数据回收站
*/
@Tag(name = "数据回收站", description = "数据回收站")
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
@RequiredArgsConstructor
public class AdminRecycleDataController extends BaseController<RecycleDataService, RecycleDataEntity> {
final private RecycleDataService recycleDataService;
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setListOption(createOp().queryWrapper(QueryWrapper.create().orderBy(RecycleDataEntityTableDef.RECYCLE_DATA_ENTITY.CREATE_TIME, false)));
}
@Operation(summary = "恢复数据", description = "恢复数据")
@PostMapping("/restore")
public R restore(@RequestBody Map<String, Object> params) {
return R.ok(this.service.restore(getIds(params)));
}
}
@@ -0,0 +1,56 @@
package com.cool.modules.recycle.entity;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.handler.Fastjson2TypeHandler;
import com.tangzc.autotable.annotation.Ignore;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
/**
* 数据回收站 软删除的时候数据会回收到该表
*/
@Getter
@Setter
@Table(value = "recycle_data", comment = "数据回收站表")
public class RecycleDataEntity extends BaseEntity<RecycleDataEntity> {
@ColumnDefine(comment = "表信息", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private EntityInfo entityInfo;
@Index()
@ColumnDefine(comment = "操作人", notNull = true)
private Long userId;
@ColumnDefine(comment = "被删除的数据", type = "json")
@Column(typeHandler = Fastjson2TypeHandler.class)
private List<Object> data;
@ColumnDefine(comment = "请求的接口", notNull = true)
private String url;
@ColumnDefine(comment = "请求参数", type = "json", notNull = true)
@Column(typeHandler = Fastjson2TypeHandler.class)
private Map<String, Object> params;
@ColumnDefine(comment = "删除数据条数", defaultValue = "1")
private Integer count;
@Setter
@Getter
public static class EntityInfo {
// entityClassName
public String entityClassName;
}
@Ignore
@Column(ignore = true) // 操作人名称
public String userName;
}
@@ -0,0 +1,7 @@
package com.cool.modules.recycle.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.recycle.entity.RecycleDataEntity;
public interface RecycleDataMapper extends BaseMapper<RecycleDataEntity> {
}
@@ -0,0 +1,21 @@
package com.cool.modules.recycle.service;
import cn.hutool.json.JSONObject;
import com.cool.core.base.BaseService;
import com.cool.modules.recycle.entity.RecycleDataEntity;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.List;
public interface RecycleDataService extends BaseService<RecycleDataEntity> {
Object page(JSONObject requestParams, Page<RecycleDataEntity> page, QueryWrapper queryWrapper);
/**
* 恢复数据
*
* @param ids
* @return
*/
Boolean restore(List<Long> ids);
}
@@ -0,0 +1,118 @@
package com.cool.modules.recycle.service.impl;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cool.core.base.BaseServiceImpl;
import com.cool.core.base.service.MapperProviderService;
import com.cool.modules.base.entity.sys.BaseSysUserEntity;
import com.cool.modules.base.service.sys.BaseSysUserService;
import com.cool.modules.recycle.entity.RecycleDataEntity;
import com.cool.modules.recycle.mapper.RecycleDataMapper;
import com.cool.modules.recycle.service.RecycleDataService;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 数据回收站
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class RecycleDataServiceImpl extends BaseServiceImpl<RecycleDataMapper, RecycleDataEntity>
implements RecycleDataService {
final private BaseSysUserService baseSysUserService;
final private MapperProviderService mapperProviderService;
@Override
public Object page(JSONObject requestParams, Page<RecycleDataEntity> page,
QueryWrapper queryWrapper) {
String keyWord = requestParams.getStr("keyWord");
if (ObjUtil.isNotEmpty(keyWord)) {
List<Long> list = baseSysUserService
.list(queryWrapper.select(BaseSysUserEntity::getId)
.like(BaseSysUserEntity::getName, keyWord))
.stream().map(BaseSysUserEntity::getId).toList();
queryWrapper.like(RecycleDataEntity::getUrl, keyWord).or(w -> {
w.in(RecycleDataEntity::getUserId, list, ObjUtil.isNotEmpty(list));
});
}
Page<RecycleDataEntity> iPage = page(page, queryWrapper);
List<RecycleDataEntity> records = iPage.getRecords();
List<Long> list = records.stream().map(RecycleDataEntity::getUserId)
.filter(ObjUtil::isNotEmpty).toList();
if (ObjUtil.isNotEmpty(list)) {
Map<Long, String> map = baseSysUserService
.list(QueryWrapper.create()
.select(BaseSysUserEntity::getId, BaseSysUserEntity::getName)
.in(BaseSysUserEntity::getId, list))
.stream()
.collect(Collectors.toMap(BaseSysUserEntity::getId, BaseSysUserEntity::getName));
records.forEach(o -> {
if (map.containsKey(o.getUserId())) {
o.setUserName(map.get(o.getUserId()));
}
});
}
return iPage;
}
@Override
public Boolean restore(List<Long> ids) {
if (ObjUtil.isEmpty(ids)) {
return false;
}
List<RecycleDataEntity> list = list(
QueryWrapper.create().in(RecycleDataEntity::getId, ids));
list.forEach(o -> {
// 处理恢复数据
boolean flag = handlerRestore(o);
if (flag) {
// 删除回收站记录
o.removeById();
}
});
return true;
}
/**
* 处理数据恢复
*/
private boolean handlerRestore(RecycleDataEntity recycleDataEntity) {
RecycleDataEntity.EntityInfo entityInfo = recycleDataEntity.getEntityInfo();
try {
Class<?> entityClass = ClassUtil.loadClass(entityInfo.getEntityClassName());
List<Object> records = recycleDataEntity.getData();
BaseMapper<?> baseMapper = mapperProviderService.getMapperByEntityClass(
entityClass);
// 插入数据
List insertList = new ArrayList<>();
for (Object record : records) {
Object entity = JSONUtil.toBean(JSONUtil.parseObj(record), entityClass);
Method getIdMethod = entityClass.getMethod("getId");
Object id = getIdMethod.invoke(entity);
if (baseMapper.selectOneById((Long) id) == null) {
insertList.add(entity);
}
}
baseMapper.insertBatch(insertList);
return true;
} catch (Exception e) {
log.error("恢复数据失败", e);
}
return false;
}
}
@@ -0,0 +1,24 @@
package com.cool.modules.space.controller.admin;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.modules.space.entity.SpaceInfoEntity;
import com.cool.modules.space.service.SpaceInfoService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import static com.cool.modules.space.entity.table.SpaceInfoEntityTableDef.SPACE_INFO_ENTITY;
/**
* 文件空间信息
*/
@Tag(name = "文件空间信息", description = "文件空间信息")
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
public class AdminSpaceInfoController extends BaseController<SpaceInfoService, SpaceInfoEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setPageOption(createOp().fieldEq(SPACE_INFO_ENTITY.TYPE, SPACE_INFO_ENTITY.CLASSIFY_ID));
}
}
@@ -0,0 +1,23 @@
package com.cool.modules.space.controller.admin;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.modules.space.entity.SpaceTypeEntity;
import com.cool.modules.space.service.SpaceTypeService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
/**
* 文件空间信息
*/
@Tag(name = "文件空间信息", description = "文件空间信息")
@CoolRestController(api = { "add", "delete", "update", "page", "list", "info" })
public class AdminSpaceTypeController extends BaseController<SpaceTypeService, SpaceTypeEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
}
}
@@ -0,0 +1,58 @@
package com.cool.modules.space.entity;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.autotable.annotation.Ignore;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
/**
* 文件空间信息
*/
@Getter
@Setter
@Table(value = "space_info", comment = "文件空间信息")
public class SpaceInfoEntity extends BaseEntity<SpaceInfoEntity> {
@ColumnDefine(comment = "地址", notNull = true)
private String url;
@ColumnDefine(comment = "类型", notNull = true)
private String type;
@ColumnDefine(comment = "分类ID", type = "tinyint")
private Integer classifyId;
@Index()
@ColumnDefine(comment = "文件id")
private String fileId;
@ColumnDefine(comment = "文件名")
private String name;
@ColumnDefine(comment = "文件大小")
private Integer size;
@ColumnDefine(comment = "文档版本", defaultValue = "1")
private Long version;
@ColumnDefine(comment = "文件位置")
private String filePath;
@Ignore
@Column(ignore = true)
private String key;
public void setFilePath(String filePath) {
this.filePath = filePath;
this.key = filePath;
}
public void setKey(String key) {
this.key = key;
this.filePath = key;
}
}
@@ -0,0 +1,23 @@
package com.cool.modules.space.entity;
import com.cool.core.base.BaseEntity;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
/**
* 图片空间信息分类
*/
@Getter
@Setter
@Table(value = "space_type", comment = "图片空间信息分类")
public class SpaceTypeEntity extends BaseEntity<SpaceTypeEntity> {
@ColumnDefine(comment = "类别名称", notNull = true)
private String name;
@ColumnDefine(comment = "父分类ID", type = "tinyint")
private Integer parentId;
}
@@ -0,0 +1,10 @@
package com.cool.modules.space.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.space.entity.SpaceInfoEntity;
/**
* 文件空间信息
*/
public interface SpaceInfoMapper extends BaseMapper<SpaceInfoEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.space.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.space.entity.SpaceTypeEntity;
/**
* 文件空间信息
*/
public interface SpaceTypeMapper extends BaseMapper<SpaceTypeEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.space.service;
import com.cool.core.base.BaseService;
import com.cool.modules.space.entity.SpaceInfoEntity;
/**
* 文件空间信息
*/
public interface SpaceInfoService extends BaseService<SpaceInfoEntity> {
}
@@ -0,0 +1,10 @@
package com.cool.modules.space.service;
import com.cool.core.base.BaseService;
import com.cool.modules.space.entity.SpaceTypeEntity;
/**
* 文件空间信息
*/
public interface SpaceTypeService extends BaseService<SpaceTypeEntity> {
}
@@ -0,0 +1,15 @@
package com.cool.modules.space.service.impl;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.space.entity.SpaceInfoEntity;
import com.cool.modules.space.mapper.SpaceInfoMapper;
import com.cool.modules.space.service.SpaceInfoService;
import org.springframework.stereotype.Service;
/**
* 文件空间信息
*/
@Service
public class SpaceInfoServiceImpl extends BaseServiceImpl<SpaceInfoMapper, SpaceInfoEntity>
implements SpaceInfoService {
}
@@ -0,0 +1,15 @@
package com.cool.modules.space.service.impl;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.space.entity.SpaceTypeEntity;
import com.cool.modules.space.mapper.SpaceTypeMapper;
import com.cool.modules.space.service.SpaceTypeService;
import org.springframework.stereotype.Service;
/**
* 文件空间信息
*/
@Service
public class SpaceTypeServiceImpl extends BaseServiceImpl<SpaceTypeMapper, SpaceTypeEntity>
implements SpaceTypeService {
}
@@ -0,0 +1,21 @@
package com.cool.modules.task.config;
import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* 定时任务配置
*/
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulerFactoryBeanCustomizer {
@Override
public void customize(SchedulerFactoryBean schedulerFactoryBean) {
schedulerFactoryBean.setStartupDelay(2);
schedulerFactoryBean.setAutoStartup(true);
schedulerFactoryBean.setOverwriteExistingJobs(true);
}
}
@@ -0,0 +1,62 @@
package com.cool.modules.task.controller.admin;
import cn.hutool.json.JSONObject;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.base.BaseController;
import com.cool.core.request.R;
import com.cool.modules.task.entity.TaskInfoEntity;
import com.cool.modules.task.entity.table.TaskInfoEntityTableDef;
import com.cool.modules.task.service.TaskInfoService;
import com.mybatisflex.core.paginate.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import jakarta.servlet.http.HttpServletRequest;
import static com.cool.modules.task.entity.table.TaskInfoEntityTableDef.TASK_INFO_ENTITY;
/**
* 任务
*/
@Tag(name = "任务管理", description = "统一管理任务")
@CoolRestController(api = { "add", "delete", "update", "info", "page" })
public class AdminTaskInfoController extends BaseController<TaskInfoService, TaskInfoEntity> {
@Override
protected void init(HttpServletRequest request, JSONObject requestParams) {
setPageOption(createOp().fieldEq(TASK_INFO_ENTITY.STATUS, TASK_INFO_ENTITY.TYPE));
}
@Operation(summary = "执行一次")
@PostMapping("/once")
public R once(@RequestAttribute JSONObject requestParams) {
service.once(requestParams.getLong("id"));
return R.ok();
}
@Operation(summary = "开始任务")
@PostMapping("/start")
public R start(@RequestAttribute JSONObject requestParams) {
service.start(requestParams.getLong("id"), requestParams.getInt("type"));
return R.ok();
}
@Operation(summary = "停止任务")
@PostMapping("/stop")
public R stop(@RequestAttribute JSONObject requestParams) {
service.stop(requestParams.getLong("id"));
return R.ok();
}
@Operation(summary = "任务日志")
@GetMapping("/log")
public R log(@RequestAttribute JSONObject requestParams) {
Integer page = requestParams.getInt("page", 0);
Integer size = requestParams.getInt("size", 20);
return R.ok(pageResult((Page<TaskInfoEntity>) service.log(new Page<>(page, size), requestParams.getLong("id"),
requestParams.getInt("status"))));
}
}
@@ -0,0 +1,64 @@
package com.cool.modules.task.entity;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@Table(value = "task_info", comment = "任务信息")
public class TaskInfoEntity extends BaseEntity<TaskInfoEntity> {
/**
* 任务调度参数key
*/
@Column(ignore = true)
public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
@ColumnDefine(comment = "名称", notNull = true)
private String name;
@ColumnDefine(comment = "任务ID")
private String jobId;
@ColumnDefine(comment = "最大执行次数 不传为无限次")
private Integer repeatCount;
@ColumnDefine(comment = "每间隔多少毫秒执行一次 如果cron设置了 这项设置就无效")
private Integer every;
@ColumnDefine(comment = "状态 0:停止 1:运行", defaultValue = "1", notNull = true)
private Integer status;
@ColumnDefine(comment = "服务实例名称")
private String service;
@ColumnDefine(comment = "状态 0:cron 1:时间间隔", defaultValue = "0")
private Integer taskType;
@ColumnDefine(comment = "状态 0:系统 1:用户", defaultValue = "0", type = "tinyint")
private Integer type;
@ColumnDefine(comment = "任务数据")
private String data;
@ColumnDefine(comment = "备注")
private String remark;
@ColumnDefine(comment = "cron")
private String cron;
@ColumnDefine(comment = "下一次执行时间")
private Date nextRunTime;
@ColumnDefine(comment = "开始时间")
private Date startDate;
@ColumnDefine(comment = "结束时间")
private Date endDate;
}
@@ -0,0 +1,30 @@
package com.cool.modules.task.entity;
import com.cool.core.base.BaseEntity;
import com.mybatisflex.annotation.Column;
import com.tangzc.autotable.annotation.Index;
import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine;
import com.mybatisflex.annotation.Table;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Table(value = "task_log", comment = "任务日志")
public class TaskLogEntity extends BaseEntity<TaskLogEntity> {
@Index
@ColumnDefine(comment = "任务ID", notNull = true, type = "bigint")
private Long taskId;
@ColumnDefine(comment = "状态 0:失败 1:成功", defaultValue = "0")
private Integer status;
@ColumnDefine(comment = "详情", type = "text")
private String detail;
// 任务名称
@Column(ignore = true)
private String taskName;
}
@@ -0,0 +1,26 @@
package com.cool.modules.task.event;
import com.cool.core.init.DBFromJsonInit;
import com.cool.modules.task.service.TaskInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* 事件监听
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TaskEvent {
final private TaskInfoService taskInfoService;
@EventListener
public void handleDbInitCompleteEvent(DBFromJsonInit.DbInitCompleteEvent event) {
taskInfoService.init();
log.info("初始化任务");
}
}
@@ -0,0 +1,8 @@
package com.cool.modules.task.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.task.entity.TaskInfoEntity;
public interface TaskInfoMapper extends BaseMapper<TaskInfoEntity> {
}
@@ -0,0 +1,8 @@
package com.cool.modules.task.mapper;
import com.mybatisflex.core.BaseMapper;
import com.cool.modules.task.entity.TaskLogEntity;
public interface TaskLogMapper extends BaseMapper<TaskLogEntity> {
}
@@ -0,0 +1,106 @@
package com.cool.modules.task.run;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.cool.modules.task.entity.TaskInfoEntity;
import com.cool.modules.task.entity.TaskLogEntity;
import com.cool.modules.task.service.TaskInfoLogService;
import com.cool.modules.task.service.TaskInfoService;
import com.mybatisflex.core.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 定时任务
*/
@Slf4j
public class ScheduleJob extends QuartzJobBean {
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
protected void executeInternal(JobExecutionContext context) {
// 获取spring bean
TaskInfoLogService taskInfoLogService = SpringUtil.getBean(TaskInfoLogService.class);
// 获取spring bean
TaskInfoService taskInfoService = SpringUtil.getBean(TaskInfoService.class);
Scheduler scheduler = SpringUtil.getBean(Scheduler.class);
TaskInfoEntity taskInfoEntity = taskInfoService
.getById(context.getJobDetail().getKey().getName().split("_")[1]);
if (ObjUtil.isEmpty(taskInfoEntity)) {
log.warn("taskInfoEntity is null");
return;
}
// 数据库保存执行记录
TaskLogEntity taskLogEntity = new TaskLogEntity();
// 任务开始时间
long startTime = System.currentTimeMillis();
try {
// 执行任务
log.info("任务准备执行,任务ID:" + taskInfoEntity.getJobId());
taskLogEntity.setTaskId(taskInfoEntity.getId());
// 解析执行
String service = taskInfoEntity.getService();
if (StrUtil.isNotEmpty(service)) {
String[] arr = service.split("\\.");
String methodName = arr[1].substring(0, arr[1].indexOf("("));
String params = service.substring(service.indexOf("(") + 1, service.indexOf(")"));
ScheduleRunnable task = new ScheduleRunnable(StringUtil.firstCharToLowerCase(arr[0]).replaceAll(" ", ""), methodName, params);
Future<?> future = executorService.submit(task);
future.get();
}
// 任务执行总时长
long times = System.currentTimeMillis() - startTime;
// 状态 0:失败 1:成功
taskLogEntity.setStatus(1);
taskLogEntity.setDetail("任务执行完毕,任务ID:" + taskInfoEntity.getJobId() + " 总共耗时:" + times + "毫秒");
log.info(taskLogEntity.getDetail());
} catch (Exception e) {
// 任务执行总时长
long times = System.currentTimeMillis() - startTime;
taskLogEntity.setDetail(
"任务执行失败,任务ID:" + taskInfoEntity.getJobId() + " 总共耗时:" + times + "毫秒" + "失败原因:" + e.getMessage());
log.error("任务执行失败,任务ID:" + taskInfoEntity.getJobId(), e);
// 状态 0:失败 1:成功
taskLogEntity.setStatus(0);
} finally {
taskInfoLogService.add(taskLogEntity);
}
ThreadUtil.execAsync(() -> {
ThreadUtil.sleep(2000);
TaskInfoEntity next = new TaskInfoEntity();
next.setId(taskInfoEntity.getId());
try {
if (!scheduler.checkExists(context.getTrigger().getJobKey())) {
if (context.getTrigger().getNextFireTime() == null) {
next.setStatus(0);
}
} else {
if (context.getTrigger().getNextFireTime() == null) {
next.setNextRunTime(context.getTrigger().getNextFireTime());
}
}
} catch (SchedulerException e) {
log.error("err", e);
}
taskInfoService.updateById(next);
});
}
}
@@ -0,0 +1,101 @@
package com.cool.modules.task.run;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.cool.core.exception.CoolException;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
* 执行定时任务
*/
public class ScheduleRunnable implements Runnable {
private final Object target;
private final Method method;
private final Object[] params;
public ScheduleRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException {
this.target = SpringUtil.getBean(beanName);
if (StrUtil.isNotBlank(params)) {
String[] paramArray = params.split(",");
this.params = new Object[paramArray.length];
Class<?>[] paramTypes = new Class<?>[paramArray.length];
for (int i = 0; i < paramArray.length; i++) {
String param = paramArray[i].trim();
if (param.matches("-?\\d+")) {
this.params[i] = Integer.parseInt(param);
paramTypes[i] = int.class;
} else if (param.matches("-?\\d+L")) {
this.params[i] = Long.parseLong(param.substring(0, param.length() - 1));
paramTypes[i] = long.class;
} else if (param.matches("-?\\d+\\.\\d+")) {
this.params[i] = Double.parseDouble(param);
paramTypes[i] = double.class;
} else if (param.matches("-?\\d+\\.\\d+f")) {
this.params[i] = Float.parseFloat(param.substring(0, param.length() - 1));
paramTypes[i] = float.class;
} else if (param.equalsIgnoreCase("true") || param.equalsIgnoreCase("false")) {
this.params[i] = Boolean.parseBoolean(param);
paramTypes[i] = boolean.class;
} else if (param.length() == 1) {
this.params[i] = param.charAt(0);
paramTypes[i] = char.class;
} else {
// Remove leading and trailing quotation marks for string parameters
if (param.startsWith("\"") && param.endsWith("\"")) {
param = param.substring(1, param.length() - 1);
}
this.params[i] = param;
paramTypes[i] = String.class;
}
}
this.method = findMethod(target.getClass(), methodName, paramTypes);
} else {
this.params = new Object[0];
this.method = target.getClass().getDeclaredMethod(methodName);
}
}
private Method findMethod(Class<?> targetClass, String methodName, Class<?>[] paramTypes) throws NoSuchMethodException {
try {
return targetClass.getDeclaredMethod(methodName, paramTypes);
} catch (NoSuchMethodException e) {
// Try with wrapper classes
for (int i = 0; i < paramTypes.length; i++) {
if (paramTypes[i] == int.class) {
paramTypes[i] = Integer.class;
} else if (paramTypes[i] == long.class) {
paramTypes[i] = Long.class;
} else if (paramTypes[i] == double.class) {
paramTypes[i] = Double.class;
} else if (paramTypes[i] == float.class) {
paramTypes[i] = Float.class;
} else if (paramTypes[i] == boolean.class) {
paramTypes[i] = Boolean.class;
} else if (paramTypes[i] == char.class) {
paramTypes[i] = Character.class;
}
}
return targetClass.getDeclaredMethod(methodName, paramTypes);
}
}
@Override
public void run() {
try {
ReflectionUtils.makeAccessible(method);
if (params.length > 0) {
method.invoke(target, params);
} else {
method.invoke(target);
}
} catch (Exception e) {
throw new CoolException("执行定时任务失败", e);
}
}
}
@@ -0,0 +1,10 @@
package com.cool.modules.task.service;
import com.cool.core.base.BaseService;
import com.cool.modules.task.entity.TaskLogEntity;
/**
* 任务日志
*/
public interface TaskInfoLogService extends BaseService<TaskLogEntity> {
}
@@ -0,0 +1,48 @@
package com.cool.modules.task.service;
import com.cool.core.base.BaseService;
import com.cool.modules.task.entity.TaskInfoEntity;
import com.cool.modules.task.entity.TaskLogEntity;
import com.mybatisflex.core.paginate.Page;
/**
* 任务信息
*/
public interface TaskInfoService extends BaseService<TaskInfoEntity> {
/**
* 初始化任务
*/
void init();
/**
* 执行一次
*
* @param taskId 任务ID
*/
void once(Long taskId);
/**
* 停止任务
*
* @param taskId 任务ID
*/
void stop(Long taskId);
/**
* 任务日志
*
* @param taskId 任务ID
* @param status 任务状态
* @return 日志列表
*/
Object log(Page<TaskLogEntity> page, Long taskId, Integer status);
/**
* 开始任务
*
* @param taskId 任务ID
* @param type 任务类型
*/
void start(Long taskId, Integer type);
}
@@ -0,0 +1,12 @@
package com.cool.modules.task.service.impl;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.task.entity.TaskLogEntity;
import com.cool.modules.task.mapper.TaskLogMapper;
import com.cool.modules.task.service.TaskInfoLogService;
import org.springframework.stereotype.Service;
@Service
public class TaskInfoLogServiceImpl extends BaseServiceImpl<TaskLogMapper, TaskLogEntity>
implements TaskInfoLogService {
}
@@ -0,0 +1,138 @@
package com.cool.modules.task.service.impl;
import static com.cool.modules.task.entity.table.TaskInfoEntityTableDef.TASK_INFO_ENTITY;
import static com.cool.modules.task.entity.table.TaskLogEntityTableDef.TASK_LOG_ENTITY;
import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cool.core.base.BaseServiceImpl;
import com.cool.modules.task.entity.TaskInfoEntity;
import com.cool.modules.task.entity.TaskLogEntity;
import com.cool.modules.task.mapper.TaskInfoMapper;
import com.cool.modules.task.service.TaskInfoService;
import com.cool.modules.task.utils.ScheduleUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor
public class TaskInfoServiceImpl extends BaseServiceImpl<TaskInfoMapper, TaskInfoEntity> implements
TaskInfoService {
final private Scheduler scheduler;
@Override
public void init() {
try {
List<TaskInfoEntity> list = list();
list.forEach(scheduleJob -> {
CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler,
scheduleJob.getJobId());
if (cronTrigger == null) {
ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
} else {
ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
}
updateById(scheduleJob);
});
} catch (Exception ignored) {
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void once(Long taskId) {
ScheduleUtils.run(scheduler, getById(taskId));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void stop(Long taskId) {
ScheduleUtils.pauseJob(scheduler, taskId + "");
TaskInfoEntity taskInfoEntity = getById(taskId);
taskInfoEntity.setStatus(0);
updateById(taskInfoEntity);
modifyAfter(JSONUtil.parseObj(taskInfoEntity), taskInfoEntity);
}
@Override
public Object log(Page page, Long taskId, Integer status) {
QueryWrapper queryWrapper = QueryWrapper.create().select(TASK_LOG_ENTITY.ALL_COLUMNS,
TASK_INFO_ENTITY.NAME.as("taskName")).from(TASK_LOG_ENTITY)
.leftJoin(TASK_INFO_ENTITY).on(TASK_LOG_ENTITY.TASK_ID.eq(TASK_INFO_ENTITY.ID))
.eq(TaskLogEntity::getTaskId, taskId, taskId != null)
.eq(TaskLogEntity::getStatus, status, status != null)
.orderBy(TaskLogEntity::getCreateTime, false);
return mapper.paginate(page, queryWrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void start(Long taskId, Integer type) {
TaskInfoEntity taskInfoEntity = getById(taskId);
taskInfoEntity.setStatus(1);
if (type != null) {
taskInfoEntity.setType(type);
}
boolean isExists = false;
try {
isExists = scheduler.checkExists(ScheduleUtils.getJobKey(taskId + ""));
} catch (SchedulerException e) {
log.error("err", e);
}
if (isExists) {
ScheduleUtils.updateScheduleJob(scheduler, taskInfoEntity);
ScheduleUtils.resumeJob(scheduler, taskId + "");
} else {
ScheduleUtils.createScheduleJob(scheduler, taskInfoEntity);
}
updateById(taskInfoEntity);
modifyAfter(JSONUtil.parseObj(taskInfoEntity), taskInfoEntity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long add(JSONObject requestParams, TaskInfoEntity scheduleJob) {
scheduleJob.setStatus(1);
super.add(scheduleJob);
scheduleJob.setJobId(scheduleJob.getId() + "");
ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
updateById(scheduleJob);
super.modifyAfter(requestParams, scheduleJob);
return scheduleJob.getId();
}
@Override
public boolean update(JSONObject requestParams, TaskInfoEntity entity) {
updateById(entity);
ScheduleUtils.deleteScheduleJob(scheduler, entity.getId().toString());
if (entity.getStatus() == 1) {
start(entity.getId(), entity.getType());
} else {
stop(entity.getId());
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean delete(JSONObject requestParams, Long... ids) {
Convert.toList(String.class, ids).forEach(jobId -> {
ScheduleUtils.deleteScheduleJob(scheduler, jobId);
});
return super.delete(requestParams, ids);
}
}
@@ -0,0 +1,251 @@
package com.cool.modules.task.utils;
import com.cool.core.exception.CoolException;
import com.cool.modules.task.entity.TaskInfoEntity;
import com.cool.modules.task.run.ScheduleJob;
import org.quartz.*;
/**
* 定时任务工具类
*
* @author Mark sunlightcs@gmail.com
* @since 1.2.0 2016-11-28
*/
public class ScheduleUtils {
private final static String JOB_NAME = "TASK_";
public enum ScheduleStatus {
/**
* 暂停
*/
PAUSE(0),
/**
* 正常
*/
NORMAL(1);
private int value;
ScheduleStatus(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
/**
* 获取触发器key
*/
public static TriggerKey getTriggerKey(String jobId) {
return TriggerKey.triggerKey(JOB_NAME + jobId);
}
/**
* 获取jobKey
*/
public static JobKey getJobKey(String jobId) {
return JobKey.jobKey(JOB_NAME + jobId);
}
/**
* 获取表达式触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
throw new CoolException("获取定时任务CronTrigger出现异常", e);
}
}
/**
* 获取表达式触发器
*/
public static SimpleTrigger getSimpleTrigger(Scheduler scheduler, String jobId) {
try {
return (SimpleTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
throw new CoolException("获取定时任务CronTrigger出现异常", e);
}
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, TaskInfoEntity scheduleJob) {
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getJobId()))
.build();
if (scheduleJob.getTaskType() == 0) {
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCron())
.withMisfireHandlingInstructionDoNothing();
TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder);
if (scheduleJob.getStartDate() != null) {
triggerBuilder.startAt(scheduleJob.getStartDate());
}
if (scheduleJob.getEndDate() != null) {
triggerBuilder.endAt(scheduleJob.getEndDate());
}
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = triggerBuilder.build();
scheduler.scheduleJob(jobDetail, trigger);
scheduleJob.setNextRunTime(trigger.getNextFireTime());
}
if (scheduleJob.getTaskType() == 1) {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(scheduleJob.getEvery() / 1000);
if (scheduleJob.getRepeatCount() != null) {
scheduleBuilder.withRepeatCount(scheduleJob.getRepeatCount());
} else {
scheduleBuilder.repeatForever();
}
TriggerBuilder<SimpleTrigger> triggerBuilder = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder);
if (scheduleJob.getStartDate() != null) {
triggerBuilder.startAt(scheduleJob.getStartDate());
}
if (scheduleJob.getEndDate() != null) {
triggerBuilder.endAt(scheduleJob.getEndDate());
}
Trigger trigger = triggerBuilder.build();
scheduler.scheduleJob(jobDetail, trigger);
scheduleJob.setNextRunTime(trigger.getNextFireTime());
}
// 暂停任务
if (scheduleJob.getStatus() != null && scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
pauseJob(scheduler, scheduleJob.getJobId());
}
} catch (SchedulerException e) {
throw new CoolException("创建定时任务失败", e);
}
}
/**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, TaskInfoEntity scheduleJob) {
try {
TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());
if (scheduleJob.getTaskType() == 0) {
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCron())
.withMisfireHandlingInstructionDoNothing();
CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());
TriggerBuilder<CronTrigger> triggerBuilder = trigger.getTriggerBuilder();
if (scheduleJob.getStartDate() != null) {
triggerBuilder.startAt(scheduleJob.getStartDate());
}
if (scheduleJob.getEndDate() != null) {
triggerBuilder.endAt(scheduleJob.getEndDate());
}
// 按新的cronExpression表达式重新构建trigger
trigger = triggerBuilder.withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
scheduleJob.setNextRunTime(trigger.getNextFireTime());
}
if (scheduleJob.getTaskType() == 1) {
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(scheduleJob.getEvery() / 1000);
SimpleTrigger trigger = getSimpleTrigger(scheduler, scheduleJob.getJobId());
if (scheduleJob.getRepeatCount() != null) {
scheduleBuilder.withRepeatCount(scheduleJob.getRepeatCount());
} else {
scheduleBuilder.repeatForever();
}
TriggerBuilder<SimpleTrigger> triggerBuilder = trigger.getTriggerBuilder();
if (scheduleJob.getStartDate() != null) {
triggerBuilder.startAt(scheduleJob.getStartDate());
}
if (scheduleJob.getEndDate() != null) {
triggerBuilder.endAt(scheduleJob.getEndDate());
}
trigger = triggerBuilder.withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
scheduleJob.setNextRunTime(trigger.getNextFireTime());
}
// 暂停任务
if (scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
pauseJob(scheduler, scheduleJob.getJobId());
}
} catch (SchedulerException e) {
throw new CoolException("更新定时任务失败", e);
}
}
/**
* 立即执行任务
*/
public static void run(Scheduler scheduler, TaskInfoEntity scheduleJob) {
try {
// 参数
JobDataMap dataMap = new JobDataMap();
scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap);
} catch (SchedulerException e) {
throw new CoolException("立即执行定时任务失败", e);
}
}
/**
* 暂停任务
*/
public static void pauseJob(Scheduler scheduler, String jobId) {
try {
scheduler.pauseJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new CoolException("暂停定时任务失败", e);
}
}
/**
* 恢复任务
*/
public static void resumeJob(Scheduler scheduler, String jobId) {
try {
scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new CoolException("恢复定时任务失败", e);
}
}
/**
* 删除定时任务
*/
public static void deleteScheduleJob(Scheduler scheduler, String jobId) {
try {
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new CoolException("删除定时任务失败", e);
}
}
}

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