Spring-MVC的文件上传下载,及插件的使用(让项目开发更节省时间)

2023-10-27

                                             

目录

一、概述

( 1 )  介绍

( 2 )  讲述

二、上传

三、下载

四、jrebel的使用

五、多文件上传

给我们带来什么收获


一、概述

( 1 )  介绍

Spring MVC的文件上传下载是指在Spring MVC框架中实现文件的上传和下载功能。文件上传是指将本地计算机上的文件上传到服务器端,而文件下载是指从服务器端将文件下载到本地计算机上。

Spring MVC提供了方便的机制来处理文件上传和下载。文件上传可以通过配置MultipartResolver Bean来处理上传请求,并使用@RequestParam注解来接收上传的文件。然后可以将文件保存到指定位置。

文件下载可以通过在Controller中返回ResponseEntity<byte[]>对象来表示要下载的文件。可以设置响应头信息,包括Content-Disposition和Content-Type,并将文件内容读取到字节数组中,最后将字节数组写入响应流中,完成文件下载。

文件上传下载在实际开发中非常常见,例如用户上传头像、上传文件等场景都需要使用文件上传功能。而文件下载可以用于提供用户下载文件、下载导出的报表等场景。

Spring MVC的文件上传下载功能可以方便地与其他Spring MVC特性结合使用,例如数据绑定、表单验证等,从而实现更复杂的业务需求。同时,Spring MVC还提供了一些工具类和注解来简化文件上传下载的操作,使开发更加便捷。

( 2 )  讲述

使用Spring MVC进行文件上传和下载需要以下步骤:

文件上传:

  • 1. 首先,在Spring MVC的配置文件中配置MultipartResolver Bean。可以使用CommonsMultipartResolver或者StandardServletMultipartResolver。
  • 2. 在Controller中,创建一个方法来处理文件上传请求。可以使用@RequestParam注解来接收上传的文件。例如,可以使用MultipartFile类型的参数来接收上传的文件。
  • 3. 在方法中,可以使用MultipartFile对象的transferTo()方法将文件保存到指定的位置。可以使用File对象或者路径字符串作为参数。

文件下载:

  • 1. 配置MultipartResolver Bean: 在Spring MVC的配置文件中,需要配置一个MultipartResolver Bean来处理文件上传请求。可以使用CommonsMultipartResolver或者StandardServletMultipartResolver。这两个Resolver都是Spring MVC提供的默认实现,可以根据项目需求选择其中一个。
  • 2. 创建文件上传表单: 在前端页面中,创建一个表单用于文件上传。设置表单的enctype属性为"multipart/form-data",以支持文件上传。
  • 3. 创建Controller方法: 在Controller中,创建一个方法来处理文件上传请求。可以使用@RequestParam注解来接收上传的文件。例如,可以使用MultipartFile类型的参数来接收上传的文件。
  • 4. 处理文件上传结果: 根据具体需求,可以在文件上传成功或失败后,返回不同的视图或进行其他操作。

以上是使用Spring MVC进行文件上传的基本步骤。需要注意的是,文件上传的大小限制、文件类型限制等可以通过配置MultipartResolver Bean来进行设置。此外,还可以使用其他第三方库来实现更复杂的文件上传功能,例如Apache Commons FileUpload。 

需要注意的是,文件上传和下载的功能可以根据具体的需求进行调整和扩展。可以通过其他第三方库来实现更复杂的文件上传和下载操作,例如Apache Commons FileUpload和Apache HttpClient等。

另外,还可以使用Spring MVC提供的其他功能来增强文件上传下载的功能,例如数据校验、异常处理等。这样可以更好地满足实际项目的需求。

二、上传

以下实例演示的代码是基于本人博客中的代码进行扩展 : SpringMVC的整合完成CRUD

首先我们需要在数据库中的数据表( 酒店表[ t_hotel ] )进行增加一个字段来存放图片路径

我这里的属性名为 himage 数据表的字段如图  : 

将自动生成的mapper和model包删除,进行重新生成接口,实体及配置文件,将我们新增的

字段进行自动增加进来,并且重新写模糊查询的配置动态SQL。

写在自动生成的HotelMapper.xml配置文件中

  <select id="selectHotelPage" resultType="com.CloudJun.model.Hotel" parameterType="com.CloudJun.model.Hotel" >
    select  * from t_hotel
    <where>
      <if test="hname != null">
        and hname like concat('%',#{hname},'%')
      </if>
    </where>
  </select>

在自动生成的接口 HotelMapper 中增加以下代码

List<Hotel> selectHotelPage(Hotel hotel);

创建一个公共路径处理类  名为 : PageController

 

package com.CloudJun.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * @author CloudJun
 * @create  2023-09-07 14:39
 */
    @Controller
    public class PageController {

        @RequestMapping("/page/{page}")
        public String to(@PathVariable("page") String page){
            return page;
        }
        @RequestMapping("/page/{dir}/{page}")
        public String to(@PathVariable("dir") String dir,
                         @PathVariable("page") String page){
            return dir+"/"+page;
        }

}

将前端的 index.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 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<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 }/hot/list" method="post">
    <div class="form-group mb-2">
        <input type="text" class="form-control-plaintext" name="hname"
               placeholder="请输入书籍名称">
<%--        <input name="rows" value="10" 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 }/hot/revise">新增</a>
</form>

<table class="table table-striped">
    <thead>
    <tr>
        <th scope="col">房间编号</th>
        <th scope="col">房间名称</th>
        <th scope="col">房间类型</th>
        <th scope="col">房间图片</th>
        <th scope="col">操作</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach  var="h" items="${list }">
        <tr>
            <td>${h.hid }</td>
            <td>${h.hname }</td>
            <td>
                <img src="${h.himage }"style="height: 100px;width: 100px;">
            </td>
            <td>${h.htype }</td>
            <td>
                <a href="${pageContext.request.contextPath }/hot/revise?hid=${h.hid}">修改</a>
                <a href="${pageContext.request.contextPath }/hot/del?hid=${h.hid}">删除</a>
                <a href="${pageContext.request.contextPath }/page/hot/upload?hid=${h.hid}">图片上传</a>
                <a href="${pageContext.request.contextPath }/hot/download?hid=${h.hid}">图片下载</a>
            </td>
        </tr>
    </c:forEach>
    </tbody>
</table>
<!-- 这一行代码就相当于前面分页需求前端的几十行了 -->
<z:page pageBean="${pageBean }"></z:page>

</body>
</html>

HotelController 控制器中增加文件上传的方法路径进行配置

    //文件上传
    @RequestMapping("/upload")
    public String uploadFile(Hotel hotel,MultipartFile multipartFile) throws Exception {
        //文件上传的本地存放地址
        String dir= PropertiesUtil.getValue("dir");
        //网络访问地址(请求)
        String server = PropertiesUtil.getValue("server");
        String filename = multipartFile.getOriginalFilename();
        FileUtils.copyInputStreamToFile(multipartFile.getInputStream(),new File(dir+filename));
        hotel.setHimage(server+filename);
        hotelbiz.updateByPrimaryKeySelective(hotel);
        return "redirect:list";
    }

创建一个名为 upload.jsp 的页面进行显示操作

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/hot/upload" method="post" enctype="multipart/form-data">
    <label>班级编号:</label><input type="text" name="hid" readonly="readonly" value="${param.hid}"/><br/>
    <label>班级图片:</label><input type="file" name="multipartFile"/><br/>
    <input type="submit" value="上传图片"/>
</form>

<form method="post" action="${pageContext.request.contextPath }/hot/uploads" enctype="multipart/form-data">
    <input type="file" name="files" multiple>
    <button type="submit">上传</button>
</form>

</body>
</html>

创建一个名为 resource.properties 的资源文件

dir=D:/temp/upload/
server=/upload/

创建工具类 PropertiesUtil 

package com.CloudJun.utils;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesUtil {
	public static String getValue(String key) throws IOException {
		Properties p = new Properties();
		InputStream in = PropertiesUtil.class.getResourceAsStream("/resource.properties");
		p.load(in);
		return p.getProperty(key);
	}
	
}

然后启动服务器,访问浏览器路径 ( 根据自己的配置及控制器进行填入访问路径 )

访问该路径进行测试  :  http://localhost:8080/ssm/hot/list

结果如下 : 

三、下载

需要在 HotelController  控制器中增加文件下载的方法路径进行配置

    //文件下载
    @RequestMapping("/download")
    public ResponseEntity<byte[]> download(Hotel hotel, HttpServletRequest req){
        try {
            //先根据文件id查询对应图片信息
            Hotel hot = hotelbiz.selectByPrimaryKey(hotel.getHid());
            String diskPath = PropertiesUtil.getValue("dir");
            String reqPath = PropertiesUtil.getValue("server");
            String realPath = hot.getHimage().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;
    }

之后可以直接开启服务器,在浏览器中进行测试

结果如下 : 

四、jrebel的使用

根据图中操作,安装jrebel插件

然后下载该文件,进行jrebel的使用    :   jrebel插件的辅助使用 

如果觉得下载或者使用插件麻烦,也可以使用idea的自带Debug

(也可以进行项目启动,只是比较影响开发效率)

重新开启idea时会有如图上两个图标,已是启动服务器的图标(这是jrebel的使用)

 

打开下载的辅助插件的使用,会有一个黑窗口,有黑窗口后才可以进行jrebel那个两图标使用

之后会出现以下窗口,第一行输入 : http://127.0.0.1:8888/0e63ac70-2074-46d3-9de1-46fb2befde0a

第二行之后的操作如图 : 

服务器成功启动后,在去设置里面进行离线模式的操作设置

此设置完是之后使用jrebel时可以不需要开启哪个辅助应用工具了(黑窗口)

JRebel是一个Java开发工具,它可以实现在不重启应用服务器的情况下,实时更新Java代码的功能。以下是JRebel插件的一些好处:

  • 1. 提高开发效率:使用JRebel可以避免频繁的应用服务器重启,节省了开发人员的时间。每次修改Java代码后,只需要重新加载相关的类,即可立即看到代码变更的效果,无需重新启动整个应用。
  • 2. 加快开发周期:应用服务器的启动通常需要一定的时间,而使用JRebel可以减少这个等待时间,从而加快了开发周期。开发人员可以更快地进行代码调试和测试,提高了开发效率。
  • 3. 提供更好的调试体验:JRebel可以在不重启应用服务器的情况下,实时更新代码,从而提供了更好的调试体验。开发人员可以在调试过程中随时修改代码,查看变更的效果,快速定位和解决问题。
  • 4. 支持多种框架和应用服务器:JRebel支持多种Java框架和应用服务器,包括Spring、Hibernate、Java EE等。无论是开发Web应用、企业应用还是移动应用,都可以使用JRebel进行实时代码更新。
  • 5. 减少开发错误:由于JRebel可以实时更新代码,开发人员可以立即看到代码变更的效果,从而更容易发现和修复潜在的错误。这有助于提高代码质量和减少开发错误。

总的来说,JRebel插件可以提高Java开发的效率和质量,减少应用服务器重启的时间,提供更好的调试体验,从而加快开发周期。它是一个非常有用的工具,特别适合需要频繁修改和调试Java代码的开发人员。

五、多文件上传

需要在 HotelController  控制器中增加文件多文件上传的方法路径进行配置

 //多文件上传
    @RequestMapping("/uploads")
    public String uploads(HttpServletRequest req, Hotel hotel, 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";
    }

增加完后,开启服务器进行浏览器的测试即可

测试结果: 

给我们带来什么收获

学习Spring MVC的文件上传下载可以给我们带来以下收获:

  • 1. 实现文件上传和下载功能:学习Spring MVC的文件上传下载,可以掌握如何在Web应用中实现文件的上传和下载功能。这对于很多应用来说是必需的,比如用户上传头像、上传附件等。
  • 2. 提高用户体验:通过文件上传下载功能,可以提高用户的体验。用户可以方便地上传和下载文件,无需通过其他繁琐的方式来实现。这可以增加用户对应用的满意度和使用度。
  • 3. 增加应用的功能和价值:通过文件上传下载功能,可以为应用增加更多的功能和价值。比如,可以实现用户之间的文件共享、文件的备份和恢复等功能,从而提升应用的实用性和吸引力。
  • 4. 拓展自己的技术能力:学习Spring MVC的文件上传下载,可以拓展自己的技术能力。这涉及到文件处理、网络通信、安全性等方面的知识,可以帮助我们更全面地理解和应用Web开发相关的技术。
  • 5. 掌握常用的文件处理技术:学习Spring MVC的文件上传下载,可以掌握一些常用的文件处理技术。比如,文件的读写、文件的压缩和解压、文件的加密和解密等。这些技术在实际开发中经常会用到,可以提高我们的工作效率。

总的来说,学习Spring MVC的文件上传下载可以带来很多收获,包括实现文件上传下载功能、提高用户体验、增加应用的功能和价值、拓展自己的技术能力以及掌握常用的文件处理技术。这对于Web开发人员来说是非常有价值的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring-MVC的文件上传下载,及插件的使用(让项目开发更节省时间) 的相关文章

  • Java 弱哈希映射 - 需要根据值的弱点而不是键来删除条目

    所以JavaWeakHashMap让我们创建一个映射 如果其键变弱 则删除该映射的条目 但是我怎样才能创建一个Map 当它的条目被删除时values地图上变弱了 我想使用映射的原因是作为全局哈希表 它根据对象的 ID 跟踪对象 ID gt
  • 如何用Java创建图像

    比如说在我的程序中 我有这个paint 方法 我的愿望是创建所绘制的矩形的图像 使用 for 循环 我尝试了下面的方法 它确实给了我那些矩形 蓝色 但背景是全黑的 当我运行程序而不创建图像 仅在 JFrame 上绘制矩形时 背景为白色 我怎
  • 使用 Gson 序列化时如何公开类名

    我的场景非常复杂 但总结如下 我试图了解编译器的源代码 并了解每个 AST 节点代表什么 我正在生成不同程序的 AST 的 JSON 序列化 然后检查可视化的 JSON 输出 它工作得很好 除了一个问题是在 Gson 中生成的 JSON 数
  • CSS 未在 Spring Boot 中加载

    我是 spring 框架工作和 spring boot 的新手 我正在尝试使用 CSS javascript js 添加静态 html 文件 文件结构是 我的 html 文件头看起来像这样
  • GSON:自定义对象反序列化

    好吧 我编辑了这个问题 因为它不够清楚 Edit 2 更新了 JSON 文件 我在 Android 应用程序中使用 GSON 我需要解析来自服务器的 JSON 文件 而且有点太复杂了 我不想让我的对象结构太重 所以我想简化内容 所以我的对象
  • 在 JSP 中对表单操作使用相对路径

    如何在表单操作中使用相对路径
  • (Java) 在 Mac OS X 上以编程方式访问“系统根目录”下的 SSL 证书

    我正在编写一个 Java 应用程序 它可以通过远程 Https 站点进行 REST Api 调用 远程站点由受信任的证书签名 它在 Windows 上运行良好 但由于 SSL 证书问题 在 OS X 上运行时遇到问题 我做了一些挖掘 发现原
  • Java - 同步方法导致程序大幅减慢

    我正在尝试了解线程和同步 我做了这个测试程序 public class Test static List
  • 从 org.w3c.dom.Node 获取 Xpath

    我可以从 org w3c dom Node 获取完整的 xpath 吗 假设当前节点指向 xml 文档中间的某个位置 我想提取该元素的 xpath 我正在寻找的输出 xpath 是 parent child1 chiild2 child3
  • 在 javafx 中注册鼠标处理程序,但处理程序不是内联的

    我有一个 JavaFX 应用程序变得有点大 我想保持代码的可读性 我有一个折线图 我希望内置缩放功能 该功能在单击鼠标时发生 我知道我需要向图表注册鼠标侦听器 我无法从 Oracle 示例中弄清楚什么 即如下所示 http docs ora
  • 在 Spring Security SAML 身份验证请求中配置 POST ProtocolBinding

    Spring Security SAML 坚持在 SAML 身份验证请求中请求 Artifact 绑定 ProtocolBinding 属性
  • Java 中意外的负数

    import java util public class Prac9FibonacciNumbers public static void main String args int x new int 100 x 0 1 x 1 1 fo
  • 使用antlr4获取预处理器行并解析C代码

    我正在使用 Antlr4 来解析 C 代码 并使用以下语法来解析 链接到 C g4 https github com antlr grammars v4 blob master c C g4 上面的语法默认不提供任何解析规则来获取预处理器语
  • WebSocketStompClient 将无法连接到 SockJS 端点

    我正在尝试新的 从版本 4 2 开始 java STOMP 客户端支持 我的出发点是入门指南 使用 WebSocket 构建交互式 Web 应用程序 http spring io guides gs messaging stomp webs
  • Spring Boot如何加入自定义查询

    我需要创建一个端点 该端点按州返回人口普查数据以及城市列表 我目前使用两个端点来获取此数据 目前回应 自定义查询一 censusByState id 1 code 11 name Rond nia statePopulation 18152
  • 相当于 C# 中 Java 的“ByteBuffer.putType()”

    我正在尝试通过从 Java 移植代码来格式化 C 中的字节数组 在 Java 中 使用方法 buf putInt value buf putShort buf putDouble 等等 但我不知道如何将其移植到 C 我尝试过 MemoryS
  • 如何使用 Spring Resource.groovy 正确注入 Grails 服务

    使用 Grails 2 2 1 我定义了以下 Grails 服务 package poc class TestService def helperService class HelperService 我已经用过TestService如下
  • RecyclerView 适配器的 Kotlin 泛型

    我正在尝试编写一个通用的 recyclerview 适配器 我找到了几个例子 然而 仍然无法弄清楚如何实现通用适配器 我写的代码是 open abstract class BaseAdapter
  • javafx中的stackpane和root有什么区别?

    我正在练习javafx做饼图 以下是开发饼图的代码 如果我这样做Group并与StackPane 我发现输出没有区别 我已经评论了组部分 只是徘徊两者之间的区别 import javafx application Application i
  • 按字母顺序对对象的 ArrayList 进行排序

    我必须创建一个方法来排序数组列表根据电子邮件按字母顺序排列对象 然后打印排序后的数组 我在排序时遇到麻烦的部分 我已经研究过并尝试使用Collections sort vehiclearray 但这对我不起作用 我是因为我需要一个叫做比较器

随机推荐