POI简单导入

       在系统设计中,都会有新增数据的功能,像那种人力资源系统,就需要大量新增员工信息或者一些大量的资料,大量的数据使得操作员要逐条手动添加,还要不断地切换复制,增加了新增数据的成本,同时加大了新增数据错误的几率,所以有了导入功能,批量导入可以把大量数据一次性新增进系统,既可以提高准确性,又节省了人力。

       如何做好导入功能,首先想要导入,那咱们得先有Excel表格的模板吧,要不然谁知道你新增的格式是怎么样的。哎,在做模板之前,我们得给项目中加入依赖吧,工具包、注解包、文件上传。光是加入依赖还不够,还得去配置。

<!-- 导入导出工具包,可以完成Excel导出、导入,Word导出 -->
<dependency>
   <groupId>cn.afterturn</groupId>
   <artifactId>easypoi-base</artifactId>
   <version>3.2.0</version>
</dependency>

<!-- 基础注解包,作用与实体对象上,拆分后方便maven多工程的依赖管理-->
<dependency>
   <groupId>cn.afterturn</groupId>
   <artifactId>easypoi-annotation</artifactId>
   <version>3.2.0</version>
</dependency>

<!-- 文件上传 -->
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.1</version>
</dependency>

       加入文件上传的配置,这个配置是指定上传的文件总大小不能超过100MB,不是限制单个文件大小,是所有文件的大小之和。文件上传的配置可以放在Spring-mvc.xml中。 

<!-- 文件上传的配置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
   <!-- 指定所上传文件的总大小不能超过100MB。注意maxUploadSize属性的限制不是针对单个文件,而是所有文件的容量之和 -->
   <property name="maxUploadSize" value="102400"/>
</bean>

       依赖加了,文件上传配置加了,那就先来看看jsp页面的代码,Excel模板先不急。页面中给个导入按钮,用button标签,在button标签中加入点击事件(οnclick=”ToLead()”),在JS里给个点击导入按钮的Layui询问框,若是不想要询问框也可以去掉不用,里面的代码都做了相应的解释。

// 执行导入
function ToLead(){
    layer.confirm('请选择需要的操作', {
        btn:['下载模板','导入数据','取消'],area:['320px','155px']
    }, function (index){
        // 下载模板的链接
        window.location.href = "${pageContext.request.contextPath}/Vehicle/Exceling";
        // 按钮“下载模板”的回调
        layer.close(index);
    }, function (index){
        // 打开导入文件模态框
        $("#dao").click();
        // 按钮“导入数据”的回调
        layer.close(index);
    }, function (index){
        // 按钮“取消”的回调
        layer.close(index);
    });
}

       询问框里面的按钮,我们先实现下载模板,就是提供相关的Excel模板给客户或者操作员下载出来,方便填写好数据信息上传。通过给出的链接来跳到控制器,控制器再执行下载模板的方法,代码解释都在图片里了。

/**
 * 导入训练场(模板下载)
 * @param response
 * @throws IOException
 */
@RequestMapping("/Exceling")
public void Exceling(HttpServletResponse response) throws IOException {
    // new一个初始量为10的空的数组列表
    List<Training> list = new ArrayList<>();

    // 自定义Excel表格标题与工作表标签名
    Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("训练场导入模板", "训练场"), Training.class, list);

    // 下载模板的文件名
    String filename = "训练场导入模板.xls";

    //不设置编码中文无法显示
    filename = URLEncoder.encode(filename, "UTF-8");

    // 设置流的响应头
    response.setHeader("Content-Disposition", "attachment;Filename=" + filename);
    // 创建流
    OutputStream outputStream = response.getOutputStream();
    // 写入流
    workbook.write(outputStream);
    // 关闭流
    outputStream.close();
}

       还没完呢,要去实体类中给字段加上Excel注解,注解里加上需要的类型,如:字段名(name=)、列宽(width=)、替换类型(replace=)、校验字段(isImportField=),常用的还有导出类型(type=)、列高(height=)………还有其他的类型,请搜索“EasyPOI 详细教程以及注解的使用”。图中都是简单的设置Excel模板中的字段表头样式,实体类的get与set方法以及其他的,你们自行添加。

public class Training {
    //训练场ID
    private Integer trainingID;

    /**
     * 训练场名称
     */
    @Excel(name = "训练场名称", width = 18,isImportField = "diyi")
    private String trainingName;

    /**
     * 训练场号码
     */
    @Excel(name = "训练场号码", width = 18,isImportField = "diyi")
    private String trainingNumber;

    /**
     * 容纳车辆
     */
    @Excel(name = "容纳车辆", width = 15,isImportField = "diyi")
    private String carAccommodate;

    /**
     * 投放车辆
     */
    @Excel(name = "投放车辆", width = 15,isImportField = "diyi")
    private String putInCar;

    /**
     * 训练场地址
     */
    @Excel(name = "训练场地址", width = 30,isImportField = "diyi")
    private String trainingSite;

    /**
     * 训练场状态
     */
    @Excel(name = "训练场状态", width = 15,replace = {"作废_0","启用_1"},isImportField = "diyi")
    private Integer trainingState;

    //车型ID
    private Integer carTypeID;
    /**
     * 车型
     */
    @Excel(name = "车型", width = 15,isImportField = "diyi")
    private String carType;

    //科目类型ID
    private Integer subjectsTypeID;
    /**
     * 科目类型
     */
    @Excel(name = "科目类型", width = 15,isImportField = "diyi")
    private String subjectsType;
}

       客户或者操作员有了模板后,填写好了信息准备上传,现在就该做上传功能了。询问框第二个按钮就是导入数据,通过点击“导入数据”按钮打开文件上传的模态框。在页面的导入按钮下面放一个隐藏的button按钮,用于打开文件上传模态框的按钮。

       这个文件上传是调用了Layui的文件上传的插件,所以调用隐藏按钮的ID打开,还要去控制器写个文件上传的方法,值得注意的是size:0,允许上传的文件大小,可自定义设置文件大小。文件上传基础参数可以参考Layui的文件上传。选择好上传的文件后,判断上传的数据长度是否不等于0,不等于0就会获取预览框按钮打开并把获取到数据赋值进去,便可以在模态框中查看是否是你想要导入的数据。后面的两个是上传完毕的回调与上传异常的回调。

var layer, upload, tableIns;
/*声明Layui组件*/
layui.use(['table','layer','upload'],function (){
    var table = layui.table;
    layer = layui.layer;
    upload = layui.upload;

    //文件导入
    upload.render({
        elem: '#dao' //绑定元素
        , url: '${pageContext.request.contextPath}/Vehicle/Exceled' //上传接口
        , accept: 'file' //允许上传的文件类型
        //规定打开文件选择框时,筛选出的文件类型
        , acceptMime: 'application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        , exts: 'xls|xlsx' //允许上传的文件后缀。一般结合 accept 参数类设定
        , auto: true //是否选完文件后自动上传
        // , bindAction: '#bindAction'//指向一个按钮触发上传color
        , size: 0 //最大允许上传的文件大小kb
        //,method: 'post'  //可选项。HTTP类型,默认post
        , before: function (obj) { //obj参数包含的信息,跟 choose回调完全一致。
            layer.load(); //上传loading
        }
        , done: function (res) {//执行上传请求后的回调
            console.log(res);
            if (res.length != 0) {// 预览
                $("#upfile").click();//打开模态框
                table.reload('demo1', {//赋值数据
                    data: res
                });
            }
            //上传完毕回调
            layer.closeAll('loading'); //关闭loading
            return;//不可取消
        }
        , error: function () {//执行上传请求出现异常的回调
            layer.closeAll('loading'); //关闭loading
            //请求异常回调
            return;//不可取消
        }
    });
});

       文件上传接口,控制器方法:

/**
 * 文件上传
 * @param file
 * @param session
 * @return
 * @throws Exception
 */
@RequestMapping("/Exceled")
@ResponseBody
public List<Training> Exceled(@RequestParam("file") CommonsMultipartFile[] file, HttpSession session) throws Exception {
    ImportParams params = new ImportParams();
    //设置标题与表头不需要导入
    params.setTitleRows(1);
    params.setHeadRows(1);

    //开始导入数据
    List<Training> list = ExcelImportUtil.importExcel(file[0].getInputStream(), Training.class, params);

    //保存到session
    session.setAttribute("supvolist", list);

    //返回list
    return list;
}

       这是文件上传预览框,在预览框内放入提示与表格,表格是跟页面表格一样的,这样就能看到导入的数据是否跟页面表格一致。表格上一步的提示的可以自定义。确定没问题可以进行导入操作,给开始导入按钮一个点击事件(addfile( ))。注意:文件上传预览框是放在文件导入的上面的,都在Layui方法里面。

var layer, upload, tableIns;
/*声明Layui组件*/
layui.use(['table','layer','upload'],function (){
    var table = layui.table;
    layer = layui.layer;
    upload = layui.upload;

    /*文件上传预览数据表格*/
    table.render({
        elem: '#demo1',//表格ID
        //url: '${pageContext.request.contextPath}/Vehicle/JumpThreePage',//数据接口
        //data:
        page: true,//开启分页
        cols: [[
            {type: 'numbers',title: '序号',fixed: 'left'},/*序列号*/
            {field: 'trainingName',title: '训练场名称',align: 'center',width: 180},
            {field: 'subjectsType',title: '科目',align: 'center',width: 113},
            {field: 'carType',title: '培训车型',align: 'center',width: 100},
            {field: 'trainingNumber',title: '联系电话',align: 'center',width: 160},
            {field: 'trainingSite',title: '训练场地址',align: 'center',width: 280},
            {templet: function (data){
                    return data.carAccommodate+" ➡ "+data.putInCar;
                },title: '容纳 → 投放(辆) ',align: 'center',width: 180},
            {field: 'trainingState',title: '训练场状态',align: 'center',width: 100,templet: '#trainingState'},
        ]],
        /*解析原始数据格式*/
        parseData:function (res){
            return{
                "code": 0, //解析接口状态
                "msg": res.message, //解析提示文本
                "count": res.length, //解析数据长度
                "data": res //解析数据列表
            };
        }
    });
});

       点击开始导入执行post请求到控制器:

//保存导入
function addfile(){
    //用post请求提交到控制器上传方法
    $.post("${pageContext.request.contextPath}/Vehicle/savesup", {
        AreyouOK: true//参数
    }, function (data) {
        layer.alert(data.msg);//Layui提示
        //刷新表格
        tableIns.reload({url:"${pageContext.request.contextPath}/Vehicle/JumpThreePage"});
        $("#shishi").click();//关闭模态框
    });
}

       控制器执行导入方法并判断重要的数据:

/**
 * 保存上传
 * @param AreyouOK
 * @param session
 * @return
 */
@ResponseBody
@RequestMapping("/savesup")
public JsonReturn savesup(Boolean AreyouOK, HttpSession session) {
    JsonReturn jsonReturn = new JsonReturn();
    int a = 0;//成功
    int b = 0;//名字相同
    int c = 0;//关键数据错误
    int d = 0;//必要数据不存在
    if (AreyouOK) {
        //取值
        List<Training> list = (List<Training>) session.getAttribute("supvolist");
        //判断是否有值
        if (list != null) {
            for (Training ting : list) {
                if (ting == null) {
                    continue;//跳过单次循环
                }//空列

                //查询是否存在训练场名称
                Training tr = vehicleService.TrainingName(ting.getTrainingName());
                if (tr != null) {
                    b++;
                    continue;//跳过单次循环
                }

                //根据新增的科目类型查询对应的ID
                SubjectsType su = vehicleService.SubjectsType(ting.getSubjectsType());
                if (su == null) {
                    c++;
                    continue;
                }

                //根据新增的车型查询对应的ID
                CarType ca = vehicleService.CarType(ting.getCarType());
                if (ca == null) {
                    c++;
                    continue;
                }

                ting.setSubjectsTypeID(su.getSubjectsTypeID());//科目类型对应ID
                ting.setCarTypeID(ca.getCarTypeID());//车型对应ID

                // 判断必要数据不存在
                if (ting.getTrainingName() == "" || ting.getTrainingName() == null
                        || ting.getSubjectsTypeID() == null || ting.getSubjectsTypeID() == 0
                        || ting.getCarTypeID() == null || ting.getCarTypeID() == 0){
                    d++;
                    continue;//跳过单次循环
                }
                // 执行新增
                int it = vehicleService.insertTraining(ting);
                if (it > 0) {
                    a++;
                }
            }
            String su = String.format("共发现 " + list.size() + " 条数据<br>保存成功数 : " + a + "<br/>保存失败数 : " + (list.size() - a) + " <br>原因如下:<br>训练场名称相同数 : " + b + " <br>数据不完整数 : " + d + " <br>关键数据不存在数 : " + c);
            jsonReturn.setState(true);
            jsonReturn.setMsg(su);
            session.removeAttribute("supvolist");
        } else {
            jsonReturn.setMsg("请先导入数据");
        }
    }
    else {
        jsonReturn.setMsg("请正确导入数据");
    }
    return jsonReturn;
}

 


版权声明:本文为weixin_44540181原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。