问题
由于第一次使用 spring boot 在开发项目, 在文件上传下载这块 出现了两个BUG:
BUG1: 在服务器Jar包形式下,文件(图片)上传成功后, 浏览器访问不到;
BUG2: 文件下载时, 系统报错:
org.apache.catalina.connector.ClientAbortException: java.io.IOException: 您的主机中的软件终止了一个已建立的连接....
解决方案
我在 Eclipse 中可以实现文件上传,下载,访问, 但项目打成Jar包后, 文件可以上传, 但访问不成功, 导致 访问的图片都加载不到.
附上代码:
package com.gy.fast.common.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import com.gy.fast.common.exception.SysException;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
/**
* 文件上传工具
*
* @author geYang
* @date 2018-06-13
*/
public class UploadUtils {
/**
* 文件指定访问URL
*/
public static final String BASE_URL = "/files/";
/**
* 文件指定存放目录
*/
public static final String BASE_PATH = "uploadfiles/";
/**
* 用户图片存放目录
*/
public static final String USER_IMAGE = "userimage/";
/**
* 允许上传文件集合
*/
protected static String[] ALLOW_FORMAT = {
".jpg", ".png", ".gif", ".jpeg", ".txt", ".zip",
".doc", ".docx", ".xls", ".xlsx"
};
/**
* 获取项目绝对路径
* @return String( E:\FrindHR\niuniu_lawyer_internal\niuer-law\target\classes )
* @author geYang
* @date 2018-06-13 06:47
* */
public static String getClassFilePath() {
try {
String classPath = ResourceUtils.getURL("classpath:").getPath();
File classFile = new File(classPath);
if (!classFile.exists()) {
classFile = new File("");
}
String classFilePath = classFile.getAbsolutePath();
System.out.println("classFilePath(项目根路径): " + classFilePath);
return classFilePath;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 文件存放的绝对路径
* @param path 默认为 OTHER(other)
* @author geYang
* @date 2018-06-13 07:06
* */
public static String getUploadFilePath(String path) {
String classFilePath = getClassFilePath();
path = CommonUtil.isBlank(path) || path.equals(BASE_URL) || path.equals(BASE_PATH) ? OTHERF : path;
File uploadFile = new File(classFilePath, BASE_PATH + path);
if (!uploadFile.exists()) {
uploadFile.mkdirs();
}
String uploadFilePath = uploadFile.getAbsolutePath();
System.out.println("uploadFilePath(文件上传路径): " + uploadFilePath);
return uploadFilePath;
}
/**
* 文件上传
* @param file 文件
* @param path 存放目录
* @author geYang
* @date 2018-06-13 07:09
* */
public static String upload(MultipartFile file, String path) {
if (file.isEmpty()) {
return null;
}
String oldfileName = file.getOriginalFilename();
String fileName = getfileName(oldfileName);
String fileUrl = null;
try {
// 文件存放目录
String uploadFilePath = getUploadFilePath(path);
uploadFile(file.getBytes(), uploadFilePath, fileName);
fileUrl = getFileUrl(path, fileName);
} catch (IOException e) {
e.printStackTrace();
}
return fileUrl;
}
/**
* 获取文件访问路径
* */
public static String getFileUrl(String path, String fileName) {
String fileUrl = BASE_URL + path + fileName;
System.out.println("fileUrl(文件访问路径): " + fileUrl);
return fileUrl;
}
/**
* 获取文件存放路径(相对路径)
* @param fileUrl 文件访问路径
* @return uploadfiles/outher/08.jpg
* @author geYang
* @date 2018-06-13 07:25
* */
private static String getUploadPath(String fileUrl) {
String uploadPath = fileUrl.replace(BASE_URL, BASE_PATH);
System.out.println("uploadPath(文件存放路径): " + uploadPath);
return uploadPath;
}
/**
* 获取文件存放全路径(绝对)
* @param fileUrl
* @return E:\FrindHR\niuniu_lawyer_internal\niuer-law\target\test-classes/uploadfiles/outher/08.jpg
* @author geYang
* @date 2018-06-13 07:24
* */
public static String getUploadPathAll(String fileUrl) {
String uploadPathAll = getClassFilePath() + "/" + getUploadPath(fileUrl);
System.out.println("uploadPathAll(文件存放绝对路径): " + uploadPathAll);
return uploadPathAll;
}
/**
* 生成随机文件名
*
* @param originalName
* @return
* @author geYang
* @date 2018-06-13 10:54
*/
private static String getfileName(String originalName) {
String suffix = getSuffix(originalName);
StringBuffer name = new StringBuffer();
name.append(DateUtil.format(new Date(), "yyyyMMddHHmmss")).append(RandomUtil.randomString(5)).append(suffix);
return name.toString();
}
/**
* 获取文件后缀名
*/
public static String getSuffix(String name) {
String suffix = name.substring(name.lastIndexOf("."));
if (!checkSuffix(suffix)) {
throw new SysException("文件不合法");
}
return suffix;
}
/**
* 判断文件名是否合格
* @param name
* @return
* @author geYang
* @date 2018-06-13 08:35
* */
public static boolean checkName(String name) {
return checkSuffix(getSuffix(name));
}
/**
* 校验后缀名是否合法
* */
private static boolean checkSuffix(String suffix) {
Set<String> setSuffix = new HashSet<>(Arrays.asList(ALLOW_FORMAT));
return setSuffix.contains(suffix);
}
/**
* 文件上传
* */
public static void uploadFile(byte[] file, String filePath, String fileName) throws IOException {
File targetFile = new File(filePath);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
FileOutputStream out = new FileOutputStream(filePath + "/" + fileName);
out.write(file);
out.flush();
out.close();
}
/**
* 获取文件下载数据
* @param url
* @return
* @author geYang
* @date 2018-06-13 10:20
* */
private static byte[] getDownloadByte(String fileUrl) {
String uploadPath = getUploadPathAll(fileUrl);
byte[] data = null;
try {
InputStream inputStream = new FileInputStream(new File(uploadPath));
data = new byte[inputStream.available()];
inputStream.read(data);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
throw new SysException("文件下载异常");
}
return data;
}
/**
* 文件下载
* @param fileUrl 文件访问路径
* @param fileName 定义下载文件名,不带后缀
* @param response
* @throws IOException
* @author geYang
* @date 2018-06-13 10:30
* */
public static void download(String fileUrl, String fileName ,HttpServletResponse response) throws IOException {
// 文件下载
byte[] DownloadByte = getDownloadByte(fileUrl);
if (DownloadByte == null) {
throw new SysException("下载文件不存在");
}
response.reset();
fileName = URLEncoder.encode(fileName.trim()+getSuffix(fileUrl), "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\""+ fileName +"\"");
response.addHeader("Content-Length", "" + DownloadByte.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(DownloadByte, response.getOutputStream());
}
}
/**
* WebMvc配置
* @author geYang
* @date 2018-05-14
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 上传图片访问目录:
registry.addResourceHandler(UploadUtils.BASE_URL + "**").addResourceLocations("classpath:/" + UploadUtils.BASE_PATH);
}
}
文件上传是控制台输出:
classFilePath(项目根路径): E:\testJar
uploadFilePath(文件上传路径): E:\testJar\uploadfiles\userimage
fileUrl(文件访问路径): /files/userimage/20180615160036s4ouv.jpg
这些都是正确的, 在 jar包所在的目录中生成了 uploadfiles/userimage/userimage/20180615160036s4ouv.jpg
证明文件上传是正常的, 但关键就是 访问不到.
如果是Eclipse启动项目, 我能通过
localhost:8080/files/userimage/20180615160036s4ouv.jpg
代码实现
1, 文件上传工具类:
package com.gy.fast.common.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import com.gy.fast.common.exception.SysException;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
/**
* 文件上传工具
*
* @author geYang
* @date 2018-06-13
*/
public class UploadUtils {
/**
* 文件指定访问URL
*/
public static final String BASE_URL = "/files/";
/**
* 文件指定存放目录
*/
public static final String BASE_PATH = "uploadfiles/";
/**
* 用户图片存放目录
*/
public static final String USER_IMAGE = "userimage/";
/**
* 其他文件存放目录
*/
public static final String OTHERF = "outher/";
/**
* 允许上传文件集合
*/
protected static String[] ALLOW_FORMAT = {
".jpg", ".png", ".gif", ".jpeg", ".txt", ".zip",
".doc", ".docx", ".xls", ".xlsx"
};
/**
* 获取项目绝对路径
* @return String( E:\FrindHR\niuniu_lawyer_internal\niuer-law\target\classes )
* @author geYang
* @date 2018-06-13 06:47
* */
public static String getClassFilePath() {
try {
String classPath = ResourceUtils.getURL("classpath:").getPath();
File classFile = new File(classPath);
if (!classFile.exists()) {
classFile = new File("");
}
String classFilePath = classFile.getAbsolutePath();
System.out.println("classFilePath(项目根路径): " + classFilePath);
return classFilePath;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 文件存放的绝对路径
* @param path 默认为 OTHER(other)
* @author geYang
* @date 2018-06-13 07:06
* */
public static String getUploadFilePath(String path) {
String classFilePath = getClassFilePath();
path = CommonUtil.isBlank(path) || path.equals(BASE_URL) || path.equals(BASE_PATH) ? OTHERF : path;
File uploadFile = new File(classFilePath, BASE_PATH + path);
if (!uploadFile.exists()) {
uploadFile.mkdirs();
}
String uploadFilePath = uploadFile.getAbsolutePath();
System.out.println("uploadFilePath(文件上传路径): " + uploadFilePath);
return uploadFilePath;
}
/**
* 文件上传
* @param file 文件
* @param path 存放目录
* @author geYang
* @date 2018-06-13 07:09
* */
public static String upload(MultipartFile file, String path) {
if (file.isEmpty()) {
return null;
}
String oldfileName = file.getOriginalFilename();
String fileName = getfileName(oldfileName);
String fileUrl = null;
try {
// 文件存放目录
String uploadFilePath = getUploadFilePath(path);
uploadFile(file.getBytes(), uploadFilePath, fileName);
fileUrl = getFileUrl(path, fileName);
} catch (IOException e) {
e.printStackTrace();
}
return fileUrl;
}
/**
* 获取文件访问路径
* */
public static String getFileUrl(String path, String fileName) {
String fileUrl = BASE_URL + path + fileName;
System.out.println("fileUrl(文件访问路径): " + fileUrl);
return fileUrl;
}
/**
* 获取文件存放路径(相对路径)
* @param fileUrl 文件访问路径
* @return uploadfiles/outher/08.jpg
* @author geYang
* @date 2018-06-13 07:25
* */
private static String getUploadPath(String fileUrl) {
String uploadPath = fileUrl.replace(BASE_URL, BASE_PATH);
System.out.println("uploadPath(文件存放路径): " + uploadPath);
return uploadPath;
}
/**
* 获取文件存放全路径(绝对)
* @param fileUrl
* @return E:\FrindHR\niuniu_lawyer_internal\niuer-law\target\test-classes/uploadfiles/outher/08.jpg
* @author geYang
* @date 2018-06-13 07:24
* */
public static String getUploadPathAll(String fileUrl) {
String uploadPathAll = getClassFilePath() + "/" + getUploadPath(fileUrl);
System.out.println("uploadPathAll(文件存放绝对路径): " + uploadPathAll);
return uploadPathAll;
}
/**
* 生成随机文件名
*
* @param originalName
* @return
* @author geYang
* @date 2018-06-13 10:54
*/
private static String getfileName(String originalName) {
String suffix = getSuffix(originalName);
StringBuffer name = new StringBuffer();
name.append(DateUtil.format(new Date(), "yyyyMMddHHmmss")).append(RandomUtil.randomString(5)).append(suffix);
return name.toString();
}
/**
* 获取文件后缀名
*/
public static String getSuffix(String name) {
String suffix = name.substring(name.lastIndexOf("."));
if (!checkSuffix(suffix)) {
throw new SysException("文件不合法");
}
return suffix;
}
/**
* 判断文件名是否合格
* @param name
* @return
* @author geYang
* @date 2018-06-13 08:35
* */
public static boolean checkName(String name) {
return checkSuffix(getSuffix(name));
}
/**
* 校验后缀名是否合法
* */
private static boolean checkSuffix(String suffix) {
Set<String> setSuffix = new HashSet<>(Arrays.asList(ALLOW_FORMAT));
return setSuffix.contains(suffix);
}
/**
* 文件上传
* */
public static void uploadFile(byte[] file, String filePath, String fileName) throws IOException {
File targetFile = new File(filePath);
if (!targetFile.exists()) {
targetFile.mkdirs();
}
FileOutputStream out = new FileOutputStream(filePath + "/" + fileName);
out.write(file);
out.flush();
out.close();
}
/**
* 获取文件下载数据
* @param url
* @return
* @author geYang
* @date 2018-06-13 10:20
* */
private static byte[] getDownloadByte(String fileUrl) {
try {
String uploadPath = getUploadPathAll(fileUrl);
InputStream inputStream = new FileInputStream(new File(uploadPath));
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
inputStream.close();
return data;
} catch (IOException e) {
e.printStackTrace();
throw new SysException("文件下载异常");
}
}
/**
* 文件下载
* @param fileUrl 文件访问路径
* @param fileName 定义下载文件名,不带后缀
* @param response
* @throws IOException
* @author geYang
* @date 2018-06-13 10:30
* */
public static void download(String fileUrl, String fileName ,HttpServletResponse response) throws IOException {
// 文件下载
byte[] downloadByte = getDownloadByte(fileUrl);
if (downloadByte == null) {
throw new SysException("下载文件不存在");
}
int downloadByteLength = downloadByte.length;
response.reset();
fileName = URLEncoder.encode(fileName.trim()+getSuffix(fileUrl), "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\""+ fileName +"\"");
response.addHeader("Content-Length", String.valueOf(downloadByteLength));
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(downloadByte, response.getOutputStream());
}
}
2, 访问文件时 spring boot 路径处理:
/**
* WebMvc配置
* @author geYang
* @date 2018-05-14
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 上传图片访问目录: 如果有权限拦截的话,应该将 (UploadUtils.BASE_URL + "**") 放行
registry.addResourceHandler(UploadUtils.BASE_URL + "**").addResourceLocations("file:"+ UploadUtils.getClassFilePath()+ "/" + UploadUtils.BASE_PATH);
}
}