springboot的单体服务 字典参数转译

宅哥聊构架 后端 2024-09-20

springboot的单体服务 字典参数转译

问题难点:

  1. 公司的字典参数是保存在表里面的,所以增删改都需要保持一致。
  2. 这个字典释义是给前端展示给用户用的,我后台写接口时不用做转换工作。
  3. 如何代码改动最小...

code.........

开启缓存

使用springboot 自带的缓存;在项目代码中添加 @EnableCachingjava

代码解读
复制代码
@EnableCaching @SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }

创建一个字典缓存类

看了springboot 自带的缓存框架只需要实现Cache就可以啦;由于我这里为了方便,你可以直接继承ConcurrentMapCache就可以啦;为了防止缓存被更改我这里都是拷贝副本。springboot的单体服务 字典参数转译java

代码解读
复制代码
/** * 字典缓存 * <br/> * date: 2024/5/24<br/> * version 0.1 * * @author ls<br /> */ @Component public class DicCache implements Cache { /** * cache name */ public static final String name = "DIC_CACHE"; private final ConcurrentMap<String, CacheValue> store; public DicCache() { store = new ConcurrentHashMap<>(); } public void put(String key, EntityDicAO value) { if (null == key || null == value) return; EntityDicAO newValue = (EntityDicAO) copy(value); this.store.put(key, new CacheValue(newValue)); } public CacheValue putIfAbsent(String key, EntityDicAO value) { if (null == key || null == value) return null; EntityDicAO newValue = (EntityDicAO) copy(value); return this.store.putIfAbsent(key, new CacheValue(newValue)); } /** * 从缓存中删除 * * @param key index */ public void evict(String key) { this.store.remove(key); } /** * 从缓存中删除 * * @param key index */ public void remove(String key) { this.evict(key); } /** * Return the cache name. */ @Override public String getName() { return name; } /** * Return the underlying native cache provider. */ @Override public Object getNativeCache() { return this.store; } public EntityDicAO get(String key) { CacheValue cacheValue = this.store.get(key); return (EntityDicAO) copy(cacheValue.getValue()); } @Override public ValueWrapper get(Object key) { if (!this.store.containsKey(key)) { return null; } CacheValue cacheValue = this.store.get(key); return (ValueWrapper) copy(cacheValue); } @Override public <T> T get(Object key, Class<T> type) { return (T) this.get((String) key); } @Override public <T> T get(Object key, Callable<T> valueLoader) { CacheValue value = this.store.computeIfAbsent((String) key, r -> { try { T loaderValue = valueLoader.call(); if ((loaderValue instanceof EntityDicAO)) { EntityDicAO loaderValueDic = (EntityDicAO) loaderValue; CacheValue cacheValue = new CacheValue((EntityDicAO) this.copy(loaderValueDic)); return cacheValue; } return null; } catch (Exception ex) { throw new ValueRetrievalException(key, valueLoader, ex); } }); return (T) Optional.ofNullable(value).map(CacheValue::getValue).orElse(null); } @Override public void put(Object key, Object value) { if (value instanceof EntityDicAO) { this.put((String) key, (EntityDicAO) value); return; } if (value instanceof ServiceResult) { ServiceResult valueSt = (ServiceResult) value; Object data = valueSt.getData(); if (data instanceof EntityDicAO) { this.put((String) key, (EntityDicAO) data); } } } @Override public ValueWrapper putIfAbsent(Object key, Object value) { CacheValue cacheValue = this.putIfAbsent((String) key, (EntityDicAO) value); return new SimpleValueWrapper(cacheValue.getValue()); } @Override public void evict(Object key) { this.evict((String) key); } @PreDestroy public void clear() { this.store.clear(); } public EntityDicAO findTypeWithCode(String type, String code) { Optional<CacheValue> value = this.store.values().stream().filter(e -> e.getKey().equals(CacheValue.generateKey(type, code))).findFirst(); return (EntityDicAO) value.map(CacheValue::getValue).map(this::copy).orElse(null); } /** * 缓存包装 */ static class CacheValue implements ValueWrapper, Serializable { private final String key; private final EntityDicAO value; CacheValue(EntityDicAO value) { this.key = generateKey(value); this.value = value; } public String getKey() { return key; } public EntityDicAO getValue() { return value; } private static String generateKey(EntityDicAO value) { // 确保使用用户的唯一标识作为缓存键的一部分 return generateKey(value.getType(), value.getCode()); } protected static String generateKey(String type, String code) { // 确保使用用户的唯一标识作为缓存键的一部分 return MessageFormat.format("{0}@{1}", type, code); } /** * Return the actual value in the cache. */ @Override public Object get() { return this.getValue(); } } /** * 复制字典 * * @param value 字典 * @return 新的字典 */ private <T extends Serializable> Serializable copy(T value) { return SerializationUtils.clone(value); } }

添加一个 cache 配置类

DicCache 添加到cacheManager中java

代码解读
复制代码
@Configuration public class DicCacheConfig { @Autowired private DicCache dicCache; @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Collections.singletonList(dicCache)); return cacheManager; } }

字典服务改造

现在只需要在字典服务中以最小的改动进行修改,添加@CachePut、@CacheEvict 注解就可以实现增删改一致啦java

代码解读
复制代码
public class DicService extends ServiceImpl<EntityDicGeneratedMapper, EntityDicAO> { /** * 保存参数信息 * * @param dicAO 参数信息 * @return 是否成功 */ @CachePut(value = DicCache.name,key = "#dicAO.id",condition = "#result.succeed == true ") @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) public ServiceResult<EntityDicAO> createOrUpdateDic(EntityDicAO dicAO) { //......业务逻辑代码 } /** * 删除参数信息 * * @param id 参数信息ID * @return 是否成功 */ @CacheEvict(value = DicCache.name,key = "#id",condition = "#result.succeed == true ") @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) public ServiceResult<Boolean> deleteDic(String id) { //......业务逻辑代码 } }

实现字典转译

字典释义是给前端展示用的,那是不是数据序列化的时候再做字典转译就可以啦;springboot 默认使用Jackson来做序列化,实现一个jackson 自定义序列化

实现一个自定义注解java

代码解读
复制代码
package x.x.x; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 字典序列化 * @author ls * 2024/5/27 * @version 1.0 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @JacksonAnnotationsInside @JsonSerialize(using = DictSerializerHandel.class) //这里绑定处理类 public @interface DicSerializer { /** 字典类型 */ String type(); /** * 字典释义后的json 字段名 * 默认是原始字段拼接一个Name */ String name() default ""; /** * 值类型 */ Type valueType() default Type.SINGLE; /** *多值时的分隔符 */ String separator() default ","; enum Type{ /** *单值 */ SINGLE, /** *多值 */ MULTI_VALUE } }

实现一个基于注解的jackson 自定义序列化,这里需要注意一下不要导错包 com.fasterxml.jackson.databind 这个包下的。java

代码解读
复制代码
package x.x.x; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import java.io.IOException; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; /** * 字典序列化处理 * @author ls * 2024/5/27 * @version 1.0 */ @JacksonStdImpl public class DictSerializerHandel extends StdSerializer<String> implements ContextualSerializer { private String type; private String name; private DicSerializer.Type valueType; private String separator; public DictSerializerHandel() { super(String.class); } @Override public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { if (Objects.isNull(value)) { gen.writeObject(null); return; } String currentName = gen.getOutputContext().getCurrentName(); if(StringUtils.isEmpty(value) || StringUtils.isEmpty(currentName)){ gen.writeString(""); return; } gen.writeString(value); // 通过数据字典类型和value获取name DicService dicService = SpringUtils.getBean(DicService.class); String translatedValue = ""; switch (valueType){ case SINGLE: EntityDicAO dic = dicService.getDicByTypeWithCode(type, value).getData(); translatedValue= Optional.ofNullable(dic).map(EntityDicAO::getName).orElse(""); break; case MULTI_VALUE: translatedValue = Arrays.stream(value.split(separator)).map(e->dicService.getDicByTypeWithCode(type, e).getData()).filter(Objects::nonNull).map(EntityDicAO::getName).filter(StringUtils::isNotBlank) .distinct().collect(Collectors.joining(separator)); break; default: } gen.writeStringField( StringUtils.isBlank(name) ? currentName.concat("Name") : name, translatedValue ); } @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty beanProperty) { if (beanProperty != null && beanProperty.getType().getRawClass().equals(String.class)) { // 获取注解的参数 DicSerializer annotation = beanProperty.getAnnotation(DicSerializer.class); if (null != annotation) { type = annotation.type(); name = annotation.name(); valueType = annotation.valueType(); separator = annotation.separator(); return this; } } return new ToStringSerializer(); } }

到此就大致可以1啦..................

使用java

代码解读
复制代码
public class EntityEvaluation { // ............ /** * 评估类型 */ @DicSerializer(type = "assessment") private String type; /** * 评估分析-长期目标 多选 多个用‘,‘号分割 */ @DicSerializer(type = "PATIENT_CONCERNS",valueType = DicSerializer.Type.MULTI_VALUE) private String patientConcerns; // ............ }

转载来源:https://juejin.cn/post/7377589884187967498

Apipost 私有化火热进行中

评论