前言
在上一期的博客文章中我们了解学习到了有关SpringMVC框架实现模拟增删改查四大功能实现,今天给大家带来的是SpringMVC实现文件的上传下载功能实现模拟,让我们一起来一探究竟吧。
在Spring MVC中,文件上传下载是指通过web应用程序上传和下载文件。Spring MVC提供了一些便捷的方式来处理文件上传和下载的流程。在文件上传方面,可以MultipartFile对象来接收和处理客户端上传的文件。而在文件下载方面,可以使用Spring MVC的ResponseEntity和InputStreamResource等类来实现文件下载的功能。
要进行文件上传,可以通过在控制器方法的参数中声明MultipartFile类型的参数来接收上传的文件,然后通过MultipartFile对象的一些方法(如getOriginalFilename()、getSize()等)可以获取文件的原始名称和大小等信息。接收到文件后,可以将文件保存到指定的位置或进行进一步的处理。
一、文件上传
1. 配置多功能视图解析器(spring-mvc.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--1) 扫描com.zking.zf及子子孙孙包下的控制器(扫描范围过大,耗时)--> <context:component-scan base-package="com.yx"/> <!--2) 此标签默认注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter --> <mvc:annotation-driven /> <!--3) 创建ViewResolver视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- viewClass需要在pom中引入两个包:standard.jar and jstl.jar --> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!--4) 单独处理图片、样式、js等资源 --> <mvc:resources location="/static/" mapping="/static/**"/> <!-- 处理文件的上传下载的问题--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 必须和用户JSP 的pageEncoding属性一致,以便正确解析表单的内容 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 文件最大大小(字节) 1024*1024*50=50M--> <property name="maxUploadSize" value="52428800"></property> <!--resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常--> <property name="resolveLazily" value="true"/> </bean> <aop:aspectj-autoproxy/> </beans>
主要是添加下面这段代码
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 必须和用户JSP 的pageEncoding属性一致,以便正确解析表单的内容 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 文件最大大小(字节) 1024*1024*50=50M--> <property name="maxUploadSize" value="52428800"></property> <!--resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常--> <property name="resolveLazily" value="true"/> </bean>
在spring-mvc.xml文件添加之前,在pom.xml也要导入相关的依赖和插件。
2. 添加文件上传页面(upload.jsp)
upload.jsp
<%-- Created by IntelliJ IDEA. User: 86158 Date: 2023/9/9 Time: 16:08 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>班级logo上传</title> </head> <body> <form action="${pageContext.request.contextPath }/clz/upload" method="post" enctype="multipart/form-data"> <label>班级编号:</label><input type="text" name="cid" readonly="readonly" value="${param.cid}"/><br/> <label>班级图片:</label><input type="file" name="photo"/><br/> <input type="submit" value="上传图片"/> </form> </body> </html>
3.做硬盘网络路径映射
4. 编写一个处理页面跳转的类
PageController.java
package com.yx.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-10 17:03 * 处理页面跳转的 */ @Controller @RequestMapping("/page") public class PageController { @RequestMapping("/page/{page}") public String toPage(@PathVariable("page") String page){ return page; } @RequestMapping("/page/{dir}{page}") public String toDirPage(@PathVariable("dir") String dir, @PathVariable("page") String page){ return dir+"/"+page; } }
ClazzController.java
package com.yx.web; import com.yx.biz.ClazzBiz; import com.yx.model.Clazz; import com.yx.utils.PageBean; import com.yx.utils.PropertiesUtil; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; import java.util.List; /** * @author 君易--鑨 * @site www.yangxin.com * @company 木易 * @create 2023-09-09 15:25 */ @Controller @RequestMapping("/clz") public class ClazzController { @Autowired private ClazzBiz clazzBiz; // 增 @RequestMapping("/add") public String add(Clazz Clazz){ int i = clazzBiz.insertSelective(Clazz); return "redirect:list"; } // 删 @RequestMapping("/del/{mid}") public String del(@PathVariable("mid") Integer mid){ int i = clazzBiz.deleteByPrimaryKey(mid); return "redirect:list"; } // 改 @RequestMapping("/edit") public String del(Clazz Clazz){ int i = clazzBiz.updateByPrimaryKeySelective(Clazz); return "redirect:list"; } // 文件上传 @RequestMapping("/upload") public String upload(Clazz clazz,MultipartFile photo){ try { //上传的图片真实存放地址 String dir= PropertiesUtil.getValue("dir"); //网络服务器访问地址 String server=PropertiesUtil.getValue("server"); String filename = photo.getOriginalFilename(); System.out.println("文件名称:"+filename); System.out.println("文件类型:"+photo.getContentType()); FileUtils.copyInputStreamToFile(photo.getInputStream(),new File(dir+filename)); clazz.setPic(server+filename);//保存到数据库中 clazzBiz.updateByPrimaryKeySelective(clazz);//调用方法修改 } catch (IOException e) { e.printStackTrace(); } return "redirect:list"; } // 查 @RequestMapping("/list") public String list(Clazz Clazz, HttpServletRequest request){ // Clazz接口参数 PageBean pageBean=new PageBean(); pageBean.setRequest(request); List<Clazz> Clazzs = clazzBiz.ListPager(Clazz, pageBean); request.setAttribute("lst",Clazzs); request.setAttribute("pageBean",pageBean); //最终跳转到WEB-IEF/Clazz/list.jsp页面 return "clz/list"; } // 数据回显 @RequestMapping("/preSave") public String preSave(Clazz Clazz, Model model){ if (Clazz !=null && Clazz.getCid() !=null && Clazz.getCid() != 0){ Clazz c = clazzBiz.selectByPrimaryKey(Clazz.getCid()); model.addAttribute("c",c); } return "clz/edit"; } }
5. 初步模拟上传文件
这只是实现了将选中的文件下载到指定的文件夹中,在数据库中未进行修改数据。
6.配置目录的配置文件
resource.properties
dir=D:/photo/upload/ server=/upload/
7. 最终实现文件上传并显示
二、文件下载
方法代码
@RequestMapping(value="/download") public ResponseEntity<byte[]> download(Clazz clazz,HttpServletRequest req){ try { //先根据文件id查询对应图片信息 Clazz clz = this.clazzBiz.selectByPrimaryKey(clazz.getCid()); String diskPath = PropertiesUtil.getValue("dir"); String reqPath = PropertiesUtil.getValue("server"); String realPath = clz.getPic().replace(reqPath,diskPath); String fileName = realPath.substring(realPath.lastIndexOf("/")+1); //下载关键代码 File file=new File(realPath); HttpHeaders headers = new HttpHeaders();//http头信息 String downloadFileName = new String(fileName.getBytes("UTF-8"),"iso-8859-1");//设置编码 headers.setContentDispositionFormData("attachment", downloadFileName); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); //MediaType:互联网媒介类型 contentType:具体请求中的媒体类型信息 return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.OK); }catch (Exception e){ e.printStackTrace(); } return null; }
将文件下载的代码添加到指定的Controller类中
jsp页面代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://jsp.veryedu.cn" prefix="z"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css" rel="stylesheet"> <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script> <title>班级列表</title> <style type="text/css"> .page-item input { padding: 0; width: 40px; height: 100%; text-align: center; margin: 0 6px; } .page-item input, .page-item b { line-height: 38px; float: left; font-weight: 400; } .page-item.go-input { margin: 0 10px; } </style> </head> <body> <form class="form-inline" action="${pageContext.request.contextPath }/clz/list" method="post"> <div class="form-group mb-2"> <input type="text" class="form-control-plaintext" name="cname" placeholder="请输入班级名称"> <!-- <input name="rows" value="20" type="hidden"> --> <!-- 不想分页 --> <%-- <input name="pagination" value="false" type="hidden">--%> </div> <button type="submit" class="btn btn-primary mb-2">查询</button> <a class="btn btn-primary mb-2" href="${pageContext.request.contextPath }/clz/preSave">新增</a> </form> <table class="table table-striped "> <thead> <tr> <th scope="col">班级ID</th> <th scope="col">班级名称</th> <th scope="col">教员</th> <th scope="col">图片</th> <th scope="col">操作</th> </tr> </thead> <tbody> <c:forEach var="b" items="${lst }"> <tr> <td>${b.cid }</td> <td>${b.cname }</td> <td>${b.cteacher }</td> <td> <img src="${b.pic}" style="height:100px;width: 60px; "> </td> <td> <a href="${pageContext.request.contextPath }/clz/preSave?cid=${b.cid}">修改</a> <a href="${pageContext.request.contextPath }/clz/del/${b.cid}">删除</a> <a href="${pageContext.request.contextPath }/page/clz/upload?cid=${b.cid}">图片上传</a> <a href="${pageContext.request.contextPath }/clz/download?cid=${b.cid}">图片下载</a> </td> </tr> </c:forEach> </tbody> </table> <!-- 这一行代码就相当于前面分页需求前端的几十行了 --> <z:page pageBean="${pageBean }"></z:page> </body> </html>
效果测试
三、多文件上传
jsp页面显示代码
<%-- Created by IntelliJ IDEA. User: 86158 Date: 2023/9/9 Time: 16:08 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>班级logo上传</title> </head> <body> <form action="${pageContext.request.contextPath }/clz/upload" method="post" enctype="multipart/form-data"> <label>班级编号:</label><input type="text" name="cid" readonly="readonly" value="${param.cid}"/><br/> <label>班级图片:</label><input type="file" name="photo"/><br/> <input type="submit" value="上传图片"/> </form> <p>多文件上传</p> <form method="post" action="${pageContext.request.contextPath }/clz/uploads" enctype="multipart/form-data"> <input type="file" name="files" multiple> <button type="submit">上传</button> </form> </body> </html>
多文件上传方法
@RequestMapping("/uploads") public String uploads(HttpServletRequest req, Clazz clazz, MultipartFile[] files){ try { StringBuffer sb = new StringBuffer(); for (MultipartFile cfile : files) { //思路: //1) 将上传图片保存到服务器中的指定位置 String dir = PropertiesUtil.getValue("dir"); String server = PropertiesUtil.getValue("server"); String filename = cfile.getOriginalFilename(); FileUtils.copyInputStreamToFile(cfile.getInputStream(),new File(dir+filename)); sb.append(filename).append(","); } System.out.println(sb.toString()); } catch (Exception e) { e.printStackTrace(); } return "redirect:list"; }
测试多文件上传
这是模拟多文件上传到本地路径,在本地路径的文件夹中会显示该图片。(未进行数据库操作),可根据自己的项目需求进行修改运用,例如在商品的多张图片、药品批量入库等等上。
四、扩展(jrebel插件运用)
安装插件
打开代理服务器
代理服务器放在上传资源中了。注意先启动代理服务器再运用jrebel实现项目运行。
jrebel启动项目
后续注意事项
本期博客分享到这,希望老铁能够三连一波。