------这里只是测试类------实际使用的看下面
需要用到ExcelUtils工具类
ExcelUtils的主要作用是把Excel转化成 List<List<Object>>类型的数据,方便遍历
package tech.niua.common.excelimport;import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook;/*** Created by sangyinghao* Date :2022/4/26* Description : excel导入工具类* Version :1.0*/ public class ExcelUtils {private final static String excel2003L =".xls"; //2003- 版本的excelprivate final static String excel2007U =".xlsx"; //2007+ 版本的excel/*** @Description:获取IO流中的数据,组装成List<List<Object>>对象* @param in,fileName* @return* @throws IOException*/public static List<List<Object>> getListByExcel(InputStream in, String fileName) throws Exception{List<List<Object>> list = null;//创建Excel工作薄Workbook work = getWorkbook(in,fileName);if(null == work){throw new Exception("创建Excel工作薄为空!");}Sheet sheet = null; //页数Row row = null; //行数Cell cell = null; //列数list = new ArrayList<List<Object>>();//遍历Excel中所有的sheetfor (int i = 0; i < work.getNumberOfSheets(); i++) {sheet = work.getSheetAt(i);if(sheet==null){continue;}//遍历当前sheet中的所有行for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {row = sheet.getRow(j);if(row==null){continue;}//遍历所有的列List<Object> li = new ArrayList<Object>();for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {cell = row.getCell(y);li.add(getValue(cell));}list.add(li);}}return list;}/*** @Description:根据文件后缀,自适应上传文件的版本* @param inStr,fileName* @return* @throws Exception*/public static 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{throw new Exception("解析的文件格式有误!");}return wb;}/*** @Description:对表格中数值进行格式化* @param cell* @return*///解决excel类型问题,获得数值public static String getValue(Cell cell) {String value = "";if(null==cell){return value;}switch (cell.getCellType()) {//数值型case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {//如果是date类型则 ,获取该cell的date值Date date = DateUtil.getJavaDate(cell.getNumericCellValue());SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");value = format.format(date);;}else {// 纯数字BigDecimal big=new BigDecimal(cell.getNumericCellValue());value = big.toString();//解决1234.0 去掉后面的.0if(null!=value&&!"".equals(value.trim())){String[] item = value.split("[.]");if(1<item.length&&"0".equals(item[1])){value=item[0];}}}break;//字符串类型case STRING:value = cell.getStringCellValue();break;// 公式类型case FORMULA://读公式计算值value = String.valueOf(cell.getNumericCellValue());if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串value = cell.getStringCellValue();}break;// 布尔类型case BOOLEAN:value = " "+ cell.getBooleanCellValue();break;default:value = cell.getStringCellValue();}if("null".endsWith(value.trim())){value="";}return value;}}
package test.excel;import org.junit.Test;import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Field; import java.util.List;public class TestExcel {@Testpublic void importExcel(){String filepath = "/Users/Desktop/sys_user.xlsx";FileInputStream inputStream = null;try {inputStream = new FileInputStream(new File(filepath));//把Excel文件转化成 List<List<Object>>类型的数据List<List<Object>> list = ExcelUtils.getListByExcel(inputStream, filepath);System.out.println(list);//定义第一行List<Object> firstRows = null;//数据不为空if(list != null && list.size() > 0){//拿到第一行firstRows = list.get(0);}//遍历每一行for (int i = 1; i < list.size(); i++) {//拿到这一行List<Object> rows = list.get(i);//初始化对象Demo demo = new Demo();//遍历这一行for (int j = 0; j < rows.size(); j++) {//定义cellVal,拿到每一个的值String cellVal = (String) rows.get(j);//把对象,标题名,值 都传过去TestExcel.setFieldValueByFieldName(demo, firstRows.get(j).toString().trim(), cellVal);}System.out.println(demo);}} catch (Exception e) {e.printStackTrace();}}// @Test // public void testRef(){ // tech.niua.admin.test.domain.Test test = new tech.niua.admin.test.domain.Test(); // test.setId(100L); // test.setName("wangzhen"); // Object id = TestExcel.getFieldValueByFieldName("id", test); // Object username = TestExcel.getFieldValueByFieldName("username", test); // System.out.println(username); // }private static void setFieldValueByFieldName(Object object, String fieldName, Object val) {try {//反射拿到所有的object的属性值Field[] fields = object.getClass().getDeclaredFields();//遍历一遍for (int i = 0; i < fields.length; i++) {//定义一个Field类型的值,遍历给它赋值Field field = fields[i];//如果传过来的fieldName等于field数据中的名称名if(fieldName.equals(field.getName())){//把它set进去field.set(object, val.toString());return;}}} catch (Exception e) {e.printStackTrace();}}private static Object getFieldValueByFieldName(String fieldName, Object object) {try {Field field = object.getClass().getField(fieldName);//设置对象的访问权限,保证对private的属性的访问return field.get(object);} catch (Exception e) { // e.printStackTrace();return null;}} }
主要步骤:
定义一个文件输入流,把excel文件放进输入流
调用ExcelUtils.getListByExcel(inputStream, filepath) 【这里把输入流和路径名当作参数,路径名当作参数是为了拿到文件名的后缀,判断xls还是xlsx,到ExcelUtils里判断版本】拿到excel文件转换成List<List<Object>>类型的数据
如果数据不为空的话,拿到数据中的第一行 list.get(0) 即标题名
for循环遍历每一行 list.get(i) ,在每一行初始化Demo对象(目的要给它赋值)
嵌套for循环遍历每一列rows.get(j),拿到每一个格的值
调用setFieldValueByFieldName方法,在一行内的每一次列遍历的时候都调用一次,而且把对应的标题名也当作参数传进去
每一行遍历结束,一个完整的Demo对象就被赋值成功了,就可以在业务中把它添加进数据库了
setFieldValueByFieldName方法
把对象,标题名,数值 传过去
通过反射拿到对象的属性值,遍历对象的属性值,如果属性名等于传过来的标题名,就可以对齐进行set,把数值set进对象里,做到了赋值
package test.excel;import tech.niua.common.annotation.Excel;/*** Demo实体类*/ public class Demo {public String id;@Excel(name = "姓名")public String name;public String createTime;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCreateTime() {return createTime;}public void setCreateTime(String createTime) {this.createTime = createTime;}@Overridepublic String toString() {return "Demo{" +"id='" + id + '\'' +", name='" + name + '\'' +", createTime='" + createTime + '\'' +'}';} }
如果在实体类中添加注解
下面是可以实际应用的方法!!!!!!!
--改进--
因为通过上传获取服务器文件路径信息,把服务器文件路径返回到前端,再通过传递路径信息到后端对文件路径的文件进行操作
有两个缺点:
1.两次请求,慢
2.客户端可以知道服务器的路径,不安全
点击上传之间上传成功
后端接收到文件,把文件转成输入流传到getObjectList方法中,同时需要传入的还有实体类(因为需要反射获取实体类类型,在方法中给实体类List赋值),返回过来的List<Object>转换成实体类List,然后再通过mybatisplus插入进数据库
Controller层
/*** Excel文件导入* @param file* @return* @throws Exception*/@PostMapping("/imports")@PreAuthorize("hasAuthority('/signature/imports')")//传进来二进制文件数据public ResultJson uploadFile(MultipartFile file) throws Exception {Signature signature =new Signature();List<Object> objects = ObjectList.getObjectList(file,signature);List<Signature> list = (List<Signature>) (List)objects;boolean flag = signatureService.saveOrUpdateBatch(list);if(flag){return ResultJson.ok();}return ResultJson.failure(ResultCode.NOT_UPDATE);}
封装的文件转List<Object>方法
package tech.niua.common.excelimport;import org.springframework.web.multipart.MultipartFile; import tech.niua.common.annotation.Excel; import tech.niua.common.config.NiuaConfig; import tech.niua.common.utils.file.FileUploadUtils;import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Field; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List;public class ObjectList {/*** 封装的将Excel文件信息转换成List<Object>的方法,需要传实体类* @param file* @param object* @return* @throws Exception*/public static List<Object> getObjectList(MultipartFile file, Object object) throws Exception {//通过反射拿到对象Class cls = object.getClass();// 上传文件路径C:/Users/10565/Desktop/niuniu/uploadString filePath = NiuaConfig.getUploadPath();// 上传并返回新文件名称 2022/04/28/3015c5d0-8e05-4e02-b1f6-81440f373b56.xlsxString fileName = FileUploadUtils.upload(filePath, file);//完整的上传文件的路径fileName =filePath+ File.separator+fileName;//把上传的文件转换成输入流FileInputStream fileInputStream = new FileInputStream(new File(fileName));//输入流 和 文件路径 作为参数传入 获取List<List<Object>>类型数据的方法中List<List<Object>> list = ExcelUtils.getListByExcel(fileInputStream,fileName);/*** 将数据转换成List<Object>类型的数据*///初始化标题List<Object> firstRows = null;//如果转换过来的数据不为空,拿到标题if (list != null && list.size() > 0) {firstRows = list.get(0);}//初始化实际数据List<Object> excelDate = new ArrayList<>();//从一开始遍历,为的是拿到数据for (int i = 1; i < list.size(); i++) {//每一行实例化一个List<Object>数据,后面插入的也是这些List<Object> rows = list.get(i);//实例化对象,方便赋值Object obj = cls.newInstance();//对obj的每一个的字段进行赋值for (int j = 0; j < rows.size(); j++) {//把excel转过来的数据的每个字段的值转换成String类型String cellVal = (String) rows.get(j);//对obj进行赋值(实体类,字段名,字段值)ObjectList.setFieldValueByFieldName(obj, firstRows.get(j).toString().trim(), cellVal);}//添加进List<Object>,每个obj都是一条数据excelDate.add(obj);}return excelDate;}//调用一次这个方法只能给一条数据的一个字段赋值public static void setFieldValueByFieldName(Object object, String fieldName, Object val) {try {//反射拿到实体类每个变量的数据Field[] fields = object.getClass().getDeclaredFields();//把实体类每个变量遍历一遍for (int i = 0; i < fields.length; i++) {//一个实体类的一个变量,代表一种类型Field field = fields[i];field.setAccessible(true);//拿到当前实体类字段的Excel注解Excel excel = field.getAnnotation(Excel.class);if(excel==null){continue;}//如果excel转化过来的字段值和便利店实体类的遍历的注解名相同,说明对应上了,赋值!!if(fieldName.equals(excel.name())||fieldName.equals(field.getName())){//把属性值set进对象/*** 保证Integer和Long和LocalDateTime类型(实体类)也能被赋值*/if(field.getType()==Integer.class){//把有这个类型的要被赋值的对象和这个类型的数值当作参数,可以赋值field.set(object,Integer.valueOf(val.toString()));} else if(field.getType()==Long.class){field.set(object,Long.valueOf(val.toString()));}else if(field.getType()== LocalDateTime.class){DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime time = LocalDateTime.parse(val.toString(),df);field.set(object,time);}elsefield.set(object, val);return;}}} catch (Exception e) {e.printStackTrace();}}}
package tech.niua.common.excelimport;import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook;/*** Created by sangyinghao* Date :2022/4/26* Description : excel导入工具类* Version :1.0*/ public class ExcelUtils {private final static String excel2003L =".xls"; //2003- 版本的excelprivate final static String excel2007U =".xlsx"; //2007+ 版本的excel/*** @Description:获取IO流中的数据,组装成List<List<Object>>对象* @param in,fileName* @return* @throws IOException*/public static List<List<Object>> getListByExcel(InputStream in, String fileName) throws Exception{List<List<Object>> list = null;//创建Excel工作薄Workbook work = getWorkbook(in,fileName);if(null == work){throw new Exception("创建Excel工作薄为空!");}Sheet sheet = null; //页数Row row = null; //行数Cell cell = null; //列数list = new ArrayList<List<Object>>();//遍历Excel中所有的sheetfor (int i = 0; i < work.getNumberOfSheets(); i++) {sheet = work.getSheetAt(i);if(sheet==null){continue;}//遍历当前sheet中的所有行for (int j = sheet.getFirstRowNum(); j <= sheet.getLastRowNum(); j++) {row = sheet.getRow(j);if(row==null){continue;}//遍历所有的列List<Object> li = new ArrayList<Object>();for (int y = row.getFirstCellNum(); y < row.getLastCellNum(); y++) {cell = row.getCell(y);li.add(getValue(cell));}list.add(li);}}return list;}/*** @Description:根据文件后缀,自适应上传文件的版本* @param inStr,fileName* @return* @throws Exception*/public static 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{throw new Exception("解析的文件格式有误!");}return wb;}/*** @Description:对表格中数值进行格式化* @param cell* @return*///解决excel类型问题,获得数值public static String getValue(Cell cell) {String value = "";if(null==cell){return value;}switch (cell.getCellType()) {//数值型case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {//如果是date类型则 ,获取该cell的date值Date date = DateUtil.getJavaDate(cell.getNumericCellValue());SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");value = format.format(date);;}else {// 纯数字BigDecimal big=new BigDecimal(cell.getNumericCellValue());value = big.toString();//解决1234.0 去掉后面的.0if(null!=value&&!"".equals(value.trim())){String[] item = value.split("[.]");if(1<item.length&&"0".equals(item[1])){value=item[0];}}}break;//字符串类型case STRING:value = cell.getStringCellValue();break;// 公式类型case FORMULA://读公式计算值value = String.valueOf(cell.getNumericCellValue());if (value.equals("NaN")) {// 如果获取的数据值为非法值,则转换为获取字符串value = cell.getStringCellValue();}break;// 布尔类型case BOOLEAN:value = " "+ cell.getBooleanCellValue();break;default:value = cell.getStringCellValue();}if("null".endsWith(value.trim())){value="";}return value;}}
通用Path实体类
package tech.niua.common.domain;import lombok.Data;@Data public class Path {private String url;private String fileName;private String path; }
前端直接把文件传到后端
关于文件路径部分以及上传部分
NiuaConfig
![]()
![]()
所以filePath是
C:/Users/10565/Desktop/niuniu/upload
![]()
![]()
fileName是/年/月/日/文件名
拼接起来就可以拿到服务器上文件路径