前兩篇文章我們搭建了一個ftp服務器,並對服務器進行了相應的配置,這篇文章我們來說一下我們如何上傳文件。
先介紹一下項目,本項目採用的是spring mvc +spring +mybatis ,用maven 進行項目管理。看一下項目結構 。
如果單獨做測試的話不用這麼費勁,寫一個簡單的測試類就ok了!而在這個項目中,parent是所有項目的父包,其他的項目都把該項目做爲父項目。common中放入的是一些公用的工具類,pojo對象等,pojo和mapper項目是mybatis逆向生成的項目。而service 是處理業務邏輯的項目,web 是展示層的項目。介紹完了,直接看我們要求的代碼。
上傳文件需要的工具類。代碼如下所示,這個東西一般不用自己再寫了,網上有很多,直接找一個用就可以了,但是要弄懂它的意思。
public class FtpUtil {
/**
* Description: 向FTP服務器上傳文件
* @param host FTP服務器hostname
* @param port FTP服務器端口
* @param username FTP登錄賬號
* @param password FTP登錄密碼
* @param basePath FTP服務器基礎目錄
* @param filePath FTP服務器文件存放路徑。例如分日期存放:/2015/01/01。文件的路徑爲basePath+filePath
* @param filename 上傳到FTP服務器上的文件名
* @param input 輸入流
* @return 成功返回true,否則返回false
*/
public static boolean uploadFile(String host, int port, String username, String password, String basePath,
String filePath, String filename, InputStream input) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);// 連接FTP服務器
// 如果採用默認端口,可以使用ftp.connect(host)的方式直接連接FTP服務器
ftp.login(username, password);// 登錄
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
//切換到上傳目錄
if (!ftp.changeWorkingDirectory(basePath+filePath)) {
//如果目錄不存在創建目錄
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
//設置上傳文件的類型爲二進制類型
ftp.setFileType(FTP.BINARY_FILE_TYPE);
//上傳文件
if (!ftp.storeFile(filename, input)) {
return result;
}
input.close();
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
/**
* Description: 從FTP服務器下載文件
* @param host FTP服務器hostname
* @param port FTP服務器端口
* @param username FTP登錄賬號
* @param password FTP登錄密碼
* @param remotePath FTP服務器上的相對路徑
* @param fileName 要下載的文件名
* @param localPath 下載後保存到本地的路徑
* @return
*/
public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
String fileName, String localPath) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);
// 如果採用默認端口,可以使用ftp.connect(host)的方式直接連接FTP服務器
ftp.login(username, password);// 登錄
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
ftp.changeWorkingDirectory(remotePath);// 轉移到FTP服務器目錄
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(fileName)) {
File localFile = new File(localPath + "/" + ff.getName());
OutputStream is = new FileOutputStream(localFile);
ftp.retrieveFile(ff.getName(), is);
is.close();
}
}
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
}
我們的pojo項目和mapper項目,不需要寫代碼,在service層要做一些處理,判斷是否上傳成功。會看到如何代碼有很多的獲取值的,因爲我們不能見ftp服務器的一些信息都寫死到代理嗎,我們要把它放入配置文件中,可以是xml文件,或者properties等,這裏採用的是properties文件形式。Service 項目是jar 類型的,最後要打成jar包,放入到web項目中,所以所有的配置文件信息應該都放入web項目中。
我們ftp配置信息在resource.properties文件中,如下所示,在寫這個配置文件的時候千萬要注意所有的值前後不要空格,所有的值前後不要空格,所有的值前後不要空格,重要的事情講三遍,我就是因爲一個空格弄了整整半天。
#ftp相關配置
FTP_ADDRESS=192.168.xx.xxx
FTP_PORT=21
FTP_USERNAME=ftpuser
FTP_PASSWORD=123456
FTP_BASEPATH=/home/ftpuser/www/images
#圖片服務器相關配置i
IMAGE_BASE_URL=http://192.168.xx.xxx/www/images
配置完resource.properties以後,要確保在項目啓動的時候一定要加載這個文件,在配置文件中加上這句話。<!-- 加載配置文件 -->
<context:property-placeholderlocation="classpath:resource/*.properties" /> 這樣就可以保證配置文件會被加載了。
然後我們在service中寫自己的業務邏輯,
@Service
public class PictureServiceImpl implements PictureService {
//獲取ip地址
@Value("${FTP_ADDRESS}")
private String FTP_ADDRESS;
//端口號
@Value("${FTP_PORT}")
private String FTP_PORT;
//用戶名
@Value("${FTP_USERNAME}")
private String FTP_USERNAME;
//密碼
@Value("${FTP_PASSWORD}")
private String FTP_PASSWORD;
//基本路徑
@Value("${FTP_BASEPATH}")
private String FTP_BASEPATH;
//下載地址地基礎url
@Value("${IMAGE_BASE_URL}")
private String IMAGE_BASE_URL;
@Override
public Map uploadPicture(MultipartFile uploadFile) {
Map resultmMap = new HashMap<>();
try {
// 生成一個文件名
// 獲取舊的名字
String oldName = uploadFile.getOriginalFilename();
String newName = IDUtils.genImageName();
//新名字
newName = newName + oldName.substring(oldName.lastIndexOf("."));
//上傳的路徑
String imagePath = new DateTime().toString("/yyyy/mm/dd");
//端口號
int port = Integer.parseInt(FTP_PORT);
System.out.println(FTP_BASEPATH);
//調用方法,上傳文件
boolean result = FtpUtil.uploadFile(FTP_ADDRESS, port,
FTP_USERNAME, FTP_PASSWORD, FTP_BASEPATH, imagePath,
newName, uploadFile.getInputStream());
//判斷是否上傳成功
if (!result) {
resultmMap.put("error", 1);
resultmMap.put("message", "上傳失敗");
return resultmMap;
}
resultmMap.put("error", 0);
resultmMap.put("url", IMAGE_BASE_URL + imagePath + newName);
return resultmMap;
} catch (IOException e) {
resultmMap.put("error", 1);
resultmMap.put("message", "上傳發生異常");
return resultmMap;
}
}
}
Controler中服務請求的轉發工作。代碼如下。
@Controller
public class PictureController {
@Autowired
private PictureService pictureService;
@RequestMapping("/pic/upload")
@ResponseBody
public Map pictureUpload(MultipartFile uploadFile){
Map result = pictureService.uploadPicture(uploadFile);
return result;
}
}
在jsp 頁面中我們用
<span style="font-size:18px;"> <a href="javascript:void(0)" class="easyui-linkbuttonpicFileUpload">上傳圖片</a>
<inputtype="hidden" name="image"/></span>
而調用到js代碼如下所示
// 初始化圖片上傳組件
initPicUpload : function(data){
$(".picFileUpload").each(function(i,e){
var _ele = $(e);
_ele.siblings("div.pics").remove();
_ele.after('\
<div class="pics">\
<ul></ul>\
</div>');
// 回顯圖片
if(data && data.pics){
var imgs = data.pics.split(",");
for(var i in imgs){
if($.trim(imgs[i]).length > 0){
_ele.siblings(".pics").find("ul").append("<li><a href='"+imgs[i]+"' target='_blank'><img src='"+imgs[i]+"' width='80' height='50' /></a></li>");
}
}
}
//給“上傳圖片按鈕”綁定click事件
$(e).click(function(){
var form = $(this).parentsUntil("form").parent("form");
//打開圖片上傳窗口
KindEditor.editor(TT.kingEditorParams).loadPlugin('multiimage',function(){
var editor = this;
editor.plugin.multiImageDialog({
clickFn : function(urlList) {
var imgArray = [];
KindEditor.each(urlList, function(i, data) {
imgArray.push(data.url);
form.find(".pics ul").append("<li><a href='"+data.url+"' target='_blank'><img src='"+data.url+"' width='80' height='50' /></a></li>");
});
form.find("[name=image]").val(imgArray.join(","));
editor.hideDialog();
}
});
});
});
});
},
這些代碼都寫完以後,我們測試會發現依然有問題,Expected MultipartHttpServletRequest: is a MultipartResolverconfigured 這個錯誤是因爲我們沒有配置解析文件的jar。所以我們還要在springmvc的配置文件中加上如下配置。這樣我們應該就沒問題了!
<span style="font-size:18px;"><!-- 上傳文件攔截,設置最大上傳文件大小10M=10*1024*1024(B)=10485760 bytes -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize"value="10485760" />
</bean></span>
這樣我們就可以了,如果有需要源碼的情單獨聯繫我。不方便放入資源中!