从头开始搭建一个SpringBoot项目--SpringBoot文件的上传

前言

流程分析

代码

  • 结构
  • 代码详情
  • UploadFileInfo.class
  • UploadController.class
  • UploadDao.class
  • UploadDao.xml
  • UploadServices.class
  • UploadServicesImpl.class
  • 测试
  • 下载
  • 示例

前言

文件的上传和下载是很多系统必备的功能,之前的一篇文章简单描述了下载,那么现在我们来实现上传文件并且存储到服务器。

值得注意的是,在以下的示例系统中,我已经引入了SpringSecurity、Swagger、Mybatis等框架了。 详情参考: 从头开始搭建一个SpringBoot项目–SpringSecurity的配置

流程分析

用户上传文件,第一步肯定是选择文件,然后系统接收文件并保存到服务器,这一步里面我们首先要做的应该是获取此次上传信息,比如上传人、上传时间、上传文件类型等等。剩下的就是需要考虑的问题是,如何保存?

我的意思是如何保存这个文件?比如文件名称,如果有两个用户上传了一个同样名字的文件,那我们就让用户保存吗?那肯定是不可以的。所以保存时候很重要的一点就是,文件不能同名。所以这里我们保存在服务器上的文件名称最好做一个映射:用户定义文件名 -- 服务器保存文件名称。这种映射关系可以保存在数据库中,这样就保证了文件名的唯一性。

比如用户上传文件名称为你遭老罪了.png,保存的时候用一个时间戳或者uuid + 文件后缀作为该文件在服务器上的名称,假设为:123456789.png,然后把你遭老罪了--123456789,这样的一个映射关系保存到数据库里面,这样用户要按照文件名从服务器上获取该文件的时候我们也能的找到,保存的时候也不会有同名的风险。

PS: 同名风险还是有的,虽然很小,但确实存在:UUID可能生成相同,时间戳可能多用户上传时一样,如果需要的话保存前可以做一个文件名同名检查。如果文件名已存在,则再生成一个。

上传文件的流程图的话大致是以下这样:

spring中公布服务器文件夹 springboot文件服务器搭建_spring中公布服务器文件夹

代码

结构

spring中公布服务器文件夹 springboot文件服务器搭建_上传文件_02

代码详情

UploadFileInfo.class

@Setter
@Getter
@ToString
@NoArgsConstructor
public class UploadFileInfo {
    @ApiModelProperty(value = "上传人id")
    int uploaderId;
    @ApiModelProperty(value = "上传人名称")
    String uploaderName;
    @ApiModelProperty(value = "上传人时间")
    String uploadTime;
    @ApiModelProperty(value = "上传文件大小")
    int size;
    @ApiModelProperty(value = "上传文件名称")
    String fileName;
    @ApiModelProperty(value = "上传文件唯一名称")
    String uName;
    @ApiModelProperty(value = "存储路径")
    String storePath;
    @ApiModelProperty(value = "文件后缀")
    String extension;

    public UploadFileInfo(UserBean userBean) {
        if (userBean == null)
            throw new RuntimeException("用户为空");
        this.uploaderId = userBean.getId();
        this.uploaderName = userBean.getUsername();
    }
}

UploadController.class

这里面的日期工具类在我的其他文章里 主页搜索日期就可找到。

@RestController
@Controller
@RequestMapping(value = "/upload/")
@Api(tags = "03 上传文件" , position = 3)
public class UploadController {
    //配置文件中保存的位置
    @Value("${root.upload.path}")
    private String uploadPath;
    @Autowired
    UploadServices uploadServices;

    @ApiOperation(value = "上传文件测试" , notes = "支持所有文件")
    @PostMapping(value = "/uploadTest")
    public Result uploadFile(
            @RequestParam(required = true) MultipartFile file
    ) {
        UploadFileInfo up = getUploadInfo(file);
        System.out.println(up.toString());
        if(uploadServices.addUploadInfo(up) <= 0) {
            return ResultUtil.success(ResultCode.ERROR);
        }
        try {
        	//将当前文件保存到服务器指定目录下的文件
            file.transferTo(new File(up.getStorePath()));
        }catch (Exception e) {
            e.printStackTrace();
        }
      return ResultUtil.success(ResultCode.SUCCESS);
    }

    /**
     * @Description
     * @Param file
     * @Return {@link UploadFileInfo}
     * @Author 三文鱼先生
     * @Date 2023/3/2 10:45
     **/
    public UploadFileInfo getUploadInfo(MultipartFile file) {
        UserBean user = (UserBean) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //设置上上传人基本信息
        UploadFileInfo uploadFileInfo = new UploadFileInfo(user);
        //文件存储时的唯一id
        String uName = UUID.randomUUID().toString().replaceAll("-" , "");
        //当前时间
        uploadFileInfo.setUploadTime(DateUtil.formatStr(new Date() , DateUtil.SecondPattern));
        //文件大小
        uploadFileInfo.setSize((int) file.getSize());
        String[] fileName = file.getOriginalFilename().split("\\.");
        String extension = fileName[1];
        //存储路径
        String storePath = uploadPath + uName + "." + extension;
        //上传文件后缀
        uploadFileInfo.setExtension(extension);
        //服务器存储地址
        uploadFileInfo.setStorePath(storePath);
        //使用uuid作为文件在服务器上的名称
        uploadFileInfo.setUName(uName);
        //文件的真实名称
        uploadFileInfo.setFileName(fileName[0]);
        return uploadFileInfo;
    }

}

UploadDao.class

public interface UploadDao {
    //添加上传文件记录信息
    int addUploadInfo(UploadFileInfo uploadFileInfo);
}

UploadDao.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.demo.uploadfile.dao.UploadDao">
    <insert id="addUploadInfo" parameterType="com.demo.uploadfile.bean.UploadFileInfo">
        insert into my_file(
        uploaderId,
        uploaderName,
        uploadTime,
        size,
        fileName,
        uName,
        storePath,
        extension
        ) values(
        #{uploaderId},
        #{uploaderName},
        #{uploadTime},
        #{size},
        #{fileName},
        #{uName},
        #{storePath},
        #{extension}
        );
    </insert>
</mapper>

UploadServices.class

public interface UploadServices {
    int addUploadInfo(UploadFileInfo uploadFileInfo);
}

UploadServicesImpl.class

@Service
public class UploadServicesImpl implements UploadServices {
    @Autowired
    UploadDao uploadDao;

    @Override
    public int addUploadInfo(UploadFileInfo uploadFileInfo) {
        return uploadDao.addUploadInfo(uploadFileInfo);
    }
}

测试

spring中公布服务器文件夹 springboot文件服务器搭建_spring boot_03

spring中公布服务器文件夹 springboot文件服务器搭建_spring boot_04

下载

下载的话就比较简单了,这里在之前的文章: 记SpringBoot下载的两种方式,在这里需要注意的应该是,配置SpringSecurity配置下不拦截/file/**。

spring中公布服务器文件夹 springboot文件服务器搭建_spring boot_05

示例

图片文件可以查看后 右键自定义保存

spring中公布服务器文件夹 springboot文件服务器搭建_上传文件_06

其他文件诸如:doc、excel、rar等都会直接下载。

spring中公布服务器文件夹 springboot文件服务器搭建_spring boot_07