springboot文件上传(图片)
坑坑坑
在上传过后的文件命名时,尽量不要是带上源文件名!!!
正确写法是: String filenameUUID = UUID.randomUUID().toString().replace("-", "")+".zip";
错误写法是: String filenameUUID = UUID.randomUUID().toString().replace("-", "")+originalFileName;
因为:带上原始的文件名,有可能原始的文件名,会是带上特殊字符.
线上springboot文件上传,过了一段时间报错!
原因:
spring boot的应用服务在启动的时候,会生成在操作系统的/tmp目录下生成一个Tomcat.*的文件目录,用于"java.io.tmpdir"文件流操作
程序对文件的操作时:会生成临时文件,暂存在临时文件中;
lunix 系统的tmpwatch 命令会删除10天未使用的临时文件;
长时间不操作,导致/tmp下面的tomcat临时文件目录被删除,且删除的文件不可恢复,上传文件时获取不到文件目录,报错
{"timestamp":1552273330708,"status":500,
"error":"Internal Server Error",
"exception":"org.springframework.web.multipart.MultipartException",
"message":"Could not parse multipart servlet request; nested exception is java.io.IOException:
The temporary upload location [/tmp/tomcat.1756970833364702281.8080/work/Tomcat/localhost/api] is not valid",
"path":"/api/file/upload-picture"}
解决
自己选择了添加配置这种方案
server.tomcat.basedir=/data/tms/tmp/tomcat
线上部署操作
一: 拷贝,备份
cp application.properties bk-2019312application.properties
二: vi编辑器
vi application.properties
三: 可编辑
i
四: 添加配置
server.tomcat.basedir=/data/tms/tmp/tomcat
五: 杀死进程
ps -ef | grep tms
kill -9
六: 启动
nohup java -jar -Dspring.profiles.active=beta -Dspring.config.location=application.properties tms.jar >tms.log &
下面是自己部署线上之前测试
其中校验了是否是图片,这个是两个项目中都用的此接口
package com.macro.mall.controller;
import com.macro.mall.dto.CommonResult;
import com.macro.mall.util.JwtTokenUtil;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @Desc 文件上传接口
* @Date 2018/10/30 12:20
* @Author cui_yl
*/
@RestController
@RequestMapping(value = "/file/***")
public class FileUploadController {
private final static Logger logger = LoggerFactory.getLogger(FileUploadController.class);
@Value(value = "${image.upload.host}")
private String imageUploadHost;
@Value(value = "${image.upload.path}")
private String imageUploadPath;
@Value(value = "${spring.profiles.active}")
private String springProfilesActive;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value("${jwt.tokenHead}")
private String tokenHead;
/**
* @Desc 上传文件
* @Date 2018/10/27 17:40
* @Param []
*/
@PostMapping("/upload-picture")
public Object singleFileUpload(@RequestParam("file") MultipartFile file) {
try {
FileInputStream fileInputStream = (FileInputStream)file.getInputStream();
String originalFilename = file.getOriginalFilename();
if ((!originalFilename.toLowerCase().endsWith(".png") && !originalFilename.toLowerCase().endsWith(".jpg"))){
return new CommonResult().validateFailed("请上传JPG/PNG格式图片");
}
String picType = getPicType(fileInputStream);
if (!TYPE_JPG.equals(picType) && !TYPE_PNG.equals(picType)){
return new CommonResult().validateFailed("请上传JPG/PNG格式图片");
}
File dir = new File(imageUploadPath);
if(!dir.exists()) {
dir.mkdir();
}
if (file.isEmpty()) {
throw new RuntimeException("请选择一个文件上传!");
}
byte[] bytes = file.getBytes();
String filename = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd")+"-"+UUID.randomUUID().toString()+"."+picType;
Path path = Paths.get(imageUploadPath, filename);
Files.write(path, bytes);
String url=imageUploadHost+filename;
/**
*
* BufferedImage image = ImageIO.read(connection.getInputStream());
* int srcWidth = image .getWidth(); // 源图宽度
* int srcHeight = image .getHeight(); // 源图高度
*/
BufferedImage image = ImageIO.read(file.getInputStream());
int srcWidth = image .getWidth(); // 源图宽度
int srcHeight = image .getHeight(); // 源图高度
String size = String.valueOf(srcWidth)+"*"+String.valueOf(srcHeight);
Map<String,Object> map = new HashMap<>();
map.put("fileName",originalFilename);
map.put("url",url);
map.put("size",size);
return new CommonResult().success( map);
} catch (Exception e) {
logger.error("上传文件失败"+e.getMessage(), e);
return new CommonResult().failed("上传文件失败"+e.getMessage());
}
}
private static final String TYPE_JPG = "jpg";
private static final String TYPE_GIF = "gif";
private static final String TYPE_PNG = "png";
private static final String TYPE_BMP = "bmp";
private static final String TYPE_UNKNOWN = "unknown";
/**
* 根据文件流判断图片类型
* @param fis
* @return jpg/png/gif/bmp
*/
public static String getPicType(FileInputStream fis) throws Exception{
byte[] b = new byte[4];//读取文件的前几个字节来判断图片格式
try {
fis.read(b, 0, b.length);
String type = bytesToHexString(b).toUpperCase();
if (type.contains("FFD8FF")) {
return TYPE_JPG;
} else if (type.contains("89504E47")) {
return TYPE_PNG;
} else if (type.contains("47494638")) {
return TYPE_GIF;
} else if (type.contains("424D")) {
return TYPE_BMP;
}else{
return TYPE_UNKNOWN;
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* byte数组转换成16进制字符串
* @param src
* @return
*/
public static String bytesToHexString(byte[] src) throws Exception{
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}
下面这个是同事给的工具类, 感觉也很好
package com.macro.mall.util;
import java.io.File;
import java.io.FileOutputStream;
import java.util.UUID;
import org.apache.commons.lang.time.DateFormatUtils;
public class FileUtil {
public static File uploadFile(byte[] file, String filePath, String fileName) {
filePath = filePath+File.separator+ DateFormatUtils.format(System.currentTimeMillis(), "yyyyMM");
File targetFile = new File(filePath);
String suffix="";
if(fileName.lastIndexOf(".")>0){
suffix = fileName.substring(fileName.lastIndexOf("."));
}
if(!targetFile.exists()){
targetFile.mkdirs();
}
targetFile = new File(filePath+File.separator+UUID.randomUUID().toString()+suffix);
try(FileOutputStream out = new FileOutputStream(targetFile)){
out.write(file);
out.flush();
return targetFile;
} catch (Exception e) {
}finally {
}
return null;
}
public static String getSuffix(String fileName){
if(fileName.lastIndexOf(".")>0){
return fileName.substring(fileName.lastIndexOf("."));
}else{
return "";
}
}
public static boolean delAllFile(String path) {
boolean flag = false;
File file = new File(path);
if (!file.exists()) {
return flag;
}
if (!file.isDirectory()) {
return flag;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
} else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.deleteOnExit();
}
if (temp.isDirectory()) {
delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
delFolder(path + "/" + tempList[i]);//再删除空文件夹
flag = true;
}
}
return flag;
}
public static boolean delFolder(String folderPath) {
try {
delAllFile(folderPath); //删除完里面所有内容
String filePath = folderPath;
filePath = filePath.toString();
File myFilePath = new File(filePath);
myFilePath.deleteOnExit();
return true;
} catch (Exception e) {
// logger.error("文件夹删除失败");
return false;
}
}
}
下面是上传文件
/**
* @Desc 上传模板
* @Date 2018/11/22 19:42
* @Param [multipartRequest]
*/
@PostMapping("/templatezip")
public ResponseBean create(@RequestParam("file") MultipartFile file, @RequestHeader("Authorization") String authorization) {
try {
if (null == file){
return new ResponseBean(400, "缺少文件");
}
int userId = JWTUtil.getUserId(authorization);
long size = (file.getSize())/(1024*1024);
if (size>=20){
return new ResponseBean(400, "请以上传20M以内的压缩包");
}
String originalFilename = file.getOriginalFilename();
if (!originalFilename.endsWith(".zip")){
return new ResponseBean(400, "请以上传zip格式的压缩包");
}
File dir = new File(UPLOADED_FOLDER);
if(!dir.exists()) {dir.mkdir();}
byte[] bytes = file.getBytes();
String filenameUUID = UUID.randomUUID().toString().replace("-", "")+".zip";
if (StringUtils.isEmpty(filenameUUID)){
throw new RuntimeException("获得模板UUID名称 error");
}
Path path = Paths.get(UPLOADED_FOLDER, filenameUUID);
Files.write(path, bytes);//保存模板文件
String uuidFilePath = path.toString();
HashMap<String, String> map = new HashMap<>();
map.put("originalFilename", originalFilename);
map.put("uuidFilePath", uuidFilePath);
return new ResponseBean(200, "上传成功", map);//返回模板绝对文件路径
} catch (Exception e) {
logger.warn("保存模板信息失败", e);
return new ResponseBean("保存失败", 500);
}
}
- 批量上传,但是代码中在返回批量上传后的图片路径时,由于业务只返回了第一个
package com.macro.mall.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.macro.mall.dto.CommonResult;
import com.macro.mall.util.JwtTokenUtil;
import io.swagger.annotations.Api;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
* @Desc 文件上传接口
* @Date 2018/10/30 12:20
* @Author cui_yl
*/
@Api(tags = "FileUploadController",description = "文件上传")
@Controller
@RequestMapping(value = "/file")
public class FileUploadController {
private final static Logger logger = LoggerFactory.getLogger(FileUploadController.class);
@Value(value = "${image.upload.host}")
private String imageUploadHost;
@Value(value = "${image.upload.path}")
private String imageUploadPath;
@Value(value = "${spring.profiles.active}")
private String springProfilesActive;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Value("${jwt.tokenHead}")
private String tokenHead;
/**
* @Desc 上传文件
* @Date 2018/10/27 17:40
* @Param []
*/
@PostMapping("/upload-picture")
@ResponseBody
public Object singleFileUpload(@RequestParam(value = "file") MultipartFile files[]) {
try {
if (null == files || files.length < 1) {
throw new RuntimeException("请选择一个文件上传!");
}
File dir = new File(imageUploadPath);
if(!dir.exists()) {
dir.mkdirs();
}
List<Map> list = new ArrayList<>();
BufferedOutputStream bw = null;
try {
for (MultipartFile file : files) {
String originalFilename = file.getOriginalFilename();
//判断是否有文件且是否为图片文件
if(originalFilename!=null && !"".equalsIgnoreCase(originalFilename.trim()) && isImageFile(originalFilename)) {
String fileName = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMdd")+"-"+UUID.randomUUID().toString()+ getFileType(originalFilename);
//创建输出文件对象
File outFile = new File(imageUploadPath + "/" +fileName);
//拷贝文件到输出文件对象
FileUtils.copyInputStreamToFile(file.getInputStream(), outFile);
String url=imageUploadHost+fileName;
/**
*
* BufferedImage image = ImageIO.read(connection.getInputStream());
* int srcWidth = image .getWidth(); // 源图宽度
* int srcHeight = image .getHeight(); // 源图高度
*/
BufferedImage image = ImageIO.read(file.getInputStream());
int srcWidth = image .getWidth(); // 源图宽度
int srcHeight = image .getHeight(); // 源图高度
String size = String.valueOf(srcWidth)+"*"+String.valueOf(srcHeight);
Map<String,Object> map = new HashMap<>();
map.put("fileName", originalFilename);
map.put("url", url);
map.put("size", size);
list.add(map);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return new CommonResult().success(list.get(0));
} catch (Exception e) {
logger.error("上传文件失败"+e.getMessage(), e);
return new CommonResult().failed("上传文件失败"+e.getMessage());
}
}
private static final String TYPE_JPG = "jpg";
private static final String TYPE_GIF = "gif";
private static final String TYPE_PNG = "png";
private static final String TYPE_BMP = "bmp";
private static final String TYPE_UNKNOWN = "unknown";
private Boolean isImageFile(String fileName) {
String[] img_type = new String[]{".jpg", ".jpeg", ".png", ".gif", ".bmp"};
if (fileName == null) {
return false;
}
fileName = fileName.toLowerCase();
for (String type : img_type) {
if (fileName.endsWith(type)) {
return true;
}
}
return false;
}
/**
* 获取文件后缀名
*
* @param fileName
* @return
*/
private String getFileType(String fileName) {
if (fileName != null && fileName.indexOf(".") >= 0) {
return fileName.substring(fileName.lastIndexOf("."), fileName.length());
}
return "";
}
/**
* 根据文件流判断图片类型
* @param fis
* @return jpg/png/gif/bmp
*/
public static String getPicType(FileInputStream fis) throws Exception{
byte[] b = new byte[4];//读取文件的前几个字节来判断图片格式
try {
fis.read(b, 0, b.length);
String type = bytesToHexString(b).toUpperCase();
if (type.contains("FFD8FF")) {
return TYPE_JPG;
} else if (type.contains("89504E47")) {
return TYPE_PNG;
} else if (type.contains("47494638")) {
return TYPE_GIF;
} else if (type.contains("424D")) {
return TYPE_BMP;
}else{
return TYPE_UNKNOWN;
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* byte数组转换成16进制字符串
* @param src
* @return
*/
public static String bytesToHexString(byte[] src) throws Exception{
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}