Spring Boot 底层级探索系列 04 - Web 开发(3)

简介: Spring Boot 底层级探索系列 04 - Web 开发(3)

江帅帅,奈学教育,擅长系统架构设计,大数据,运维等技术领域;对大中后台技术有丰富经验(交易平台、基础服务、智能客服、基础架构、智能运维、数据库、安全、IT 等方向);曾担任怀致科技 CTO,并还在东软集团、中国移动、多迪集团等企业中任职过相关技术负责人。

Spring Boot 文件的上传下载

说真的,在 Spring Boot 实现文件下载,真的是方便到让我颤抖。Java 中实现文件上传可以用两个组件:CommonMultipartResolver 和 StandardServletMultipartResolver。

Spring Boot 在 web 模块中集成了 Spring MVC ,文件上传这块儿的支持是可以通过即插即用的 MultipartResolver 实现类:CommonMultipartResolver。如果用它,则需要使用 commons-fileupload 组件来处理。

Spring Boot 提供的文件上传自动化配置类是 MultipartAutoConfiguration 中默认使用了 StandardServletMultipartResolver,在上传文件甚至能够做到零配置。

1. 单文件上传

1)添加 fileUpload.html 文件

在上传页面的表单中,添加一个 type 为 file 的控件,用来选择需要上传的图片文件。上传的接口是 “/upload”,另外 method 要设置为 “post”,还有 enctype 要设置为 “multipart/form-data”,代码具体如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upload</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
    <p><input type="file" name="upload" value="选一张图片"></p>
    <p><input type="submit" value="开始上传"></p>
</form>
</body>
</html>

2)添加 FileUploadController 文件

首先,设置我们的文件上传路径为项目运行目录下的 upload 文件夹。然后,我们用 MultipartFile 来绑定上传的文件,使用 transferTo() 方法可以非常方便实现文件存储到磁盘当中。具体实现代码如下:

@PostMapping("/upload")
public String upload(HttpServletRequest req, MultipartFile uploadFile) {
    String path = req.getSession().getServletContext().getRealPath("/upload/");
    File folder = new File(path);
    if (!folder.isDirectory()) {
        folder.mkdirs();
    }
    String oName = uploadFile.getOriginalFilename();
    String nName = UUID.randomUUID().toString() + oName.substring(oName.lastIndexOf("."), oName.length());
    try {
        uploadFile.transferTo(new File(folder + File.separator + nName));
        String filePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + "/upload/" + nName;
        return "ok";
    } catch (IOException ex) {
        ex.printStackTrace();
    }
    return "error";
}

地址栏中,输入 http://localhost:8080/fileUpload.html 选择文件上传,具体运行效果如下:

2. 采用对象方式来上传文件

很多时候的上传操作,也都会把文件作为对象的属性进行保存,具体如何实现?下面通过注册页面,填写用户的相关信息,然后点击注册来上传 User 对象。

1)添加 fileUpload2.html 文件

通过一个表单,来收集用户的具体信息,然后点击“注册用户”按钮即可提交 /register 注册请求。代码具体如下:

<body>
    <form action="/register" method="post" enctype="multipart/form-data">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p>头像:<input type="file" name="pic"></p>
        <p><input type="submit" value="注册用户"></p>
    </form>
</body>

2)添加 User 类

User 类主要是用来封装用户信息的,其中 MultipartFile 类型的 pic 是用来接收上传的图像文件。

public class User {
    private String username;
    private String password;
    private MultipartFile pic;
    // getter 和 setter 方法
}

3)添加 userRegister() 方法

在 userRegister() 方法形参列表中,使用 @ModelAttribute 注解将表单提交的数据绑定到 User 对象中,其中图片会保存到 User 的 pic 属性中,然后转换为 Multipart 类型。文件上传成功之后,所有的用户信息都保存到 model 当中。

@Controller
public class FileUploadController {
    @PostMapping("/register")
    public String userRegister(HttpServletRequest req, @ModelAttribute User user, Model model) throws Exception {
        if (!user.getPic().isEmpty()) {
            String picPath = req.getServletContext().getRealPath("/upload/");
            String picName = user.getPic().getOriginalFilename();
            File filePath = new File(picPath, picName);
            if (!filePath.getParentFile().exists()){
                filePath.getParentFile().mkdirs();
            }
            user.getPic().transferTo(new File(picPath + File.separator + picName));
            model.addAttribute("user", user);
            return "userMsg";
        } else {
            return "error";
        }
    }
}

3)在 templates 目录中,添加 userMsg.html 文件

<body>
    <table>
        <tr>
            <td><img th:src="@{'upload/'+${user.pic.originalFilename}}" height="100"/></td>
            <td th:text="${user.username}">用户名</td>
        </tr>
    </table>
</body>

运行效果,具体如下:

3. 多文件上传

1)添加 fileUpload2.html 页面
<form action="/uploadFiles" method="post" enctype="multipart/form-data">
    <p>选第一张图片:<input type="file" name="uploadFiles"></p>
    <p>选第二张图片:<input type="file" name="uploadFiles"></p>
    <p>选第三张图片:<input type="file" name="uploadFiles"></p>
    <p><input type="submit" value="开始上传"></p>
</form>
</body>
2)添加 uploadFiles() 方法
@PostMapping("/uploadFiles")
public String uploadFiles(MultipartFile[] uploadFiles, HttpServletRequest req) {
    String path = req.getSession().getServletContext().getRealPath("/upload/");
    File folder = new File(path);
    if (!folder.isDirectory()) {
        folder.mkdirs();
    }
    if (null != uploadFiles && uploadFiles.length > 0) {
        for (MultipartFile uploadFile : uploadFiles) {
            String oName = uploadFile.getOriginalFilename();
            String nName = UUID.randomUUID().toString() + oName.substring(oName.lastIndexOf("."), oName.length());
            try {
                uploadFile.transferTo(new File(folder, nName));
                return "ok";
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    return "error";
}

运行结果,具体如下:

4. 文件下载

1)编辑 userMsg.html 页面
<table>
    <tr>
        <td><img th:src="@{'upload/'+${user.pic.originalFilename}}" height="100"/></td>
        <td th:text="${user.username}">用户名</td>
        <td><a th:href="@{download(pic=${user.pic.originalFilename })}">下载头像</a></td>
    </tr>
</table>
2)添加 downloadPic() 方法

这里使用了 ResponseEntity 类型,就能定义返回的 HttpHeaders、BodyBuilder 和 HttpStatus,然后返回客户端下载。

@RequestMapping(value="/download")
public ResponseEntity<byte[]> downloadPic(HttpServletRequest request, @RequestParam("pic") String filename, @RequestHeader("User-Agent") String userAgent, Model model)throws Exception{
    String path = request.getServletContext().getRealPath(
        "/upload/");
    File file = new File(path + File.separator + filename);
    BodyBuilder builder = ResponseEntity.ok();
    builder.contentLength(file.length());
    // 二进制流数据
    builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
    
    // 解码
    filename = URLEncoder.encode(filename, "UTF-8");
    if (userAgent.indexOf("MSIE") > 0) {
        // IE
        builder.header("Content-Disposition", "attachment; filename=" + filename);
    } else {
        // FireFox、Chrome
        builder.header("Content-Disposition", "attachment; filename*=UTF-8''" + filename);
    }
    return builder.body(FileUtils.readFileToByteArray(file));
}

运行效果,具体如下:

目录
相关文章
|
24天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
45 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
8天前
|
XML JSON Java
Spring Boot 开发中常见的错误
本文总结了 Java 开发中常见的几个问题及其改进方法,包括:1. 过度使用 `@Component` 注解;2. `@ResponseBody` 注解的错误用法;3. `@Autowired` 的不当使用;4. `application.properties` 管理不善;5. 异常处理不当。每部分详细解释了错误情况和建议的改进方案,并提供了相应的代码示例。
38 11
|
1天前
|
人工智能 前端开发 Java
Spring AI Alibaba + 通义千问,开发AI应用如此简单!!!
本文介绍了如何使用Spring AI Alibaba开发一个简单的AI对话应用。通过引入`spring-ai-alibaba-starter`依赖和配置API密钥,结合Spring Boot项目,只需几行代码即可实现与AI模型的交互。具体步骤包括创建Spring Boot项目、编写Controller处理对话请求以及前端页面展示对话内容。此外,文章还介绍了如何通过添加对话记忆功能,使AI能够理解上下文并进行连贯对话。最后,总结了Spring AI为Java开发者带来的便利,简化了AI应用的开发流程。
60 0
|
8天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
25 5
|
6天前
|
前端开发 Java 开发者
这款免费 IDEA 插件让你开发 Spring 程序更简单
Feign-Helper 是一款支持 Spring 框架的 IDEA 免费插件,提供 URL 快速搜索、Spring Web Controller 路径一键复制及 Feign 与 Controller 接口互相导航等功能,极大提升了开发效率。
|
20天前
|
前端开发 安全 JavaScript
2025年,Web3开发学习路线全指南
本文提供了一条针对Dapp应用开发的学习路线,涵盖了Web3领域的重要技术栈,如区块链基础、以太坊技术、Solidity编程、智能合约开发及安全、web3.js和ethers.js库的使用、Truffle框架等。文章首先分析了国内区块链企业的技术需求,随后详细介绍了每个技术点的学习资源和方法,旨在帮助初学者系统地掌握Dapp开发所需的知识和技能。
2025年,Web3开发学习路线全指南
|
26天前
|
存储 前端开发 JavaScript
如何在项目中高效地进行 Web 组件化开发
高效地进行 Web 组件化开发需要从多个方面入手,通过明确目标、合理规划、规范开发、加强测试等一系列措施,实现组件的高效管理和利用,从而提高项目的整体开发效率和质量,为用户提供更好的体验。
30 7
|
26天前
|
前端开发 JavaScript Java
如何使用 Spring Boot 和 Angular 开发全栈应用程序:全面指南
如何使用 Spring Boot 和 Angular 开发全栈应用程序:全面指南
37 1
|
1月前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
1月前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
37 2