工作半年了,之前总是喜欢把总结和学习到的新东西放到自己OneNote上保存,方便自己回顾。但最近翻翻boss直聘上的要求,貌似写技术博客是个加分项哎,思来想去,决定以后但文档都在简上写好了,因为平时查问题的时候发现还是简书的排版最好,废话不说了开始吧!
-
pom.xml依赖引入
<!-- ftp客户端 -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.1</version>
</dependency>
-
FtpUtil工具类,主要是封装了利用commons.net包下的FTPClient连接、登陆ftp服务器,并切换到ftp服务器下指定文件夹,设置上传到一些属性最后完成上传。其中的ftpIP,ftpUser, ftpPass, ftpPort都是从配置文件properties中读取的。
public class FtpUtil {
private static Logger logger = LoggerFactory.getLogger(FtpUtil.class);
//从properties文件读取相应的配置
private static String ftpIP = PropertiesUtil.getProperty("ftp.server.ip");
private static String ftpUser = PropertiesUtil.getProperty("ftp.user");
private static String ftpPass = PropertiesUtil.getProperty("ftp.pass");
private static String ftpPort = PropertiesUtil.getProperty("ftp.port");
/**
* 将文件直接上传到ftp服务器到方法,不会经过tomcat本地缓冲
*
* @param remotePath ftp服务器中的文件夹
* @param fileName 文件的新名称
* @param inputStream
* @return
*/
public static boolean uploadFile(String remotePath, String fileName, InputStream inputStream) {
boolean isSeccess = false;
boolean result = false;
FTPClient ftpClient = new FTPClient();
try {
//连接登陆
ftpClient.connect(ftpIP);
isSeccess = ftpClient.login(ftpUser, ftpPass);
logger.info("ftp服务器:{},登陆--{}", ftpIP, isSeccess);
//如果登陆成功...
if (isSeccess) {
//切换到指定的ftp服务器文件夹目录
boolean isChangeSuccess = ftpClient.changeWorkingDirectory(remotePath);
//如果切换失败则创建改目录再切换
if (!isChangeSuccess) {
ftpClient.makeDirectory(PropertiesUtil.getProperty("ftp.dir"));
ftpClient.changeWorkingDirectory(remotePath);
}
//设置缓冲大小,编码格式,文件类型
ftpClient.setBufferSize(1024);
ftpClient.setControlEncoding("UTF-8");
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
//开始上传
logger.info("开始上传文件:{}", fileName);
result = ftpClient.storeFile(fileName, inputStream);
logger.info("文件:{},上传:{}", fileName, result);
return result;
}
} catch (IOException e) {
logger.error("文件上传失败", e);
} finally {
try {
//关闭流
inputStream.close();
ftpClient.logout();
} catch (IOException e) {
logger.error("输入流关闭失败", e);
}
}
return result;
}
}
-
Service层主要是对上传对文件进行重命名,并封装好返回给前端的结果样式,其中ServerResponse对象是前端要求的高可用响应对象,附在最后
@Service("iFileService")
public class FileServiceImpl implements IFileService {
//让控制台输出此文件记录内容
private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);
/**
* 将文件直接上传至ftp服务器
*
* @param file
* @return
*/
@Override
public ServerResponse upload(MultipartFile file) {
Map<String, String> resultMap = new HashMap();
String oldName = file.getOriginalFilename();
String newName = UUID.randomUUID().toString();
//给文件重命名
newName = newName + oldName.substring(oldName.lastIndexOf("."));
try {
//利用FtpUtil中到方法进行上传文件
boolean result = FtpUtil.uploadFile(PropertiesUtil.getProperty("ftp.dir"), newName, file.getInputStream());
if (result) {
//如果上传成功,则返回前端新的文件名和路径
resultMap.put("uri", newName);
//根据nginx配置的ftp文件夹和域名的对应关系组装文件在ftp服务器中的位置
resultMap.put("url", PropertiesUtil.getProperty("ftp.server.http.prefix") + PropertiesUtil.getProperty("ftp.dir") + newName);
return ServerResponse.createBySucess(resultMap);
} else {
return ServerResponse.createByErrorMessage("上传失败");
}
} catch (IOException e) {
e.printStackTrace();
}
return ServerResponse.createByErrorMessage("上传失败");
}
}
-
Controller层逻辑,主要是对用户权限对校验以及文件上传
@RequestMapping(value = "upload", method = {RequestMethod.POST})
@ResponseBody
public ServerResponse upload(@RequestParam(value = "file", required = true) MultipartFile file, HttpSession session) {
User user = (User) session.getAttribute(Const.CURRENT_USER);
if (user == null) {
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登陆");
}
if (user.getRole() != Const.ADMIN) {
return ServerResponse.createByErrorMessage("用户无此权限");
}
//业务逻辑
return iFileService.upload(file);
}
- 附:高可用响应类
public class ServerResponse<T> implements Serializable {
private int status;
private String msg;
private T data;
private ServerResponse(int status) {
this.status = status;
}
private ServerResponse(int status, T data) {
this(status, data, null);
}
private ServerResponse(int status, T data, String msg) {
this.status = status;
this.data = data;
this.msg = msg;
}
private ServerResponse(int status, String msg) {
this(status);
this.msg = msg;
}
@JsonIgnore //json序列化到时候就不会显示这个public方法在json里面
public boolean isSuccess() {
return this.status == ResponseCode.SUCCESS.getCode();
}
public int getStatus() {
return status;
}
public T getData() {
return data;
}
public String getMsg() {
return msg;
}
//成功时返回到数据封装ServerResponse对象
public static <T> ServerResponse<T> createBySucess(){
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
}
public static <T> ServerResponse<T> createBySucessMsg(String msg){
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg);
}
public static <T> ServerResponse<T> createBySucess(T data){
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),data);
}
public static <T> ServerResponse<T> createBySucess(String msg,T data){
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),data,msg);
}
public static <T> ServerResponse<T> createByError(){
return new ServerResponse<T>(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc());
}
public static <T> ServerResponse<T> createByErrorMessage(String msg){
return new ServerResponse<T>(ResponseCode.ERROR.getCode(),msg);
}
public static <T> ServerResponse<T> createByErrorCodeMessage(Integer code,String msg){
return new ServerResponse<T>(code,msg);
}
}
- 附:properties配置文件,其中ftp.server.http.prefix是nginx配置文件中对应ftp文件夹的那个servername
ftp.server.ip=192.168.1.1
ftp.user=ftpuser
ftp.pass=123456
ftp.server.http.prefix=http://image.test.com/
ftp.port=21
#ftp.dir=img/
ftp.dir=video/
- 这个是conf.d文件夹下自己添加的conf文件,其中的image.test.com对应的是服务器根目录下的ftpfile文件,如果只是测试,在本机hosts文件中也要配置域名和ip的对应关系。否则从返回的结果中也是无法访问的
当在浏览器中输入image.test.com域名时,首先会从本机hosts文件查看是否有对应的ip,如果有则去访问对应的ip资源,然后会被nginx截获,并与nginx配置的域名ip对应关系对比,如果一致则可以访问资源。
server {
listen 80;
autoindex on;
server_name image.test.com;
access_log /etc/nginx/logs/access.log combined;
index index.html index.htm index.jsp index.php;
#error_page 404 /404.html;
if ( $query_string ~* ".*[\;'\<\>].*" ){
return 404;
}
location ~ /(mmall_fe|mmall_admin_fe)/dist/view/* {
deny all;
}
location / {
root /ftpfile;
add_header Access-Control-Allow-Origin *;
}
}
- 最后的返回结果样式, 直接访问url后的结果
{
"status": 0,
"data": {
"uri": "05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg",
"url": "http://image.test.com/video/05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg"
}
}
//Linux服务器中ftpfile文件夹中的video文件下的上传文件
[slf@www ftpfile]$ cd video
[slf@www video]$ ls
05c0a49a-a461-4ab2-b277-58a1051f828c.jpeg
[slf@www video]$
image.png
网友评论