最近項目的需要,使用者在上傳圖檔時需要将圖檔儲存在伺服器某個目錄下,由于項目是導成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<String,String> 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<String,String> 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<String,String> 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<String,String> 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<String ,String> 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<String,Object> addGoodsImg(MultipartFile file){
if (file != null){
//上傳檔案
Map<String,String> 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<String,String> 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<String,String> uploadGoodsImg(MultipartFile file){
if (file != null){
//上傳檔案
Map<String,String> map = SaveImgUnit.saveMultFile(file,GOODS_IMG_PATH);
return map;
}else {
Map<String,String> 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.在前端中使用
<img src="http://localhost:端口/showImg?imgUrl=xxx" />
即可通路并在浏覽器顯示圖檔。
六、參考資料
https://blog.csdn.net/qq_39529566/article/details/81872062