content: package com.seezoon.admin.modules.sys.controller;
  
  import java.io.*;
  import java.net.URLEncoder;
  import java.nio.charset.StandardCharsets;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  
  import javax.servlet.http.HttpServletResponse;
  import javax.validation.Valid;
  import javax.validation.constraints.NotBlank;
  import javax.validation.constraints.NotEmpty;
  import javax.validation.constraints.NotNull;
  
  import org.apache.commons.lang3.StringUtils;
  import org.springframework.security.access.prepost.PreAuthorize;
  import org.springframework.util.Assert;
  import org.springframework.web.bind.annotation.*;
  import org.springframework.web.multipart.MultipartFile;
  
  import com.github.pagehelper.PageSerializable;
  import com.google.common.collect.Lists;
  import com.seezoon.admin.framework.file.FileService;
  import com.seezoon.admin.modules.sys.service.SysFileService;
  import com.seezoon.dao.modules.sys.entity.SysFile;
  import com.seezoon.dao.modules.sys.entity.SysFileCondition;
  import com.seezoon.framework.api.DefaultCodeMsgBundle;
  import com.seezoon.framework.api.Result;
  import com.seezoon.framework.component.file.FileInfo;
  import com.seezoon.framework.web.BaseController;
  
  import io.swagger.annotations.Api;
  import io.swagger.annotations.ApiOperation;
  import io.swagger.annotations.ApiParam;
  import lombok.RequiredArgsConstructor;
  
  /**
   * 文件
   *
   * @author seezoon-generator 2021年1月2日 上午1:04:41
   */
  @Api(tags = "文件管理")
  @RestController
  @RequestMapping("/sys/file")
  @RequiredArgsConstructor
  public class SysFileController extends BaseController {
  
      private final SysFileService sysFileService;
      private final FileService fileService;
  
      @ApiOperation(value = "主键查询")
      @PreAuthorize("hasAuthority('sys:file:query')")
      @GetMapping("/query/{id}")
      public Result<SysFile> query(@PathVariable String id) {
          SysFile sysFile = sysFileService.find(id);
          return Result.ok(sysFile);
      }
  
      @ApiOperation(value = "分页查询")
      @PreAuthorize("hasAuthority('sys:file:query')")
      @PostMapping("/query")
      public Result<PageSerializable<SysFile>> query(@Valid @RequestBody SysFileCondition condition) {
          PageSerializable<SysFile> pageSerializable =
              sysFileService.find(condition, condition.getPage(), condition.getPageSize());
          pageSerializable.getList().forEach((v) -> {
              v.setUrl(this.fileService.getUrl(v.getRelativePath()));
          });
          return Result.ok(pageSerializable);
      }
  
      /**
       * 通常图片展不需要文件名，可以省DB交互
       *
       * @param relativePaths
       * @param includeFileName
       * @return
       */
      @ApiOperation(value = "查询文件信息")
      @PostMapping("/info")
      public Result<List<FileInfo>> info(@NotBlank @ApiParam("相对路径,逗号分隔") @RequestParam String relativePaths,
          @ApiParam("是否包含文件名") @RequestParam(required = false) boolean includeFileName) {
          List<FileInfo> fileInfos = this.sysFileService.info(relativePaths, includeFileName);
          return Result.ok(fileInfos);
      }
  
      @ApiOperation(value = "单个上传")
      @PreAuthorize("hasAuthority('sys:file:upload')")
      @PostMapping(value = "/upload")
      public Result<FileInfo> upload(@NotNull @RequestParam MultipartFile file) throws IOException {
          // 开启图片压缩
  
          FileInfo fileInfo = sysFileService.upload(file.getOriginalFilename(), file.getContentType(), file.getSize(),
              file.getInputStream());
          return Result.ok(fileInfo);
      }
  
      @ApiOperation(value = "批量上传")
      @PreAuthorize("hasAuthority('sys:file:upload')")
      @PostMapping(value = "/upload_batch")
      public Result<List<FileInfo>> upload(@NotEmpty @RequestParam MultipartFile[] files) {
          List<FileInfo> fileInfos = Lists.newArrayList();
          Arrays.stream(files).forEach((file) -> {
              try {
                  FileInfo fileInfo = sysFileService.upload(file.getOriginalFilename(), file.getContentType(),
                      file.getSize(), file.getInputStream());
                  fileInfos.add(fileInfo);
              } catch (IOException e) {
                  throw new RuntimeException(e);
              }
          });
          return Result.ok(fileInfos);
      }
  
      @ApiOperation(value = "下载")
      @PreAuthorize("hasAuthority('sys:file:download')")
      @GetMapping(value = "/download")
      public void download(@NotBlank @RequestParam String id, HttpServletResponse response) throws IOException {
          SysFile sysFile = sysFileService.find(id);
          Assert.notNull(sysFile, "file record not exists");
          try (InputStream inputStream = fileService.download(sysFile.getRelativePath());
              OutputStream outputStream = response.getOutputStream();
              BufferedOutputStream bos = new BufferedOutputStream(outputStream);
              BufferedInputStream bin = new BufferedInputStream(inputStream)) {
  
              // 设置响应类型 available 在流式下载不准确，设置后下载数据不全
              // response.setContentLength(inputStream.available());
              response.setContentType(sysFile.getContentType());
              response.setHeader("Content-Disposition",
                  "attachment;filename=" + URLEncoder.encode(sysFile.getName(), StandardCharsets.UTF_8));
              // 1M 一写
              byte[] buffer = new byte[1024 * 1024];
              int len = 0;
              while (-1 != (len = bin.read(buffer))) {
                  bos.write(buffer, 0, len);
              }
          }
  
      }
  
      @ApiOperation(value = "删除")
      @PreAuthorize("hasAuthority('sys:file:delete')")
      @PostMapping(value = "/delete")
      public Result delete(@RequestParam String id) {
          SysFile sysFile = sysFileService.find(id);
          Assert.notNull(sysFile, "file record not exists");
          try {
              fileService.delete(sysFile.getRelativePath());
          } catch (IOException e) {
              logger.error("remove file:" + sysFile.getRelativePath() + " error", e);
          }
          int count = sysFileService.delete(id);
          return count == 1 ? Result.SUCCESS : Result.error(DefaultCodeMsgBundle.DELETE_ERROR, count);
      }
  
      @ApiOperation(value = "批量删除")
      @PreAuthorize("hasAuthority('sys:file:delete')")
      @PostMapping(value = "/delete_batch")
      public Result delete(@RequestParam String[] ids) {
          int successCount = 0;
          List<String> errorIds = new ArrayList<>(ids.length);
          for (String id: ids) {
              SysFile sysFile = sysFileService.find(id);
              Assert.notNull(sysFile, "file record not exists");
              try {
                  fileService.delete(sysFile.getRelativePath());
              } catch (IOException e) {
                  logger.error("remove file:" + sysFile.getRelativePath() + " error", e);
              }
              int count = sysFileService.delete(id);
              if (1 == count) { // 删除成功
                  successCount ++;
              } else { // 删除失败
                  errorIds.add(id + "：" + sysFile.getName());
              }
          }
          return successCount == ids.length
                  ? Result.SUCCESS
                  : Result.error(DefaultCodeMsgBundle.DELETE_ERROR,
                          "删除失败文件列表：\n" + StringUtils.join(errorIds, ",\n"));
      }
  
      @ApiOperation(value = "文件url前缀")
      @GetMapping(value = "/url_prefix")
      public Result<String> urlPrefix() {
          return Result.ok(fileService.getUrlPrefix());
      }
  }
  