一、创建Docker镜像
docker pull vsftpd
二、创建Docker容器
docker run -d -p 20:20 -p 21:21 -p 21100-21110:21100-21110 \
-v /home/ftp:/home/vsftpd -e FTP_USER=ftpUsr -e FTP_PASS=123456 \
-e PASV_ADDRESS=192.168.0.10 -e PASV_MIN_PORT=21100 -e PASV_MAX_PORT=21110 \
--name vsftpd --restart=always fauria/vsftpd
三、配置maven插件
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
</dependency>
四、设置工程的配置项
user:
document-host: 192.168.0.105
document-ftp-port: 21
document-ftp-username: ftpUsr
document-ftp-password: 123456
document-path: /document
#回显地址
document-ftp-httpPath: ftp://192.168.0.105
@Component
@ConfigurationProperties(prefix = "user")
@Data
public class UserConfig {
private String documentHost;
private String documentFtpPort;
private String documentFtpUsername;
private String documentFtpPassword;
private String documentPath;
private String documentFtpHttpPath;
}
五、连接到FTP
private FTPClient connectFtpServer() {
// 创建FTPClient对象(对于连接ftp服务器,以及上传和上传都必须要用到一个对象)
FTPClient ftpClient = new FTPClient();
// 设置连接超时时间
ftpClient.setConnectTimeout(1000 * 30);
// 设置ftp字符集
ftpClient.setControlEncoding("utf-8");
// 设置被动模式,文件传输端口设置,否则文件上传不成功,也不报错
ftpClient.enterLocalPassiveMode();
try {
// 定义返回的状态码
int replyCode;
// 连接ftp(当前项目所部署的服务器和ftp服务器之间可以相互通讯,表示连接成功)
// ftpClient.connect(userConfig.getDocumentHost());
if (StringUtils.isBlank(userConfig.getDocumentFtpPort())) {
ftpClient.connect(userConfig.getDocumentHost());
} else {
ftpClient.connect(userConfig.getDocumentHost(), Integer.parseInt(userConfig.getDocumentFtpPort()));
}
// 输入账号和密码进行登录
ftpClient.login(userConfig.getDocumentFtpUsername(), userConfig.getDocumentFtpPassword());
//切换目录
ftpClient.changeWorkingDirectory(userConfig.getDocumentPath());
// 接受状态码(如果成功,返回230,如果失败返回503)
replyCode = ftpClient.getReplyCode();
// 根据状态码检测ftp的连接,调用isPositiveCompletion(reply)-->如果连接成功返回true,否则返回false
if (!FTPReply.isPositiveCompletion(replyCode)) {
log.info("connect ftp {} failed", userConfig.getDocumentHost());
// 说明连接失败,需要断开连接
ftpClient.disconnect();
return null;
}
log.info("replyCode:" + replyCode);
} catch (IOException e) {
log.error("connect fail:" + e.toString());
return null;
}
return ftpClient;
}
六、判断文件是否存在
FTPFile[] li = ftp.listFiles(fileName);
Boolean b = (li !=null) && (li.length >0);
七、下载文件核心代码
public void downloadDocument(String filename, OutputStream out) {
FTPClient ftp = connectFtpServer();
try{
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
ftp.retrieveFile(filename, out);
ftp.logout();
} catch (Exception e) {
log.error("FTP文件下载失败!" + e.toString());
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
log.error(ioe.toString());
}
}
}
}
或:
public void downloadDocument(String filename, OutputStream out) {
FTPClient ftp = connectFtpServer();
try{
ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
/* 控制流量,从而控制下载速度 */
InputStream is = null;
is = ftp.retrieveFileStream(filename);
byte[] buffer = new byte[1024];
int len = is.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = is.read(buffer);
}
is.close();
ftp.logout();
} catch (Exception e) {
log.error("FTP文件下载失败!" + e.toString());
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
log.error(ioe.toString());
}
}
}
}
八、VUE 展示其内容于页面上
<template>
<div>
<Table class="Ttable"
border
:columns="columnData"
:data="datas"
:ellipsis="true"
:loading="tableLoading"
>
<Tooltip
slot-scope="{ row, index }"
slot="action"
content="点击显示文件内容"
transfer
>
<Icon
type="md-list-box"
:size="24"
@click="showDocument(row)"
/>
</Tooltip>
<Page v-if="pageObj.total >1"
:total.sync="pageObj.total"
:current="pageObj.pageIndex"
:page-size="pageObj.pageSize"
transfer
show-total show-sizer
:styles="{marginLeft:'14px'}"
@on-change="changPage"
@on-page-size-change="changPageSize"
/>
</Table>
<Modal v-model="showDocumentModal" footer-hide width="80%" :mask-closable="false" >
<dl v-html="doccumentHtml" />
<Affix slot="close" ref="documentCloserRef" offset-top="88" :style="{scrollLeft:'92% !important'}" >
<Tooltip content="关闭" >
<Icon :color="'#ff9900'" size="40" type="ios-close-circle" />
</Tooltip>
</Affix>
</Modal>
</div>
</template>
<script>
import {StringUtils} from "@/libs/StringUtil";
export default {
name: "ProceedingsDocuments",
components: {},
data(){
return{
datas:[],
/**
* 表头
*/
columnData:[
{
title: "序号",
type: 'index',
width: 100,
align: 'center',
sortable: true,
className: "table-column-middle",
},
{【其他业务字段】},
{
title: "详情",
slot: "action",
align: "center",
},
],
tableLoading:false,
/**
* 分页参数
*/
pageObj:{
total:0,
pageSize:10,
pageIndex:1,
},
showDocumentModal: false,
doccumentHtml: ''
}
},
methods:{
【……】,
/**
* 打开文书
*/
showDocument(rowInfo) {
let _this = this;
let documentId = '';
if(rowInfo!=null && (rowInfo.documentId!=null) ){
documentId = rowInfo.documentId;
}
if(StringUtils.isNotEmpty(rowkey) && (rowInfo.documentExistence)){
this.$api.postDownloadFile('/data/punishment/document',{documentId},function (resp){
var reader = new FileReader();
reader.onload = function(event){
var content = reader.result;//内容就在这里
let pureContent = _this.purifyContent(content);
_this.doccumentHtml = pureContent;
_this.$set(_this.$refs.documentCloserRef.styles,'left','89%');
_this.$nextTick(()=>{
_this.showDocumentModal = true;
});
};
reader.readAsText(resp);
},e=>{
console.error(e);
});
}else{
this.$message.warning('对不起,无法将文件打开。');
}
},
purifyContent(content) {
let pureContent = '';
try {
【对文档的内容的后续整理】
} catch (e) {
console.error(e);
}
return pureContent;
},
},
mounted() {
……;
}
}
</script>
<style scoped>
.Ttable {
color: #515a6e;
text-align: center;
width: 1047px;
}
</style>