【关于JAVA代码实现FTP服务器作为中介内外网交互】

本文主要根据项目中实际遇到情况作为案例简单分享一下思路。

一、项目实际需求

1.现有内网服务器一台,外网服务器一台。已搭建好FTP服务器,并完成了端口映射。实际情况如下:
【关于JAVA代码实现FTP服务器作为中介内外网交互】_第1张图片

解决思路:

1.外网服务器部署服务(此处不需要DB相关服务,只需要搭建FTP环境即可),调用外网服务器接口,外网服务将【请求】依据【自定义格式】以及【唯一规则命名】生成文件保存上传FTP输入目录中。

2.内网服务器部署完整的服务,监听FTP输入目录,一旦发现有新文件生成,则读取文件内容解析请求信息,然后调用接口,将【返回数据】依据【自定义格式】以及【唯一规则命名】生成文件保存上传FTP输出目录。(此处不采取外网服务器监听FTP输出目录来解析文件这种方式,考虑到会长期连接FTP服务器,浪费资源,也会出现掉线情况,还得考虑心跳包,而且整体效果不好)

整体解决思路完成。然后便是涉及到处理的细节方面:

为了模拟正常的前后端交互,便采取了如下方式:

1.客户端发出请求,外网服务器将请求根据【唯一命名】写入文件到FTP输入目录,之后对FTP输出目录进行轮询(根据网络环境需求,我这里最多只轮询了3次,每次间隔1S),如发现有同名文件返回则进行解析然后将数据返回至客户端。

2.在监听输入目录有新文件生成时,解析新文件,根据请求信息来执行业务代码,将返回数据封装成文件(文件命名同收到文件一样)保存至FTP输出目录。

3.注意:在进行解析后的文件都需删除,避免FTP目录中文件过多,导致轮询时间过长,若需要备份,则另外增加备份功能。

二、部分代码片段

1.外网服务器收到请求

 @RequestMapping("/list")
 //此处参数中的 loraName 为 当前操作用户,用于生成文件命名规则使用,data为请求数据。
    public R list(String loginName, String data, HttpServletRequest httpServletRequest) throws IOException {
        String accessToken = httpServletRequest.getHeader("accessToken");
        //baseUrl 为配置文件中项目请求路径
        String url = baseUrl+"/api/adviseManange/car/list";
        //此处我自定义的唯一文件名称为 【登录名 + 时间戳(精确到毫秒)】
        SimpleDateFormat sdf =new SimpleDateFormat("YYYYMMddHHmmssSSS");
        String date = sdf.format(new Date());
        String fileName =loginName+"_"+date;
        //将文件写入FTP输入目录
        ftpServerUtil.writeAndUploadFile(url,data,fileName,localUrl,accessToken);
        //轮询 查询FTP输出目录
        String backData = FTPSearchFile_out.fileList(host,port,userName,password,basePath,fileName+".txt");
        if (StringUtils.isBlank(backData)){
            return R.error("连接超时");
        }
        Map<String,Object> retMap = new Gson().fromJson(backData,Map.class);
        return R.ok(retMap);
    }

2.FTP写入操作 (此处采用的每次请求都去连接FTP服务器,也可采用先写一个FTP连接池,每次需要的时候就从连接池中借一个,用完还掉。可以根据具体项目来考虑,前者在性能上能满足就不需要使用后者了,后者在性能上更好,但是得增加连接池的维护操作)

@Component
public class FtpServerUtil {

    @Autowired
    FTPUtils ftpUtils;

    @Autowired
    //此处实体类已经注入了配置文件中 填写的相关 FTP服务器 配置
    private FTPProperties ftpProperties;

    public void writeAndUploadFile(String url,String data,String fileName,String localUrl,String accessToken) throws IOException {

        Map<String,String> query = new HashMap<>();
        query.put("url",url);
        query.put("data",data);
        if (StringUtils.isNotBlank(accessToken)){
            query.put("accessToken",accessToken);
        }
        String queryData = new Gson().toJson(query);
        // 生成的文件路径
        String path = localUrl +"\\"+ fileName + ".txt";
        File file = new File(path);
        if (!file.exists()) {
            file.getParentFile().mkdirs();
        }
        file.createNewFile();
        // write 解决中文乱码问题
        // FileWriter fw = new FileWriter(file, true);
        OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write(queryData);
        bw.flush();
        bw.close();
        fw.close();
        uploadFile(fileName+".txt", path);
    }

    public void uploadFile(String remoteFile, String localFile) {
        try {
            FTPClient ftp = new FTPClient();
            ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
            ftp.connect(ftpProperties.getHost(),ftpProperties.getPort());
            if(FTPReply.isPositiveCompletion(ftp.getReplyCode()))
            {
                ftp.login(ftpProperties.getUsername(),ftpProperties.getPassword());
            }
            int replyCode = ftp.getReplyCode(); //是否成功登录服务器
            if(!FTPReply.isPositiveCompletion(replyCode)){
                System.out.println("connect failed...ftp服务器");
            }
            ftp.changeWorkingDirectory(ftpProperties.getBaseUrl());
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            FileInputStream input = new FileInputStream(new File(localFile));
            ftp.storeFile(remoteFile, input);

            ftp.disconnect();
            input.close();

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

3.内网服务器监听FTP输入目录

@Component
public class FileListenerFactory {
    // 设置监听路径 此处是本地测试地址,可以换成服务器地址
    private final String monitorDir = "F:\\FTPTestIn";
    // 设置轮询间隔
    private final long interval = TimeUnit.SECONDS.toMillis(1);

    // 自动注入业务服务
    @Autowired
    private ListenerService listenerService;

    public FileAlterationMonitor getMonitor() {
        // 创建过滤器
        System.out.println("===in FileAlterationMonitor=== ");
        IOFileFilter directories = FileFilterUtils.and(
                FileFilterUtils.directoryFileFilter(),
                HiddenFileFilter.VISIBLE);
        IOFileFilter files = FileFilterUtils.and(
                FileFilterUtils.fileFileFilter(),
                FileFilterUtils.suffixFileFilter(".txt"));
        IOFileFilter filter = FileFilterUtils.or(directories, files);

        // 装配过滤器
//         FileAlterationObserver observer = new FileAlterationObserver(new File(monitorDir));
        FileAlterationObserver observer = new FileAlterationObserver(new File(monitorDir), filter);
        System.out.println("observer= "+observer);
        // 向监听者添加监听器,并注入业务服务
        observer.addListener(new FileListener(listenerService));
        //        observer.addListener(new FileListener());

        // 返回监听者
        return new FileAlterationMonitor(interval, observer);
    }

}
@Component
public class FileListenerRunner implements CommandLineRunner {


    @Autowired
    private FileListenerFactory fileListenerFactory;

    @Override
    public void run(String... args) throws Exception {

        // 创建监听者
        System.out.println("fileListenerFactory= "+fileListenerFactory);
        FileAlterationMonitor fileAlterationMonitor = fileListenerFactory.getMonitor();
        try {
            // do not stop this thread
            fileAlterationMonitor.start();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
public class FileListener extends FileAlterationListenerAdaptor{

    // 声明业务服务
    private ListenerService listenerService;

    // 采用构造函数注入服务
    public FileListener(ListenerService listenerService) {
        this.listenerService = listenerService;
    }

    @Override
    public void onStart(FileAlterationObserver observer) {

    }

    @Override
    public void onDirectoryCreate(File directory) {

    }

    @Override
    public void onDirectoryChange(File directory) {

    }

    @Override
    public void onDirectoryDelete(File directory) {

    }

    @Override
    public void onFileCreate(File file) {
        try {
            listenerService.require(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFileChange(File file) {

    }

    @Override
    public void onFileDelete(File file) {

    }

    @Override
    public void onStop(FileAlterationObserver observer) {

    }
}

监听业务处理类

@Service
public class ListenerService {

    @Value("${local-saveUrl}")
    private String localUrl;

    @Autowired
    FtpServerUtil ftpServerUtil;

    public void require(File file) throws IOException {

            String fileName = file.getName();
            fileName = fileName.substring(0,fileName.lastIndexOf("."));

            InputStreamReader isr = new InputStreamReader(new FileInputStream(file),  "UTF-8");
            BufferedReader br = new BufferedReader(isr);
            StringBuffer resposeBuffer = new StringBuffer("");
            String lineTxt = "";
            String b = "";
            while ( (b = br.readLine()) != null) {
                lineTxt = lineTxt + b ;
            }


            Map<String,String> map = new HashMap<>();
            try {
                 map = (Map)JSON.parse(lineTxt);
            }catch (Exception e){
                e.printStackTrace();
            }

            String url = map.get("url");
            String data = map.get("data");
            String accessToken = map.get("accessToken");
            Map<String,String> dataMap = new HashMap<>();

            try {
                dataMap = (Map<String,String>)JSON.parse(data);
            }catch (Exception e){
                e.printStackTrace();
            }
            if (dataMap == null || dataMap.size()<=0){
                dataMap = new HashMap<>();
            }
            //通过HttpPost 方式调用接口
            String retString = HttpUtil.doPost(url, dataMap, accessToken);
            //将返回的数据封装并写入FTP输出目录。
            ftpServerUtil.writeAndUploadFile(retString,fileName,localUrl);
            br.close();

    }
}
三、总结
此方式需要注意的几个点。

1.在写入文件时,文件命名唯一的标准。
2.根据服务器,网络环境设置轮询时间。
3.根据项目实际使用情况来选用FTP直连 或者 连接池方式。

此为项目中遇到,特此记录采用的方式,以及解决思路,也许之后经验丰富了,能有更好的解决办法,若有不正确,漏掉的细节部分,望各位大佬留言提醒,谢谢了!【 一位搬砖码农日常】

你可能感兴趣的:(java日常记录,java,linux)