SpringMVC的文件上传
本篇文章主要解决两个问题
- 怎么使用springMVC 框架上传文件
- 怎么在服务器上的指定路径保存文件,是它成为一个小型的文件服务
1.文件的上传
1.1 上传文件需要的组件
- SpringMVC 框架
- form-components.js组件
1.2 HTML页面的实现
我们以一个form的表单为例,在这个表单中除了上传文件的选项外,还有其他的input
选项,当点击提交按钮的时候,这些都会被提交到后台进行处理。下面是html的代码:
<form class="form-horizontal" id="add-blog-form" name="add-blog-form" enctype="multipart/form-data">
<div class="control-group">
<label class="control-label">博客名</label>
<div class="controls">
<input type="text" placeholder="请输入博客名" class="m-wrap medium" name="add-blogName">
<span class="help-inline"></span>
</div>
</div>
<div class="control-group" >
<label class="control-label">博客上传</label>
<div class="controls">
<input type="file" placeholder="" class="m-wrap medium" name="add-blog">
<span class="help-inline"></span>
</div>
</div>
<div class="control-group" >
<label class="control-label">图片上传</label>
<div class="controls">
<input type="file" placeholder="" class="m-wrap medium" name="add-fig">
<span class="help-inline"></span>
</div>
</div>
</form>
注意: form 标签中必须要有这句enctype="multipart/form-data
.在这个html中,还需引入form-components.js :
<script src="../js/jquery-form.js" ></script>
1.3 javaScript 的实现
jQuery Form插件是一个优秀的Ajax表单插件,可以非常容易地、无侵入地升级HTML表单以支持Ajax。我们使用它的ajaxSubmit()方法来提交表单。代码如下:
$("#add-blog-form").ajaxSubmit({
dataType: 'json',
url: '../blog/upload.do',
type: 'POST',
contentType: "application/x-www-form-urlencoded; charset=utf-8",
success:function(data){
$("#add-responsive").modal('hide');
var r ;
console.log("su"+data)
if(data=="success"){
r = "添加成功!";
showRow();
}else{
r = "添加失败!";
}
$("h2#all-result").html(r);
$("#result-responsive").modal('show');
},
error:function(){
//输出错误信息
}
1.4 后台的处理
首先配置spring-mvc 的xml文件如下:
<!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 默认编码 -->
<property name="defaultEncoding" value="utf-8" />
<!-- 文件大小最大值 -->
<property name="maxUploadSize" value="10485760000" />
<!-- 内存中的最大值 -->
<property name="maxInMemorySize" value="40960" />
</bean>
后台使用的是SpringMVC 来进行处理,代码如下:
@Value("#{configProperties['mdFile.path']}")
private String mdFilePath;
@Value("#{configProperties['imgFile.path']}")
private String imgFilePath;
@RequestMapping(value="/upload" ,method = RequestMethod.POST, produces = "application/json;charset=utf8")
@ResponseBody
public String upload(@RequestParam(value="add-blog") MultipartFile file1,@RequestParam(value="add-fig", required=false) MultipartFile file2,
@RequestParam(value="add-blogName") String blogName ) throws IOException {
if (!file1.isEmpty()) {
InputStream in1 = null;
OutputStream out1 = null;
String imgRealPath=null;
try {
// 获得在tomcat中项目的路径, 需要在web.xml配置ft.webapp
//String webRootPath = System.getProperty("ft.webapp");
String html = null;
//logger.info(webRootPath);
// String rootPath = System.getProperty("catalina.home");
//File dir = new File(webRootPath + File.separator + "uploadFiles");
File dirMd = new File(mdFilePath+blogName);
if (!dirMd.exists())
dirMd.mkdirs();
File serverFile = new File(dirMd.getAbsolutePath() + File.separator + file1.getOriginalFilename());
in1 = file1.getInputStream();
out1 = new FileOutputStream(serverFile);
byte[] b = new byte[1024];
int len = 0;
while ((len = in1.read(b)) > 0) {
html += new String(b,0,len,"UTF-8");
out1.write(b, 0, len);
}
out1.close();
in1.close();
if(file2!=null){
InputStream inImg = null;
OutputStream outImg = null;
try {
File dirImg = new File(imgFilePath+blogName);
if (!dirImg.exists())
dirImg.mkdirs();
imgRealPath = dirImg.getAbsolutePath() + File.separator + file2.getOriginalFilename();
File serverFileImg = new File(imgRealPath);
inImg = file2.getInputStream();
outImg = new FileOutputStream(serverFileImg);
byte[] b2 = new byte[1024];
int len2 = 0;
while ((len2 = inImg.read(b2)) > 0) {
outImg.write(b2, 0, len2);
}
outImg.close();
inImg.close();
}catch (Exception e){
return "fail";
}finally {
if (outImg != null) {
outImg.close();
outImg = null;
}
if (inImg != null) {
inImg.close();
inImg = null;
}
}
}
html = blogService.renderToHtml(html);
System.out.println("++++++++++++"+html);
String noNeed = "<p>null</p>";
String newHtml="";
if(html.startsWith(noNeed)){
newHtml = html.replaceFirst(noNeed," ");
}
System.out.println("=========="+newHtml);
//insert form to database
blogService.insertBlog2database(blogName, newHtml, imgRealPath);
//update tags info
tagService.updateTagofBlogId(blogName);
return "success";
} catch (Exception e) {
return "fail";
} finally {
if (out1 != null) {
out1.close();
out1 = null;
}
if (in1 != null) {
in1.close();
in1 = null;
}
}
} else {
return null;
}
}
上面代码最主要的是对接收的文件进行按字节流的读入和写出,关于写出文件的相关问题会在下面章节进行详细的介绍。其他的是一些业务的逻辑代码,可以跳过。
2. 上传后文件的处理
在前一节中,我们通过前端处理把要上传的文件信息传到了后端,并在后端写入的指定的路径,一般来说上传的文件都会在tomcat的工程路径下,但是这样有一定的局限性,比如我们读取文件又要写一些读入的代码,做一些判断。因此,我们会使用Tomcat做一个简单的文件服务器,这样只需要在数据库中存储文件的路径,然后使用代码访问这个路径就可以访问到文件了。
2.1 Tomcat 的相关配置
在server.xml
中的Host
标签中加入Context
标签的内容 , 如下所示:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<Context path="/root/blogfile" docBase="/root/blogfile" />
</Host>
注: 使用的是Tomcat8.0版本,这里实际上配置的是虚拟目录,<Context>
是Host标记的子元素,表示一个虚拟目录,它主要有两个属性,path就相当于虚拟目录名字,而 docbase则是具体的文件位置。这样设置后就可以访问到了,如果想在浏览器中看到文件还需要设置web.xml, 把listings
设置为true
。
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> ```
这样访问`host+路径`就可以访问到文件,如果不配置会出现404.
![uploadfile.png](http://upload-images.jianshu.io/upload_images/1814710-f221e7535f611499.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
#### 2.2 后台的配置处理
在1.4 中,我们刚开始使用了@Value注解进行了配置:
``` java
@Value("#{configProperties['mdFile.path']}")
private String mdFilePath;
@Value("#{configProperties['imgFile.path']}")
private String imgFilePath;
它的作用是获取配置文件的key所对应的值,我们知道,在java中一些变化的量,尤其是路径,最好写在配置文件中,这样发生变化只修改配置文件就可以了,不用动代码。我们的配置文件如下:文件名:filePath.properties内容:
mdFile.path = /root/blogfile/md
imgFile.path = /root/blogfile/fig
文件名:applicationContext.xml追加内容:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:filePath.properties</value>
</list>
</property>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
<property name="properties" ref="configProperties"/>
</bean>
至此,SpringMVC的上传文件以及后期的处理已经完成。