ftp所需依赖:
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>1.4.1<version>
</dependency>
FTPClientUtils 工具类
package com.thinkgem.jeesite.common.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;
import com.thinkgem.jeesite.modules.sys.utils.DictUtils;
public class FTPClientUtils {
protected Logger logger = Logger.getLogger("FTPClientUtils");
/*
* //ftp://120.35.26.129:9754/IMAGE/ 心电图室
* //ftp://120.35.26.129:9754/IMAGE/ 彩超室
* //US/20190314/2011659/0.jpg
* //US/20190314/2011659/1.jpg
* /*String hostname = "120.35.26.129"; //ftp服务器地址
* String username = "peisusr"; //用户名
* String password = "Tj1234";
* String remoteBaseDir = "/IMAGE"; //ftp服务器目录
*/
public String hostname = "106.15.124.251";
//ftp服务器端口号默认为21
public Integer port = 21 ;
//ftp登录账号
public String username = "zhangsan";
//ftp登录密码
public String password = "1234";
public FTPClient ftpClient = null;
/**
* 初始化ftp服务器
*/
public void initFtpClient() {
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
System.out.println("connecting...ftp服务器:"+this.hostname+":"+this.port);
ftpClient.connect(hostname, port); //连接ftp服务器
ftpClient.login(username, password); //登录ftp服务器
int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
if(!FTPReply.isPositiveCompletion(replyCode)){
System.out.println("connect failed...ftp服务器:"+this.hostname+":"+this.port);
logger.error("connect failed..ftp服务器:"+this.hostname+":"+this.port+":"+this.username+":"+this.password);
}
System.out.println("connect successfu...ftp服务器:"+this.hostname+":"+this.port);
logger.error("connect failed..ftp服务器:"+this.hostname+":"+this.port+":"+this.username+":"+this.password);
}catch (Exception e) {
logger.error("初始化ftp服务器异常:"+this.hostname+":"+this.port+":"+this.username+":"+this.password,e);
}
}
/**
* 上传文件
* @param pathname ftp服务保存地址
* @param fileName 上传到ftp的文件名
* @param originfilename 待上传文件的名称(绝对地址) *
* @return
*/
public boolean uploadFile( String pathname, String fileName,String originfilename){
boolean flag = false;
InputStream inputStream = null;
try{
System.out.println("开始上传文件");
inputStream = new FileInputStream(new File(originfilename));
initFtpClient();
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.changeWorkingDirectory(pathname);
ftpClient.enterLocalPassiveMode();//被动模式
//ftpClient.enterLocalActiveMode();// //主动模式
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
ftpClient.logout();
flag = true;
System.out.println("上传文件成功");
}catch (Exception e) {
System.out.println("上传文件失败");
logger.error("上传文件失败",e);
e.printStackTrace();
}finally{
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
/**
* 上传文件
* @param pathname ftp服务保存地址
* @param fileName 上传到ftp的文件名
* @param inputStream 输入文件流
* @return
*/
public boolean uploadFile( String pathname, String fileName,InputStream inputStream){
boolean flag = false;
try{
System.out.println("开始上传文件");
initFtpClient();
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.changeWorkingDirectory(pathname);
ftpClient.enterLocalPassiveMode();//被动模式
//ftpClient.enterLocalActiveMode();// //主动模式
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
ftpClient.logout();
flag = true;
System.out.println("上传文件成功");
}catch (Exception e) {
System.out.println("上传文件失败");
logger.error("上传文件失败",e);
}finally{
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
//改变目录路径
public boolean changeWorkingDirectory(String directory) {
boolean flag = true;
try {
flag = ftpClient.changeWorkingDirectory(directory);
if (flag) {
System.out.println("进入文件夹" + directory + " 成功!");
} else {
System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹");
logger.error("进入文件夹" + directory + " 失败!开始创建文件夹");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return flag;
}
//创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
public boolean CreateDirecroty(String remote) throws IOException {
logger.error("创建文件夹的方法remote=" + remote);
boolean success = true;
String directory = remote + "/";
logger.error("创建文件夹的方法directory=" + directory);
// 如果远程目录不存在,则递归创建远程服务器目录
if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) {
logger.error("创建文件夹的方法判断完目录");
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
String path = "";
String paths = "";
for (int i = 1; i < 10; i++) {
logger.error("创建文件夹的方法" + i + ",subDirectory=" + remote.substring(start, end));
String subDirectory = new String(remote.substring(start, end).getBytes("GBK"), "iso-8859-1");
logger.error("创建文件夹的方法" + i + ",subDirectory=" + subDirectory);
subDirectory = remote.substring(start, end);
path = path + "/" + subDirectory;
logger.error("创建文件夹的方法" + i + ",path=" + path);
//logger.error("创建文件夹的方法" + i + ",existFile=" + existFile(path));
//if (!existFile(path)) {
if (makeDirectory(subDirectory)) {
changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录[" + subDirectory + "]失败");
logger.error("创建文件夹的方法" + i + ",创建目录[" + subDirectory + "]失败");
changeWorkingDirectory(subDirectory);
}
// } else {
// changeWorkingDirectory(subDirectory);
// }
paths = paths + "/" + subDirectory;
logger.error("创建文件夹的方法" + i + ",paths" + paths);
start = end + 1;
end = directory.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
if (i == 9) {
logger.error("创建文件夹的方法死循环");
}
}
}
return success;
}
//判断ftp服务器文件是否存在
public boolean existFile(String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
//创建目录
public boolean makeDirectory(String dir) {
boolean flag = true;
try {
flag = ftpClient.makeDirectory(dir);
if (flag) {
System.out.println("创建文件夹" + dir + " 成功!");
logger.error("创建文件夹" + dir + " 成功!");
} else {
System.out.println("创建文件夹" + dir + " 失败!");
logger.error("创建文件夹" + dir + " 失败!");
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
/** * 下载文件 *
* @param pathname FTP服务器文件目录 *
* @param filename 文件名称 *
* @param localpath 下载后的文件路径 *
* @return */
public boolean downloadFile(String pathname, String filename, String localpath){
boolean flag = false;
OutputStream os=null;
try {
initFtpClient();
ftpClient.enterLocalPassiveMode();//被动模式
//ftpClient.enterLocalActiveMode();//主动模式
//切换FTP目录
ftpClient.changeWorkingDirectory(pathname);
logger.error("*****************开始获取该目录下 "+pathname+" 有多少文件********************");
System.out.println("*****************开始获取该目录下 "+pathname+" 有多少文件********************");
FTPFile[] ftpFiles = ftpClient.listFiles();//如果目录不存在,则会获取根目录的文件或目录
logger.error("该下载目录:"+pathname+" 有"+ftpFiles.length+"个文件");
System.out.println("该下载目录:"+pathname+" 有"+ftpFiles.length+"个文件");
for(FTPFile file : ftpFiles){
if(filename.equalsIgnoreCase(file.getName())){
File localFile = new File(localpath + "/" + file.getName());
os = new FileOutputStream(localFile);
ftpClient.retrieveFile(file.getName(), os);
os.close();
}
}
ftpClient.logout();
flag = true;
System.out.println("下载文件成功");
} catch (Exception e) {
System.out.println("下载文件失败");
logger.error("下载文件失败",e);
e.printStackTrace();
} finally{
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
if(null != os){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
public String downloadFileq(String path,String ftpName,File localFile) {
boolean flag=true;
initFtpClient();
//保存至Ftp
try {
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
//ftpClient.enterLocalPassiveMode(); // 用被动模式传输,解决linux服务长时间等待,导致超时问题
ftpClient.setBufferSize(1024*1024);//设置缓存区,默认缓冲区大小是1024,也就是1K
//切换目录,目录不存在创建目录
ftpClient.changeWorkingDirectory(path);
OutputStream os = new FileOutputStream(localFile);
flag = ftpClient.retrieveFile(ftpName, os);
//关闭流
os.flush();
os.close();
//关闭连接
ftpClient.logout();
ftpClient.disconnect();
System.out.println("******************downloadFileq下载成功:——"+ftpName+"*******************************");
logger.error("******************downloadFileq下载成功——"+ftpName+"*******************************");
} catch (SocketException e) {
System.out.println("*****************downloadFileq-SocketException下载失败:"+e);
logger.error("*****************downloadFileq-SocketException下载失败:"+e);
return "SocketNotSuccess-SocketException";
} catch (IOException e) {
System.out.println("*****************downloadFileq-IOException下载失败:"+e);
logger.error("*****************downloadFileq-IOException下载失败下载失败:"+e);
return "SocketNotSuccess-IOException";
}
return "************downloadFileq下载成功******************";
}
/** * 删除文件 *
* @param pathname FTP服务器保存目录 *
* @param filename 要删除的文件名称 *
* @return */
public boolean deleteFile(String pathname, String filename){
boolean flag = false;
try {
System.out.println("开始删除文件");
initFtpClient();
//切换FTP目录
ftpClient.changeWorkingDirectory(pathname);
ftpClient.dele(filename);
ftpClient.logout();
flag = true;
System.out.println("删除文件成功");
} catch (Exception e) {
System.out.println("删除文件失败");
logger.error("删除文件失败",e);
e.printStackTrace();
} finally {
if(ftpClient.isConnected()){
try{
ftpClient.disconnect();
}catch(IOException e){
e.printStackTrace();
}
}
}
return flag;
}
public static void main(String[] args) {
FTPClientUtils ftp =new FTPClientUtils();
//ftp.uploadFile("/US", "te111.png", "D://download//test111.png");
//ftp.downloadFile("/AS/2099999190730/12345678/", "3.jpg", "D://");
// File f=new File("D:/bbb.jpg");
// System.out.println(ftp.downloadFileq("/AS/20190730/12345678/", "1.jpg", f));
// ftp.deleteFile("/US", "test111.png");
}
}
jsp文件:
<%@ page contentType="text/html;charset=UTF-8" %>
<%--<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>--%>
<%@ include file="/WEB-INF/views/include/taglib.jsp"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${ctx}/ftpTransfer/upload" method="post" enctype="multipart/form-data">
<%-- <label>用户名:</label><input type="text" name="name"/><br/>--%>
<label>体检号:</label><input type="text" name="paraTJH000"/><br/>
<label>科室类型:</label><input type="text" name="paraKSLX00"/><br/>
<label>是否打印1或0:</label><input type="text" name="paraBDY000"/><br/>
<label>头 像1</label><input type="file" name="file"/><br/>
<label>头 像2</label><input type="file" name="file"/><br/>
<input type="submit" value="提 交"/>
</form>
</body>
</html>
控制层:
package com.thinkgem.jeesite.modules.xmsq.web;
import com.thinkgem.jeesite.common.domain.ResponseBo;
import com.thinkgem.jeesite.common.utils.CommonUtils;
import com.thinkgem.jeesite.common.utils.FTPClientUtils;
import com.thinkgem.jeesite.modules.common.aop.SystemLog;
import com.thinkgem.jeesite.modules.xmsq.service.FtpTransferService;
import com.thinkgem.jeesite.modules.xmsq.utils.XmsqUserUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
@Controller
@RequestMapping(value ="${adminPath}/ftpTransfer")
public class FtpTransferController {
protected Logger applog = Logger.getLogger("applog");
@Autowired
private FtpTransferService ftpTransferService;
/**
* 上传图片文件到ftp服务器
* @param request
* @return
* PEIS_ReportPictureManage.examItemPictureOperate
*/
@ResponseBody
@SystemLog(module = "ftpTransfer:upload")
@RequestMapping(value = {"upload"})
public Object upload(@RequestParam("file")MultipartFile[] file , @RequestParam Map<String,Object> params, HttpServletRequest request){
ResponseBo responseBo = ResponseBo.ok();
try {
params.put("paraOPFLAG", "0");//0新增 1修改 2删除 这里是新增 设置为0
/*params.put("paraTJH000", "1234567");
params.put("paraKSLX00", "US");
params.put("paraBMBH00", "90");
params.put("paraCZY000", "9999");
params.put("paraBDY000", "1");*/
if(!CommonUtils.isStringNull((String) params.get("paraTJH000"))){
responseBo = ResponseBo.error("体检号不能空");
return responseBo;
}
if(!CommonUtils.isStringNull((String) params.get("paraKSLX00"))){
responseBo = ResponseBo.error("科室类型不能为空");
return responseBo;
}
if(!CommonUtils.isStringNull((String) params.get("paraBDY000"))){
responseBo = ResponseBo.error("是否在报告上展示不能为空 1-展示,0-不展示");
return responseBo;
}
XmsqUserUtils.putBasicParameters(params);
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String str = sdf.format(date);
FTPClientUtils ftp = new FTPClientUtils();
for (int i = 0; i < file.length; i++) {
if (!file[i].isEmpty()) {
InputStream is = file[i].getInputStream();
ftp.uploadFile("/"+params.get("paraKSLX00")+"/"+str+"/"+params.get("paraTJH000"),i+".jpg",is);
}
}
responseBo.put("data", params);
}catch (Exception e) {
responseBo = ResponseBo.error(e.getMessage(),e);
applog.error("上传图片失败" , e);
}
return responseBo;
}
@RequestMapping(value = "toUpload")
public String upload(HttpServletRequest request) {
return "modules/test/upload";
}
}
ftp java中设置主动模式或被动模式
ftpClient.enterLocalActiveMode(); //主动模式
// ftpClient.enterLocalPassiveMode(); 被动模式
主动模式:
PORT中文称为主动模式,工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据,原理如下图:
被动模式:
PASV是Passive的缩写,中文成为被动模式,工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输,原理如下图:
从上面的运行原来看到,主动模式和被动模式的不同简单概述为: 主动模式传送数据时是“服务器”连接到“客户端”的端口;被动模式传送数据是“客户端”连接到“服务器”的端口。
主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
被动模式只需要服务器端开放端口给客户端连接就行了。
我在实际项目中碰到的问题是,FTP的客户端和服务器分别在不同网络,两个网络之间有至少4层的防火墙,服务器端只开放了21端口, 客户端机器没开放任何端口。FTP客户端连接采用的被动模式,结果客户端能登录成功,但是无法LIST列表和读取数据。很明显,是因为服务器端没开放被动模式下的随机端口导致。
由于被动模式下,服务器端开放的端口随机,但是防火墙要不能全部开放,解决的方案是,在ftp服务器配置被动模式下开放随机端口在 50000-60000之间(范围在ftp服务器软件设置,可以设置任意1024上的端口段),然后在防火墙设置规则,开放服务器端50000-60000之间的端口端。
主动模式下,客户端的FTP软件设置主动模式开放的端口段,在客户端的防火墙开放对应的端口段。