背景:产品希望能让客户上传csv格式的文件,Java后端解析文件并将记录更新到mysql数据库。

上网搜了下api,于是找到了opencsv-2.3.jar这个jar包,pom依赖如下:

<!-- https://mvnrepository.com/artifact/net.sf.opencsv/opencsv -->
<dependency>
    <groupId>net.sf.opencsv</groupId>
	<artifactId>opencsv</artifactId>
	<version>2.3</version>
    </dependency>

不说废话,先贴代码:

/**
* 批量导入数据
* 
* @param file
* @param request
* @return
* @throws IOException    *
 */
public Result<Map<String, Integer>> batchImport(@RequestParam("file") MultipartFile file,
	HttpServletRequest request) {
File dir = new File(localpath);
      if(!dir.isDirectory()) {
		dir.mkdirs();
       }
File localFile = new File(localpath + file.getOriginalFilename());

try {if (!localFile.exists()) {localFile.createNewFile();}BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(localFile));out.write(file.getBytes());out.flush();out.close();// File files = new File("E:\\template.csv");//本机测试FileReader fReader = new FileReader(localFile);CSVReader csvReader = new CSVReader(fReader);// 去掉表头String[] tableHeader = csvReader.readNext();if (!tableHeader[0].contains("WeChat")) {csvReader.close();throw new BusinessException("文件内容与模板要求不一致,请检查确认后重新导入");}while (true) {String[] ss = csvReader.readNext();if (ss != null) {total++;if (ss.length > 1) {csvReader.close();throw new BusinessException("文件内容与模板要求不一致,请检查确认后重新导入");}for (String s : ss) {if (!s.trim().matches(RegexPattern.WECHART)) {isError = true;formatError.add(count++);break;}staffWx = staffWxRepository.findByWxNo(s);// 存在且已监控,则不做处理if (null != staffWx && staffWx.getMonitorStatus()) {// 如果创建人为null则将当前操作人置为创建人if (null == staffWx.getCreator()) {staffWx.modify(staffWx.getWxNo(), staffWx.getRemark(), Boolean.TRUE,staff.getEhrAccount(), staff.getEhrAccount());}count++;break;} else if (null != staffWx && !staffWx.getMonitorStatus()) {// 存在但未监控,则修改为监控状态if (null == staffWx.getCreator()) {staffWx.modify(staffWx.getWxNo(), staffWx.getRemark(), Boolean.TRUE,staff.getEhrAccount(), staff.getEhrAccount());}staffWx.modify(staffWx.getWxNo(), staffWx.getRemark(), Boolean.TRUE, staff.getEhrAccount(),staffWx.getCreator());count++;} else {// 不存在,则新增并监控staffWx = new StaffWx();staffWx.add(s, null, Boolean.TRUE, staff.getEhrAccount(), null);staffWxRepository.save(staffWx);count++;}}} else {break;}}if (isError) {csvReader.close();throw new BusinessException("文件第" + formatError + "行存在非法的微信号或字符,请检查确认后重新导入");}csvReader.close();} catch (IOException e) {e.printStackTrace();throw new BusinessException("文件内容与模板要求不一致,请检查确认后重新导入");} finally {localFile.delete();}Map<String, Integer> result = new HashMap<String, Integer>();result.put("successNum", count - 2);result.put("repetitionNum", total - count + 2);return Result.success(result);}

注意:

这个地方用的是springboot提供的MultipartFile来接收前端上传的文件,然后将文件流写到本机指定的文件中,接着再用opencsv提供的api读取文件处理。

因为我这个地方只用到了解析csv文件,所以只讲这个方面。opencsv提供了两个读取文件中记录的方法:

String[] tableHeader = csvReader.readNext();//每次读取一行记录,而且不跳过空行(这个在涉及到行号校验的时候很重要)

List<String[]> list = csvReader.readAll();//一次读取所有的记录,但是会过滤空行(开始我用的是这个方法,发现行号不对,不得已才改成上面的方法)

这里插播一点:印象中在创建文件的时候,如果父目录不存在则会自定创建父目录,开始我也是这样写的代码,当同事问我的时候我也很肯定的说可以,后来不放心,测试了一下,发现尴尬了,报错“系统找不到指定路径”......所以才有了下面这段代码:

File dir = new File(localpath);
      if(!dir.isDirectory()) {
		dir.mkdirs();
       }

其实这个操作是为了将临时生成的文件存放在这个位置,当然也可以把文件放咱classpath下面,这样可能会更简单些。

当然啦,上面贴的代码不全面,仅供学习。