【SpringBoot】18 上传文件到数据库(Thymeleaf + MySQL)
Git仓库
https://gitee.com/Lin_DH/system
介绍
使用 Thymeleaf 写的页面,将(txt、jpg、png)格式文件上传到 MySQL 数据库中。
依赖
pom.xml
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
数据库配置
application.yml
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/system?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: root
mybatis-plus:
type-aliases-package: com.lm.system.common
mapper-locations: classpath:com.lm.system/mapper/*Mapper.xml
check-config-location: true
configuration:
#日志实现,不配置不会输出SQL日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
SQL
t_file.sql
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50734
Source Host : localhost:3306
Source Schema : system
Target Server Type : MySQL
Target Server Version : 50734
File Encoding : 65001
Date: 18/10/2024 15:14:51
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_file
-- ----------------------------
DROP TABLE IF EXISTS `t_file`;
CREATE TABLE `t_file` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`format` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`data` longblob NOT NULL,
`size` double NOT NULL,
`create_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
实现代码
第一步:编写上传页面
uploadToBD.html
<!DOCTYPE html>
<html lang="en">
<head lang="en">
<meta charset="UTF-8" />
<title>文件上传到数据库页面</title>
</head>
<body>
<h1>文件上传到数据库页面</h1>
<form method="post" action="/uploadToDB" enctype="multipart/form-data">
请选择要上传的txt/jpeg/png格式文件:<input type="file" name="file"><br>
<hr>
<input type="submit" value="提交">
</form>
</body>
</html>
第二步:编写文件实体类
SysFile.java
package com.lm.system.common;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author DUHAOLIN
* @date 2024/10/17
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysFile {
@TableId(value = "id", type = IdType.INPUT)
private Integer id;
private String name;
private String format;
private byte[] data;
private long size;
private Date createTime;
}
第三步:编写dao层接口
SysFileMapper.java
package com.lm.system.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.lm.system.common.SysFile;
/**
* @author DUHAOLIN
* @date 2024/10/17
*/
//@DS("system")
public interface SysFileMapper {
int insertFile(SysFile file);
}
第四步:编写dao层SQL
SysFileMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lm.system.mapper.SysFileMapper">
<resultMap id="beans" type="com.lm.system.common.SysFile">
<id property="id" column="id" jdbcType="INTEGER" />
<result property="name" column="name" jdbcType="VARCHAR" />
<result property="format" column="format" jdbcType="VARCHAR" />
<result property="data" column="data" jdbcType="BLOB" />
<result property="size" column="size" jdbcType="DOUBLE" />
<result property="createTime" column="create_time" jdbcType="TIMESTAMP" />
</resultMap>
<insert id="insertFile" parameterType="com.lm.system.common.SysFile">
INSERT INTO t_file (NAME, FORMAT, DATA, SIZE)
VALUES (#{name}, #{format}, #{data}, #{size})
</insert>
</mapper>
第五步:添加 controller
FileController.java
import com.lm.system.exception.FileException;
import com.lm.system.mapper.SysFileMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
/**
* @author DUHAOLIN
* @date 2024/10/15
*/
@Controller
public class FileController {
@Resource
private SysFileMapper fileMapper;
private final static String FILE_FORMAT_TXT = "txt";
private final static String FILE_FORMAT_JPEG = "jpg";
private final static String FILE_FORMAT_PNG = "png";
@Value("${file.upload.path}")
private String path;
private void checkFile(MultipartFile file, String[] fileFormats) {
//校验文件大小
checkSize(file.getSize());
//校验文件名
checkFilename(file.getOriginalFilename());
//校验文件格式
checkFileFormat(file.getOriginalFilename(), fileFormats);
}
private void checkSize(long size) {
if (size > 10485760L) //10MB
throw new FileException("文件大于10MB");
}
private void checkFilename(String filename) {
if (!StringUtils.hasText(filename))
throw new FileException("文件名有误");
}
private void checkFileFormat(String filename, String[] fileFormats) {
int i = filename.lastIndexOf(".");
String suffix = filename.substring(i + 1); //文件后缀
long c = Arrays.stream(fileFormats).filter(s -> s.equals(suffix)).count(); //判断是否存在该文件后缀
if (c < 1) throw new FileException("文件格式有误,该文件类型为:" + suffix);
}
@GetMapping("uploadToDBPage")
public String uploadToDBPage() {
return "uploadToDB";
}
@PostMapping("uploadToDB")
@ResponseBody
public String uploadToDB(@RequestParam("file") MultipartFile file) throws IOException {
//校验文件
try {
String[] fileFormats = { FILE_FORMAT_TXT, FILE_FORMAT_JPEG, FILE_FORMAT_PNG };
checkFile(file, fileFormats);
} catch (FileException e) {
e.printStackTrace();
return e.getMessage();
}
//构建存储对象
SysFile sysFile = SysFile.builder()
.name(getFilename(file.getOriginalFilename()))
.format(getFileFormat(file.getOriginalFilename()))
.data(file.getBytes())
.size(file.getSize())
.build();
int i = fileMapper.insertFile(sysFile);
return i > 0 ? "添加成功" : "添加失败";
}
private String getFileFormat(String filename) {
int i = filename.lastIndexOf(".");
return filename.substring(i + 1); //文件后缀
}
/**
* 获取不带后缀的文件名
*/
private String getFilename(String originalFilename) {
int i = originalFilename.lastIndexOf(".");
return originalFilename.substring(0, i);
}
}
第六步:配置默认 tomcat 最大吞吐量
application.yml
server:
port: 8888
tomcat:
max-swallow-size: 100MB #tomcat的最大吞吐量,默认为2MB,-1则为不限制
spring:
application:
name: system
servlet:
multipart:
max-file-size: 10MB #默认为1MB
max-request-size: 10MB #默认为10MB
上传大于配置文件设定的文件后,页面无响应。
添加上 tomcat 最大吞吐量配置,则能够正常返回。
存在全局异常捕获的可以把文件最大文件限制异常捕获的也加上。
GlobalExceptionHandler.java
@Value("${spring.servlet.multipart.max-file-size}")
private String maxFileSize;
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({MaxUploadSizeExceededException.class})
public String handleMaxUploadSizeException(Exception e, HttpServletRequest request) {
log.error("400-上传文件超过最大限制{},{},{}", maxFileSize, e.getMessage(), request.getServletPath());
e.printStackTrace();
return ResultBody
.build(HttpStatus.BAD_REQUEST)
.setMsg("上传文件超过最大限制" + maxFileSize)
.getReturn();
}
效果图
txt
上传 txt 格式文件,添加成功。
jpg
上传 jpg 格式文件,添加成功。
png
上传 png 格式文件,添加成功。
csv
上传允许格式之外的格式文件,如 csv 文件,则页面返回“文件格式有误”,上传失败。