java实现图片直接上传到ftp服务器

工作半年了,之前总是喜欢把总结和学习到的新东西放到自己OneNote上保存,方便自己回顾。但最近翻翻boss直聘上的要求,貌似写技术博客是个加分项哎,思来想去,决定以后但文档都在简上写好了,因为平时查问题的时候发现还是的排版最好,废话不说了开始吧!

  • pom.xml依赖引入

  
    
      commons-net
      commons-net
      3.1
    
  • FtpUtil工具类,主要是封装了利用commons.net包下的FTPClient连接、登陆ftp服务器,并切换到ftp服务器下指定文件夹,设置上传到一些属性最后完成上传。其中的ftpIP,ftpUser, ftpPass, ftpPort都是从配置文件properties中读取的。

public class FtpUtil {

    private static Logger logger = LoggerFactory.getLogger(FtpUtil.class);
    //从properties文件读取相应的配置
    private static String ftpIP = PropertiesUtil.getProperty("ftp.server.ip");
    private static String ftpUser = PropertiesUtil.getProperty("ftp.user");
    private static String ftpPass = PropertiesUtil.getProperty("ftp.pass");
    private static String ftpPort = PropertiesUtil.getProperty("ftp.port");

/**
     * 将文件直接上传到ftp服务器到方法,不会经过tomcat本地缓冲
     *
     * @param remotePath  ftp服务器中的文件夹
     * @param fileName    文件的新名称
     * @param inputStream
     * @return
     */
    public static boolean uploadFile(String remotePath, String fileName, InputStream inputStream) {
        boolean isSeccess = false;
        boolean result = false;
        FTPClient ftpClient = new FTPClient();
        try {
            //连接登陆
            ftpClient.connect(ftpIP);
            isSeccess = ftpClient.login(ftpUser, ftpPass);
            logger.info("ftp服务器:{},登陆--{}", ftpIP, isSeccess);
            //如果登陆成功...
            if (isSeccess) {
                //切换到指定的ftp服务器文件夹目录
                boolean isChangeSuccess = ftpClient.changeWorkingDirectory(remotePath);
                //如果切换失败则创建改目录再切换
                if (!isChangeSuccess) {
                    ftpClient.makeDirectory(PropertiesUtil.getProperty("ftp.dir"));
                    ftpClient.changeWorkingDirectory(remotePath);
                }
                //设置缓冲大小,编码格式,文件类型
                ftpClient.setBufferSize(1024);
                ftpClient.setControlEncoding("UTF-8");
                ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                //开始上传
                logger.info("开始上传文件:{}", fileName);
                result = ftpClient.storeFile(fileName, inputStream);
                logger.info("文件:{},上传:{}", fileName, result);
                return result;
            }
        } catch (IOException e) {
            logger.error("文件上传失败", e);
        } finally {
            try {
                //关闭流
                inputStream.close();
                ftpClient.logout();
            } catch (IOException e) {
                logger.error("输入流关闭失败", e);
            }
        }
        return result;
    }
}
  • Service层主要是对上传对文件进行重命名,并封装好返回给前端的结果样式,其中ServerResponse对象是前端要求的高可用响应对象,附在最后

@Service("iFileService")
public class FileServiceImpl implements IFileService {

    //让控制台输出此文件记录内容
    private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);

    /**
     * 将文件直接上传至ftp服务器
     *
     * @param file
     * @return
     */
    @Override
    public ServerResponse upload(MultipartFile file) {
        Map resultMap = new HashMap();
        String oldName = file.getOriginalFilename();
        String newName = UUID.randomUUID().toString();
        //给文件重命名
        newName = newName + oldName.substring(oldName.lastIndexOf("."));
        try {
            //利用FtpUtil中到方法进行上传文件
            boolean result = FtpUtil.uploadFile(PropertiesUtil.getProperty("ftp.dir"), newName, file.getInputStream());
            if (result) {
                //如果上传成功,则返回前端新的文件名和路径
                resultMap.put("uri", newName);
                //根据nginx配置的ftp文件夹和域名的对应关系组装文件在ftp服务器中的位置
                resultMap.put("url", PropertiesUtil.getProperty("ftp.server.http.prefix") + PropertiesUtil.getProperty("ftp.dir") + newName);
                return ServerResponse.createBySucess(resultMap);
            } else {
                return ServerResponse.createByErrorMessage("上传失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ServerResponse.createByErrorMessage("上传失败");
    }
}
  • Controller层逻辑,主要是对用户权限对校验以及文件上传

@RequestMapping(value = "upload", method = {RequestMethod.POST})
    @ResponseBody
    public ServerResponse upload(@RequestParam(value = "file", required = true) MultipartFile file, HttpSession session) {
        User user = (User) session.getAttribute(Const.CURRENT_USER);
        if (user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登陆");
        }
        if (user.getRole() != Const.ADMIN) {
            return ServerResponse.createByErrorMessage("用户无此权限");
        }
        //业务逻辑
        return iFileService.upload(file);
    }

  • 附:高可用响应类
public class ServerResponse implements Serializable {
    private int status;
    private String msg;
    private T data;

    private ServerResponse(int status) {
        this.status = status;
    }

    private ServerResponse(int status, T data) {
        this(status, data, null);
    }

    private ServerResponse(int status, T data, String msg) {
        this.status = status;
        this.data = data;
        this.msg = msg;
    }

    private ServerResponse(int status, String msg) {
        this(status);
        this.msg = msg;
    }
    @JsonIgnore     //json序列化到时候就不会显示这个public方法在json里面
    public boolean isSuccess() {
        return this.status == ResponseCode.SUCCESS.getCode();
    }

    public int getStatus() {
        return status;
    }

    public T getData() {
        return data;
    }

    public String getMsg() {
        return msg;
    }

    //成功时返回到数据封装ServerResponse对象
    public static  ServerResponse createBySucess(){
        return new ServerResponse(ResponseCode.SUCCESS.getCode());
    }
    public static  ServerResponse createBySucessMsg(String msg){
        return new ServerResponse(ResponseCode.SUCCESS.getCode(),msg);
    }
    public static  ServerResponse createBySucess(T data){
        return new ServerResponse(ResponseCode.SUCCESS.getCode(),data);
    }
    public static  ServerResponse createBySucess(String msg,T data){
        return new ServerResponse(ResponseCode.SUCCESS.getCode(),data,msg);
    }

    public static  ServerResponse createByError(){
        return new ServerResponse(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc());
    }
    public static  ServerResponse createByErrorMessage(String msg){
        return new ServerResponse(ResponseCode.ERROR.getCode(),msg);
    }
    public static  ServerResponse createByErrorCodeMessage(Integer code,String msg){
        return new ServerResponse(code,msg);
    }
}
  • 附:properties配置文件,其中ftp.server.http.prefix是nginx配置文件中对应ftp文件夹的那个servername
ftp.server.ip=192.168.1.1
ftp.user=ftpuser
ftp.pass=123456
ftp.server.http.prefix=http://image.test.com/
ftp.port=21

#ftp.dir=img/
ftp.dir=video/
  • 这个是conf.d文件夹下自己添加的conf文件,其中的image.test.com对应的是服务器根目录下的ftpfile文件,如果只是测试,在本机hosts文件中也要配置域名和ip的对应关系。否则从返回的结果中也是无法访问的

当在浏览器中输入image.test.com域名时,首先会从本机hosts文件查看是否有对应的ip,如果有则去访问对应的ip资源,然后会被nginx截获,并与nginx配置的域名ip对应关系对比,如果一致则可以访问资源。

server {
    listen 80;
    autoindex on;
    server_name image.test.com;
    access_log /etc/nginx/logs/access.log combined;
    index index.html index.htm index.jsp index.php;
    #error_page 404 /404.html;
    if ( $query_string ~* ".*[\;'\<\>].*" ){
        return 404;
    }

    location ~ /(mmall_fe|mmall_admin_fe)/dist/view/* {
        deny all;
    }

    location / {
        root /ftpfile;
        add_header Access-Control-Allow-Origin *;
    }
}

  • 最后的返回结果样式, 直接访问url后的结果
{
    "status": 0,
    "data": {
        "uri": "05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg",
        "url": "http://image.test.com/video/05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg"
    }
}
//Linux服务器中ftpfile文件夹中的video文件下的上传文件
[slf@www ftpfile]$ cd video
[slf@www video]$ ls
05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg
[slf@www video]$ 

image.png

你可能感兴趣的:(java实现图片直接上传到ftp服务器)