利用后端的SpringBoot框架和前端的React框架实现一个文件上传的小项目,对目前的学习做一个总结。
环境搭建
我们先分别搭建前后端的项目环境,然后进行项目开发。
前端环境搭建
前端开发需要一些基本的HTML, CSS和Javscript的背景知识。
我们直接使用成前端比较热门的React框架进行网页搭建,还有一个热门框架是Vue。
先安装NODE环境,在https://nodejs.org/en/下载长期支持版,安装之后,在命令行输入node -v 确定版本。
编程环境选择VSCode,同时安装了几个插件:
- IntelliJ IDEA Keybindings
- Prettier
- Prettier ESlint
之后,我们使用umi作为项目的脚手架,搭建项目
1 2 3 4 5 6
| mkdir file_upload_frontend && cd file_upload_frontend pnpm dlx create-umi@latest
pnpm i antd @ant-design/icons
|
安装结束后,启动项目,访问Network里的地址,就确定项目是跑上了。
1 2 3 4 5 6 7 8 9 10 11
| pnpm dev .... ╔════════════════════════════════════════════════════╗ ║ App listening at: ║ ║ > Local: http://localhost:8000 ║ ready - ║ > Network: http://192.168.50.97:8000 ║ ║ ║ ║ Now you can open browser with the above addresses↑ ║ ╚════════════════════════════════════════════════════╝ ...
|
网页显示如下
后端环境搭建
后端使用Java SpringBoot实现RESTful的接口开发。(这里的背景知识要求比较多,Java的面向对象编程,反射,注解,Spring框架,SpringMVC框架)
首先,到https://www.jetbrains.com/idea/download/里下载一个社区版的IntelliJ IDEA。相比于商业版,社区办缺少了Spring初始化、SQL数据库连接、HTTP客户端等功能,但是也是能用。
接着,在https://start.spring.io中创建一个SpringBoot项目,配置如下
得到一个fileupload.zip文件,解压缩后就得到了我们项目的基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| fileupload ├── HELP.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main │ ├── java │ │ └── top │ │ └── xuzhougeng │ │ └── fileupload │ │ └── FileuploadApplication.java │ └── resources │ ├── application.properties │ ├── static │ └── templates └── test └── java └── top └── xuzhougeng └── fileupload └── FileuploadApplicationTests.java
|
利用IDEA打开这个项目,把resources下的application.properties改成application.yaml,编辑内容如下
然后点击IDEA的运行键,如果能正常访问localhost:8070就意味着后端环境配置成功
代码编写
前端基础代码
前端的工作非常简单,只需要去Ant Design的官方找一个合适的模版。
打开https://ant-design.gitee.io/components/overview-cn/,找到Upload上传组件块,选择一个顺眼的,复制它的代码
之后在项目中建立一个src/pages/upload.tsx文件,把代码粘贴进去
修改 .umirc.tsx 中的路由配置
TSX1 2 3 4 5 6 7 8 9 10 11
| import { defineConfig } from "umi";
export default defineConfig({ routes: [ { path: "/", component: "index" }, { path: "/docs", component: "docs" }, { path: "/upload", component: "upload"} ], npmClient: 'pnpm', });
|
打开http://localhost:8000/upload 如果看到里面内容跟复制的内容一样,就算成功。
接下来,编辑upload.tsx文件,做一些基本的修改
TSX1 2
| multiple: false, //只允许传一个文件 action: 'http://localhost:8070/files', //设置上传的站点
|
multiple设置为false,用于限制单次上传的文件数,action设置上传的目标地址。
这样子,前端就算完工了。
后端代码
后端文件上传代码参考https://www.bezkoder.com/spring-boot-file-upload/
首先,我们写服务层的代码,实现两个功能
- 初始化文件上传后存放的目录
- 保存文件
在top.xuzhougeng.fileupload建立一个软件包, service。
然后在service中创建一个接口FileStorageService,里面就定义两个接口函数
1 2 3 4 5 6 7 8 9 10
| package top.xuzhougeng.fileupload.service; import org.springframework.web.multipart.MultipartFile;
public interface FileStorageService {
public void init(); public void save(MultipartFile file); }
|
通过在FileStorageService上用快捷键option + enter,实现接口。
实现类存放在service的impl目录下
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package top.xuzhougeng.fileupload.service.impl;
import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import top.xuzhougeng.fileupload.service.FileStorageService;
import java.io.IOException; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths;
@Service public class FileStorageServiceImpl implements FileStorageService {
private final Path root = Paths.get("uploads"); @Override public void init() { try { Files.createDirectories(root); } catch (IOException e){ throw new RuntimeException("无法初始化upload的上传目录"); }
}
@Override public void save(MultipartFile file) { try { Files.copy(file.getInputStream(), this.root.resolve(file.getOriginalFilename())); } catch (Exception e){ if (e instanceof FileAlreadyExistsException){ throw new RuntimeException("文件已存在"); }
throw new RuntimeException(e.getMessage()); } } }
|
初始化init调用Files模块创建文件夹。save函数的参数类型为MultipartFile,是SpringMVC用来简化文件上传操作的工作类。通过调用Files模块,将上传的文件流复制到指定的目录下。
服务层搞定之后,就是控制层,创建一个软件包controller,并在目录下建立一个FileController类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package top.xuzhougeng.fileupload.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import top.xuzhougeng.fileupload.service.FileStorageService;
@RestController @CrossOrigin(value = {"http://192.168.50.97:8000"}) public class FileController {
private FileStorageService fileStorageService; @Autowired public void setFileStorageService(FileStorageService fileStorageService) { this.fileStorageService = fileStorageService; }
@PostMapping("/files") public String fileSave(@RequestParam("file") MultipartFile file){ System.out.println("loading file"); try { fileStorageService.save(file); return "Upload successfully"; } catch (Exception e){ return "Upload failed"; }
} }
|
它的功能非常简单,就是相应POST请求,然后调用服务层的fileStorageService的save方法进行文件保存。
最后还需要修改启动函数,使其实现CommandLineRunner,覆写他的 run方法,使其在运行前调用FileStorageService的init方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @SpringBootApplication public class FileuploadApplication implements CommandLineRunner {
@Resource private FileStorageService fileStorageService;
@Override public void run(String... args) throws Exception { fileStorageService.init(); }
public static void main(String[] args) { SpringApplication.run(FileuploadApplication.class, args); }
}
|
最后启动后端,测试下文件上传。