Skip to content

Commit

Permalink
feat: 增加树形结构数据的字典文本转换支持
Browse files Browse the repository at this point in the history
  • Loading branch information
houkunlin committed Dec 12, 2021
1 parent 6692659 commit 097d83c
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 2 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {
}

group = 'com.houkunlin'
version = '1.4.5.1'
version = '1.4.6-BUILD-SNAPSHOT'
sourceCompatibility = '1.8'
description = """
系统数据字典自动翻译成字典文本。可集合系统数据库中存储的用户数据字典,也可使用枚举做系统数据字典,主要用在返回数据给前端时自动把字典值翻译成字典文本信息;
Expand Down
66 changes: 66 additions & 0 deletions src/main/java/com/houkunlin/system/dict/starter/DictUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
public class DictUtil {
public static final String TYPE_PREFIX = "dict:t:";
public static final String VALUE_PREFIX = "dict:v:";
public static final String PARENT_PREFIX = "dict:p:";

private static DictStore store;
/**
Expand All @@ -42,6 +43,13 @@ public static DictTypeVo getDictType(String type) {
return store.getDictType(type);
}

/**
* 获取字典文本
*
* @param type 字典类型
* @param value 字典值
* @return
*/
public static String getDictText(String type, String value) {
if (type == null || value == null || store == null) {
return null;
Expand Down Expand Up @@ -69,6 +77,41 @@ public static String getDictText(String type, String value) {
return dictText;
}

/**
* 获取字典父级值
*
* @param type 字典类型
* @param value 字典值
* @return 字典父级值
* @since 1.4.6
*/
public static String getDictParentValue(String type, String value) {
if (type == null || value == null || store == null) {
return null;
}
if (cache == null || missCache == null) {
return store.getDictParentValue(type, value);
}
final String dictParentKey = dictParentKey(type, value);
final String result = cache.getIfPresent(dictParentKey);
if (result != null) {
return result;
}
final AtomicInteger integer = missCache.get(dictParentKey, s -> new AtomicInteger(1));
if (integer.get() > missNum) {
return null;
}

final String parentValue = store.getDictParentValue(type, value);
if (parentValue == null) {
// 未命中数据
integer.incrementAndGet();
} else {
cache.put(dictParentKey, parentValue);
}
return parentValue;
}

public static String dictKey(String type) {
return TYPE_PREFIX + type;
}
Expand All @@ -77,7 +120,30 @@ public static String dictKey(DictValueVo value) {
return VALUE_PREFIX + value.getDictType() + ":" + value.getValue();
}

/**
* 构建字典父级值缓存 KEY
*
* @param value 字典值对象
* @return 字典父级值缓存 KEY
* @since 1.4.6
*/
public static String dictParentKey(DictValueVo value) {
return PARENT_PREFIX + value.getDictType() + ":" + value.getValue();
}

public static String dictKey(String type, Object value) {
return VALUE_PREFIX + type + ":" + value;
}

/**
* 构建字典父级值缓存 KEY
*
* @param type 字典类型
* @param value 字典值
* @return 字典父级值缓存 KEY
* @since 1.4.6
*/
public static String dictParentKey(String type, Object value) {
return PARENT_PREFIX + type + ":" + value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ public DictTypeVo.DictTypeBuilder add(final Object value, final String title) {
return this;
}

/**
* 树形结构数据
*
* @param parentValue 字典父级值
* @param value 字典值
* @param title 字典文本
* @return this
* @since 1.4.6
*/
public DictTypeVo.DictTypeBuilder add(final Object parentValue, final Object value, final String title) {
this.children.add(new DictValueVo(type, parentValue, value, title, 0));
return this;
}

public DictTypeVo build() {
return new DictTypeVo(title, type, remark, children);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ public class DictValueVo implements Serializable {
@ApiModelProperty(value = "字典类型代码", hidden = true)
@JsonIgnore
private String dictType;
/**
* 父级字典值,由父级字典值可以组成一个类似树形结构数据的字典信息。
* 构建树形结构字典数据所需要的一个父级值;
*
* @since 1.4.6
*/
@ApiModelProperty("父级字典值")
private Object parentValue;
/**
* 字典值
*/
Expand All @@ -45,4 +53,11 @@ public class DictValueVo implements Serializable {
*/
@ApiModelProperty("排序值(系统不会执行排序后再返回给前端)")
private int sorted;

public DictValueVo(final String dictType, final Object value, final String title, final int sorted) {
this.dictType = dictType;
this.value = value;
this.title = title;
this.sorted = sorted;
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/houkunlin/system/dict/starter/json/DictText.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@
*/
Array array() default @Array(split = "");

/**
* 是否是树形结构数据;
*
* @return boolean <ul>
* <li>true 是树形结构数据,加载父级信息(采用递归加载,可能会多次加载父级信息);</li>
* <li>false 不是树形结构数据,不加载父级信息;</li>
* </ul>
* @since 1.4.6
*/
boolean tree() default false;

enum Type {
/**
* 根据全局参数决定配置
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ private Object obtainResult(final List<String> dictTexts) {
* @return 字典值文本
*/
protected String obtainDictValueText(String dictValue) {
// @since 1.4.6 - START
if (dictText.tree()) {
final List<String> values = new LinkedList<>();
String value = dictValue;
do {
final String text = DictUtil.getDictText(dictType, value);
if (text != null) {
values.add(0, text);
}
value = DictUtil.getDictParentValue(dictType, value);
} while (value != null);
if (values.isEmpty()) {
return null;
}
return String.join("/", values);
}
// @since 1.4.6 - END
return DictUtil.getDictText(dictType, dictValue);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,14 @@ public interface DictStore {
* @return 字典文本
*/
String getDictText(String type, String value);

/**
* 获取字典父级值
*
* @param type 字典所属类型
* @param value 字典值
* @return 字典文本
* @since 1.4.6
*/
String getDictParentValue(String type, String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ public void store(final Iterator<DictValueVo> iterator) {
}
} else {
CACHE_TEXT.put(dictKey, title);
// @since 1.4.6 - START
final String dictParentKey = DictUtil.dictParentKey(valueVo);
final Object parentValue = valueVo.getParentValue();
if (parentValue == null) {
CACHE_TEXT.remove(dictParentKey);
} else {
CACHE_TEXT.put(dictParentKey, parentValue.toString());
}
// @since 1.4.6 - END
}
});
}
Expand Down Expand Up @@ -91,6 +100,11 @@ public String getDictText(final String type, final String value) {
return remoteDict.getDictText(type, value);
}

@Override
public String getDictParentValue(final String type, final String value) {
return CACHE_TEXT.get(DictUtil.dictParentKey(type, value));
}

@Override
public void afterPropertiesSet() throws Exception {
if (logger.isDebugEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -38,6 +39,7 @@ public void store(final DictTypeVo dictType) {

@Override
public void store(final Iterator<DictValueVo> iterator) {
final ValueOperations<String, String> opsForValue = dictValueRedisTemplate.opsForValue();
iterator.forEachRemaining(valueVo -> {
final String dictKey = DictUtil.dictKey(valueVo);
final String title = valueVo.getTitle();
Expand All @@ -47,7 +49,16 @@ public void store(final Iterator<DictValueVo> iterator) {
logger.debug("[removeDictValue] 字典值文本被删除 {}", dictKey);
}
} else {
dictValueRedisTemplate.opsForValue().set(dictKey, title);
opsForValue.set(dictKey, title);
// @since 1.4.6 - START
final String dictParentKey = DictUtil.dictParentKey(valueVo);
final Object parentValue = valueVo.getParentValue();
if (parentValue == null) {
dictValueRedisTemplate.delete(dictParentKey);
} else {
opsForValue.set(dictParentKey, parentValue.toString());
}
// @since 1.4.6 - END
}
});
}
Expand Down Expand Up @@ -101,6 +112,14 @@ public String getDictText(final String type, final String value) {
return remoteDict.getDictText(type, value);
}

@Override
public String getDictParentValue(final String type, final String value) {
if (type == null || value == null) {
return null;
}
return dictValueRedisTemplate.opsForValue().get(DictUtil.dictParentKey(type, value));
}

@Override
public void afterPropertiesSet() throws Exception {
if (logger.isDebugEnabled()) {
Expand Down
73 changes: 73 additions & 0 deletions src/test/java/com/houkunlin/system/dict/starter/TreeDataTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.houkunlin.system.dict.starter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.houkunlin.system.dict.starter.bean.DictTypeVo;
import com.houkunlin.system.dict.starter.json.Array;
import com.houkunlin.system.dict.starter.json.DictText;
import com.houkunlin.system.dict.starter.notice.RefreshDictTypeEvent;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationEventPublisher;

/**
* 默认注解使用测试
*
* @author HouKunLin
* @since 1.4.6
*/
@SpringBootTest
class TreeDataTest {
public static final String DICT_TYPE = "TreeData";
@Autowired
private ObjectMapper objectMapper;
@Autowired
private static ApplicationEventPublisher publisher;

@Autowired
public void setPublisher(final ApplicationEventPublisher publisher) {
final DictTypeVo typeVo = DictTypeVo.newBuilder(DICT_TYPE, "树形结构数据测试")
.add("", "1", "节点1")
.add("", "2", "节点2")
.add("", "3", "节点3")
.add("1", "1-1", "节点1-1")
.add("1", "1-2", "节点1-2")
.add("1", "1-3", "节点1-3")
.add("2", "2-1", "节点2-1")
.add("2", "2-2", "节点2-2")
.add("2", "2-3", "节点2-3")
.add("3", "3-1", "节点3-1")
.add("3", "3-2", "节点3-2")
.add("3", "3-3", "节点3-3")
.build();
publisher.publishEvent(new RefreshDictTypeEvent(typeVo));
}

/**
* 基础测试
*
* @throws JsonProcessingException 序列化异常
* @since 1.4.6
*/
@Test
void testBasic1() throws JsonProcessingException {
@Data
@AllArgsConstructor
class Bean {
@DictText(value = DICT_TYPE, tree = true)
private String userType;
@DictText(value = DICT_TYPE, tree = true)
private String userType1;
@DictText(value = DICT_TYPE, tree = true, array = @Array(toText = false))
private String userType3;
}
final Bean bean = new Bean("1", "3-3", "1-1,1-2,1-3,2-1,2-2,2-3,3-1,3-2,3-3,3-4");
final String value = objectMapper.writeValueAsString(bean);
System.out.println(bean);
System.out.println(value);
}

}

0 comments on commit 097d83c

Please sign in to comment.