上传文件有很多种方法,这里主要讲通过poi组件(jar包)实现文件上传。项目依赖commons-io.jar和commons-fileupload(版本没有太大要求,能实现功能即可),楼主用的是commons-fileupload-1.3.1.jar和commons-io-2.4.jar。
主pom.xml配置
<dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons.io.version}</version>
</dependency>
<dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>${commons.fileupload.version}</version>
</dependency>

创建WorkBook对象引用poijar包的maven依赖
<dependency>
    <groupId>org.jeecg</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>2.3.0.2</version>
</dependency>

除了引入上述两种jar包,还可以在spring配置文件中添加id为multipartResolver的bean,用于控制文件上传的大小,
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
        <property name="defaultEncoding" value="UTF-8" />  
        <property name="maxUploadSize" value="10240000" />  
        <!-- 设置在文件上传时允许写到内存中的最大值,以字节为单位计算,默认是10240 -->  
        <!-- 但是经实验,上传文件大小若小于此参数,则不会生成临时文件,故改为2048 -->  
        <property name="maxInMemorySize" value="2048" />    
</bean>  

准备工作做好后,开始编写前端代码。前端用form表单,通过Form表单提交时enctype必须为"multipart/form-data"。
<form:form id="file_form"
        action="${ctx}/endUser/upload"
        enctype="multipart/form-data" method="post">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal"
                        aria-hidden="true">×</button>
                    <h4 class="modal-title" id="blankTitle">
                        导入Excel
                        <!-- 提示 -->
                    </h4>
                </div>
                <div class="modal-body" id="modal-body">
                    <div class="row">
                        <div class="form-horizontal">
                            <div class="form-group ">
                                <label class="col-lg-4 col-sm-4 control-label">文件选择:</label>
                                <div class="col-lg-8 col-sm-8">
                                    <input type="file" name="file" id="file_input" />
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="row">
                        <div class="form-horizontal">
                            <div class="form-group ">
                                <label class="col-lg-4 col-sm-4 control-label">文件上传:</label>
                                <div class="col-lg-8 col-sm-8">
                                    <input type="submit" value="上传" id='upFile-btn'>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
</form:form>

form提交时通过jquery校验文件上传的格式,楼主这里实现上传excel文件,所以校验excel格式
$("#file_form").submit(
            function() {
                //首先验证文件格式
                var fileName = $('#file_input').val();
                if (fileName === '') {
                    alert('请选择文件');
                    return false;
                }
                var fileType = (fileName.substring(fileName
                        .lastIndexOf(".") + 1, fileName.length))
                        .toLowerCase();
                if (fileType !== 'xls' && fileType !== 'xlsx') {
                    alert('文件格式不正确,excel文件!');
                    return false;
                }
                        }
});

仅校验是不够的,还需要用ajaxSubmit进行假提交,即不真正提交文件到服务器,而是只在后台获取上传的文件
$("#file_form").submit(
    $("#file_form").ajaxSubmit({
                    dataType : "json",
                    clearForm: true, 
                    success : function(data, textStatus) {
                        if (data.returnCode == 1) {
                            console.log('上传文件成功');
                            alert("上传文件成功");
                        } else {
                            console.log('文件格式错误');
                            alert("文件格式错误");
                        }
                        return false;
                    }
                }); 
            return false;
    });

后台通过form的action转发的url获取上传的文件,方法名和url同名,文件则是以MultipartFile类型传递的
        /**
         * /enduser/upload
         * 导入Excel
         * @param request
         * @throws Exception 
         */
        @RequestMapping(value="/upload",method= {RequestMethod.POST})
        @ResponseBody
        public String upload(@RequestParam(value = "file") MultipartFile file,HttpServletRequest request) throws Exception  {
            //判空
            if(file.isEmpty()) {
                return null;
            }
            logger.debug("原始文件名称:"+file.getName());
            logger.debug("==========开始转换Excel文件==========");
            //MultipartFile转换为File
            File f = multipartToFile(file);
            try {
                endUserProvider.importExcel(f);
            } catch (Exception e) {
                logger.error("==========解析Excel文件失败==========",e);
            }
            return "redirect:/endUser/list";
        }

值得注意的是,上传的文件自动绑定到MultipartFile。若文件为空,MultipartFile不为空,而是用MultipartFile.isEmpty()判空。
文件由MultipartFile转为File后,由File得到文件的输入流is,通过WorkBookFactory创建WorkBook对象
MultipartFile转为File
/** 
         * MultipartFile 转换成File 
         *  
         * @param multfile 原文件类型 
         * @return File 
         * @throws IOException 
         */  
        private File multipartToFile(MultipartFile multfile) throws IOException {  
            CommonsMultipartFile cf = (CommonsMultipartFile)multfile;   
            //这个myfile是MultipartFile的  
            DiskFileItem fi = (DiskFileItem) cf.getFileItem();  
            File file = fi.getStoreLocation();  
            //手动创建临时文件  
            if(file.length() < 0){  
                File tmpFile = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") +   
                        file.getName());  
                multfile.transferTo(tmpFile);  
                return tmpFile;  
            }  
            return file;  
        }  

FileInputStream is = new FileInputStream(file);
workbook = WorkbookFactory.create(is);
is.close();

此处有更简洁的思路,先将MultipartFile转为File类型,然后获取文件输入流来创建WorkBook对象
Workbook workbook = null;
try {
    InputStream is = file.getInputStream();
    workbook = WorkbookFactory.create(is);
    is.close();
    } catch (InvalidFormatException | IOException e) {
    .error("文件流转换为Workbook对象异常",e);
    }  

最后就是通过WorkBook对象得到Sheet对象,然后得到Excel的行和列,分别遍历行列进行文件的处理啦
for(int i=0;i<workbook.getNumberOfSheets();i++) {
    //获取Excel文件的第一个sheetSheet sheet = workbook.getSheetAt(i);  
    //获取文件的行
    int totalRows = sheet.getPhysicalNumberOfRows(); 
    //循环Excel行数  
    for (int r = 1; r < totalRows; r++) { 
        Row row = sheet.getRow(r);  
    if (row == null){  
         continue;  
                }
    //遍历列  
        for (int c = 0; c < totalCells; c++) {  
         Cell cell = row.getCell(c);
            //文件处理
            }
      }
}

文件下载
这里说下大体思路,就不贴详细代码了。
页面上布一个超链接,指向文件下载的方法
文件下载的方法
/**
         *  /endUser/excelDown
         * @param req
         * @param res
         * @throws IOException 
         */
        @RequestMapping(value="/excelDown")
        public void excelDown(HttpServletRequest req, HttpServletResponse res) throws IOException {
            req.setCharacterEncoding("UTF-8");
            res.setContentType("application/force-download");//应用程序强制下载
            String path = req.getSession().getServletContext().getRealPath("/WEB-INF/ExcelModel/测试卡模板20180226.xls");
            File file = new File(path);
            // 取得文件名。
            String filename = file.getName();
            filename = URLEncoder.encode(filename, "UTF-8");
            // 以流的形式下载文件。
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            res.reset();
            // 设置response的Header
            res.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
            res.addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(res.getOutputStream());
            res.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
}

需要注意的地方
excel单元格为很长的数值类型时,可能获取到科学计数法的数值。 所以需要格式化处理: DecimalFormat df = new DecimalFormat("0"); String value = df.format(cell.getNumericalValue());