基于Java语言SpringMVC框架的Excel上传解析以及下载教程

基于SpringMVC的Excel上传解析以及下载

简介:

本文主要基于Java的,介绍的分为三个部分,文件上传、Excel解析、文件下载,然而这三个部分都有各种各样的方法实现,原生的最通用,但也是代码量最多,本文介绍的只是基于spring,可能使用的人群没原生的那么多,仅供参考。

说明:

本文所提示的依赖的jar包指的都是主要的jar,其中还需要其他的jar未具体一一说明,这个官网上下载都会有提示相关下载的,但为了方便各位道友,点击此处打开下载页面

文件上传:

文件上窜的思路是提交一个带文件的表单,后台动过循环遍历表单元素判断是传统数据还是文件流数据,如果是文件流数据则进行文件接收保存。

依赖的jar:commons-fileupload-1.2.1.jar。

下面贴出代码以及注释,其中加粗的是核心代码,其他的是我项目中的其他代码可以忽略。

public void upExcel(HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException {
		// 定义返回值
		Map<String, Object> resMap = new HashMap<String, Object>();
		String chatid = request.getParameter("chatid");
		if (chatid == null || "".equals(chatid)) {
			resMap.put("resCode", "4");
			resMap.put("resMsg", "群组参数错误!");
			responseToPage(request, response, new JSONObject(resMap).toString());
			return;
		}
		// 定义服务器保存的文件名(因为我的项目特殊需求,后上传的文件覆盖前面的文件,所以采用写死的文件名,这个可以根据不同的需求生成文件名)
		String name = "ldry";
		// 检索文件
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
		if(multipartResolver.isMultipart(request)) {
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request;
			Iterator<?> iter = multiRequest.getFileNames();
			while(iter.hasNext()) {
                // 遍历文件
				MultipartFile file = multiRequest.getFile(iter.next().toString());
				if(file != null && file.getSize() > 0) {
					// 获取文件后缀
					String postfix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
					// 文件类型校验
					if (!"xls".equals(postfix) && !"xlsx".equals(postfix)) {
						resMap.put("r esCode", "3");
						resMap.put("resMsg", "请上传*.xls/*.xlsx类型的文件!");
						responseToPage(request, response, new JSONObject(resMap).toString());
						return;
					}
					
					// 获取文件目录
					String pathLast = this.getServletContext().getRealPath("/WEB-INF/upload");
					// 校验 创建文件目录
					File filepath = new File(pathLast);
					if (!filepath.exists() && !filepath.isDirectory()) {
						System.out.println("创建目录 " + pathLast);
						filepath.mkdir();
					}
					
					// 清空相关旧文件
					File delFile1 = new File(filepath + "\\"+ name + ".xls");
					delFile1.delete();
					File delFile2 = new File(filepath + "\\"+ name + ".xlsx");
					delFile2.delete();
					
					// 拼装完整文件路径
					String path = pathLast + "\\"+ name + "." + postfix;
					// 保存
					file.transferTo(new File(path));
					// 解析EXCEL
					resMap = ExcelToDB(path,chatid);
                } else {
                	resMap.put("resCode", "3");
					resMap.put("resMsg", "请勿导入空文件!");
                }
            }
        } else {
        	resMap.put("resCode", "3");
			resMap.put("resMsg", "未识别文件");
        }
        responseToPage(request, response, new JSONObject(resMap).toString());
    }

HTML代码,为了能自己定义上传文件的样式,本文是吧上传文件的空间跳成透明,在其上面防止空间实现的,仅供参考,注意

 enctype="multipart/form-data"
是设置表单拥有文件元素,这个必须加

 encoding="multipart/form-data"
是为了兼容某可恶浏览器

<div class="filegroup">
			<label class="upstyle btn btn-success">
				选择文件
				<form id="upFileForm" enctype="multipart/form-data" encoding="multipart/form-data">
					<input type="hidden" id="chatid" name="chatid" />
			 		<input type="file" id="filexz" name="upexcel" style="border: solid;" accept=".xls,.xlsx" />
			 	</form>
		 	</label>
		 	<label class="upTip">
		 		未选择文件
		 	</label>
			<button type="button" class="subbtn btn btn-success" οnclick="subfile()">  保 存  </button>
		</div>
css把文件元素设置成透明,其他的样式此处就不贴出来了

#filexz{
		width: 100px;
	    position: absolute;
	    top: 0;
	    opacity: 0;
	}
下面贴出js代码,红色部分是相关代码,其他部分可忽略
$(function() {
		filetip();
	});
	// 文件选择提示
	function filetip() {
		$(".upstyle").on("change",function(){
		    var filePath = $("#filexz").val();
		    if(filePath.indexOf("xls") != -1 || filePath.indexOf("xlsx") != -1){
		        var arr = filePath.split('\\');
		        var fileName = arr[arr.length-1];
		        $(".upTip").css("color", "green");
		        $(".upTip").html(fileName);
		    }else{
		        $(".upTip").css("color", "red");
		        $(".upTip").html("请选择*.xls/*.xlsx类型的文件!");
		        return false;
		    }
		});
	}
	
	// 文件上传(表单提交)
	function subfile() {
		var upload = window.top.layer.load(1);
		var form = new FormData(document.getElementById("upFileForm"));
		$.ajax({
			url : "<%=basePath%>suzhou/bg/lhzh/lhzh.do?action=upExcel",
			type : "post",
			data : form,
			processData : false,
			contentType : false,
			success : function(value){
				window.top.layer.close(upload); // 关闭正在上传提示
				var result = JSON.parse(value);
				if (result.resCode == "0") {
					window.top.layer.msg(result.resMsg, {icon: 1, time: 2000});
					location.reload();
				} else if (result.resCode == "1") {
					window.top.layer.alert(result.resMsg + ".\n其他记录已导入",{icon: 6});
				} else {
					window.top.layer.alert(result.resMsg,{icon: 5});
				}
			},
			error:function(e){
				window.top.layer.alert("请求错误!",{icon: 2});
			}
		});
	}

Excel解析:
要注意的是其实也可以在上传文件时解析Excel,但是个人不推荐那样,因为如果文件较大是需要一定的时间的,然而这段时间操作端要是断网或者其他原因导致上传中断会造成一系列的错误,所以推荐先把文件保存下来再解析。Excel解析其实就是读取文件然后获取Excel里面的工作表(sheet),行(row),列(cell),这个一般都可以通过遍历解决,但不同的需求可以采取不同的方式,比如我的项目只看第一张工作表的,我就不遍历工作表
sheet)只看第一张,列支取指定两列的我也不遍历,毕竟如果套三层循环,对效率影响还是很大的。

依赖的jar包:poi-3.16.jar。

下面贴出代码以及注释,其中加粗的是核心代码,其他的是我项目中的其他代码可以忽略

private Map<String, Object> ExcelToDB(String path,String chatid) {
		Map<String, Object> resMap = new HashMap<String, Object>();
		resMap.put("resCode", "0");
		String resMsg = "";
		File file = new File(path);
		
		InputStream is = null;
		int rowNum = 0;
		try {
			is = new FileInputStream(file);
			Workbook wb = null;
			// 获取后缀名
			String postfix = path.substring(path.lastIndexOf(".") + 1); 
			if ("xls".equals(postfix)) {
				wb = new HSSFWorkbook(is);
			} else {
				wb = new XSSFWorkbook(is);
			}
			// 遍历工作表(此处项目需要,所以只关心第一张工作表)
			Sheet sheet = wb.getSheetAt(0);
			
			List<Object[]> objs = new ArrayList<Object[]>();
			// 总行数
			int totalRows = sheet.getPhysicalNumberOfRows(); 
			// 遍历当前工作表的行
			for (int i = 1; i < totalRows; i++) {
				int type = 0; // 人员类别 0短期值班/1长期值班
				rowNum = i + 1;
				Row row = sheet.getRow(i);
				if (row == null) {
					continue;
				}
				// 遍历当前行的列,此处项目需要,不做遍历
				Cell c0 = row.getCell(0);
				Cell c1 = row.getCell(1);
				
				// 身份证号初处理
				if (c0 == null || "".equals(c0.toString().trim())) {
					resMap.put("resCode", "1");
					resMsg += "第" + rowNum + "行第1列为空。";
					continue;
				}
				
				c0.setCellType(CellType.STRING);
				String idcard = getCellValue(c0).trim();
				// 此处判断是否为空,可以用其他的判断,此处为了项目代码统一
				if (StringUtils.isEmpty(idcard)) 
					continue;
				// 此处过滤掉特定的数据
				if ("320666666666666666".equals(idcard)) 
					continue;
				 
				// 值班时间以及人员类别处理
				String time = null;
				if (c1 == null || "".equals(c1.toString().trim())) {
					type = 1;
				} else {
					SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
					c1.setCellType(CellType.NUMERIC);
					if (c1.getNumericCellValue() == 0.0) {
						resMap.put("resCode", "1");
						resMsg += "第" + rowNum + "行第2列日期格式异常。";
						continue;
					}
					time = sdf.format(c1.getDateCellValue());
				}
				Object[] obj = new Object[]{time,chatid,idcard,type};
				objs.add(obj);
			}
			int[] zbres = this.flowper_service.batchSave(objs);
			if ("0".equals(resMap.get("resCode"))) {
				resMsg = "导入成功";
			}
			resMap.put("resMsg", resMsg);
			try {
				is.close();
			} catch (IOException e) {
				is = null;
				e.printStackTrace();
	        }
		} catch (FileNotFoundException e) {
			// e.printStackTrace();
			resMap.put("resCode", "2");
			resMap.put("resMsg", "创建文件流失败!");
		} catch (IOException e) {
			// e.printStackTrace();
			resMap.put("resCode", "2");
			resMap.put("resMsg", "读取文件失败!");
		} finally {
			if(is != null) {
				try {
					is.close();
				} catch (IOException e) {
					is = null;
					e.printStackTrace();
		        }
			}
		}
		return resMap;
	}
此处为了准确解析而且解析的字段不多,所以在代码里手动转化了数据格式以及类型,下面贴出通用方法,但是由于环境不同有的不能用的可以参考上面的手动解析的

/**
	 * 获取Excel单元格的值
	 * PS:奇葩的POI。把getCellType()给过时了却没推出新的获取单元格类型方法<p>
	 * 	     导致代码在有些编译器上挺难看的。
	 */
	@SuppressWarnings("deprecation")
	public String getCellValue(Cell cell) {
		if (null != cell) {     
			switch (cell.getCellType()) {     
				case Cell.CELL_TYPE_NUMERIC: // 数字
					return cell.getNumericCellValue() + "";     
				case Cell.CELL_TYPE_STRING: // 字符串
					return cell.getStringCellValue() + "";     
				case Cell.CELL_TYPE_BOOLEAN: // 布尔
					return cell.getBooleanCellValue() + "";     
				case Cell.CELL_TYPE_FORMULA: // 公式
					return cell.getCellFormula() + "";     
				case Cell.CELL_TYPE_BLANK: // 空值
					return "";
				case Cell.CELL_TYPE_ERROR: // 故障
					return "";
				default:
					return "未知类型";
			}
		} else {
			return "";
		}
	}


文件下载:

文件下载就是服务端直接把文件以流的形式输出给浏览器,废话不多说,直接贴代码
HTML代码
<a href="<%=basePath%>suzhou/bg/lhzh/lhzh.do?action=downExcel"><u><I></i>点击这里</I></u></a>
Java后台代码

public void downExcel(HttpServletRequest request, HttpServletResponse response) throws IOException {
		JSONObject res = new JSONObject();
		res.put("errcode", "0");
		res.put("errmsg", "下载成功");
		String fileName = "值班表示例.xls";
		// 此处对文件名进行编码一方乱码的,可视情况使用
		// fileName = new String(fileName.getBytes("iso8859-1"),"UTF-8");
		// 文件路径
		String path = this.getServletContext().getRealPath("/WEB-INF/download");
		File file = new File(path + "\\" + fileName);
		if(!file.exists()){
			res.put("errcode", "1");
			res.put("errmsg", "您要下载的资源已被删除!");
			responseToPage(request, response, res.toString());
			return;
		}
		// 设置响应头,让浏览器下载文件
		response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
		// 文件放到输入流
		FileInputStream in = new FileInputStream(path + "\\" + fileName);
		// 创建输出流
		OutputStream out = response.getOutputStream();
		// 创建缓冲区
		byte buffer[] = new byte[1024];
		int len = 0;
		while ((len = in.read(buffer)) > 0) {
			// 输出缓冲区的内容到浏览器,实现文件下载
			out.write(buffer, 0, len);
		}
		in.close();
		out.close();
	}
本文介绍就到此结束了,希望对您有所帮助,也感谢您的阅读和支持

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
poi解析excel功能参数说明 此项目是基于springMVC实现的,基本流程为从前台jsp页面使用Ajax文件上传导入excel文件(.xls(97-03)/.xlsx(07以后)),传到后台controller调用相应工具类解析后返回指定参数做后续处理. 1. POIUtil.java工具类 解析通过MutilpartFile导入的Excel解析里面数据,先判断文件的类型(excel处理有两种此处为两种通用)是.xls/.xlsx,通过workbook.getNumberOfSheets()获取工作簿数量,遍历工作簿,sheet.getLastRowNum()获取最大行数,将每行数据放入List list = new Array List(),并根据excel数据类型将器转换为字符串、数字、Boolean、公式、空值类型防止出现错误,最后返回一个list. 2. ExcelUtil.java工具类 解析通过MutilpartFile导入的Excel解析里面数据,先判断文件的类型(excel处理有两种此处为两种通用)是.xls/.xlsx,采用Apache的POI的API来操作Excel,读取内容后保存到List中,再将List转Json(使用Linked,增删快,与Excel表顺序保持一致),Sheet表1————>List1<Map> 步骤1:根据Excel版本类型创建对于的Workbook以及CellSytle 步骤2:遍历每一个表中的每一行的每一列,这里做了些小改动,因为后续可能解析过后可能会保存入数据库,这里为第一行数据添加一个自定义表头 String[] p = new String[]{"name","age","sex","tel","address","e-mail","phone"}; 遍历的列数量以p的length为准 步骤3:一个sheet表就是一个Json,多表就多Json,对应一个 List 一个sheet表的一行数据就是一个 Map 一行中的一列,就把当前列头为key,列值为value存到该列的Map中 Map 一个线性Hash Map,以Excel的sheet表顺序,并以sheet表明作为key,sheet表转换Json后的字符串作为value 最后返回一个LinkedHashMap 3. ExcelToJsonPoi.java工具类 这个与上面工具类类似,不过这个是解析本地excel文件不是使用的流,使用迭代遍历sheet工作簿与每行每列的值,将所有类型作为String类型处理返回一个json对象输出至控制台

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值