11 changed files with 313 additions and 9 deletions
			
			
		@ -0,0 +1,48 @@
					 | 
				
			||||
package com.mh.user.annotation; | 
				
			||||
 | 
				
			||||
import java.lang.annotation.*; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @author LJF | 
				
			||||
 * @version 1.0 | 
				
			||||
 * @project mh_esi | 
				
			||||
 * @description 数据字典注解 | 
				
			||||
 * @date 2024-11-08 11:40:46 | 
				
			||||
 */ | 
				
			||||
@Target(ElementType.FIELD) | 
				
			||||
@Inherited | 
				
			||||
@Retention(RetentionPolicy.RUNTIME) | 
				
			||||
@Documented | 
				
			||||
public @interface FieldParam { | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 字典值 | 
				
			||||
     * @return | 
				
			||||
     */ | 
				
			||||
    String value() default ""; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 字典类型 | 
				
			||||
     * @return | 
				
			||||
     */ | 
				
			||||
    String type() default ""; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 字典标签 | 
				
			||||
     * @return | 
				
			||||
     */ | 
				
			||||
    String label() default ""; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 要翻译的字段,目标字段翻译的字段+Str | 
				
			||||
     * @return | 
				
			||||
     */ | 
				
			||||
    String targetField() default ""; | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 要翻译的字段值类型 | 
				
			||||
     * @return | 
				
			||||
     */ | 
				
			||||
    Class targetFieldValueClazz() default String.class; | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,17 @@
					 | 
				
			||||
package com.mh.user.annotation; | 
				
			||||
 | 
				
			||||
import java.lang.annotation.*; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @author LJF | 
				
			||||
 * @version 1.0 | 
				
			||||
 * @project mh_esi | 
				
			||||
 * @description 需要翻译的字典值 | 
				
			||||
 * @date 2024-11-08 14:29:39 | 
				
			||||
 */ | 
				
			||||
@Retention(RetentionPolicy.RUNTIME) | 
				
			||||
@Target(ElementType.METHOD) | 
				
			||||
@Documented | 
				
			||||
public @interface TranslationDict { | 
				
			||||
    FieldParam[] value(); | 
				
			||||
} | 
				
			||||
@ -0,0 +1,136 @@
					 | 
				
			||||
package com.mh.user.aspect; | 
				
			||||
 | 
				
			||||
import com.alibaba.fastjson2.JSONObject; | 
				
			||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils; | 
				
			||||
import com.mh.user.annotation.FieldParam; | 
				
			||||
import com.mh.user.annotation.TranslationDict; | 
				
			||||
import com.mh.user.model.SysDict; | 
				
			||||
import com.mh.user.service.SysDictService; | 
				
			||||
import lombok.extern.slf4j.Slf4j; | 
				
			||||
import org.aspectj.lang.ProceedingJoinPoint; | 
				
			||||
import org.aspectj.lang.annotation.Around; | 
				
			||||
import org.aspectj.lang.annotation.Aspect; | 
				
			||||
import org.aspectj.lang.reflect.MethodSignature; | 
				
			||||
import org.springframework.beans.factory.annotation.Autowired; | 
				
			||||
import org.springframework.stereotype.Component; | 
				
			||||
 | 
				
			||||
import java.lang.reflect.Method; | 
				
			||||
import java.util.List; | 
				
			||||
import java.util.Map; | 
				
			||||
import java.util.Optional; | 
				
			||||
import java.util.regex.Matcher; | 
				
			||||
import java.util.regex.Pattern; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @author LJF | 
				
			||||
 * @version 1.0 | 
				
			||||
 * @project mh_esi | 
				
			||||
 * @description 数据字典转换 | 
				
			||||
 * @date 2024-11-08 14:08:20 | 
				
			||||
 */ | 
				
			||||
@Aspect | 
				
			||||
@Component | 
				
			||||
@Slf4j | 
				
			||||
public class DictDataTranslateAsp { | 
				
			||||
 | 
				
			||||
    @Autowired | 
				
			||||
    private SysDictService sysDictService; | 
				
			||||
 | 
				
			||||
    @Around("@annotation(com.mh.user.annotation.TranslationDict)") | 
				
			||||
    public Object aroundMethodTranslate(ProceedingJoinPoint joinPoint) throws Throwable { | 
				
			||||
        // 接收到请求时间
 | 
				
			||||
        Long startTime = System.currentTimeMillis(); | 
				
			||||
        // 注意,如果调用joinPoint.proceed()方法,则修改的参数值不会生效,必须调用joinPoint.proceed(args)
 | 
				
			||||
        Object result = joinPoint.proceed(); | 
				
			||||
 | 
				
			||||
        // 获取返回值类型
 | 
				
			||||
        Class<?> returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType(); | 
				
			||||
 | 
				
			||||
        // 取出要翻译的字典值
 | 
				
			||||
        String returnJsonResult = JSONObject.toJSONString(result); | 
				
			||||
 | 
				
			||||
        // 开始解析
 | 
				
			||||
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); | 
				
			||||
 | 
				
			||||
        // 获取注解上参数
 | 
				
			||||
        TranslationDict annotation = method.getAnnotation(TranslationDict.class); | 
				
			||||
        FieldParam[] fieldParams = annotation.value(); | 
				
			||||
 | 
				
			||||
        // 遍历
 | 
				
			||||
        for (FieldParam fieldParam : fieldParams) { | 
				
			||||
            log.info("字典类型:{},取值字段:{}", fieldParam.type(), fieldParam.targetField()); | 
				
			||||
            Pattern dictPattern = getPattern(fieldParam); | 
				
			||||
            Matcher matcher = dictPattern.matcher(returnJsonResult); | 
				
			||||
            StringBuffer sb = new StringBuffer(); | 
				
			||||
            // 转义字段
 | 
				
			||||
            this.translateDict(fieldParam, dictPattern, matcher, sb); | 
				
			||||
            matcher.appendTail(sb); | 
				
			||||
            returnJsonResult = sb.toString(); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        result = JSONObject.parseObject(returnJsonResult, returnType); | 
				
			||||
        // 如果这里不返回result,则目标对象实际返回值会被置为null
 | 
				
			||||
        // 处理完成时间
 | 
				
			||||
        Long endTime = System.currentTimeMillis(); | 
				
			||||
        log.info("数据字典转换耗时:{}ms", endTime - startTime); | 
				
			||||
        return result; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * 字典值转义为中文 | 
				
			||||
     * | 
				
			||||
     * @param fieldParam | 
				
			||||
     * @param fieldPattern | 
				
			||||
     * @param fieldMatcher | 
				
			||||
     * @param sb | 
				
			||||
     */ | 
				
			||||
    private void translateDict(FieldParam fieldParam, Pattern fieldPattern, Matcher fieldMatcher, StringBuffer sb) { | 
				
			||||
        //从缓存中一次性取值
 | 
				
			||||
        List<SysDict> dictNames = sysDictService.findByType(fieldParam.type()); | 
				
			||||
        while (fieldMatcher.find()) { | 
				
			||||
            //取出要翻译字段对应的值
 | 
				
			||||
            Matcher dictValueMatcher = fieldPattern.matcher(fieldMatcher.group()); | 
				
			||||
            dictValueMatcher.find(); | 
				
			||||
            String group = dictValueMatcher.group(); | 
				
			||||
            //""sex":1", ""sex":"1"",""sex":null"
 | 
				
			||||
            //属性无值
 | 
				
			||||
            if (group.split(":").length <= 1) continue; | 
				
			||||
            String dictName = ""; | 
				
			||||
            //获取字典值
 | 
				
			||||
            String dictValue = group.split(":")[1].replace("\"", ""); | 
				
			||||
            //属性值非为空 为空赋值空串
 | 
				
			||||
            if (StringUtils.isNotBlank(dictValue) && !dictValue.equalsIgnoreCase("null")) { | 
				
			||||
                //多值
 | 
				
			||||
                if (dictValue.split(",").length > 1) { | 
				
			||||
                    for (String s : dictValue.split(",")) { | 
				
			||||
                        //fieldParam.dictType() + "_" + s 根据自己字典表设置的规则去查询
 | 
				
			||||
                        String type = s; | 
				
			||||
                        Optional<SysDict> first = dictNames.stream().filter(d -> d.getValue().equals(type)).findFirst(); | 
				
			||||
                        if (!first.isPresent()) continue; | 
				
			||||
                        dictName += first.get().getLabel() + "/"; | 
				
			||||
                    } | 
				
			||||
                } else { | 
				
			||||
                    String type = dictValue; | 
				
			||||
                    Optional<SysDict> first = dictNames.stream().filter(d -> d.getValue().equals(type)).findFirst(); | 
				
			||||
                    if (!first.isPresent()) continue; | 
				
			||||
                    dictName = first.get().getLabel(); | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            String s = "\"" + fieldParam.targetField() + "Str" + "\":\"" + dictName + "\"," + fieldMatcher.group(); | 
				
			||||
            log.info("拼接后字符串:{}", s); | 
				
			||||
            fieldMatcher.appendReplacement(sb, s); | 
				
			||||
 | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private Pattern getPattern(FieldParam fieldParam) { | 
				
			||||
        Pattern fieldPattern;//属性整型 字符型
 | 
				
			||||
        if (fieldParam.targetFieldValueClazz().equals(Integer.class)) { | 
				
			||||
            fieldPattern = Pattern.compile("\"" + fieldParam.targetField() + "\":(\\d+)?"); | 
				
			||||
        } else { | 
				
			||||
            fieldPattern = Pattern.compile("\"" + fieldParam.targetField() + "\":\"([0-9a-zA-Z_,]+)?\""); | 
				
			||||
        } | 
				
			||||
        return fieldPattern; | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,62 @@
					 | 
				
			||||
package com.mh.user.config; | 
				
			||||
 | 
				
			||||
import com.github.benmanes.caffeine.cache.*; | 
				
			||||
import lombok.extern.slf4j.Slf4j; | 
				
			||||
import org.springframework.context.annotation.Bean; | 
				
			||||
import org.springframework.context.annotation.Configuration; | 
				
			||||
 | 
				
			||||
import java.util.concurrent.TimeUnit; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @author LJF | 
				
			||||
 * @title : | 
				
			||||
 * @description 使用caffeine缓存技术 | 
				
			||||
 * @updateTime 2020-12-15 | 
				
			||||
 * @throws : | 
				
			||||
 */ | 
				
			||||
@Slf4j | 
				
			||||
@Configuration | 
				
			||||
public class CaffeineCacheConfig { | 
				
			||||
 | 
				
			||||
    //        软引用: 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。
 | 
				
			||||
    //        弱引用: 弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,
 | 
				
			||||
    //                不管当前内存空间足够与否,都会回收它的内存
 | 
				
			||||
    @Bean(name = "caffeineCache") | 
				
			||||
    public Cache<String, Object> caffeineCache() { | 
				
			||||
        return Caffeine.newBuilder() | 
				
			||||
                // 软引用
 | 
				
			||||
                .softValues() | 
				
			||||
                // 弱引用
 | 
				
			||||
//                .weakValues()
 | 
				
			||||
                // 设置最后一次写入或访问后经过固定时间过期
 | 
				
			||||
                .expireAfterWrite(8*60*60, TimeUnit.SECONDS) | 
				
			||||
                // 初始的缓存空间大小
 | 
				
			||||
                .initialCapacity(100) | 
				
			||||
                // 缓存的最大条数
 | 
				
			||||
                .maximumSize(1000) | 
				
			||||
                .build(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    //定义缓存,可直接使用
 | 
				
			||||
    @Bean | 
				
			||||
    public LoadingCache expiryCache(){ | 
				
			||||
        LoadingCache<String, Object> loadingCache = Caffeine.newBuilder() | 
				
			||||
                .initialCapacity(100) | 
				
			||||
                .maximumSize(1000) | 
				
			||||
                //缓存写入/删除监控
 | 
				
			||||
                .writer(new CacheWriter<Object, Object>() { | 
				
			||||
                    @Override | 
				
			||||
                    public void write(Object key, Object value) { //此方法是同步阻塞的
 | 
				
			||||
                        log.info("--缓存写入--:key={}, value={}", key, value); | 
				
			||||
                    } | 
				
			||||
                    @Override | 
				
			||||
                    public void delete(Object key, Object value, RemovalCause cause) { | 
				
			||||
                        log.info("--缓存删除--:key={}", key); } | 
				
			||||
                }) | 
				
			||||
                .expireAfterAccess(6, TimeUnit.HOURS) //过期时间
 | 
				
			||||
                .build((String key)->"刷新的数据"); //cacheload实现类,刷新时候调用
 | 
				
			||||
//        loadingCache.put("name","侯征");
 | 
				
			||||
        return loadingCache; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue