本文使用java代码实现图片远程上传到linux的图片服务器上。

前提:linux安装好了ftp模块,nginx服务器,搭建好了图片服务器,可以远程访问

一个需求

通过springMVC接受图片文件然后上传到图片服务器,把图片在图片服务器上的相对路径(不包括图片服务器的ip,防止图片服务器ip改变)保存在数据库中

实现环境:前台上传图片组件+springMVC+spring+mybatis+mysql

引入依赖

需要导入相关jar包,这里使用maven管理,导入依赖:

commons-io
commons-io

2.1

commons-fileupload
commons-fileupload

1.3

commons-net
commons-net

3.3

由于上传文件需要图片服务器相关的配置信息,这里为了不硬编码在代码中,模仿数据库连接信息的方式配置在配置文件中,然后交给spring进行管理

图片服务器需要的配置的配置文件放在classpath下:

ftp.properties

#ftp相关配置

FTP_ADDRESS=192.168.1.113

FTP_PORT=21

FTP_USERNAME=ftpuser_album

FTP_PASSWORD=123456

FTP_BASEPATH=/home/ftpuser_album/www/album_images

#图片服务器相关配置

IMAGE_BASE_URL=http://192.168.1.113/album_images

配置文件内容让spring读取到容器中,然后存储在实体类中:

spring配置

classpath:db.properties

classpath:ftp.properties

classpath:redis.properties

springMVC配置文件需要配置上传文件的bean

实体类:FtpConfig.java

@Component
public class FtpConfig {
/**
* 获取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;
...set和get方法就省略
}

这样哪里需要使用图片服务器配置信息就可以通过@AutoWired注入FtpConfig对象即可

上传案例

上传的工具类:

public class FtpUtil {
/**
* ftp上传图片方法
*title:pictureUpload

*@param ftpConfig  由spring管理的FtpConfig配置,在调用本方法时,可以在使用此方法的类中通过@AutoWared注入该属性。由于本方法是静态方法,所以不能在此注入该属性

*@param picNewName 图片新名称--防止重名 例如:"1.jpg"

*@param picSavePath 图片保存路径。注:最后访问路径是 ftpConfig.getFTP_ADDRESS()+"/images"+picSavePath

*@param file 要上传的文件(图片)

*@return 若上传成功,返回图片的访问路径,若上传失败,返回null

* @throws IOException

*/

public static String pictureUploadByConfig(FtpConfig ftpConfig,String picNewName,String picSavePath,InputStream inputStream) throws IOException{
String picHttpPath = null;
boolean flag = uploadFile(ftpConfig.getFTP_ADDRESS(), ftpConfig.getFTP_PORT(), ftpConfig.getFTP_USERNAME(),
ftpConfig.getFTP_PASSWORD(), ftpConfig.getFTP_BASEPATH(), picSavePath, picNewName, inputStream);
if(!flag){
return picHttpPath;
}
//picHttpPath = ftpConfig.getFTP_ADDRESS()+"/images"+picSavePath+"/"+picNewName;
picHttpPath = ftpConfig.getIMAGE_BASE_URL()+picSavePath+"/"+picNewName;
System.out.println("==="+picHttpPath);
return picHttpPath;
}
/**
* 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, String ftpPort, String username, String password, String basePath,
String filePath, String filename, InputStream input) {
int port = Integer.parseInt(ftpPort);
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);
ftp.enterLocalPassiveMode();//这个设置允许被动连接--访问远程ftp时需要
//上传文件
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;
}
}
springMVC的使用:
@Autowired
private FtpConfig ftpConfig;
@RequestMapping("/uploadFiles")
@ResponseBody
public MSG uploadFiles(@RequestParam("albumId")Integer albumId,@RequestParam("file")MultipartFile[] files) throws IOException {
List photoList = new ArrayList();
//循环上传多个图片
for(MultipartFile file:files){
Photo photo = new Photo();
String oldName = file.getOriginalFilename();
String picNewName = UploadUtils.generateRandonFileName(oldName);//通过工具类产生新图片名称,防止重名
String picSavePath = UploadUtils.generateRandomDir(picNewName);//通过工具类把图片目录分级
photo.setPhotoUrl(picSavePath+"/"+picNewName);//设置图片的url--》就是存储到数据库的字符串url
photo.setAlbumId(albumId);//设置图片所属相册id
photo.setPhotoDesc(oldName);//设置图片描述
photoList.add(photo);
FtpUtil.pictureUploadByConfig(ftpConfig,picNewName,picSavePath,file.getInputStream());//上传到图片服务器的操作
}
//添加到数据库
iPhotoService.savePhotoList(photoList);//调用service层方法
return MSG.success();//上传成功做的操作,我这里返回上传成功的信号
}
UploadUtils.java工具类:
public class UploadUtils {
/**
* 得到真实文件名
* @param fileName
* @return
*/
public static String subFileName(String fileName){
//查找最后一个 \ (文件分隔符)位置
int index = fileName.lastIndexOf(File.separator);
if(index == -1){
//没有分隔符,说明是真实名称
return fileName;
}else {
return fileName.substring(index+1);
}
}
/**
* 获得随机UUID文件名
* @param fileName
* @return
*/
public static String generateRandonFileName(String fileName){
//首相获得扩展名,然后生成一个UUID码作为名称,然后加上扩展名
String ext = fileName.substring(fileName.lastIndexOf("."));
return UUID.randomUUID().toString()+ext;
}
/**
* 获得hashcode 生成二级目录
* @param uuidFileName
* @return
*/
public static String generateRandomDir(String uuidFileName){
int hashCode = uuidFileName.hashCode();//得到它的hashcode编码
//一级目录
int d1 = hashCode & 0xf;
//二级目录
int d2 = (hashCode >> 4) & 0xf;
return "/"+d1+"/"+d2;
}
}

最后亲测能够实现上传。