forked from gin/simple-template
feat: initial commit
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.domain.common.cache;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.agileboot.infrastructure.cache.guava.AbstractGuavaCacheTemplate;
|
||||
import com.agileboot.infrastructure.cache.redis.RedisCacheTemplate;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.agileboot.domain.system.role.db.SysRoleEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import javax.annotation.PostConstruct;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 缓存中心 提供全局访问点
|
||||
* 如果是领域类的缓存 可以自己新建一个直接放在CacheCenter 不用放在infrastructure包里的GuavaCacheService
|
||||
* 或者RedisCacheService
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
public class CacheCenter {
|
||||
|
||||
public static AbstractGuavaCacheTemplate<String> configCache;
|
||||
|
||||
public static AbstractGuavaCacheTemplate<SysDeptEntity> deptCache;
|
||||
|
||||
public static RedisCacheTemplate<String> captchaCache;
|
||||
|
||||
public static RedisCacheTemplate<SystemLoginUser> loginUserCache;
|
||||
|
||||
public static RedisCacheTemplate<SysUserEntity> userCache;
|
||||
|
||||
public static RedisCacheTemplate<SysRoleEntity> roleCache;
|
||||
|
||||
public static RedisCacheTemplate<SysPostEntity> postCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
GuavaCacheService guavaCache = SpringUtil.getBean(GuavaCacheService.class);
|
||||
RedisCacheService redisCache = SpringUtil.getBean(RedisCacheService.class);
|
||||
|
||||
configCache = guavaCache.configCache;
|
||||
deptCache = guavaCache.deptCache;
|
||||
|
||||
captchaCache = redisCache.captchaCache;
|
||||
loginUserCache = redisCache.loginUserCache;
|
||||
userCache = redisCache.userCache;
|
||||
roleCache = redisCache.roleCache;
|
||||
postCache = redisCache.postCache;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
package com.agileboot.domain.common.cache;
|
||||
|
||||
|
||||
import com.agileboot.infrastructure.cache.guava.AbstractGuavaCacheTemplate;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.agileboot.domain.system.config.db.SysConfigService;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class GuavaCacheService {
|
||||
|
||||
private final SysConfigService configService;
|
||||
|
||||
private final SysDeptService deptService;
|
||||
|
||||
public final AbstractGuavaCacheTemplate<String> configCache = new AbstractGuavaCacheTemplate<String>() {
|
||||
@Override
|
||||
public String getObjectFromDb(Object id) {
|
||||
return configService.getConfigValueByKey(id.toString());
|
||||
}
|
||||
};
|
||||
|
||||
public final AbstractGuavaCacheTemplate<SysDeptEntity> deptCache = new AbstractGuavaCacheTemplate<SysDeptEntity>() {
|
||||
@Override
|
||||
public SysDeptEntity getObjectFromDb(Object id) {
|
||||
return deptService.getById(id.toString());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
package com.agileboot.domain.common.cache;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.agileboot.common.enums.common.BusinessTypeEnum;
|
||||
import com.agileboot.common.enums.common.GenderEnum;
|
||||
import com.agileboot.common.enums.common.LoginStatusEnum;
|
||||
import com.agileboot.common.enums.common.NoticeStatusEnum;
|
||||
import com.agileboot.common.enums.common.NoticeTypeEnum;
|
||||
import com.agileboot.common.enums.common.OperationStatusEnum;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.common.UserStatusEnum;
|
||||
import com.agileboot.common.enums.common.VisibleStatusEnum;
|
||||
import com.agileboot.common.enums.common.YesOrNoEnum;
|
||||
import com.agileboot.common.enums.dictionary.Dictionary;
|
||||
import com.agileboot.common.enums.DictionaryEnum;
|
||||
import com.agileboot.common.enums.dictionary.DictionaryData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 本地一级缓存 使用Map
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class MapCache {
|
||||
|
||||
private static final Map<String, List<DictionaryData>> DICTIONARY_CACHE = MapUtil.newHashMap(128);
|
||||
|
||||
private MapCache() {
|
||||
}
|
||||
|
||||
static {
|
||||
initDictionaryCache();
|
||||
}
|
||||
|
||||
private static void initDictionaryCache() {
|
||||
// TODO 这个可以做成自动扫描
|
||||
loadInCache(BusinessTypeEnum.values());
|
||||
loadInCache(YesOrNoEnum.values());
|
||||
loadInCache(StatusEnum.values());
|
||||
loadInCache(GenderEnum.values());
|
||||
loadInCache(NoticeStatusEnum.values());
|
||||
loadInCache(NoticeTypeEnum.values());
|
||||
loadInCache(OperationStatusEnum.values());
|
||||
loadInCache(LoginStatusEnum.values());
|
||||
loadInCache(VisibleStatusEnum.values());
|
||||
loadInCache(UserStatusEnum.values());
|
||||
}
|
||||
|
||||
|
||||
public static Map<String, List<DictionaryData>> dictionaryCache() {
|
||||
return DICTIONARY_CACHE;
|
||||
}
|
||||
|
||||
private static void loadInCache(DictionaryEnum[] dictionaryEnums) {
|
||||
DICTIONARY_CACHE.put(getDictionaryName(dictionaryEnums[0].getClass()), arrayToList(dictionaryEnums));
|
||||
}
|
||||
|
||||
|
||||
private static String getDictionaryName(Class<?> clazz) {
|
||||
Objects.requireNonNull(clazz);
|
||||
Dictionary annotation = clazz.getAnnotation(Dictionary.class);
|
||||
|
||||
Objects.requireNonNull(annotation);
|
||||
return annotation.name();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<DictionaryData> arrayToList(DictionaryEnum[] dictionaryEnums) {
|
||||
if(ArrayUtil.isEmpty(dictionaryEnums)) {
|
||||
return ListUtil.empty();
|
||||
}
|
||||
return Arrays.stream(dictionaryEnums).map(DictionaryData::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Vendored
+82
@@ -0,0 +1,82 @@
|
||||
package com.agileboot.domain.common.cache;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import com.agileboot.infrastructure.cache.redis.CacheKeyEnum;
|
||||
import com.agileboot.infrastructure.cache.redis.RedisCacheTemplate;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.agileboot.domain.system.role.db.SysRoleEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import com.agileboot.domain.system.post.db.SysPostService;
|
||||
import com.agileboot.domain.system.role.db.SysRoleService;
|
||||
import com.agileboot.domain.system.user.db.SysUserService;
|
||||
import java.io.Serializable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RedisCacheService {
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
public RedisCacheTemplate<String> captchaCache;
|
||||
public RedisCacheTemplate<SystemLoginUser> loginUserCache;
|
||||
public RedisCacheTemplate<SysUserEntity> userCache;
|
||||
public RedisCacheTemplate<SysRoleEntity> roleCache;
|
||||
|
||||
public RedisCacheTemplate<SysPostEntity> postCache;
|
||||
|
||||
// public RedisCacheTemplate<RoleInfo> roleModelInfoCache;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
||||
captchaCache = new RedisCacheTemplate<>(redisUtil, CacheKeyEnum.CAPTCHAT);
|
||||
|
||||
loginUserCache = new RedisCacheTemplate<>(redisUtil, CacheKeyEnum.LOGIN_USER_KEY);
|
||||
|
||||
userCache = new RedisCacheTemplate<SysUserEntity>(redisUtil, CacheKeyEnum.USER_ENTITY_KEY) {
|
||||
@Override
|
||||
public SysUserEntity getObjectFromDb(Object id) {
|
||||
SysUserService userService = SpringUtil.getBean(SysUserService.class);
|
||||
return userService.getById((Serializable) id);
|
||||
}
|
||||
};
|
||||
|
||||
roleCache = new RedisCacheTemplate<SysRoleEntity>(redisUtil, CacheKeyEnum.ROLE_ENTITY_KEY) {
|
||||
@Override
|
||||
public SysRoleEntity getObjectFromDb(Object id) {
|
||||
SysRoleService roleService = SpringUtil.getBean(SysRoleService.class);
|
||||
return roleService.getById((Serializable) id);
|
||||
}
|
||||
};
|
||||
|
||||
// roleModelInfoCache = new RedisCacheTemplate<RoleInfo>(redisUtil, CacheKeyEnum.ROLE_MODEL_INFO_KEY) {
|
||||
// @Override
|
||||
// public RoleInfo getObjectFromDb(Object id) {
|
||||
// UserDetailsService userDetailsService = SpringUtil.getBean(UserDetailsService.class);
|
||||
// return userDetailsService.getRoleInfo((Long) id);
|
||||
// }
|
||||
//
|
||||
// };
|
||||
|
||||
postCache = new RedisCacheTemplate<SysPostEntity>(redisUtil, CacheKeyEnum.POST_ENTITY_KEY) {
|
||||
@Override
|
||||
public SysPostEntity getObjectFromDb(Object id) {
|
||||
SysPostService postService = SpringUtil.getBean(SysPostService.class);
|
||||
return postService.getById((Serializable) id);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.agileboot.domain.common.command;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class BulkOperationCommand<T> {
|
||||
|
||||
public BulkOperationCommand(List<T> idList) {
|
||||
if (CollUtil.isEmpty(idList)) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_BULK_DELETE_IDS_IS_INVALID);
|
||||
}
|
||||
// 移除重复元素
|
||||
this.ids = new HashSet<>(idList);
|
||||
}
|
||||
|
||||
private Set<T> ids;
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.agileboot.domain.common.dto;
|
||||
|
||||
import com.agileboot.domain.system.user.dto.UserDTO;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class CurrentLoginUserDTO {
|
||||
|
||||
private UserDTO userInfo;
|
||||
private String roleKey;
|
||||
private Set<String> permissions;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.domain.common.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class TokenDTO {
|
||||
|
||||
private String token;
|
||||
|
||||
private CurrentLoginUserDTO currentUser;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.common.dto;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TreeSelectedDTO {
|
||||
|
||||
private List<Long> checkedKeys;
|
||||
private List<Tree<Long>> menus;
|
||||
private List<Tree<Long>> depts;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.agileboot.domain.common.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class UploadDTO {
|
||||
|
||||
private String url;
|
||||
private String fileName;
|
||||
private String newFileName;
|
||||
private String originalFilename;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.common.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UploadFileDTO {
|
||||
|
||||
public UploadFileDTO(String imgUrl) {
|
||||
this.imgUrl = imgUrl;
|
||||
}
|
||||
|
||||
private String imgUrl;
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.domain.system.config;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.system.config.command.ConfigUpdateCommand;
|
||||
import com.agileboot.domain.system.config.dto.ConfigDTO;
|
||||
import com.agileboot.domain.system.config.model.ConfigModel;
|
||||
import com.agileboot.domain.system.config.model.ConfigModelFactory;
|
||||
import com.agileboot.domain.system.config.query.ConfigQuery;
|
||||
import com.agileboot.domain.system.config.db.SysConfigEntity;
|
||||
import com.agileboot.domain.system.config.db.SysConfigService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ConfigApplicationService {
|
||||
|
||||
private final ConfigModelFactory configModelFactory;
|
||||
|
||||
private final SysConfigService configService;
|
||||
|
||||
public PageDTO<ConfigDTO> getConfigList(ConfigQuery query) {
|
||||
Page<SysConfigEntity> page = configService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<ConfigDTO> records = page.getRecords().stream().map(ConfigDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
public ConfigDTO getConfigInfo(Long id) {
|
||||
SysConfigEntity byId = configService.getById(id);
|
||||
return new ConfigDTO(byId);
|
||||
}
|
||||
|
||||
public void updateConfig(ConfigUpdateCommand updateCommand) {
|
||||
ConfigModel configModel = configModelFactory.loadById(updateCommand.getConfigId());
|
||||
configModel.loadUpdateCommand(updateCommand);
|
||||
|
||||
configModel.checkCanBeModify();
|
||||
|
||||
configModel.updateById();
|
||||
|
||||
CacheCenter.configCache.invalidate(configModel.getConfigKey());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.agileboot.domain.system.config.command;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@Schema
|
||||
public class ConfigUpdateCommand {
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
private Long configId;
|
||||
|
||||
@NotNull
|
||||
@NotEmpty
|
||||
private String configValue;
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-11-03
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_config")
|
||||
@ApiModel(value = "SysConfigEntity对象", description = "参数配置表")
|
||||
public class SysConfigEntity extends BaseEntity<SysConfigEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("参数主键")
|
||||
@TableId(value = "config_id", type = IdType.AUTO)
|
||||
private Integer configId;
|
||||
|
||||
@ApiModelProperty("配置名称")
|
||||
@TableField("config_name")
|
||||
private String configName;
|
||||
|
||||
@ApiModelProperty("配置键名")
|
||||
@TableField("config_key")
|
||||
private String configKey;
|
||||
|
||||
@ApiModelProperty("可选的选项")
|
||||
@TableField("config_options")
|
||||
private String configOptions;
|
||||
|
||||
@ApiModelProperty("配置值")
|
||||
@TableField("config_value")
|
||||
private String configValue;
|
||||
|
||||
@ApiModelProperty("是否允许修改")
|
||||
@TableField("is_allow_change")
|
||||
private Boolean isAllowChange;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.configId;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
public interface SysConfigMapper extends BaseMapper<SysConfigEntity> {
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
public interface SysConfigService extends IService<SysConfigEntity> {
|
||||
|
||||
/**
|
||||
* 通过key获取配置
|
||||
*
|
||||
* @param key 配置对应的key
|
||||
* @return 配置
|
||||
*/
|
||||
String getConfigValueByKey(String key);
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.agileboot.domain.system.config.db;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 参数配置表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-09
|
||||
*/
|
||||
@Service
|
||||
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfigEntity> implements
|
||||
SysConfigService {
|
||||
|
||||
@Override
|
||||
public String getConfigValueByKey(String key) {
|
||||
if (StrUtil.isBlank(key)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
QueryWrapper<SysConfigEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("config_key", key);
|
||||
SysConfigEntity one = this.getOne(queryWrapper);
|
||||
if (one == null || one.getConfigValue() == null) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
return one.getConfigValue();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.agileboot.domain.system.config.dto;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.enums.common.YesOrNoEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.config.db.SysConfigEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "ConfigDTO", description = "配置信息")
|
||||
public class ConfigDTO {
|
||||
|
||||
public ConfigDTO(SysConfigEntity entity) {
|
||||
if (entity != null) {
|
||||
configId = entity.getConfigId() + "";
|
||||
configName = entity.getConfigName();
|
||||
configKey = entity.getConfigKey();
|
||||
configValue = entity.getConfigValue();
|
||||
configOptions =
|
||||
JSONUtil.isTypeJSONArray(entity.getConfigOptions()) ? JSONUtil.toList(entity.getConfigOptions(),
|
||||
String.class) : ListUtil.empty();
|
||||
isAllowChange = Convert.toInt(entity.getIsAllowChange());
|
||||
isAllowChangeStr = BasicEnumUtil.getDescriptionByBool(YesOrNoEnum.class, entity.getIsAllowChange());
|
||||
remark = entity.getRemark();
|
||||
createTime = entity.getCreateTime();
|
||||
}
|
||||
}
|
||||
|
||||
private String configId;
|
||||
private String configName;
|
||||
private String configKey;
|
||||
private String configValue;
|
||||
private List<String> configOptions;
|
||||
private Integer isAllowChange;
|
||||
private String isAllowChangeStr;
|
||||
private String remark;
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.agileboot.domain.system.config.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.config.command.ConfigUpdateCommand;
|
||||
import com.agileboot.domain.system.config.db.SysConfigEntity;
|
||||
import com.agileboot.domain.system.config.db.SysConfigService;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class ConfigModel extends SysConfigEntity {
|
||||
|
||||
private SysConfigService configService;
|
||||
|
||||
private Set<String> configOptionSet;
|
||||
|
||||
public ConfigModel(SysConfigService configService) {
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
public ConfigModel(SysConfigEntity entity, SysConfigService configService) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
|
||||
List<String> options =
|
||||
JSONUtil.isTypeJSONArray(entity.getConfigOptions()) ? JSONUtil.toList(entity.getConfigOptions(),
|
||||
String.class) : ListUtil.empty();
|
||||
|
||||
this.configOptionSet = new HashSet<>(options);
|
||||
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(ConfigUpdateCommand updateCommand) {
|
||||
this.setConfigValue(updateCommand.getConfigValue());
|
||||
}
|
||||
|
||||
|
||||
public void checkCanBeModify() {
|
||||
if (StrUtil.isBlank(getConfigValue())) {
|
||||
throw new ApiException(ErrorCode.Business.CONFIG_VALUE_IS_NOT_ALLOW_TO_EMPTY);
|
||||
}
|
||||
|
||||
if (!configOptionSet.isEmpty() && !configOptionSet.contains(getConfigValue())) {
|
||||
throw new ApiException(ErrorCode.Business.CONFIG_VALUE_IS_NOT_IN_OPTIONS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.agileboot.domain.system.config.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.config.db.SysConfigEntity;
|
||||
import com.agileboot.domain.system.config.db.SysConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 配置模型工厂
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ConfigModelFactory {
|
||||
|
||||
private final SysConfigService configService;
|
||||
|
||||
public ConfigModel loadById(Long configId) {
|
||||
SysConfigEntity byId = configService.getById(configId);
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, configId, "参数配置");
|
||||
}
|
||||
return new ConfigModel(byId, configService);
|
||||
}
|
||||
|
||||
public ConfigModel create() {
|
||||
return new ConfigModel(configService);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.agileboot.domain.system.config.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.agileboot.domain.system.config.db.SysConfigEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@Schema(name = "配置查询参数")
|
||||
public class ConfigQuery extends AbstractPageQuery<SysConfigEntity> {
|
||||
|
||||
@Schema(description = "配置名称")
|
||||
private String configName;
|
||||
|
||||
@Schema(description = "配置key")
|
||||
private String configKey;
|
||||
|
||||
@Schema(description = "是否允许更改配置")
|
||||
private Boolean isAllowChange;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysConfigEntity> addQueryCondition() {
|
||||
QueryWrapper<SysConfigEntity> queryWrapper = new QueryWrapper<SysConfigEntity>()
|
||||
.like(StrUtil.isNotEmpty(configName), "config_name", configName)
|
||||
.eq(StrUtil.isNotEmpty(configKey), "config_key", configKey)
|
||||
.eq(isAllowChange != null, "is_allow_change", isAllowChange);
|
||||
|
||||
this.timeRangeColumn = "create_time";
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.agileboot.domain.system.dept;
|
||||
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import com.agileboot.domain.system.dept.command.AddDeptCommand;
|
||||
import com.agileboot.domain.system.dept.command.UpdateDeptCommand;
|
||||
import com.agileboot.domain.system.dept.dto.DeptDTO;
|
||||
import com.agileboot.domain.system.dept.model.DeptModel;
|
||||
import com.agileboot.domain.system.dept.model.DeptModelFactory;
|
||||
import com.agileboot.domain.system.dept.query.DeptQuery;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptService;
|
||||
import com.agileboot.domain.system.role.db.SysRoleService;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 部门服务
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeptApplicationService {
|
||||
|
||||
private final SysDeptService deptService;
|
||||
|
||||
private final SysRoleService roleService;
|
||||
|
||||
private final DeptModelFactory deptModelFactory;
|
||||
|
||||
|
||||
public List<DeptDTO> getDeptList(DeptQuery query) {
|
||||
List<SysDeptEntity> list = deptService.list(query.toQueryWrapper());
|
||||
return list.stream().map(DeptDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public DeptDTO getDeptInfo(Long id) {
|
||||
SysDeptEntity byId = deptService.getById(id);
|
||||
return new DeptDTO(byId);
|
||||
}
|
||||
|
||||
public List<Tree<Long>> getDeptTree() {
|
||||
List<SysDeptEntity> list = deptService.list();
|
||||
|
||||
return TreeUtil.build(list, 0L, (dept, tree) -> {
|
||||
tree.setId(dept.getDeptId());
|
||||
tree.setParentId(dept.getParentId());
|
||||
tree.putExtra("label", dept.getDeptName());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void addDept(AddDeptCommand addCommand) {
|
||||
DeptModel deptModel = deptModelFactory.create();
|
||||
deptModel.loadAddCommand(addCommand);
|
||||
|
||||
deptModel.checkDeptNameUnique();
|
||||
deptModel.generateAncestors();
|
||||
|
||||
deptModel.insert();
|
||||
}
|
||||
|
||||
public void updateDept(UpdateDeptCommand updateCommand) {
|
||||
DeptModel deptModel = deptModelFactory.loadById(updateCommand.getDeptId());
|
||||
deptModel.loadUpdateCommand(updateCommand);
|
||||
|
||||
deptModel.checkDeptNameUnique();
|
||||
deptModel.checkParentIdConflict();
|
||||
deptModel.checkStatusAllowChange();
|
||||
deptModel.generateAncestors();
|
||||
|
||||
deptModel.updateById();
|
||||
}
|
||||
|
||||
public void removeDept(Long deptId) {
|
||||
DeptModel deptModel = deptModelFactory.loadById(deptId);
|
||||
|
||||
deptModel.checkHasChildDept();
|
||||
deptModel.checkDeptAssignedToUsers();
|
||||
|
||||
deptModel.deleteById();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.agileboot.domain.system.dept.command;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class AddDeptCommand {
|
||||
|
||||
/**
|
||||
* 父部门ID
|
||||
*/
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
@Size(max = 30, message = "部门名称长度不能超过30个字符")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
private String leaderName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
@Size(max = 11, message = "联系电话长度不能超过11个字符")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 50, message = "邮箱长度不能超过50个字符")
|
||||
private String email;
|
||||
|
||||
|
||||
private Integer status;
|
||||
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.dept.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdateDeptCommand extends AddDeptCommand {
|
||||
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long deptId;
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.agileboot.domain.system.dept.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 部门表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_dept")
|
||||
@ApiModel(value = "SysDeptEntity对象", description = "部门表")
|
||||
public class SysDeptEntity extends BaseEntity<SysDeptEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("部门id")
|
||||
@TableId(value = "dept_id", type = IdType.AUTO)
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty("父部门id")
|
||||
@TableField("parent_id")
|
||||
private Long parentId;
|
||||
|
||||
@ApiModelProperty("祖级列表")
|
||||
@TableField("ancestors")
|
||||
private String ancestors;
|
||||
|
||||
@ApiModelProperty("部门名称")
|
||||
@TableField("dept_name")
|
||||
private String deptName;
|
||||
|
||||
@ApiModelProperty("显示顺序")
|
||||
@TableField("order_num")
|
||||
private Integer orderNum;
|
||||
|
||||
@TableField("leader_id")
|
||||
private Long leaderId;
|
||||
|
||||
@ApiModelProperty("负责人")
|
||||
@TableField("leader_name")
|
||||
private String leaderName;
|
||||
|
||||
@ApiModelProperty("联系电话")
|
||||
@TableField("phone")
|
||||
private String phone;
|
||||
|
||||
@ApiModelProperty("邮箱")
|
||||
@TableField("email")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty("部门状态(0正常 1停用)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.deptId;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.dept.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 部门表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysDeptMapper extends BaseMapper<SysDeptEntity> {
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.agileboot.domain.system.dept.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 部门表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysDeptService extends IService<SysDeptEntity> {
|
||||
|
||||
|
||||
/**
|
||||
* 检测部门名称是否一致
|
||||
*
|
||||
* @param deptName 部门名称
|
||||
* @param deptId 部门id
|
||||
* @param parentId 父级部门id
|
||||
* @return 校验结果
|
||||
*/
|
||||
boolean isDeptNameDuplicated(String deptName, Long deptId, Long parentId);
|
||||
|
||||
/**
|
||||
* 检测部门底下是否还有正在使用中的子部门
|
||||
* @param deptId 部门id
|
||||
* @param enabled 部门是否开启
|
||||
* @return 结果
|
||||
*/
|
||||
boolean hasChildrenDept(Long deptId, Boolean enabled);
|
||||
|
||||
/**
|
||||
* 是否是目标部门的子部门
|
||||
* @param parentId 目标部门id
|
||||
* @param childId 子部门id
|
||||
* @return 校验结果
|
||||
*/
|
||||
boolean isChildOfTheDept(Long parentId, Long childId);
|
||||
|
||||
/**
|
||||
* 检测该部门是否已有用户使用
|
||||
* @param deptId 部门id
|
||||
* @return 校验结果
|
||||
*/
|
||||
boolean isDeptAssignedToUsers(Long deptId);
|
||||
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.agileboot.domain.system.dept.db;
|
||||
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 部门表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysDeptServiceImpl extends ServiceImpl<SysDeptMapper, SysDeptEntity> implements SysDeptService {
|
||||
|
||||
private final SysUserMapper userMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDeptNameDuplicated(String deptName, Long deptId, Long parentId) {
|
||||
QueryWrapper<SysDeptEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("dept_name", deptName)
|
||||
.ne(deptId != null, "dept_id", deptId)
|
||||
.eq(parentId != null, "parent_id", parentId);
|
||||
|
||||
return this.baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasChildrenDept(Long deptId, Boolean enabled) {
|
||||
QueryWrapper<SysDeptEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(enabled != null, "status", 1)
|
||||
.and(o -> o.eq("parent_id", deptId).or()
|
||||
.apply("FIND_IN_SET (" + deptId + " , ancestors)")
|
||||
);
|
||||
return this.baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isChildOfTheDept(Long parentId, Long childId) {
|
||||
QueryWrapper<SysDeptEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.apply("dept_id = '" + childId + "' and FIND_IN_SET ( " + parentId + " , ancestors)");
|
||||
return this.baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDeptAssignedToUsers(Long deptId) {
|
||||
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("dept_id", deptId);
|
||||
return userMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.agileboot.domain.system.dept.dto;
|
||||
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class DeptDTO {
|
||||
|
||||
public DeptDTO(SysDeptEntity entity) {
|
||||
if (entity != null) {
|
||||
this.id = entity.getDeptId();
|
||||
this.parentId = entity.getParentId();
|
||||
this.deptName = entity.getDeptName();
|
||||
this.orderNum = entity.getOrderNum();
|
||||
this.leaderName = entity.getLeaderName();
|
||||
this.email = entity.getEmail();
|
||||
this.phone = entity.getPhone();
|
||||
this.status = entity.getStatus();
|
||||
this.createTime = entity.getCreateTime();
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String deptName;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private String leaderName;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String email;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String statusStr;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.agileboot.domain.system.dept.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.dept.command.AddDeptCommand;
|
||||
import com.agileboot.domain.system.dept.command.UpdateDeptCommand;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptService;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class DeptModel extends SysDeptEntity {
|
||||
|
||||
private final SysDeptService deptService;
|
||||
|
||||
public DeptModel(SysDeptService deptService) {
|
||||
this.deptService = deptService;
|
||||
}
|
||||
|
||||
public DeptModel(SysDeptEntity entity, SysDeptService deptService) {
|
||||
if (entity != null) {
|
||||
// 如果大数据量的话 可以用MapStruct优化
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
this.deptService = deptService;
|
||||
}
|
||||
|
||||
public void loadAddCommand(AddDeptCommand addCommand) {
|
||||
this.setParentId(addCommand.getParentId());
|
||||
this.setDeptName(addCommand.getDeptName());
|
||||
this.setOrderNum(addCommand.getOrderNum());
|
||||
this.setLeaderName(addCommand.getLeaderName());
|
||||
this.setPhone(addCommand.getPhone());
|
||||
this.setEmail(addCommand.getEmail());
|
||||
this.setStatus(addCommand.getStatus());
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(UpdateDeptCommand updateCommand) {
|
||||
loadAddCommand(updateCommand);
|
||||
setStatus(Convert.toInt(updateCommand.getStatus(), 0));
|
||||
}
|
||||
|
||||
public void checkDeptNameUnique() {
|
||||
if (deptService.isDeptNameDuplicated(getDeptName(), getDeptId(), getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_NAME_IS_NOT_UNIQUE, getDeptName());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkParentIdConflict() {
|
||||
if (Objects.equals(getParentId(), getDeptId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_PARENT_ID_IS_NOT_ALLOWED_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkHasChildDept() {
|
||||
if (deptService.hasChildrenDept(getDeptId(), null)) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_EXIST_CHILD_DEPT_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkDeptAssignedToUsers() {
|
||||
if (deptService.isDeptAssignedToUsers(getDeptId())) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_EXIST_LINK_USER_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
public void generateAncestors() {
|
||||
|
||||
// 处理 getParentId 可能为 null 的情况
|
||||
if (getParentId() == null || getParentId() == 0) {
|
||||
setAncestors(String.valueOf(getParentId() == null ? 0 : getParentId()));
|
||||
return;
|
||||
}
|
||||
|
||||
SysDeptEntity parentDept = deptService.getById(getParentId());
|
||||
|
||||
// 检查 parentDept 是否为 null 或者状态为禁用
|
||||
if (parentDept == null || StatusEnum.DISABLE.equals(
|
||||
BasicEnumUtil.fromValue(StatusEnum.class, parentDept.getStatus()))) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_PARENT_DEPT_NO_EXIST_OR_DISABLED);
|
||||
}
|
||||
|
||||
// 处理 parentDept.getAncestors() 可能为 null 的情况
|
||||
String ancestors = parentDept.getAncestors() == null ? "" : parentDept.getAncestors();
|
||||
setAncestors(ancestors + "," + getParentId());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DDD 有些阻抗 如果为了追求性能的话 还是得通过 数据库的方式来判断
|
||||
*/
|
||||
public void checkStatusAllowChange() {
|
||||
if (StatusEnum.DISABLE.getValue().equals(getStatus()) &&
|
||||
deptService.hasChildrenDept(getDeptId(), true)) {
|
||||
throw new ApiException(ErrorCode.Business.DEPT_STATUS_ID_IS_NOT_ALLOWED_CHANGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.agileboot.domain.system.dept.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.dept.command.AddDeptCommand;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 部门模型工厂
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DeptModelFactory {
|
||||
|
||||
private final SysDeptService deptService;
|
||||
|
||||
public DeptModel loadById(Long deptId) {
|
||||
SysDeptEntity byId = deptService.getById(deptId);
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, deptId, "部门");
|
||||
}
|
||||
return new DeptModel(byId, deptService);
|
||||
}
|
||||
|
||||
public DeptModel create() {
|
||||
return new DeptModel(deptService);
|
||||
}
|
||||
|
||||
public DeptModel loadFromAddCommand(AddDeptCommand addCommand, DeptModel model) {
|
||||
model.setParentId(addCommand.getParentId());
|
||||
model.setDeptName(addCommand.getDeptName());
|
||||
model.setOrderNum(addCommand.getOrderNum());
|
||||
model.setLeaderName(addCommand.getLeaderName());
|
||||
model.setPhone(addCommand.getPhone());
|
||||
model.setEmail(addCommand.getEmail());
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.agileboot.domain.system.dept.query;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractQuery;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class DeptQuery extends AbstractQuery<SysDeptEntity> {
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysDeptEntity> addQueryCondition() {
|
||||
// TODO parentId 这个似乎没使用
|
||||
return new QueryWrapper<SysDeptEntity>()
|
||||
// .eq(status != null, "status", status)
|
||||
.eq(parentId != null, "parent_id", parentId);
|
||||
// .like(StrUtil.isNotEmpty(deptName), "dept_name", deptName);
|
||||
// .and(deptId != null && isExcludeCurrentDept, o ->
|
||||
// o.ne("dept_id", deptId)
|
||||
// .or()
|
||||
// .apply("FIND_IN_SET (dept_id , ancestors)")
|
||||
// );
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.agileboot.domain.system.log;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.log.dto.LoginLogDTO;
|
||||
import com.agileboot.domain.system.log.query.LoginLogQuery;
|
||||
import com.agileboot.domain.system.log.dto.OperationLogDTO;
|
||||
import com.agileboot.domain.system.log.query.OperationLogQuery;
|
||||
import com.agileboot.domain.system.log.db.SysLoginInfoEntity;
|
||||
import com.agileboot.domain.system.log.db.SysOperationLogEntity;
|
||||
import com.agileboot.domain.system.log.db.SysLoginInfoService;
|
||||
import com.agileboot.domain.system.log.db.SysOperationLogService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LogApplicationService {
|
||||
|
||||
// TODO 命名到时候统一改成叫LoginLog
|
||||
private final SysLoginInfoService loginInfoService;
|
||||
|
||||
private final SysOperationLogService operationLogService;
|
||||
|
||||
public PageDTO<LoginLogDTO> getLoginInfoList(LoginLogQuery query) {
|
||||
Page<SysLoginInfoEntity> page = loginInfoService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<LoginLogDTO> records = page.getRecords().stream().map(LoginLogDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
public void deleteLoginInfo(BulkOperationCommand<Long> deleteCommand) {
|
||||
QueryWrapper<SysLoginInfoEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("info_id", deleteCommand.getIds());
|
||||
loginInfoService.remove(queryWrapper);
|
||||
}
|
||||
|
||||
public PageDTO<OperationLogDTO> getOperationLogList(OperationLogQuery query) {
|
||||
Page<SysOperationLogEntity> page = operationLogService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<OperationLogDTO> records = page.getRecords().stream().map(OperationLogDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
public void deleteOperationLog(BulkOperationCommand<Long> deleteCommand) {
|
||||
operationLogService.removeBatchByIds(deleteCommand.getIds());
|
||||
}
|
||||
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统访问记录
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_login_info")
|
||||
@ApiModel(value = "SysLoginInfoEntity对象", description = "系统访问记录")
|
||||
public class SysLoginInfoEntity extends Model<SysLoginInfoEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("访问ID")
|
||||
@TableId(value = "info_id", type = IdType.AUTO)
|
||||
private Long infoId;
|
||||
|
||||
@ApiModelProperty("用户账号")
|
||||
@TableField("username")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty("登录IP地址")
|
||||
@TableField("ip_address")
|
||||
private String ipAddress;
|
||||
|
||||
@ApiModelProperty("登录地点")
|
||||
@TableField("login_location")
|
||||
private String loginLocation;
|
||||
|
||||
@ApiModelProperty("浏览器类型")
|
||||
@TableField("browser")
|
||||
private String browser;
|
||||
|
||||
@ApiModelProperty("操作系统")
|
||||
@TableField("operation_system")
|
||||
private String operationSystem;
|
||||
|
||||
@ApiModelProperty("登录状态(1成功 0失败)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("提示消息")
|
||||
@TableField("msg")
|
||||
private String msg;
|
||||
|
||||
@ApiModelProperty("访问时间")
|
||||
@TableField("login_time")
|
||||
private Date loginTime;
|
||||
|
||||
@ApiModelProperty("逻辑删除")
|
||||
@TableField("deleted")
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.infoId;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统访问记录 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-06
|
||||
*/
|
||||
public interface SysLoginInfoMapper extends BaseMapper<SysLoginInfoEntity> {
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统访问记录 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-06
|
||||
*/
|
||||
public interface SysLoginInfoService extends IService<SysLoginInfoEntity> {
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统访问记录 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-07-10
|
||||
*/
|
||||
@Service
|
||||
public class SysLoginInfoServiceImpl extends ServiceImpl<SysLoginInfoMapper, SysLoginInfoEntity> implements
|
||||
SysLoginInfoService {
|
||||
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 操作日志记录
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_operation_log")
|
||||
@ApiModel(value = "SysOperationLogEntity对象", description = "操作日志记录")
|
||||
public class SysOperationLogEntity extends Model<SysOperationLogEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("日志主键")
|
||||
@TableId(value = "operation_id", type = IdType.AUTO)
|
||||
private Long operationId;
|
||||
|
||||
@ApiModelProperty("业务类型(0其它 1新增 2修改 3删除)")
|
||||
@TableField("business_type")
|
||||
private Integer businessType;
|
||||
|
||||
@ApiModelProperty("请求方式")
|
||||
@TableField("request_method")
|
||||
private Integer requestMethod;
|
||||
|
||||
@ApiModelProperty("请求模块")
|
||||
@TableField("request_module")
|
||||
private String requestModule;
|
||||
|
||||
@ApiModelProperty("请求URL")
|
||||
@TableField("request_url")
|
||||
private String requestUrl;
|
||||
|
||||
@ApiModelProperty("调用方法")
|
||||
@TableField("called_method")
|
||||
private String calledMethod;
|
||||
|
||||
@ApiModelProperty("操作类别(0其它 1后台用户 2手机端用户)")
|
||||
@TableField("operator_type")
|
||||
private Integer operatorType;
|
||||
|
||||
@ApiModelProperty("用户ID")
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
@ApiModelProperty("操作人员")
|
||||
@TableField("username")
|
||||
private String username;
|
||||
|
||||
@ApiModelProperty("操作人员ip")
|
||||
@TableField("operator_ip")
|
||||
private String operatorIp;
|
||||
|
||||
@ApiModelProperty("操作地点")
|
||||
@TableField("operator_location")
|
||||
private String operatorLocation;
|
||||
|
||||
@ApiModelProperty("部门ID")
|
||||
@TableField("dept_id")
|
||||
private Long deptId;
|
||||
|
||||
@ApiModelProperty("部门名称")
|
||||
@TableField("dept_name")
|
||||
private String deptName;
|
||||
|
||||
@ApiModelProperty("请求参数")
|
||||
@TableField("operation_param")
|
||||
private String operationParam;
|
||||
|
||||
@ApiModelProperty("返回参数")
|
||||
@TableField("operation_result")
|
||||
private String operationResult;
|
||||
|
||||
@ApiModelProperty("操作状态(1正常 0异常)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("错误消息")
|
||||
@TableField("error_stack")
|
||||
private String errorStack;
|
||||
|
||||
@ApiModelProperty("操作时间")
|
||||
@TableField("operation_time")
|
||||
private Date operationTime;
|
||||
|
||||
@ApiModelProperty("逻辑删除")
|
||||
@TableField("deleted")
|
||||
@TableLogic
|
||||
private Boolean deleted;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.operationId;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 操作日志记录 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-08
|
||||
*/
|
||||
public interface SysOperationLogMapper extends BaseMapper<SysOperationLogEntity> {
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 操作日志记录 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-08
|
||||
*/
|
||||
public interface SysOperationLogService extends IService<SysOperationLogEntity> {
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.agileboot.domain.system.log.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 操作日志记录 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-08
|
||||
*/
|
||||
@Service
|
||||
public class SysOperationLogServiceImpl extends ServiceImpl<SysOperationLogMapper, SysOperationLogEntity> implements
|
||||
SysOperationLogService {
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.agileboot.domain.system.log.dto;
|
||||
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.common.enums.common.LoginStatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.log.db.SysLoginInfoEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@ExcelSheet(name = "登录日志")
|
||||
public class LoginLogDTO {
|
||||
|
||||
public LoginLogDTO(SysLoginInfoEntity entity) {
|
||||
if (entity != null) {
|
||||
logId = entity.getInfoId() + "";
|
||||
username = entity.getUsername();
|
||||
ipAddress = entity.getIpAddress();
|
||||
loginLocation = entity.getLoginLocation();
|
||||
operationSystem = entity.getOperationSystem();
|
||||
browser = entity.getBrowser();
|
||||
status = entity.getStatus();
|
||||
statusStr = BasicEnumUtil.getDescriptionByValue(LoginStatusEnum.class, entity.getStatus());
|
||||
msg = entity.getMsg();
|
||||
loginTime = entity.getLoginTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ExcelColumn(name = "ID")
|
||||
private String logId;
|
||||
|
||||
@ExcelColumn(name = "用户名")
|
||||
private String username;
|
||||
|
||||
@ExcelColumn(name = "ip地址")
|
||||
private String ipAddress;
|
||||
|
||||
@ExcelColumn(name = "登录地点")
|
||||
private String loginLocation;
|
||||
|
||||
@ExcelColumn(name = "操作系统")
|
||||
private String operationSystem;
|
||||
|
||||
@ExcelColumn(name = "浏览器")
|
||||
private String browser;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
@ExcelColumn(name = "描述")
|
||||
private String msg;
|
||||
|
||||
@ExcelColumn(name = "登录时间")
|
||||
private Date loginTime;
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package com.agileboot.domain.system.log.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.common.enums.common.BusinessTypeEnum;
|
||||
import com.agileboot.common.enums.common.OperationStatusEnum;
|
||||
import com.agileboot.common.enums.common.OperatorTypeEnum;
|
||||
import com.agileboot.common.enums.common.RequestMethodEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.log.db.SysOperationLogEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@ExcelSheet(name = "操作日志")
|
||||
public class OperationLogDTO {
|
||||
|
||||
public OperationLogDTO(SysOperationLogEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
this.requestMethod = BasicEnumUtil.getDescriptionByValue(RequestMethodEnum.class,
|
||||
entity.getRequestMethod());
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(OperationStatusEnum.class, entity.getStatus());
|
||||
businessTypeStr = BasicEnumUtil.getDescriptionByValue(BusinessTypeEnum.class, entity.getBusinessType());
|
||||
operatorTypeStr = BasicEnumUtil.getDescriptionByValue(OperatorTypeEnum.class, entity.getOperatorType());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "ID")
|
||||
private Long operationId;
|
||||
|
||||
private Integer businessType;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String businessTypeStr;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestMethod;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestModule;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String requestUrl;
|
||||
|
||||
@ExcelColumn(name = "操作类型")
|
||||
private String calledMethod;
|
||||
|
||||
private Integer operatorType;
|
||||
|
||||
@ExcelColumn(name = "操作人类型")
|
||||
private String operatorTypeStr;
|
||||
|
||||
@ExcelColumn(name = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@ExcelColumn(name = "用户名")
|
||||
private String username;
|
||||
|
||||
@ExcelColumn(name = "ip地址")
|
||||
private String operatorIp;
|
||||
|
||||
@ExcelColumn(name = "ip地点")
|
||||
private String operatorLocation;
|
||||
|
||||
@ExcelColumn(name = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
@ExcelColumn(name = "部门")
|
||||
private String deptName;
|
||||
|
||||
@ExcelColumn(name = "操作参数")
|
||||
private String operationParam;
|
||||
|
||||
@ExcelColumn(name = "操作结果")
|
||||
private String operationResult;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
@ExcelColumn(name = "错误堆栈")
|
||||
private String errorStack;
|
||||
|
||||
@ExcelColumn(name = "操作时间")
|
||||
private Date operationTime;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.agileboot.domain.system.log.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.agileboot.domain.system.log.db.SysLoginInfoEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class LoginLogQuery extends AbstractPageQuery<SysLoginInfoEntity> {
|
||||
|
||||
private String ipAddress;
|
||||
private String status;
|
||||
private String username;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysLoginInfoEntity> addQueryCondition() {
|
||||
QueryWrapper<SysLoginInfoEntity> queryWrapper = new QueryWrapper<SysLoginInfoEntity>()
|
||||
.like(StrUtil.isNotEmpty(ipAddress), "ip_address", ipAddress)
|
||||
.eq(StrUtil.isNotEmpty(status), "status", status)
|
||||
.like(StrUtil.isNotEmpty(username), "username", username);
|
||||
|
||||
addSortCondition(queryWrapper);
|
||||
|
||||
// 可以手动设置 也可以由前端传回
|
||||
// this.timeRangeColumn = "login_time";
|
||||
// addTimeCondition(queryWrapper, "login_time");
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.agileboot.domain.system.log.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.agileboot.domain.system.log.db.SysOperationLogEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OperationLogQuery extends AbstractPageQuery<SysOperationLogEntity> {
|
||||
|
||||
private String businessType;
|
||||
private String status;
|
||||
private String username;
|
||||
private String requestModule;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysOperationLogEntity> addQueryCondition() {
|
||||
QueryWrapper<SysOperationLogEntity> queryWrapper = new QueryWrapper<SysOperationLogEntity>()
|
||||
.like(businessType!=null, "business_type", businessType)
|
||||
.eq(status != null, "status", status)
|
||||
.like(StrUtil.isNotEmpty(username), "username", username)
|
||||
.like(StrUtil.isNotEmpty(requestModule), "request_module", requestModule);
|
||||
|
||||
this.timeRangeColumn = "operation_time";
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.agileboot.domain.system.menu;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import com.agileboot.domain.system.menu.command.AddMenuCommand;
|
||||
import com.agileboot.domain.system.menu.command.UpdateMenuCommand;
|
||||
import com.agileboot.domain.system.menu.dto.MenuDTO;
|
||||
import com.agileboot.domain.system.menu.dto.MenuDetailDTO;
|
||||
import com.agileboot.domain.system.menu.dto.RouterDTO;
|
||||
import com.agileboot.domain.system.menu.model.MenuModel;
|
||||
import com.agileboot.domain.system.menu.model.MenuModelFactory;
|
||||
import com.agileboot.domain.system.menu.query.MenuQuery;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuService;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 菜单应用服务
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MenuApplicationService {
|
||||
|
||||
private final SysMenuService menuService;
|
||||
|
||||
private final MenuModelFactory menuModelFactory;
|
||||
|
||||
|
||||
public List<MenuDTO> getMenuList(MenuQuery query) {
|
||||
List<SysMenuEntity> list = menuService.list(query.toQueryWrapper());
|
||||
return list.stream().map(MenuDTO::new)
|
||||
.sorted(Comparator.comparing(MenuDTO::getRank, Comparator.nullsLast(Integer::compareTo)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public MenuDetailDTO getMenuInfo(Long menuId) {
|
||||
SysMenuEntity byId = menuService.getById(menuId);
|
||||
return new MenuDetailDTO(byId);
|
||||
}
|
||||
|
||||
public List<Tree<Long>> getDropdownList(SystemLoginUser loginUser) {
|
||||
List<SysMenuEntity> menuEntityList =
|
||||
loginUser.isAdmin() ? menuService.list() : menuService.getMenuListByUserId(loginUser.getUserId());
|
||||
|
||||
return buildMenuTreeSelect(menuEntityList);
|
||||
}
|
||||
|
||||
|
||||
public void addMenu(AddMenuCommand addCommand) {
|
||||
MenuModel model = menuModelFactory.create();
|
||||
model.loadAddCommand(addCommand);
|
||||
|
||||
// TODO 只允许在页面类型上添加按钮
|
||||
// 目前前端不支持嵌套的外链跳转
|
||||
model.checkMenuNameUnique();
|
||||
model.checkAddButtonInIframeOrOutLink();
|
||||
model.checkAddMenuNotInCatalog();
|
||||
model.checkExternalLink();
|
||||
|
||||
model.insert();
|
||||
}
|
||||
|
||||
public void updateMenu(UpdateMenuCommand updateCommand) {
|
||||
MenuModel model = menuModelFactory.loadById(updateCommand.getMenuId());
|
||||
model.loadUpdateCommand(updateCommand);
|
||||
|
||||
model.checkMenuNameUnique();
|
||||
model.checkAddButtonInIframeOrOutLink();
|
||||
model.checkAddMenuNotInCatalog();
|
||||
model.checkExternalLink();
|
||||
model.checkParentIdConflict();
|
||||
|
||||
model.updateById();
|
||||
}
|
||||
|
||||
|
||||
public void remove(Long menuId) {
|
||||
MenuModel menuModel = menuModelFactory.loadById(menuId);
|
||||
|
||||
menuModel.checkHasChildMenus();
|
||||
menuModel.checkMenuAlreadyAssignToRole();
|
||||
|
||||
menuModel.deleteById();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建前端所需要树结构
|
||||
*
|
||||
* @param menus 菜单列表
|
||||
* @return 树结构列表
|
||||
*/
|
||||
public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuEntity> menus) {
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
//默认为id可以不设置
|
||||
config.setIdKey("menuId");
|
||||
return TreeUtil.build(menus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
tree.putExtra("label", menu.getMenuName());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public List<Tree<Long>> buildMenuEntityTree(SystemLoginUser loginUser) {
|
||||
List<SysMenuEntity> allMenus;
|
||||
if (loginUser.isAdmin()) {
|
||||
allMenus = menuService.list();
|
||||
} else {
|
||||
allMenus = menuService.getMenuListByUserId(loginUser.getUserId());
|
||||
}
|
||||
|
||||
// 传给前端的路由排除掉按钮和停用的菜单
|
||||
List<SysMenuEntity> noButtonMenus = allMenus.stream()
|
||||
.filter(menu -> !menu.getIsButton())
|
||||
.filter(menu-> StatusEnum.ENABLE.getValue().equals(menu.getStatus()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
TreeNodeConfig config = new TreeNodeConfig();
|
||||
// 默认为id 可以不设置
|
||||
config.setIdKey("menuId");
|
||||
|
||||
return TreeUtil.build(noButtonMenus, 0L, config, (menu, tree) -> {
|
||||
// 也可以使用 tree.setId(dept.getId());等一些默认值
|
||||
tree.setId(menu.getMenuId());
|
||||
tree.setParentId(menu.getParentId());
|
||||
// TODO 可以取meta中的rank来排序
|
||||
// tree.setWeight(menu.getRank());
|
||||
tree.putExtra("entity", menu);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public List<RouterDTO> buildRouterTree(List<Tree<Long>> trees) {
|
||||
List<RouterDTO> routers = new LinkedList<>();
|
||||
if (CollUtil.isNotEmpty(trees)) {
|
||||
for (Tree<Long> tree : trees) {
|
||||
Object entity = tree.get("entity");
|
||||
if (entity != null) {
|
||||
RouterDTO routerDTO = new RouterDTO((SysMenuEntity) entity);
|
||||
List<Tree<Long>> children = tree.getChildren();
|
||||
if (CollUtil.isNotEmpty(children)) {
|
||||
routerDTO.setChildren(buildRouterTree(children));
|
||||
}
|
||||
routers.add(routerDTO);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return routers;
|
||||
}
|
||||
|
||||
|
||||
public List<RouterDTO> getRouterTree(SystemLoginUser loginUser) {
|
||||
List<Tree<Long>> trees = buildMenuEntityTree(loginUser);
|
||||
return buildRouterTree(trees);
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.agileboot.domain.system.menu.command;
|
||||
|
||||
import com.agileboot.domain.system.menu.dto.MetaDTO;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class AddMenuCommand {
|
||||
|
||||
private Long parentId;
|
||||
@NotBlank(message = "菜单名称不能为空")
|
||||
@Size(max = 50, message = "菜单名称长度不能超过50个字符")
|
||||
private String menuName;
|
||||
/**
|
||||
* 路由名称 必须唯一
|
||||
*/
|
||||
private String routerName;
|
||||
|
||||
@Size(max = 200, message = "路由地址不能超过200个字符")
|
||||
private String path;
|
||||
|
||||
private Integer status;
|
||||
private Integer menuType;
|
||||
|
||||
private Boolean isButton;
|
||||
|
||||
@Size(max = 100, message = "权限标识长度不能超过100个字符")
|
||||
private String permission;
|
||||
|
||||
private MetaDTO meta;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.domain.system.menu.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdateMenuCommand extends AddMenuCommand {
|
||||
|
||||
@NotNull
|
||||
private Long menuId;
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.agileboot.domain.system.menu.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2023-07-21
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_menu")
|
||||
@ApiModel(value = "SysMenuEntity对象", description = "菜单权限表")
|
||||
public class SysMenuEntity extends BaseEntity<SysMenuEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("菜单ID")
|
||||
@TableId(value = "menu_id", type = IdType.AUTO)
|
||||
private Long menuId;
|
||||
|
||||
@ApiModelProperty("菜单名称")
|
||||
@TableField("menu_name")
|
||||
private String menuName;
|
||||
|
||||
@ApiModelProperty("菜单的类型(1为普通菜单2为目录3为iFrame4为外部网站)")
|
||||
@TableField("menu_type")
|
||||
private Integer menuType;
|
||||
|
||||
@ApiModelProperty("路由名称(需保持和前端对应的vue文件中的name保持一致defineOptions方法中设置的name)")
|
||||
@TableField("router_name")
|
||||
private String routerName;
|
||||
|
||||
@ApiModelProperty("父菜单ID")
|
||||
@TableField("parent_id")
|
||||
private Long parentId;
|
||||
|
||||
@ApiModelProperty("组件路径(对应前端项目view文件夹中的路径)")
|
||||
@TableField("path")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty("是否按钮")
|
||||
@TableField("is_button")
|
||||
private Boolean isButton;
|
||||
|
||||
@ApiModelProperty("权限标识")
|
||||
@TableField("permission")
|
||||
private String permission;
|
||||
|
||||
@ApiModelProperty("路由元信息(前端根据这个信息进行逻辑处理)")
|
||||
@TableField("meta_info")
|
||||
private String metaInfo;
|
||||
|
||||
@ApiModelProperty("菜单状态(1启用 0停用)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.menuId;
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.agileboot.domain.system.menu.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysMenuMapper extends BaseMapper<SysMenuEntity> {
|
||||
|
||||
/**
|
||||
* 根据用户查询出所有菜单
|
||||
*
|
||||
* @param userId 用户id
|
||||
* @return 菜单列表
|
||||
*/
|
||||
@Select("SELECT DISTINCT m.* "
|
||||
+ "FROM sys_menu m "
|
||||
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
|
||||
+ " LEFT JOIN sys_user u ON rm.role_id = u.role_id "
|
||||
+ "WHERE u.user_id = #{userId} "
|
||||
+ " AND m.status = 1 "
|
||||
+ " AND m.deleted = 0 "
|
||||
+ "ORDER BY m.parent_id")
|
||||
List<SysMenuEntity> selectMenuListByUserId(@Param("userId")Long userId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据角色ID查询菜单树信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 选中菜单列表
|
||||
*/
|
||||
@Select("SELECT DISTINCT m.menu_id "
|
||||
+ "FROM sys_menu m "
|
||||
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
|
||||
+ "WHERE rm.role_id = #{roleId} "
|
||||
+ " AND m.deleted = 0 "
|
||||
+ "GROUP BY m.menu_id ")
|
||||
List<Long> selectMenuIdsByRoleId(@Param("roleId") Long roleId);
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.agileboot.domain.system.menu.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysMenuService extends IService<SysMenuEntity> {
|
||||
|
||||
/**
|
||||
* 根据用户查询系统菜单列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SysMenuEntity> getMenuListByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据角色ID查询菜单树信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 选中菜单列表
|
||||
*/
|
||||
List<Long> getMenuIdsByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 校验菜单名称是否唯一
|
||||
*
|
||||
* @param menuName 菜单名称
|
||||
* @param menuId 菜单id
|
||||
* @param parentId 父级菜单id
|
||||
* @return 校验结果
|
||||
*/
|
||||
boolean isMenuNameDuplicated(String menuName, Long menuId, Long parentId);
|
||||
|
||||
/**
|
||||
* 是否存在菜单子节点
|
||||
* @param menuId 菜单ID
|
||||
* @return 结果 true 存在 false 不存在
|
||||
*/
|
||||
boolean hasChildrenMenu(Long menuId);
|
||||
|
||||
/**
|
||||
* 查询菜单是否存在角色
|
||||
* @param menuId 菜单ID
|
||||
* @return 结果 true 存在 false 不存在
|
||||
*/
|
||||
boolean isMenuAssignToRoles(Long menuId);
|
||||
|
||||
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.agileboot.domain.system.menu.db;
|
||||
|
||||
import com.agileboot.domain.system.role.db.SysRoleMenuEntity;
|
||||
import com.agileboot.domain.system.role.db.SysRoleMenuMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 菜单权限表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenuEntity> implements SysMenuService {
|
||||
|
||||
private final SysRoleMenuMapper roleMenuMapper;
|
||||
|
||||
|
||||
/**
|
||||
* 根据角色ID查询菜单树信息
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 选中菜单列表
|
||||
*/
|
||||
@Override
|
||||
public List<Long> getMenuIdsByRoleId(Long roleId) {
|
||||
return this.baseMapper.selectMenuIdsByRoleId(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMenuNameDuplicated(String menuName, Long menuId, Long parentId) {
|
||||
QueryWrapper<SysMenuEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("menu_name", menuName)
|
||||
.ne(menuId != null, "menu_id", menuId)
|
||||
.eq(parentId != null, "parent_id", parentId);
|
||||
return this.baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasChildrenMenu(Long menuId) {
|
||||
QueryWrapper<SysMenuEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("parent_id", menuId);
|
||||
return baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询菜单使用数量
|
||||
*
|
||||
* @param menuId 菜单ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean isMenuAssignToRoles(Long menuId) {
|
||||
QueryWrapper<SysRoleMenuEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("menu_id", menuId);
|
||||
return roleMenuMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<SysMenuEntity> getMenuListByUserId(Long userId) {
|
||||
return baseMapper.selectMenuListByUserId(userId);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class ExtraIconDTO {
|
||||
|
||||
// 是否是svg
|
||||
private boolean svg;
|
||||
// iconfont名称,目前只支持iconfont,后续拓展
|
||||
private String name;
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import com.agileboot.common.enums.common.MenuTypeEnum;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class MenuDTO {
|
||||
|
||||
public MenuDTO(SysMenuEntity entity) {
|
||||
if (entity != null) {
|
||||
this.id = entity.getMenuId();
|
||||
this.parentId = entity.getParentId();
|
||||
this.menuName = entity.getMenuName();
|
||||
this.routerName = entity.getRouterName();
|
||||
this.path = entity.getPath();
|
||||
this.status = entity.getStatus();
|
||||
this.isButton = entity.getIsButton();
|
||||
this.statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus());
|
||||
|
||||
if (!entity.getIsButton()) {
|
||||
this.menuType = entity.getMenuType();
|
||||
this.menuTypeStr = BasicEnumUtil.getDescriptionByValue(MenuTypeEnum.class, entity.getMenuType());
|
||||
} else {
|
||||
this.menuType = 0;
|
||||
}
|
||||
|
||||
if (StrUtil.isNotEmpty(entity.getMetaInfo()) && JacksonUtil.isJson(entity.getMetaInfo())) {
|
||||
MetaDTO meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class);
|
||||
this.rank = meta.getRank();
|
||||
this.icon = meta.getIcon();
|
||||
}
|
||||
this.createTime = entity.getCreateTime();
|
||||
}
|
||||
}
|
||||
|
||||
// 设置成id和parentId 便于前端处理树级结构
|
||||
private Long id;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private String menuName;
|
||||
|
||||
private String routerName;
|
||||
|
||||
private String path;
|
||||
|
||||
private Integer rank;
|
||||
|
||||
private Integer menuType;
|
||||
|
||||
private String menuTypeStr;
|
||||
|
||||
private Boolean isButton;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String statusStr;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String icon;
|
||||
|
||||
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MenuDetailDTO extends MenuDTO {
|
||||
|
||||
public MenuDetailDTO(SysMenuEntity entity) {
|
||||
super(entity);
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(entity.getMetaInfo()) && JacksonUtil.isJson(entity.getMetaInfo())) {
|
||||
this.meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class);
|
||||
}
|
||||
this.permission = entity.getPermission();
|
||||
}
|
||||
|
||||
private String permission;
|
||||
private MetaDTO meta;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 路由显示信息
|
||||
* 必须加上@JsonInclude(Include.NON_NULL)的注解 否则传null值给Vue动态路由渲染时会出错
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public class MetaDTO {
|
||||
// 菜单名称(兼容国际化、非国际化,如果用国际化的写法就必须在根目录的locales文件夹下对应添加)
|
||||
private String title;
|
||||
// 菜单图标
|
||||
private String icon;
|
||||
// 是否显示该菜单
|
||||
private Boolean showLink;
|
||||
// 是否显示父级菜单
|
||||
private Boolean showParent;
|
||||
// 页面级别权限设置
|
||||
private List<String> roles;
|
||||
// 按钮级别权限设置
|
||||
private List<String> auths;
|
||||
// 需要内嵌的iframe链接地址
|
||||
private String frameSrc;
|
||||
/**
|
||||
* 是否是内部页面 使用frameSrc来嵌入页面时,当isFrameSrcInternal=true的时候, 前端需要做特殊处理
|
||||
* 比如链接是 /druid/login.html
|
||||
* 前端需要处理成 http://localhost:8080/druid/login.html
|
||||
*/
|
||||
private Boolean isFrameSrcInternal;
|
||||
|
||||
/**
|
||||
* 菜单排序,值越高排的越后(只针对顶级路由)
|
||||
*/
|
||||
private Integer rank;
|
||||
|
||||
|
||||
// ========= 目前系统仅支持以上这些参数的设置 后续有需要的话开发者可自行设置的这些参数 ===========
|
||||
|
||||
// 菜单名称右侧的额外图标
|
||||
private ExtraIconDTO extraIcon;
|
||||
// 是否缓存该路由页面(开启后,会保存该页面的整体状态,刷新后会清空状态)
|
||||
private Boolean keepAlive;
|
||||
// 内嵌的iframe页面是否开启首次加载动画
|
||||
private Boolean frameLoading;
|
||||
// 页面加载动画(两种模式,第一种直接采用vue内置的transitions动画,第二种是使用animate.css编写进、离场动画,平台更推荐使用第二种模式,已经内置了animate.css,直接写对应的动画名即可)
|
||||
private TransitionDTO transition;
|
||||
// 当前菜单名称或自定义信息禁止添加到标签页
|
||||
private Boolean hiddenTag;
|
||||
// 显示在标签页的最大数量,需满足后面的条件:不显示在菜单中的路由并且是通过query或params传参模式打开的页面。在完整版全局搜dynamicLevel即可查看代码演示
|
||||
private Integer dynamicLevel;
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 动态路由信息
|
||||
* 必须加上@JsonInclude(Include.NON_NULL)的注解 否则传null值给Vue动态路由渲染时会出错
|
||||
* @author valarchie
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class RouterDTO {
|
||||
|
||||
public RouterDTO(SysMenuEntity entity) {
|
||||
if (entity != null) {
|
||||
this.name = entity.getRouterName();
|
||||
this.path = entity.getPath();
|
||||
// 暂时不需要component
|
||||
// this.component = entity.getComponent();
|
||||
// this.rank = entity.getRank();
|
||||
// this.redirect = entity.getRedirect();
|
||||
if (JacksonUtil.isJson(entity.getMetaInfo())) {
|
||||
this.meta = JacksonUtil.from(entity.getMetaInfo(), MetaDTO.class);
|
||||
} else {
|
||||
this.meta = new MetaDTO();
|
||||
}
|
||||
this.meta.setAuths(Lists.newArrayList(entity.getPermission()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由名字 根据前端的要求 必须唯一
|
||||
* 并按照前端项目的推荐 这个Name最好和组件的Name一样 使用菜单表中的router_name
|
||||
* TODO 这里后端需要加校验
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 路由路径地址
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 路由重定向
|
||||
*/
|
||||
private String redirect;
|
||||
|
||||
/**
|
||||
* 组件地址
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 一级菜单排序值(排序仅支持一级菜单)
|
||||
*/
|
||||
private Integer rank;
|
||||
|
||||
|
||||
/**
|
||||
* 其他元素
|
||||
*/
|
||||
private MetaDTO meta;
|
||||
|
||||
/**
|
||||
* 子路由
|
||||
*/
|
||||
private List<RouterDTO> children;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.menu.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class TransitionDTO {
|
||||
|
||||
// 当前页面动画,这里是第一种模式,比如 name: "fade" 更具体看后面链接
|
||||
// https://cn.vuejs.org/api/built-in-components.html#transition
|
||||
private String name;
|
||||
// 当前页面进场动画,这里是第二种模式,比如 enterTransition: "animate__fadeInLeft"
|
||||
private String enterTransition;
|
||||
// 当前页面离场动画,这里是第二种模式,比如 leaveTransition: "animate__fadeOutRight"
|
||||
private String leaveTransition;
|
||||
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.agileboot.domain.system.menu.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Business;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import com.agileboot.domain.system.menu.command.AddMenuCommand;
|
||||
import com.agileboot.domain.system.menu.command.UpdateMenuCommand;
|
||||
import com.agileboot.common.enums.common.MenuTypeEnum;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuService;
|
||||
import java.util.Objects;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class MenuModel extends SysMenuEntity {
|
||||
|
||||
private SysMenuService menuService;
|
||||
|
||||
public MenuModel(SysMenuService menuService) {
|
||||
this.menuService = menuService;
|
||||
}
|
||||
|
||||
public MenuModel(SysMenuEntity entity, SysMenuService menuService) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
this.menuService = menuService;
|
||||
}
|
||||
|
||||
public void loadAddCommand(AddMenuCommand command) {
|
||||
if (command != null) {
|
||||
BeanUtil.copyProperties(command, this, "menuId");
|
||||
|
||||
String metaInfo = JacksonUtil.to(command.getMeta());
|
||||
this.setMetaInfo(metaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(UpdateMenuCommand command) {
|
||||
if (command != null) {
|
||||
if (!Objects.equals(this.getMenuType(), command.getMenuType()) && !this.getIsButton()) {
|
||||
throw new ApiException(Business.MENU_CAN_NOT_CHANGE_MENU_TYPE);
|
||||
}
|
||||
loadAddCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkMenuNameUnique() {
|
||||
if (menuService.isMenuNameDuplicated(getMenuName(), getMenuId(), getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_NAME_IS_NOT_UNIQUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iframe和外链跳转类型 不允许添加按钮
|
||||
*/
|
||||
public void checkAddButtonInIframeOrOutLink() {
|
||||
SysMenuEntity parentMenu = menuService.getById(getParentId());
|
||||
|
||||
if (parentMenu != null && getIsButton() && (
|
||||
Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.IFRAME.getValue())
|
||||
|| Objects.equals(parentMenu.getMenuType(),MenuTypeEnum.OUTSIDE_LINK_REDIRECT.getValue())
|
||||
)) {
|
||||
throw new ApiException(Business.MENU_NOT_ALLOWED_TO_CREATE_BUTTON_ON_IFRAME_OR_OUT_LINK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 只允许在目录菜单类型底下 添加子菜单
|
||||
*/
|
||||
public void checkAddMenuNotInCatalog() {
|
||||
SysMenuEntity parentMenu = menuService.getById(getParentId());
|
||||
|
||||
if (parentMenu != null && !getIsButton() && (
|
||||
!Objects.equals(parentMenu.getMenuType(), MenuTypeEnum.CATALOG.getValue())
|
||||
)) {
|
||||
throw new ApiException(Business.MENU_ONLY_ALLOWED_TO_CREATE_SUB_MENU_IN_CATALOG);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkExternalLink() {
|
||||
// if (getIsExternal() && !HttpUtil.isHttp(getPath()) && !HttpUtil.isHttps(getPath())) {
|
||||
// throw new ApiException(ErrorCode.Business.MENU_EXTERNAL_LINK_MUST_BE_HTTP);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
public void checkParentIdConflict() {
|
||||
if (getMenuId().equals(getParentId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_PARENT_ID_NOT_ALLOW_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkHasChildMenus() {
|
||||
if (menuService.hasChildrenMenu(getMenuId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_EXIST_CHILD_MENU_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkMenuAlreadyAssignToRole() {
|
||||
if (menuService.isMenuAssignToRoles(getMenuId())) {
|
||||
throw new ApiException(ErrorCode.Business.MENU_ALREADY_ASSIGN_TO_ROLE_NOT_ALLOW_DELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.agileboot.domain.system.menu.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 菜单模型工厂
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MenuModelFactory {
|
||||
|
||||
private final SysMenuService menuService;
|
||||
|
||||
public MenuModel loadById(Long menuId) {
|
||||
SysMenuEntity byId = menuService.getById(menuId);
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, menuId, "菜单");
|
||||
}
|
||||
return new MenuModel(byId, menuService);
|
||||
}
|
||||
|
||||
public MenuModel create() {
|
||||
return new MenuModel(menuService);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package com.agileboot.domain.system.menu.model;
|
||||
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class RouterModel extends SysMenuEntity {
|
||||
|
||||
// public RouterDTO produceMultipleLevelMenuRouterVO(List<RouterDTO> children) {
|
||||
// RouterDTO router = produceDefaultRouterVO();
|
||||
//
|
||||
// if (CollUtil.isNotEmpty(children) && Objects.equals(MenuTypeEnum.DIRECTORY.getValue(), getMenuType())) {
|
||||
// router.setAlwaysShow(true);
|
||||
// router.setRedirect("noRedirect");
|
||||
// router.setChildren(children);
|
||||
// }
|
||||
//
|
||||
// return router;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public RouterDTO produceSingleLevelMenuRouterVO() {
|
||||
// RouterDTO router = produceDefaultRouterVO();
|
||||
//
|
||||
// router.setMeta(null);
|
||||
// List<RouterDTO> childrenList = new ArrayList<>();
|
||||
// RouterDTO children = new RouterDTO();
|
||||
// children.setPath(getPath());
|
||||
// children.setComponent(getComponent());
|
||||
// children.setName(StrUtil.upperFirst(getPath()));
|
||||
// children.setMeta(new MetaDTO(getMenuName(), getIcon(), !getIsCache(), getPath()));
|
||||
// children.setQuery(getQuery());
|
||||
// childrenList.add(children);
|
||||
// router.setChildren(childrenList);
|
||||
//
|
||||
// return router;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// public RouterDTO produceInnerLinkRouterVO() {
|
||||
//
|
||||
// RouterDTO router = produceDefaultRouterVO();
|
||||
//
|
||||
// router.setMeta(new MetaDTO(getMenuName(), getIcon()));
|
||||
// router.setPath("/");
|
||||
// List<RouterDTO> childrenList = new ArrayList<>();
|
||||
// RouterDTO children = new RouterDTO();
|
||||
// String routerPath = trimHttpPrefixForPath(getPath());
|
||||
// children.setPath(routerPath);
|
||||
// children.setComponent(MenuComponentEnum.INNER_LINK.description());
|
||||
// children.setName(StrUtil.upperFirst(routerPath));
|
||||
// children.setMeta(new MetaDTO(getMenuName(), getIcon(), getPath()));
|
||||
// childrenList.add(children);
|
||||
// router.setChildren(childrenList);
|
||||
//
|
||||
// return router;
|
||||
// }
|
||||
//
|
||||
// public RouterDTO produceDefaultRouterVO() {
|
||||
// RouterDTO router = new RouterDTO();
|
||||
// router.setHidden(!getIsVisible());
|
||||
// router.setName(calculateRouteName());
|
||||
// router.setPath(calculateRouterPath());
|
||||
// router.setComponent(calculateComponentType());
|
||||
// router.setQuery(getQuery());
|
||||
// router.setMeta(new MetaDTO(getMenuName(), getIcon(), !getIsCache(), getPath()));
|
||||
// return router;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 获取路由名称
|
||||
// * @return 路由名称
|
||||
// */
|
||||
// public String calculateRouteName() {
|
||||
// String routerName = StrUtil.upperFirst(getPath());
|
||||
// // 非外链并且是一级目录(类型为目录)
|
||||
// if (isSingleLevelMenu()) {
|
||||
// routerName = StrUtil.EMPTY;
|
||||
// }
|
||||
// return routerName;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 是否为单个一级菜单
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isSingleLevelMenu() {
|
||||
// return isTopLevel() && MenuTypeEnum.MENU.getValue().equals(getMenuType()) && !getIsExternal();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 是否为顶级内部链接菜单
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isTopInnerLink() {
|
||||
// return isTopLevel() && isInnerLink();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 是否为多级菜单
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isMultipleLevelMenu(Tree<Long> tree) {
|
||||
// return MenuTypeEnum.DIRECTORY.getValue().equals(getMenuType()) && tree.hasChild();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 获取路由地址
|
||||
// * @return 路由地址
|
||||
// */
|
||||
// public String calculateRouterPath() {
|
||||
// String routerPath = getPath();
|
||||
// // 内链打开外网方式
|
||||
// if (!isTopLevel() && isInnerLink()) {
|
||||
// routerPath = trimHttpPrefixForPath(routerPath);
|
||||
// }
|
||||
// // 非外链并且是一级目录(类型为目录)
|
||||
// if (isTopLevel() && Objects.equals(MenuTypeEnum.DIRECTORY.getValue(), getMenuType()) && !getIsExternal()) {
|
||||
// routerPath = "/" + getPath();
|
||||
// // 非外链并且是一级目录(类型为菜单)
|
||||
// } else if (isSingleLevelMenu()) {
|
||||
// routerPath = "/";
|
||||
// }
|
||||
// return routerPath;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 是否为内链组件
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isInnerLink() {
|
||||
// return !getIsExternal() && (HttpUtil.isHttp(getPath()) || HttpUtil.isHttps(getPath()));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 是否顶层目录或者菜单
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isTopLevel() {
|
||||
// return Objects.equals(getParentId(), 0L);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 内链域名特殊字符替换
|
||||
// */
|
||||
// public String trimHttpPrefixForPath(String path) {
|
||||
// if (HttpUtil.isHttp(path)) {
|
||||
// return StrUtil.stripIgnoreCase(path, Constants.HTTP, "");
|
||||
// }
|
||||
// if (HttpUtil.isHttps(path)) {
|
||||
// return StrUtil.stripIgnoreCase(path, Constants.HTTPS, "");
|
||||
// }
|
||||
// return path;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 获取组件信息
|
||||
// *
|
||||
// * @return 组件信息
|
||||
// */
|
||||
// public String calculateComponentType() {
|
||||
// String component = MenuComponentEnum.LAYOUT.description();
|
||||
// if (StrUtil.isNotEmpty(getComponent()) && !isSingleLevelMenu()) {
|
||||
// component = getComponent();
|
||||
// } else if (isInnerLinkView()) {
|
||||
// component = MenuComponentEnum.INNER_LINK.description();
|
||||
// } else if (isParentView()) {
|
||||
// component = MenuComponentEnum.PARENT_VIEW.description();
|
||||
// }
|
||||
// return component;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 是否为inner_link_view组件
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isInnerLinkView() {
|
||||
// return StrUtil.isEmpty(getComponent()) && !isTopLevel() && isInnerLink();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /**
|
||||
// * 是否为parent_view组件
|
||||
// *
|
||||
// * @return 结果
|
||||
// */
|
||||
// public boolean isParentView() {
|
||||
// return StrUtil.isEmpty(getComponent()) && !isTopLevel() &&
|
||||
// MenuTypeEnum.DIRECTORY.getValue().equals(getMenuType());
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.agileboot.domain.system.menu.query;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractQuery;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class MenuQuery extends AbstractQuery<SysMenuEntity> {
|
||||
// 直接交给前端筛选
|
||||
// private String menuName;
|
||||
// private Boolean isVisible;
|
||||
// private Integer status;
|
||||
private Boolean isButton;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysMenuEntity> addQueryCondition() {
|
||||
QueryWrapper<SysMenuEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq(isButton != null, "is_button", isButton);
|
||||
// .like(StrUtil.isNotEmpty(menuName), "menu_name", menuName)
|
||||
// .eq(isVisible != null, "is_visible", isVisible)
|
||||
// .eq(status != null, "status", status);
|
||||
this.orderColumn = "parent_id";
|
||||
this.orderDirection = "descending";
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.agileboot.domain.system.monitor;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Internal;
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.system.monitor.dto.OnlineUserDTO;
|
||||
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO;
|
||||
import com.agileboot.domain.system.monitor.dto.RedisCacheInfoDTO.CommandStatusDTO;
|
||||
import com.agileboot.domain.system.monitor.dto.ServerInfo;
|
||||
import com.agileboot.infrastructure.cache.redis.CacheKeyEnum;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.connection.RedisServerCommands;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MonitorApplicationService {
|
||||
|
||||
private final RedisTemplate<String, ?> redisTemplate;
|
||||
|
||||
public RedisCacheInfoDTO getRedisCacheInfo() {
|
||||
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
|
||||
Properties commandStats = (Properties) redisTemplate.execute(
|
||||
(RedisCallback<Object>) connection -> connection.info("commandstats"));
|
||||
Long dbSize = redisTemplate.execute(RedisServerCommands::dbSize);
|
||||
|
||||
if (commandStats == null || info == null) {
|
||||
throw new ApiException(Internal.INTERNAL_ERROR, "获取Redis监控信息失败。");
|
||||
}
|
||||
|
||||
RedisCacheInfoDTO cacheInfo = new RedisCacheInfoDTO();
|
||||
|
||||
cacheInfo.setInfo(info);
|
||||
cacheInfo.setDbSize(dbSize);
|
||||
cacheInfo.setCommandStats(new ArrayList<>());
|
||||
|
||||
commandStats.stringPropertyNames().forEach(key -> {
|
||||
String property = commandStats.getProperty(key);
|
||||
|
||||
CommandStatusDTO commonStatus = new CommandStatusDTO();
|
||||
commonStatus.setName(StrUtil.removePrefix(key, "cmdstat_"));
|
||||
commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));
|
||||
|
||||
cacheInfo.getCommandStats().add(commonStatus);
|
||||
});
|
||||
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
public List<OnlineUserDTO> getOnlineUserList(String username, String ipAddress) {
|
||||
Collection<String> keys = redisTemplate.keys(CacheKeyEnum.LOGIN_USER_KEY.key() + "*");
|
||||
|
||||
Stream<OnlineUserDTO> onlineUserStream = keys.stream().map(o ->
|
||||
CacheCenter.loginUserCache.getObjectOnlyInCacheByKey(o))
|
||||
.filter(Objects::nonNull).map(OnlineUserDTO::new);
|
||||
|
||||
List<OnlineUserDTO> filteredOnlineUsers = onlineUserStream
|
||||
.filter(o ->
|
||||
StrUtil.isEmpty(username) || username.equals(o.getUsername())
|
||||
).filter( o ->
|
||||
StrUtil.isEmpty(ipAddress) || ipAddress.equals(o.getIpAddress())
|
||||
).collect(Collectors.toList());
|
||||
|
||||
Collections.reverse(filteredOnlineUsers);
|
||||
return filteredOnlineUsers;
|
||||
}
|
||||
|
||||
public ServerInfo getServerInfo() {
|
||||
return ServerInfo.fillInfo();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* CPU相关信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class CpuInfo {
|
||||
|
||||
/**
|
||||
* 核心数
|
||||
*/
|
||||
private int cpuNum;
|
||||
|
||||
/**
|
||||
* CPU总的使用率
|
||||
*/
|
||||
private double total;
|
||||
|
||||
/**
|
||||
* CPU系统使用率
|
||||
*/
|
||||
private double sys;
|
||||
|
||||
/**
|
||||
* CPU用户使用率
|
||||
*/
|
||||
private double used;
|
||||
|
||||
/**
|
||||
* CPU当前等待率
|
||||
*/
|
||||
private double wait;
|
||||
|
||||
/**
|
||||
* CPU当前空闲率
|
||||
*/
|
||||
private double free;
|
||||
|
||||
public double getTotal() {
|
||||
return NumberUtil.round(total * 100, 2).doubleValue();
|
||||
}
|
||||
|
||||
public double getSys() {
|
||||
return NumberUtil.div(sys * 100, total, 2);
|
||||
}
|
||||
|
||||
public double getUsed() {
|
||||
return NumberUtil.div(used * 100, total, 2);
|
||||
}
|
||||
|
||||
public double getWait() {
|
||||
return NumberUtil.div(wait * 100, total, 2);
|
||||
}
|
||||
|
||||
public double getFree() {
|
||||
return NumberUtil.div(free * 100, total, 2);
|
||||
}
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 系统文件相关信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class DiskInfo {
|
||||
|
||||
/**
|
||||
* 盘符路径
|
||||
*/
|
||||
private String dirName;
|
||||
|
||||
/**
|
||||
* 盘符类型
|
||||
*/
|
||||
private String sysTypeName;
|
||||
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
private String typeName;
|
||||
|
||||
/**
|
||||
* 总大小
|
||||
*/
|
||||
private String total;
|
||||
|
||||
/**
|
||||
* 剩余大小
|
||||
*/
|
||||
private String free;
|
||||
|
||||
/**
|
||||
* 已经使用量
|
||||
*/
|
||||
private String used;
|
||||
|
||||
/**
|
||||
* 资源的使用率
|
||||
*/
|
||||
private double usage;
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* JVM相关信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class JvmInfo {
|
||||
|
||||
/**
|
||||
* 当前JVM占用的内存总数(M)
|
||||
*/
|
||||
private double total;
|
||||
|
||||
/**
|
||||
* JVM最大可用内存总数(M)
|
||||
*/
|
||||
private double max;
|
||||
|
||||
/**
|
||||
* JVM空闲内存(M)
|
||||
*/
|
||||
private double free;
|
||||
|
||||
/**
|
||||
* JDK版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* JDK路径
|
||||
*/
|
||||
private String home;
|
||||
|
||||
public double getTotal() {
|
||||
return NumberUtil.div(total, Constants.MB, 2);
|
||||
}
|
||||
|
||||
public double getMax() {
|
||||
return NumberUtil.div(max, Constants.MB, 2);
|
||||
}
|
||||
|
||||
public double getFree() {
|
||||
return NumberUtil.div(free, Constants.MB, 2);
|
||||
}
|
||||
|
||||
public double getUsed() {
|
||||
return NumberUtil.div(total - free, Constants.MB, 2);
|
||||
}
|
||||
|
||||
public double getUsage() {
|
||||
return NumberUtil.div((total - free) * 100, total, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JDK名称
|
||||
*/
|
||||
public String getName() {
|
||||
return ManagementFactory.getRuntimeMXBean().getVmName();
|
||||
}
|
||||
|
||||
/**
|
||||
* JDK启动时间
|
||||
*/
|
||||
public String getStartTime() {
|
||||
return DateUtil.format(DateUtil.date(ManagementFactory.getRuntimeMXBean().getStartTime()),
|
||||
DatePattern.NORM_DATETIME_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* JDK运行时间
|
||||
*/
|
||||
public String getRunTime() {
|
||||
return DateUtil.formatBetween(DateUtil.date(ManagementFactory.getRuntimeMXBean().getStartTime()),
|
||||
DateUtil.date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行参数
|
||||
*/
|
||||
public String getInputArgs() {
|
||||
return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 內存相关信息
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class MemoryInfo {
|
||||
|
||||
/**
|
||||
* 内存总量
|
||||
*/
|
||||
private double total;
|
||||
|
||||
/**
|
||||
* 已用内存
|
||||
*/
|
||||
private double used;
|
||||
|
||||
/**
|
||||
* 剩余内存
|
||||
*/
|
||||
private double free;
|
||||
|
||||
public double getTotal() {
|
||||
return NumberUtil.div(total, Constants.GB, 2);
|
||||
}
|
||||
|
||||
public double getUsed() {
|
||||
return NumberUtil.div(used, Constants.GB, 2);
|
||||
}
|
||||
|
||||
public double getFree() {
|
||||
return NumberUtil.div(free, Constants.GB, 2);
|
||||
}
|
||||
|
||||
public double getUsage() {
|
||||
return NumberUtil.div(used * 100, total, 2);
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import com.agileboot.domain.system.dept.db.SysDeptEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 当前在线会话
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class OnlineUserDTO {
|
||||
|
||||
/**
|
||||
* 会话编号
|
||||
*/
|
||||
private String tokenId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* 登录地址
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String operationSystem;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
|
||||
public OnlineUserDTO(SystemLoginUser user) {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
this.setTokenId(user.getCachedKey());
|
||||
this.tokenId = user.getCachedKey();
|
||||
this.username = user.getUsername();
|
||||
this.ipAddress = user.getLoginInfo().getIpAddress();
|
||||
this.loginLocation = user.getLoginInfo().getLocation();
|
||||
this.browser = user.getLoginInfo().getBrowser();
|
||||
this.operationSystem = user.getLoginInfo().getOperationSystem();
|
||||
this.loginTime = user.getLoginInfo().getLoginTime();
|
||||
|
||||
SysDeptEntity deptEntity = CacheCenter.deptCache.get(user.getDeptId() + "");
|
||||
|
||||
if (deptEntity != null) {
|
||||
this.deptName = deptEntity.getDeptName();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class RedisCacheInfoDTO {
|
||||
|
||||
private Properties info;
|
||||
private Long dbSize;
|
||||
private List<CommandStatusDTO> commandStats;
|
||||
|
||||
@Data
|
||||
public static class CommandStatusDTO {
|
||||
private String name;
|
||||
private String value;
|
||||
}
|
||||
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import lombok.Data;
|
||||
import oshi.hardware.CentralProcessor;
|
||||
import oshi.hardware.CentralProcessor.TickType;
|
||||
import oshi.hardware.GlobalMemory;
|
||||
import oshi.hardware.HardwareAbstractionLayer;
|
||||
import oshi.software.os.FileSystem;
|
||||
import oshi.software.os.OSFileStore;
|
||||
import oshi.software.os.OperatingSystem;
|
||||
import oshi.util.Util;
|
||||
|
||||
/**
|
||||
* 服务器相关信息
|
||||
*
|
||||
* @author ruoyi
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class ServerInfo {
|
||||
|
||||
private static final int OSHI_WAIT_SECOND = 1000;
|
||||
|
||||
/**
|
||||
* CPU相关信息
|
||||
*/
|
||||
private CpuInfo cpuInfo = new CpuInfo();
|
||||
|
||||
/**
|
||||
* 內存相关信息
|
||||
*/
|
||||
private MemoryInfo memoryInfo = new MemoryInfo();
|
||||
|
||||
/**
|
||||
* JVM相关信息
|
||||
*/
|
||||
private JvmInfo jvmInfo = new JvmInfo();
|
||||
|
||||
/**
|
||||
* 服务器相关信息
|
||||
*/
|
||||
private SystemInfo systemInfo = new SystemInfo();
|
||||
|
||||
/**
|
||||
* 磁盘相关信息
|
||||
*/
|
||||
private List<DiskInfo> diskInfos = new LinkedList<>();
|
||||
|
||||
public static ServerInfo fillInfo() {
|
||||
ServerInfo serverInfo = new ServerInfo();
|
||||
|
||||
oshi.SystemInfo si = new oshi.SystemInfo();
|
||||
HardwareAbstractionLayer hal = si.getHardware();
|
||||
|
||||
serverInfo.fillCpuInfo(hal.getProcessor());
|
||||
serverInfo.fillMemoryInfo(hal.getMemory());
|
||||
serverInfo.fillSystemInfo();
|
||||
serverInfo.fillJvmInfo();
|
||||
serverInfo.fillDiskInfos(si.getOperatingSystem());
|
||||
|
||||
return serverInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置CPU信息
|
||||
*/
|
||||
private void fillCpuInfo(CentralProcessor processor) {
|
||||
// CPU信息
|
||||
long[] prevTicks = processor.getSystemCpuLoadTicks();
|
||||
Util.sleep(OSHI_WAIT_SECOND);
|
||||
long[] ticks = processor.getSystemCpuLoadTicks();
|
||||
long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
|
||||
long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
|
||||
long softIrq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
|
||||
long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
|
||||
long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
|
||||
long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
|
||||
long ioWait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
|
||||
long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
|
||||
long totalCpu = user + nice + cSys + idle + ioWait + irq + softIrq + steal;
|
||||
cpuInfo.setCpuNum(processor.getLogicalProcessorCount());
|
||||
cpuInfo.setTotal(totalCpu);
|
||||
cpuInfo.setSys(cSys);
|
||||
cpuInfo.setUsed(user);
|
||||
cpuInfo.setWait(ioWait);
|
||||
cpuInfo.setFree(idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内存信息
|
||||
*/
|
||||
private void fillMemoryInfo(GlobalMemory memory) {
|
||||
memoryInfo.setTotal(memory.getTotal());
|
||||
memoryInfo.setUsed(memory.getTotal() - memory.getAvailable());
|
||||
memoryInfo.setFree(memory.getAvailable());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置服务器信息
|
||||
*/
|
||||
private void fillSystemInfo() {
|
||||
Properties props = System.getProperties();
|
||||
|
||||
systemInfo.setComputerName(NetUtil.getLocalHostName());
|
||||
systemInfo.setComputerIp(NetUtil.getLocalhost().getHostAddress());
|
||||
systemInfo.setOsName(props.getProperty("os.name"));
|
||||
systemInfo.setOsArch(props.getProperty("os.arch"));
|
||||
systemInfo.setUserDir(props.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Java虚拟机
|
||||
*/
|
||||
private void fillJvmInfo() {
|
||||
Properties props = System.getProperties();
|
||||
jvmInfo.setTotal(Runtime.getRuntime().totalMemory());
|
||||
jvmInfo.setMax(Runtime.getRuntime().maxMemory());
|
||||
jvmInfo.setFree(Runtime.getRuntime().freeMemory());
|
||||
jvmInfo.setVersion(props.getProperty("java.version"));
|
||||
jvmInfo.setHome(props.getProperty("java.home"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置磁盘信息
|
||||
*/
|
||||
private void fillDiskInfos(OperatingSystem os) {
|
||||
FileSystem fileSystem = os.getFileSystem();
|
||||
List<OSFileStore> fsArray = fileSystem.getFileStores();
|
||||
for (OSFileStore fs : fsArray) {
|
||||
long free = fs.getUsableSpace();
|
||||
long total = fs.getTotalSpace();
|
||||
long used = total - free;
|
||||
DiskInfo diskInfo = new DiskInfo();
|
||||
diskInfo.setDirName(fs.getMount());
|
||||
diskInfo.setSysTypeName(fs.getType());
|
||||
diskInfo.setTypeName(fs.getName());
|
||||
diskInfo.setTotal(convertFileSize(total));
|
||||
diskInfo.setFree(convertFileSize(free));
|
||||
diskInfo.setUsed(convertFileSize(used));
|
||||
if (total != 0){
|
||||
diskInfo.setUsage(NumberUtil.div(used * 100, total, 4));
|
||||
} else {
|
||||
//Windows下如果有光驱(可能是虚拟光驱),total为0,不能做除数
|
||||
diskInfo.setUsage(0);
|
||||
}
|
||||
diskInfos.add(diskInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节转换
|
||||
*
|
||||
* @param size 字节大小
|
||||
* @return 转换后值
|
||||
*/
|
||||
public String convertFileSize(long size) {
|
||||
float castedSize = (float) size;
|
||||
|
||||
if (size >= Constants.GB) {
|
||||
return String.format("%.1f GB", castedSize / Constants.GB);
|
||||
}
|
||||
|
||||
if (size >= Constants.MB) {
|
||||
return String.format("%.1f MB", castedSize / Constants.MB);
|
||||
}
|
||||
|
||||
return String.format("%.1f KB", castedSize / Constants.KB);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.agileboot.domain.system.monitor.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 系统相关信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class SystemInfo {
|
||||
|
||||
/**
|
||||
* 服务器名称
|
||||
*/
|
||||
private String computerName;
|
||||
|
||||
/**
|
||||
* 服务器Ip
|
||||
*/
|
||||
private String computerIp;
|
||||
|
||||
/**
|
||||
* 项目路径
|
||||
*/
|
||||
private String userDir;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String osName;
|
||||
|
||||
/**
|
||||
* 系统架构
|
||||
*/
|
||||
private String osArch;
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.agileboot.domain.system.notice;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.notice.command.NoticeAddCommand;
|
||||
import com.agileboot.domain.system.notice.command.NoticeUpdateCommand;
|
||||
import com.agileboot.domain.system.notice.dto.NoticeDTO;
|
||||
import com.agileboot.domain.system.notice.model.NoticeModel;
|
||||
import com.agileboot.domain.system.notice.model.NoticeModelFactory;
|
||||
import com.agileboot.domain.system.notice.query.NoticeQuery;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeEntity;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NoticeApplicationService {
|
||||
|
||||
private final SysNoticeService noticeService;
|
||||
|
||||
private final NoticeModelFactory noticeModelFactory;
|
||||
|
||||
public PageDTO<NoticeDTO> getNoticeList(NoticeQuery query) {
|
||||
Page<SysNoticeEntity> page = noticeService.getNoticeList(query.toPage(), query.toQueryWrapper());
|
||||
List<NoticeDTO> records = page.getRecords().stream().map(NoticeDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
|
||||
public NoticeDTO getNoticeInfo(Long id) {
|
||||
NoticeModel noticeModel = noticeModelFactory.loadById(id);
|
||||
return new NoticeDTO(noticeModel);
|
||||
}
|
||||
|
||||
|
||||
public void addNotice(NoticeAddCommand addCommand) {
|
||||
NoticeModel noticeModel = noticeModelFactory.create();
|
||||
noticeModel.loadAddCommand(addCommand);
|
||||
|
||||
noticeModel.checkFields();
|
||||
|
||||
noticeModel.insert();
|
||||
}
|
||||
|
||||
|
||||
public void updateNotice(NoticeUpdateCommand updateCommand) {
|
||||
NoticeModel noticeModel = noticeModelFactory.loadById(updateCommand.getNoticeId());
|
||||
noticeModel.loadUpdateCommand(updateCommand);
|
||||
|
||||
noticeModel.checkFields();
|
||||
|
||||
noticeModel.updateById();
|
||||
}
|
||||
|
||||
public void deleteNotice(BulkOperationCommand<Integer> deleteCommand) {
|
||||
noticeService.removeBatchByIds(deleteCommand.getIds());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.agileboot.domain.system.notice.command;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class NoticeAddCommand {
|
||||
|
||||
@NotBlank(message = "公告标题不能为空")
|
||||
@Size(max = 50, message = "公告标题不能超过50个字符")
|
||||
protected String noticeTitle;
|
||||
|
||||
protected String noticeType;
|
||||
|
||||
/**
|
||||
* 想要支持富文本的话, 避免Xss过滤的话, 请加上@JsonDeserialize(using = StringDeserializer.class) 注解
|
||||
*/
|
||||
@NotBlank
|
||||
@JsonDeserialize(using = StringDeserializer.class)
|
||||
protected String noticeContent;
|
||||
|
||||
protected String status;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.notice.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class NoticeUpdateCommand extends NoticeAddCommand {
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
protected Long noticeId;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.agileboot.domain.system.notice.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知公告表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_notice")
|
||||
@ApiModel(value = "SysNoticeEntity对象", description = "通知公告表")
|
||||
public class SysNoticeEntity extends BaseEntity<SysNoticeEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("公告ID")
|
||||
@TableId(value = "notice_id", type = IdType.AUTO)
|
||||
private Integer noticeId;
|
||||
|
||||
@ApiModelProperty("公告标题")
|
||||
@TableField("notice_title")
|
||||
private String noticeTitle;
|
||||
|
||||
@ApiModelProperty("公告类型(1通知 2公告)")
|
||||
@TableField("notice_type")
|
||||
private Integer noticeType;
|
||||
|
||||
@ApiModelProperty("公告内容")
|
||||
@TableField("notice_content")
|
||||
private String noticeContent;
|
||||
|
||||
@ApiModelProperty("公告状态(1正常 0关闭)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.noticeId;
|
||||
}
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.agileboot.domain.system.notice.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知公告表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysNoticeMapper extends BaseMapper<SysNoticeEntity> {
|
||||
|
||||
/**
|
||||
* 根据条件分页查询角色关联的用户列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryWrapper 条件选择器
|
||||
* @return 分页处理后的公告列表
|
||||
*/
|
||||
@Select("SELECT n.* "
|
||||
+ "FROM sys_notice n "
|
||||
+ "LEFT JOIN sys_user u ON n.creator_id = u.user_id"
|
||||
+ " ${ew.customSqlSegment}")
|
||||
Page<SysNoticeEntity> getNoticeList(Page<SysNoticeEntity> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<SysNoticeEntity> queryWrapper);
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.agileboot.domain.system.notice.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知公告表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysNoticeService extends IService<SysNoticeEntity> {
|
||||
|
||||
/**
|
||||
* 获取公告列表
|
||||
*
|
||||
* @param page 页码对象
|
||||
* @param queryWrapper 查询对象
|
||||
* @return 分页处理后的公告列表
|
||||
*/
|
||||
Page<SysNoticeEntity> getNoticeList(Page<SysNoticeEntity> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<SysNoticeEntity> queryWrapper);
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.agileboot.domain.system.notice.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 通知公告表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
@Service
|
||||
public class SysNoticeServiceImpl extends ServiceImpl<SysNoticeMapper, SysNoticeEntity> implements SysNoticeService {
|
||||
|
||||
@Override
|
||||
public Page<SysNoticeEntity> getNoticeList(Page<SysNoticeEntity> page, Wrapper<SysNoticeEntity> queryWrapper) {
|
||||
return this.baseMapper.getNoticeList(page, queryWrapper);
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.agileboot.domain.system.notice.dto;
|
||||
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class NoticeDTO {
|
||||
|
||||
public NoticeDTO(SysNoticeEntity entity) {
|
||||
if (entity != null) {
|
||||
this.noticeId = entity.getNoticeId() + "";
|
||||
this.noticeTitle = entity.getNoticeTitle();
|
||||
this.noticeType = entity.getNoticeType();
|
||||
this.noticeContent = entity.getNoticeContent();
|
||||
this.status = entity.getStatus();
|
||||
this.createTime = entity.getCreateTime();
|
||||
|
||||
SysUserEntity cacheUser = CacheCenter.userCache.getObjectById(entity.getCreatorId());
|
||||
if (cacheUser != null) {
|
||||
this.creatorName = cacheUser.getUsername();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String noticeId;
|
||||
|
||||
private String noticeTitle;
|
||||
|
||||
private Integer noticeType;
|
||||
|
||||
private String noticeContent;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String creatorName;
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.agileboot.domain.system.notice.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.domain.system.notice.command.NoticeAddCommand;
|
||||
import com.agileboot.domain.system.notice.command.NoticeUpdateCommand;
|
||||
import com.agileboot.common.enums.common.NoticeTypeEnum;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class NoticeModel extends SysNoticeEntity {
|
||||
|
||||
public NoticeModel(SysNoticeEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadAddCommand(NoticeAddCommand command) {
|
||||
if (command != null) {
|
||||
BeanUtil.copyProperties(command, this, "noticeId");
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(NoticeUpdateCommand command) {
|
||||
if (command != null) {
|
||||
loadAddCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkFields() {
|
||||
BasicEnumUtil.fromValue(NoticeTypeEnum.class, getNoticeType());
|
||||
BasicEnumUtil.fromValue(StatusEnum.class, getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.agileboot.domain.system.notice.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeEntity;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 公告模型工厂
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class NoticeModelFactory {
|
||||
|
||||
private final SysNoticeService noticeService;
|
||||
|
||||
public NoticeModel loadById(Long noticeId) {
|
||||
SysNoticeEntity byId = noticeService.getById(noticeId);
|
||||
|
||||
if (byId == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, noticeId, "通知公告");
|
||||
}
|
||||
|
||||
return new NoticeModel(byId);
|
||||
}
|
||||
|
||||
public NoticeModel create() {
|
||||
return new NoticeModel();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.agileboot.domain.system.notice.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.agileboot.domain.system.notice.db.SysNoticeEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class NoticeQuery extends AbstractPageQuery<SysNoticeEntity> {
|
||||
|
||||
private String noticeType;
|
||||
|
||||
private String noticeTitle;
|
||||
|
||||
private String creatorName;
|
||||
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysNoticeEntity> addQueryCondition() {
|
||||
QueryWrapper<SysNoticeEntity> queryWrapper = new QueryWrapper<SysNoticeEntity>()
|
||||
.like(StrUtil.isNotEmpty(noticeTitle), "notice_title", noticeTitle)
|
||||
.eq(StrUtil.isNotEmpty(noticeType), "notice_type", noticeType)
|
||||
.eq("n.deleted", 0)
|
||||
.like(StrUtil.isNotEmpty(creatorName), "u.username", creatorName);
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.agileboot.domain.system.post;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.system.post.command.AddPostCommand;
|
||||
import com.agileboot.domain.system.post.command.UpdatePostCommand;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.agileboot.domain.system.post.db.SysPostService;
|
||||
import com.agileboot.domain.system.post.dto.PostDTO;
|
||||
import com.agileboot.domain.system.post.model.PostModel;
|
||||
import com.agileboot.domain.system.post.model.PostModelFactory;
|
||||
import com.agileboot.domain.system.post.query.PostQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PostApplicationService {
|
||||
|
||||
private final PostModelFactory postModelFactory;
|
||||
|
||||
private final SysPostService postService;
|
||||
|
||||
public PageDTO<PostDTO> getPostList(PostQuery query) {
|
||||
Page<SysPostEntity> page = postService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<PostDTO> records = page.getRecords().stream().map(PostDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询满足条件的所有岗位,不分页
|
||||
* @param query 查询条件
|
||||
* @return 满足查询条件的岗位列表
|
||||
* @author Kevin Zhang
|
||||
* @date 2023-10-02
|
||||
*/
|
||||
public List<PostDTO> getPostListAll(PostQuery query) {
|
||||
List<SysPostEntity> all = postService.list(query.toQueryWrapper());
|
||||
List<PostDTO> records = all.stream().map(PostDTO::new).collect(Collectors.toList());
|
||||
return records;
|
||||
}
|
||||
|
||||
public PostDTO getPostInfo(Long postId) {
|
||||
SysPostEntity byId = postService.getById(postId);
|
||||
return new PostDTO(byId);
|
||||
}
|
||||
|
||||
public void addPost(AddPostCommand addCommand) {
|
||||
PostModel postModel = postModelFactory.create();
|
||||
postModel.loadFromAddCommand(addCommand);
|
||||
|
||||
postModel.checkPostNameUnique();
|
||||
postModel.checkPostCodeUnique();
|
||||
|
||||
postModel.insert();
|
||||
}
|
||||
|
||||
public void updatePost(UpdatePostCommand updateCommand) {
|
||||
PostModel postModel = postModelFactory.loadById(updateCommand.getPostId());
|
||||
postModel.loadFromUpdateCommand(updateCommand);
|
||||
|
||||
postModel.checkPostNameUnique();
|
||||
postModel.checkPostCodeUnique();
|
||||
|
||||
postModel.updateById();
|
||||
}
|
||||
|
||||
|
||||
public void deletePost(BulkOperationCommand<Long> deleteCommand) {
|
||||
for (Long id : deleteCommand.getIds()) {
|
||||
PostModel postModel = postModelFactory.loadById(id);
|
||||
postModel.checkCanBeDelete();
|
||||
}
|
||||
|
||||
postService.removeBatchByIds(deleteCommand.getIds());
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.agileboot.domain.system.post.command;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class AddPostCommand {
|
||||
|
||||
@NotBlank(message = "岗位编码不能为空")
|
||||
@Size(max = 64, message = "岗位编码长度不能超过64个字符")
|
||||
protected String postCode;
|
||||
|
||||
/**
|
||||
* 岗位名称
|
||||
*/
|
||||
@NotBlank(message = "岗位名称不能为空")
|
||||
@Size(max = 64, message = "岗位名称长度不能超过64个字符")
|
||||
protected String postName;
|
||||
|
||||
/**
|
||||
* 岗位排序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
protected Integer postSort;
|
||||
|
||||
protected String remark;
|
||||
|
||||
@PositiveOrZero
|
||||
protected String status;
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.post.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdatePostCommand extends AddPostCommand {
|
||||
|
||||
@NotNull(message = "岗位ID不能为空")
|
||||
@Positive
|
||||
private Long postId;
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.agileboot.domain.system.post.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 岗位信息表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_post")
|
||||
@ApiModel(value = "SysPostEntity对象", description = "岗位信息表")
|
||||
public class SysPostEntity extends BaseEntity<SysPostEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("岗位ID")
|
||||
@TableId(value = "post_id", type = IdType.AUTO)
|
||||
private Long postId;
|
||||
|
||||
@ApiModelProperty("岗位编码")
|
||||
@TableField("post_code")
|
||||
private String postCode;
|
||||
|
||||
@ApiModelProperty("岗位名称")
|
||||
@TableField("post_name")
|
||||
private String postName;
|
||||
|
||||
@ApiModelProperty("显示顺序")
|
||||
@TableField("post_sort")
|
||||
private Integer postSort;
|
||||
|
||||
@ApiModelProperty("状态(1正常 0停用)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.postId;
|
||||
}
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.agileboot.domain.system.post.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 岗位信息表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysPostMapper extends BaseMapper<SysPostEntity> {
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.agileboot.domain.system.post.db;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 岗位信息表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysPostService extends IService<SysPostEntity> {
|
||||
|
||||
/**
|
||||
* 校验岗位名称
|
||||
* @param postId 职位Id
|
||||
* @param postName 职位名称
|
||||
* @return 结果
|
||||
*/
|
||||
boolean isPostNameDuplicated(Long postId, String postName);
|
||||
|
||||
/**
|
||||
* 校验岗位编码
|
||||
* @param postId 职位id
|
||||
* @param postCode 职位代码
|
||||
* @return 结果
|
||||
*/
|
||||
boolean isPostCodeDuplicated(Long postId, String postCode);
|
||||
|
||||
|
||||
/**
|
||||
* 检测职位是否分配给用户
|
||||
*
|
||||
* @param postId 职位id
|
||||
* @return 校验结果
|
||||
*/
|
||||
boolean isAssignedToUsers(Long postId);
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.agileboot.domain.system.post.db;
|
||||
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 岗位信息表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SysPostServiceImpl extends ServiceImpl<SysPostMapper, SysPostEntity> implements SysPostService {
|
||||
|
||||
private final SysUserMapper userMapper;
|
||||
|
||||
/**
|
||||
* 校验岗位名称是否唯一
|
||||
*
|
||||
* @param postName 岗位名称
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public boolean isPostNameDuplicated(Long postId, String postName) {
|
||||
QueryWrapper<SysPostEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.ne(postId != null, "post_id", postId)
|
||||
.eq("post_name", postName);
|
||||
return baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPostCodeDuplicated(Long postId, String postCode) {
|
||||
QueryWrapper<SysPostEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.ne(postId != null, "post_id", postId)
|
||||
.eq("post_code", postCode);
|
||||
return baseMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isAssignedToUsers(Long postId) {
|
||||
QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("post_id", postId);
|
||||
return userMapper.exists(queryWrapper);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.domain.system.post.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.enums.common.StatusEnum;
|
||||
import com.agileboot.common.enums.BasicEnumUtil;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import java.util.Date;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class PostDTO {
|
||||
|
||||
public PostDTO(SysPostEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
statusStr = BasicEnumUtil.getDescriptionByValue(StatusEnum.class, entity.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "岗位ID")
|
||||
private Long postId;
|
||||
|
||||
|
||||
@ExcelColumn(name = "岗位编码")
|
||||
private String postCode;
|
||||
|
||||
@ExcelColumn(name = "岗位名称")
|
||||
private String postName;
|
||||
|
||||
|
||||
@ExcelColumn(name = "岗位排序")
|
||||
private Integer postSort;
|
||||
|
||||
@ExcelColumn(name = "备注")
|
||||
private String remark;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@ExcelColumn(name = "状态")
|
||||
private String statusStr;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.agileboot.domain.system.post.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.system.post.command.AddPostCommand;
|
||||
import com.agileboot.domain.system.post.command.UpdatePostCommand;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.agileboot.domain.system.post.db.SysPostService;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
public class PostModel extends SysPostEntity {
|
||||
|
||||
private SysPostService postService;
|
||||
|
||||
public PostModel(SysPostService postService) {
|
||||
this.postService = postService;
|
||||
}
|
||||
|
||||
public PostModel(SysPostEntity entity, SysPostService postService) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
this.postService = postService;
|
||||
}
|
||||
|
||||
public void loadFromAddCommand(AddPostCommand addCommand) {
|
||||
if (addCommand != null) {
|
||||
BeanUtil.copyProperties(addCommand, this, "postId");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void loadFromUpdateCommand(UpdatePostCommand command) {
|
||||
if (command != null) {
|
||||
loadFromAddCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkCanBeDelete() {
|
||||
if (postService.isAssignedToUsers(this.getPostId())) {
|
||||
throw new ApiException(ErrorCode.Business.POST_ALREADY_ASSIGNED_TO_USER_CAN_NOT_BE_DELETED);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPostNameUnique() {
|
||||
if (postService.isPostNameDuplicated(getPostId(), getPostName())) {
|
||||
throw new ApiException(ErrorCode.Business.POST_NAME_IS_NOT_UNIQUE, getPostName());
|
||||
}
|
||||
}
|
||||
|
||||
public void checkPostCodeUnique() {
|
||||
if (postService.isPostCodeDuplicated(getPostId(), getPostCode())) {
|
||||
throw new ApiException(ErrorCode.Business.POST_CODE_IS_NOT_UNIQUE, getPostCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.agileboot.domain.system.post.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Business;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.agileboot.domain.system.post.db.SysPostService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PostModelFactory {
|
||||
|
||||
private final SysPostService postService;
|
||||
|
||||
public PostModel loadById(Long postId) {
|
||||
SysPostEntity byId = postService.getById(postId);
|
||||
if (byId == null) {
|
||||
throw new ApiException(Business.COMMON_OBJECT_NOT_FOUND, postId, "职位");
|
||||
}
|
||||
return new PostModel(byId, postService);
|
||||
}
|
||||
|
||||
public PostModel create() {
|
||||
return new PostModel(postService);
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.agileboot.domain.system.post.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.agileboot.domain.system.post.db.SysPostEntity;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class PostQuery extends AbstractPageQuery<SysPostEntity> {
|
||||
|
||||
private String postCode;
|
||||
private String postName;
|
||||
private Integer status;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<SysPostEntity> addQueryCondition() {
|
||||
QueryWrapper<SysPostEntity> queryWrapper = new QueryWrapper<SysPostEntity>()
|
||||
.eq(status != null, "status", status)
|
||||
.eq(StrUtil.isNotEmpty(postCode), "post_code", postCode)
|
||||
.like(StrUtil.isNotEmpty(postName), "post_name", postName);
|
||||
// 当前端没有选择排序字段时,则使用post_sort字段升序排序(在父类AbstractQuery中默认为升序)
|
||||
if (StrUtil.isEmpty(this.getOrderColumn())) {
|
||||
this.setOrderColumn("post_sort");
|
||||
}
|
||||
this.setTimeRangeColumn("create_time");
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
package com.agileboot.domain.system.role;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.system.role.command.AddRoleCommand;
|
||||
import com.agileboot.domain.system.role.command.UpdateDataScopeCommand;
|
||||
import com.agileboot.domain.system.role.command.UpdateRoleCommand;
|
||||
import com.agileboot.domain.system.role.command.UpdateStatusCommand;
|
||||
import com.agileboot.domain.system.role.dto.RoleDTO;
|
||||
import com.agileboot.domain.system.role.model.RoleModel;
|
||||
import com.agileboot.domain.system.role.model.RoleModelFactory;
|
||||
import com.agileboot.domain.system.role.query.AllocatedRoleQuery;
|
||||
import com.agileboot.domain.system.role.query.RoleQuery;
|
||||
import com.agileboot.domain.system.role.query.UnallocatedRoleQuery;
|
||||
import com.agileboot.domain.system.user.dto.UserDTO;
|
||||
import com.agileboot.domain.system.user.model.UserModel;
|
||||
import com.agileboot.domain.system.user.model.UserModelFactory;
|
||||
import com.agileboot.domain.system.role.db.SysRoleEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import com.agileboot.domain.system.menu.db.SysMenuService;
|
||||
import com.agileboot.domain.system.role.db.SysRoleService;
|
||||
import com.agileboot.domain.system.user.db.SysUserService;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RoleApplicationService {
|
||||
|
||||
private final RoleModelFactory roleModelFactory;
|
||||
|
||||
private final UserModelFactory userModelFactory;
|
||||
|
||||
private final SysRoleService roleService;
|
||||
|
||||
private final SysUserService userService;
|
||||
|
||||
private final SysMenuService menuService;
|
||||
|
||||
|
||||
public PageDTO<RoleDTO> getRoleList(RoleQuery query) {
|
||||
Page<SysRoleEntity> page = roleService.page(query.toPage(), query.toQueryWrapper());
|
||||
List<RoleDTO> records = page.getRecords().stream().map(RoleDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(records, page.getTotal());
|
||||
}
|
||||
|
||||
public RoleDTO getRoleInfo(Long roleId) {
|
||||
SysRoleEntity byId = roleService.getById(roleId);
|
||||
RoleDTO roleDTO = new RoleDTO(byId);
|
||||
List<Long> selectedDeptList = StrUtil.split(byId.getDeptIdSet(), ",")
|
||||
.stream().filter(StrUtil::isNotEmpty).map(Long::new).collect(Collectors.toList());
|
||||
roleDTO.setSelectedDeptList(selectedDeptList);
|
||||
roleDTO.setSelectedMenuList(menuService.getMenuIdsByRoleId(roleId));
|
||||
return roleDTO;
|
||||
}
|
||||
|
||||
|
||||
public void addRole(AddRoleCommand addCommand) {
|
||||
RoleModel roleModel = roleModelFactory.create();
|
||||
roleModel.loadAddCommand(addCommand);
|
||||
|
||||
roleModel.checkRoleNameUnique();
|
||||
roleModel.checkRoleKeyUnique();
|
||||
|
||||
roleModel.insert();
|
||||
}
|
||||
|
||||
public void deleteRoleByBulk(List<Long> roleIds) {
|
||||
if (roleIds != null) {
|
||||
for (Long roleId : roleIds) {
|
||||
RoleModel roleModel = roleModelFactory.loadById(roleId);
|
||||
|
||||
roleModel.checkRoleCanBeDelete();
|
||||
|
||||
roleModel.deleteById();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateRole(UpdateRoleCommand updateCommand) {
|
||||
RoleModel roleModel = roleModelFactory.loadById(updateCommand.getRoleId());
|
||||
roleModel.loadUpdateCommand(updateCommand);
|
||||
|
||||
roleModel.checkRoleKeyUnique();
|
||||
roleModel.checkRoleNameUnique();
|
||||
|
||||
roleModel.updateById();
|
||||
}
|
||||
|
||||
public void updateStatus(UpdateStatusCommand command) {
|
||||
RoleModel roleModel = roleModelFactory.loadById(command.getRoleId());
|
||||
|
||||
roleModel.setStatus(command.getStatus());
|
||||
|
||||
roleModel.updateById();
|
||||
}
|
||||
|
||||
public void updateDataScope(UpdateDataScopeCommand command) {
|
||||
RoleModel roleModel = roleModelFactory.loadById(command.getRoleId());
|
||||
|
||||
roleModel.setDeptIds(command.getDeptIds());
|
||||
roleModel.setDataScope(command.getDataScope());
|
||||
roleModel.generateDeptIdSet();
|
||||
|
||||
roleModel.updateById();
|
||||
}
|
||||
|
||||
|
||||
public PageDTO<UserDTO> getAllocatedUserList(AllocatedRoleQuery query) {
|
||||
Page<SysUserEntity> page = userService.getUserListByRole(query);
|
||||
List<UserDTO> dtoList = page.getRecords().stream().map(UserDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}
|
||||
|
||||
public PageDTO<UserDTO> getUnallocatedUserList(UnallocatedRoleQuery query) {
|
||||
Page<SysUserEntity> page = userService.getUserListByRole(query);
|
||||
List<UserDTO> dtoList = page.getRecords().stream().map(UserDTO::new).collect(Collectors.toList());
|
||||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}
|
||||
|
||||
public void deleteRoleOfUserByBulk(List<Long> userIds) {
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Long userId : userIds) {
|
||||
LambdaUpdateWrapper<SysUserEntity> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.set(SysUserEntity::getRoleId, null).eq(SysUserEntity::getUserId, userId);
|
||||
|
||||
userService.update(updateWrapper);
|
||||
|
||||
CacheCenter.userCache.delete(userId);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRoleOfUserByBulk(Long roleId, List<Long> userIds) {
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleModel roleModel = roleModelFactory.loadById(roleId);
|
||||
roleModel.checkRoleAvailable();
|
||||
|
||||
for (Long userId : userIds) {
|
||||
UserModel user = userModelFactory.loadById(userId);
|
||||
user.setRoleId(roleId);
|
||||
user.updateById();
|
||||
|
||||
CacheCenter.userCache.delete(userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.domain.system.role.command;
|
||||
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import javax.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class AddRoleCommand {
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
@NotBlank(message = "角色名称不能为空")
|
||||
@Size(max = 30, message = "角色名称长度不能超过30个字符")
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*/
|
||||
@ExcelColumn(name = "角色权限")
|
||||
@NotBlank(message = "权限字符不能为空")
|
||||
@Size(max = 100, message = "权限字符长度不能超过100个字符")
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 角色排序
|
||||
*/
|
||||
@ExcelColumn(name = "角色排序")
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer roleSort;
|
||||
|
||||
|
||||
private String remark;
|
||||
|
||||
|
||||
@ExcelColumn(name = "数据范围")
|
||||
private String dataScope;
|
||||
|
||||
@PositiveOrZero
|
||||
private String status;
|
||||
|
||||
@NotNull
|
||||
private List<Long> menuIds;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.agileboot.domain.system.role.command;
|
||||
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Positive;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class UpdateDataScopeCommand {
|
||||
|
||||
@NotNull
|
||||
@Positive
|
||||
private Long roleId;
|
||||
|
||||
@NotNull
|
||||
@NotEmpty
|
||||
private List<Long> deptIds;
|
||||
|
||||
private Integer dataScope;
|
||||
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.agileboot.domain.system.role.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdateRoleCommand extends AddRoleCommand {
|
||||
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long roleId;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.domain.system.role.command;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UpdateStatusCommand {
|
||||
|
||||
private Long roleId;
|
||||
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.agileboot.domain.system.role.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 角色信息表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_role")
|
||||
@ApiModel(value = "SysRoleEntity对象", description = "角色信息表")
|
||||
public class SysRoleEntity extends BaseEntity<SysRoleEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("角色ID")
|
||||
@TableId(value = "role_id", type = IdType.AUTO)
|
||||
private Long roleId;
|
||||
|
||||
@ApiModelProperty("角色名称")
|
||||
@TableField("role_name")
|
||||
private String roleName;
|
||||
|
||||
@ApiModelProperty("角色权限字符串")
|
||||
@TableField("role_key")
|
||||
private String roleKey;
|
||||
|
||||
@ApiModelProperty("显示顺序")
|
||||
@TableField("role_sort")
|
||||
private Integer roleSort;
|
||||
|
||||
@ApiModelProperty("数据范围(1:全部数据权限 2:自定数据权限 3: 本部门数据权限 4: 本部门及以下数据权限 5: 本人权限)")
|
||||
@TableField("data_scope")
|
||||
private Integer dataScope;
|
||||
|
||||
@ApiModelProperty("角色所拥有的部门数据权限")
|
||||
@TableField("dept_id_set")
|
||||
private String deptIdSet;
|
||||
|
||||
@ApiModelProperty("角色状态(1正常 0停用)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.roleId;
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.agileboot.domain.system.role.db;
|
||||
|
||||
import com.agileboot.domain.system.menu.db.SysMenuEntity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 角色信息表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-06-16
|
||||
*/
|
||||
public interface SysRoleMapper extends BaseMapper<SysRoleEntity> {
|
||||
|
||||
/**
|
||||
* 根据角色ID查询对应的菜单权限
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @return 权限列表
|
||||
*/
|
||||
@Select("SELECT m.* "
|
||||
+ "FROM sys_menu m "
|
||||
+ " LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id "
|
||||
+ " LEFT JOIN sys_role r ON r.role_id = rm.role_id "
|
||||
+ "WHERE m.status = 1 AND m.deleted = 0 "
|
||||
+ " AND r.status = 1 AND r.deleted = 0 "
|
||||
+ " AND r.role_id = #{roleId}")
|
||||
List<SysMenuEntity> getMenuListByRoleId(Long roleId);
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.agileboot.domain.system.role.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import java.io.Serializable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 角色和菜单关联表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2022-10-02
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("sys_role_menu")
|
||||
@ApiModel(value = "SysRoleMenuXEntity对象", description = "角色和菜单关联表")
|
||||
public class SysRoleMenuEntity extends Model<SysRoleMenuEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("角色ID")
|
||||
@TableId(value = "role_id", type = IdType.AUTO)
|
||||
private Long roleId;
|
||||
|
||||
@ApiModelProperty("菜单ID")
|
||||
@TableField("menu_id")
|
||||
private Long menuId;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.menuId;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user