因为最近的一个项目涉及到了文件上传下载,然后自己就去网上找了很多文章来看,但发现许多都不是很适合,在总结了许多文章后形成了自己的一套解决方案。
首先你需要在你的linux虚拟机上配置好ftp环境,建议安装可视化的虚拟机,这样后面你能够看的明确一些,在保证虚拟机的ftp服务一直开着Service vsftpd start这是开启ftp服务的命令,当然你也可以设置开机自启。保证虚拟机联网,可以windows下测试一下是否能够连上你的虚拟机,打开cmd,ping 你的虚拟机ip;open 你的虚拟机IP;ftp 输入你的用户名和密码。如果可以连接那说明配置没问题。
**
**
1:pom.xml需要引入一个依赖
<!-- ftpclient -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.1</version>
</dependency>
就是用这个工具包里面的方法进行上传下载的。
2:controller接收到前端传过来的文件流
@PostMapping("/upload")
@ResponseBody
public Map<String, String> uploadImg(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
return uploadService.upfile(file, request);//这里调用service的upfile方法,传入两个参数。
}
3:service层处理业务逻辑
public Map<String, String> upfile(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
Map<String, String> map = new HashMap<>();
map.put("code", "0");
map.put("msg", "上传文件失败");
String fileName = file.getOriginalFilename();//获取文件名
String suffixName = fileName.substring(fileName.lastIndexOf("."));//获取文件的后缀名
//这里有一个比较重要的信息。因为文件上传如果就是以他的中文名字的话下载下来是为空的就是文件里什么都没有。
//所以在文件上传的时候我先保存了文件信息,然后通过得到文件名去查找这个文件的Id,以他的Id加上后缀作为新的文件名存到ftp服务器中
Resource resource = repository.findResourceByName(fileName);
//上面这个方法就是springdatajpa,不熟悉的同学可以去看博主上一篇文章,或者用你自己的方法取得文件id
fileName = resource.getId()+suffixName;
//上传的文件名也需要加上后缀,不然虚拟机不知道文件格式
InputStream inputStream = file.getInputStream();
String filePath = null;
//关于ftp处理文件上传下载这里单独写了一个工具类ftpUtil,下面会写这个类
//@Autowired private FtpUtil ftpUtil;service层上面引入了这个方法。
Boolean flag = ftpUtil.uploadFile(fileName, inputStream);//主要就是这里实现了ftp的文件上传
if (flag == true) {
//log.info("上传文件成功!");
filePath = ftpUtil.FTP_BASEPATH + fileName;
map.put("code", "1");
map.put("msg", "上传文件成功");
}
map.put("path", filePath);
System.out.println(map);
return map;
}
4:ftpUtil
@Component//这就是我们刚才加入的依赖
public class FtpUtil {
//ftp服务器ip地址
private static final String FTP_ADDRESS = "192.168.71.132";
//端口号
private static final int FTP_PORT = 21;
//用户名
private static final String FTP_USERNAME = "huanglong";
//密码
private static final String FTP_PASSWORD = "123456";
//路径都是/home/加上用户名
public final String FTP_BASEPATH = "/home/huanglong";
//
@Autowired
private ResourceRepository resourceRepository;
//参数传过来了文件和文件的输入流
public boolean uploadFile(String originFileName, InputStream input) {
boolean success = false;
FTPClient ftp = new FTPClient();//这是最开始引入的依赖里的方法
ftp.setControlEncoding("utf-8");
try {
int reply;
ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
reply = ftp.getReplyCode();//连接成功会的到一个返回状态码
System.out.println(reply);//可以输出看一下是否连接成功
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//设置文件类型
ftp.changeWorkingDirectory(FTP_BASEPATH);//修改操作空间
//对了这里说明一下你所操作的文件夹必须要有可读权限,chomd 777 文件夹名//这里我就是用的我的home文件夹
ftp.storeFile(originFileName, input);//这里开始上传文件
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
System.out.println("连接失败");
return success;
}
System.out.println("连接成功!");
input.close();
ftp.logout();
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return success;
}
上传和下载机制差不多,不用引入新的依赖
1:controller前端传过来下载地址和要下载的文件的ip然后请求下载
@PostMapping("/file")
public boolean downfile(String path, String id){
//通过文件的id去得到这个文件的所有信息
Resource resource = resourceRepository.findResourceById(id);
String type = resource.getType();//取出要下载的这个文件类型
//因为之前存的时候就是用id加后缀存在服务器中的,所以现在也要用同样的名字去查找
id = id+type;//然后用ip加类型作为文件名去下载文件
boolean flag = false;
System.out.println("文件名:"+id);//这里可以输出一下有没有错
//这里我要得到文件的id和type作为filename去下载,下载是通过filename去对应的目录查找文件名相同的文件下载下来,后台将文件名转换中文文件名。
try {
flag = downloadService.downfile( "\\huanglong" , id,path);//下载调用service层的方法
System.out.println(flag);
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
2:service层处理业务逻辑
public boolean downfile(String pathname, String filename, String localpath) throws IOException {
boolean flag ;//同样这里也是用ftpUtil这个工具类去下载,传入文件的存放地址和文件名,和文件在服务器上的地址
flag = ftpUtil.downloadFile(pathname, filename,localpath);
return flag;
}
3:ftpUtil
public boolean downloadFile(String pathname, String filename, String localpath) {
boolean flag = false;
FTPClient ftp = new FTPClient();
OutputStream os = null;
try {
System.out.println("开始下载文件");
ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
int reply = ftp.getReplyCode();//得到连接成功的返回状态码
System.out.println(reply);
ftp.enterLocalActiveMode();//主动,一定要加上这几句设置为主动
//下面是将这个文件夹的所有文件都取出来放在ftpFiles这个文件数组里面
FTPFile[] ftpFiles = ftp.listFiles();
//然后便利这个数组找出和我们要下载的文件的文件名一样的文件
for (FTPFile file : ftpFiles) {
byte[] bytes = file.getName().getBytes("ISO-8859-1");
file.setName(new String(bytes, "utf-8"));
System.out.println("name: " + file.getName());//
if (filename.equalsIgnoreCase(file.getName())) {//判断找到所下载的文件,file.getName就是服务器上对应的文件
//下面就是通过文件id再去数据库查找文件的中文名,将这个作为文件名下载到本地目录
String fileName = file.getName().substring(0, file.getName().lastIndexOf("."));
System.out.println("该文件的id:"+fileName);
Resource resource = resourceRepository.findResourceById(fileName);
fileName = resource.getName();
File localFile = new File(localpath + "/" + fileName);
os = new FileOutputStream(localFile);//得到文件的输出流
ftp.retrieveFile(file.getName(), os);//开始下载文件
os.close();
}
}
ftp.logout();
flag = true;
System.out.println("下载文件成功");
} catch (Exception e) {
System.out.println("下载文件失败");
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != os) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
//经过测试时下载成功了的,下载的文件也不为空。
希望能对你们有所帮助。。