【SpringBoot】上传图片到Linux服务器(html+ajax+jquery+ftpclient+nginx)
最近在做毕业设计,需要做一个批量上传图片的功能。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kclub</groupId>
<artifactId>tenement_project</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>tenement_project Maven Webapp</name>
<url>http://maven.apache.org</url>
<!-- 父级 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.7</java.version>
</properties>
<dependencies>
<!-- start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- web application -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-boot-devtools工具包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>true</scope>
</dependency>
<!-- mybatis引入的依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 引入fastjson插件 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.32</version>
</dependency>
<!-- theymeleaf模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-email -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<!-- 阿里短信服务jar/ -->
<dependency>
<groupId>aliyun-java-sdk-core</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>aliyun-java-sdk-dysmsapi</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0</version>
</dependency>
<!-- /阿里短信服务jar -->
<!-- https://mvnrepository.com/artifact/com.aliyun/aliyun-java-sdk-core -->
<!-- 文件上传 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<!-- commons-logging/commons-logging 日志 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
<build>
<finalName>tenement_project</finalName>
<pluginManagement>
<plugins>
<!-- 项目打包,将springboot应用打包为可执行的jar或war文件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- springloader -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- fork: 如果没有该项配置,肯呢个devtools不会起作用, 即应用不会restart -->
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
先介绍一下,前端的代码:
①在前端html中使用file类型的input标签,
<input type="file" multiple="multiple" id="uploadImages">
②js操作,获取file,存在一个fileStack数组中,并通过,jquery each方法,将图片回写
到Html中。
$(function() {
// 图片上传
fileStack = [];// 存放图片文件的数组
// 当<input type="file">change时调用addFiles()
$("#uploadImages").change(function() {
addFiles();
})
// 删除操作,操作这个fileStack
function addFiles() {
var files = document.querySelector("input[type=file]");
var filelist = files.files;// 选择图片列表
$.each(filelist,function(i, file) {fileStack.push(file);
var reader = new FileReader();
reader.onload = function(e) {
var result = this.result;
var img = document.createElement("img");
// img.src = result;
var i = 0;
$("#imagesUl").append("<li class='img_box' data-index='"
+ (i++)
+ "' draggable='true'><img src='"
+ result
+ "'><div class='img_cover'></div><div class='toolbar_wrap'>"
+ "<div class='opacity'></div>"
+ "<div class='toolbar'>"
+ "<a href='javascript:;' class='edit'></a><a href='javascript:;' class='delete'></a></div></div></li>");
};
reader.readAsDataURL(file);
});
} })
③提交数据到后台,用each方法将上述fileStack数组添加到formdata中
var formdata = new FormData();//定义一个formdata对象
$.each(fileStack, function(i, file) {// 所有文件都要放到同一个名字下面:如files
formdata.append("file", file);
});
function submitMethod(formdata) {
$.ajax({
type : 'POST',
url : "/tenement/uploadImages.action",
dataType : 'json',
data : formdata,
cache : false,
processData : false,
contentType : false,
success : function(responseStr) {
if (responseStr == "1") {
swal("发布成功,信息审核中", "", "success");
} else {
swal("发布失败,未知错误", "", "error");
}
},
error : function(responseStr) {
swal("发布失败,未知错误", "", "error");
}
});
}
后台代码:
Controller层代码:
/**
* 数据上传
*
* @param albumId
* @param files
* @return
* @throws IOException
*/
@RequestMapping("/uploadImages.action")
public @ResponseBody String uploadFiles(@RequestParam("albumId") Integer albumId,
@RequestParam("file") MultipartFile[] files) throws IOException {
logger.info("【上传图片controller】");
FtpConfig ftpConfig = new FtpConfig();
List<Photo> photoList = new ArrayList<Photo>();
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 + "/");//
* 设置图片的url--》就是存储到数据库的字符串url photo.setAlbumId(albumId);//
* 设置图片所属相册id photo.setUser_id("wk");
* photo.setPhoteName(picNewName);
*/
photoList.add(photo);
FtpUtil.pictureUploadByConfig(ftpConfig, picNewName, picSavePath, file.getInputStream());// 上传到图片服务器的操作
// 添加到数据库
}
iPhotoService.uploadImages(photoList);
return state.Success;
}
UploadUtils.java,获得文件新名字,生成一二级目录
package com.tenement.utils.ftp_images_server;
import java.io.File;
import java.util.UUID;
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;
}
public static String generateRandonFileName() {
return UUID.randomUUID().toString();
}
/**
* 获得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;
}
public static void main(String[] args) {
System.out.println(generateRandonFileName());
}
}
FtpUtil.java,上传文件到服务器上的工具类
package com.tenement.utils.ftp_images_server;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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;
/**
* 正在使用
* @author wk
*
*/
public class FtpUtil {
private static final Log logger = LogFactory.getLog(FtpUtil.class);
public static String pictureUploadByConfig(FtpConfig ftpConfig, String picNewName, String picSavePath,
InputStream inputStream) throws IOException {
logger.info("【pictureUploadByConfig】");
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.getIMAGE_BASE_URL() + picSavePath + "/" + picNewName;
logger.info("【picHttpPath】"+picHttpPath);
return picHttpPath;
}
/**
* Description: 向FTP服务器上传文件
*
* @param host
* FTP服务器hostname
* @param port
* FTP服务器端口
* @param username
* FTP登录账号
* @param password
* FTP登录密码
* @param basePath
* FTP服务器基础目录
* @param filePath
* FTP服务器文件存放路径。
* @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;
}
}
FtpConfig.java实体类
package com.tenement.utils.ftp_images_server;
/**
* ftp服务器配置实体类
*
* @author wk
*
*/
public class FtpConfig {
/**
* 获取IP地址
*/
private String FTP_ADDRESS = "服务器ip地址";
/**
* 端口号
*/
private String FTP_PORT = "21";
/**
* 用户名
*/
private String FTP_USERNAME = "ftp用户名";
/**
* 密码
*/
private String FTP_PASSWORD = "ftp用户密码";
/**
* 基本路径,用户图片
*/
private String FTP_BASEPATH = "/home/ftptest/tenement/house_images";
/**
* 下载地址地基础url,这个是配置的图片服务器的地址,最后访问图片时候,需要用该基础地址
*/
private String IMAGE_BASE_URL = "url";
public String getFTP_ADDRESS() {
return FTP_ADDRESS;
}
public void setFTP_ADDRESS(String fTP_ADDRESS) {
FTP_ADDRESS = fTP_ADDRESS;
}
public String getFTP_PORT() {
return FTP_PORT;
}
public void setFTP_PORT(String fTP_PORT) {
FTP_PORT = fTP_PORT;
}
public String getFTP_USERNAME() {
return FTP_USERNAME;
}
public void setFTP_USERNAME(String fTP_USERNAME) {
FTP_USERNAME = fTP_USERNAME;
}
public String getFTP_PASSWORD() {
return FTP_PASSWORD;
}
public void setFTP_PASSWORD(String fTP_PASSWORD) {
FTP_PASSWORD = fTP_PASSWORD;
}
public String getIMAGE_BASE_URL() {
return IMAGE_BASE_URL;
}
public void setIMAGE_BASE_URL(String iMAGE_BASE_URL) {
IMAGE_BASE_URL = iMAGE_BASE_URL;
}
public String getFTP_BASEPATH() {
return FTP_BASEPATH;
}
public void setFTP_BASEPATH(String fTP_BASEPATH) {
FTP_BASEPATH = fTP_BASEPATH;
}
}
在这之前在项目pom.xml引入相关jar包
<!-- 加入上传文件组件 -->
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
整体思路:
前台获取获取file数组,传到后台,使用ftpclient类,将file传到linux服务器
上,在数据库中存储的是图片的一二级目录和图片新名字。
最后访问时通过nginx反向代理功能来访问服务器上的图片
如何利用Nginx搭建图片服务器参照博客:
https://blog.csdn.net/qq_36762765/article/details/79539226
参考:https://blog.csdn.net/maoyuanming0806/article/details/78068091
版权声明:本文为qq_36762765原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。