在之前的文章中已经介绍过springMvc的文件上传,springMvc文件上传
场景介绍
在本篇博客中主要介绍使用springMvc进行图片的上传
功能需求:在很多网站中都有上传用户头像的功能,上传之后就会立刻在页面上显示出来,这边就是采用的异步的方式,并且在实际应用中最好有一个单独的服务器作为图片服务器,因为加载图片的时候通常会占据较大的带宽,与应用程序服务器放在一块的话,影响应用程序服务器的性能,在这里由于没有两台服务器,所以会在一台电脑上部署两个tomcat,这样当图片上传后,会先将图片通过jersey上传到另一台服务器下,然后将路径保存到数据库中
准备
在同一台电脑上部署两台tomcat
第一步 准备好tomcat压缩包,解压后,修改server.xml中的三个端口(不要与其他应用程序的端口号冲突,例如SVN的8443),这三个端口号默认是8005,8009,8080,将他们修改为别的
第二步 因为jersey是需要将图片写入到服务器中的,所以需要配置图片上传的tomcat允许用户用过post或者put向服务器写数据(默认是不允许的),配置方式如下
<!--tomcat中的web.xml,主要设置readOnly为false-->
<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>readonly</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
准备好jersey的jar包
使用springMvc上传图片
文件上传解析器的配置
与上传文件一样,需要配置一个文件上传的解析器,注意在配置的时候,图片解析器的id必须为multipartResolver
<!-- 配置图片上传的解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 单位是字节,这里设置成10MB,即1024*1024 -->
<property name="maxUploadSize" value="10485760"></property>
<property name="uploadTempDir" value="/WEB-INF/temp"></property>
</bean>
前端代码的编写
因为是图片上传,所以我们可以将input标签包裹在form表单里,然后使用ajax直接提交表单到后台,至于提交的其它的字段,我们可以在控制器里不管它们
注意
异步上传图片的时候,需要在用户点击选择—>打开文件后,就通过ajax将图片上传到服务器,所以需要监听input type=‘file’的一个事件,这个事件就是onchange
<form id="jvForm" action="/back/brand/add.do" method="post" enctype="multipart/form-data">
...
<tr>
<td width="20%" class="pn-flabel pn-flabel-h"></td>
<td width="80%" class="pn-fcontent">
<img width="100" height="100" id="allImgUrl"/>
<input type="hidden" name="imgUrl" id="imgUrl"/>
<input type="file" onchange="uploadPic()" name="pic"/>
</td>
</tr>
...
</form>
在上传文件后,我们将图片回显到页面上的img标签上,并且将返回过来的imgUrl设置到隐藏域中,因为当用户真正提交表单的时候,需要将图片的路径保存到数据库中,而当触发的onchange事件时,只会将图片上传到服务器,并将图片的路径返回过来,并不会保存到数据库,这就要求我们在提交的时候将imgUrl保存
<script type="text/javascript">
function uploadPic(){
$("#jvForm").ajaxSubmit({
url:"/back/uploadPic.do",
dataType:"json",
type:"post",
success:function(data){
$("#allImgUrl").attr("src",data.url);
$("#imgUrl").val(data.path);
}
});
}
</script>
控制器的编写
import org.apache.commons.io.FilenameUtils;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.Client;
@RequestMapping("/uploadPic.do")
public void uploadPic(MultipartFile pic, HttpServletResponse response) {
// 获取文件的相关信息
// 文件的名称,使用uuid
String fileName = UUID.randomUUID().toString().replace("-", "");
// 获取文件的扩展名
String ext = FilenameUtils.getExtension(pic.getOriginalFilename());
// 要上传的文件的url,将其回显到前台进行展示
// 将其回显到前端,在brand添加表单提交的时候,插入到数据库中
String path = "babasport_images/" + fileName + "." + ext;
//Constants.IMAGE_SERVER http://localhost:8088/
String url = Constants.IMAGE_SERVER + path;
Client client = new Client();
WebResource resource = client.resource(url);
try {
resource.put(pic.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
JSONObject jo = new JSONObject();
jo.put("url", url);
jo.put("path", path);
response.setContentType("application/json;charset=UTF-8");
try {
response.getWriter().write(jo.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
注意事项
1. 返回的时候,是返回的json,所以一定要设置contentType
2. 图片上传的前端必须要设置enctype=”multipart/form-data”,以及用post
一个常见异常的解决
Failed to parse multipart request
org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. 、\localhost \_ \upload__3d7cf8b_11936276cf8__7ffd_00000011.tmp
需要重新设置一下文件上传时,commons.fileupload将上传的文件以流的形式将文件写到一个临时文件夹中,现在这个文件找不到了
解决方法:自己设置临时文件夹,不用commons.fileupload默认的,在注入的时候注入uploadTempDir