Java实体类中的字典及JSON字段与MySQL数据转换

思路1:手写工具类处理(基于反射,比较麻烦,不推荐): 

字典表结果如下:

CREATE TABLE `sys_dict` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `dict_code` varchar(128) NOT NULL COMMENT '字典编码',
  `dict_name` varchar(128) NOT NULL COMMENT '字典名称',
  `dict_value` int(3) NOT NULL COMMENT '字典值',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8mb4 COMMENT='字典表';


INSERT INTO `sys_dict` VALUES (NULL, 'contract_type', '预研合同', '1');
INSERT INTO `sys_dict` VALUES (NULL, 'contract_type', '研制合同', '2');
INSERT INTO `sys_dict` VALUES (NULL, 'contract_type', '订购合同', '3');

1、创建java注解:

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

/**
 * @Description: 自定义注解,实现字典name 、value的转换
 * @Author: kang
 * @Date: 2024/1/18
 */
@Target(ElementType.FIELD) // 这个注解应用于字段
@Retention(RetentionPolicy.RUNTIME) // 这个注解在运行时仍然可用
public @interface DictField {
	String value() default ""; // 默认值为空字符串
}

2、在需要解析的实体上加注解,注意这些@DictField里面的值就是对应字典表的code

public class ContractInfo {
    private static final long serialVersionUID = 1L;
 
    private Long id;
    private String name;
    private String code;

    /**
     * 合同类型
     */
	@DictField("contract_type")
    private String type;

    /**
     * 产品层级
     */
	@DictField("product_level")
    private String productLevel;

    /**
     * 合同类别
     */
	@DictField("contract_category")
    private String category;
}

3、定义工具类,将这些注解的值转化为字典的name用于前端展示


import cn.hutool.core.collection.CollUtil;
import com.mars.admin.aspect.DictField;
import com.mars.admin.entity.SysDict;
import com.mars.admin.service.SysDictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.List;

/**
 * @Description: 自定义注解,实现字典name 、value的转换
 * @Author: kang
 * @Date: 2024/1/18
 */
@Slf4j
@Service
public class DictUtil {

	@Resource
	private SysDictService sysDictService;

	/**
	 * @Description: 字典值转为名称,比如页面展示,excel导出展示
	 * @Author: kang
	 * @Date: 2024/1/18
	 */
	public void convertObjValue2Name(Object obj) {
		if (obj == null) {
			return;
		}

		List<SysDict> dictList = sysDictService.getAll();
		if (CollUtil.isEmpty(dictList)) {
			return;
		}

		try {
			for (Field field : obj.getClass().getDeclaredFields()) {
				//1、判断对象有没有注解
				DictField dictField = field.getAnnotation(DictField.class);
				if (dictField != null) {
					//2、如果有,则注解的value就是字典类型,字段的值就是字典的值
					field.setAccessible(true);
					String dictCode = dictField.value();
					String dictValue = (String) field.get(obj);
					//3、筛选出数据库对应的字典,完成字典value -> 字典name的转换
					SysDict sysDict = dictList.stream().filter(i ->         dictCode.equals(i.getDictCode())
							&& dictValue.equals(i.getDictValue())).findFirst().orElse(null);
					if (sysDict != null) {
						field.set(obj, sysDict.getDictName());
					}
				}
			}
		} catch (Exception e) {
			log.info("##### 字典注解映射出错了:{}", e.getMessage());
		}
	}

	/**
	 * @Description: 字典名称转为值,比如excel导入
	 * @Author: kang
	 * @Date: 2024/1/18
	 */
	public void convertObjName2Value(Object obj) {
		if (obj == null) {
			return;
		}

		List<SysDict> dictList = sysDictService.getAll();
		if (CollUtil.isEmpty(dictList)) {
			return;
		}

		try {
			for (Field field : obj.getClass().getDeclaredFields()) {
				//1、判断对象有没有注解
				DictField dictField = field.getAnnotation(DictField.class);
				if (dictField != null) {
					//2、如果有,则注解的value就是字典类型,字段的值就是字典的值
					field.setAccessible(true);
					String dictCode = dictField.value();
					String dictValue = (String) field.get(obj);
					//3、筛选出数据库对应的字典,完成字典字典name -> value的转换
					SysDict sysDict = dictList.stream().filter(i -> dictCode.equals(i.getDictCode())
							&& dictValue.equals(i.getDictName())).findFirst().orElse(null);
					if (sysDict != null) {
						field.set(obj, sysDict.getDictValue());
					}
				}
			}
		} catch (Exception e) {
			log.info("##### 字典注解映射出错了:{}", e.getMessage());
		}
	}

	/**
	 * @Description: 字典值转为名称,比如页面展示,excel导出展示
	 * @Author: kang
	 * @Date: 2024/1/18
	 */
	public <Q> void convertListValue2Name(List<Q> list) {
		if (CollUtil.isEmpty(list)) {
			return;
		}

		List<SysDict> dictList = sysDictService.getAll();
		if (CollUtil.isEmpty(dictList)) {
			return;
		}

		try {
			for (Q obj : list) {
				convertObjValue2Name(obj);
			}
		} catch (Exception e) {
			log.info("##### 字典注解映射出错了:{}", e.getMessage());
		}
	}

	/**
	 * @Description: 字典名称转为值,比如excel导入
	 * @Author: kang
	 * @Date: 2024/1/18
	 */
	public <Q> void convertListName2Value(List<Q> list) {
		if (CollUtil.isEmpty(list)) {
			return;
		}

		List<SysDict> dictList = sysDictService.getAll();
		if (CollUtil.isEmpty(dictList)) {
			return;
		}

		try {
			for (Q obj : list) {
				convertObjName2Value(obj);
			}
		} catch (Exception e) {
			log.info("##### 字典注解映射出错了:{}", e.getMessage());
		}
	}

}

4、也可以在controller手动调用,也可以定义切面,我比较懒直接手动调用

@GetMapping("contractinfo/list")
    public void export(ContractInfo contractinfo) throws Exception {
      List<ContractInfo> list = contractinfoService.list(Wrappers.query(contractinfo));
        
        //手动调用	  
        dictUtil.convertListValue2Name(list);

}

ok  , 大功告成!

思路2:基于mybatis-plus解决字典转换(推荐):

1、User类中有一个用户状态字段:

像这种字段我们一般会定义一个枚举,做业务判断的时候就可以直接基于枚举做比较。但是我们数据库采用的是int类型,对应的PO也是Integer。因此业务操作时必须手动把枚举Integer转换,非常麻烦。

因此,MybatisPlus提供了一个处理枚举的类型转换器,可以帮我们把枚举类型与数据库类型自动转换

2.定义枚举

我们定义一个用户状态的枚举:

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;

@Getter
public enum UserStatus {
    NORMAL(1, "正常"),
    FREEZE(2, "冻结")
    ;
    private final int value;
    private final String desc;

    UserStatus(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}

然后把User类中的status字段改为UserStatus 类型:

要让MybatisPlus处理枚举与数据库类型自动转换,我们必须告诉MybatisPlus,枚举中的哪个字段的值作为数据库值。

3、MybatisPlus提供了@EnumValue注解来标记枚举属性:

4、配置枚举处理器

在application.yaml文件中添加配置:

mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

可以看到使用mybatisPlus的配置非常简洁、方便!!

ok  , 大功告成!

基于mybatis-plus解决表中JSON转换:

数据库的user表中有一个info字段,是JSON类型:

格式像这样:

{"age": 20, "intro": "佛系青年", "gender": "male"}

而目前User实体类中却是String类型:

这样一来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类。

而一旦我们把info改为对象类型,就需要在写入数据库时手动转为String,再读取数据库时,手动转换为对象,这会非常麻烦。

因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

接下来,我们就来看看这个处理器该如何使用。

3.4.1.定义实体

首先,我们定义一个单独实体类来与info字段的属性匹配:

import lombok.Data;

@Data
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}

3.4.2.使用类型处理器

接下来,将User类的info字段修改为UserInfo类型,并声明类型处理器:

测试可以发现,所有数据都正确封装到UserInfo当中了:

同时,为了让页面返回的结果也以对象格式返回,我们要修改UserVO中的info字段:

此时,在页面查询结果如下:

ok  , 大功告成!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值