天天看點

springboot項目導成jar包部署至Linux,圖檔上傳時儲存至jar包外的目錄問題的解決方案

最近項目的需要,使用者在上傳圖檔時需要将圖檔儲存在伺服器某個目錄下,由于項目是導成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

繼續閱讀