PART1:第一阶段:将上传的excel存储在服务器文件系统的一个绝对路径下,并在前台页面上提供导入导出按钮,能够把存在服务器某个路径下的excel表格等导出来以及把某些文件导入到服务器某个目录下存储起来,其中出现了部分问题并从问题当中学到了经验。
开发步骤:咱们玩的是maven或者说javaweb项目,那么步骤也就是那几步喽,导个jar包或者写个maven依赖坐标,写几个配置文件或者工具类或者XxxTemplate类,供咱们集成某个插件或者技术使用,然后SSM【前台–>controller–>service—>dao+entity+mybatis映射文件中的.xml文件,里面写了很多操作数据库的增删该查】,这不就一条路走通了嘛
将上传的excel存储在服务器的一个绝对路径下,并提供下载按钮,能够把存在服务器某个路径下的excel表格等导出来。(在这里当时出现过一个很大的问题就是,之前我们就考虑到说只能存excel没考虑到客户有可能会把txt或者JPG照片等也传上去存下来,隔一段时间再取出来,后来就在项目的工具类中把txt呀、图片呀等都加进去了,就加了一个文件类型判断)
PART1-1:SSM中
DownloadController.java【文件下载】
/**
* Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
*/
package com.xinhuize.internal.modules.sediment.web.sedimentdata;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.xinhuize.internal.common.config.Global;
import com.xinhuize.internal.common.web.BaseController;
import com.xinhuize.internal.modules.sediment.entity.sedimentData.SedimentData;
/**
*
* @author HHB
* @version 2021年8月28日
*/
@Controller
@RequestMapping("${adminPath}/sedimentdata/Download")
public class DownloadController extends BaseController {
/**
*
* @param session
* @param response
* @param sedimentData
* @param request
* @param redirectAttributes
* @param model
* @return
* @throws IOException
* @author HHB
*/
@SuppressWarnings("unused")
@RequestMapping("excelDownload")
public String excelDownload(HttpSession session, HttpServletResponse response, SedimentData sedimentData, HttpServletRequest request,
RedirectAttributes redirectAttributes, Model model) throws IOException {
//得到选择的年份,作为第一层文件夹名称
String sedSelectedYear = sedimentData.getSedSelectedYear();
//得到设备名称,作为第二层文件夹名称
String sedimentEquipmentName = sedimentData.getSedimentEquipmentName();
//得到表名,作为第三层文件夹名称
String sedimentTableName = sedimentData.getSedimentTableName();
//String filePath = "D:/xinhuize" + "saveExcel/" + sedSelectedYear + "/" + sedimentEquipmentName + "/" + sedimentTableName + "/";// 文件保存的第一层文件夹 ,组合而来
String filePath = "/usr/local/xinhuize-excel-save" + "/" + sedSelectedYear + "/" + sedimentEquipmentName + "/" + sedimentTableName + "/";// 文件保存的第一层文件夹 ,组合而来
File[] fileListDownLoad = new File(filePath).listFiles();
if (fileListDownLoad == null) {
addMessage(redirectAttributes, "下载失败,请联系管理员");
}else {
for (File file : fileListDownLoad) {
if (file.isFile()) {
String name = file.getName();
/* 第二步:根据已存在的文件,创建文件输入流 */
InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
/* 第三步:创建缓冲区,大小为流的最大字符数 */
byte[] buffer = new byte[inputStream.available()]; // int available() 返回值为流中尚未读取的字节的数量
/* 第四步:从文件输入流读字节流到缓冲区 */
inputStream.read(buffer);
String fileName = file.getName();// 获取文件名
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("utf-8"), "utf-8"));
response.addHeader("Content-Length", "" + file.length());
/* 第六步:创建文件输出流 */
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
if (file.isFile() && file.getName().endsWith(".xls")) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
setResponseHeader(response, fileName);
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
setResponseHeader(response, fileName);
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
/* 第七步:把缓冲区的内容写入文件输出流 */
outputStream.write(buffer);
/* 第八步:刷空输出流,并输出所有被缓存的字节 */
outputStream.flush();
/* 第九步:关闭输出流 */
outputStream.close();
/* 第五步: 关闭输入流 */
inputStream.close();
}
}
addMessage(redirectAttributes, "下载成功");
}
return "redirect:" + Global.getAdminPath() + "/sedimentdata/sedimentData/exportWholeFile?repage";
}
/**
* 发送响应流方法
* @param response
* @param fileName
* @author HHB
*/
public static void setResponseHeader(HttpServletResponse response, String fileName) {
try {
try {
// 设置表文件名的字符编码,不然中文文件名会乱码
fileName = new String(fileName.getBytes("utf-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
response.setContentType("application/octet-stream;charset=utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Pargam", "no-cache");
response.addHeader("Cache-Control", "no-cache");
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* 获取指定文件夹下的所有文件名
* @param path
* @param listFileName
* @author HHB
*/
public void getAllFileName(String path, List<String> listFileName) {
File file = new File(path);
String[] names = file.list();
if (names != null) {
String[] completNames = new String[names.length];
for (int i = 0; i < names.length; i++) {
completNames[i] = names[i];
listFileName.add(completNames[i]);
}
}
}
/**
* 获取文件后缀名
* @param filename
* @return
* @author HHB
*/
private String getfilenamelast(String filename) {
int start = filename.lastIndexOf(".");
if (start != -1) {
filename = filename.substring(start, filename.length());
}
return filename;
}
}
/**
* Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
*/
package com.xinhuize.internal.modules.sediment.web.sedimentdata;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.xinhuize.internal.modules.sediment.entity.sedimentData.SedimentData;
/**
* 0代表失败,1代表成功,2格式错误
* @author HHB
* @version 2021年8月27日
*/
@Controller
@RequestMapping("${adminPath}/sedimentdata/Upload")
public class UploadController {
/**
*
* @param request
* @param sedimentData
* @param redirectAttributes 用于结合addMessage,弹出上传成功的小弹幕字样
* @param model 页面再一次刷新时,之前一次选好的的框中内容还在,不会随着刷新而没了
* @return
* @throws IOException
* @author HHB
*/
@ResponseBody
@RequestMapping("excelUpload")
public String excelUpload(HttpServletRequest request, SedimentData sedimentData, RedirectAttributes redirectAttributes, Model model)
throws IOException {
String isSuccess = null;
Map<String, String> map = new HashMap<String, String>();
//得到选择的年份,作为第一层文件夹名称
String sedSelectedYear = sedimentData.getSedSelectedYear();
//得到设备名称,作为第二层文件夹名称
String sedimentEquipmentName = sedimentData.getSedimentEquipmentName();
//得到表名,作为第三层文件夹名称
String sedimentTableName = sedimentData.getSedimentTableName();
// 转型为MultipartHttpRequest
//前台传输过来的上传的文件名
try {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
List<MultipartFile> fileList = multipartRequest.getFiles("analysisFile");
for (MultipartFile mf : fileList) {
if (!mf.isEmpty()) {
try {
// 文件保存的第二层文件夹 ,以日期(年月日)命名
//String dataName = Tool.getyyyy();
//以上传时的文件名存储
String uploadFileName = mf.getOriginalFilename();
//String filePath = "D:/xinhuize" + "saveExcel/" + sedSelectedYear + "/" + sedimentEquipmentName + "/" + sedimentTableName + "/";// 文件保存的第一层文件夹 ,组合而来
String filePath = "/usr/local/xinhuize-excel-save" + "/" + sedSelectedYear + "/" + sedimentEquipmentName + "/" + sedimentTableName + "/";
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
// 转存文件 三层路径,最后以上传时的文件名存储
mf.transferTo(new File(filePath + uploadFileName));
isSuccess = "ok";
} else {
File[] listFiles = file.listFiles();
if (uploadFileName.endsWith(".xlsx") && file != null || listFiles != null || uploadFileName.endsWith(".xls")) {
for (int i = 0; i < listFiles.length; i++) {
if (listFiles[i].isFile()) {
listFiles[i].delete();
}
// 转存文件 三层路径,最后以上传时的文件名存储
mf.transferTo(new File(filePath + uploadFileName));
isSuccess = "ok";
}
}
}
} catch (Exception e) {
map.put("isok", "0");
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
//弹出上传成功的小弹幕字样
//return "redirect:"+Global.getAdminPath()+"/sedimentdata/sedimentData/exportWholeFile?repage";
return isSuccess;
}
/**
* 获取文件后缀名
* @param filename
* @return
* @author HHB
*/
private String getfilenamelast(String filename) {
int start = filename.lastIndexOf(".");
if (start != -1) {
filename = filename.substring(start, filename.length());
}
return filename;
}
/**
*
* @param redirectAttributes
* @param messages
* @author HHB
*/
protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
StringBuilder sb = new StringBuilder();
for (String message : messages) {
sb.append(message).append(messages.length > 1 ? "
" : "");
}
redirectAttributes.addFlashAttribute("message", sb.toString());
}
}
Tools.java
/**
* Copyright (c) 2013-Now http://AIminminAI.com All rights reserved.
*/
package com.xinhuize.internal.modules.sediment.web.sedimentdata;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import org.apache.log4j.Logger;
/**
*
* @author HHB
* @version 2021年8月27日
*/
public class Tool {
private static Logger log = Logger.getLogger(Tool.class);
//获取日期
public static String getyyyyMMdd(){
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(d);
}
//获取带毫秒时间戳
public static String getyyyyMMddHHmmssSSS(){
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
return sdf.format(d);
}
//获取10000-100000的随机数
public static int getRandom(){
int max=100000;
int min=10000;
Random random = new Random();
int s = random.nextInt(max)%(max-min+1) + min;
return s;
}
public static String getyyyy(){
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
return sdf.format(d);
}
}
注意事项总结分析:
先判断上传的文件是普通表单还是带文件的表单
,用ServletFileUpload.isMultipartContent(request)
如果没有则用文件流中的mkdir()方法创建这个目录
但是我们都建议使用Apache的文件上传组件来实现,common-fileupload, 它需要依赖于commons -io组件,所以呢,咱们就要导jar包或者导入相关的maven依赖
;PART1-2:SpringBoot中:
pom.xml中引入必要的spring-file-storage.jar
,比如本地和Aliyun OSS上传如果要上传文件到OSS平台,需要引入对应平台的SDK包,将aliyun oss提供的变量配置到相应的模块上
。springboot启动类中增加注解@EnableFileStorage,显式的开启文件上传功能
,到这就可以用了@EnableFileStorage // 文件上传工具
@SpringBootApplication
public class SpringbootFileStorageApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFileStorageApplication.class, args);
}
}
@RestController
public class FileController {
@Autowired
private FileStorageService fileStorageService;
/**
* 上传文件
*/
@PostMapping(value = {"/upload"})
public Object upload(MultipartFile file) {
FileInfo upload = fileStorageService.of(file).upload();
return upload;
}
}
依赖坐标
:创建文件上传的处理控制器,命名为UploadController
spring.servlet.multipart.max-file-size=2MB//这个参数用于限制了上传文件的大小
spring.servlet.multipart.max-request-size=2MB//用于限制了上传请求的大小
file.upload.path=/Users/didi //file.upload.path是上面我们自己定义的用来保存上传文件的路径
PART2:第二部分,就是用上了OSS,学习到了OSS相关的基础以及使用
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
aliyun.endpoint=oss-cn-beijing.aliyuncs.com
aliyun.accessKeyId=LTAI5t9mpendCkALZKtBcqW1
aliyun.accessKeySecret=XXX(你的accessKeySecret)
aliyun.bucketName=malf-bucket
aliyun.urlPrefix=https://malf-bucket.oss-cn-beijing.aliyuncs.com/
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=1000MB
巨人的肩膀:
感谢csdn上有意无意被我看到的文章们,感谢这些作者,学习到了很多
https://blog.didispace.com
/spring-boot-learning-21-4-3/
https://segmentfault.com/a/1190000040035818【OSS比较好的教程】
程序员小富老师
码哥字节老师
码农翻身
SpringForAll
javaGuide