简介
文件上传功能,是信息系统开发中的常用功能,在传统的开发流程中,前端通过表单上传文件,后端进行文件处理。不利之处在于
- 后端需要写重复代码,每开发一个包含上传功能的系统,就需要写一遍上传逻辑。
- 当文件未保存在共享服务器时,其它开发人员无法获取上传的文件的正确地址。
- 当文件保存在共享文件系统时,需要对共享文件系统进行读写获取对应文件。
基于以上不利之处,我们结合包含了upload_module和upload-progress_module的nginx,以及nginx本身作为http服务器的特性,设计了本文件上传服务器,希望能减少大家的开发量。
1.文件上传服务器原理
2.部署Nginx上传服务器
部署Nginx上传服务器在上一篇文章已经说明,这里就不再赘述,详见docker 安装 Nginx 作为上传服务器
启动Nginx。
3.上传控件的使用
①使用iframeUplaod上传文件插件,该代码基本原理就是动态创建一个iframe,在iframe中再增加一个form,最后数据放到这个form中提交给服务器,前端代码如下:
<body>
<div id="uploadFile" class="upload">
</div>
<a href="javascript:void(0);" id="submit">提交</a>
<div class="pic-upload fl">
<div id="imgPreview">
<img class="picIcon" id="picIcon" src="${basePath}/resources/theme/images/user_default.jpg">
</div>
<input type="hidden" id="iconUrl" value="${basePath}/resources/theme/images/user_default.jpg">
</div>
<script src="${basePath}/resources/others/jquery/jquery-1.8.3.min.js"></script>
<script src="${basePath}/resources/upload/iframeUpload.js"></script>
<script language="javaScript">
$(function () {
var localPath = 'http://'+document.domain + ":" +
window.location.port + basePath+"/result";
var submitForm = IframeUpload.create({
id: "1",
url: basePath+"/fastdfs/systemIcon",
//progressUrl:"http://192.168.2.125:10000/progress",
interval:300,
containerId: 'uploadFile',
resultPath:localPath,
success: function (res) {
if (res.result == 'success') {
$("#iconUrl").val(res.msg);
$(".picIcon").attr('src', res.msg);
} else {
alert("上传失败!!!");
}
},
});
$('a#submit').click(function(){
submitForm.submit();
});
});
</script>
</body>
②如何在Java应用中集成上传文件组件
●在项目的pom.xml文件中添加相关依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-ssh</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
这里省略了spring相关依赖,若需要其他依赖,读者可自行查找添加。
●将config.properties中的内容复制到项目所在的properties文件中,并配置以下内容
remote.host=192.168.2.125 #文件上传服务器ip
remote.port=22 #文件上传服务器的SSH端口
remote.user=root #文件上传服务器的SSH用户名
remote.password=123456 #文件上传服务器的密码
remote.dir=/root/nginx/files/ #nginx配置的上传文件目录
nginx.port=10000 #nginx中配置监听的端口
nginx.fileuri=/files #nginx配置转发文件uri
remote.extern.host=192.168.2.125 #访问路径的host
●在spring-mvc.xml文件中引入conf.properties文件
<bean id="appProperty"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<array>
<value>classpath:conf.properties</value>
</array>
</property>
</bean>
●在spring-mvc.xml文件中配置文件上传解析器
<!-- 文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="524288000"></property>
</bean>
● 编写上传文件工具类,获取上传后的图片地址以及重命名文件
package com.eshore.upload.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.jcabi.ssh.SSHByPassword;
import com.jcabi.ssh.Shell;
@Component
public class FileUploadUtil {
@Value("${remote.host}")
private String remoteHost;
@Value("${remote.port}")
private String remotePort;
@Value("${remote.user}")
private String remoteUser;
@Value("${remote.password}")
private String remotePassword;
@Value("${remote.dir}")
private String remoteDir;
@Value("${nginx.port}")
private String nginxPort;
@Value("${nginx.fileuri}")
private String nginxFileUri;
public String getUrlFromRequest(HttpServletRequest request,String filename) throws NullPointerException{
StringBuilder builder = new StringBuilder("http://");
builder.append(remoteHost);
builder.append(":");
builder.append(nginxPort);
builder.append(nginxFileUri);
builder.append("/");
builder.append(filename);
return builder.toString();
}
public String renameFile(HttpServletRequest request) throws IOException,NullPointerException{
Shell shell = new SSHByPassword(remoteHost, Integer.valueOf(remotePort), remoteUser, remotePassword);
Shell.Plain plain = new Shell.Plain(shell);
String orgFile = request.getParameter("file_name");
if (orgFile == null) {
throw new NullPointerException("文件名不存在");
}
orgFile.replaceAll(" ", "");
String hostFile = request.getParameter("file_path");
if (hostFile == null) {
throw new NullPointerException("文件路径不存在");
}
String timestamp = new SimpleDateFormat("YYYY-MM-dd-HH-mm-ss").format(new Date()).toString();
String filename = new StringBuilder(timestamp).append("-").append(orgFile).toString().replaceAll(" ", "").replaceAll("/", "");
String hostFilePath = remoteDir.concat(hostFile.substring(hostFile.lastIndexOf("/") + 1));
String orgFilePath = remoteDir.concat(filename);
String renameCmd = new StringBuilder("mv ").append("\'").append(hostFilePath).append("\'").append(" ")
.append("\'").append(orgFilePath).append("\'").toString();
String result = plain.exec(renameCmd);
if (!result.isEmpty()) {
throw new NullPointerException("命令运行失败,请检查文件名是否有特殊符号,如()");
}
return filename;
}
}
●Controller层处理,返回结果,图片url入库
package com.eshore.upload.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.view.RedirectView;
import com.eshore.upload.util.FileUploadUtil;
@Controller
public class UploadController {
@Autowired
private FileUploadUtil fileUploadUtil;
@RequestMapping("/hello")
public String hello() {
return "hello";
}
@RequestMapping("/systemIcon")
public RedirectView uploadSystemIcon(HttpServletRequest request,
HttpServletResponse response, RedirectAttributes ra) {
String url = null; //这个URL是最终跳转返回的URL,本实例中,为/upload/result
String newUrl = request.getParameter("org");
try {
//重命名文件名称
String filename = fileUploadUtil.renameFile(request);
//获取返回的URL
url = fileUploadUtil.getUrlFromRequest(request, filename);
/**
* 如果需要保存图片信息,这里可以将url存入到数据库
*/
} catch (NullPointerException | IOException e) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
ra.addAttribute("result", "fail");
ra.addAttribute("msg", "exception happened");
return new RedirectView(newUrl);
}
ra.addAttribute("result", "success");
ra.addAttribute("msg", url);
return new RedirectView(newUrl);
}
@RequestMapping("/result")
public ModelAndView result(HttpServletRequest request) throws IOException {
ModelAndView view = new ModelAndView("upload/result");
return view;
}
@RequestMapping("/file")
public ModelAndView file(HttpServletRequest request) throws IOException {
ModelAndView view = new ModelAndView("upload/upload");
return view;
}
}
4.项目源码
项目源码已同步到GitHub:https://github.com/yinZh0522/nginx-upload