UploadController.java 4.26 KB
package com.infoloop.tianting.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.infoloop.tianting.config.OssConfig;
import com.infoloop.tianting.server.StorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Nullable;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Api(tags = "上传、下载管理")
@ApiSupport(order = 99)
@Slf4j
@Validated
@RestController
public class UploadController {

    private final OssConfig ossConfig;

    private final StorageService storageService;

    @Autowired(required = false)
    public UploadController(OssConfig ossConfig, @Nullable StorageService storageService) {
        this.ossConfig = ossConfig;
        this.storageService = storageService;
    }

    @SaIgnore
    @ApiOperation("上传")
    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public String upload(@RequestParam("file") MultipartFile file,
                         @RequestParam(value = "folder", defaultValue = "upload") String folder) throws Exception {
        Assert.notNull(storageService, "存储服务未初始化,请检查配置 aliyun.oss.endpoint");
        String extension = FileNameUtil.getSuffix(file.getOriginalFilename());
        String path = generateUploadPath(folder, extension);
        File tempFile = File.createTempFile(IdUtil.fastSimpleUUID(), null);
        try {
            file.transferTo(tempFile);
            storageService.putObject(ossConfig.getBucket(), path, tempFile);
        } catch (Exception e) {
            log.error("上传失败: {}", file.getOriginalFilename(), e);
            throw new RuntimeException("文件上传失败,请稍后重试");
        } finally {
            tempFile.delete();
        }
        return String.format("%s/%s", ossConfig.getHost(), path);
    }

    @SaIgnore
    @ApiOperation("下载")
    @GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public void download(@RequestParam("path") String path, HttpServletResponse response) {
        Assert.notNull(storageService, "存储服务未初始化,请检查配置 aliyun.oss.endpoint");
        try (InputStream inputStream = storageService.getObjectInputStream(ossConfig.getBucket(), path);
             ServletOutputStream outputStream = response.getOutputStream()) {
            String fileName = path.substring(path.lastIndexOf("/") + 1);
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + "\"");
            IoUtil.copy(inputStream, outputStream);
        } catch (Exception e) {
            log.error("下载失败: {}", path, e);
            throw new RuntimeException("文件下载失败,请稍后重试");
        }
    }

    private String generateUploadPath(String folder, String extension) {
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        return String.format("nutri-api/%s/%s/%s.%s", folder, datePath, IdUtil.fastSimpleUUID(), extension);
    }

}