最近项目的需要,用户在上传图片时需要将图片保存在服务器某个目录下,由于项目是导成jar包直接使用springboot内嵌的Tomcat部署的,没有war包那么方便可以直接上传至Tomcat的webapp目录下,所以我采用了另一种方式上传图片及访问图片。
项目环境:
1.springboot1.5.9(使用内嵌Tomcat8)
2.mysql5.6
3.centerOS7
4.jdk1.8
一、创建获取服务器目录工具类GetServerRealPathUnit.java
import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIConversion;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileNotFoundException;
/*
**author:weijiakun
*获取目录工具类
*/
public class GetServerRealPathUnit {
public static String getPath(String subdirectory){
//获取跟目录---与jar包同级目录的upload目录下指定的子目录subdirectory
File upload = null;
try {
//本地测试时获取到的是"工程目录/target/upload/subdirectory
File path = new File(ResourceUtils.getURL("classpath:").getPath());
if(!path.exists()) path = new File("");
upload = new File(path.getAbsolutePath(),subdirectory);
if(!upload.exists()) upload.mkdirs();//如果不存在则创建目录
String realPath = upload + "/";
return realPath;
} catch (FileNotFoundException e) {
throw new RuntimeException("获取服务器路径发生错误!");
}
}
}
二、创建图片上传工具类SaveImgUnit.java
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/*
**author:weijiakun
*上传图片工具类
*/
public class SaveImgUnit {
//以base64编码格式上传,将照片转成字节流
public static Map getImg(String imageFile,String subdirectory){
// 通过base64来转化图片
String type = imageFile.substring(imageFile.indexOf("/")+1,imageFile.indexOf(";"));
if (type.equals("png")){
imageFile = imageFile.replaceAll("data:image/png;base64,", "");
}
if (type.equals("jpeg")){
imageFile = imageFile.replaceAll("data:image/jpeg;base64,", "");
}
BASE64Decoder decoder = new BASE64Decoder();
// Base64解码
byte[] imageByte = null;
try {
imageByte = decoder.decodeBuffer(imageFile);
for (int i = 0; i < imageByte.length; ++i) {
if (imageByte[i] < 0) {// 调整异常数据
imageByte[i] += 256;
}
}
} catch (Exception e) {
e.printStackTrace();
}
type = "." + type;
return saveImg(imageByte,subdirectory,type);
}
//存储照片到服务器
private static Map saveImg(byte[] imageByte,String subdirectory,String type){
// 生成文件名及文件类型
String files = new SimpleDateFormat("yyyyMMddHHmmssSSS")
.format(new Date())
+ (new Random().nextInt(9000) % (9000 - 1000 + 1) + 1000)
+ type;
Map map = new HashMap<>();
//获取跟目录---与jar包同级目录并生成文件路径
String filename = GetServerRealPathUnit.getPath(subdirectory) + files;
try {
// 生成文件
File imageFile = new File(filename);
imageFile.createNewFile();
if(!imageFile.exists()){
imageFile.createNewFile();
}
OutputStream imageStream = new FileOutputStream(imageFile);
imageStream.write(imageByte);
imageStream.flush();
imageStream.close();
map.put("res","success");
map.put("url",files);
return map;
} catch (Exception e) {
e.printStackTrace();
map.put("res","error");
return map;
}
}
//以MultipartFile方式上传到服务器
public static Map saveMultFile(MultipartFile file,String subdirectory){
//上传文件路径
String path = GetServerRealPathUnit.getPath(subdirectory);
//重新修改文件名防止重名
String filename = new SimpleDateFormat("yyyyMMddHHmmssSSS")
.format(new Date())
+ (new Random().nextInt(9000) % (9000 - 1000 + 1) + 1000)
+ file.getOriginalFilename();
File filepath = new File(path, filename);
//判断路径是否存在,没有就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
//将上传文件保存到一个目标文档中
Map map = new HashMap<>();
File file1 = new File(path + File.separator + filename);
try {
file.transferTo(file1);
map.put("res","success");
map.put("url",filename);
return map;
} catch (IOException e) {
map.put("res","error");
return map;
}
}
}
需要注意的是,这里我通过base64编码格式上传图片只写了jpg和png格式的转换判断,如需支持更多图片格式只需在getImg()方法中添加图片类型判断即可。
三、创建图片上传controller接口
这里只举例以base64编码格式上传
/**
**author:weijiakun
*/
@RestController
public class GoodsImgController {
@Autowired
private GoodsImgService goodsImgService;
/**
**author:weijiakun
**date:2018-09-11
* 上传以base64编码格式图片
*/
@RequestMapping(value = "/addGoodsImg",method = RequestMethod.POST)
public Map addGoodsImg(MultipartFile file){
if (file != null){
//上传文件
Map map = goodsImgService.uploadGoodsImg(file);
if (map.get("res").equals("success")){
//上传成功返回图片URL
return ReturnMapUtil.getReturnMap(0,"success",map);
}else{
return ReturnMapUtil.getReturnMap(1,"error");
}
}
}
}
四、创建图片上传服务service
public interface GoodsImgService {
/**
**author:weijiakun
* 上传商品图片
*/
Map uploadGoodsImg(MultipartFile file);
}
/**
**author:weijiakun
*/
@Service(value = "goodsImgService")
public class GoodsImgServiceImpl implements GoodsImgService {
//注入配置文件application.yml中设置的图片存放子目录名
@Value("${upload.path.goodsImg}")
private String GOODS_IMG_PATH;
/**
**author:weijiakun
* 上传以base64编码格式图片
*/
@Override
public Map uploadGoodsImg(MultipartFile file){
if (file != null){
//上传文件
Map map = SaveImgUnit.saveMultFile(file,GOODS_IMG_PATH);
return map;
}else {
Map map = new HashMap<>();
map.put("res","error");
return map;
}
}
}
至此,图片通过base64编码方式或MultipartFile方式上传至服务器与jar包同级的目录下。
五、访问服务器上的图片
由于图片上传的Linux目录存在权限问题,不允许用户随意访问,所以采用将图片转换为io流传输至服务器显示。
1.在上面创建的controller中添加一个/showImg接口
/**
*author:weijiakun
* IO流读取图片
* @param imgUrl 图片url
*/
@RequestMapping(value = "/showImg",method = RequestMethod.GET)
public void IoReadImage(String imgUrl HttpServletResponse response)throws IOException {
goodsImgService.IoReadImage(imgUrl,response);
}
2.添加服务层service业务方法IoReadImage()
/**
*author:weijiakun
* IO流读取图片
* @param imgUrl 图片url,即图片保存在服务器上的名称
*/
@Override
public void IoReadImage(String imgUrl, HttpServletResponse response) throws IOException {
ServletOutputStream out = null;
FileInputStream ips = null;
String upload = null;
//获取商品图片目录
upload = GetServerRealPathUnit.getPath(GOODS_IMG_PATH);
try {
//获取图片存放路径
String imgPath = upload + "/" + imgUrl;
ips = new FileInputStream(new File(imgPath));
String type = imgUrl.substring(imgUrl.indexOf(".")+1);
if (type.equals("png")){
response.setContentType("image/png");
}
if (type.equals("jpeg")){
response.setContentType("image/jpeg");
}
out = response.getOutputStream();
//读取文件流
int len = 0;
byte[] buffer = new byte[1024 * 10];
while ((len = ips.read(buffer)) != -1){
out.write(buffer,0,len);
}
out.flush();
}catch (Exception e){
e.printStackTrace();
}finally {
out.close();
ips.close();
}
}
3.在前端中使用即可访问并在浏览器显示图片。
六、参考资料
https://blog.csdn.net/qq_39529566/article/details/81872062