流程:将图片上传通过FTP上传到服务器中,然后回显,
在页面加载时访问后台是否有已存在的图片,如果有加载到列表当中。
1.什么是FTP?
文件传输协议(File Transfer Protocol,FTP)
是一种提供网络之间共享文件的协议,它可以在计算机之间可靠、高效地传送文件。在传输时,传输双方的操作系统、磁盘文件系统类型可以不同。
FTP 协议允许 TCP/IP 网络上的两台计算机之间进行文件传输。而 FTP 服务是基于 FTP 协议的文件传输服务。
工作时,一台计算机上运行 FTP 客户端应用程序,另一台计算机上需要运行 FTP 服务器端程序。只有拥有了 FTP 服务,客户端才能进行文件传输。下面介绍FTP服务的构成和文件传输模式。
FTP 服务构成
上述的文件传输,指的是客户端和FTP服务器端之间的文件传输,如文件上传和下载。要实现文件传输还需要满足两个条件,如下:
服务器端必须开启一个 TCP 端口(默认为 21 端口),用来监听来自客户端的请求。 客户端连接 FTP 服务器端,需要使用 TCP 方式。这样可以保证客户端和服务器之间的会话是可靠的。
客户端与FTP服务器端之间传输一个文件是一次完整的 FTP 会话。该会话包含有两个连接,分别为控制连接和数据连接。其作用如下:
- 控制连接:客户端向 FTP 服务器的 21 端口发送连接,服务器接受连接,建立一条命令通道。FTP的命令和应答就是通过控制连接来传输的,这个连接会存在于整个 FTP会话过程中。该连接主要负责将命令从客户端传给服务器,并将服务器的应答返回给客户端。所以,该连接不用于发送数据,只用于传输命令。
- 数据连接:每当一个文件在客户端与服务器之间进行传输时,就会创建数据连接。该连接主要用来进行文件传输。
数据格式
在使用 FTP 进行文件传输时,针对不同的文件类型,FTP 提供了两种文件传输模式,分别为 ASCII 和二进制。这两种模式支持的文件如下:
ASCII:用于传输简单的文本文件,为默认类型。
二进制:用于传输程序文件、字处理文档、可执行文件或图片。
FTPUtil
package com.project.management.contractor.common.util;
import com.project.management.contractor.common.constant.FTPConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Component;
import java.io.*;
@Slf4j
@Component
public class FTPUtil {
public static final String ip = "192.168.0.140";
public static final Integer port = 21 ;
public static final String username = "ftpuser";
public static final String password = "ftpuser";
public static final int connectTimeout = 6000;
public static FTPClient ftpClient = null;
public static void initClient() throws IOException {
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
ftpClient.setConnectTimeout(connectTimeout);
ftpClient.connect(ip, port);
ftpClient.login(username, password);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)){
log.info("FTP建立连接失败");
}
log.info("FTP建立连接成功");
}
public static void closeClient() throws IOException {
ftpClient.logout();
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
log.info("FTP关闭连接成功");
}
public static void uploadFile(String filePath, String fileName,String originFileName) throws IOException {
try(InputStream inputStream = new FileInputStream(new File(originFileName))){
initClient();
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(filePath);
ftpClient.storeFile(fileName, inputStream);
ftpClient.logout();
log.info(fileName + "FTP上传文件成功");
}finally {
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
}
}
public static void uploadFile(String filePath, String fileName, InputStream inputStream) throws IOException {
initClient();
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(filePath);
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
ftpClient.logout();
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
log.info(fileName + "FTP上传文件成功");
}
public static void uploadFile(String filePath, String fileName, File file) throws IOException {
try(InputStream inputStream = new FileInputStream(file)){
initClient();
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(filePath);
ftpClient.storeFile(fileName, inputStream);
ftpClient.logout();
log.info("FTP上传文件成功");
}finally {
if (ftpClient.isConnected()){
ftpClient.disconnect();
}
}
}
public static void uploadFiles(String filePath, String fileName, InputStream inputStream) throws IOException {
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(filePath);
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
log.info(fileName + "FTP上传文件成功");
}
public static void deleteFile(String filePath, String fileName) throws IOException {
initClient();
ftpClient.changeWorkingDirectory(filePath);
ftpClient.dele(fileName);
ftpClient.logout();
if (ftpClient.isConnected())
ftpClient.disconnect();
log.info(fileName + "FTP删除文件成功");
}
public static void deleteFiles(String filePath, String fileName) throws IOException {
ftpClient.changeWorkingDirectory(filePath);
ftpClient.dele(fileName);
log.info(fileName + "FTP删除文件成功");
}
public static byte[] downloadFile(String fileAddress) throws IOException {
initClient();
ftpClient.changeWorkingDirectory(FTPConstant.filePath);
InputStream inputStream = ftpClient.retrieveFileStream(fileAddress);
byte[] bytes = inputStream2byte(inputStream);
inputStream.close();
closeClient();
return bytes;
}
public static byte[] inputStream2byte(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = inputStream.read(buff, 0, 100)) > 0) {
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
}
}
FTPConstant
public class FTPConstant {
public static final String filePath = "\\pmc\\pmcfile";
public static final String requestPrefix = "/pmc/pmcfile/";
}
FileTypeUtil
public class FileTypeUtil {
/**
* 获取文件类型后缀
* @param file
* @return
*/
public static String getFileTypeSuffix(MultipartFile file){
return file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
}
}
serviceimpl
/**
* 文件服务
* @author Administrator
*/
@Slf4j
public class FileServiceImpl implements FileService{
@Autowired
private FTPUtil ftpUtil;
@Override
public Result<FileInfo> uploadFile(MultipartFile file) throws IOException {
String newName = SysUtil.generateStringId() + FileTypeUtil.getFileTypeSuffix(file);
ftpUtil.uploadFile(FTPConstant.filePath, newName, file.getInputStream());
FileInfo fileInfo = new FileInfo();
fileInfo.setFileName(file.getOriginalFilename());
fileInfo.setFileAddress(FTPConstant.requestPrefix + newName);
return new Result<FileInfo>().success(fileInfo);
}
@Override
public Result<?> deleteFile(String fileAddress) throws IOException {
ftpUtil.deleteFile(FTPConstant.filePath, fileAddress);
return Result.ok("单文件删除成功");
}
@Override
public void downloadFile(String fileAddress, HttpServletResponse response) throws IOException {
}
@Override
public void downloadFiles(String fileAddress, HttpServletResponse response) {
}
}
以上是ftp工具类
以下是自己的代码
前端
<template>
<div>
<div class="demo-upload-list" v-for="item in uploadList">
<template v-if="item.status === 'finished'">
<img :src="item.url">
<div class="demo-upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item.url)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
</div>
</template>
<template v-else>
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
</template>
</div>
<Upload ref="upload" :show-upload-list="false" :default-file-list="defaultList" :on-success="handleSuccess" :format="['jpg','jpeg','png']"
:max-size="2048" :data="subdata" :on-format-error="handleFormatError" :on-exceeded-size="handleMaxSize"
:before-upload="handleBeforeUpload" multiple type="drag" action="http://localhost:8092/progress/batchUploadFile"
style="display: inline-block;width:58px;">
<div style="width: 58px;height:58px;line-height: 58px;">
<Icon type="ios-camera" size="20"></Icon>
</div>
</Upload>
<Modal title="查看图片" v-model="visible">
<img :src="'http://192.168.0.140/static/' + imgName" v-if="visible" style="width: 100%">
</Modal>
<br />
<Button @click="getdata" style="margin-left: 8px">数 据</Button>
</div>
</template>
<script>
import {
postAction,
getAction,
putAction,
deleteAction,
getSyncAction
} from '@/libs/request'
export default {
data() {
return {
subdata: {
mainid: ''
},
defaultList: [
// {
// "name":"微信图片_20191218101204.jpg",
// "url":"http://192.168.0.140/static/pmc/pmcfile/f7cdac8d9e4340b8ba99e3b11915526a.jpg",
// },
],
imgName: '',
visible: false,
uploadList: []
}
},
created() {
//this.subdata.mainid=this.$route.query.excelid
this.subdata.mainid = 'd51d3312dab395b4b0342341a88be6c4';
},
methods: {
handleView(name) {
let str = 'http://192.168.0.140/static/'
this.imgName = name.substr(str.length - 1);
this.visible = true;
},
handleRemove(file) {
let str = 'http://192.168.0.140/static/'
let newurl = (file.url).substr(str.length - 1)
getAction('/progress/deleteFile', {
fileAddress: newurl
}).then(res => {
console.log("删除状态" + res.data.code);
const fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(file), 1);
})
},
handleSuccess(res, file) {
let resdata = res.data
file.name = resdata.fileName
file.url = "http://192.168.0.140/static" + resdata.fileAddress
},
handleFormatError(file) {
this.$Notice.warning({
title: 'The file format is incorrect',
desc: 'File format of ' + file.name + ' is incorrect, please select jpg or png.'
});
},
handleMaxSize(file) {
this.$Notice.warning({
title: '文件超过最大尺寸',
desc: '文件: ' + file.name + ' 太大, 已超过2M.'
});
},
handleBeforeUpload() {
console.log(this.uploadList.length);
const check = this.uploadList.length < 5;
if (!check) {
this.$Notice.warning({
title: '最多可上传5张图片.'
});
}
return check;
},
getListinfo() {
// // 第一种 同步
// let defaltdata = this.defaultList
// console.log("defaultlist");
// console.log(this.defaultList);
// getSyncAction({
// url: "http://localhost:8092/progress/selectImages",
// data: this.subdata,
// success: function(res) {
// console.log(3);
// let resdata = res.data
// resdata.forEach(r => {
// defaltdata.push({
// name: r.fileName,
// url: "http://192.168.0.140/static" + r.fileAddress
// })
// })
// }
// })
// 第二种
let _self = this
getAction('/progress/selectImages',this.subdata).then(res => {
let resdata =res.data.data
resdata.forEach(r=>{
this.$refs.upload.fileList.push({
name:r.fileName,
url:"http://192.168.0.140/static"+r.fileAddress,
status:'finished',
percentage:100
})
})
})
},
getdata() {
console.log('upload')
console.log(JSON.stringify(this.uploadList))
console.log('default')
console.log(JSON.stringify(this.defaultList))
}
},
mounted() {
this.getListinfo();
this.uploadList = this.$refs.upload.fileList;
}
}
</script>
<style>
.demo-upload-list {
display: inline-block;
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border: 1px solid transparent;
border-radius: 4px;
overflow: hidden;
background: #fff;
position: relative;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
margin-right: 4px;
}
.demo-upload-list img {
width: 100%;
height: 100%;
}
.demo-upload-list-cover {
display: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .6);
}
.demo-upload-list:hover .demo-upload-list-cover {
display: block;
}
.demo-upload-list-cover i {
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 0 2px;
}
</style>
后台
@Service
public class PmcFileServiceImpl extends ServiceImpl<PmcFileMapper, PmcFile> implements PmcFileService {
@Autowired
private FileService fileService;
@Autowired
private PmcFileMapper mapper;
/**
* FTP上传图片进度填报
* @throws IOException
*/
@Override
public Result<FileInfo> batchUploadFile(MultipartFile file,String mainid) throws IOException {
Result<FileInfo> batchUploadFile = fileService.uploadFile(file);
if(batchUploadFile.getCode()>0) {
FileInfo data = batchUploadFile.getData();
PmcFile fileinfo=new PmcFile();
fileinfo.setFileName(data.getFileName());
fileinfo.setFileAddress(data.getFileAddress());
fileinfo.setMainId(mainid);
fileinfo.setDelFlag("0");
System.out.println(fileinfo);
mapper.insert(fileinfo);
}
return batchUploadFile;
}
/**
* FTP上传图片单文件删除
* @throws IOException
*
*/
@Override
public Result<?> deleteFile(String fileAddress) throws IOException {
Result<?> deleteFile = fileService.deleteFile(fileAddress);
if(deleteFile.getCode()>0) {
UpdateWrapper<PmcFile> updatewrapper =new UpdateWrapper<>();
updatewrapper.eq("file_address", fileAddress);
mapper.delete(updatewrapper);
}
return Result.ok("删除成功");
}
//读取已上传的列表
@Override
public Result<List<FileSelectParamVo>> selectImages(String mainid) {
QueryWrapper<PmcFile> wrapper =new QueryWrapper<>();
wrapper.eq("main_id", mainid);
List<PmcFile> selectList = mapper.selectList(wrapper);
List<FileSelectParamVo> filelist=new ArrayList<FileSelectParamVo>();
selectList.forEach(list->{
FileSelectParamVo filevo=new FileSelectParamVo();
filevo.setFileAddress(list.getFileAddress());
filevo.setFileName(list.getFileName());
filevo.setMainId(list.getMainId());
filelist.add(filevo);
});
return new Result<List<FileSelectParamVo>>().success(filelist);
}
}