文件上传是项目开发中最常见的功能。为了能上传文件,必须将表单的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 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>
2)在springmvc.xml进行配置文件如下:
SpringMVC上下文中默认没有装配 MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置 MultipartResolver。
<!-- 配置文件上传的解析器:--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 上传文件大小上限,单位为字节(10MB) --> <property name="maxInMemorySize"> <value>10485760</value> </property> <!-- 上传文件大小上限,单位为字节(10MB) --> <property name="defaultEncoding" value="UTF-8"></property> </bean>
3)编辑上传文件的jsp页面:method="post" enctype="multipart/form-data"
<div> <h4>文件上传</h4> <form action="<%=path %>/upload" method="post" enctype="multipart/form-data"> 文件说明:<input type="text" name="wjsm" /><br/> 附件:<input type="file" name="file" /><br/> <input type="submit" value="提交" /> </form> </div>
4)编写Controller以及处理方法:测试ok
@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 属性可自定义修改下载的文件名。这样就实现文件下载了。
<a href="resource\uploadFile\t01cebc3fe2b30885fe.jpg" download="">下载</a>
但是如果该文件的文件名为中文文件名,在某些早起的浏览器上就会导致下载失败;如果使用最新的Firefox、Chrome、Opera、Safari则都可以正常下载文件名为中文的文件了。
SpringMVC提供了一个 ResponseEntity 类型,使用它可以很方便地定义返回的 HttpHeaders 和HttpStatus 。以下代码演示文件的下载功能:
@RequestMapping(value="/download") public ResponseEntity<byte[]> 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<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED); }
另外需要注意的一点:ajax请求无法响应下载功能,我们可构建表单进行提交,下面有使用到。
数据表只保存路径文件和文件名, 上传与下载的文件都存放到约定好的本地磁盘的某个路径下。
tomcat 默认访问运行项目下的资源文件, 无法访问本地磁盘的文件,可通过在 server.xml 配置tomcat虚拟路径来读取。
<!-- 增加的-path="/虚拟名" docBase="虚拟路径" --> <Context docBase="D:\JQ\JQuploadfile\attachments\" path="/DJQ" reloadable="true"/>
页面这样访问即可
附件:<a href="/DJQ/${user.fjpath }" download="">${user.fjm }</a> <br/>
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)新增页面(表单添加附件上传功能):
<h3>新增用户</h3> <form:form action="${pageContext.request.contextPath }/add" method="post" enctype="multipart/form-data" modelAttribute="user" > 用户名:<form:input path="username"/> <form:errors path="username"/> <br/> 用户密码:<form:input path="password"/> <form:errors path="password"/> <br/> email:<form:input path="email"/> <form:errors path="email"/><br/> 用户所属部门:<form:select path="department.id" itemValue="id" itemLabel="departmentname" items="${departments }"/> <br/> 生日:<form:input path="birthday"/> <form:errors path="birthday"/><br/> 年龄:<form:input path="age"/> <form:errors path="age"/><br/> 身高:<form:input path="height"/> <form:errors path="height"/><br/> 附件:<input type="file" name="file" /><br/> <input type="submit" value="保存"> <br/> </form:form>
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<FieldError> 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、超链接下载:简单方便
附件:<a href="/DJQ/${user.fjpath }" download="">${user.fjm }</a> <br/>
2、SpringMVC下载:可构建表单进行提交
ajax请求无法响应下载功能因为response原因,一般请求浏览器是会处理服务器输出的response,例如生成png、文件下载等,然而ajax请求只是个“字符型”的请求,即请求的内容是以文本类型存放的。文件的下载是以二进制形式进行的,虽然可以读取到返回的response,但只是读取而已,是无法执行的,说白点就是js无法调用到浏览器的下载处理机制和程序。
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了。下表中列出了一些URL特殊符号及编码
十六进制值 | |||
1. | + | URL 中+号表示空格 | %2B |
2. | 空格 | URL中的空格可以用+号或者编码 | %20 |
3. | / | 分隔目录和子目录 | %2F |
4. | ? | 分隔实际的 URL 和参数 | %3F |
5. | % | 指定特殊字符 | %25 |
6. | # | 表示书签 | %23 |
7. | & | URL 中指定的参数间的分隔符 | %26 |
8. | = | 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"
<h3>查看用户信息</h3> <form id="userShowForm" action="" method="post" enctype="multipart/form-data"> 用户编号:<input type="text" name="id" value="${user.id }"/> <br/> 用户名:<input type="text" name="username" value="${user.username }"/> <br/> 用户密码:<input type="text" name="password" value="${user.password }"/> <br/> email:<input type="text" name="email" value="${user.email }"/><br/> 用户所属部门:<input type="text" name="email" value="${user.department.departmentname }"/><br/> 生日:<input type="text" name="birthday" value="${user.birthday }"/> <br/> 年龄:<input type="text" name="age" value="${user.age }"/> <br/> 身高:<input type="text" name="height" value="${user.height }"/> <br/> <%-- 附件:<a href="/DJQ/${user.fjpath }" download="">${user.fjm }</a> <br/> --%> 附件:<a href="javascript: void(0)" id="downloadfj" url="<%=path%>/download?fjm=${user.fjm}" fjpath="${user.fjpath }">${user.fjm }</a> <br/> </form> <script type="text/javascript" src="${pageContext.request.contextPath }/static/js/jquery-3.3.1.min.js"></script> <script type="text/javascript"> $("#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(); }); </script>
2)controller 处理方法: 实测ok
@RequestMapping(value="/download") public ResponseEntity<byte[]> 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<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.CREATED); }
数据库信息: