本人经过十次打磨,发明excle操作表格 ,简单容易入手,速度效率快 !!!!!本文用的是阿里巴巴的poi!
1.导入pom依赖--第一步
<!-- EasyExcel start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.2.1</version>
</dependency>
<!-- EasyPoi start -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>3.2.0</version>
</dependency>
<!-- EasyPoi end -->
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop-transcoder-allinone</artifactId>
<version>2.4</version>
</dependency>
2.下载excle
场景介绍:系统需要用户导入数据 常常限制excle的规范 ,所以需要下载模板进行数据导入,整体实现通过HttpServletResponse response 下载文件 把需要下载的文件放在resources目录下 --springboot会自动识别文件
--- 代码如下--
// @ApiOperation(value = "简单测试:下载“分类导入模板文件”", notes = "简单测试:下载“分类导入模板文件”")
@GetMapping("/simple/downloadTemplate")
public void simpleDownloadTemplate(HttpServletResponse response) throws IOException {
//定义resources文件下的路径
String fileName = "分类导入模板.xlsx";
Resource r = new ClassPathResource(fileName);
try (
FileInputStream fileInputStream = new FileInputStream(r.getFile());
ServletOutputStream outputStream = response.getOutputStream();
) {
response.setContentType("application/force-download");
try {
// fileName = new String(fileName.getBytes("utf-8"), "utf-8");
fileName = URLEncoder.encode(fileName, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setHeader("Content-Disposition", "attachment;filename=" + UUID.randomUUID() + "_" + fileName);
//设置下载文件uuid+的名称
IOUtils.copy(fileInputStream, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
2.1效果如下
3.上传文件Excle
场景介绍:用户下载完文件 然后进行数据上传 --通常需要你去解析数据然后存入数据库中 在确定返回 值 是不是成功
所以有二个问题:1.存储数据,2.存放excle表格到系统里面
3.1添加工具类-- fileUtil
可以自己研究或修改
convertMultipartFileToFile 这个方法主要是判断文件是否为 xlsx 文件 如果 不是 就报错,是的就存入本地
package com.example.annualmeetingactivitiesmaster.demos.utils;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;
public class FileUtil {
/**
* 转换MultipartFile对象为java.io.File类型
*
* @param multipartFile
* @return
*/
public static File convertMultipartFileToFile(MultipartFile multipartFile) {
File result = null;
try {
/**
* UUID.randomUUID().toString()是javaJDK提供的一个自动生成主键的方法。
* UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,
* 它保证对在同一时空中的所有机器都是唯一的,是由一个十六位的数字组成,表现出来的形式。
* 由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,
* 过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,
* 全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),
* UUID的唯一缺陷在于生成的结果串会比较长。
*
*
* File.createTempFile和File.createNewFile()的区别:
* 后者只是创建文件,而前者可以给文件名加前缀和后缀
*/
//这里对生成的文件名加了UUID随机生成的前缀,后缀是null
result = File.createTempFile(UUID.randomUUID().toString(), null);
multipartFile.transferTo(result);
result.deleteOnExit();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 根据url获取文件对象
*
* @param fileUrl
* @return
*/
public static File downloadFile(String fileUrl) {
File result = null;
try {
result = File.createTempFile(UUID.randomUUID().toString(), null);
URL url = new URL(fileUrl);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(3000);
BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(result));
byte[] car = new byte[1024];
int l = 0;
while ((l = bis.read(car)) != -1) {
bos.write(car, 0, l);
}
bis.close();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* @param request
* @return
*/
public static String getRealPath(HttpServletRequest request) {
ServletContext sc = request.getSession().getServletContext();
String uploadDir = sc.getRealPath("/upload");
return uploadDir;
}
public static boolean saveFile(String savePath, String fileFullName, MultipartFile file) throws IOException {
File uploadFile = new File(savePath + fileFullName);
FileUtils.writeByteArrayToFile(new File(savePath, fileFullName), file.getBytes());
return uploadFile.exists();
}
public static String mergeFile(int chunksNumber, String ext, String uploadFolderPath,
HttpServletRequest request) {
//合并分片流
String mergePath = uploadFolderPath;
String destPath = getRealPath(request);// 文件路径
String newName = System.currentTimeMillis() + ext;// 文件新名称
SequenceInputStream s;
InputStream s1;
try {
s1 = new FileInputStream(mergePath + 0 + ext);
String tempFilePath;
InputStream s2 = new FileInputStream(mergePath + 1 + ext);
s = new SequenceInputStream(s1, s2);
for (int i = 2; i < chunksNumber; i++) {
tempFilePath = mergePath + i + ext;
InputStream s3 = new FileInputStream(tempFilePath);
s = new SequenceInputStream(s, s3);
}
//分片文件存储到/upload/chunked目录下
StringBuilder filePath = new StringBuilder();
filePath.append(destPath).append(File.separator).append("chunked").append(File.separator);
saveStreamToFile(s, filePath.toString(), newName);
// 删除保存分块文件的文件夹
deleteFolder(mergePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return newName;
}
private static boolean deleteFolder(String mergePath) {
File dir = new File(mergePath);
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
try {
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return dir.delete();
}
private static void saveStreamToFile(SequenceInputStream inputStream, String filePath, String newName)
throws Exception {
File fileDirectory = new File(filePath);
synchronized (fileDirectory) {
if (!fileDirectory.exists()) {
if (!fileDirectory.mkdir()) {
throw new Exception("文件夹创建失败,路径为:" + fileDirectory);
}
}
if (!fileDirectory.exists()) {
if (!fileDirectory.mkdir()) {
throw new Exception("文件夹创建失败,路径为:" + fileDirectory);
}
}
}
OutputStream outputStream = new FileOutputStream(filePath + newName);
byte[] buffer = new byte[1024];
int len = 0;
try {
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
outputStream.flush();
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
outputStream.close();
inputStream.close();
}
}
}
3.2 把xlsx存放系统路径
开发路径和打成jar包后 路径是不一样的!!!!!
打成jar包后 无法识别 资源目录 也就是说无法在往jar包里面存放文件,需要把文件存在本地,也就是在外地添加文件夹。
resources文件 生成的路径匹配问题(开发环境使用存储方式)
Resource resource = new ClassPathResource("resources路径"); 生成的文件 存在打包好的 路径下, 用于开发环境。
打成jar包或者war包 上线环境 创建 appconfig.java
打jar包上传静态资源生成系统路径,获取项目所在的文件夹
@Component public class AppConfig { /** * 获取项目所在的文件夹 * @return */ public String getResPhysicalPath(){ ApplicationHome home = new ApplicationHome(getClass()); File jarFile = home.getSource(); //项目部署的目录 if(jarFile != null){ String path = jarFile.getParentFile().getPath(); return path; } return null; } }
转换MultipartFile转换File类型
file = FileUtil.convertMultipartFileToFile(uploadFile); //把MultipartFile转换File类型
3.3 进行上传文件确定文件格式,确定上传文件路径(开发环境)
public String saveByExcelFileV1(@RequestParam("file") MultipartFile uploadFile, HttpServletRequest request) {
File file = null; //判断文件格式
String useridentity = null;
//把MultipartFile转换File类型
//判断文件类型是否正确 --不建议这样写 有漏洞
String originalFilename = uploadFile.getOriginalFilename();
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
//判断文件是不是xlsx文件 如果不是 就返回异常
if (!".xlsx".equalsIgnoreCase(fileType)) {
return "返回值"
}
file = FileUtil.convertMultipartFileToFile(uploadFile)//把MultipartFile转换File类型
//如果是就存入我的文件夹里面
/**1.存在开发环境中
Resource resource = new ClassPathResource("路径名"); //资源文件路径
*log*.info("contextPath:{}", resource.getURL());
String fileName = UUID.*randomUUID*().toString(); //获取文件随机名
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1); //获取文件后缀
File fileDir = new File();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd/");
String directory = simpleDateFormat.format(new Date()); //创建时间文件夹
//创建文件夹
File dir = new File(resource.getFile()+"/"+directory);
if (!dir.exists()) {
dir.mkdirs();
}
//
File resultImg = new
File(resource.getFile()+"/"+directory,fileName+"."+"xlsx");
log.info("图片上俩,新文件名:" + resultImg.getPath());
//上传到文件夹中
file.transferTo(resultImg);
**/
}
3.4 打包 上线环境 存放系统路径
public ResponseResult saveByExcelFileV1(@RequestParam("file") MultipartFile uploadFile, HttpServletRequest request) {
File file = null;
String useridentity = null;
//把MultipartFile转换File类型
//判断文件类型是否正确 --不建议这样写 有漏洞
String originalFilename = uploadFile.getOriginalFilename();
String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
if (!".xlsx".equalsIgnoreCase(fileType)) {
return ResponseResult.fail(ResultCode.XlXSERRORR.getMsg());
}
/**存入系统路径
//file 为 web层上传的 file文件
dir = new File( new AppConfig(). getResPhysicalPath()+"/系统环境的文件夹"+"/"+ directory);
if (!dir.exists()) {
dir.mkdirs();
}
log.info("图片上传,保存位置:" +new AppConfig(). getResPhysicalPath()+"/系统环境的文件夹"+"/"+ directory);
//3.给文件重新设置一个名字
//后缀
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + suffix;
//4.创建这个新文件
File newFile = new File( new AppConfig(). getResPhysicalPath() +"/static/bookletsImges"+"/"+ directory + newFileName);
log.info("图片上俩,新文件名:" + newFile.getPath());
//5.复制操作 线程
synchronized (this) {
try {
file.transferTo(newFile); //保存文件
}
**/
}
4.导出数据 变成 Exel文件
确定2个方向: 1.数据是集合 2.变成Exel 的头和列
4.1 确认 实体类的列 下面是示例
package com.example.annualmeetingactivitiesmaster.demos.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
*
* @TableName xlsx_data
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName( value ="xlsx_data")
@ExcelIgnoreUnannotated //忽悠字段导入
public class XlsxData implements Serializable {
/**
* id
*/
// @ExcelProperty(index = 0, value ="唯一标识符")
@TableId(type = IdType.AUTO)
@Size(max= 255,message="编码长度不能超过255")
// @NotNull(message="[id]不能为空")
// @ApiModelProperty("id")
private Integer xslxId;
/**
* 姓名
*/
@ExcelProperty(index = 1, value ="姓名")
@Size(max= 255,message="编码长度不能超过255")
// @ApiModelProperty("姓名")
// @Length(max= 255,message="编码长度不能超过255")
private String xslxName;
/**
* 手机号
*/
// @ApiModelProperty("手机号")
@ExcelProperty(index = 2, value ="手机号")
private String xslxChargenumber;
/**
* 公司
*/
@ExcelProperty(index = 3, value ="公司")
@Size(max= 255,message="编码长度不能超过255")
// @ApiModelProperty("公司")
// @Length(max= 255,message="编码长度不能超过255")
private String xslxFirm;
/**
* 属于那位用户
*/
// @ExcelProperty(index = 4, value ="测试")
// @ApiModelProperty("属于那位用户")
private Integer xslxUserid;
}
4.2确认数据 变成集合 转换成Exel
@GetMapping(value = "/xlsx/data/download")
public void exportData(HttpServletResponse response, HttpServletRequest request) throws IOException {
String useridentity = null ; //存储用户id
try {
String token = request.getHeader("token");
Claims obj = parseJWT(token); //使用的token解决方法 ,没有就删除
useridentity = String.valueOf(obj.getSubject());
log.info(useridentity + "用户id"); //解析出用户的id 进行存储 作为标识 确定导入的数据隶属与那个用户
} catch (Exception e) {
throw new RuntimeException(ResultCode.TOKEN_ERROR.getMsg());
}
String fileName = URLEncoder.encode("xlsx用户数据", "UTF-8");
List<XlsxData> xlsxData = this.xlsxService.selectData(useridentity); //修改成自己查询出来的数据集合
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
log.info(xlsxData.toString() + "用户查询的数据");
EasyExcel.write(response.getOutputStream(), XlsxData.class).sheet("模板").doWrite(xlsxData);
}
4.3 下载即可 就会正常展示数据
5.上传文件 解析Excel 数据 比较复杂
确定方向 1.数据属于那一列 映射实体,解析数据时候确认出格式
5.1 展示代码 ,不懂可以问我 需要添加 线程锁,不然数据会出问题,把数据封装好,直接给web层即可。
@Transactional(propagation = Propagation.REQUIRED)
public List<XlsxData> showData(File file,String token) throws IOException {
//添加线程锁
synchronized (this) {
List<XlsxData> list = new ArrayList<>();
XSSFWorkbook hssfWorkbook = new XSSFWorkbook(Files.newInputStream(file.toPath())); //获取工作簿下sheet的个数
int sheetNum = hssfWorkbook.getNumberOfSheets();
XSSFCell cell = null;
System.out.println("该excel文件中总共有:" + sheetNum + "个sheet");
if (sheetNum>2){
list.add(null);
return list;
// throw new RuntimeException("文件中sheet数量超过两个");
}
//遍历工作簿中的所有数据
for (int i = 0; i < sheetNum; i++) {
//读取第i个工作表
System.out.println("读取第" + (i + 1) + "个sheet");
XSSFSheet sheet = hssfWorkbook.getSheetAt(i);
//获取最后一行的num,即总行数。此处从0开始
int maxRow = sheet.getLastRowNum();
for (int row = 0; row <= maxRow; row++) {
//获取最后单元格num,即总单元格数 ***注意:此处从1开始计数***
int maxRol = sheet.getRow(row).getLastCellNum();
System.out.println("--------第" + row + "行的数据如下--------");
for (int rol = 0; rol < maxRol; rol++) {
System.out.print(sheet.getRow(row).getCell(rol) + " ");
cell = sheet.getRow(row).getCell(rol);
}
if (cell != null && cell.getCellType() != cell.CELL_TYPE_BLANK && row >= 2) {
XSSFCell cell3 = sheet.getRow(row).getCell(0);
System.out.println(cell3.toString() + "姓名");
XSSFCell cell1 = sheet.getRow(row).getCell(1);
System.out.println(cell1.toString() + "手机号");
XSSFCell cell2 = sheet.getRow(row).getCell(2);
System.out.println(cell2.toString() + "公司名字");
String xslxChargenumber = cell2.toString();
Pattern pattern = Pattern.compile("[0-9]*");
Matcher isNum = pattern.matcher(cell2.toString());
if (!isNum.matches()) { //判断手机号
xslxChargenumber = "0";
} else if (xslxChargenumber == null || xslxChargenumber.equals("")) {
xslxChargenumber = "0";
}
Integer integer = Integer.valueOf(xslxChargenumber);
//转换用户id
Integer userid = Integer.valueOf(token);
list.add(new XlsxData(null, cell3.toString(), xslxChargenumber ,cell2.toString(), userid));
}
}
}
int i = xlsxDataMapper.insertBatchSomeColumn(list); //插入数据
System.out.println(i);
System.out.println(list);
return list;
}
}
6.最后分享一个创建网络url的方法
//协议 :// ip地址 :端口号 / 文件目录(/images/2020/03/15/xxx.jpg
String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + '/' + "static/bookletsImges/" + directory + newFileName;
log.info("图片上传,访问URL:" + url);
map.put("url", url);
谢谢大家,有问题可以私信与我