EasyExcel converter转换数据库映射关系

无人久伴 提交于 2020-12-18 13:47:18

项目中的需求:导出功能,且有些字段是需要通过数据库存储的数据字典来进行翻译转换。比如:企业类型,1=生产企业,2=配送企业,3=经营企业,等等。这些映射关系虽然变化频率很低,但也是动态存储在数据库中的。我们不希望将这些映射关系写死在Java代码中。

EasyExcel有个Converter功能,目前看来有两种实现方式:

一种是在@ExcelProperty注解中指定:

@ExcelProperty(value = "创建时间",index = 5,converter = DateTimeConverter.class)
private Date creTime;

一种是注册写处理器的方式,类似于:

public static void export(HttpServletResponse response, List rowList,String fileName,Class clazz,String sheetName) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), clazz)
                .registerWriteHandler(new CustomCellWriteHandler())
                .registerWriteHandler(your converter constructor)//这里可以继续添加其他的转换器或处理器
                .sheet(sheetName).doWrite(rowList);
    }

这两种方式各自有缺点:

注解方式:这种方式直接使用的话,无法动态维护映射关系。假设我们已经有了映射关系范围,无法通过构造器的方式注入到转换器中。

注册方式:这种注册方式是针对类型的全局转换器。比如我们将如下的转换器注册进去,它就会针对所有的Integer类型的字段,全部按照这个转换器里的规则,进行转换。而不是针对某个字段。

在我们的项目中,数据字典的翻译是很常见的,甚至通过一个ID去动态查询其他表的一个信息,也是极为常见的所以最好是能有一种方案,让我们比较灵活的翻译来自数据库的映射关系。

鉴于我们的项目使用的是Springboot,所以可以通过某种方式,获取到Spring容器中的数据库访问组件Bean(dao,或者我们自己封装的组件类)。

以下是我在项目中已经实现的一种方案。

先从网上找了一个通过Spring应用上下文获取Spring容器中bean的工具类:

@Component
public class SpringApplicationUtils  implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;

    /**
     * 获取applicationContext
     *
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringApplicationUtils.applicationContext == null) {
            SpringApplicationUtils.applicationContext = applicationContext;
        }
    }

    /**
     * 通过name获取 Bean.
     */
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    /**
     * 通过class获取Bean.
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * 通过name,以及Clazz返回指定的Bean
     *
     * @param name
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    /**
     * 获取指定类型的所有bean实例
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
        Map<String, T> instances = getApplicationContext().getBeansOfType(clazz);
        return instances;
    }
}

然后定义我们的EasyExcel converter实现类,用于转换一个状态,将状态码转为可读性比较好的状态名称:

public class EnableStatusConverter implements Converter<Integer> {

    private static Map<Integer,String> statusMap = null;

    //baseService是项目中封装的一个组件类,间接调用dao中的方法,并对返回结果进行了处理封装
    private BaseService baseService;

    //懒汉模式构造器,将状态码映射关系注入进map中,不必每次都连接数据库进行查询
    public EnableStatusConverter() {
        baseService = SpringApplicationUtils.getBean(BaseService.class);
        if (CollectionUtil.isEmpty(statusMap)){
            statusMap = baseService.getItemMap(DictTypeConstants.D_ENABLE_STATUS);
        }
    }

    @Override
    public Class supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        String enableStatusName = cellData.getStringValue();
        for (Integer enableStatus : statusMap.keySet()) {
            if(StringUtils.equalsStr(enableStatusName,statusMap.get(enableStatus))){
                return enableStatus;
            }
        }
        return null;
    }

    @Override
    public CellData convertToExcelData(Integer enableStatus, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        String enableStatusName = statusMap.get(enableStatus);
        return new CellData(StringHelper.isEmpty(enableStatusName) ? "":enableStatusName);
    }
}

然后是Excel Row对应的实体类,在@ExcelProperty注解中,converter属性指定转换器即可:

public class BzVaccKnowRowModel {
    @ExcelProperty(value = "ID号",index = 0)
    private Integer knowId;
    @ExcelProperty(value = "知识标题",index = 1)
    private String title;
    @ExcelProperty(value = "浏览量",index = 2)
    private Integer viewNum;
    @ExcelProperty(value = "收藏量",index = 3)
    private Integer collectNum;
    @ExcelProperty(value = "状态",index = 4,converter = EnableStatusConverter.class)
    private Integer enableStatus;
    @ExcelProperty(value = "创建时间",index = 5,converter = DateTimeConverter.class)
    private Date creTime;
}

其他的导出逻辑,并无其他不同,不再赘述。

直接上Excel导出结果:

状态列,即为本次翻译的主要对象。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!