Java连接ftp服务器

Java-操作ftp服务器

记录一下最近碰到的需求问题,文件同步,将oss文件同步到ftp服务器上,首先到手的ftp服务器是这样的,ssl证书过期,加密方式为隐式传输,默认端口990。FileZilla测试没有问题,直接上代码测试,结果第一步就卡住了,卡在了hostname的连接上,通过FileZilla连接过程初步判断是证书和加密方式的问题,然后就自己建了一个不含ssl证书,明文传输的,默认端口21的ftp,连接并操作果然完全没问题。

下面是对无证书无加密的ftp测试:

public static void main(String[] args) throws Exception {
        FTPClient ftpClient = new FTPClient();
    	//连接ftp
        ftpClient.connect("hostname", "port");
    	//登陆ftp
        ftpClient.login("username", "password");
    	//需要把文件上传到FTP哪个目录
        ftpClient.changeWorkingDirectory("/home/ftptest/test");
        ftpClient.deleteFile("/home/ftptest/test");
    	//需要上传的文件
        File file = new File("E:\\a.txt");
    	//存储文件,成功返回true,失败false
        System.out.println(ftpClient.storeFile(file.getName(), new FileInputStream(file)));
    }

1.连接服务器证书认证过期

连接到目标服务器,首先是需要设置隐式传输,就要先在创建对象时就先设置好,这时FTPClient他没有设置为隐式的构造方式,但他的子类FTPSClient,在他的构造函数中有

	/**
     * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
     * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
     * @param isImplicit The security mode(Implicit/Explicit).
     * @param context A pre-configured SSL Context
     */
    public FTPSClient(boolean isImplicit, SSLContext context) {
        this(DEFAULT_PROTOCOL, isImplicit);
        this.context = context;
    }

这个构造方法提供了证书和加密方式的设置,设为隐式传输只要isImplicit为true,而证书我是自定义一个证书,下面是证书初始化代码

    //创建SSL上下文 
    SSLContext sslContext = SSLContext.getInstance("TLS");
    //自定义证书,忽略已过期证书
    TrustManager[] trustAllCerts = new TrustManager[1];
    TrustManager tm = new miTM();
    trustAllCerts[0] = tm;
    //初始化
    sslContext.init(null, trustAllCerts, null);

    static class miTM implements TrustManager, X509TrustManager {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            public boolean isServerTrusted(X509Certificate[] certs) {
                return true;
            }

            public boolean isClientTrusted(X509Certificate[] certs) {
                return true;
            }

            public void checkServerTrusted(X509Certificate[] certs, String authType)
                    throws CertificateException {
                return;
            }

            public void checkClientTrusted(X509Certificate[] certs, String authType)
                    throws CertificateException {
                return;
            }
        }

2.上传文件失败

这次的上传文件失败,是因为使用的还是父类的ftpClient.storeFile()的方法,需要将FTPClient ftpClient = new FTPClient();改为FTPSClient ftpClient = new FTPSClient();通过测试会发现,使用俩种不同的初始化方式,虽然使用上传文件方法名都相同,但在方法中实现的方式不同,这时会在发现第三个问题。

3.上传文件进程卡住

选用了子类上传文件的方法,会发现进程会卡死,通过测试发现卡在socket = server.accept();中,百度后也没解决,然后再看上传的方法问题,在测试中会发现在程序运行时会比对一些参数,所以这里我们还需要进行其他的一些配置,像主动连接参数配置问题,不加也会发生进程卡死,因为默认为主动,需要设置为被动模式,传输失败跟传输端口有关,具体需要添加的配置如下

//设为被动模式		
ftpClient.enterLocalPassiveMode();
//设为CMD_PBSZ,是跟SSL证书的验证有关系
ftpClient.execPBSZ(0);
//设置PROT_COMMAND_VALUE(会进行参数匹配,"C","E","S","P"在不同范围内匹配不同方式)
ftpClient.execPROT("P");

4.文件上传成功,但是图坏了

历经千辛万苦,图片确实通过这种方式上传成功了,但是打开一看会发现图片失真了,这是因为和文本传输不同,传输图片需要对传输方式进行设置,设为二进制传输方式

//以二进制形式传输
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

以上就是这次遇到的一些问题,下面附完整代码

附录

    private OSS ossClient;

    private FTPSClient ftpClient;

    @Override
    public void FtpSyncFile(Long id) {

        List<MeetingTaskWechatPhoto> meetingTaskWechatPhotos = meetingTaskWechatPhotoRepository.findByMeetingTaskIdAndDeletedFalse(id);
        String meetingNo = meetingTaskRepository.findById(id).get().getMeetingNo();
        try {
            // 创建OSSClient实例。
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            // 读取文件内容。
            InputStream is = ossObject.getObjectContent();

            //创建SSL上下文
            SSLContext sslContext = SSLContext.getInstance("TLS");
            //自定义证书,忽略已过期证书
            TrustManager[] trustAllCerts = new TrustManager[1];
            TrustManager tm = new miTM();
            trustAllCerts[0] = tm;
            //初始化
            sslContext.init(null, trustAllCerts, null);

            //创建客户端,加密选择Implicit
            ftpClient = new FTPSClient(true, sslContext);
            //连接ftp
            ftpClient.connect(hostname, Integer.parseInt(port));
            //登陆ftp
            ftpClient.login(username, password);
            //创建文件夹
            ftpClient.makeDirectory("/" + meetingNo);
            //需要把文件上传到FTP哪个目录
            ftpClient.changeWorkingDirectory("/" + meetingNo);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.execPBSZ(0);
            ftpClient.execPROT("P");
            //上传图片
            for (MeetingTaskWechatPhoto meetingTaskWechatPhoto : meetingTaskWechatPhotos) {
                String photoUrl = meetingTaskWechatPhoto.getPhoto_url();
                String[] split = StringUtils.split(photoUrl, "/");
                String pictureName = split[split.length - 1];
                //存储文件,成功返回true,失败false
                //以二进制形式传输

                if (ftpClient.storeFile(pictureName, is)) {
                    log.info(pictureName + "上传成功");
                } else {
                    log.info(pictureName + "上传失败");
                }
            }
            //断开连接
            ftpClient.disconnect();
            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
            is.close();
            // 关闭OSSClient。
            ossClient.shutdown();

        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件同步失败!");
        }
    }

    static class miTM implements TrustManager, X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(X509Certificate[] certs, String authType)
                throws CertificateException {
            return;
        }

        public void checkClientTrusted(X509Certificate[] certs, String authType)
                throws CertificateException {
            return;
        }
    }

——————————————————————————

参考文章:https://blog.csdn.net/slan2069586311/article/details/89633741

你可能感兴趣的:(服务器,java,ssl)