背景:产品希望能让客户上传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下面,这样可能会更简单些。
当然啦,上面贴的代码不全面,仅供学习。