文件上传是项目开发中最常见的功能。为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。
Spring MVC 为文件上传提供了直接的支持,这种支持是用即插即用的 MultipartResolver 实现的。Spring MVC 使用 Apache Commons FileUpload技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver 。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
一、简单文件上传和下载: 文件上传
1)pom.xml 导入依赖:
commons-fileupload
commons-fileupload
1.3.3
2)在springmvc.xml进行配置文件如下:
SpringMVC上下文中默认没有装配 MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置 MultipartResolver。
MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart() 方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller,在 MultipartResolver 接口中有如下方法:
10485760
3)编辑上传文件的jsp页面:method="post" enctype="multipart/form-data"
文件上传
文件说明:
附件:
4)编写Controller以及处理方法:测试ok
MultipartFile 封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。在 MultipartFile 接口中有如下方法:
- String getName(); // 获取参数的名称
- String getOriginalFilename(); // 获取文件的原名称
- String getContentType(); // 文件内容的类型
- boolean isEmpty(); // 文件是否为空
- long getSize(); // 文件大小
- byte[] getBytes(); // 将文件内容以字节数组的形式返回
- InputStream getInputStream(); // 将文件内容以输入流的形式返回
- void transferTo(File dest); // 将文件内容传输到指定文件中
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(String wjsm, @RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
System.out.println("文件说明:" + wjsm);
if(!file.isEmpty()) {
String path = request.getServletContext().getRealPath("/resource/uploadFile");
//获取上传文件的原名
String fileName = file.getOriginalFilename();
File desfile = new File(path,fileName);
if(!desfile.getParentFile().exists()) {
desfile.getParentFile().mkdirs();
}
file.transferTo(new File(path + File.separator + fileName));
}else {
System.out.println("文件为空!");
}
return "success";
}
文件下载
文件下载比较简单,可直接在页面给出一个超链接,该链接 href 属性为要下载文件的文件,download 属性可自定义修改下载的文件名。这样就实现文件下载了。
下载
但是如果该文件的文件名为中文文件名,在某些早起的浏览器上就会导致下载失败;如果使用最新的Firefox、Chrome、Opera、Safari则都可以正常下载文件名为中文的文件了。
SpringMVC提供了一个 ResponseEntity 类型,使用它可以很方便地定义返回的 HttpHeaders 和HttpStatus 。以下代码演示文件的下载功能:
@RequestMapping(value="/download")
public ResponseEntity download(HttpServletRequest request, @RequestParam("fileName") String fileName) throws Exception{
//下载文件路径
String path = request.getServletContext().getRealPath("/resource/uploadFile");
File file = new File(path + File.separator + fileName);
HttpHeaders headers = new HttpHeaders();
//下载显示的文件名,并解决中文名称乱码问题
String downloadFileName = new String(fileName.getBytes("UTF-8"),"iso-8859-1");
//通知浏览器以attachment(下载方式)打开
headers.setContentDispositionFormData("attachment", downloadFileName);
//applicatin/octet-stream: 二进制流数据(最常见的文件下载)
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
}
另外需要注意的一点:ajax请求无法响应下载功能,我们可构建表单进行提交,下面有使用到。
二、实际项目文件上传和下载:
数据表只保存路径文件和文件名, 上传与下载的文件都存放到约定好的本地磁盘的某个路径下。
tomcat 默认访问运行项目下的资源文件, 无法访问本地磁盘的文件,可通过在 server.xml 配置tomcat虚拟路径来读取。
页面这样访问即可
附件:${user.fjm }
文件上传
1)model:忽略校验:
public class User {
private int id;
@NotEmpty(message="用户名不能为空")
@Pattern(regexp="^\\w{6,18}$",message="用户名必须由6到18位的数字字母或者下划线组成")
private String username;
@NotNull
@Length(min=6,max=32,message="密码必须为6到32位的字符串")
private String password;
@Past
private Date birthday;
@NotNull(message="年龄不能为空")
@Max(value=100)
@Min(value=1)
private Integer age;
@DecimalMax(value="2.5")
@DecimalMin(value="1.0")
private Double height;
@Email
private String email;
@NotNull
private Department department;
private String fjm; //附件原名
private String fjpath; // 附近路径
... }
2)新增页面(表单添加附件上传功能):
新增用户
用户名:
用户密码:
email:
用户所属部门:
生日:
年龄:
身高:
附件:
3)controller 处理方法: 忽略校验, 实测ok
@RequestMapping(value="/add", method = RequestMethod.POST)
public String addfj(@Valid User user, BindingResult errors, Model model, @RequestParam("file") MultipartFile file, HttpServletRequest request) throws Exception {
String realpath = "D:\\JQ\\JQuploadfile\\attachments\\";
String savepath = "t_user";
String uploadfilepath = realpath + savepath;
//判断数据绑定结果 errors.getErrorCount()>0 也可以
if (errors.hasFieldErrors()) {
System.out.println("参数值不合法!");
// 获得所有的属性错误
List fieldErrors = errors.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
// 把错误信息存放在model对象中
model.addAttribute(fieldError.getField(), fieldError.getDefaultMessage());
System.out.println(fieldError.getField() + "===" + fieldError.getDefaultMessage());
model.addAttribute("departments", departmentService.getAllList());
return "user-add";
}
}
if(!file.isEmpty()) {
//获取上传文件的原名
String fileName = file.getOriginalFilename();
File desfile = new File(uploadfilepath,fileName);
if(!desfile.getParentFile().exists()) {
desfile.getParentFile().mkdirs();
}
file.transferTo(desfile);
user.setFjm(fileName);
user.setFjpath(savepath + File.separator + fileName); //保存文件路径
System.out.println(user);
}else {
System.out.println("文件为空!");
}
userService.add(user);
return "redirect: /sshweb/users";
}
文件下载
查看详情页面提供下载功能 :
1、超链接下载:简单方便
附件:${user.fjm }
2、SpringMVC下载:可构建表单进行提交
ajax请求无法响应下载功能因为response原因,一般请求浏览器是会处理服务器输出的response,例如生成png、文件下载等,然而ajax请求只是个“字符型”的请求,即请求的内容是以文本类型存放的。文件的下载是以二进制形式进行的,虽然可以读取到返回的response,但只是读取而已,是无法执行的,说白点就是js无法调用到浏览器的下载处理机制和程序。
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了。下表中列出了一些URL特殊符号及编码
十六进制值1.+URL 中+号表示空格%2B2.空格URL中的空格可以用+号或者编码%203./分隔目录和子目录%2F4.?分隔实际的 URL 和参数%3F5.%指定特殊字符%256.#表示书签%237.&URL 中指定的参数间的分隔符%268.=URL 中指定参数的值%3D解决的方法:
replace() 方法如果直接用str.replace("-","!")只会替换第一个匹配的字符. 而str.replace(/\-/g,"!")则可以替换掉全部匹配的字符(g为全局标志)。 replace()
js中替换字符变量如下:
data2=data2.replace(/\%/g,"%25"); data2=data2.replace(/\#/g,"%23"); data2=data2.replace(/\\{1}/g,"%2F");
代码中可以使用
URLEncoder.encode(url, "UTF-8");
1)jsp页面:method="post" enctype="multipart/form-data"
查看用户信息
用户编号:
用户名:
用户密码:
email:
用户所属部门:
生日:
年龄:
身高:
附件:${user.fjm }
$("#downloadfj").on("click",function(){
var _fjpath = $(this).attr("fjpath").replace(/\\{1}/g,"%2F");
var _url = $(this).attr("url") + "&fjpath=" + _fjpath;
$("#userShowForm").attr("action",_url).submit();
});
2)controller 处理方法: 实测ok
@RequestMapping(value="/download")
public ResponseEntity download(HttpServletRequest request, @RequestParam("fjm") String fjm, @RequestParam("fjpath") String fjpath) throws Exception{
String realpath = "D:\\JQ\\JQuploadfile\\attachments\\";
//下载的文件
String downloadpathfile = realpath + fjpath;
File file = new File(downloadpathfile);
HttpHeaders headers = new HttpHeaders();
//下载显示的文件名,并解决中文名称乱码问题
String downloadFileName = new String(fjm.getBytes("UTF-8"),"iso-8859-1");
//通知浏览器以attachment(下载方式)打开
headers.setContentDispositionFormData("attachment", downloadFileName);
//applicatin/octet-stream: 二进制流数据(最常见的文件下载)
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED);
}
数据库信息: