自定义数据字典翻译注解

自定义数据字典翻译注解

  • 参考出处
    • 代码背景
    • @Dict注解
    • 注解对应实现类
    • 工具类
        • 分页工具类
    • service层查询接口
    • service实现类和Mybatis的SQL语句
    • 实体类
    • 缓存的ehcache.xml存放在项目的位置
    • ehcache.xml
    • ehcache.xsd项目位置
    • ehcache.xsd内容
    • 每次新增或修改数据字典时候清空当前缓存
    • 数据表
    • 表格图片:
    • 表格数据样例
    • 使用样例

参考出处

(非常感谢)https://blog.csdn.net/weixin_42687829/article/details/103289383

代码背景

小公司新项目加上本人也就两个开发,很多地方用到了字典,于是在网上参考一篇数据字典翻译类,自己记录一下,方便之后项目用到使用。

@Dict注解


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: Yin XX
 * @Description:
 * @Date: Create in 11:33 2020/4/30
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
     
    /**
     * 方法描述:数据dataSource
     * @return 返回类型: String
     */
    String dictDataSource();

    /**
     * 方法描述:这是返回后Put到josn中的文本key值
     * @return 返回类型: String
     */
    String dictText() default "";
}

注解对应实现类


import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.renren.common.annotation.Dict;
import io.renren.common.utils.ObjConvertUtils;
import io.renren.common.utils.PageUtils;
import io.renren.modules.dictionaries.service.DictionariesService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Author: Yin XX
 * @Description:
 * @Date: Create in 11:26 2020/4/30
 */
@Aspect
@Component
@Slf4j
public class DictAspect {
     

	//表对应字段加上_dictText即可显示出文本
    private static String DICT_TEXT_SUFFIX = "_dictText";

    @Autowired
    private DictionariesService dataItemService;

    //定义切点Pointcut拦截所有对服务器的请求
    @Pointcut("execution(* io.renren.modules.*.service.*.*(..))")
    public void excudeService() {
     

    }

    /**
     * 这是触发DictionariesService的时候会执行的,在环绕通知中目标对象方法被调用后的结果进行再处理
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
     
        //这是定义开始事件
        long time1 = System.currentTimeMillis();
        //这是方法并获取返回结果
        Object result = pjp.proceed();
        //这是获取到结束时间
        long time2 = System.currentTimeMillis();
        log.info("获取JSON数据耗时:" + (time2 - time1) + "ms");
        //解析开始时间
        long start = System.currentTimeMillis();
        //开始解析(翻译字段内部的值凡是打了@Dict这玩意的都会被翻译)
        this.parseDictText(result);
        //解析结束时间
        long end = System.currentTimeMillis();
        log.info("解析注入JSON数据耗时:" + (end - start) + "ms");
        return result;
    }


    private void parseDictText(Object result) {
     
        if (result instanceof PageUtils) {
     
            List<JSONObject> items = new ArrayList<>();
            PageUtils pageUtils = (PageUtils) result;
            //循环查找出来的数据
            for (Object record : pageUtils.getList()) {
     
                ObjectMapper mapper = new ObjectMapper();
                String json = "{}";
                try {
     
                    //解决@JsonFormat注解解析不了的问题详见SysAnnouncement类的@JsonFormat
                    json = mapper.writeValueAsString(record);
                } catch (JsonProcessingException e) {
     
                    log.error("Json解析失败:" + e);
                }
                JSONObject item = JSONObject.parseObject(json);

                //解决继承实体字段无法翻译问题
                for (Field field : ObjConvertUtils.getAllFields(record)) {
     
                    //解决继承实体字段无法翻译问题
                    if (field.getAnnotation(Dict.class) != null) {
     //如果该属性上面有@Dict注解,则进行翻译
                        String datasource = field.getAnnotation(Dict.class).dictDataSource();//拿到注解的dictDataSource属性的值
                        String text = field.getAnnotation(Dict.class).dictText();//拿到注解的dictText属性的值
                        //获取当前带翻译的值
                        String key = String.valueOf(item.get(field.getName()));
                        //翻译字典值对应的text值
                        String textValue = translateDictValue(datasource, key);
                        //DICT_TEXT_SUFFIX的值为,是默认值:
                        //public static final String DICT_TEXT_SUFFIX = "_dictText";
                        log.debug("字典Val: " + textValue);
                        log.debug("翻译字典字段:" + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue);
                        //如果给了文本名
                        if (!StringUtils.isBlank(text)) {
     
                            item.put(text, textValue);
                        } else {
     
                            //走默认策略
                            item.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
                        }
                    }
                    //date类型默认转换string格式化日期
                    if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
     
                        SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
                    }
                }
                items.add(item);
            }
            pageUtils.setList(items);
        }
    }


    /**
     * 翻译字典文本
     * @param datasource
     * @param key
     * @return
     */
    private String translateDictValue(String datasource, String key) {
     
        //如果key为空直接返回就好了
        if (ObjConvertUtils.isEmpty(key)) {
     
            return null;
        }
        StringBuffer textValue = new StringBuffer();
        //分割key值
        String[] keys = key.split(",");
        //循环keys中的所有值
        for (String k : keys) {
     
            String tmpValue = null;
            log.debug("字典key:" + k);
            if (k.trim().length() == 0) {
     
                continue;//跳过循环
            }
            tmpValue = dataItemService.selectByFieldNameAndFieldValue(datasource, k.trim());

            if (tmpValue != null) {
     
                if (!"".equals(textValue.toString())) {
     
                    textValue.append(",");
                }
                textValue.append(tmpValue);
            }
        }
        //返回翻译的值
        return textValue.toString();
    }
}

工具类


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: Yin xx
 * @Description:
 * @Date: Create in 11:38 2020/4/30
 */
public class ObjConvertUtils {
     
    /**
     * 获取类的所有属性,包括父类
     * @param object
     * @return
     */
    public static Field[] getAllFields(Object object) {
     
        Class<?> clazz = object.getClass();
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
     
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    public static boolean isEmpty(Object object) {
     
        if (object == null) {
     
            return (true);
        }
        if ("".equals(object)) {
     
            return (true);
        }
        if ("null".equals(object)) {
     
            return (true);
        }
        return (false);
    }
}

分页工具类

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */

package io.renren.common.utils;

import com.baomidou.mybatisplus.core.metadata.IPage;

import java.io.Serializable;
import java.util.List;

/**
 * 分页工具类
 *
 * @author Mark [email protected]
 */
public class PageUtils implements Serializable {
     
	private static final long serialVersionUID = 1L;
	/**
	 * 总记录数
	 */
	private int totalCount;
	/**
	 * 每页记录数
	 */
	private int pageSize;
	/**
	 * 总页数
	 */
	private int totalPage;
	/**
	 * 当前页数
	 */
	private int currPage;
	/**
	 * 列表数据
	 */
	private List<?> list;
	
	/**
	 * 分页
	 * @param list        列表数据
	 * @param totalCount  总记录数
	 * @param pageSize    每页记录数
	 * @param currPage    当前页数
	 */
	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
     
		this.list = list;
		this.totalCount = totalCount;
		this.pageSize = pageSize;
		this.currPage = currPage;
		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
	}

	/**
	 * 分页
	 */
	public PageUtils(IPage<?> page) {
     
		this.list = page.getRecords();
		this.totalCount = (int)page.getTotal();
		this.pageSize = (int)page.getSize();
		this.currPage = (int)page.getCurrent();
		this.totalPage = (int)page.getPages();
	}

	public int getTotalCount() {
     
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
     
		this.totalCount = totalCount;
	}

	public int getPageSize() {
     
		return pageSize;
	}

	public void setPageSize(int pageSize) {
     
		this.pageSize = pageSize;
	}

	public int getTotalPage() {
     
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
     
		this.totalPage = totalPage;
	}

	public int getCurrPage() {
     
		return currPage;
	}

	public void setCurrPage(int currPage) {
     
		this.currPage = currPage;
	}

	public List<?> getList() {
     
		return list;
	}

	public void setList(List<?> list) {
     
		this.list = list;
	}
	
}

service层查询接口


import com.baomidou.mybatisplus.extension.service.IService;
import io.renren.common.utils.PageUtils;
import io.renren.modules.dictionaries.entity.DictionariesEntity;
import org.springframework.cache.annotation.Cacheable;

import java.util.Map;

/**
 * @Author: Yin xx
 * @Description:
 * @Date: Create in 16:06 2020/4/29
 */
public interface DictionariesService extends IService<DictionariesEntity> {
     

    /**
     * 列表查询
     * @param params
     * @return
     */
    PageUtils queryPage(Map<String, Object> params);

    /**
     * 将查询出来的字段存放在缓存中
     * @param fieldName
     * @param fieldValue
     * @return
     */
    @Cacheable(value = "dictEhcache") //把数据缓存到本地
    String selectByFieldNameAndFieldValue(String fieldName,String fieldValue);

}

service实现类和Mybatis的SQL语句

    @Override
    public String selectByFieldNameAndFieldValue(String fieldName, String fieldValue) {
     
        DictionariesEntity entity = this.baseMapper.selectByFieldNameAndFieldValue(fieldName, fieldValue);
        if(entity ==null){
     
            return "无翻译词汇";
        }
        return entity.getFieldDetail();
    }

==============================分割线,以下是SQL=================================================

   <!--通过表格字段名和字段值查询该字典信息-->
    <select id="selectByFieldNameAndFieldValue" parameterType="java.lang.String"
            resultType="io.renren.modules.dictionaries.entity.DictionariesEntity">
        SELECT * FROM pz_dictionaries
        <where>
            <if test="fieldName != null and fieldName !=''">
                field_name = #{
     fieldName}
            </if>
            <if test="fieldValue != null and fieldValue !=''">
                and field_value = #{
     fieldValue}
            </if>
        </where>
    </select>

实体类


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 lombok.Data;

import java.io.Serializable;

/**
 * @Author: Yin xx
 * @Description: 数据字典表
 * @Date: Create in 16:11 2020/4/29
 */
@Data
@TableName("pz_dictionaries")
public class DictionariesEntity implements Serializable {
     

    /**
     * 字段唯一标识
     */
    @TableId(value = "id",type = IdType.UUID)
    private String id;

    /**
     * 字段名
     */
    @TableField("field_name")
    private String fieldName;

    /**
     * 字段值
     */
    @TableField("field_value")
    private String fieldValue;

    /**
     * 字段说明
     */
    @TableField("field_detail")
    private String fieldDetail;

    /**
     * 具体描述
     */
    @TableField("field_describe")
    private String fieldDescribe;
}

缓存的ehcache.xml存放在项目的位置

自定义数据字典翻译注解_第1张图片

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./config/ehcache.xsd"
         updateCheck="false">

    <!--这个是磁盘存储路径,当内存缓存满了的时候,就会往这里面放,java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样。-->
    <diskStore path="D:/ehcacheData"/>

    <!--maxElementsInMemory      内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况
                         1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中
                         2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素overflowToDisk,
                         内存不足时,是否启用磁盘缓存-->
    <!--eternal:缓存中对象是否永久有效-->
    <!--timeToIdleSeconds:缓存数据在失效前的允许闲置时间(单位:),仅当eternal=false时使用,
                          默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除-->
    <!--timeToLiveSeconds:缓存数据的总的存活时间(单位:秒),仅当eternal=false时使用,从创建开始计时,失效结束。-->
    <!--maxElementsOnDisk:磁盘缓存中最多可以存放的元素数量,0表示无穷大-->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="600"
            timeToLiveSeconds="600"
            maxElementsOnDisk="10000000"
            memoryStoreEvictionPolicy="LRU" />

    <!-- 这里的 dictEhcache 缓存空间是为了缓存字典数据做准备 -->
    <cache
            name="dictEhcache"
            eternal="false"
            maxElementsInMemory="1000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="600"
            timeToLiveSeconds="600"
            memoryStoreEvictionPolicy="LRU" />
</ehcache>

ehcache.xsd项目位置

自定义数据字典翻译注解_第2张图片

ehcache.xsd内容

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.7">
    <xs:element name="ehcache">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="1" minOccurs="0" ref="diskStore"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="sizeOfPolicy"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="transactionManagerLookup"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="cacheManagerEventListenerFactory"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="managementRESTService"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerProviderFactory"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cacheManagerPeerListenerFactory"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="terracottaConfig"/>
                <xs:element maxOccurs="1" minOccurs="0" ref="defaultCache"/>
                <xs:element maxOccurs="unbounded" minOccurs="0" ref="cache"/>
            </xs:sequence>
            <xs:attribute name="name" use="optional"/>
            <xs:attribute default="true" name="updateCheck" type="xs:boolean" use="optional"/>
            <xs:attribute default="autodetect" name="monitoring" type="monitoringType" use="optional"/>
            <xs:attribute default="true" name="dynamicConfig" type="xs:boolean" use="optional"/>
            <xs:attribute default="15" name="defaultTransactionTimeoutInSeconds" type="xs:integer" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnit" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnit" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="managementRESTService">
        <xs:complexType>
            <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
            <xs:attribute name="bind" use="optional"/>
            <xs:attribute name="securityServiceLocation" use="optional"/>
            <xs:attribute name="securityServiceTimeout" use="optional" type="xs:integer"/>
            <xs:attribute name="sslEnabled" use="optional" type="xs:boolean"/>
            <xs:attribute name="needClientAuth" use="optional" type="xs:boolean"/>
            <xs:attribute name="sampleHistorySize" use="optional" type="xs:integer"/>
            <xs:attribute name="sampleIntervalSeconds" use="optional" type="xs:integer"/>
            <xs:attribute name="sampleSearchIntervalSeconds" use="optional" type="xs:integer"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="diskStore">
        <xs:complexType>
            <xs:attribute name="path" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="transactionManagerLookup">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheManagerEventListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheManagerPeerProviderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheManagerPeerListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="terracottaConfig">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="1" minOccurs="0" name="tc-config">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:any maxOccurs="unbounded" minOccurs="0" processContents="skip"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute default="localhost:9510" name="url" use="optional"/>
            <xs:attribute name="rejoin" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="wanEnabledTSA" type="xs:boolean" use="optional" default="false"/>
        </xs:complexType>
    </xs:element>
    <!--
     add clone support for addition of cacheExceptionHandler. Important!
    -->
    <xs:element name="defaultCache">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
            </xs:sequence>
            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
            <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cache">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheDecoratorFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="pinning"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriter"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="copyStrategy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="searchable"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="elementValueComparator"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="sizeOfPolicy"/>
                <xs:element minOccurs="0" maxOccurs="1" ref="persistence"/>
            </xs:sequence>
            <xs:attribute name="diskExpiryThreadIntervalSeconds" type="xs:integer" use="optional"/>
            <xs:attribute name="diskSpoolBufferSizeMB" type="xs:integer" use="optional"/>
            <xs:attribute name="diskPersistent" type="xs:boolean" use="optional"/>
            <xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
            <xs:attribute name="eternal" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxElementsInMemory" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxEntriesLocalHeap" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="memoryStoreEvictionPolicy" type="xs:string" use="optional"/>
            <xs:attribute name="clearOnFlush" type="xs:boolean" use="optional"/>
            <xs:attribute name="name" type="xs:string" use="required"/>
            <xs:attribute name="overflowToDisk" type="xs:boolean" use="optional"/>
            <xs:attribute name="timeToIdleSeconds" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="timeToLiveSeconds" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxElementsOnDisk" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxEntriesLocalDisk" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="maxEntriesInCache" type="xs:nonNegativeInteger" use="optional"/>
            <xs:attribute name="transactionalMode" type="transactionalMode" use="optional" default="off"/>
            <xs:attribute name="statistics" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnRead" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="copyOnWrite" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="logging" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="cacheLoaderTimeoutMillis" type="xs:integer" use="optional" default="0"/>
            <xs:attribute name="overflowToOffHeap" type="xs:boolean" use="optional" default="false"/>
            <xs:attribute name="maxMemoryOffHeap" type="xs:string" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalOffHeap" type="memoryUnitOrPercentage" use="optional"/>
            <xs:attribute default="0" name="maxBytesLocalDisk" type="memoryUnitOrPercentage" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheEventListenerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
            <xs:attribute name="listenFor" use="optional" type="notificationScope" default="all"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="bootstrapCacheLoaderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheExtensionFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheExceptionHandlerFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheLoaderFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="cacheDecoratorFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="searchAttribute">
        <xs:complexType>
            <xs:attribute name="name" use="required" type="xs:string"/>
            <xs:attribute name="expression" type="xs:string"/>
            <xs:attribute name="class" type="xs:string"/>
            <xs:attribute name="type" type="xs:string" use="optional"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="searchable">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
            </xs:sequence>
            <xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="allowDynamicIndexing" use="optional" type="xs:boolean" default="false"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="pinning">
        <xs:complexType>
            <xs:attribute name="store" use="required" type="pinningStoreType"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="terracotta">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" ref="nonstop"/>
            </xs:sequence>
            <xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="300000"/>
            <xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
            <xs:attribute name="copyOnRead" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="coherent" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="consistency" use="optional" type="consistencyType" default="eventual"/>
            <xs:attribute name="synchronousWrites" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="concurrency" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="localCacheEnabled" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="compressionEnabled" use="optional" type="xs:boolean" default="false"/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="consistencyType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="strong"/>
            <xs:enumeration value="eventual"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="nonstop">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" ref="timeoutBehavior"/>
            </xs:sequence>
            <xs:attribute name="enabled" use="optional" type="xs:boolean" default="true"/>
            <xs:attribute name="immediateTimeout" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="timeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
            <xs:attribute name="searchTimeoutMillis" use="optional" type="xs:positiveInteger" default="30000"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="timeoutBehavior">
        <xs:complexType>
            <xs:attribute name="type" use="optional" type="timeoutBehaviorType" default="exception"/>
            <xs:attribute name="properties" use="optional" default=""/>
            <xs:attribute name="propertySeparator" use="optional" default=","/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="timeoutBehaviorType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="noop"/>
            <xs:enumeration value="exception"/>
            <xs:enumeration value="localReads"/>
            <xs:enumeration value="localReadsAndExceptionOnWrite"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="monitoringType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="autodetect"/>
            <xs:enumeration value="on"/>
            <xs:enumeration value="off"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="pinningStoreType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="localMemory"/>
            <xs:enumeration value="inCache"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="terracottaCacheValueType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="serialization"/>
            <xs:enumeration value="identity"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="transactionalMode">
        <xs:restriction base="xs:string">
            <xs:enumeration value="off"/>
            <xs:enumeration value="xa_strict"/>
            <xs:enumeration value="xa"/>
            <xs:enumeration value="local"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="cacheWriter">
        <xs:complexType>
            <xs:sequence>
                <xs:element minOccurs="0" maxOccurs="1" ref="cacheWriterFactory"/>
            </xs:sequence>
            <xs:attribute name="writeMode" use="optional" type="writeModeType" default="write-through"/>
            <xs:attribute name="notifyListenersOnException" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="minWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="maxWriteDelay" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="rateLimitPerSecond" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="writeCoalescing" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="writeBatching" use="optional" type="xs:boolean" default="false"/>
            <xs:attribute name="writeBatchSize" use="optional" type="xs:positiveInteger" default="1"/>
            <xs:attribute name="retryAttempts" use="optional" type="xs:nonNegativeInteger" default="0"/>
            <xs:attribute name="retryAttemptDelaySeconds" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="writeBehindConcurrency" use="optional" type="xs:nonNegativeInteger" default="1"/>
            <xs:attribute name="writeBehindMaxQueueSize" use="optional" type="xs:nonNegativeInteger" default="0"/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="writeModeType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="write-through"/>
            <xs:enumeration value="write-behind"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:element name="cacheWriterFactory">
        <xs:complexType>
            <xs:attribute name="class" use="required"/>
            <xs:attribute name="properties" use="optional"/>
            <xs:attribute name="propertySeparator" use="optional"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="copyStrategy">
        <xs:complexType>
            <xs:attribute name="class" use="required" type="xs:string"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="elementValueComparator">
        <xs:complexType>
            <xs:attribute name="class" use="required" type="xs:string"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="sizeOfPolicy">
        <xs:complexType>
            <xs:attribute name="maxDepth" use="required" type="xs:integer"/>
            <xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue"
                          type="maxDepthExceededBehavior"/>
        </xs:complexType>
    </xs:element>
    <xs:element name="persistence">
        <xs:complexType>
            <xs:attribute name="strategy" use="required" type="persistenceStrategy"/>
            <xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/>
        </xs:complexType>
    </xs:element>
    <xs:simpleType name="persistenceStrategy">
        <xs:restriction base="xs:string">
            <xs:enumeration value="localTempSwap"/>
            <xs:enumeration value="localRestartable"/>
            <xs:enumeration value="none"/>
            <xs:enumeration value="distributed"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="maxDepthExceededBehavior">
        <xs:restriction base="xs:string">
            <xs:enumeration value="continue"/>
            <xs:enumeration value="abort"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="notificationScope">
        <xs:restriction base="xs:string">
            <xs:enumeration value="local"/>
            <xs:enumeration value="remote"/>
            <xs:enumeration value="all"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="memoryUnit">
        <xs:restriction base="xs:token">
            <xs:pattern value="[0-9]+[bBkKmMgG]?"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="memoryUnitOrPercentage">
        <xs:restriction base="xs:token">
            <xs:pattern value="([0-9]+[bBkKmMgG]?|100%|[0-9]{1,2}%)"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

每次新增或修改数据字典时候清空当前缓存

/**
     * 保存
     * @param entity
     * @return
     */
    @RequestMapping("/save")
    @RequiresPermissions("dictionaries:list")
    @CacheEvict(value="dictEhcache", allEntries=true) //清空缓存
    public R save(@RequestBody DictionariesEntity entity) {
     
        String errMassage = "保存失败";
        if(entity != null){
     
            Map<String,Object> parMap = new HashMap<>();
            parMap.put("field_name",entity.getFieldName());
            parMap.put("field_value",entity.getFieldValue());
            Collection<DictionariesEntity> collections = service.listByMap(parMap);
            if(collections.size()==0){
     
                boolean b = service.save(entity);
                if (b) {
     
                    return R.ok();
                }
            }else {
     
                errMassage="该表'字段名'和'字段码值'已存在";
            }
        }
        return R.error().put("msg",errMassage);
    }

数据表

pz_dictionaries表字段:

字段名 类型 备注
id varchar uuid,唯一标识
field_name varchar 对应表格字段名
field_value varchar 字段值
field_detail varchar 字段说明
field_describe varchar 具体描述

表格图片:

自定义数据字典翻译注解_第3张图片

表格数据样例

自定义数据字典翻译注解_第4张图片

使用样例



 /**
     * 子任务状态
     */
    @TableField("subtask_status")
    @Dict(dictDataSource = "subtask_status")//需要翻译的实体类字段加上注解
    private String subtaskStatus;


==============================前端样例======================================

<el-table-column
          prop="subtaskStatus_dictText" //在字段后加上_dictText
          header-align="center"
          align="center"
          label="子任务状态">
        </el-table-column>

你可能感兴趣的:(java,spring)