环境:ssm
参考工具类(自己改了一些):https://blog.csdn.net/aishenla/article/details/52890235
功能实现:
表格内所有行都是必需的信息,缺少了会不进行存入,并会提示
唯一信息已存在的行,不进行存入,并会提示
第一次上传:
结果:
第二次相同上传:
所有行缺失:
部分缺失以及存在:
直接点击上传:
jsp:
<form action="${appPath}/upload" method="post" enctype="multipart/form-data">
<label>文件域:</label>
<div>
<input type="file" name="file" />
<input type="file" name="file" />
</div>
<br>
<input type="submit" value="点击上传">
</form>
controller:
@RequestMapping(value="/upload",produces = {"text/html;charset=utf-8"})
@ResponseBody
@Transactional
public String upload(@RequestParam("file")MultipartFile[] multipartFiles, Model model) throws
IOException {
return userService.find(multipartFiles[0]);
}
service:
public String find(MultipartFile file){
Map<String, Object> jsonMap = new HashMap<String, Object>();
Map<String,Object> result = new HashMap<String, Object>();
//去掉缺少必填信息的行和唯一信息在数据库内已存在的行,并记录错误行号和信息
Map<String,String> errInfo = new HashMap();
//没问题的行:唯一信息,行号
Map<String,String> ids = new HashMap();
//唯一信息
List<String> idz = new LinkedList<>();
if(file.isEmpty()){
jsonMap.put("status",0);
jsonMap.put("msg","文件不存在");
jsonMap.put("content",null);
return JSONObject.fromObject(jsonMap).toString();
}
InputStream in = null;
try {
in = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
List<List<Object>> listob = null;
try{
//因为要导入的excel比较特殊,不是常规的一行类别,其他行都是数据,所以我需要根据具体模板来读取excel
//已在工具内完成检查是否缺少信息
result = new ImportExcelUtil().getBankListByExcel(in,file.getOriginalFilename(),2);
if(result.get("status")!=null)
return JSONObject.fromObject(result).toString();
else {
listob = (List<List<Object>>) result.get("list");
ids = (Map<String, String>) result.get("ids");
idz = (List<String>) result.get("idz");
if (result.get("errInfo")!=null){
errInfo = (Map<String, String>) result.get("errInfo");
}
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
List<User> u = userMapper.find(idz);
Iterator i = u.iterator();
while (i.hasNext()){
User user = (User)i.next();
System.out.println((user.getUsername()!=null)+"用户名:"+user.getUsername());
//向错误信息中加入唯一信息
errInfo.put("第"+(Integer.parseInt(ids.get(user.getUsername()))+1)+"行 "+user.getUsername(),"已存在");
ids.remove(user.getUsername());
//这里有个坑,因为hashmap不按插入顺序排的,所以索引与list不是对应的,然后用key作为对象,查找在list的索引,在以此删除
int ind = idz.indexOf(user.getUsername());
idz.remove(ind);
}
if (idz.size()==0){
jsonMap.put("msg","全部内容已存在或者不完整");
jsonMap.put("status",0);
jsonMap.put("content", errInfo);
return JSONObject.fromObject(jsonMap).toString();
}
List<User> voList = new ArrayList();
Set<Map.Entry<String,String>> ex= ids.entrySet();
i = ex.iterator();
while (i.hasNext()){
Map.Entry<String,String> e = (Map.Entry<String, String>) i.next();
User v = new User();
v.setUsername(String.valueOf(listob.get(Integer.parseInt(e.getValue())).get(0)));
// System.out.println(String.valueOf(listob.get(o).get(0)));
v.setPassword(String.valueOf(listob.get(Integer.parseInt(e.getValue())).get(1)));
// System.out.println(String.valueOf(listob.get(o).get(1)));
voList.add(v);
}
//完成后插入装好的voList,插入也可以构造成一句(批量),提高效率:
//INSERT INTO 表名(部分列名) VALUES (对应的列值集合1)<,(对应的列值集合2)>;
int resultCode=this.insert(voList);
if(resultCode>0){
if(errInfo.size()!=0) {
jsonMap.put("status", 10);
jsonMap.put("content", errInfo);
jsonMap.put("msg","部分添加成功");
} else {
jsonMap.put("status",1);
jsonMap.put("content",null);
jsonMap.put("msg","添加成功");
}
return JSONObject.fromObject(jsonMap).toString();
} else {
jsonMap.put("msg","添加失败");
jsonMap.put("status",0);
jsonMap.put("content",null);
return JSONObject.fromObject(jsonMap).toString();
}
}
public int insert(List<User> voList) { return userMapper.insert(voList); }
mapper:
@Select({"<script>"+"SELECT username From user WHERE username IN "
+"<foreach collection='ids' item='id' open='(' separator=',' close=')'>"
+"#{id}"+"</foreach>"+"</script>"})
List<User> find(@Param("ids") List<String> ids);
@Insert({
"<script>"
+"insert into user"
+" (username,password)"
+" values"
+"<foreach collection='list' item='item' index='index' separator=','>"
+"("
+"#{item.username},"
+"#{item.password}"
+")"
+"</foreach>"
+"</script>"})
int insert(@Param("list") List<User> list);
工具类:
public class ImportExcelUtil {
private final static String excel2003L =".xls"; //2003- 版本的excel
private final static String excel2007U =".xlsx"; //2007+ 版本的excel
private Map<String,Object> result = new HashMap();
private Map<String,String> errInfo = new HashMap();
//没问题的行:唯一信息,行号
private Map<String,String> ids = new HashMap();
//唯一信息
private List<String> idz = new LinkedList<>();
/**
* 描述:获取IO流中的数据,组装成List<List<Object>>对象
* @param in,fileName
* @return
* @throws
*/
public Map<String,Object> getBankListByExcel(InputStream in, String fileName,int column)
throws Exception {
//创建Excel工作薄
Workbook work = this.getWorkbook(in,fileName);
if(null == work){
result.put("status",0);
result.put("msg","文件为空或文件格式有误");
result.put("content",null);
return result;
}
//为了好删除不用的一行
List<List<Object>> list = new LinkedList<List<Object>>();
Sheet sheet = null;
Row row = null;
Cell cell = null;
//遍历Excel中所有的sheet
for (int i = 0; i < work.getNumberOfSheets(); i++) {
sheet = work.getSheetAt(i);
if(sheet==null){continue;}
//遍历当前sheet中的所有行,第二行开始(排除标题行)
for (int j = sheet.getFirstRowNum()+1; j <= sheet.getLastRowNum(); j++) {
System.out.println("j值"+j);
row = sheet.getRow(j);
//遍历所有的列
List<Object> li = new ArrayList<Object>();
System.out.println(row.getLastCellNum());
//就getLastCellNum()是某行的列数而不是索引
//getFirstCellNum()弄得头疼
int y = 0;
for (; y < column; y++) {
cell = row.getCell(y);
if(cell==null){
li.add(-1);
Collections.swap(li,y,0);
errInfo.put("第"+j+"行","缺少信息");
list.add(li);
break;
}
System.out.println(cell.getCellType());
System.out.println("cell值"+this.getCellValue(cell));
if(this.getCellValue(cell)!=null)
//保存当前行中每列
li.add(this.getCellValue(cell));
else {
li.add(-1);
Collections.swap(li,y,0);
errInfo.put("第"+j+"行",sheet.getRow(0).getCell(y)+"为空");
list.add(li);
cell = null;
break;
}
}
if(cell==null){
continue;
}
idz.add((String)this.getCellValue(row.getCell(0)));
ids.put((String)this.getCellValue(row.getCell(0)),(j-1)+"");
//保存当前行
list.add(li);
}
}
if(idz.size()>0){
result.put("idz",idz);
result.put("ids",ids);
result.put("list",list);
if (errInfo.size()>0){
result.put("errInfo",errInfo);
}
} else {
result.put("status",0);
result.put("msg","所有行缺少信息");
result.put("content",null);
}
work.close();
return result;
}
/**
* 描述:根据文件后缀,自适应上传文件的版本
* @param inStr,fileName
* @return
* @throws Exception
*/
public Workbook getWorkbook(InputStream inStr,String fileName) throws Exception{
Workbook wb = null;
String fileType = fileName.substring(fileName.lastIndexOf("."));
if(excel2003L.equals(fileType)){
wb = new HSSFWorkbook(inStr); //2003-
}else if(excel2007U.equals(fileType)){
wb = new XSSFWorkbook(inStr); //2007+
}else{
return null;
}
return wb;
}
/**
* 描述:对表格中数值进行格式化
* @param cell
* @return
*/
public Object getCellValue(Cell cell){
Object value = null;
DecimalFormat df = new DecimalFormat("0"); //格式化number或String字符
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd"); //日期格式化
DecimalFormat df2 = new DecimalFormat("0.00"); //格式化数字
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
value = cell.getRichStringCellValue().getString();
break;
case Cell.CELL_TYPE_NUMERIC:
if("General".equals(cell.getCellStyle().getDataFormatString())){
value = df.format(cell.getNumericCellValue());
}else if("m/d/yy".equals(cell.getCellStyle().getDataFormatString())){
value = sdf.format(cell.getDateCellValue());
}else{
value = df2.format(cell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_BOOLEAN:
value = cell.getBooleanCellValue();
break;
case Cell.CELL_TYPE_BLANK:
value = null;
break;
default:
break;
}
return value;
}
}
应该还有不少问题,不过先告一段落
map遍历
map里面不能重复,后面加入的会覆盖前面的
set会去掉map内重复的
Set<Map.Entry<String,String>> entry= ids.entrySet();
i = entry.iterator();
while(i.hasNext()){
Map.Entry<String,String> e = (Map.Entry<String, String>) i.next();
//TODO something
}