All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.shitsurei.service.system.impl.SystemFileBusinessImpl Maven / Gradle / Ivy

The newest version!
package io.github.shitsurei.service.system.impl;

import io.github.shitsurei.common.util.SessionUtil;
import io.github.shitsurei.dao.enumerate.system.*;
import io.github.shitsurei.dao.exception.GlobalException;
import io.github.shitsurei.dao.pojo.po.system.SystemFile;
import io.github.shitsurei.dao.pojo.po.system.SystemFileConfig;
import io.github.shitsurei.dao.pojo.po.system.SystemUser;
import io.github.shitsurei.dao.pojo.vo.system.FileConfigVO;
import io.github.shitsurei.dao.pojo.vo.system.FileVO;
import io.github.shitsurei.dao.repository.system.SystemFileConfigRepository;
import io.github.shitsurei.dao.repository.business.SystemFileRepository;
import io.github.shitsurei.service.system.IFileStorage;
import io.github.shitsurei.service.system.ISystemFileBusiness;
import io.github.shitsurei.service.system.ISystemLogBusiness;
import io.github.shitsurei.service.system.ISystemUserBusiness;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * 系统文件业务类
 *
 * @author zhanggr-b
 * @version 1.0
 * @date 2022/1/7 11:41
 */
@Service
@Slf4j
public class SystemFileBusinessImpl implements ISystemFileBusiness {

    @Autowired
    private SystemFileConfigRepository fileConfigRepository;

    @Autowired
    private SystemFileRepository fileRepository;

    @Autowired
    private IFileStorage fileStorage;

    @Autowired
    private ISystemLogBusiness logBusiness;

    @Autowired
    private ISystemUserBusiness userBusiness;

    @Override
    public List configList() {
        List systemFileConfigList = fileConfigRepository.queryAllByDataStatus(DataStatus.VALID);
        return systemFileConfigList.stream().map(systemFileConfig -> {
            FileConfigVO fileConfigVO = new FileConfigVO();
            BeanUtils.copyProperties(systemFileConfig, fileConfigVO);
            return fileConfigVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List checkFileValid(ArrayList uploadFiles, String configCode, String businessId) {
        SystemFileConfig fileConfig = fileConfigRepository.getSystemFileConfigByConfigCodeAndDataStatus(configCode, DataStatus.VALID);
        if (Objects.isNull(fileConfig)) {
            throw new GlobalException(GlobalExceptionEnum.FILE_CONFIG_NOTFOUND);
        }
        if (fileConfig.getMaxUploadNum() > -1 && StringUtils.isNotBlank(businessId) &&
                // 当前上传文件数量超过限制
                (uploadFiles.size() > fileConfig.getMaxUploadNum() ||
                        // 当前上传文件数量加已上传文件数量(仅统计当前配置绑定同一条业务数据的未删除文件数量)超过限制
                        uploadFiles.size() + fileRepository.countAllBySystemFileConfigAndBindIdAndDataStatus(fileConfig, businessId, DataStatus.VALID) > fileConfig.getMaxUploadNum())
        ) {
            throw new GlobalException(GlobalExceptionEnum.FILE_UPLOAD_NUM_LIMIT);
        }
        List supportFileSuffixes = FileSuffix.resolveFileType(fileConfig.getSupportFileTypes());
        return uploadFiles.stream().map(uploadFile -> {
            if (fileConfig.getMaxUploadSize() > 0 && uploadFile.getSize() / 1024 > fileConfig.getMaxUploadSize()) {
                throw new GlobalException(GlobalExceptionEnum.FILE_SIZE_OVERFLOW);
            }
            String originalFilename = uploadFile.getOriginalFilename();
            if (StringUtils.isBlank(originalFilename)) {
                throw new GlobalException(GlobalExceptionEnum.FILE_NAME_EMPTY);
            }
            FileSuffix fileSuffix = FileSuffix.valueOf(originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toUpperCase(Locale.ROOT));
            if (!supportFileSuffixes.contains(fileSuffix)) {
                throw new GlobalException(GlobalExceptionEnum.FILE_TYPE_NOT_SUPPORT);
            }
            Date now = new Date();
            String systemUserId = SessionUtil.getLoginUser().getSystemUserId();
            SystemFile file = SystemFile.builder()
                    .systemFileConfig(fileConfig)
                    .originalFileName(originalFilename)
                    .fileSuffix(fileSuffix)
                    .fileSize(uploadFile.getSize())
                    .systemFileConfig(fileConfig)
                    .uploader(userBusiness.findSystemUserById(systemUserId))
                    .createPerson(systemUserId)
                    .createTime(now)
                    .updatePerson(systemUserId)
                    .updateTime(now)
                    .dataStatus(DataStatus.VALID)
                    .build();
            if (StringUtils.isNotBlank(businessId)) {
                file.setBindId(businessId);
            }
            return file;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List save(List systemFiles, ArrayList uploadFiles) {
        if (CollectionUtils.isEmpty(systemFiles) || CollectionUtils.isEmpty(uploadFiles)) {
            log.warn("file collection empty | 文件集合为空");
            return Collections.emptyList();
        }
        if (systemFiles.size() != uploadFiles.size()) {
            log.warn("file collection num not match | 文件集合数量不匹配");
            return Collections.emptyList();
        }
        // 使用附件组作为本地存储的二级目录(仅对本地存储生效)
        List filePath = fileStorage.save(uploadFiles, systemFiles.get(0).getSystemFileConfig().getConfigCode());
        for (int i = 0; i < systemFiles.size(); i++) {
            systemFiles.get(i).setSavePath(filePath.get(i));
        }
        Iterable saveFileList = fileRepository.saveAll(systemFiles);
        String logContent = String.format("上传文件集合【%s】,所属配置【%s】,绑定业务数据【%s】",
                systemFiles.stream().map(SystemFile::getOriginalFileName).collect(Collectors.joining(",")),
                systemFiles.get(0).getSystemFileConfig().getConfigName(), systemFiles.get(0).getBindId());
        logBusiness.saveLog(LogType.FILE_CHANGE, logContent, null);
        log.info(logContent);
        // 将存储的文件集合id返回
        return StreamSupport.stream(saveFileList.spliterator(), false).map(SystemFile::getSystemFileId).collect(Collectors.toList());
    }

    @Override
    public List rawFileList(List bindIdList) {
        return fileRepository.queryAllByBindIdInAndDataStatus(bindIdList, DataStatus.VALID);
    }

    @Override
    public List fileList(String businessId) {
        return fileList(Collections.singletonList(businessId));
    }

    @Override
    public List fileList(List businessIdList) {
        List systemFileList = fileRepository.queryAllByBindIdInAndDataStatus(businessIdList, DataStatus.VALID);
        return systemFileList.stream().map(systemFile -> {
            FileVO fileVO = new FileVO();
            BeanUtils.copyProperties(systemFile, fileVO);
            fileVO.setFileConfigCode(systemFile.getSystemFileConfig().getConfigCode());
            return fileVO;
        }).collect(Collectors.toList());
    }

    @Override
    public SystemFile checkFileById(String fileId) {
        if (!fileRepository.findById(fileId).isPresent()) {
            throw new GlobalException(GlobalExceptionEnum.FILE_NOTFOUND);
        }
        return fileRepository.findById(fileId).get();
    }

    @Override
    public boolean checkOperateValid(SystemFile file, DataOperate operate) {
        SystemUser loginUser = SessionUtil.getLoginUser();
        if (Objects.equals(file.getUploader(), loginUser)) {
            return true;
        }
        switch (operate) {
            case RETRIEVE:
                return file.getSystemFileConfig().getRetrieveLimit();
            case UPDATE:
                return file.getSystemFileConfig().getUpdateLimit();
            case DELETE:
                return file.getSystemFileConfig().getDeleteLimit();
            default:
                return true;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(SystemFile file) {
        file.setDataStatus(DataStatus.DELETE);
        file.setUpdatePerson(SessionUtil.getLoginUser().getSystemUserId());
        file.setUpdateTime(new Date());
        fileRepository.save(file);
        if (file.getSystemFileConfig().getRealDelete()) {
            fileStorage.delete(file.getSavePath());
        }
        String logContent = String.format("删除文件【%s】,所属配置【%s】", file.getOriginalFileName(), file.getSystemFileConfig().getConfigName());
        logBusiness.saveLog(LogType.FILE_CHANGE, logContent, null);
        log.info(logContent);
        return true;
    }

    @Override
    public void output(SystemFile file, HttpServletRequest request, HttpServletResponse response) {
        // 根据浏览器版本信息设置文件原始名
        String originalName = encodeFileNameByBrowserType(file.getOriginalFileName(), request.getHeader("User-Agent"));
        //设置UTF-8编码
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());

        // 设置文件下载请求头
        String contentDispositionType = "attachment";
        if (Arrays.asList(FileSuffix.JPG, FileSuffix.JPEG, FileSuffix.GIF, FileSuffix.PNG, FileSuffix.BMP).contains(file.getFileSuffix())) {
            // 如文件后缀名为图片直接在浏览器打开
            contentDispositionType = "inline";
        }
        response.addHeader("Content-Disposition", contentDispositionType + ";filename=\"" + originalName + "\"");
        //根据附件类型获取响应content-type配置
        response.setContentType(getContentType(file.getFileSuffix(), request));
        // 设置返回的文件大小
        response.addHeader("Content-Length", String.valueOf(file.getFileSize()));
        // 获取下载文件输出到response中
        fileStorage.download(file.getSavePath(), response);

        String logContent = String.format("下载文件【%s】,所属配置【%s】", file.getOriginalFileName(), file.getSystemFileConfig().getConfigName());
        logBusiness.saveLog(LogType.FILE_CHANGE, logContent, null);
        log.info(logContent);
    }

    @Override
    @Transactional(rollbackFor = GlobalException.class)
    public boolean createFileConfig(SystemFileConfig fileConfig) {
        SystemFileConfig config = fileConfigRepository.getSystemFileConfigByConfigCodeAndDataStatus(fileConfig.getConfigCode(), DataStatus.VALID);
        if (Objects.nonNull(config)) {
            throw new GlobalException(GlobalExceptionEnum.FILE_CONFIG_CODE_FAILURE);
        }
        SystemUser loginUser = null;
        try {
            loginUser = SessionUtil.getLoginUser();
        } catch (Exception ignored) {
        }
        Date now = new Date();
        fileConfig.setCreatePerson(Objects.nonNull(loginUser) ? loginUser.getSystemUserId() : "systemInit");
        fileConfig.setCreateTime(now);
        fileConfig.setUpdatePerson(Objects.nonNull(loginUser) ? loginUser.getSystemUserId() : "systemInit");
        fileConfig.setUpdateTime(now);
        fileConfig.setDataStatus(DataStatus.VALID);
        fileConfigRepository.save(fileConfig);

        String logContent = String.format("用户【%s】新增文件配置【%s】,配置编码【%s】", Objects.nonNull(loginUser) ? loginUser.getSystemUserId() : "systemInit", fileConfig.getConfigName(), fileConfig.getConfigCode());
        logBusiness.saveLog(LogType.FILE_CONFIG_CHANGE, logContent, null);
        log.info(logContent);
        return true;
    }

    @Override
    @Transactional(rollbackFor = GlobalException.class)
    public boolean updateFileConfig(SystemFileConfig fileConfig) {
        SystemFileConfig existFileConfig = fileConfigRepository.getSystemFileConfigByConfigCodeAndDataStatus(fileConfig.getConfigCode(), DataStatus.VALID);
        if (Objects.isNull(existFileConfig)) {
            throw new GlobalException(GlobalExceptionEnum.FILE_CONFIG_NOTFOUND);
        }
        BeanUtils.copyProperties(fileConfig, existFileConfig);
        Date now = new Date();
        fileConfig.setUpdatePerson(SessionUtil.getLoginUser().getSystemUserId());
        fileConfig.setUpdateTime(now);
        fileConfigRepository.save(existFileConfig);

        String logContent = String.format("更新文件配置【%s】,配置编码【%s】", fileConfig.getConfigName(), fileConfig.getConfigCode());
        logBusiness.saveLog(LogType.FILE_CONFIG_CHANGE, logContent, null);
        log.info(logContent);
        return true;
    }

    @Override
    @Transactional(rollbackFor = GlobalException.class)
    public boolean deleteFileConfig(String fileCode) {
        SystemFileConfig existFileConfig = fileConfigRepository.getSystemFileConfigByConfigCodeAndDataStatus(fileCode, DataStatus.VALID);
        if (Objects.isNull(existFileConfig)) {
            throw new GlobalException(GlobalExceptionEnum.FILE_CONFIG_NOTFOUND);
        }
        Date now = new Date();
        existFileConfig.setDataStatus(DataStatus.DELETE);
        existFileConfig.setUpdatePerson(SessionUtil.getLoginUser().getSystemUserId());
        existFileConfig.setUpdateTime(now);
        fileConfigRepository.save(existFileConfig);

        String logContent = String.format("删除文件配置【%s】", existFileConfig.getConfigName());
        logBusiness.saveLog(LogType.FILE_CONFIG_CHANGE, logContent, null);
        log.info(logContent);
        return true;
    }

    @Override
    public boolean bind(String systemFileId, String bindId) {
        SystemFile file = checkFileById(systemFileId);
        if (StringUtils.equals(file.getBindId(), bindId)) {
            return true;
        }
        // 校验更新权限
        checkOperateValid(file, DataOperate.UPDATE);
        SystemFileConfig fileConfig = file.getSystemFileConfig();
        Integer existFileNum = fileRepository.countAllBySystemFileConfigAndBindIdAndDataStatus(fileConfig, bindId, DataStatus.VALID);
        if (existFileNum.equals(fileConfig.getMaxUploadNum())) {
            throw new GlobalException(GlobalExceptionEnum.FILE_BIND_FAILURE);
        }
        file.setBindId(bindId);
        file.setUpdatePerson(SessionUtil.getLoginUser().getSystemUserId());
        file.setUpdateTime(new Date());
        fileRepository.save(file);

        String logContent = String.format("文件【%s】换绑业务数据主键【%s】", file.getOriginalFileName(), bindId);
        logBusiness.saveLog(LogType.FILE_CHANGE, logContent, null);
        log.info(logContent);
        return true;
    }

    @Override
    public SystemFile checkSystemFileById(String userProfileId) {
        return fileRepository.findById(userProfileId).orElseThrow(() -> new GlobalException(GlobalExceptionEnum.DATA_EXCEPTION, "文件查询结果为空!"));
    }

    @Override
    public SystemFileRepository getDao() {
        return fileRepository;
    }

    @Override
    public SystemFileConfigRepository getConfigDao() {
        return fileConfigRepository;
    }

    /**
     * 根据浏览器类型编码文件名
     *
     * @param fileName
     * @param userAgent
     * @return
     */
    private String encodeFileNameByBrowserType(String fileName, String userAgent) {
        if (StringUtils.isBlank(fileName)) {
            throw new GlobalException(GlobalExceptionEnum.FILE_NAME_EMPTY);
        }
        fileName = fileName.replaceAll("\\s", "");
        try {
            if (StringUtils.isBlank(userAgent)) {
                fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), "ISO8859-1");
            }
            userAgent = userAgent.toLowerCase();
            // Microsoft // Internet // Explorer // IE 11
            if (userAgent.contains("msie") || userAgent.contains("edge") || userAgent.contains("rv:11.")) {
                fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name());
            }
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        return fileName;
    }

    /**
     * 根据附件类型获取response内容类型
     *
     * @param fileSuffix
     * @param request
     * @return
     */
    private String getContentType(FileSuffix fileSuffix, HttpServletRequest request) {
        String contentTypeStr = "application/octet-stream";
        switch (fileSuffix) {
            case DOC:
            case DOCX:
                contentTypeStr = "application/msword";
                break;
            case TXT:
            case PDF:
                contentTypeStr = "application/octet-stream";
                break;
            default:
                String contentType = request.getServletContext().getMimeType(fileSuffix.name());
                if (StringUtils.isNotEmpty(contentType)) {
                    contentTypeStr = contentType;
                }
        }
        return contentTypeStr;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy