Enterprise Spring Boot case - Spring Boot upload file (picture)

If you are Xiaobai, this set of information can help you become a big bull. If you have rich development experience, this set of information can help you break through the bottleneck
2022web full set of video tutorial front-end architecture H5 vue node applet Video + data + code + interview questions.

Article catalogue

A series of articles on enterprise level spring boot cases have been launched, covering most enterprise level spring boot usage scenarios. They will be updated from time to time. The source code address of enterprise level spring boot cases is: https://gitee.com/JourWon/spring-boot-example , you are welcome to study and correct together

The common operation of uploading pictures and files on the website is to directly upload them to the webapp directory of the server, or directly upload them to a specified folder of the service. This method is really convenient and simple for simple stand-alone applications, and there will be fewer problems. However, for distributed projects, the way of directly uploading to the project path is obviously unreliable, and with the increase of business volume, files will also increase, and the pressure on the server will naturally increase. Here is a brief introduction to several common ways to upload pictures and files.

  1. Directly upload to the specified server path;
  2. Upload to third-party content storage, such as saving pictures to Alibaba cloud OSS;
  3. Build your own file storage server, such as FastDFS, FTP server, etc

This article mainly talks about the simplest way, that is, upload files or pictures to a specified folder on the server. The project structure is shown in the figure below

1. Add dependency

<dependencies>
    <!-- Knife4j-API Interface document -->
    <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
    </dependency>

    <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- springboot relevant -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2. Spring configuration

In application Add the following configuration to the YML configuration file

# spring configuration
spring:
  application:
    # apply name
    name: spring-boot-file-upload
  servlet:
    multipart:
      # The file size that a single file can upload
      max-file-size: 1MB
      # Total file size of files that can be uploaded in a single request
      max-request-size: 10MB

3. Add Knife4j configuration class

@EnableKnife4j
@Configuration
public class Knife4jConfig {

    /**
     * Create Docket object
     *
     * @return Docket
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * API Basic information
     *
     * @return ApiInfo
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Knife4j-API Interface document")
                .description("API Interface document")
                .contact(new Contact("JourWon", "https://thinkwon.blog.csdn.net/", "JourWon@163.com"))
                .version("1.0.0")
                .build();
    }

}

4. Add enumeration and entity classes

4.1 response code enumeration

@Getter
@AllArgsConstructor
public enum CommonResponseCodeEnum {

    /**
     * success
     */
    SUCCESS("00000", "success"),

    /**
     * User request parameter error
     */
    REQUEST_PARAMETER_ILLEGAL("A0400", "User request parameter error"),
    /**
     * Access not authorized
     */
    UNAUTHORIZED_ACCESS("A0301", "Access not authorized"),
    /**
     * The current request type is not supported
     */
    NONSUPPORT_REQUEST_TYPE("A0444", "The current request type is not supported"),
    /**
     * User id does not exist
     */
    USER_ID_NOT_EXIST("A0445", "user id non-existent"),
    /**
     * Duplicate database field
     */
    DATABSE_FIELD_DUPLICATE("A0446", "Duplicate database field"),

    /**
     * System execution error
     */
    SYSTEM_EXCEPTION("B0001", "System execution error"),

    /**
     * System execution timeout
     */
    SYSTEM_EXECUTION_TIMEOUT("B0100", "System execution timeout"),
    ;

    /**
     * Response coding
     */
    private final String code;

    /**
     * Response information
     */
    private final String message;

}

4.2 upload file information

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UploadFile {

    /**
     * file name
     */
    private String fileName;

    /**
     * File url
     */
    private String url;

}

4.3 uniformly return the response object of the front end

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "CommonResponse-Uniformly return the response object of the front end")
public class CommonResponse<T> implements Serializable {

    private static final long serialVersionUID = -1338376281028943181L;

    /**
     * MDC_KEY
     */
    public static final String MDC_KEY = "traceId";

    @ApiModelProperty(value = "Response coding")
    private String code;

    @ApiModelProperty(value = "Response information")
    private String message;

    @ApiModelProperty(value = "Business data")
    private T data;

    @ApiModelProperty(value = "traceId")
    private String traceId = MDC.get(MDC_KEY);

    @ApiModelProperty(value = "Response date and time")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss.SSS")
    private LocalDateTime localDateTime = LocalDateTime.now();

    public CommonResponse(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public CommonResponse(CommonResponseCodeEnum commonResponseCodeEnum) {
        this.code = commonResponseCodeEnum.getCode();
        this.message = commonResponseCodeEnum.getMessage();
    }

    public CommonResponse(T data) {
        this.code = CommonResponseCodeEnum.SUCCESS.getCode();
        this.message = CommonResponseCodeEnum.SUCCESS.getMessage();
        this.data = data;
    }

    public CommonResponse(CommonResponseCodeEnum commonResponseCodeEnum, T data) {
        this.code = commonResponseCodeEnum.getCode();
        this.message = commonResponseCodeEnum.getMessage();
        this.data = data;
    }

    public static <T> CommonResponse<T> success() {
        return new CommonResponse<>(CommonResponseCodeEnum.SUCCESS);
    }

    public static <T> CommonResponse<T> success(String message) {
        return new CommonResponse<>(CommonResponseCodeEnum.SUCCESS.getCode(), message);
    }

    public static <T> CommonResponse<T> success(T data) {
        return new CommonResponse<>(CommonResponseCodeEnum.SUCCESS, data);
    }

    public static <T> CommonResponse<T> success(CommonResponseCodeEnum commonResponseCodeEnum, T data) {
        return new CommonResponse<>(commonResponseCodeEnum, data);
    }

    public static <T> CommonResponse<T> failure(CommonResponseCodeEnum commonResponseCodeEnum) {
        return new CommonResponse<>(commonResponseCodeEnum);
    }

    public static <T> CommonResponse<T> failure(CommonResponseCodeEnum commonResponseCodeEnum, T data) {
        return new CommonResponse<>(commonResponseCodeEnum, data);
    }

}

5. File upload interface and implementation class

5.1 file upload interface

public interface FileStorageService {

    /**
     * Initialization method, create folder
     */
    void init();

    /**
     * Save file
     *
     * @param multipartFile
     */
    void save(MultipartFile multipartFile);

    /**
     * Load file by file name
     *
     * @param filename
     * @return
     */
    Resource load(String filename);

    /**
     * Load all files
     *
     * @return
     */
    Stream<Path> load();

    /**
     * Recursively delete files
     */
    void clear();

}

5.2 file upload interface implementation class

@Service
public class FileStorageServiceImpl implements FileStorageService {

    private final Path path = Paths.get("fileStorage");

    @Override
    public void init() {
        try {
            if (!Files.exists(path)) {
                Files.createDirectory(path);
            }
        } catch (IOException e) {
            throw new RuntimeException("Could not initialize folder for upload!");
        }
    }

    @Override
    public void save(MultipartFile multipartFile) {
        try {
            Files.copy(multipartFile.getInputStream(), this.path.resolve(multipartFile.getOriginalFilename()));
        } catch (IOException e) {
            throw new RuntimeException("Could not store the file. Error:" + e.getMessage());
        }
    }

    @Override
    public Resource load(String filename) {
        Path file = path.resolve(filename);
        try {
            Resource resource = new UrlResource(file.toUri());
            if (resource.exists() || resource.isReadable()) {
                return resource;
            } else {
                throw new RuntimeException("Could not read the file.");
            }
        } catch (MalformedURLException e) {
            throw new RuntimeException("Error:" + e.getMessage());
        }
    }

    @Override
    public Stream<Path> load() {
        try {
            return Files.walk(this.path, 1)
                    .filter(path -> !path.equals(this.path))
                    .map(this.path::relativize);
        } catch (IOException e) {
            throw new RuntimeException("Could not load the files.");
        }
    }

    @Override
    public void clear() {
        FileSystemUtils.deleteRecursively(path.toFile());
    }

}

6. Initialize file storage space

@Configuration
public class FileUploadRunner implements CommandLineRunner {

    @Resource
    FileStorageService fileStorageService;

    @Override
    public void run(String... args) {
        // Delete the files in the folder when the project starts
        // fileStorageService.clear();
        // create folder
        fileStorageService.init();
    }

}

7. File upload controller

@Slf4j
@RestController
@RequestMapping("/file")
@Api(value = "File controller")
public class FileUploadController {

    @javax.annotation.Resource
    FileStorageService fileStorageService;

    @PostMapping("/upload")
    @ApiOperation("Upload file")
    public CommonResponse upload(@RequestParam("file") MultipartFile file) {
        try {
            fileStorageService.save(file);
            return CommonResponse.success("Upload file successfully: " + file.getOriginalFilename());
        } catch (Exception e) {
            return CommonResponse.failure(CommonResponseCodeEnum.SYSTEM_EXCEPTION);
        }
    }

    @GetMapping("/list")
    @ApiOperation("Get file list")
    public CommonResponse<List<UploadFile>> files(HttpServletResponse response) {
        List<UploadFile> files = fileStorageService.load()
                .map(path -> {
                    String fileName = path.getFileName().toString();
                    String url = MvcUriComponentsBuilder
                            .fromMethodName(FileUploadController.class,
                                    "getFile",
                                    path.getFileName().toString(), response
                            ).build().toString();
                    return new UploadFile(fileName, url);
                }).collect(Collectors.toList());

        return CommonResponse.success(files);
    }

    @GetMapping("/{filename:.+}")
    @ApiOperation("Download File")
    public ResponseEntity<Resource> getFile(@PathVariable("filename") String filename, HttpServletResponse response) throws UnsupportedEncodingException {
        Resource file = fileStorageService.load(filename);
        String fileName = file.getFilename();

        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        // Here is urlencoder Encode can prevent Chinese garbled code
        String fn = URLEncoder.encode(Objects.requireNonNull(fileName), StandardCharsets.UTF_8.name());

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment;filename=" + fn)
                .body(file);
    }

}

8. Startup class

@SpringBootApplication
public class SpringBootFileUploadApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootFileUploadApplication.class, args);
    }

}

The three interfaces of the above file upload controller can be verified through postman

Keywords: Java Front-end Spring Spring Boot html

Added by bacarudaguy on Sun, 20 Feb 2022 21:32:19 +0200