图片上传--工作中

需求:在app接口文档中编写头像上传的接口;

1、在controller中传入人员的id以及头像,调用service层编写的头像上传的功能,代码如下:

@ApiOperation("头像上传")
    @PostMapping("/saveHeadImageUrl")
    public Result saveHeadImageUrl(HeadImageBean bean) {
        if (null == bean || DataUtil.isEmpty(bean.getImage()) || DataUtil.isEmpty(bean.getEmpId())) {
            return new Result(StatusCode.RET_BAD_REQUEST);
        }
        String s = workerService.uploadImage(bean.getEmpId(), bean.getImage());
        return new Result(s);
    }
View Code

2、进入uploadImage方法,同样传入的是工人id以及头像。new一个MultipartFile数组对象,长度为1,将图片传入数组中。此时,需要调用UploadImageUtil这个工具类,该工具类包括FTP上传下载的工具类、host、port、username、password,后面四个是进入远程ftp的参数。FTP上传下载的工具类代码如下:

package org.fiberhome.smartsiteapp.util.ftp;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.fiberhome.smartsiteapp.config.FtpException;
import org.fiberhome.smartsiteapp.util.DataUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;


/**
 * FTP上传下载
 *
 */
@Component
public class FtpUtil {
    protected  final static Logger logger = LoggerFactory.getLogger(FtpUtil.class);
    private FTPClient ftpClient = null;
    
    
    
    private String filePath;
    



    /**
     * 获取FTP连接
     * 
     * @param port
     * @param username
     * @param password
     * @return
     * @throws FtpException
     */
    
    public  void init(String host, int port, String username, String password) throws FtpException {
            if (ftpClient == null) {
                ftpClient = new FTPClient();
            }
            try {
                // 连接FTP服务器
                ftpClient.connect(host, port);
            } catch (Exception e) {
                throw new FtpException("FTP[" + host + ":" + port + "]连接失败!", e);
            }
            logger.info("ftpClient.getReplyCode()="+String.valueOf(ftpClient.getReplyCode()));
            // 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                try {
                    ftpClient.login(username, password);
                } catch (Exception e) {
                    throw new FtpException("FTP用户[" + username + "]登陆失败!", e);
                }
            } else {
                throw new FtpException("FTP连接出错!");
            }

            logger.info("用户[" + username + "]登陆[" + host + "]成功.");
            try {
                // 设置被动模式
                ftpClient.enterLocalPassiveMode();
                ftpClient.setFileTransferMode(FTPClient.STREAM_TRANSFER_MODE);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            } catch (Exception e) {
                logger.error("", e);
                throw new FtpException("FTP初始化出错!", e);
            }
    }

    /**
     * 关闭FTP客户端
     * 
     * @throws Exception
     */
    public void close(String username,String host) throws FtpException {
            try {
                ftpClient.logout();
                logger.info("用户[" + username + "]退出[" + host + "]成功.");
            } catch (IOException e) {
                logger.error("", e);
                ftpClient = null;
                throw new FtpException("FTP退出登录出错!", e);
            }
    }

    /**
     * 上传
     * 
     * @param fileName 上传目录
     * @param in 本地目录
     * @return
     * @throws Exception
     */
    public String uploadFile(String fileName ,InputStream in) throws Exception {
        try {
            setPath(filePath, true);
            ftpClient.storeFile(fileName, in);
            logger.info("[" + fileName + "]上传成功!");
            return filePath+"/"+fileName;
        } catch (IOException e) {
            logger.error("", e);
            throw new FtpException("FTP上传[" + fileName + "]出错!", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
    }



    /** 获得目录下最大文件名 */
    public String getMaxFileName(String remotePath) {
        try {
            ftpClient.changeWorkingDirectory(remotePath);
            FTPFile[] files = ftpClient.listFiles();
            Arrays.sort(files, new Comparator<FTPFile>() {
                public int compare(FTPFile o1, FTPFile o2) {
                    return o2.getName().compareTo(o1.getName());
                }
            });
            return files[0].getName();
        } catch (IOException e) {
            logger.error("", e);
            throw new FtpException("FTP访问目录[" + remotePath + "]出错!", e);
        }
    }

    
    public void setPath(String path, boolean createIfNotExists)
            throws Exception
          {
            if (DataUtil.isEmpty(path)) {
              return;
            }
            String[] ss = path.split("/");
            path = "/";
            for (int i = 0; i < ss.length; i++) {
              if (!DataUtil.isEmpty(ss[i])) {
                try {
                  path = path + ss[i] + "/";
                  int r = ftpClient.cwd(path);
                  if ((!FTPReply.isPositiveCompletion(r)) && (createIfNotExists)) {
                    ftpClient.makeDirectory(path);
                    ftpClient.cwd(path);
                  }
                } catch (Exception e) {
                  if (createIfNotExists) {
                    ftpClient.makeDirectory(path);
                    ftpClient.cwd(path);
                  } else {
                    throw e;
                  }
                }
              }
            }
            ftpClient.setFileType(2);
          }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
    
}
View Code

调用UploadImageUtil时,将MultipartFile数组对象中存的头像传入文件上传处理的方法内。

在工作中遇到的是为了使图片路径的唯一化,所以是以域名+项目名+时间+UUID生成的随机数+图片格式,比如:http://yl.fiberhomecloudnj.com:7084/SmartSiteApp/2019/10/19/be40cd28-7f92-4f8e-a915-de0637a1c2e8.jpg。当然这是生成图片最终的结果;

下面就是一步步的实现该路径:

 1、这是为图片路径进行初始化

DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String format = LocalDate.now().format(dt);
StringBuilder filePath = new StringBuilder("pub/");
filePath.append("SmartSiteApp/" + format);
/*设置FTP属性*/
ftpClient.setFilePath(filePath.toString());


2、登录远程ftp服务器:传入host、port、username、password
public  void init(String host, int port, String username, String password) throws FtpException {
            if (ftpClient == null) {
                ftpClient = new FTPClient();
            }
            try {
                // 连接FTP服务器
                ftpClient.connect(host, port);
            } catch (Exception e) {
                throw new FtpException("FTP[" + host + ":" + port + "]连接失败!", e);
            }
            logger.info("ftpClient.getReplyCode()="+String.valueOf(ftpClient.getReplyCode()));
            // 如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器
            if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                try {
                    ftpClient.login(username, password);
                } catch (Exception e) {
                    throw new FtpException("FTP用户[" + username + "]登陆失败!", e);
                }
            } else {
                throw new FtpException("FTP连接出错!");
            }

            logger.info("用户[" + username + "]登陆[" + host + "]成功.");
            try {
                // 设置被动模式
                ftpClient.enterLocalPassiveMode();
                ftpClient.setFileTransferMode(FTPClient.STREAM_TRANSFER_MODE);
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            } catch (Exception e) {
                logger.error("", e);
                throw new FtpException("FTP初始化出错!", e);
            }
    }
View Code

 3、上传图片具体操作:

  在图片路径初始化的基础上加上UUID生成的随机数,生成例如的路径SmartSiteApp/2019/10/19/be40cd28-7f92-4f8e-a915-de0637a1c2e8.jpg,代码如下:

Map<String, Object> fileMap = new HashMap<>();
            MultipartFile f = files[i];
            String name = f.getOriginalFilename();
            //后缀名唯一化,方便在数据库中进行更新操作
            String uuid = UUID.randomUUID().toString();
            String postFix = name.substring(name.lastIndexOf(".")).toLowerCase();
            //图片后缀名,压缩用
            String fileEnd = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
            String fileName = uuid + postFix;
View Code

  在原有的基础上,将原图片按照原尺寸压缩图片,具体方法实现是按照流实现的

//原图片
                BufferedImage imgsrc = ImageIO.read(f.getInputStream());
                // 原尺寸压缩图片
                BufferedImage newImg = disposeImage(imgsrc, imgsrc.getWidth(), imgsrc.getHeight());
                bs = new ByteArrayOutputStream();
                imOut = ImageIO.createImageOutputStream(bs);
                ImageIO.write(newImg, fileEnd, imOut);
                InputStream is = new ByteArrayInputStream(bs.toByteArray());
                fileName = ftpClient.uploadFile(fileName, is).replace("pub", "");
View Code

  其中已经通过调用upLoadFile将图片传入ftp服务器对应的目录下,然后通过拼接路径返回到上一级

/**
     * 上传
     * 
     * @param fileName 上传目录
     * @param in 本地目录
     * @return
     * @throws Exception
     */
    public String uploadFile(String fileName ,InputStream in) throws Exception {
        try {
            setPath(filePath, true);
            ftpClient.storeFile(fileName, in);
            logger.info("[" + fileName + "]上传成功!");
            return filePath+"/"+fileName;
        } catch (IOException e) {
            logger.error("", e);
            throw new FtpException("FTP上传[" + fileName + "]出错!", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
        }
    }
View Code

  将已经获得的路径名塞入map中,然后返回service层

/*上传*/
        List<Map<String, Object>> maps = uploadImageUtil.uploadImageToFtp(multipartFiles);
        String filePath = "#ftp#" + maps.get(0).get("filePath").toString();
        /*存库*/
        int i = workerMapper.updateHeadImage(empId, filePath);

        return urlBase + filePath.replaceAll("#ftp#", "");
View Code

  其中#ftp#是根据工作中数据库中存储图片路径的规范,将图片路径存入数据库后,就是将公网地址替代#ftp#,形成最后的访问上传头像的地址。

 其中UploadImageUtil的代码如下:

package org.fiberhome.smartsiteapp.util;

import org.fiberhome.smartsiteapp.config.FtpException;
import org.fiberhome.smartsiteapp.util.ftp.FtpUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.*;

/**
 * 文件上传
 *
 * @author lxc
 * @date 2019/7/22
 */
@Component
public class UploadImageUtil {
    @Resource
    private FtpUtil ftpClient;

    @Value("${ftp.host}")
    private String host;
    @Value("${ftp.port}")
    private int port;
    @Value("${ftp.name}")
    private String username;
    @Value("${ftp.password}")
    private String password;

    /**
     * 上传文件处理(支持批量),并且将图片大小进行压缩
     */
    public List<Map<String, Object>> uploadImageToFtp(MultipartFile[] files) {
        List<Map<String, Object>> file = new ArrayList<Map<String, Object>>();

        DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        String format = LocalDate.now().format(dt);
        StringBuilder filePath = new StringBuilder("pub/");
        filePath.append("SmartSiteApp/" + format);
        /*设置FTP属性*/
        ftpClient.setFilePath(filePath.toString());
        System.out.println(host + "----" + port + "----" + username + "----" + password);
        //登录远程ftp服务器
        ftpClient.init(host, port, username, password);

        /*上传图片*/
        for (int i = 0; i < files.length; i++) {
            Map<String, Object> fileMap = new HashMap<>();
            MultipartFile f = files[i];
            String name = f.getOriginalFilename();
            //后缀名唯一化,方便在数据库中进行更新操作
            String uuid = UUID.randomUUID().toString();
            String postFix = name.substring(name.lastIndexOf(".")).toLowerCase();
            //图片后缀名,压缩用
            String fileEnd = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
            String fileName = uuid + postFix;

            ImageOutputStream imOut = null;
            ByteArrayOutputStream bs = null;
            try {
                //原图片
                BufferedImage imgsrc = ImageIO.read(f.getInputStream());
                // 原尺寸压缩图片
                BufferedImage newImg = disposeImage(imgsrc, imgsrc.getWidth(), imgsrc.getHeight());
                bs = new ByteArrayOutputStream();
                imOut = ImageIO.createImageOutputStream(bs);
                ImageIO.write(newImg, fileEnd, imOut);
                InputStream is = new ByteArrayInputStream(bs.toByteArray());
                fileName = ftpClient.uploadFile(fileName, is).replace("pub", "");
                fileMap.put("filePath", fileName);
                file.add(fileMap);
            } catch (Exception e) {
                throw new FtpException("上传失败");
            }
        }
        ftpClient.close(username, host);
        return file;

    }

    /**
     * 上传文件处理(支持批量),并且将图片大小进行压缩
     */
//    public List<Map<String, Object>> uploadImageWithFtp(HttpServletRequest request) {
//        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
//                request.getSession().getServletContext());
//        List<Map<String, Object>> file = new ArrayList<Map<String, Object>>();
//        if (!multipartResolver.isMultipart(request)) {
//            throw new FtpException("非法参数");
//        }
//        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
//        Iterator<String> iterator = multiRequest.getFileNames();
//
//        String serverName = multiRequest.getParameter("serverName");
//        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");
//        String date = format.format(new Date());
//        StringBuilder filePath = new StringBuilder("pub/");
//        if (null == serverName && serverName.equals("")) {
//            filePath.append(date);
//        } else {
//            filePath.append(serverName + "/" + date);
//        }
//        ftpClient.setFilePath(filePath.toString());
//        System.out.println(host + "----" + port + "----" + username + "----" + password);
//        ftpClient.init(host, port, username, password);
//        while (iterator.hasNext()) {
//            String key = iterator.next();
//            MultipartFile multipartFile = multiRequest.getFile(key);
//            if (multipartFile != null) {
//                Map<String, Object> fileMap = new HashMap<>();
//                String name = multipartFile.getOriginalFilename();
//                fileMap.put("fileName", name);
//                String fileType = multipartFile.getContentType();
//                fileMap.put("fileType", fileType);
//
//                long fileBytes = multipartFile.getSize();
//                fileMap.put("fileBytes", fileBytes);
//                if (name.indexOf(".") == -1 && "blob".equals(name)) {
//                    name = name + ".png";
//                }
//                String uuid = UUID.randomUUID().toString();
//                String postFix = name.substring(name.lastIndexOf(".")).toLowerCase();
//                //图片后缀名,压缩用
//                String fileEnd = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
//                String fileName = uuid + postFix;
//                ImageOutputStream imOut = null;
//                ByteArrayOutputStream bs = null;
//                try {
//                    //原图片
//                    BufferedImage imgsrc = ImageIO.read(multipartFile.getInputStream());
//                    // 原尺寸压缩图片
//                    BufferedImage newImg = disposeImage(imgsrc, imgsrc.getWidth(), imgsrc.getHeight());
//                    bs = new ByteArrayOutputStream();
//                    imOut = ImageIO.createImageOutputStream(bs);
//                    ImageIO.write(newImg, fileEnd, imOut);
//                    InputStream is = new ByteArrayInputStream(bs.toByteArray());
//                    fileName = ftpClient.uploadFile(fileName, is).replace("pub", "");
//                    fileMap.put("filePath", fileName);
//                    file.add(fileMap);
//                } catch (Exception e) {
//                    throw new FtpException("上传失败");
//                }
//            }
//        }
//        ftpClient.close(username, host);
//        return file;
//    }

    /**
     * 压缩图片
     *
     * @param src
     * @param width
     * @param height
     * @return
     */
    private synchronized static BufferedImage disposeImage(BufferedImage src, int width, int height) {
        BufferedImage newImg = null;
        // 判断输入图片的类型
        switch (src.getType()) {
            case 13:
                // png,gifnewImg = new BufferedImage(new_w, new_h,
                // BufferedImage.TYPE_4BYTE_ABGR);
                break;
            default:
                newImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                break;
        }
        Graphics2D g = newImg.createGraphics();
        // 从原图上取颜色绘制新图
        g.drawImage(src, 0, 0, width, height, null);
        g.dispose();
        // 根据图片尺寸压缩比得到新图的尺寸
        newImg.getGraphics().drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
        return newImg;
    }
}
View Code
原文地址:https://www.cnblogs.com/lxc116317/p/11704527.html