导入依赖
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.8.0</version>
</dependency>
controller层
package com.neutech.controller;
import com.neutech.vo.ResultVO;
import com.neutech.vo.WangEditorItemVO;
import com.neutech.vo.WangEditorVO;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@RestController
@RequestMapping(value = "/upload")
public class FileUploadController {
@Value("${ftp.hostname}")
private String hostname;
@Value("${ftp.port}")
private Integer port;
@Value("${ftp.username}")
private String username;
@Value("${ftp.password}")
private String password;
@Value("${ftp.speed}")
private Integer speed;
@Value("${nginx.prefix}")
private String nginxPrefix;
@PostMapping("/fileUpload")
public ResultVO fileUpload(MultipartFile file) {
// MultipartFile类型的对象当前台不传此参数有时是null,有时不是null
if (file == null || file.getSize() == 0) {
return ResultVO.error(1006, "文件未选择");
}
String fileName = "";
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(hostname, port);
ftpClient.login(username, password);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
return ResultVO.error(1007, "ftp服务器连接失败");
}
ftpClient.setControlEncoding("utf-8");
ftpClient.enterLocalPassiveMode();
ftpClient.setBufferSize(speed);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
// 切换文件夹
ftpClient.changeWorkingDirectory("/home/ftpuser/");
// 推送到服务器上的文件名一定不能重复,需要我们生成一个不重复的文件名
// UUID 号称全世界都不会重复 1.jpg
fileName = UUID.randomUUID().toString() +
file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (!ftpClient.storeFile(fileName, file.getInputStream())) {
return ResultVO.error(1009, "上传失败");
}
} catch (IOException e) {
e.printStackTrace();
return ResultVO.error(1010, "ftp服务器连接失败");
}
// 生成一个可访问的地址返回
return ResultVO.success(nginxPrefix + fileName);
// return ResultVO.success(fileName);
}
@PostMapping("/wangUpload")
public WangEditorVO wangUpload(MultipartFile[] files) {
if (files == null || files.length == 0) {
return WangEditorVO.error();
}
List<WangEditorItemVO> wangEditorItemVOList = new ArrayList<>();
for (MultipartFile file : files) {
ResultVO resultVO = fileUpload(file);
WangEditorItemVO wangEditorItemVO = new WangEditorItemVO();
wangEditorItemVO.setUrl((String) resultVO.getData());
wangEditorItemVOList.add(wangEditorItemVO);
}
return WangEditorVO.success(wangEditorItemVOList);
}
}
配置文件层
application.yml文件中写入:
ftp:
hostname: 192.168.253.151
port: 21
username: ftpuser
password: 52xzg1314
speed: 1024
nginx:
prefix: http://192.168.253.151/
说明:
1. 解决更换端口号时需要代码重新编译打包的问题
- 一些值放常量类里:需要重启服务器、重新编译、重新打包
- 可以防止配置文件中:项目重启,但不用重新编译。配置文件不是java代码,不用重新编译。
这里使用第二种方式:
首先,yml配置文件中写入如下内容。
ftp:
hostname: 192.168.253.151
post: 21
username: ftpuser
password: 52xzg1314
- 注意:yml文件中,数字不可以以0开头,会把他当成八进制解析。
解决方法:
加双引号,告诉他这是字符串,你别转
而在java代码中读取配置文件:
- (在添加了@RestController注解的类里面,涉及框架原理:
yml文件是spring里面的。
当添加了@RestController表示将这个类交给IOC去处理,spring就能往类里面添加值。
而不添加时,spring无法往类里面加东西
)
@Value("${ftp.hostname}")
private String hostname;
@Value("${ftp.port}")
private Integer port;
@Value("${ftp.username}")
private String username;
@Value("${ftp.password}")
private String password;
@Value("${nginx.prefix}")
private String nginxPrefix;
2. 保证逻辑完整
保证在任何情况下都有返回值
3. 文件名处理
不可以叫用户自己的文件名。容易重名。
如何生成一个不重复的文件名:
- 时间:不行(web是并发程序)
- UUID号称全世界都不会重复
fileName = UUID.randomUUID().toString() +
file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
if (!ftpClient.storeFile(fileName, file.getInputStream())) {
return ResultVO.error(1009, "上传失败");
}
UUID:36位,无后缀
结果示例:
postman请求入下:
Xftp中也可以看到该文件
linux下nginx配置文件访问路径
whereis nginx
cd xxxx
ll
cd conf
vi nginx.conf
更改配置文件到图片存储路径:如图:
浏览器访问
启动nginx:
systemctl start nginx
nginx403原因:用户权限问题
解决:
- 传到一个nginx能访问的路径,ftpuser用户就得配权限
- nginx能访问ftpuser目录
采用方法二:
如下图:更改这一行语句如图:
之后访问:
linux主机ip地址/图片名
例如:http://192.168.253.151/a08f4ff4-ebac-47d0-9433-d78c4a7020c8.jpg
访问成功。
后续运行
只需要在虚拟机内启动ftp服务后,即可发送文件。
systemctl start vsftpd