commit:升级到vue3,更新最近工作流技术栈,支持sa-token

This commit is contained in:
Jerry
2024-07-05 22:42:33 +08:00
parent bbcc608584
commit 565ecb6371
1751 changed files with 236790 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>common</artifactId>
<groupId>com.orangeforms</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-dict</artifactId>
<dependencies>
<dependency>
<groupId>com.orangeforms</groupId>
<artifactId>common-redis</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.orangeforms</groupId>
<artifactId>common-sequence</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.orangeforms</groupId>
<artifactId>common-swagger</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,44 @@
package com.orangeforms.common.dict.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 全局字典项目数据状态。
*
* @author Jerry
* @date 2024-07-02
*/
public final class GlobalDictItemStatus {
/**
* 正常。
*/
public static final int NORMAL = 0;
/**
* 禁用。
*/
public static final int DISABLED = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(4);
static {
DICT_MAP.put(NORMAL, "正常");
DICT_MAP.put(DISABLED, "禁用");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private GlobalDictItemStatus() {
}
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.common.dict.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.dict.model.GlobalDictItem;
/**
* 全局字典项目数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface GlobalDictItemMapper extends BaseDaoMapper<GlobalDictItem> {
}

View File

@@ -0,0 +1,34 @@
package com.orangeforms.common.dict.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.dict.model.GlobalDict;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* 全局字典数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface GlobalDictMapper extends BaseDaoMapper<GlobalDict> {
/**
* 获取全局编码字典。
* @param filter 过滤对象。
* @param orderBy 排序字符串。
* @return 全局编码字典。
*/
@Select("<script>"
+ "SELECT * FROM zz_global_dict "
+ "WHERE deleted_flag = 1 "
+ "<if test=\"filter != null\">"
+ " <if test=\"filter.dictCode != null and filter.dictCode != ''\"> AND dict_code = #{filter.dictCode} </if>"
+ " <if test=\"filter.dictName != null and filter.dictName != ''\"> AND dict_name = #{filter.dictName} </if>"
+ "</if>"
+ "<if test=\"orderBy != null and orderBy != ''\"> ORDER BY ${orderBy} </if>"
+ "</script>")
List<GlobalDict> getGlobalDictList(@Param("filter") GlobalDict filter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,54 @@
package com.orangeforms.common.dict.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.dict.model.TenantGlobalDictItem;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 租户全局字典项目数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface TenantGlobalDictItemMapper extends BaseDaoMapper<TenantGlobalDictItem> {
/**
* 批量插入。
*
* @param dictItemList 字典条目列表。
*/
@Insert("<script>"
+ "INSERT INTO zz_tenant_global_dict_item "
+ " (id,"
+ " dict_code,"
+ " tenant_id,"
+ " item_id,"
+ " item_name,"
+ " show_order,"
+ " status,"
+ " create_time,"
+ " create_user_id,"
+ " update_time,"
+ " update_user_id,"
+ " deleted_flag)"
+ "VALUES "
+ "<foreach collection=\"dictItemList\" index=\"index\" item=\"item\" separator=\",\" >"
+ " (#{item.id},"
+ " #{item.dictCode},"
+ " #{item.tenantId},"
+ " #{item.itemId},"
+ " #{item.itemName},"
+ " #{item.showOrder},"
+ " #{item.status},"
+ " #{item.createTime},"
+ " #{item.createUserId},"
+ " #{item.updateTime},"
+ " #{item.updateUserId},"
+ " #{item.deletedFlag})"
+ "</foreach>"
+ "</script>")
void insertList(@Param("dictItemList") List<TenantGlobalDictItem> dictItemList);
}

View File

@@ -0,0 +1,13 @@
package com.orangeforms.common.dict.dao;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.dict.model.TenantGlobalDict;
/**
* 租户全局字典数据操作访问接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface TenantGlobalDictMapper extends BaseDaoMapper<TenantGlobalDict> {
}

View File

@@ -0,0 +1,40 @@
package com.orangeforms.common.dict.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import com.orangeforms.common.core.validator.UpdateGroup;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 全局系统字典Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "全局系统字典Dto")
@Data
public class GlobalDictDto {
/**
* 主键Id。
*/
@Schema(description = "主键Id")
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
private Long dictId;
/**
* 字典编码。
*/
@Schema(description = "字典编码")
@NotBlank(message = "数据验证失败,字典编码不能为空!")
private String dictCode;
/**
* 字典中文名称。
*/
@Schema(description = "字典中文名称")
@NotBlank(message = "数据验证失败,字典中文名称不能为空!")
private String dictName;
}

View File

@@ -0,0 +1,54 @@
package com.orangeforms.common.dict.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import com.orangeforms.common.core.validator.UpdateGroup;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 全局系统字典项目Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "全局系统字典项目Dto")
@Data
public class GlobalDictItemDto {
/**
* 主键Id。
*/
@Schema(description = "主键Id")
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
private Long id;
/**
* 字典编码。
*/
@Schema(description = "字典编码")
@NotBlank(message = "数据验证失败,字典编码不能为空!")
private String dictCode;
/**
* 字典数据项Id。
*/
@Schema(description = "字典数据项Id")
@NotNull(message = "数据验证失败字典数据项Id不能为空")
private String itemId;
/**
* 字典数据项名称。
*/
@Schema(description = "字典数据项名称")
@NotBlank(message = "数据验证失败,字典数据项名称不能为空!")
private String itemName;
/**
* 显示顺序(数值越小越靠前)。
*/
@Schema(description = "显示顺序")
@NotNull(message = "数据验证失败,显示顺序不能为空!")
private Integer showOrder;
}

View File

@@ -0,0 +1,29 @@
package com.orangeforms.common.dict.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "租户全局系统字典Dto")
@EqualsAndHashCode(callSuper = true)
@Data
public class TenantGlobalDictDto extends GlobalDictDto {
/**
* 是否为所有租户的通用字典。
*/
@Schema(description = "是否为所有租户的通用字典")
private Boolean tenantCommon;
/**
* 租户的非公用字典的初始化字典数据。
*/
@Schema(description = "租户的非公用字典的初始化字典数据")
private String initialData;
}

View File

@@ -0,0 +1,18 @@
package com.orangeforms.common.dict.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典项目Dto。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "租户全局系统字典项目Dto")
@EqualsAndHashCode(callSuper = true)
@Data
public class TenantGlobalDictItemDto extends GlobalDictItemDto {
}

View File

@@ -0,0 +1,65 @@
package com.orangeforms.common.dict.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import java.util.Date;
/**
* 全局系统字典实体类。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_global_dict")
public class GlobalDict {
/**
* 主键Id。
*/
@Id(value = "dict_id")
private Long dictId;
/**
* 字典编码。
*/
@Column(value = "dict_code")
private String dictCode;
/**
* 字典中文名称。
*/
@Column(value = "dict_name")
private String dictName;
/**
* 更新用户名。
*/
@Column(value = "update_user_id")
private Long updateUserId;
/**
* 更新时间。
*/
@Column(value = "update_time")
private Date updateTime;
/**
* 创建用户Id。
*/
@Column(value = "create_user_id")
private Long createUserId;
/**
* 创建时间。
*/
@Column(value = "create_time")
private Date createTime;
/**
* 逻辑删除字段。
*/
@Column(value = "deleted_flag", isLogicDelete = true)
private Integer deletedFlag;
}

View File

@@ -0,0 +1,82 @@
package com.orangeforms.common.dict.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import java.util.Date;
/**
* 全局系统字典项目实体类。
*
* @author Jerry
* @date 2024-07-02
*/
@Data
@Table(value = "zz_global_dict_item")
public class GlobalDictItem {
/**
* 主键Id。
*/
@Id(value = "id")
private Long id;
/**
* 字典编码。
*/
@Column(value = "dict_code")
private String dictCode;
/**
* 字典数据项Id。
*/
@Column(value = "item_id")
private String itemId;
/**
* 字典数据项名称。
*/
@Column(value = "item_name")
private String itemName;
/**
* 显示顺序(数值越小越靠前)。
*/
@Column(value = "show_order")
private Integer showOrder;
/**
* 字典状态。具体值引用DictItemStatus常量类。
*/
private Integer status;
/**
* 创建时间。
*/
@Column(value = "create_time")
private Date createTime;
/**
* 创建用户Id。
*/
@Column(value = "create_user_id")
private Long createUserId;
/**
* 更新用户名。
*/
@Column(value = "update_user_id")
private Long updateUserId;
/**
* 更新时间。
*/
@Column(value = "update_time")
private Date updateTime;
/**
* 逻辑删除字段。
*/
@Column(value = "deleted_flag", isLogicDelete = true)
private Integer deletedFlag;
}

View File

@@ -0,0 +1,29 @@
package com.orangeforms.common.dict.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典实体类。
*
* @author Jerry
* @date 2024-07-02
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Table(value = "zz_tenant_global_dict")
public class TenantGlobalDict extends GlobalDict {
/**
* 是否为所有租户的通用字典。
*/
@Column(value = "tenant_common")
private Boolean tenantCommon;
/**
* 租户的非公用字典的初始化字典数据。
*/
@Column(value = "initial_data")
private String initialData;
}

View File

@@ -0,0 +1,23 @@
package com.orangeforms.common.dict.model;
import com.mybatisflex.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典项目实体类。
*
* @author Jerry
* @date 2024-07-02
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Table(value = "zz_tenant_global_dict_item")
public class TenantGlobalDictItem extends GlobalDictItem {
/**
* 租户Id。
*/
@Column(value = "tenant_id")
private Long tenantId;
}

View File

@@ -0,0 +1,92 @@
package com.orangeforms.common.dict.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.dict.model.GlobalDictItem;
import java.io.Serializable;
import java.util.List;
/**
* 全局字典项目数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface GlobalDictItemService extends IBaseService<GlobalDictItem, Long> {
/**
* 保存新增的全局字典项目。
*
* @param globalDictItem 新字典项目对象。
* @return 保存后的对象。
*/
GlobalDictItem saveNew(GlobalDictItem globalDictItem);
/**
* 更新全局字典项目对象。
*
* @param globalDictItem 更新的全局字典项目对象。
* @param originalGlobalDictItem 原有的全局字典项目对象。
* @return 更新成功返回true否则false。
*/
boolean update(GlobalDictItem globalDictItem, GlobalDictItem originalGlobalDictItem);
/**
* 更新字典条目的编码。
*
* @param oldCode 原有编码。
* @param newCode 新编码。
*/
void updateNewCode(String oldCode, String newCode);
/**
* 更新字典条目的状态。
*
* @param globalDictItem 字典项目对象。
* @param status 状态值。
*/
void updateStatus(GlobalDictItem globalDictItem, Integer status);
/**
* 删除指定字典项目。
*
* @param globalDictItem 待删除字典项目。
* @return 成功返回true否则false。
*/
boolean remove(GlobalDictItem globalDictItem);
/**
* 判断指定的编码和项目Id是否存在。
*
* @param dictCode 字典编码。
* @param itemId 项目Id。
* @return true存在否则false。
*/
boolean existDictCodeAndItemId(String dictCode, Serializable itemId);
/**
* 根据字典编码和项目Id获取指定字段项目对象。
*
* @param dictCode 字典编码。
* @param itemId 项目Id。
* @return 字典项目对象。
*/
GlobalDictItem getGlobalDictItemByDictCodeAndItemId(String dictCode, Serializable itemId);
/**
* 查询数据字典项目列表。
*
* @param filter 过滤对象。
* @param orderBy 排序字符串如果为空则按照showOrder升序排序。
* @return 查询结果列表。
*/
List<GlobalDictItem> getGlobalDictItemList(GlobalDictItem filter, String orderBy);
/**
* 查询指定字典编码的数据字典项目列表。查询结果按照showOrder升序排序。
*
* @param dictCode 过滤对象。
* @return 查询结果列表。
*/
List<GlobalDictItem> getGlobalDictItemListByDictCode(String dictCode);
}

View File

@@ -0,0 +1,108 @@
package com.orangeforms.common.dict.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.dict.model.GlobalDict;
import com.orangeforms.common.dict.model.GlobalDictItem;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 全局字典数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface GlobalDictService extends IBaseService<GlobalDict, Long> {
/**
* 保存全局字典对象。
*
* @param globalDict 全局字典对象。
* @return 保存后的字典对象。
*/
GlobalDict saveNew(GlobalDict globalDict);
/**
* 更新全局字典对象。
*
* @param globalDict 更新的全局字典对象。
* @param originalGlobalDict 原有的全局字典对象。
* @return 更新成功返回true否则false。
*/
boolean update(GlobalDict globalDict, GlobalDict originalGlobalDict);
/**
* 删除全局字典对象,以及其关联的字典项目数据。
*
* @param dictId 全局字典Id。
* @return 是否删除成功。
*/
boolean remove(Long dictId);
/**
* 获取全局字典列表。
*
* @param filter 过滤对象。
* @param orderBy 排序条件。
* @return 查询结果集列表。
*/
List<GlobalDict> getGlobalDictList(GlobalDict filter, String orderBy);
/**
* 判断字典编码是否存在。
*
* @param dictCode 字典编码。
* @return true表示存在否则false。
*/
boolean existDictCode(String dictCode);
/**
* 判断指定字典编码的字典项目是否存在。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param dictCode 字典编码。
* @param itemId 字典项目Id。
* @return true表示存在否则false。
*/
boolean existDictItemFromCache(String dictCode, Serializable itemId);
/**
* 从缓存中获取指定编码的字典项目列表。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param dictCode 字典编码。
* @param itemIds 字典项目Id集合。
* @return 查询结果列表。
*/
List<GlobalDictItem> getGlobalDictItemListFromCache(String dictCode, Set<Serializable> itemIds);
/**
* 从缓存中获取指定编码的字典项目列表。返回的结果Map中键是itemId值是itemName。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param dictCode 字典编码。
* @param itemIds 字典项目Id集合。
* @return 查询结果列表。
*/
Map<Serializable, String> getGlobalDictItemDictMapFromCache(String dictCode, Set<Serializable> itemIds);
/**
* 强制同步指定字典编码的全部字典项目到缓存。
*
* @param dictCode 字典编码。
*/
void reloadCachedData(String dictCode);
/**
* 从缓存中移除指定字典编码的数据。
*
* @param dictCode 字典编码。
*/
void removeCache(String dictCode);
}

View File

@@ -0,0 +1,115 @@
package com.orangeforms.common.dict.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.dict.model.TenantGlobalDict;
import com.orangeforms.common.dict.model.TenantGlobalDictItem;
import java.io.Serializable;
import java.util.List;
/**
* 租户全局字典项目数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface TenantGlobalDictItemService extends IBaseService<TenantGlobalDictItem, Long> {
/**
* 保存新增的租户字典项目。
*
* @param tenantGlobalDict 字典对象。
* @param tenantGlobalDictItem 新字典项目对象。
* @return 保存后的对象。
*/
TenantGlobalDictItem saveNew(TenantGlobalDict tenantGlobalDict, TenantGlobalDictItem tenantGlobalDictItem);
/**
* 批量新增的租户字典项目。
*
* @param dictItemList 字典项对象列表。
*/
void saveNewBatch(List<TenantGlobalDictItem> dictItemList);
/**
* 更新租户字典项目对象。
*
* @param tenantGlobalDict 字典对象。
* @param tenantGlobalDictItem 更新的全局字典项目对象。
* @param originalTenantGlobalDictItem 原有的全局字典项目对象。
* @return 更新成功返回true否则false。
*/
boolean update(
TenantGlobalDict tenantGlobalDict,
TenantGlobalDictItem tenantGlobalDictItem,
TenantGlobalDictItem originalTenantGlobalDictItem);
/**
* 更新字典条目的编码。
*
* @param oldCode 原有编码。
* @param newCode 新编码。
*/
void updateNewCode(String oldCode, String newCode);
/**
* 更新字典条目的状态。
*
* @param tenantGlobalDict 字典对象。
* @param tenantGlobalDictItem 字典项目对象。
* @param status 状态值。
*/
void updateStatus(TenantGlobalDict tenantGlobalDict, TenantGlobalDictItem tenantGlobalDictItem, Integer status);
/**
* 删除指定租户字典项目。
*
* @param tenantGlobalDict 字典对象。
* @param tenantGlobalDictItem 待删除字典项目。
* @return 成功返回true否则false。
*/
boolean remove(TenantGlobalDict tenantGlobalDict, TenantGlobalDictItem tenantGlobalDictItem);
/**
* 判断指定字典的项目Id是否存在。如果是租户非公用字典会基于租户Id进行过滤。
*
* @param tenantGlobalDict 字典对象。
* @param itemId 项目Id。
* @return true存在否则false。
*/
boolean existDictCodeAndItemId(TenantGlobalDict tenantGlobalDict, Serializable itemId);
/**
* 判断指定租户的编码是否已经存在字典数据。
*
* @param dictCode 字典编码。
* @return true存在否则false。
*/
boolean existDictCode(String dictCode);
/**
* 根据租户字典编码和项目Id获取指定字段项目对象。
*
* @param dictCode 字典编码。
* @param itemId 项目Id。
* @return 字典项目对象。
*/
TenantGlobalDictItem getGlobalDictItemByDictCodeAndItemId(String dictCode, Serializable itemId);
/**
* 查询租户数据字典项目列表。
*
* @param filter 过滤对象。
* @param orderBy 排序字符串如果为空则按照showOrder升序排序。
* @return 查询结果列表。
*/
List<TenantGlobalDictItem> getGlobalDictItemList(TenantGlobalDictItem filter, String orderBy);
/**
* 查询指定字典的租户数据字典项目列表。如果是租户非公用字典会仅仅返回该租户的字典数据列表。按照showOrder升序排序。
*
* @param tenantGlobalDict 编码字典对象。
* @return 查询结果列表。
*/
List<TenantGlobalDictItem> getGlobalDictItemList(TenantGlobalDict tenantGlobalDict);
}

View File

@@ -0,0 +1,137 @@
package com.orangeforms.common.dict.service;
import com.orangeforms.common.core.base.service.IBaseService;
import com.orangeforms.common.dict.model.TenantGlobalDict;
import com.orangeforms.common.dict.model.TenantGlobalDictItem;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 租户全局字典数据操作服务接口。
*
* @author Jerry
* @date 2024-07-02
*/
public interface TenantGlobalDictService extends IBaseService<TenantGlobalDict, Long> {
/**
* 保存租户全局字典对象。
*
* @param tenantGlobalDict 全局租户字典对象。
* @param tenantIdSet 租户Id集合。
* @return 保存后的字典对象。
*/
TenantGlobalDict saveNew(TenantGlobalDict tenantGlobalDict, Set<Long> tenantIdSet);
/**
* 更新租户全局字典对象。
*
* @param tenantGlobalDict 更新的租户全局字典对象。
* @param originalTenantGlobalDict 原有的租户全局字典对象。
* @return 更新成功返回true否则false。
*/
boolean update(TenantGlobalDict tenantGlobalDict, TenantGlobalDict originalTenantGlobalDict);
/**
* 删除租户全局字典对象,以及其关联的字典项目数据。
*
* @param dictId 全局字典Id。
* @return 是否删除成功。
*/
boolean remove(Long dictId);
/**
* 获取全局字典列表。
*
* @param filter 过滤对象。
* @param orderBy 排序条件。
* @return 查询结果集列表。
*/
List<TenantGlobalDict> getGlobalDictList(TenantGlobalDict filter, String orderBy);
/**
* 判断租户字典编码是否存在。
*
* @param dictCode 字典编码。
* @return true表示存在否则false。
*/
boolean existDictCode(String dictCode);
/**
* 根据字典编码获取全局字典编码对象。
*
* @param dictCode 字典编码。
* @return 查询后的字典对象。
*/
TenantGlobalDict getTenantGlobalDictByDictCode(String dictCode);
/**
* 从缓存中中获取指定字典数据。如果缓存中不存在,会从数据库读取并同步到缓存。
*
* @param dictCode 字典编码。
* @return 查询到的字段对象。
*/
TenantGlobalDict getTenantGlobalDictFromCache(String dictCode);
/**
* 从缓存中获取指定编码的字典项目列表。
* 如果是租户非公用字典,会仅仅返回该租户的字典数据列表。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param tenantGlobalDict 编码字典对象。
* @param itemIds 字典项目Id集合。
* @return 查询结果列表。
*/
List<TenantGlobalDictItem> getGlobalDictItemListFromCache(TenantGlobalDict tenantGlobalDict, Set<Serializable> itemIds);
/**
* 从缓存中获取指定编码的字典项目列表。返回的结果Map中键是itemId值是itemName。
* 如果是租户非公用字典,会仅仅返回该租户的字典数据列表。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param tenantGlobalDict 编码字典对象。
* @param itemIds 字典项目Id集合。
* @return 查询结果列表。
*/
Map<Serializable, String> getGlobalDictItemDictMapFromCache(TenantGlobalDict tenantGlobalDict, Set<Serializable> itemIds);
/**
* 强制同步指定所有租户通用字典编码的全部字典项目到缓存。
* 如果是租户非公用字典,会仅仅返回该租户的字典数据列表。
*
* @param tenantGlobalDict 编码字典对象。
*/
void reloadCachedData(TenantGlobalDict tenantGlobalDict);
/**
* 重置所有非公用租户编码字典的数据到缓存。
* 该方法会将指定编码字典中,所有租户的缓存全部重新加载。一般用于系统故障,或大促活动的数据预热。
*
* @param tenantGlobalDict 非公用编码字典对象。
*/
void reloadAllTenantCachedData(TenantGlobalDict tenantGlobalDict);
/**
* 从缓存中移除指定字典编码的数据。
* 该方法的实现内部会判断是否为公用字典,还是租户可修改的非公用字典。
*
* @param tenantGlobalDict 字典编码。
*/
void removeCache(TenantGlobalDict tenantGlobalDict);
/**
* 判断指定字典编码的字典项目是否存在。
* 该方法通常会在业务主表中调用,为了提升整体运行时效率,该方法会从缓存中获取,如果缓存为空,
* 会从数据库读取指定编码的字典数据,并同步到缓存。
*
* @param dictCode 字典编码。
* @param itemId 字典项目Id。
* @return true表示存在否则false。
*/
boolean existDictItemFromCache(String dictCode, Serializable itemId);
}

View File

@@ -0,0 +1,143 @@
package com.orangeforms.common.dict.service.impl;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.object.TokenData;
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
import com.orangeforms.common.dict.constant.GlobalDictItemStatus;
import com.orangeforms.common.dict.dao.GlobalDictItemMapper;
import com.orangeforms.common.dict.model.GlobalDictItem;
import com.orangeforms.common.dict.service.GlobalDictItemService;
import com.orangeforms.common.dict.service.GlobalDictService;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 全局字典项目数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@MyDataSourceResolver(
resolver = DefaultDataSourceResolver.class,
intArg = ApplicationConstant.COMMON_GLOBAL_DICT_TYPE)
@Service("globalDictItemService")
public class GlobalDictItemServiceImpl
extends BaseService<GlobalDictItem, Long> implements GlobalDictItemService {
@Autowired
private GlobalDictItemMapper globalDictItemMapper;
@Autowired
private GlobalDictService globalDictService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<GlobalDictItem> mapper() {
return globalDictItemMapper;
}
@Override
public GlobalDictItem saveNew(GlobalDictItem globalDictItem) {
globalDictService.removeCache(globalDictItem.getDictCode());
globalDictItem.setId(idGenerator.nextLongId());
globalDictItem.setDeletedFlag(GlobalDeletedFlag.NORMAL);
globalDictItem.setStatus(GlobalDictItemStatus.NORMAL);
globalDictItem.setCreateUserId(TokenData.takeFromRequest().getUserId());
globalDictItem.setUpdateUserId(globalDictItem.getCreateUserId());
globalDictItem.setCreateTime(new Date());
globalDictItem.setUpdateTime(globalDictItem.getCreateTime());
globalDictItemMapper.insert(globalDictItem);
return globalDictItem;
}
@Override
public boolean update(GlobalDictItem globalDictItem, GlobalDictItem originalGlobalDictItem) {
globalDictService.removeCache(globalDictItem.getDictCode());
// 该方法不能直接修改字典状态。
globalDictItem.setStatus(originalGlobalDictItem.getStatus());
globalDictItem.setCreateUserId(originalGlobalDictItem.getCreateUserId());
globalDictItem.setCreateTime(originalGlobalDictItem.getCreateTime());
globalDictItem.setUpdateUserId(TokenData.takeFromRequest().getUserId());
globalDictItem.setUpdateTime(new Date());
return globalDictItemMapper.update(globalDictItem) == 1;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateNewCode(String oldCode, String newCode) {
GlobalDictItem globalDictItem = new GlobalDictItem();
globalDictItem.setDictCode(newCode);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(GlobalDictItem::getDictCode, oldCode);
globalDictItemMapper.updateByQuery(globalDictItem, queryWrapper);
}
@Override
public void updateStatus(GlobalDictItem globalDictItem, Integer status) {
globalDictService.removeCache(globalDictItem.getDictCode());
globalDictItem.setStatus(status);
globalDictItem.setUpdateUserId(TokenData.takeFromRequest().getUserId());
globalDictItem.setUpdateTime(new Date());
globalDictItemMapper.update(globalDictItem);
}
@Override
public boolean remove(GlobalDictItem globalDictItem) {
globalDictService.removeCache(globalDictItem.getDictCode());
return this.removeById(globalDictItem.getId());
}
@Override
public boolean existDictCodeAndItemId(String dictCode, Serializable itemId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(GlobalDictItem::getDictCode, dictCode);
queryWrapper.eq(GlobalDictItem::getItemId, itemId.toString());
return globalDictItemMapper.selectCountByQuery(queryWrapper) > 0;
}
@Override
public GlobalDictItem getGlobalDictItemByDictCodeAndItemId(String dictCode, Serializable itemId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(GlobalDictItem::getDictCode, dictCode);
queryWrapper.eq(GlobalDictItem::getItemId, itemId.toString());
return globalDictItemMapper.selectOneByQuery(queryWrapper);
}
@Override
public List<GlobalDictItem> getGlobalDictItemList(GlobalDictItem filter, String orderBy) {
QueryWrapper queryWrapper = filter == null ? QueryWrapper.create() : QueryWrapper.create(filter);
if (StrUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
} else {
queryWrapper.orderBy(GlobalDictItem::getShowOrder, true);
}
return globalDictItemMapper.selectListByQuery(queryWrapper);
}
@Override
public List<GlobalDictItem> getGlobalDictItemListByDictCode(String dictCode) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(GlobalDictItem::getDictCode, dictCode);
queryWrapper.orderBy(GlobalDictItem::getShowOrder, true);
return globalDictItemMapper.selectListByQuery(queryWrapper);
}
}

View File

@@ -0,0 +1,184 @@
package com.orangeforms.common.dict.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
import com.orangeforms.common.core.object.TokenData;
import com.orangeforms.common.core.util.RedisKeyUtil;
import com.orangeforms.common.dict.constant.GlobalDictItemStatus;
import com.orangeforms.common.dict.dao.GlobalDictMapper;
import com.orangeforms.common.dict.model.GlobalDict;
import com.orangeforms.common.dict.model.GlobalDictItem;
import com.orangeforms.common.dict.service.GlobalDictItemService;
import com.orangeforms.common.dict.service.GlobalDictService;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
* 全局字典数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@MyDataSourceResolver(
resolver = DefaultDataSourceResolver.class,
intArg = ApplicationConstant.COMMON_GLOBAL_DICT_TYPE)
@Service("globalDictService")
public class GlobalDictServiceImpl extends BaseService<GlobalDict, Long> implements GlobalDictService {
@Autowired
private GlobalDictMapper globalDictMapper;
@Autowired
private GlobalDictItemService globalDictItemService;
@Autowired
private RedissonClient redissonClient;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<GlobalDict> mapper() {
return globalDictMapper;
}
@Transactional(rollbackFor = Exception.class)
@Override
public GlobalDict saveNew(GlobalDict globalDict) {
globalDict.setDictId(idGenerator.nextLongId());
globalDict.setDeletedFlag(GlobalDeletedFlag.NORMAL);
globalDict.setCreateUserId(TokenData.takeFromRequest().getUserId());
globalDict.setUpdateUserId(globalDict.getCreateUserId());
globalDict.setCreateTime(new Date());
globalDict.setUpdateTime(globalDict.getCreateTime());
globalDictMapper.insert(globalDict);
return globalDict;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(GlobalDict globalDict, GlobalDict originalGlobalDict) {
this.removeCache(originalGlobalDict.getDictCode());
globalDict.setCreateUserId(originalGlobalDict.getCreateUserId());
globalDict.setCreateTime(originalGlobalDict.getCreateTime());
globalDict.setUpdateUserId(TokenData.takeFromRequest().getUserId());
globalDict.setUpdateTime(new Date());
if (globalDictMapper.update(globalDict) != 1) {
return false;
}
if (!StrUtil.equals(globalDict.getDictCode(), originalGlobalDict.getDictCode())) {
globalDictItemService.updateNewCode(originalGlobalDict.getDictCode(), globalDict.getDictCode());
}
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long dictId) {
GlobalDict globalDict = this.getById(dictId);
if (globalDict == null) {
return false;
}
this.removeCache(globalDict.getDictCode());
if (globalDictMapper.deleteById(dictId) == 0) {
return false;
}
GlobalDictItem filter = new GlobalDictItem();
filter.setDictCode(globalDict.getDictCode());
globalDictItemService.removeBy(filter);
return true;
}
@Override
public List<GlobalDict> getGlobalDictList(GlobalDict filter, String orderBy) {
return globalDictMapper.getGlobalDictList(filter, orderBy);
}
@Override
public boolean existDictCode(String dictCode) {
return globalDictMapper.selectCountByQuery(new QueryWrapper().eq(GlobalDict::getDictCode, dictCode)) > 0;
}
@Override
public boolean existDictItemFromCache(String dictCode, Serializable itemId) {
return CollUtil.isNotEmpty(this.getGlobalDictItemListFromCache(dictCode, CollUtil.newHashSet(itemId)));
}
@Override
public List<GlobalDictItem> getGlobalDictItemListFromCache(String dictCode, Set<Serializable> itemIds) {
if (CollUtil.isNotEmpty(itemIds) && !(itemIds.iterator().next() instanceof String)) {
itemIds = itemIds.stream().map(Object::toString).collect(Collectors.toSet());
}
List<GlobalDictItem> dataList;
RMap<Serializable, String> cachedMap =
redissonClient.getMap(RedisKeyUtil.makeGlobalDictKey(dictCode));
if (cachedMap.isExists()) {
Map<Serializable, String> dataMap =
CollUtil.isEmpty(itemIds) ? cachedMap.readAllMap() : cachedMap.getAll(itemIds);
dataList = dataMap.values().stream()
.map(c -> JSON.parseObject(c, GlobalDictItem.class)).collect(Collectors.toList());
dataList.sort(Comparator.comparingInt(GlobalDictItem::getShowOrder));
} else {
dataList = globalDictItemService.getGlobalDictItemListByDictCode(dictCode);
this.putCache(dictCode, dataList);
if (CollUtil.isNotEmpty(itemIds)) {
Set<Serializable> tmpItemIds = itemIds;
dataList = dataList.stream()
.filter(c -> tmpItemIds.contains(c.getItemId())).collect(Collectors.toList());
}
}
return dataList;
}
@Override
public Map<Serializable, String> getGlobalDictItemDictMapFromCache(String dictCode, Set<Serializable> itemIds) {
List<GlobalDictItem> dataList = this.getGlobalDictItemListFromCache(dictCode, itemIds);
return dataList.stream().collect(Collectors.toMap(GlobalDictItem::getItemId, GlobalDictItem::getItemName));
}
@Override
public void reloadCachedData(String dictCode) {
this.removeCache(dictCode);
List<GlobalDictItem> dataList = globalDictItemService.getGlobalDictItemListByDictCode(dictCode);
this.putCache(dictCode, dataList);
}
@Override
public void removeCache(String dictCode) {
if (StrUtil.isNotBlank(dictCode)) {
redissonClient.getMap(RedisKeyUtil.makeGlobalDictKey(dictCode)).delete();
}
}
private void putCache(String dictCode, List<GlobalDictItem> globalDictItemList) {
if (CollUtil.isNotEmpty(globalDictItemList)) {
Map<Serializable, String> dataMap = globalDictItemList.stream()
.filter(item -> item.getStatus() == GlobalDictItemStatus.NORMAL)
.collect(Collectors.toMap(GlobalDictItem::getItemId, JSON::toJSONString));
if (MapUtil.isNotEmpty(dataMap)) {
redissonClient.getMap(RedisKeyUtil.makeGlobalDictKey(dictCode)).putAll(dataMap);
}
}
}
}

View File

@@ -0,0 +1,189 @@
package com.orangeforms.common.dict.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.BooleanUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.object.TokenData;
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
import com.orangeforms.common.dict.constant.GlobalDictItemStatus;
import com.orangeforms.common.dict.dao.TenantGlobalDictItemMapper;
import com.orangeforms.common.dict.model.TenantGlobalDict;
import com.orangeforms.common.dict.model.TenantGlobalDictItem;
import com.orangeforms.common.dict.service.TenantGlobalDictItemService;
import com.orangeforms.common.dict.service.TenantGlobalDictService;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 租户全局字典项目数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@MyDataSourceResolver(
resolver = DefaultDataSourceResolver.class,
intArg = ApplicationConstant.TENANT_COMMON_DATASOURCE_TYPE)
@Slf4j
@Service("tenantGlobalDictItemService")
public class TenantGlobalDictItemServiceImpl
extends BaseService<TenantGlobalDictItem, Long> implements TenantGlobalDictItemService {
@Autowired
private TenantGlobalDictItemMapper tenantGlobalDictItemMapper;
@Autowired
private TenantGlobalDictService tenantGlobalDictService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<TenantGlobalDictItem> mapper() {
return tenantGlobalDictItemMapper;
}
@Transactional(rollbackFor = Exception.class)
@Override
public TenantGlobalDictItem saveNew(TenantGlobalDict dict, TenantGlobalDictItem dictItem) {
tenantGlobalDictService.removeCache(dict);
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
dictItem.setTenantId(TokenData.takeFromRequest().getTenantId());
}
dictItem.setId(idGenerator.nextLongId());
dictItem.setDeletedFlag(GlobalDeletedFlag.NORMAL);
dictItem.setStatus(GlobalDictItemStatus.NORMAL);
dictItem.setCreateUserId(TokenData.takeFromRequest().getUserId());
dictItem.setUpdateUserId(dictItem.getCreateUserId());
dictItem.setCreateTime(new Date());
dictItem.setUpdateTime(dictItem.getCreateTime());
tenantGlobalDictItemMapper.insert(dictItem);
return dictItem;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void saveNewBatch(List<TenantGlobalDictItem> dictItemList) {
if (CollUtil.isEmpty(dictItemList)) {
return;
}
Date now = new Date();
for (TenantGlobalDictItem dictItem : dictItemList) {
if (dictItem.getId() == null) {
dictItem.setId(idGenerator.nextLongId());
}
if (dictItem.getCreateUserId() == null) {
dictItem.setCreateUserId(TokenData.takeFromRequest().getUserId());
}
dictItem.setUpdateUserId(dictItem.getCreateUserId());
dictItem.setUpdateTime(now);
dictItem.setCreateTime(now);
dictItem.setStatus(GlobalDictItemStatus.NORMAL);
dictItem.setDeletedFlag(GlobalDeletedFlag.NORMAL);
}
tenantGlobalDictItemMapper.insertList(dictItemList);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(TenantGlobalDict dict, TenantGlobalDictItem dictItem, TenantGlobalDictItem originalDictItem) {
tenantGlobalDictService.removeCache(dict);
// 该方法不能直接修改字典状态更不会修改tenantId。
dictItem.setStatus(originalDictItem.getStatus());
dictItem.setTenantId(originalDictItem.getTenantId());
dictItem.setCreateUserId(originalDictItem.getCreateUserId());
dictItem.setCreateTime(originalDictItem.getCreateTime());
dictItem.setUpdateUserId(TokenData.takeFromRequest().getUserId());
dictItem.setUpdateTime(new Date());
return tenantGlobalDictItemMapper.update(dictItem) == 1;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateNewCode(String oldCode, String newCode) {
TenantGlobalDictItem dictItem = new TenantGlobalDictItem();
dictItem.setDictCode(newCode);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(TenantGlobalDictItem::getDictCode, oldCode);
tenantGlobalDictItemMapper.updateByQuery(dictItem, queryWrapper);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateStatus(TenantGlobalDict dict, TenantGlobalDictItem dictItem, Integer status) {
tenantGlobalDictService.removeCache(dict);
dictItem.setStatus(status);
dictItem.setUpdateUserId(TokenData.takeFromRequest().getUserId());
dictItem.setUpdateTime(new Date());
tenantGlobalDictItemMapper.update(dictItem);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(TenantGlobalDict dict, TenantGlobalDictItem dictItem) {
tenantGlobalDictService.removeCache(dict);
return this.removeById(dictItem.getId());
}
@Override
public boolean existDictCodeAndItemId(TenantGlobalDict dict, Serializable itemId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(TenantGlobalDictItem::getDictCode, dict.getDictCode());
queryWrapper.eq(TenantGlobalDictItem::getItemId, itemId.toString());
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
queryWrapper.eq(TenantGlobalDictItem::getTenantId, TokenData.takeFromRequest().getTenantId());
}
return tenantGlobalDictItemMapper.selectCountByQuery(queryWrapper) > 0;
}
@Override
public boolean existDictCode(String dictCode) {
return tenantGlobalDictItemMapper.selectCountByQuery(
new QueryWrapper().eq(TenantGlobalDictItem::getDictCode, dictCode)) > 0;
}
@Override
public TenantGlobalDictItem getGlobalDictItemByDictCodeAndItemId(String dictCode, Serializable itemId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(TenantGlobalDictItem::getDictCode, dictCode);
queryWrapper.eq(TenantGlobalDictItem::getItemId, itemId.toString());
return tenantGlobalDictItemMapper.selectOneByQuery(queryWrapper);
}
@Override
public List<TenantGlobalDictItem> getGlobalDictItemList(TenantGlobalDictItem filter, String orderBy) {
QueryWrapper queryWrapper = filter == null ? QueryWrapper.create() : QueryWrapper.create(filter);
if (StrUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
} else {
queryWrapper.orderBy(TenantGlobalDictItem::getShowOrder, true);
}
return tenantGlobalDictItemMapper.selectListByQuery(queryWrapper);
}
@Override
public List<TenantGlobalDictItem> getGlobalDictItemList(TenantGlobalDict dict) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(TenantGlobalDictItem::getDictCode, dict.getDictCode());
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
queryWrapper.eq(TenantGlobalDictItem::getTenantId, TokenData.takeFromRequest().getTenantId());
}
queryWrapper.orderBy(TenantGlobalDictItem::getShowOrder, true);
return tenantGlobalDictItemMapper.selectListByQuery(queryWrapper);
}
}

View File

@@ -0,0 +1,302 @@
package com.orangeforms.common.dict.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.mybatisflex.core.query.QueryWrapper;
import com.orangeforms.common.core.annotation.MyDataSourceResolver;
import com.orangeforms.common.core.base.dao.BaseDaoMapper;
import com.orangeforms.common.core.base.service.BaseService;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.constant.GlobalDeletedFlag;
import com.orangeforms.common.core.object.TokenData;
import com.orangeforms.common.core.util.DefaultDataSourceResolver;
import com.orangeforms.common.core.util.RedisKeyUtil;
import com.orangeforms.common.dict.constant.GlobalDictItemStatus;
import com.orangeforms.common.dict.dao.TenantGlobalDictMapper;
import com.orangeforms.common.dict.model.TenantGlobalDict;
import com.orangeforms.common.dict.model.TenantGlobalDictItem;
import com.orangeforms.common.dict.service.TenantGlobalDictItemService;
import com.orangeforms.common.dict.service.TenantGlobalDictService;
import com.orangeforms.common.sequence.wrapper.IdGeneratorWrapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 租户全局字典数据操作服务类。
*
* @author Jerry
* @date 2024-07-02
*/
@MyDataSourceResolver(
resolver = DefaultDataSourceResolver.class,
intArg = ApplicationConstant.TENANT_COMMON_DATASOURCE_TYPE)
@Slf4j
@Service("tenantGlobalDictService")
public class TenantGlobalDictServiceImpl
extends BaseService<TenantGlobalDict, Long> implements TenantGlobalDictService {
@Autowired
private TenantGlobalDictMapper tenantGlobalDictMapper;
@Autowired
private TenantGlobalDictItemService tenantGlobalDictItemService;
@Autowired
private RedissonClient redissonClient;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<TenantGlobalDict> mapper() {
return tenantGlobalDictMapper;
}
@Transactional(rollbackFor = Exception.class)
@Override
public TenantGlobalDict saveNew(TenantGlobalDict dict, Set<Long> tenantIdSet) {
String initialData = dict.getInitialData();
dict.setDictId(idGenerator.nextLongId());
dict.setDeletedFlag(GlobalDeletedFlag.NORMAL);
dict.setCreateUserId(TokenData.takeFromRequest().getUserId());
dict.setUpdateUserId(dict.getCreateUserId());
dict.setCreateTime(new Date());
dict.setUpdateTime(dict.getCreateTime());
if (BooleanUtil.isTrue(dict.getTenantCommon())) {
dict.setInitialData(null);
}
tenantGlobalDictMapper.insert(dict);
List<TenantGlobalDictItem> dictItemList = null;
if (StrUtil.isNotBlank(initialData)) {
dictItemList = JSONArray.parseArray(initialData, TenantGlobalDictItem.class);
dictItemList.forEach(dictItem -> {
dictItem.setDictCode(dict.getDictCode());
dictItem.setCreateUserId(dict.getCreateUserId());
});
}
if (BooleanUtil.isTrue(dict.getTenantCommon())) {
tenantGlobalDictItemService.saveNewBatch(dictItemList);
} else {
if (CollUtil.isEmpty(tenantIdSet) || dictItemList == null) {
return dict;
}
for (Long tenantId : tenantIdSet) {
dictItemList.forEach(dictItem -> {
dictItem.setId(idGenerator.nextLongId());
dictItem.setTenantId(tenantId);
});
tenantGlobalDictItemService.saveNewBatch(dictItemList);
}
}
return dict;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(TenantGlobalDict dict, TenantGlobalDict originalDict) {
this.removeGlobalDictAllCache(originalDict);
dict.setCreateUserId(originalDict.getCreateUserId());
dict.setCreateTime(originalDict.getCreateTime());
dict.setUpdateUserId(TokenData.takeFromRequest().getUserId());
dict.setUpdateTime(new Date());
if (tenantGlobalDictMapper.update(dict) != 1) {
return false;
}
if (!StrUtil.equals(dict.getDictCode(), originalDict.getDictCode())) {
tenantGlobalDictItemService.updateNewCode(originalDict.getDictCode(), dict.getDictCode());
}
return true;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long dictId) {
TenantGlobalDict dict = this.getById(dictId);
if (dict == null) {
return false;
}
this.removeGlobalDictAllCache(dict);
if (tenantGlobalDictMapper.deleteById(dictId) == 0) {
return false;
}
TenantGlobalDictItem filter = new TenantGlobalDictItem();
filter.setDictCode(dict.getDictCode());
tenantGlobalDictItemService.removeBy(filter);
return true;
}
@Override
public List<TenantGlobalDict> getGlobalDictList(TenantGlobalDict filter, String orderBy) {
QueryWrapper queryWrapper = filter == null ? QueryWrapper.create() : QueryWrapper.create(filter);
if (StrUtil.isNotBlank(orderBy)) {
queryWrapper.orderBy(orderBy);
}
return tenantGlobalDictMapper.selectListByQuery(queryWrapper);
}
@Override
public boolean existDictCode(String dictCode) {
return tenantGlobalDictMapper.selectCountByQuery(
new QueryWrapper().eq(TenantGlobalDict::getDictCode, dictCode)) > 0;
}
@Override
public TenantGlobalDict getTenantGlobalDictByDictCode(String dictCode) {
return tenantGlobalDictMapper.selectOneByQuery(new QueryWrapper().eq(TenantGlobalDict::getDictCode, dictCode));
}
@Override
public TenantGlobalDict getTenantGlobalDictFromCache(String dictCode) {
String key = RedisKeyUtil.makeGlobalDictOnlyKey(dictCode);
RBucket<String> bucket = redissonClient.getBucket(key);
if (bucket.isExists()) {
return JSON.parseObject(bucket.get(), TenantGlobalDict.class);
}
TenantGlobalDict dict = this.getTenantGlobalDictByDictCode(dictCode);
if (dict != null) {
bucket.set(JSON.toJSONString(dict));
}
return dict;
}
@Override
public List<TenantGlobalDictItem> getGlobalDictItemListFromCache(TenantGlobalDict dict, Set<Serializable> itemIds) {
if (CollUtil.isNotEmpty(itemIds) && !(itemIds.iterator().next() instanceof String)) {
itemIds = itemIds.stream().map(Object::toString).collect(Collectors.toSet());
}
String key = RedisKeyUtil.makeGlobalDictKey(dict.getDictCode());
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
key = this.appendTenantSuffix(key);
}
List<TenantGlobalDictItem> dataList;
RMap<Serializable, String> cachedMap = redissonClient.getMap(key);
if (cachedMap.isExists()) {
Map<Serializable, String> dataMap =
CollUtil.isEmpty(itemIds) ? cachedMap.readAllMap() : cachedMap.getAll(itemIds);
dataList = dataMap.values().stream()
.map(c -> JSON.parseObject(c, TenantGlobalDictItem.class)).collect(Collectors.toList());
dataList.sort(Comparator.comparingInt(TenantGlobalDictItem::getShowOrder));
} else {
dataList = tenantGlobalDictItemService.getGlobalDictItemList(dict);
this.putCache(dict, dataList);
if (CollUtil.isNotEmpty(itemIds)) {
Set<Serializable> tmpItemIds = itemIds;
dataList = dataList.stream()
.filter(c -> tmpItemIds.contains(c.getItemId())).collect(Collectors.toList());
}
}
return dataList;
}
@Override
public Map<Serializable, String> getGlobalDictItemDictMapFromCache(
TenantGlobalDict dict, Set<Serializable> itemIds) {
List<TenantGlobalDictItem> dataList = this.getGlobalDictItemListFromCache(dict, itemIds);
return dataList.stream()
.collect(Collectors.toMap(TenantGlobalDictItem::getItemId, TenantGlobalDictItem::getItemName));
}
@Override
public void reloadCachedData(TenantGlobalDict dict) {
this.removeCache(dict);
List<TenantGlobalDictItem> dataList = tenantGlobalDictItemService.getGlobalDictItemList(dict);
this.putCache(dict, dataList);
}
@Override
public void reloadAllTenantCachedData(TenantGlobalDict dict) {
if (StrUtil.isBlank(dict.getDictCode())) {
return;
}
String dictCodeKey = RedisKeyUtil.makeGlobalDictKey(dict.getDictCode());
redissonClient.getKeys().deleteByPattern(dictCodeKey + "*");
TenantGlobalDictItem filter = new TenantGlobalDictItem();
filter.setDictCode(dict.getDictCode());
List<TenantGlobalDictItem> dictItemList =
tenantGlobalDictItemService.getGlobalDictItemList(filter, null);
if (CollUtil.isEmpty(dictItemList)) {
return;
}
Map<Serializable, List<TenantGlobalDictItem>> dictItemMap =
dictItemList.stream().collect(Collectors.groupingBy(TenantGlobalDictItem::getTenantId));
for (Map.Entry<Serializable, List<TenantGlobalDictItem>> entry : dictItemMap.entrySet()) {
String key = dictCodeKey + "-" + entry.getKey();
Map<Serializable, String> dataMap = entry.getValue().stream()
.collect(Collectors.toMap(TenantGlobalDictItem::getItemId, JSON::toJSONString));
RMap<Serializable, String> cachedMap = redissonClient.getMap(key);
cachedMap.putAll(dataMap);
cachedMap.expire(1, TimeUnit.DAYS);
}
}
@Override
public void removeCache(TenantGlobalDict dict) {
if (StrUtil.isBlank(dict.getDictCode())) {
return;
}
String key = RedisKeyUtil.makeGlobalDictKey(dict.getDictCode());
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
key = this.appendTenantSuffix(key);
}
redissonClient.getMap(key).delete();
}
@Override
public boolean existDictItemFromCache(String dictCode, Serializable itemId) {
TenantGlobalDict tenantGlobalDict = this.getTenantGlobalDictFromCache(dictCode);
return CollUtil.isNotEmpty(this.getGlobalDictItemListFromCache(tenantGlobalDict, CollUtil.newHashSet(itemId)));
}
private void putCache(TenantGlobalDict dict, List<TenantGlobalDictItem> dictItemList) {
if (CollUtil.isEmpty(dictItemList)) {
return;
}
String key = RedisKeyUtil.makeGlobalDictKey(dict.getDictCode());
if (BooleanUtil.isFalse(dict.getTenantCommon())) {
key = this.appendTenantSuffix(key);
}
Map<Serializable, String> dataMap = dictItemList.stream()
.filter(item -> item.getStatus() == GlobalDictItemStatus.NORMAL)
.collect(Collectors.toMap(TenantGlobalDictItem::getItemId, JSON::toJSONString));
if (MapUtil.isNotEmpty(dataMap)) {
RMap<Serializable, String> cachedMap = redissonClient.getMap(key);
cachedMap.putAll(dataMap);
cachedMap.expire(1, TimeUnit.DAYS);
}
}
private String appendTenantSuffix(String key) {
return key + "-" + TokenData.takeFromRequest().getTenantId();
}
private void removeGlobalDictAllCache(TenantGlobalDict dict) {
String dictCode = dict.getDictCode();
if (StrUtil.isBlank(dictCode)) {
return;
}
String key = RedisKeyUtil.makeGlobalDictOnlyKey(dictCode);
redissonClient.getBucket(key).delete();
key = RedisKeyUtil.makeGlobalDictKey(dictCode);
if (BooleanUtil.isTrue(dict.getTenantCommon())) {
redissonClient.getMap(key).delete();
} else {
redissonClient.getKeys().deleteByPatternAsync(key + "*");
}
}
}

View File

@@ -0,0 +1,89 @@
package com.orangeforms.common.dict.util;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import com.orangeforms.common.core.constant.ApplicationConstant;
import com.orangeforms.common.core.object.ResponseResult;
import com.orangeforms.common.core.object.MyPageData;
import com.orangeforms.common.core.object.MyPageParam;
import com.orangeforms.common.core.util.MyModelUtil;
import com.orangeforms.common.core.util.MyPageUtil;
import com.orangeforms.common.dict.dto.GlobalDictDto;
import com.orangeforms.common.dict.model.GlobalDict;
import com.orangeforms.common.dict.model.GlobalDictItem;
import com.orangeforms.common.dict.service.GlobalDictService;
import com.orangeforms.common.dict.vo.GlobalDictVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 全局编码字典操作的通用帮助对象。
*
* @author Jerry
* @date 2024-07-02
*/
@Slf4j
@Component
public class GlobalDictOperationHelper {
@Autowired
private GlobalDictService globalDictService;
/**
* 获取全部编码字典列表。
*
* @param globalDictDtoFilter 过滤对象。
* @param pageParam 分页参数。
* @return 字典的数据列表。
*/
public ResponseResult<MyPageData<GlobalDictVo>> listAllGlobalDict(
GlobalDictDto globalDictDtoFilter, MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
GlobalDict filter = MyModelUtil.copyTo(globalDictDtoFilter, GlobalDict.class);
List<GlobalDict> dictList = globalDictService.getGlobalDictList(filter, null);
List<GlobalDictVo> dictVoList = MyModelUtil.copyCollectionTo(dictList, GlobalDictVo.class);
long totalCount = 0L;
if (dictList instanceof Page) {
totalCount = ((Page<GlobalDict>) dictList).getTotal();
}
return ResponseResult.success(MyPageUtil.makeResponseData(dictVoList, totalCount));
}
public List<Map<String, Object>> toDictDataList(List<? extends GlobalDictItem> resultList, String itemIdType) {
return resultList.stream().map(item -> {
Map<String, Object> dataMap = new HashMap<>(4);
Object itemId = item.getItemId();
if (StrUtil.equals(itemIdType, "Long")) {
itemId = Long.valueOf(item.getItemId());
} else if (StrUtil.equals(itemIdType, "Integer")) {
itemId = Integer.valueOf(item.getItemId());
}
dataMap.put(ApplicationConstant.DICT_ID, itemId);
dataMap.put(ApplicationConstant.DICT_NAME, item.getItemName());
dataMap.put("showOrder", item.getShowOrder());
dataMap.put("status", item.getStatus());
return dataMap;
}).collect(Collectors.toList());
}
public List<Map<String, Object>> toDictDataList2(List<? extends GlobalDictItem> resultList) {
return resultList.stream().map(item -> {
Map<String, Object> dataMap = new HashMap<>(5);
dataMap.put(ApplicationConstant.DICT_ID, item.getId());
dataMap.put("itemId", item.getItemId());
dataMap.put(ApplicationConstant.DICT_NAME, item.getItemName());
dataMap.put("showOrder", item.getShowOrder());
dataMap.put("status", item.getStatus());
return dataMap;
}).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,77 @@
package com.orangeforms.common.dict.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 全局系统字典项目Vo。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "全局系统字典项目Vo")
@Data
public class GlobalDictItemVo {
/**
* 主键Id。
*/
@Schema(description = "主键Id")
private Long id;
/**
* 字典编码。
*/
@Schema(description = "字典编码")
private String dictCode;
/**
* 字典数据项Id。
*/
@Schema(description = "字典数据项Id")
private String itemId;
/**
* 字典数据项名称。
*/
@Schema(description = "字典数据项名称")
private String itemName;
/**
* 显示顺序(数值越小越靠前)。
*/
@Schema(description = "显示顺序")
private Integer showOrder;
/**
* 字典状态。具体值引用DictItemStatus常量类。
*/
@Schema(description = "字典状态")
private Integer status;
/**
* 创建用户Id。
*/
@Schema(description = "创建用户Id")
private Long createUserId;
/**
* 创建时间。
*/
@Schema(description = "创建时间")
private Date createTime;
/**
* 创建用户名。
*/
@Schema(description = "创建用户名")
private Long updateUserId;
/**
* 更新时间。
*/
@Schema(description = "更新时间")
private Date updateTime;
}

View File

@@ -0,0 +1,59 @@
package com.orangeforms.common.dict.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* 全局系统字典Vo。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "全局系统字典Vo")
@Data
public class GlobalDictVo {
/**
* 主键Id。
*/
@Schema(description = "主键Id")
private Long dictId;
/**
* 字典编码。
*/
@Schema(description = "字典编码")
private String dictCode;
/**
* 字典中文名称。
*/
@Schema(description = "字典中文名称")
private String dictName;
/**
* 创建用户Id。
*/
@Schema(description = "创建用户Id")
private Long createUserId;
/**
* 创建时间。
*/
@Schema(description = "创建时间")
private Date createTime;
/**
* 创建用户名。
*/
@Schema(description = "创建用户名")
private Long updateUserId;
/**
* 更新时间。
*/
@Schema(description = "更新时间")
private Date updateTime;
}

View File

@@ -0,0 +1,18 @@
package com.orangeforms.common.dict.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典项目Vo。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "租户全局系统字典项目Vo")
@Data
@EqualsAndHashCode(callSuper = true)
public class TenantGlobalDictItemVo extends GlobalDictItemVo {
}

View File

@@ -0,0 +1,29 @@
package com.orangeforms.common.dict.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 租户全局系统字典Vo。
*
* @author Jerry
* @date 2024-07-02
*/
@Schema(description = "租户全局系统字典Vo")
@Data
@EqualsAndHashCode(callSuper = true)
public class TenantGlobalDictVo extends GlobalDictVo {
/**
* 是否为所有租户的通用字典。
*/
@Schema(description = "是否为所有租户的通用字典")
private Boolean tenantCommon;
/**
* 租户的非公用字典的初始化字典数据。
*/
@Schema(description = "租户的非公用字典的初始化字典数据")
private String initialData;
}