欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java实现ftpServer

程序员文章站 2024-03-24 08:11:04
...

maven依赖

        <dependency>
            <groupId>org.apache.ftpserver</groupId>
            <artifactId>ftpserver-core</artifactId>
            <version>1.1.1</version>
            <scope>compile</scope>
        </dependency>

 

FtpServer.java ftp服务器的相关配置,用户,密码等



@Component
@Slf4j
public class FtpServer implements CommandLineRunner {


    @Autowired
    private LocalFtplet localFtplet;

    @Autowired
    private FtpServerFactory ftpServerFactory;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Value("${ftp.server.port}")
    private int serverPort;

    @Value("${ftp.rootdir}")
    private String ftpRootDir;
    private static List<Authority> authorities = new ArrayList<>();

    static {
        authorities.add(new WritePermission());
    }

    @Autowired
    private CameraManager cameraManager;

    @Override
    public void run(String... args) throws Exception {
        ListenerFactory factory = new ListenerFactory();
        //设置监听端口
        factory.setPort(serverPort);
        DataConnectionConfigurationFactory dataConnectionConfFactory = new DataConnectionConfigurationFactory();
        dataConnectionConfFactory.setPassivePorts("10000-10500");
        factory.setDataConnectionConfiguration(dataConnectionConfFactory.createDataConnectionConfiguration());
        //替换默认监听
        ftpServerFactory.addListener("default", factory.createListener());
        UserManager userManager = ftpServerFactory.getUserManager();
        //添加ftp用户
        cameraManager.getAllCameraInfo().forEach(item -> {
            try {
                userManager.save(createFtpBaseUser(item.getSerialNo()));
            } catch (FtpException e) {
                e.printStackTrace();
            }
        });
        Map<String, Ftplet> ftpLets = new HashMap<>();
        ftpLets.put("ftpService", localFtplet);
        ftpServerFactory.setFtplets(ftpLets);
        org.apache.ftpserver.FtpServer server = ftpServerFactory.createServer();
        server.start();
        new FtpInitTask().init();
    }


    @EventListener
    public void handlerCameraSerialNoChange(CameraSerialNoChangeEvent event) {
        UserManager userManager = ftpServerFactory.getUserManager();
        try {
            if (CameraChangeType.DELETE.equals(event.getChangeType())) {
                deleteFtpUser(userManager, event.getSerialNo());
            } else if (CameraChangeType.UPDATE.equals(event.getChangeType())) {
                updateFtpUser(userManager, event.getSerialNo());
            }
        } catch (FtpException e) {
            log.error("修改ftp用户信息失败", e);
        }
    }


    class FtpInitTask {

        public void init() throws Exception {
            updateUsersRootDir();
            scheduledExecutorService.scheduleAtFixedRate(this::updateUsersRootDir, getInitialDelay(), 60 * 60 * 24, TimeUnit.SECONDS);
        }

        private void updateUsersRootDir() {
            UserManager userManager = ftpServerFactory.getUserManager();
            cameraManager.getAllCameraInfo().forEach(cameraInfo -> updateUserRootDir(userManager, cameraInfo));
        }

        public void updateUserRootDir(UserManager userManager, CameraInfo cameraInfo) {
            try {
                updateFtpUser(userManager, cameraInfo.getSerialNo());
            } catch (FtpException e) {
                log.error("修改ftp用户信息失败", e);
            }
        }

        /**
         * 获取第二天凌晨的时间戳
         *
         * @return
         */
        private long getTomorrowOneOClockTime() {
            Calendar c = Calendar.getInstance();
            c.add(Calendar.DAY_OF_MONTH, 1);
            c.set(Calendar.HOUR_OF_DAY, 0);
            c.set(Calendar.MINUTE, 0);
            c.set(Calendar.SECOND, 0);
            c.set(Calendar.MILLISECOND, 0);
            return c.getTimeInMillis();
        }

        private long getInitialDelay() {
            //延迟一秒执行,解决系统获取当前时间为昨天日期的问题
            return (getTomorrowOneOClockTime() - System.currentTimeMillis()) / 1000 + 1;
        }
    }


    private void updateFtpUser(UserManager userManager, String serialNo) throws FtpException {
        deleteFtpUser(userManager, serialNo);
        BaseUser baseUser = createFtpBaseUser(serialNo);
        String rootdir = baseUser.getHomeDirectory();
        String dir = PathUtils.filePathJoin(rootdir, TimeUtils.getNowTimeStr("yyyy-MM-dd"));
        createDir(dir);
        baseUser.setHomeDirectory(dir);
        userManager.save(baseUser);
    }

    private void deleteFtpUser(UserManager userManager, String serialNo) {
        try {
            if (userManager.doesExist(serialNo)) {
                userManager.delete(serialNo);
            }
        } catch (FtpException e) {
            log.error("删除ftp用户失败:username{}", serialNo);
        }
    }


    private BaseUser createFtpBaseUser(String serialNo) {
        BaseUser user = new BaseUser();
        user.setName(serialNo);
        //密码 如果不设置密码就是匿名用户
        user.setPassword(serialNo);
        //用户主目录
        user.setHomeDirectory(PathUtils.filePathJoin(ftpRootDir, serialNo));
        user.setAuthorities(authorities);
        return user;
    }


    //增加写权限


    private void createDir(String dir) {
        File folder = new File(dir);
        if (!folder.exists() && !folder.isDirectory()) {
            log.info("创建图片文件夹:{},结果:{}", dir, folder.mkdirs());
        }
    }
}

 

 

LocalFtplet.java  文件上传的各种回调



@Slf4j
@Component
public class LocalFtplet extends DefaultFtplet {

    @Autowired
    private ApplicationEventPublisher publisher;

    @Autowired
    private FtpFileUploadTimeHandlerCenter ftpFileUploadTimeHandlerCenter;


    @Override
    public FtpletResult onUploadStart(FtpSession session, FtpRequest request)
            throws FtpException, IOException {
        //获取上传文件的上传路径
        String path = session.getUser().getHomeDirectory();
        //获取上传用户
        String name = session.getUser().getName();
        //获取上传文件名
        String filename = request.getArgument();
        log.info("用户:'{}',开始上传文件到目录:'{}',文件名称为:'{}',时间:{}", name, path, filename, TimeUtils.getNowTimeStr());
        int startTimeRecordMapSize = ftpFileUploadTimeHandlerCenter.getStartTimeRecordMap().size();
        if (startTimeRecordMapSize < 300) {
            ftpFileUploadTimeHandlerCenter.putSessionStartTime(session.getSessionId().toString(), System.currentTimeMillis());
        } else {
            log.warn("积累了太多的开始时间未处理:startTimeRecordMap size: {}", startTimeRecordMapSize);
        }
        return super.onUploadStart(session, request);
    }


    @Override
    public FtpletResult onUploadEnd(FtpSession session, FtpRequest request)
            throws FtpException, IOException {
        //获取上传文件的上传路径
        String path = session.getUser().getHomeDirectory();
        //获取上传用户
        String name = session.getUser().getName();
        //获取上传文件名
        String filename = request.getArgument();
        log.info("用户:'{}',上传文件到目录结束:'{}',文件名称为:'{},时间:{}'", name, path, filename, TimeUtils.getNowTimeStr());

        String sessionId = session.getSessionId().toString();
        long uploadStartTime = getUploadStartTime(sessionId);
        publisher.publishEvent(FileUploadEvent.builder()
                .fileName(filename)
                .path(path)
                .sessionId(sessionId)
                .ftpUser(name)
                .uploadStartTime(uploadStartTime)
                .uploadTakeTime(countUploadTakeTime(uploadStartTime))
                .build());
        publisher.publishEvent(new ThumbnailsImageSaveEvent(filename, path, ThumbnailsImageSaveTypeEnum.SOURCE_THUMBNAILS));
        return super.onUploadEnd(session, request);
    }


    private Long countUploadTakeTime(long startUploadTime) {
        if (startUploadTime == 0L) {
            return 0L;
        }
        return System.currentTimeMillis() - startUploadTime;
    }

    private Long getUploadStartTime(String sessionId) {
        return ftpFileUploadTimeHandlerCenter.getStartTimeRecord(sessionId)
                .orElseGet(() -> {
                    log.warn("未找到文件开始上传时间");
                    return 0L;
                });
    }


}