文件上传和下载(批量/单个)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_39150374/article/details/99291877

前言

用springboot + jpa,批量上传、下载,一般批量下载处理方式都是将多个文件压缩成一个压缩包,然后在下载,主要的坑在于本地上传和下载都正常,部署在服务器上会出现各种错误,比如找不到路径,下载文件失败等等。

文件压缩工具类

见之前写的处理相关乱码的文章: https://blog.csdn.net/qq_39150374/article/details/93715504

实体类

实体类中有关联关联的id,实际项目中一般上传下载都不会是一张表

package com.example.student.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 描述:文件上传下载
 */
@Table(
        name = "Document"
)
@Entity
@Getter
@Setter
@DynamicInsert//新增时空字段不去插入values
@DynamicUpdate//只跟新变化的字段,结合merge方法使用
@JsonInclude(JsonInclude.Include.NON_NULL)
@EntityListeners({AuditingEntityListener.class})
@JsonIgnoreProperties({"modifier", "modifyDate"})
public class Document implements BaseEntity {
    @Id
    @GeneratedValue
    private Integer id;
    @Column(columnDefinition = "int default 0")
    private Integer companyId;//企业id
    @Column(columnDefinition = "varchar(100) default ''")
    private String name;//文件名
    @Column(columnDefinition = "varchar(100) default ''")
    private String path;//文件路径
    @Column(columnDefinition = "varchar(20) default ''")
    private String fileType;//文件类型
    @Column(columnDefinition = "decimal(10,0) default 0")
    private BigDecimal fileSize;//文件大小
    @Column(columnDefinition = "int default 0")
    private Integer downloadTimes;//下载次数
    @Column(columnDefinition = "varchar(20) default ''")
    private String creatorName;//创建人

    @CreatedBy
    private Integer creator;
    @CreatedDate
    private Date createDate;
    @LastModifiedBy
    private Integer modifier;
    @LastModifiedDate
    private Date modifyDate;
}

Controller层

package com.example.student.controller;


import com.example.student.criteria.DocumentCriteria;
import com.example.student.response.BaseEntity;
import com.example.student.service.DocumentServiceImpl;
import com.example.student.util.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.List;

/**
 * 描述:文件管理
 */
@RestController
@RequestMapping("api/document")
public class DocumentController extends BaseController {

    @Autowired
    DocumentServiceImpl documentService;

    /**
     * 文件上传
     *
     * @param objId   所属id
     * @param request 文件request
     * @return
     */
    @PostMapping("/upload")
    public Object fileUpload(Integer objId, MultipartHttpServletRequest request) {
        return BaseEntity.success(documentService.fileUpload(objId, request));
    }

    /**
     * 单文件下载
     *
     * @param id 文件id
     * @return
     */
    @GetMapping("/download/{id}")
    public void fileDownload(@PathVariable Integer id, HttpServletRequest request, HttpServletResponse response) {
        documentService.downloadAlone(id, request, response);
    }

    /**
     * 批量文件下载
     *
     * @param ids 文件id集合
     * @return
     */
    @PostMapping("/download")
    public void fileMultiDownload(@RequestBody Collection<Integer> ids, HttpServletRequest request, HttpServletResponse response) {
        documentService.downloadMulti(ids, request, response);
    }

    @DeleteMapping("")
    public Object delete(@RequestBody List<Integer> ids) {
        return BaseEntity.success(documentService.delete(ids));
    }
}

service层

package com.example.student.service;

import com.example.student.criteria.DocumentCriteria;
import com.example.student.e_num.DocumentType;
import com.example.student.entity.Document;
import com.example.student.entity.DocumentRelations;
import com.example.student.repository.CommonRepository;
import com.example.student.repository.DocumentRelationsRepository;
import com.example.student.repository.DocumentRepository;
import com.example.student.response.ResException;
import com.example.student.util.DateUtil;
import com.example.student.util.Helpers;
import com.example.student.util.PageBean;
import com.example.student.util.ZipFilesUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述:文件管理
 */
@Service
public class DocumentServiceImpl {

    @Autowired
    private CommonRepository commonRepository;
    @Autowired
    private DocumentRepository documentRepository;
    @Autowired
    private DocumentRelationsRepository documentRelationsRepository;
    @Value("${fileProps.filePath}")
    private String filePath;

 /**
     * 文件上传类型
     */
    private final static List<String> fileTypes = new ArrayList<String>(){{
        add("doc");
        add("docx");
        add("xls");
        add("xlsx");
        add("ppt");
        add("pptx");
        add("txt");
        add("md");
        add("pdf");
        add("jpg");
        add("jpeg");
        add("png");
        add("gif");
        add("bmp");
    }};

    /**
     * 文件上传
     *
     * @param objId   文件所属id
     * @param request 请求
     * @return
     */
    public List<Integer> fileUpload(Integer objId, MultipartHttpServletRequest request) {
        //按月来保存一个目录
        String uploadPath = DateUtil.dateToString(new Date(), DateUtil.YEAR_NO_DAY);

        //文件路径不存在,则新建
        String checkPath = filePath + "/" + uploadPath;
        File fileStream = new File(checkPath);
        if (!fileStream.exists()) {
            fileStream.mkdirs();
        }

        //开始上传
        MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
        List<MultipartFile> files = new ArrayList<>();
        for (Map.Entry<String, List<MultipartFile>> temp : multiFileMap.entrySet()) {
            files.addAll(temp.getValue());
        }

        List<Document> documents = new ArrayList<>();
        Document document;
        BufferedOutputStream stream;
        for (MultipartFile file : files) {
            if (file.isEmpty()) {
                throw new ResException("存在文件为空,请确认!");
            }
            try {
                document = new Document();
                //文件属性
                String fileName = file.getOriginalFilename();
                BigDecimal fileSize = BigDecimal.valueOf(file.getSize());
                int len = fileName.lastIndexOf(".");
                if (len <= 0) {
                    throw new ResException("文件类型有误,请确认!");
                }
                String fileType1 = fileName.substring(len + 1).toLowerCase();
                if (!fileTypes.contains(fileType1)) {
                    throw new ResException("只允许上传word、excel、ppt、pdf、txt和图片!");
                }
                String name = fileName.substring(0, len);
                String fileType = fileName.substring(len + 1);
                String physicalName = (new SimpleDateFormat("yyyyMMddHHmmssSSS")).format(new Date()) + "_" + fileName;
                String path = uploadPath + "/" + physicalName;

                document.setName(name);
                document.setFileSize(fileSize);
                document.setFileType(fileType);
                document.setPath(path);
                document.setDownloadTimes(0);

                byte[] bytes = file.getBytes();
                stream = new BufferedOutputStream(new FileOutputStream(new File(checkPath + "/" + physicalName)));
                stream.write(bytes);
                stream.close();

                documents.add(document);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        documentRepository.save(documents);
        List<Integer> documentIds = documents.stream().map(Document::getId).collect(Collectors.toList());

        //需要一个标识标识文件属于企业文件
        String isCompany = request.getParameter("isCompany");
        Boolean flag = Boolean.valueOf(isCompany);
        if (flag) {
            Helpers.requireNonNull("企业参数有误,联系管理员", objId);
            List<DocumentRelations> relationsList = new ArrayList<>();
            DocumentRelations relations;
            for (Integer documentId : documentIds) {
                relations = new DocumentRelations();
                relations.setDocumentId(documentId);
                relations.setInfoId(objId);
                relations.setInfoType(DocumentType.COMPANY.getValue());
                relationsList.add(relations);
            }
            documentRelationsRepository.save(relationsList);
        }
        return documentIds;
    }

    @Transactional
    public void downloadAlone(Integer id, HttpServletRequest request, HttpServletResponse response) {
        Document document = documentRepository.findOne(id);
        Helpers.requireNonNull("当前文件不存在,请联系管理员", document);

        File file = new File(filePath + "/" + document.getPath());
        if (!file.exists()) {
            throw new ResException("文件 :" + document.getName() + "不存在,请联系管理员!");
        }

        document.setDownloadTimes(document.getDownloadTimes() == null ? 1 : document.getDownloadTimes() + 1);
        String originFileName = document.getName() + "." + document.getFileType();
        ZipFilesUtil.downloadFile(file, originFileName, request, response);
    }

    @Transactional
    public void downloadMulti(Collection<Integer> ids, HttpServletRequest request, HttpServletResponse response) {
        List<Document> documents = documentRepository.findAllByIdIn(ids);
        List<File> files = new ArrayList<>();

        for (Document document : documents) {
            File file = new File(filePath + "/" + document.getPath());
            if (file.exists()) {
                files.add(file);
            } else {
                throw new ResException("文件 :" + document.getName() + "不存在,请联系管理员!");
            }
            document.setDownloadTimes(document.getDownloadTimes() == null ? 1 : document.getDownloadTimes() + 1);
        }

        if (files.isEmpty()) {
            throw new ResException("当前选择文件不存在,请联系管理员!");
        } else {
            String tempName = "temp.zip";
            String path = filePath + "/" + tempName;
            //压缩
            ZipFilesUtil.createZipFiles(files, path, response);
            //下载
            ZipFilesUtil.downloadFile(new File(path), tempName, request, response);
        }
    }

    /**
     * 删除
     */
    @Transactional
    public Integer delete(List<Integer> ids) {
        if (ids.isEmpty())
            return 0;
        documentRelationsRepository.deleteByInfoIdInAndInfoType(ids, DocumentType.COMPANY.getValue());
        return documentRepository.deleteAllByIdIn(ids);
    }
}

Repository

package com.example.student.repository;

import com.example.student.entity.Document;
import org.springframework.data.repository.CrudRepository;

import java.util.Collection;
import java.util.List;

/**
 * 描述:文件管理
 */
public interface DocumentRepository extends CrudRepository<Document, Integer> {
    List<Document> findAllByIdIn(Collection<Integer> ids);

    Integer deleteAllByIdIn(Collection<Integer> ids);
}

package com.example.student.repository;


import com.example.student.entity.DocumentRelations;
import org.springframework.data.repository.CrudRepository;

import java.util.Collection;
import java.util.List;

/**
 * 描述:附件关联关系
 */
public interface DocumentRelationsRepository extends CrudRepository<DocumentRelations, Integer> {
    void deleteByInfoIdInAndInfoType(Collection<Integer> infoIds, Integer infoType);

    List<DocumentRelations> findAllByInfoType(Integer infoType);

    List<DocumentRelations> findByInfoIdAndInfoType(Integer infoId, Integer infoType);
}

注意事项

yml部分配置

  http:
      multipart:
        max-file-size: 10Mb      # 单个文件不超过10M
        max-request-size: 100Mb # 请求文件总大小不超过100M

# 文件存储位置
fileProps:
  filePath: /user/student/files

猜你喜欢

转载自blog.csdn.net/qq_39150374/article/details/99291877