Java如何利用Spring的切面,实现数据表的字典翻译

字典是什么

  1. 案例分析

    • 如下图:有一个User实体类,他的sex和position_id是需要翻译的属性;
    • sex为0,表示该用户为“男”,sex为1,表示该用户为”女“;position为1表示该用户职位为总裁,2表示为主管;这些字段的”0,1,2"等值会被翻译成我们可以理解的值”总裁“,”主管“等值
      在这里插入图片描述
  • 所以我们如何实现这一功能的呢:建立一种对应关系,这种关系建立需要以下信息

    • 类的属性(哪个字段需要翻译:sex)
    • dict_Table(去哪张表找翻译数据:sys_dict_item)
    • dict_value(什么字段找key值的对应:dict_value)
    • dictText(翻译后的数据是哪一列:dict_text)

    在这里插入图片描述

Java实现

1. 实现的技术说明

  • redis:如果用户请求太过频繁,数据字典查询会对数据库造成压力,所以需要缓存到redis,查询的性能更强
  • mysql:数据存储到sql数据库中
  • SpringBoot+mybatis_plus(mybatis也可以)

2.首先定义注解@Dict

package com.happy_retail_management.common.aspect.annotation;

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

/**
 * @Dict(dictTable = "sys_user", dicText = "realname", dicCode = "id")
 * 或者dicCode=“sex”
 */
@Target(ElementType.FIELD)//修饰属性
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
    /**
     * 数据code
     * @return String
     */
    String dicCode();
    /**
     * 数据Text
     */
    String dicText() default "";
    /**
     * 数据字典
     */
    String dicTable() default "";
}

3. 定义DictModel实体类->用与保存字典

package com.happy_retail_management.system.vo;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * 字典类
 */
@Data
@EqualsAndHashCode(callSuper =false)
@Accessors(chain = true)//运行链式调用
@JsonIgnoreProperties(ignoreUnknown=true)
public class DictModel {
    private static final long serialVersionUID=1L;
    /**
     * 字典value
     */
    private String value;
    /**
     * 字典文本
     */
    private String text;
    public DictModel(){
    }
    public DictModel(String value,String text){
        this.value = value;
        this.text = text;
    }
}

4. 数据库定义sys_dict_item表

  • 表单样式:
    在这里插入图片描述

  • 建表语句

    
    SET NAMES utf8mb4;
    SET FOREIGN_KEY_CHECKS = 0;
    
    -- ----------------------------
    -- Table structure for sys_dict_item
    -- ----------------------------
    DROP TABLE IF EXISTS `sys_dict_item`;
    CREATE TABLE `sys_dict_item`  (
      `id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键',
      `dict_code` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '字典名',
      `item_text` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '字典显示字段',
      `item_value` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '字典查询字段',
      `item_description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
      PRIMARY KEY (`id`) USING BTREE
    ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    
    SET FOREIGN_KEY_CHECKS = 1; 
    

5. 定义实体类->以Product为例

  • 使用上面的@Dict注解,在注解上提供信息,有以下两种注解

    • @Dict(dictCode="sex")表示去system_dict_item表中查寻dictCode=sex,dictValue=?(需要查询的属性值)数据项,并翻译为dict_text数据
    • @Dict(dicTable="vendor",dicCode = "vendor_id" ,dicText = "vendor_name")表示去vender表查询vendor_id=?(该属性值)数据项,并且翻译为vendor_name的内容
    package com.happy_retail_management.demo.product.entity;
    
    import com.baomidou.mybatisplus.annotation.FieldFill;
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.happy_retail_management.common.aspect.annotation.Dict;
    import lombok.Data;
    import org.apache.ibatis.annotations.Result;
    import java.io.Serializable;
    import java.util.Date;
    @Data
    public class Product {
        @TableId(type = IdType.AUTO)
        private String productId;
        private String productName;
        @TableField("product_UPC")
        private String productUPC;
        private Double productPrice;
        private String productInventory;
        private String productUnits;
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date productDate;
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private Date expirationDate;
        private Double restockPrice;
        @Dict(dicTable="store",dicCode = "store_id" ,dicText = "store_name")
        private String storeId;
        @Dict(dicTable = "product_type",dicCode = "product_type_id",dicText = "product_type_name")
        private Integer productTypeId;
        @Dict(dicTable="brand",dicCode = "brand_id" ,dicText = "brand_name")
        private String brandId;
        @Dict(dicTable="vendor",dicCode = "vendor_id" ,dicText = "vendor_name")
        private String vendorId;
    }
    
    

6. 定义字典的切面

package com.happy_retail_management.common.aspect;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.happy_retail_management.common.api.vo.Result;
import com.happy_retail_management.common.aspect.annotation.Dict;
import com.happy_retail_management.common.utils.oConvertUtils;
import com.happy_retail_management.modules.system.service.ISysDictService;
import com.happy_retail_management.system.vo.DictModel;
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.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Aspect
@Slf4j
@Component
public class AutoDict {
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ISysDictService iSysDictService;
    /**
     * 定义切点
     */
    @Pointcut(value = "execution(public * com.happy_retail_management..*.*Controller.*(..))||@annotation(com.happy_retail_management.common.aspect.annotation.AutoDict)")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long time1=System.currentTimeMillis();
        Object proceed = pjp.proceed();
        long time2=System.currentTimeMillis();
        log.debug("获取Result结果耗费时间:"+(time2-time1)+"ms");
        long time3=System.currentTimeMillis();
        Object result = parseDictText(proceed);
        long time4=System.currentTimeMillis();
        log.debug("处理Result添加字典耗费时间:"+(time4-time3)+"ms");
        return result;
    }

    /**
     * 有两种字典,一种字典为
     * 字典注入实现 通过对实体类添加注解@dict 来标识需要的字典内容,字典分为单字典code即可 ,table字典 code table text配合使用
     * 示例为SysUser   字段为sex 添加了注解@Dict(dicCode = "sex") 会在字典服务立马查出来对应的text 然后在请求list的时候将这个字典text,已字段名称加_dictText形式返回到前端
     * 例输入当前返回值的就会多出一个sex_dictText字段
     * {
     *      sex:1,
     *      sex_dictText:"男"
     * }
     * @Dict(dictTable = "sys_user", dicText = "realname", dicCode = "id")
     * 如果是查询表单
     * @param result
     * @return
     */
    private Object parseDictText(Object result) {
        if(result instanceof Result){
            if(((Result) result).getData() instanceof IPage){
                List<JSONObject> items = new ArrayList<>();
                //1.筛选出嫁了Dict的字段列表
                List<Field> dictFieldList = new ArrayList<>();
                //数据字典列表,key=字典code,value=数据列表
                Map<String,List<String>> dataListMap = new HashMap<>(5);
                //取出结果集
                List<Object> records=((IPage)((Result) result).getData()).getRecords();
                //检查是否有字典字段
                Boolean hasDict = checkHasDict(records);
                if(!hasDict){
                    return result;
                }

                //进入字典翻译切面
                for(Object record:records){
                    String json="{}";
                    try{
                       json =  objectMapper.writeValueAsString(record);
                    }catch (Exception e){
                        log.error("json解析失败:"+e.getMessage());
                    }
                    //这里将record->json->JsonObject主要因为有可能类中@JsonFormat问题
                    JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
                    //遍历所有字段,把字典code取出来,放入Map中
                    for(Field field:oConvertUtils.getAllFields(record)){
                        //取出item对应的field值
                        String value = item.getString(field.getName());
                        if(oConvertUtils.isEmpty(value)){
                            continue;
                        }
                        if(field.getAnnotation(Dict.class)!=null){
                            if(!dictFieldList.contains(field)){
                                dictFieldList.add(field);
                            }
                            String code = field.getAnnotation(Dict.class).dicCode();
                            String text = field.getAnnotation(Dict.class).dicText();
                            String table = field.getAnnotation(Dict.class).dicTable();
                            List<String> dataList;
                            String dictCode = code;
                            if(!(table==null||"".equals(table))){//非空
                                //处理成为表名,表value,表key形式
                                dictCode = String.format("%s,%s,%s",table,text,code);
                            }
                            dataList = dataListMap.computeIfAbsent(dictCode,k->new ArrayList<>());
                            //list的去重添加
                            this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
                        }
                    }
                    items.add(item);
                }
                //step2 调用翻译方法,一次性翻译
                Map<String,List<DictModel>> translText = this.tranalateAllDict(dataListMap);
                //step3 将翻译结果填充刀返回的结果中
                for(JSONObject record:items){
                    for(Field field:dictFieldList){
                        String code = field.getAnnotation(Dict.class).dicCode();
                        String text = field.getAnnotation(Dict.class).dicText();
                        String table = field.getAnnotation(Dict.class).dicTable();
                        String fieldDictCode = code;
                        if(!StringUtils.isEmpty(table)){
                            fieldDictCode=String.format("%s,%s,%s",table,text,code);
                        }
                        String value=record.getString(field.getName());
                        if(oConvertUtils.isNotEmpty(value)){
                            List<DictModel> dictModels = translText.get(fieldDictCode);
                            if(dictModels==null||dictModels.size()==0){
                                continue;
                            }
                            String textVale=this.translDictText(dictModels,value);
                            record.put(field.getName()+ "_dictText",textVale);
                        }

                    }
                }
                ((IPage) ((Result) result).getData()).setRecords(items);
//                return result;
            }
        }
        return result;
    }
    /**
     * list去重复添加
     */
    private void listAddAllDeduplicate(List<String> dataList, List<String> addList) {
        // 筛选出dataList中没有的数据
        List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());
        dataList.addAll(filterList);
    }
    /**
     * 一次性将所有的字典都翻译了
     * 1.所有的普通数据字典的所有数据只执行一次SQL
     * 2.表字典相同的所有数据只执行一次SQL
     */
    private Map<String,List<DictModel>> tranalateAllDict(Map<String, List<String>> dataListMap){
        Map<String,List<DictModel>> translText = new HashMap<>();
        //需要翻译的数据,有写可以从redis缓存中获取,就不走Sql查询
        List<String> needTranslData = new ArrayList<>();
        //step1,先通过redis中获取缓存字典数据
        for(String dictCode:dataListMap.keySet()){
            List<String> dataList = dataListMap.get(dictCode);
            if(dataList.size()==0){
                break;
            }
            //表字典需要翻译的数据
            List<String> needTranslDataTable = new ArrayList<>();
            for(String s:dataList){
                String data = s.trim();
                if(data.length() == 0){
                    continue;
                }
                if(dictCode.contains(",")){
                    String keyString = String.format("reatil:cache:dictTable::SimpleKey [%s,%s]",dictCode,data);
                    if(redisTemplate.hasKey(keyString)){
                        try{
                            String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
                            List<DictModel> list = translText.computeIfAbsent(dictCode,k->new ArrayList<>());
                            list.add(new DictModel(data,text));
                        }catch(Exception e){
                            log.warn(e.getMessage());
                        }
                    } else if (!needTranslDataTable.contains(data)) {
                        //去重添加
                        needTranslDataTable.add(data);
                    }
                }else {
                    String keyString = String.format("reatil:cache:dict::%s,%s",dictCode,data);
                    if (redisTemplate.hasKey(keyString)) {
                        try {
                            String text = oConvertUtils.getString(redisTemplate.opsForValue().get(keyString));
                            List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
                            list.add(new DictModel(data, text));
                        } catch (Exception e) {
                            log.warn(e.getMessage());
                        }
                    } else if (!needTranslData.contains(data)) {
                        // 去重添加
                        needTranslData.add(data);
                    }

                }
            }
            //step2 调用数据库的翻译表字典
            if(needTranslDataTable.size()>0){
                String[] arr = dictCode.split(",");
                String table=arr[0],text=arr[1],code=arr[2];
//                    String values=String.join(",",needTranslDataTable);
                //将其翻译成List集合
                List<DictModel> texts = iSysDictService.translateDictFromTableByKeys(table,text,code,needTranslDataTable);
                List<DictModel> list=translText.computeIfAbsent(dictCode,k->new ArrayList<>());
                list.addAll(texts);
                //做redis缓存
                for(DictModel dict:texts){
                    String redisKey = String.format("reatil:cache:dictTable::SimpleKey [%s,%s]",dictCode,dict.getValue());
                    try{
                        //保留5分钟
                        redisTemplate.opsForValue().set(redisKey,dict.getText(),300, TimeUnit.SECONDS);

                    }catch(Exception e){
                        log.warn(e.getMessage(), e);
                    }
                }
            }

        }
        //step3 调用数据库进行普通字典
        if(needTranslData.size()>0){
            List<String> dictCodeList=Arrays.asList((dataListMap.keySet().toArray(new String[]{})));
            // 将不包含逗号的字典code筛选出来,因为带逗号的是表字典,而不是普通的数据字典,其实已经做了区分的了
            List<String> filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList());
//            String dictCodes = String.join(",", filterDictCodes);
//            String values = String.join(",", needTranslData);

            Map<String,List<DictModel>> manyDict = iSysDictService.queryManyDictByKeys(filterDictCodes, needTranslData);
            for(String dictCode: manyDict.keySet()){
                List<DictModel> list = translText.computeIfAbsent(dictCode,k->new ArrayList<>());
                List<DictModel> newList = manyDict.get(dictCode);
                list.addAll(newList);
                //做redis缓存
                for(DictModel dict:newList){
                    String redisKey = String.format("reatil:cache:dict::%s,%s",dictCode,dict.getValue());
                    try{
                        redisTemplate.opsForValue().set(redisKey,dict.getText());
                    }catch(Exception e){
                        log.warn(e.getMessage(),e);
                    }
                }

            }
        }
        return translText;
    }

    /**
     * 字典值替换文本
     *
     * @param dictModels
     * @param values
     * @return
     */
    private String translDictText(List<DictModel> dictModels, String values) {
        List<String> result = new ArrayList<>();

        // 允许多个逗号分隔,允许传数组对象
        String[] splitVal = values.split(",");
        for (String val : splitVal) {
            String dictText = val;
            for (DictModel dict : dictModels) {
                if (val.equals(dict.getValue())) {
                    dictText = dict.getText();
                    break;
                }
            }
            result.add(dictText);
        }
        return String.join(",", result);
    }

    /**
     * 检查返回结果集中是否包含Dict注解
     */
    private boolean checkHasDict(List<Object> records){
        if(oConvertUtils.isNotEmpty(records)&&records.size()>0){//数据非空
            for(Field field:oConvertUtils.getAllFields(records.get(0))) {
                if (oConvertUtils.isNotEmpty(field.getAnnotation(Dict.class))) {
                    return true;
                }
            }
        }
        return false;
    }
}

  • 补充oConvertUtils的工具类的内容

       /**
         * 获取类的所有属性,包括父类
         *
         * @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);
        }
    
    	public static boolean isNotEmpty(Object object) {
            if (object != null && !"".equals(object) && !object.equals("null")) {
                return (true);
            }
            return (false);
        }
    	/**
    	* 处理空值和两边的空格
    	*/
    	public static String getString(Object object) {
            if (isEmpty(object)) {
                return "";
            }
            return (object.toString().trim());
        }
    

7. 定义数据库查询的包

定义ISysDictService和ISysDictMapper以及对应的实现类,用于访问数据库;主要实现

  • ISysDictService接口

    package com.happy_retail_management.modules.system.service;
    
    import com.happy_retail_management.system.vo.DictModel;
    
    import java.util.List;
    import java.util.Map;
    
    public interface ISysDictService {
        public List<DictModel> translateDictFromTableByKeys(String table, String text, String code, List<String> keys);
        public Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys);
    }
    
    
  • ISysDictServiceImpl

    package com.happy_retail_management.modules.system.service.impl;
    
    import com.happy_retail_management.modules.system.mapper.SysDictMapper;
    import com.happy_retail_management.modules.system.service.ISysDictService;
    import com.happy_retail_management.system.vo.DictModel;
    import com.happy_retail_management.system.vo.DictModelMany;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @Service
    public class ISysDictServiceImpl implements ISysDictService {
        @Autowired
        private SysDictMapper sysDictMapper;
    
        /**
         * 查询外间
         * @param table 表名
         * @param text  显示字段名
         * @param code 存储字段名
         * @param keys 存储字段值 作为查询条件in
         * @return
         */
        @Override
        public List<DictModel> translateDictFromTableByKeys(String table, String text, String code, List<String> keys) {
            String filterSql="";
            //这里不做注入检查
            return sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, keys);
        }
        public Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> keys){
            List<DictModelMany> list = sysDictMapper.queryManyDictByKeys(dictCodeList, keys);
            Map<String, List<DictModel>> dictMap = new HashMap(5);
            for(DictModelMany dict:list){
                List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(),i->new ArrayList<>());
                dictItemList.add(new DictModel(dict.getValue(),dict.getText()));
            }
            //需不需要引入Jave枚举类的字典呢?
            return dictMap;
        }
    }
    
    
  • SysDictMapper

    package com.happy_retail_management.modules.system.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.happy_retail_management.modules.system.entity.SysDict;
    import com.happy_retail_management.system.vo.DictModel;
    import com.happy_retail_management.system.vo.DictModelMany;
    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    @Mapper
    public interface SysDictMapper extends BaseMapper<SysDict> {
        /**
         * 可通过多个字典code查询翻译文本
         * @param dictCodeList 多个字典code
         * @param keys 数据列表
         * @return
         */
        List<DictModelMany> queryManyDictByKeys(@Param("dictCodeList") List<String> dictCodeList,
                                                @Param("keys") List<String> keys);
        /**
         * 查询字典表的数据
         * @param table 表名
         * @param text   显示字段名
         * @param code   存储字段名
         * @param filterSql 条件sql
         * @param codeValues 存储字段值 作为查询条件in
         * @return
         */
        List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text,
                                                         @Param("code") String code,
                                                         @Param("filterSql") String filterSql,
                                                         @Param("codeValues") List<String> codeValues);
    
    }
    
    
  • SysDictMapper,xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.happy_retail_management.modules.system.mapper.SysDictMapper">
        <!-- 查询表字典的数据, 支持设置过滤条件和code值 精确匹配查询【已加入SQL注入check】 -->
        <select id="queryTableDictByKeysAndFilterSql" parameterType="String" resultType="com.happy_retail_management.system.vo.DictModel">
            select ${text} as "text", ${code} as "value" from ${table}
            where ${code} IN (
            <foreach item="key" collection="codeValues" separator=",">
                #{key}
            </foreach>
            )
            <if test="filterSql != null and filterSql != ''">
                and ${filterSql}
            </if>
        </select>
    
        <!-- 通过字典code获取字典数据,可批量查询 -->
        <select id="queryManyDictByKeys" parameterType="String"  resultType="com.happy_retail_management.system.vo.DictModelMany">
            SELECT
            item.dict_code,
            item.item_text AS "text",
            item.item_value AS "value"
            FROM
            sys_dict_item item
            WHERE item.dict_code IN (
            <foreach item="dictCode" collection="dictCodeList" separator=",">
                #{dictCode}
            </foreach>
            )
            AND item.item_value IN (
            <foreach item="key" collection="keys" separator=",">
                #{key}
            </foreach>
            )
        </select>
    </mapper>
    
    

8. RedisTemple缓存乱码问题解决

  • 当使用redisTemple存在乱码问题,说明实体类的序列化会变成二进制数据存入数据库中,这会导致乱码乱码;
  • 或者我梦将RedisTemple的类型直接改为StringRedisTemple,其余都不变即可;
package com.happy_retail_management.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //首先解决key的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);

        //解决value的序列化方式
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        //序列化时将类的数据类型存入json,以便反序列化的时候转换成正确的类型
        ObjectMapper objectMapper = new ObjectMapper();
        //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // 解决jackson2无法反序列化LocalDateTime的问题
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);


        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}

9. 测试Controller

  • 测试的Controller的list接口

        @RequestMapping("/list")
        public Result<IPage<Product>> list(@RequestBody Product product,
                                             @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
                                             @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
                                             HttpServletRequest request){
    
            QueryWrapper<Product> queryWrapper = QueryGenerator.initQueryWrapper(product,request.getParameterMap());
            Page<Product> page = new Page<>(pageNo,pageSize);
            IPage<Product>pageList =productService.page(page,queryWrapper);
            //如果在customerService类里面写baseMapper.selectPag(page,queryWrqpper)
            return Result.success(pageList);
        }
    
  • 发送请求看到返回数据

    可以看到下面的成功被翻译了
    在这里插入图片描述

  • 30
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值