Demo介绍
这个功能是为了能够以最小组件的方式展示如果使用SpringBoot实上传下载和相关预览功能,由于要测试后端接口,因此也写了较少的前端代码来测试接口,这里有较多省略,大家可以去项目那里运行
1 后端
后端的代码分成数个功能块
1.1 工具函数 Utils
库
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import org.springframework.core.io.ClassPathResource;
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
1.1.1 获取文件后缀名
要想实现对各个文件的操作,得知道文件的后缀名,代码如下
public static String getFileSuffix(String fileName){
String fileSuffix;
if(fileName.lastIndexOf(".")==-1){fileSuffix="";}
else{fileSuffix=fileName.substring(fileName.lastIndexOf(".")+1);}
return fileSuffix;
}
1.1.2 文件名转URL字符串
因为后端要对文件进行重定向,所以得对中文空格等字符进行转换
public static String getUrlEncode(String fileName){
String fileNameEncode;
try {
fileNameEncode = URLEncoder.encode(fileName,"UTF-8");
//替换+号否则空格解析会出错
fileNameEncode = fileNameEncode.replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
fileNameEncode = "";
}
return fileNameEncode;
}
1.1.3 word转pdf
采用的是apose.words的API 水印得有License才能去,这个暂时没做到,而且这个是收费的,商业项目慎用哦。
public static void WordToPdf(String sourcePath,String targetPath) throws Exception {
FileOutputStream os = null;
Boolean license = false;
try {
System.out.println(sourcePath+" -----> "+targetPath);
//凭证 不然切换后有水印
try{
InputStream is = new ClassPathResource("static/license/license.xml").getInputStream();
License aposeLic = new License();
aposeLic.setLicense(is);
license = true;
}
catch(Exception e){
if (!license) {
System.out.println("License验证不通过...");
}
}
//生成一个空的PDF文件
File file = new File(targetPath);
os = new FileOutputStream(file);
//要转换的word文件
Document doc = new Document(sourcePath);
doc.save(os, SaveFormat.PDF);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.2 接口代码
库
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
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.net.URLEncoder;
import java.nio.file.Paths;
import java.util.HashMap;
配置Application,记得配置,不然拦截器没有办法定位到文件
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.util.ResourceUtils;
import java.nio.file.Path;
import java.nio.file.Paths;
@SpringBootApplication
public class DemoApplication extends WebMvcConfigurationSupport {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
Path path = Paths.get("");
// private String projectPath = path.toAbsolutePath().toString();
String staticPath = Paths.get("").toAbsolutePath().toString()+"/static";
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//重定向设置
registry.addResourceHandler("/html/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/html/");
registry.addResourceHandler("/css/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/css/");
registry.addResourceHandler("/js/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX + "/static/js/");
registry.addResourceHandler("/download/**").addResourceLocations("file:"+staticPath +"/");
registry.addResourceHandler("/preview/**").addResourceLocations("file:"+staticPath +"/");
super.addResourceHandlers(registry);
}
@Bean
public CharacterEncodingFilter characterEncodingFilter(){
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
return filter;
}
}
1.2.1 上传
获取前端返回的fileName参数后保存文件
@PostMapping("/upload")
public String upload(@RequestParam("files") MultipartFile[] files) throws Exception{
if(files != null && files.length>0){
for(MultipartFile file:files){
if(!file.isEmpty()){
System.out.println("staticPath:"+new File(staticPath).getCanonicalPath());
String fileName = file.getOriginalFilename();
File newFile = new File(staticPath+"/"+fileName);
String fileSuffix = Utils.getFileSuffix(fileName);
System.out.println("save:"+newFile.getCanonicalPath()+" suffix:"+fileSuffix);
if(!new File(newFile.getParent()).exists()){
System.out.println("make dirs:"+newFile.getParent());
new File(newFile.getParent()).mkdirs();
}
if (newFile.exists()){
newFile.delete();
}
try{
file.transferTo(new File(newFile.getCanonicalPath()));
}
catch(UnsupportedEncodingException e){
System.out.println("error:"+fileName);
}
if(fileSuffix.equals("docx")||fileSuffix.equals("doc")){
String targetPdfFilePath = String.join("/",pdfFilePath,fileName.replace("."+fileSuffix,".pdf"));
File targetPdfFile = new File(targetPdfFilePath);
if(!new File(pdfFilePath).exists()){
System.out.println("make dirs:"+pdfFilePath);
new File(pdfFilePath).mkdirs();
}
if(targetPdfFile.exists()){targetPdfFile.delete();}
System.out.println("transform to pdf:");
Utils.WordToPdf(newFile.getCanonicalPath(),targetPdfFilePath);
// PdfHelper3.doc2pdf(newFile.getCanonicalPath(),targetPdfFilePath);
}
}
}
}
return "redirect:/";
}
1.2.2 下载
public void download(@RequestParam("fileName") String fileName,HttpServletResponse response) throws IOException{
String targetPath ;
String fileNameEncode;
try {
fileNameEncode = URLEncoder.encode(fileName,"UTF-8");
//替换+号否则空格解析会出错
fileNameEncode = fileNameEncode.replaceAll("\\+", "%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
fileNameEncode = "";
}
targetPath = String.join("/",staticPath,fileName);
File downloadFile = new File(targetPath);
FileInputStream downFileInputStream = new FileInputStream(downloadFile);
InputStream returnStream = new BufferedInputStream(downFileInputStream);
byte[] buffer = new byte[returnStream.available()];
System.out.println("download:"+targetPath);
System.out.println("file exist:"+new File(Paths.get(String.join("/", staticPath,fileName)).toAbsolutePath().toString()).exists());
returnStream.read(buffer);
returnStream.close();
response.reset();
//设置response的Header
response.setCharacterEncoding("UTF-8");
//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"
//filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
response.addHeader("Content-Disposition", "attachment;filename=" + fileNameEncode);
//告知浏览器文件的大小
response.addHeader("Content-Length", "" + downloadFile.length());
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
outputStream.write(buffer);
outputStream.flush();
}
1.2.3 获取目录文件列表
@GetMapping("/getFileList")
public @ResponseBody String[] getFileList() throws IOException{
HashMap<String,String> fileMap = new HashMap<String,String>();
File staticFile = new File(staticPath);
System.out.println("静态文件夹:"+staticFile.getCanonicalPath());
if (staticFile!=null && staticFile.isDirectory())
{
File[] fileList = staticFile.listFiles();
for(int i=0;i<fileList.length;i++){
String fileName = fileList[i].getName();
if(new File(String.join("/",staticPath,fileName)).isFile()){
fileMap.put(fileName,String.valueOf(i));
}
}
String[] fileNameList = new String[fileMap.keySet().size()];
fileMap.keySet().toArray(fileNameList);
return fileNameList ;
}
else{
String[] fileNameList = new String[0];
return fileNameList;
}
}
2 前端
<!DOCTYPE html>
<html>
<head>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传下载预览demo界面</title>
</head>
<body>
<form action="/upload" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple="multiple" value="请选择多个文件"/>
<button type="submit">文件上传</button>
</form>
<div id="fileNameDiv">
</div>
</body>
</html>
</body>
<script type="text/javascript" src="/js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
fileNameList = [];
function getFileList(){
$.ajax({
type:"get",
url:"/getFileList",
async:false,
success:function(response){fileNameList = response;},
error:function(){fileNameList = [];}
})
}
getFileList();
for(i=0;i<fileNameList.length;i++){
fileName = fileNameList[i];
fileNameEncode = encodeURI(fileName)
fileNameEncode = fileNameEncode.replace(/\+/g,'%2B');
hrefPreview = `/preview?fileName=${fileNameEncode}`;
hrefDelete = `/delete?fileName=${fileNameEncode}`;
hrefDownload = `/download?fileName=${fileNameEncode}`;
console.log(fileNameEncode);
$("#fileNameDiv").append(
`
<a href=${hrefDelete}>删除</a> <a href=${hrefDownload}>下载</a> <a href=${hrefPreview}>${fileName}</a> <br>
`
)
}
</script>
</html>