最近在开发过程遇到个需求,由于单位网络进行了加密,EXCEL导入批量处理数据不可用,通过查阅知识点发现了EXCEL数据复制到文本输入框中,因粘贴进来的数据带有制表符,可以通过制表符来进行数据的处理

本来可以使用导入的方式批量修改,无奈网络加密用不了导入,导入后的数据直接会变成二进制加密后的密文程序无法处理,无奈采用一下思路,首先展示EXCEL数据,下图为例

java生成的excel中的文字不换行 java导出excel换行符_java

首先后台管理前端页面先开发个输入框,将EXCEL数据进行粘贴操作,如下图,大家可以看到是把表头和底下数据都复制进来了,顺序也是一一对应的,其中看到的空格其实是制表符,空格是\t,换行是\n,感兴趣的可以自行搜索,虽然在前端页面看着是空格,但是传递到后端会发现制表符,注意点一定要从EXCEL文件进行复制,不可手动输入,不然后端就需要改动了

java生成的excel中的文字不换行 java导出excel换行符_数据_02

后端思路如下:

1、在对象里创建个String字符串类型的字段用于接收数据

String yjyInptData = pmpTargetPriceProcess.getYjyInptData();
//示例
String yjyInptData = "主键ID\t物料号\t物料名称\t目标价\n7e33a313-aaee-4f5f-aa4e-50c2e968cc48\tDZ97259770284\t双模空调底盘线束(XS/双层蓄右1800/横梁2200)\t23.06\n3edbd7fb-8c76-4749-82c9-d288d8b776e6\tDZ97149538069\t缓速器管路固定支架(二)\t12.89\n"

yjyInptData接收到的数据 如图:

java生成的excel中的文字不换行 java导出excel换行符_java_03

2、拿到数据后将数据以制表符换行\n转换成List集合

List<String> listAll = Arrays.asList(yjyInptData.split("\n")); // 根据"\n"转换为list

3、完成以上操作,将得到和前端粘贴进来行数一致长度的集合,注意这里只是行数,列的话还未提及,已知第一行数据传递进来的是表头也就是汉字,那么需要将汉字转换成实体类对应字段名称

如:”物料号“需要转换成对应字段”materialCode“

/**
* filedNameList是汉字表头,因此我们这里获取第一行下标应该就是0,获取到后,通过.split("\t")操作,将
* 制表符空格”\t“数据列数据转换成集合,示例如下
* List<String> filedNameList = ['主键ID','物料号','物料名称','目标价']
*/
List<String> filedNameList = Arrays.asList(listAll.get(0).split("\t")); // 获取表头汉字
/**
* getfiexName方法则是传递汉字表头List找到对应实体类的字段,并返回实践字段List 
*/
List<String> getfiexName = PmpTargetPriceProcess.getfiexName(filedNameList); // 将表头汉字转换为对应字段名称
// getfiexName 方法如下
public static List<String> getfiexName(List<String> filedNameList) {
        List<String> stringList = new ArrayList<>();
        for (int i = 0; i < filedNameList.size(); i++) {
            String fiexName = "";
            if (filedNameList.get(i).equals("任务编号")) {
                fiexName = "taskNumber";
            }
            if (filedNameList.get(i).equals("物料号")) {
                fiexName = "materialCode";
            }
            if (filedNameList.get(i).equals("物料名称")) {
                fiexName = "materialName";
            }
            if (filedNameList.get(i).equals("估算价")) {
                fiexName = "estimatedPrice";
            }
            if (filedNameList.get(i).equals("目标价")) {
                fiexName = "targetPrice";
            }
            if (filedNameList.get(i).equals("主键ID")) {
                fiexName = "id";
            }
            stringList.add(fiexName);
        }
        return stringList;
    }

接下来处理值的数据,通过for循环,循环上面根据行转List的数据,也就是上面的listAll,由于第一行是表头已经处理过了,所有循环从【1】下标开始,然后因为每行的数据制表符【\t】还没有处理,通过listAll.get(i).split(“\t”) ,转换为List集合,代码如下

for (int i = 1; i < listAll.size(); i++) {
            //第一行是表头汉字,忽略
            listAll.get(i);
            // 示例数据 valueList = ["7e33a313-aaee-4f5f-aa4e-50c2e968cc48","DZ97259770284","双模空调底盘线束(XS/双层蓄右1800/横梁2200)","23.06"]
            List<String> valueList = Arrays.asList(listAll.get(i).split("\t")); // 将制表符\t获取每一行数据转为list
            PmpTargetPriceProcess pmpTargetPriceProcess1 = new PmpTargetPriceProcess();
            // 首先进行判断表头和值的集合长度是否相同,如果不相同则进行报错处理(因为表头长度是4,如果值的长度是3那么肯定是少数据,这样接下来的代码执行会报错,所有这里先判断好预防一下)
            if (getfiexName.size() != valueList.size()) {
                int fail = i + 1;
                throw new Exception("数据第" + fail + "行:中存在列不全的数据,请检查后重试");
            }
            /**
             * 关键点关键方法setfields,将表头字段集合和行数据的列进行一一对应
             * 1.pmpTargetPriceProcess1实体类类型
             * 2.getfiexName字段名称
             * 3.valueList字段值
             * 调用setfields方法传递表头字段和对应列进行组装对应后返回实体类
             */
            pmpTargetPriceProcess1 = ReflectUtils.setfields(pmpTargetPriceProcess1, getfiexName, valueList);      
            // todo 你接下来的业务 
            pmpTargetPriceProcess1.setEnterTime(DateUtils.getNowDate());
            pmpTargetPriceProcess1.setEnterBy(SecurityUtils.getUsername());
            logger.info("转换后的实体类" + JSONObject.parseObject(JSONUtil.toJsonStr(pmpTargetPriceProcess1)));
            // pmpTargetPriceProcess1已经通过反射方式赋值了,进行修改业务结束
            int i2 = pmpTargetPriceProcessMapper.updatePmpTargetPriceProcess(pmpTargetPriceProcess1);
            a = a + i2;
        }

setfields()方法如下,大体思路通过反射给实体类赋值

package com.pmp.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;

public class ReflectUtils {

    private static final Logger log = LoggerFactory.getLogger(ReflectUtils.class);

    public static <T> T setfields(T entity, List<String> filedNameList, List<String> valueList) throws Exception {
        Class<?> clazz = entity.getClass();
        try {
            for (int i = 0; i < filedNameList.size(); i++) {
                // 获取字段
                Field deleterid = clazz.getDeclaredField(filedNameList.get(i));
                deleterid.setAccessible(true);
                Class<?> type = deleterid.getType();
                int size = valueList.size() - 1;
                if (size >= i) {
                	// 处理特殊类型数据需要转换,不然会报错,比如日期格式,因为在当前没有该需求就先不写了
                    if (type.getName().equals("java.math.BigDecimal")) {
                        deleterid.set(entity, new BigDecimal(valueList.get(i)));
                    } else {
                        deleterid.set(entity, valueList.get(i));
                    }
                } else {
                   throw  new Exception("数据中存在列不全的数据,请检查后重试");
                }
            }
        } catch (Exception e) { // 此异常为 实体内字段不存在
            log.error("反射添加字段报错,错误信息:" + e);
            StackTraceElement ste = e.getStackTrace()[0];
            log.error("反射添加字段异常信息:" + e.getMessage());
            log.error("反射添加字段异常类:" + ste.getClassName());
            log.error("反射添加字段异常类名:" + ste.getFileName());
            log.error("反射添加字段异常行号:" + ste.getLineNumber());
            log.error("反射添加字段异常方法:" + ste.getMethodName());
            if (e.getMessage().equals("数据中存在列不全的数据,请检查后重试")){
                throw new Exception("数据中存在列不全的数据,请检查后重试");
            } else {
                throw new Exception("数据解析失败,请检查数据或提供数据模板联系管理员!");
            }
        }
        // 返回,强转一下(拿出去之后强转也一样,但是返回值得改成obj类型)
        return entity;
    }
}

完整版代码serviceImpl层

public int updateYjyPmpTargetPriceProcess(PmpTargetPriceProcess pmpTargetPriceProcess) throws Exception {
        /**
         * 数据示例:
         * 主键ID	物料号	物料名称	目标价
         * a50056d8-f4c2-4c76-9f9f-87fec676e4f9	FDC1522110094500XK0	新M3000G驾驶室本体/导流罩/改型	11
         * 7e33a313-aaee-4f5f-aa4e-50c2e968cc48	DZ97259770284	双模空调底盘线束(XS/双层蓄右1800/横梁2200)	22
         * ea0c8b7f-929f-46c6-9a08-64bdc255e889	DZ9H319547203	排气管总成(一)	33
         * 当前数据有制表符"\n"换行,"\t"空格
         */
        logger.info("研究院开始复制EXCEL数据至文本输入框,进行批量修改");
        int a = 0;
        String yjyInptData = pmpTargetPriceProcess.getYjyInptData();
        List<String> listAll = Arrays.asList(yjyInptData.split("\n")); // 根据"\n"转换为list
        List<String> filedNameList = Arrays.asList(listAll.get(0).split("\t")); // 获取表头汉字
        List<String> getfiexName = PmpTargetPriceProcess.getfiexName(filedNameList); // 将表头汉字转换为对应字段名称
        for (int i = 0; i < listAll.size(); i++) {
            //第一行是表头汉字,忽略
            if (i == 0) {
                continue;
            }
            listAll.get(i);
            List<String> valueList = Arrays.asList(listAll.get(i).split("\t")); // 将制表符\t获取每一行数据转为list
            PmpTargetPriceProcess pmpTargetPriceProcess1 = new PmpTargetPriceProcess();
            // 首先进行判断表头和值的集合长度是否相同,如果不相同则进行报错处理
            if (getfiexName.size() != valueList.size()) {
                int fail = i + 1;
                throw new Exception("数据第" + fail + "行:中存在列不全的数据,请检查后重试");
            }
            /**
             * 1.pmpTargetPriceProcess1实体类类型
             * 2.getfiexName字段名称
             * 3.valueList字段值
             * 调用setfields方法传递表头字段和对应列进行组装对应后返回实体类
             */
            pmpTargetPriceProcess1 = ReflectUtils.setfields(pmpTargetPriceProcess1, getfiexName, valueList);     
            pmpTargetPriceProcess1.setEnterTime(DateUtils.getNowDate());
            pmpTargetPriceProcess1.setEnterBy(SecurityUtils.getUsername());
            logger.info("转换后的实体类" + JSONObject.parseObject(JSONUtil.toJsonStr(pmpTargetPriceProcess1)));
            int i2 = pmpTargetPriceProcessMapper.updatePmpTargetPriceProcess(pmpTargetPriceProcess1);
            a = a + i2;
        }
        return a;
    }