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 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

你可能感兴趣的:(Spring,Boot实战)