文包含FTP軟件介紹、下載、不同主機創建FTP賬號的方法、以及連接WordPress網站的詳細步驟。
本文原文首發于:https://loyseo.com/wordpress-ftp-access-guide/
FTP是文件傳輸協議,FTP軟件就是用來傳輸文件用的,本文將使用的免費FTP軟件FileZilla。
用FTP軟件連接WordPress網站,就是用FTP軟件管理WordPress網站的文件,譬如上傳文件、刪除文件、修改文件、下載文件等等,利用它還能解決一些問題,譬如:
由于安裝某個插件、或插件沖突、或bug、或忘記后臺地址等等,導致后臺進不去時,可進入FTP,將指定插件文件夾或插件的總文件夾(Plugins)的名字改一下,等于禁用了這個插件或所有插件,這樣就能登錄后臺了。
安裝較多或較大插件或主題時,直接可以在FTP里一次性上傳
點擊FileZilla前往下載;若是無法安裝exe客戶端,可以直接下載免安裝的zip包,解壓后直接點擊文件夾內的filezilla運行。
以外貿網站建設常用主機SiteGround為示例,我們接下來講解如何在SiteGround創建FTP賬號。
在網站的sitetools,進入Site》 FTP accounts頁面
輸入賬號及密碼
點擊Create就可以成功創建賬號
記住右邊的FTP hostname和 Port,待會在FTP軟件中需要輸入
如果你買的主機是用的Cpanel面板(譬如Chemicloud、GreenGeeks),就按照下面的方法創建FTP賬號
首先在Cpanel中找到FTP Accounts并進入
接下來輸入賬號信息,如下圖所示,需要注意的是directory,系統會為你默認生成內容,但你需要將它們全部刪除保持為空,或輸入public_html;如保持為空,則這個FTP賬號能訪問你的主機下所有文件夾,不限于網站文件夾,還有備份存放的文件夾等等;若輸入public_html,則這個FTP賬號能訪問你的主機下的網站文件夾。
賬號創建完成后,在該頁面下方會顯示賬號列表,其中包含了修改密碼、查看FTP配置和下載客戶端功能,如下圖所示,你可以點擊configure FTP client查看主機地址及端口(port:21)
首先你需要確認已經安裝了下圖中所示的Pure-Ftpd 1.0.49軟件,若沒有安裝,請在軟件商店中找到它并點擊安裝。
接下來,按如下步驟創建FTP賬號
點擊FTP菜單
點擊添加FTP按鈕
在彈出層中填寫用戶名
填寫密碼
選擇FTP需要連接的網站的文件夾
點擊提交按鈕即可
注意上圖中,在添加FTP上方,有個當前FTP地址,其中的IP便是FTP軟件中所需輸入的主機地址,端口號默認是21
打開FileZilla,點擊左上角的主機圖標
在彈出層中,點擊新站點
設置新站點名稱
輸入主機域名,若主機沒有提供FTP域名,則輸入IP;端口號默認為空即表示為21
填寫FTP賬號的用戶名和密碼
點擊連接按鈕
若連接過程中出現如下提示,直接點擊確定按鈕即可
當連接成功后,你將看到如下界面,圖中1是你的電腦,2是網站主機,你可以通過鼠標拖拽文件夾實現文件的下載或上傳,從右側拖拽到左側就是下載;從左側拖拽到右側就是上傳,注意拖拽前定好文件存儲或上傳的目錄。
除了拖拽的方法,你也可以選擇文件后,點擊右鍵展開操作項,譬如若是需要下載備份,按下圖所示
在左側選擇需要存放備份的文件夾
在右側點選備份所在的文件夾
在文件夾內找到備份,右鍵選擇下載
文件正在下載并顯示進度,若網絡中斷,也可以繼續下載并選擇斷點續傳
本文原文由LOYSEO.COM發布,LOYSEO專注于WordPress外貿網站建設教程、Elementor教程。
務:利用FTP上傳.html文件
描述:利用FTP軟件上傳編寫好的index.html文件,并能通過空間服務商提供的IP地址或者域名進行訪問。
王岑看著自己的勞動成果,非常滿意,他甚至不停的改變網頁的內容,差點就要寫一篇文章了。王岑心里美滋滋的,心想原來做網站也不難嘛,下面就是把他寫好的頁面上傳到陳輝所說的空間了。
于是他又拿出了那張鄒巴巴的小紙條,他發現上面只寫了三句話,背面還寫了一個400的客服電話。
FTP地址:180.186.72.213
FTP賬戶:koudefu
FTP密碼:123456
王岑從陳輝那里知道,這個電話是提供24小時服務的,如果在服務器上傳時有什么不明白的地方就可以打電話咨詢。于是王岑就撥起了這個客服電話,他現在哪里是有什么不明白而是全不明白。經過一連串的機器人選項后后王岑直接撥0找到的了人工服務。就聽王岑開門見山的問道:“你好!我的網站已經做好了,請問要怎么樣才能上傳到我的服務器上呢?”
語落,就聽一個非常甜美的聲音耐心的說道:“把文件上傳到服務器的方法很多。大家最常用的就是用FTP方式上傳。一般在您購買了我們的空間后,我們都會給你提供一個FTP的IP地址、賬戶名和密碼。然后您在網上下載一個FTP客戶端軟件就可以了,比如flashfxp就挺好。”
“FTP是什么?”,王岑有些不解的問道。
“FTP是英文(FileTransferProtocol)文件傳輸協議的意思,flashfxp就是利用這個協議來傳輸文件的。”客服仍舊耐心解釋道。
王岑英文不是很好,所以沒有聽清FTP的英文說明,不過他卻記住了FTP是文件傳輸協議的意思。等他回過神時,就聽電話里的客服繼續解釋道:“flashfxp的使用也挺簡單。安裝好后,在菜單欄依次點擊【站點】-【站點管理器】-【新建站點】按鈕創建一個新站點就可以了。在新建站點窗口文本框中輸入我們給您的IP地址、賬戶名和密碼,然后點擊【連接】按鈕后就可以正常使用了。”
王岑不知不覺的點了點頭,嗯了一聲繼續問道:“用你說的這個什么flashfxp就可以上傳我的代碼了對吧?”
“對,flashfxp、flashfxp不僅能夠上傳文件,還可以直接刪除啊、編輯啊、替換啊文件等等。一般flashfxp軟件左邊窗口就是您本地的文件目錄,右邊窗口則是服務器文件目錄,您只需把本地的文件直接拖拽到右邊服務器的目錄上就可以了。當您把剛才寫好index.html上傳到您的服務器(也叫空間)后,再次用我們給您提供的域名刷新你的網站就可以了。”
王岑一邊聽著客服的耐心解答,一邊按照客服的要求進行操作,中間偶爾遇到一點兒意外,客服也都一一進行了的指導。
隨后,經過幾分鐘的軟件下載、安裝和站點設置后,文件輕輕一拖,果然成功上傳了,這讓王岑很是高興。Flashfxp添加站點如下圖所示:
Flashfxp
首先寫一個簡單的FTP工具類,先實現最基本的文件上傳,下載,刪除,拷貝功能。這里操作FTP是用的commons-net-3.3.jar中的org.apache.commons.net.ftp中的對象
package com.wzh.config.utils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* @author wzh
* @create 2018-05-06 23:03
* @desc ${操作FTP文件工具類}
**/
public class FtpUtils {
private static Logger log = Logger.getLogger(FtpUtils.class);
//本地編碼集對象
private static String encode = Charset.defaultCharset().toString();
// FTP編碼為iso-8859-1
private static final String SERVER_CHARSET = "ISO-8859-1";
//FTP下載時讀入內存的大小
private static final int BUFFER_SIZE = 1024000;
/**
* 獲取FTP連接對象,連接FTP成功返回FTP對象,
* 連接FTP失敗超過最大次數返回null,使用前請判斷是否為空
* @param ftpHost 服務器ip
* @param ftpPort 服務器端口
* @param ftpUserName 用戶名
* @param ftpPassword 密碼
* @return FTPClient FTP連接對象
*/
public static FTPClient getFTPClient(String ftpHost, int ftpPort, String ftpUserName, String ftpPassword) {
//FTP連接對象
FTPClient ftpClient = null;
try
{
ftpClient = new FTPClient();
//設置FTP服務器IP和端口
ftpClient.connect(ftpHost,ftpPort);
//設置超時時間,毫秒
ftpClient.setConnectTimeout(50000);
//登錄FTP
ftpClient.login(ftpUserName,ftpPassword);
//設置被動傳輸模式
ftpClient.enterLocalPassiveMode();
//ftpClient.enterRemotePassiveMode();
//二進制傳輸
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//設置讀入內存文件大小
ftpClient.setBufferSize(BUFFER_SIZE);
//獲取FTP連接狀態碼 ,大于等于200 小于300狀態碼表示連接正常
int connectState = ftpClient.getReplyCode();
//連接失敗重試
int reNum = 0;
while (!FTPReply.isPositiveCompletion(connectState)
&& reNum < 3)
{
ftpClient.disconnect();
++reNum;
ftpClient.login(ftpUserName,ftpPassword);
}
if (reNum < 3) {
log.info("FTP連接成功");
} else {
ftpClient = null;
log.error("FTP連接失敗");
}
} catch (Exception e)
{
log.error(e.getMessage(), e);
}
return ftpClient;
}
/**
*斷開FTP
* @param ftpClient fpt連接對象
*/
public static void closeFTP(FTPClient ftpClient) {
if (null != ftpClient) {
try {
//登出FTP
ftpClient.disconnect();
log.info("登出FTP成功");
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
try {
//斷開FTP
ftpClient.disconnect();
log.info("斷開FTP成功");
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
}
/**
* 根據FTP編碼集轉換文件路徑,防止中文亂碼,并設置FTP連接的編碼集
* @param ftpClient FTP連接對象
* @param path 文件路徑
* @return 轉碼后的文件路徑
*/
public static String changeEncode(FTPClient ftpClient,String path) throws IOException
{
synchronized (encode)
{
int status = ftpClient.sendCommand("OPTS UTF8","ON");
//判斷FTP服務器是否支持UTF -8,支持使用UTF-8 否則使用本地編碼集
if(FTPReply.isPositiveCompletion(status))
{
encode = "UTF-8";
}
log.info("FTP使用編碼集:" + encode);
ftpClient.setControlEncoding(encode);
path = new String(path.getBytes(encode),SERVER_CHARSET);
}
return path;
}
/**
* 獲取文件后綴
* @param fileName 文件名或文件全路徑
* @return 文件后綴
*/
public static String getSuffix(String fileName)
{
String suffix = "";
int index = fileName.lastIndexOf(".");
if(index != -1)
{
suffix = fileName.substring(index);
log.info("獲取文件后綴名成功,文件名:" + fileName + " 后綴名:" + suffix);
}else{
log.warn("獲取文件后綴名失敗,文件名" + fileName);
}
return suffix;
}
/**
* 獲取FTP指定文件大小
* @param ftpClient ftp連接對象
* @param fileName ftp文件服務器路徑 如:/public/file/xxx.text
* @return 文件大小,獲取失敗返回-1
*/
public static Long getFtpFileSize(FTPClient ftpClient, String fileName)
{
FTPFile[] files = null;
Long fileSize = -1L;
try {
files = ftpClient.listFiles(changeEncode(ftpClient,fileName));
//因為指定了具體的文件名,這里只取數組0位
if (null != files && files.length > 0)
{
log.info("文件個數:" + files.length + " 文件名:" +
files[0].getName() + " 文件大小:" + files[0].getSize());
fileSize = files[0].getSize();
}
} catch (IOException e) {
fileSize = 1L;
log.error(e.getMessage(),e);
}
return fileSize;
}
/**
*下載FTP上指定文件路徑文件
* @param ftpClient FTP連接對象
* @param filePath 文件路徑+文件名 例如:/public/file/a.txt
* @param downPath 下載文件保存的路徑
* @param newFileName 新的文件名 例如:newFileName
* @return
*/
public static boolean downLoadFtpFile(FTPClient ftpClient, String filePath,String downPath, String newFileName)
{
//默認失敗
boolean flag = false;
//獲取文件后綴
String suffix = getSuffix(filePath);
//下載的文件對象
File dwonFile = new File(downPath + File.separator + newFileName + suffix);
try
{
OutputStream out = new FileOutputStream(dwonFile);
flag = ftpClient.retrieveFile(changeEncode(ftpClient,filePath),out);
out.flush();
out.close();
if(flag)
{
log.info("下載文件成功,文件路徑:" + filePath);
}else{
log.error("下載文件失敗,文件路徑:" + filePath);
}
}
catch (Exception e)
{
log.error(e.getMessage(),e);
}
return flag;
}
/**
* FTP文件上傳工具類
* @param ftpClient 連接對象
* @param filePath 本地文件路徑 /xxxx/xx.txt
* @param ftpPath ftp儲存路徑
* @param newFileName ftp保存的文件名
* @return true 下載成功,false 下載失敗
*/
public static boolean uploadFile(FTPClient ftpClient,String filePath,String ftpPath, String newFileName)
{
boolean flag = false;
InputStream in = null;
try {
//獲取文件后綴
String suffix = getSuffix(filePath);
//路徑轉碼,處理中文
ftpPath = changeEncode(ftpClient,ftpPath);
newFileName = changeEncode(ftpClient,newFileName + suffix);
//判斷目標文件夾是否存在,不存在就創建
if(!ftpClient.changeWorkingDirectory(ftpPath))
{
ftpClient.makeDirectory(ftpPath);
ftpClient.changeWorkingDirectory(ftpPath);
}
//上傳文件
File file = new File(filePath);
in = new FileInputStream(file);
flag = ftpClient.storeFile(newFileName,in);
if(flag)
{
log.info("文件上傳成功:" + filePath);
}
}
catch (Exception e)
{
log.error(e.getMessage(),e);
}
finally
{
try {
if(in != null)
{
in.close();
}
} catch (IOException e) {
log.error(e.getMessage(),e);
}
}
return flag;
}
/**
* FTP上文復制文件到另外一個路徑
* @param ftpClient ftp連接對象
* @param oldFtpPath 源文件儲存路徑 xxx/xxx.txt
* @param newFtpPath 新路徑 /public/file/
* @param newFileName 新文件名
* @return true 下載成功,false 下載失敗
*/
public static boolean copyFile(FTPClient ftpClient,String oldFtpPath,String newFtpPath, String newFileName)
{
boolean flag = false;
ByteArrayInputStream in = null;
ByteArrayOutputStream out = null;
try {
out = new ByteArrayOutputStream();
//獲取文件后綴
String suffix = getSuffix(oldFtpPath);
//先讀入內存,綁定out輸出流,然后再轉換為輸入流
String encodeOldPath = changeEncode(ftpClient,oldFtpPath);
ftpClient.retrieveFile(encodeOldPath,out);
in = new ByteArrayInputStream(out.toByteArray());
//切換工作目錄,沒有就創建
String encodeNewPath = changeEncode(ftpClient,newFtpPath);
if(!ftpClient.changeWorkingDirectory(encodeNewPath))
{
ftpClient.makeDirectory(encodeNewPath);
ftpClient.changeWorkingDirectory(encodeNewPath);
}
//復制文件
flag = ftpClient.storeFile(changeEncode(ftpClient,newFileName + suffix),in);
out.flush();
out.close();
in.close();
if (flag) {
log.info("文件復制成功,源文件:" + oldFtpPath + " 新路徑:" + newFtpPath + newFileName);
} else {
throw new BusinessException("文件復制失敗,源文件:" + oldFtpPath);
}
}
catch (Exception e)
{
log.error(e.getMessage(),e);
}
return flag;
}
/**
* 刪除Ftp上的文件
* @param ftpClient 連接對象
* @param filePath 服務器文件路徑 /public/file/xxx.txt
* @return true 成功,false 失敗
*/
public static boolean delectFile(FTPClient ftpClient,String filePath)
{
boolean flag = false;
try {
flag = ftpClient.deleteFile(changeEncode(ftpClient,filePath));
if(flag)
{
log.info("刪除文件成功:" + filePath);
}else{
log.error("刪除文件失敗:" + filePath);
}
} catch (IOException e) {
log.error(e.getMessage(),e);
}
return flag;
}
/**
* 文件移動
* @param ftpClient fpt連接對象
* @param oldFtpPath 文件原路徑 /public/old/xxx.txt
* @param newFtpPath 文件新路徑 /public/new/
* @param newFileName 文件名
* @return true 成功,false 失敗
*/
public static boolean moveFile(FTPClient ftpClient,String oldFtpPath,String newFtpPath, String newFileName)
{
boolean flag = false;
try {
//文件后綴
String suffix = getSuffix(oldFtpPath);
//路徑編碼
String encodeOldPath = changeEncode(ftpClient,oldFtpPath);
String encodeNewPath = changeEncode(ftpClient,newFtpPath);
String encodeNewFileName = changeEncode(ftpClient,newFileName + suffix);
//切換工作目錄
if(!ftpClient.changeWorkingDirectory(encodeNewPath))
{
ftpClient.makeDirectory(encodeNewPath);
ftpClient.changeWorkingDirectory(encodeNewPath);
}
//轉存
flag = ftpClient.rename(encodeOldPath, encodeNewFileName);
if(flag)
{
log.info("文件轉存成功:" + oldFtpPath);
}else {
log.error("文件轉存失?。?#34; + oldFtpPath);
}
} catch (IOException e) {
log.error(e.getMessage(),e);
}
return flag;
}
/**
* 讀取Ftp文本文件,返回行數據集合
* @param ftpClient ftp連接對象
* @param filePath 文件路徑 /public/file/xxx.txt
* @param encode 解析文件編碼集
* @return 行數據集合
*/
public static List<String> redFtpFileWithLine(FTPClient ftpClient, String filePath, String encode)
{
List<String> lineList = new ArrayList<String>();
InputStream in = null;
BufferedReader reader = null;
try {
//獲取文件流數據
in = ftpClient.retrieveFileStream(changeEncode(ftpClient,filePath));
if(in == null)
{
throw new BusinessException("獲取文件流失敗:" + filePath);
}
reader = new BufferedReader(new InputStreamReader(in,encode));
String inLine;
while ((inLine = reader.readLine()) != null)
{
lineList.add(inLine);
}
//關閉流
if(reader != null)
{
reader.close();
}
in.close();
/*
retrieveFileStream使用了流,需要釋放一下,不然會返回null
方法一:主動調用一次getReply()把接下來的226消費掉
方法二:主動調用一次completePendingCommand(),把流釋放掉
*/
ftpClient.getReply();
} catch (Exception e) {
log.error(e.getMessage(),e);
}
return lineList;
}
/**
* 獲取文件輸出流
* @param ftpClient ftp連接對象
* @param filePath 文件路徑
* @param out 文件輸出流
*/
public void readFileWithOutputStream(FTPClient ftpClient, String filePath, OutputStream out)
{
try {
if(out == null)
{
throw new BusinessException("輸出流為null");
}
ftpClient.retrieveFile(filePath,out);
out.flush();
out.close();
} catch (Exception e) {
log.error(e.getMessage(),e);
}
}
}
上面只是最簡單的,可以在本地操作ftp上傳下載,在web里面還是有些區別。這里既然是通過spring進行操作,我們不妨在做一些封裝,簡化在項目中的操作。例如我們操作FTP的時候,必要的東西例如,ip,端口,賬號,密碼,這些都是很少進行變化的,但是又是在項目中經常用的,這里提供一個思路,可以在項目啟動的時候,把這些信息加載到內存或者緩存中。
FtpBean對象,這里展示是省略了get set那些方法的。
package com.wzh.config.framework.domain;
import org.apache.ibatis.type.Alias;
/**
* @author wzh
* @create 2018-05-27 20:14
* @desc ${ftp 對象,用于存儲ftp賬戶信息}
**/
@Alias("ftpBean")
public class FtpBean {
/**
* fpt別名
*/
private String ftpName;
/**
* ftp服務器ip
*/
private String ftpHost;
/**
* ftp服務器端口
*/
private String ftpPort;
/**
* 賬號名
*/
private String ftpUserName;
/**
* 密碼
*/
private String ftpPassword;
Spring 在項目啟動的時候加載一些從數據庫中查詢的常量方式很多,可以在xml中配置bean,然后寫init方法,也可以使用注解,或者繼承某些類。這篇博文寫得比較詳細,想詳細了解的可以看下這篇文章
https://blog.csdn.net/honghailiang888/article/details/73333821
因為整合的demo是基于SpringBoot做的,boot中提倡少xml配置文件,所以這里提供一種基于@PostConstruct注解的方式,加載了此注解的方法,會在Spring啟動完成后第一時間執行。
package com.wzh.config.framework.frameworkInit;
import com.wzh.config.framework.domain.FtpBean;
import com.wzh.config.framework.service.InitFrameWorkConstantService;
import com.wzh.demo.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author wzh
* @create 2018-05-21 23:58
* @desc ${系統加載時初始化常量}
**/
@Component
public class InitConstant {
/**
* ftp賬號信息對象,靜態,加載到內存中
*/
private static Map<String,Object> ftpInfoMap;
public static Map<String, Object> getFtpInfoMap() {
return ftpInfoMap;
}
@Resource
@Qualifier(value = "initFrameWorkConstantService")
private InitFrameWorkConstantService initFrameWorkConstantService;
/**
* 初始化ftp賬號信息對象
*/
@PostConstruct
public void initFtpInfo()
{
ftpInfoMap = new HashMap<String, Object>();
List<FtpBean> ftpList = initFrameWorkConstantService.initFtpInfo();
if(!ftpList.isEmpty())
{
for (FtpBean bean : ftpList)
{
//鍵值對方式存放,key為ftp的別名,方便取
ftpInfoMap.put(bean.getFtpName(),bean);
}
}
}
}
把之前的FtpUtils再進行一下封裝,這里特別說一下,部分方法沒有測試,只是單純的寫了,如果拿來實際使用,需要再測試一下。這里先把文件在線解析,上傳下載,文件流的方法單獨說明,其他的方法就不一一演示了,在文末會把代碼貼出來。
在項目中有這么一個場景,就是用戶上傳實體文件入庫,有excel的,這種場景一般是在用戶端直接頁面操作,解析后入庫,還有一種是跨平臺實體文件同步,有的時候有某些大批量的數據需要跨平臺同步,如果直接通過接口的方式調用,文件條數如果是幾十萬,接口性能并不高,這個時候可以通過ftp文件服務器的方式同步,大體有兩種,第一種是接口主動通知服務端,文件已經放到ftp服務器上,還有一種就是定時任務固定時間掃碼目錄,兩種方式只是觸發機制不一樣,當時處理邏輯都是相同的。
文本文件解析方法,這里為了作為通用方法,用了下泛型和反射
/**
* 解析txt實體文件并轉換為對應的list集合,如果沒有分隔符,用String接收
* 需注意實體類與字符串拆分后的順序需相同,排除final 屬性不進行設置值
* 其實還有一種方案就是可以用xml等配置文件進行配置文件映射,屬性類型,這里為了簡單就直接要求順序相同
* @param ftpName ftp別名
* @param filePath 服務器文件路徑
* @param encode 文件編碼集
* @param regex 文件數據分隔符
* @param obj 解析映射的對象
* @param simpleDateFormat 解析映射的對象
* @param <T> 對象泛型
* @return 返回解析后的集合
*/
public <T> List<T> readFileWithLine(String ftpName, String filePath, String encode, String regex,
String simpleDateFormat,T obj) throws Exception{
//解析后返回的數據集合
List<T> clazzes = new ArrayList<T>();
FTPClient ftpClient = linkFtp(ftpName);
if(null != ftpClient)
{
List<String> info = FtpUtils.redFtpFileWithLine(ftpClient, filePath, encode);
if(null != info && !info.isEmpty())
{
if(StringUtils.isBlank(regex))
{
// 無分隔符,判斷為String 集合
clazzes.addAll((Collection<? extends T>) info);
}else {
for(String str : info)
{
// 拆分行數據
String [] line = str.split(regex);
//因為JDK用的1.9 所以沒有直接newInstance,如果是低版本的jdk 可以直接getClass().newInstance
T t = (T) obj.getClass().getDeclaredConstructor().newInstance();
// 獲取文件屬性數組
Field[] fielders = t.getClass().getDeclaredFields();
// 循環排除final屬性
List<Field> fieldList = new ArrayList<Field>();
for(Field cell : fielders)
{
if(!Modifier.isFinal(cell.getModifiers()))
{
// 非final的屬性才進行處理
fieldList.add(cell);
}
}
// 數據和對象映射要求完全對應,所以這里取對象下標
for(int i = 0; i < fieldList.size(); i++)
{
Field field = fieldList.get(i);
// 設置權限
field.setAccessible(true);
// 判斷數據類型進行轉換,這里只做了幾種常見類型的判斷,如果有需要可以繼續添加
String type = field.getType().getName();
try {
if("java.lang.Integer".equals(type) || "int".equals(type))
{
field.set(t,NumberUtils.toInt(line[i]));
}
else if("java.lang.Double".equals(type) || "double".equals(type))
{
field.set(t,NumberUtils.toDouble(line[i]));
}
else if("java.lang.Float".equals(type) || "float".equals(type))
{
field.set(t,NumberUtils.toFloat(line[i]));
}
else if("java.lang.Long".equals(type) || "long".equals(type))
{
field.set(t,NumberUtils.toLong(line[i]));
}
else if("java.lang.Short".equals(type) || "short".equals(type))
{
field.set(t,NumberUtils.toShort(line[i]));
}
else if("java.lang.Boolean".equals(type) || "boolean".equals(type))
{
field.set(t, BooleanUtils.toBoolean(line[i]));
}
else if("java.util.Date".equals(type) || "Date".equals(type))
{
SimpleDateFormat sdf=new SimpleDateFormat(simpleDateFormat);
if(StringUtils.isBlank(line[i]))
{
field.set(t, null);
}else{
field.set(t, sdf.parse(line[i]));
}
}
else {
field.set(t, line[i]);
}
}catch (Exception e){
log.error(e.getMessage(),e);
}
}
// 添加數據
clazzes.add(t);
}
}
}
}
return clazzes;
}
測試一下,首先弄一個實體文件
一個實體類User,省略get set 方法
package domin;
import java.util.Date;
/**
* <一句話功能描述>
* <功能詳細描述>
*
* @author wzh
* @version 2018-06-18 16:43
* @see [相關類/方法] (可選)
**/
public class User {
private String name;
private int age;
private Date birthday;
public User() {
super();
}
}
junit 測試
import base.BaseJunit;
import com.wzh.config.utils.FtpManagerUtils;
import domin.User;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.Date;
import java.util.List;
/**
* <一句話功能描述>
* <功能詳細描述>
* @author wzh
* @version 2018-06-18 16:16
* @see [相關類/方法] (可選)
**/
public class ftpTest extends BaseJunit {
@Autowired
@Qualifier(value = "ftpManagerUtils")
private FtpManagerUtils ftpManagerUtils;
@Test
public void readTextTest()
{
User user = new User();
try {
//對象文本文件
List<User> list = ftpManagerUtils.readFileWithLine("FTP_USER_SYSTEM",
"/file/userinfo.txt","utf-8","\\|","yyyy-MM-dd",user);
//字符串集合文件文件
List<String> strlist = ftpManagerUtils.readFileWithLine("FTP_USER_SYSTEM",
"/file/userinfo.txt","utf-8","","yyyy-MM-dd",new String());
System.out.println(list);
System.out.println(strlist);
} catch (Exception e) {
e.printStackTrace();
}
}
}
通過截圖我們可以看到不管是字符串接收行數據還是對象接收,都成功解析了,這個時候就可以根據自身的業務邏輯進行處理入庫等操作了。
在文件上傳服務器這一塊,處理的思路一般有兩種,如果項目比較小,就直接上傳到工程目錄下,或者把工程目錄掛載出去,把其他文件服務器的磁盤掛到工程目錄下的文件服務器。還有一種就是專門的文件服務器,所有的文件都上傳到文件服務器,這里做一個用戶端上傳文件后直接把文件上傳到ftp服務器上的處理方式。
文件上傳工具類,這里是用戶上傳后直接上傳ftp的場景,如果是先存工程,再傳服務器,可以用另外一個方法
/**
* 上傳文件到ftp服務器
* @param ftpName ftp別名
* @param file 文件對象
* @param ftpPath ftp 服務器保存路徑
* @param newFileName 保存的文件名
* @return 上傳是否成功過
*/
public boolean upLoadFile(String ftpName, MultipartFile file, String ftpPath, String newFileName){
//默認失敗
boolean flag = false;
FTPClient ftpClient = linkFtp(ftpName);
InputStream in = null;
if (null != ftpClient) {
try {
// 獲取文件名
String fileName = file.getOriginalFilename();
// 獲取文件后綴名
String suffix = FtpUtils.getSuffix(fileName);
// 路徑轉碼,處理中文
ftpPath = FtpUtils.changeEncode(ftpClient,ftpPath);
newFileName = FtpUtils.changeEncode(ftpClient,newFileName + suffix);
// 判斷目標文件夾是否存在,不存在就創建
if(!ftpClient.changeWorkingDirectory(ftpPath))
{
ftpClient.makeDirectory(ftpPath);
ftpClient.changeWorkingDirectory(ftpPath);
}
in = file.getInputStream();
flag = ftpClient.storeFile(newFileName,in);
if(flag)
{
log.info("文件上傳成功:" + fileName);
}
}catch (Exception e)
{
log.error("文件上傳失?。?#34; + e.getMessage(),e);
}finally
{
try {
if(in != null)
{
in.close();
}
} catch (IOException e) {
log.error(e.getMessage(),e);
}
// 關閉連接
FtpUtils.closeFTP(ftpClient);
}
}
return flag;
}
一個頁面,這里用的ftl
<#import "spring.ftl" as spring />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${request.contextPath }/ftp/upload.do" method="POST" enctype="multipart/form-data">
文件:<input type="file" name="file"/>
<input type="submit"/>
</form>
</body>
</html>
一個簡單的controller ,里面有把MultipartFile 轉換為File 其實方法也可以直接傳輸入流,這里沒過多糾結,如果需要流的場景可以重載寫一個
package com.wzh.demo.controller;
import com.wzh.config.utils.FtpManagerUtils;
import com.wzh.config.utils.FtpUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
/**
* <ftp文件上傳控制器>
* <功能詳細描述>
*
* @author wzh
* @version 2018-06-18 17:55
* @see [相關類/方法] (可選)
**/
@Controller
@RequestMapping("/ftp")
public class FtpController {
@Autowired
@Qualifier("ftpManagerUtils")
private FtpManagerUtils ftpManagerUtils;
@RequestMapping(value = "/upload.do",method = RequestMethod.GET)
public String toFileUpload()
{
return "/test/fileUpload";
}
@RequestMapping(value = "/upload.do", method = RequestMethod.POST)
public String FileUpload(@RequestParam("file") MultipartFile file)
{
String suffix = FtpUtils.getSuffix(file.getOriginalFilename());
//根據自身業務做處理重命名
String newFileName = UUID.randomUUID().toString().replace("-", "");
//文件上傳
ftpManagerUtils.upLoadFile("FTP_USER_SYSTEM",file,"/file/test/",newFileName);
return "/test/fileUpload";
}
}
去服務器查看,有uuid重命名的文件,切能正常打開
用戶頁面操作,從FTP下載文件,這個沒什么特別好說的,一般這用用在應用服務器數據庫中只存儲了用戶的文件名和基本路徑,服務器放在文件服務器上,當用戶需要下載的時候,從ftp下載文件。
文件下載工具類,這里就沒有寫特別復雜,就直接流的方式就可以了
/**
* 獲取文件流
* @param ftpName ftp別名
* @param filePath ftp服務器上文件路徑
* @param out 輸出流
*/
public void readFileWithOutputStream(String ftpName, String filePath, OutputStream out)
{
FTPClient ftpClient = linkFtp(ftpName);
if(null != ftpClient)
{
// 綁定輸出流
FtpUtils.readFileWithOutputStream(ftpClient, filePath, out);
// 關閉連接
FtpUtils.closeFTP(ftpClient);
}
}
一個簡單的頁面
<#import "spring.ftl" as spring />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${request.contextPath }/ftp/down.do" method="POST" enctype="multipart/form-data">
文件:<input type="text" name="fileName"/>
<input type="submit"/>
</form>
</body>
</html>
controller控制器
@RequestMapping(value = "/down.do",method = RequestMethod.GET)
public String toFileDown()
{
return "test/fileDown";
}
@RequestMapping(value = "/down.do", method = RequestMethod.POST)
public String fileDown(HttpServletResponse response, String fileName) {
try {
// 設置返回編碼及瀏覽器響應類型
response.setCharacterEncoding("UTF-8");
response.setContentType("multipart/form-data;charset=UTF-8");
//獲取文件后綴名
String suffix = FtpUtils.getSuffix(fileName);
//根據自身業務做處理重命名
String downName = UUID.randomUUID().toString().replace("-", "") + suffix;
response.setHeader("Content-Disposition", "attachment;fileName=" + downName);
//文件下載,大多數業務邏輯都是頁面傳遞文件名或ID,通過數據庫或其他文件查詢出具體文件路徑,這里為了測試,寫死
ftpManagerUtils.readFileWithOutputStream("FTP_USER_SYSTEM", "/file/test/" + fileName,
response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
return "test/fileDown";
}
測試一下,在代碼中也有說明,正常的下載是文件名傳遞,路徑后臺控制,這里為了測試,寫死了
點擊查詢下載成功,文件也能正常打開
這里大概就是spring 整合ftp的常用操作,寫得比較長,常見的功能都實現了,這里再次說明,很多方式沒有經過嚴格的測試,如果需要在項目中使用,需要再次測試。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。