Reference: Java operation Ali Cloud OSS operation official documents

Learning to read documents and actually use them is also a habit and skill

Here is a simple introduction, with the current popular Springboot to operate Ali Cloud OSS file storage.

1. The demand

(If you haven’t stepped on the potholes below, you can skip this chapter.)

Questions briefly

First of all, I do some open source project cases in before he met some file upload download problem, such as in the native file upload and download can be normal use, through the upload files to Springboot root directory of the project, by date folder, file access is very convenient, also can be directly address returns the relative file path, and can be accessed directly.

The problem

However, this approach has drawbacks, because when the project package (JAR package) deployment ali Cloud student machine, there is a similar IO.NotFoundException… (No Such Directory), and if war package is deployed to Tomcat, there is No problem and it can be used normally. After a long investigation, the problem is found: The internal directory structure of the JAR package cannot be changed after packaging. That is, the file upload folder classified by date cannot be added to the JAR package when the folder of a new date needs to be created. In this case, IO exceptions will occur. For the WAR package in Tomcat, the war package will be decompressed automatically when Tomcat runs, and there is a real path on the server.

The solution

  • Solution 1: I found a method on the Internet, which is to separate the file upload folder under the static springboot project after the deployment of the JAR package (equivalent to changing the relative path to the absolute path), and directly create a file upload folder under the same directory as the JAR package on the server when accessing it.
  • Solution 2: Directly upload the file to the specified file upload location on the server. This method is also equivalent to using the absolute path.
  • Scheme three: use FastDFS and Nginx on the server to build distributed file storage, this way is more complex, and students and the original memory and bandwidth is small, in their own computer virtual machine can try this scheme, or very good use, student server even.
  • Solution 4: Upload files directly to the Ali Cloud OSS file storage system

2. Ali Cloud OSS purchase and configuration

This is relatively simple, recommend a blog to everyone to understand their own ali cloud OSS purchase and configuration, can also refer to ali cloud OSS official documents.

3. Springboot operates OSS

To create a Spring Boot project, the POM file needs to import dependencies:

pom.xml

<dependencies>
    <! -- Personal version: Without this dependency, when using the @configurationProperties (prefix = "aliyun") annotation in the configuration class, my version of Spring Boot will tell you there is a problem -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <! -- swagger2 -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <! -- swagger ui -->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
    <! -- Thymeleaf -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <! -- web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <! -- Hot deployment, depending on personal habits -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    
    <! JavaBean setters/getters can be saved, and chain calls can be used.
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <! -- fastJson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.62</version>
    </dependency>
    <! -- aliyun-oos -->
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>2.8.3</version>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.10.1</version>
    </dependency>
    <! -- apache-common-lang3 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.8.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
Copy the code

The package structure is simple:



We use our own additionsapplication-aliyun-oss.propertiesYml (application. Yml) is not used to configure OSS related information in the configuration file. It is not necessary to configure all custom configuration properties in the application.

application-aliyun-oss.properties

# file upload size limit spring. Servlet. Multipart. Max - file - size = 100 MB spring. Servlet. Multipart. Max - request - size = 1000 MB # regional nodes Aliyun.endPoint=oss-cn-beijing.aliyuncs.com # Bucket domain name aliyun.urlprefix =http://csp-xxxx.oss-cn-beijing.aliyuncs.com/ # accessKey Id aliyun.accessKeyId=LTAI4XXXXXXXzqD1saGFZ # accessKey Secret aliyun.accessKeySecret=2WjxNXXXXXXXX4f2bREc # BucketName =csp-xxxx # Target folder aliyun.fileHost=filesCopy the code

Config package related configuration classes

AliyunOssConfig.java

/ * * *@Auther: csp1999
 * @DateTemptation: 2020/10/31 / *@Description: Ali Cloud OSS basic configuration */
// Declare the configuration class and put it in the Spring container
@Configuration
// Specify the location of the configuration file
@PropertySource(value = {"classpath:application-aliyun-oss.properties"})
// Specify the custom attribute prefix in the configuration file
@ConfigurationProperties(prefix = "aliyun")
@Data// lombok
@Accessors(chain = true)// open the chain call
public class AliyunOssConfig {
    private String endPoint;// Domain node
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;// The Bucket name of the OSS
    private String urlPrefix;/ / Bucket domain name
    private String fileHost;// Target folder

    // Give the OSS client to the Spring container for hosting
    @Bean
    public OSS OSSClient(a) {
        return newOSSClient(endPoint, accessKeyId, accessKeySecret); }}Copy the code

Swagger2Config.java

/ * * *@Auther: csp1999
 * @Date: 2020/10/31 / ticket *@Description: Swagger configuration class */
@Configuration
@EnableSwagger2/ / open swagger2
public class Swagger2Config {

    @Bean
    public Docket webApiConfig(a) {

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();
    }

    private ApiInfo webApiInfo(a) {
        return new ApiInfoBuilder()
                .title("SpringBoot integration with OSS-API documentation")
                .description("Ali Cloud OSS- File upload and download test")
                .version("1.0")
                .contact(new Contact("CSP"."https://blog.csdn.net/weixin_43591980"."")) .build(); }}Copy the code

Define an enumeration class about the results of the execution state

/ * * *@Auther: csp1999
 * @Date: 2020/10/31/17:03
 * @Description: Status code enumeration class */
public enum StatusCode {
    SUCCESS("success".200),ERROR("error".500);
    private String msg;
    private Integer code;

    StatusCode(String msg,Integer code){
        this.msg = msg;
        this.code = code;
    }
    StatusCode(Integer code){
        this.code = code;
    }
    StatusCode(String msg){
        this.msg = msg;
    }
    public String getMsg(a) {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Integer getCode(a) {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code; }}Copy the code

The service layer

Use ossClient to operate Ali cloud OSS in service, upload, download, delete, view all files and other operations, and at the same time, you can import the URL of the picture into the library:

FileUploadService.java

/ * * *@Auther: csp1999
 * @Date: 2020/10/31 / passion *@Description: file upload Service (to save code space in this article, do not do interface implementation class processing) */
@Service("fileUploadService")
public class FileUploadService {
    // Format that allows uploading of files (images)
    private static final String[] IMAGE_TYPE = new String[]{".bmp".".jpg".".jpeg".".gif".".png"};
    @Autowired
    private OSS ossClient;// Inject ali Cloud OSS file server client
    @Autowired
    private AliyunOssConfig aliyunOssConfig;// Inject the Ali cloud OSS basic configuration class

    Note: Ali Cloud OSS file upload official document link: https://help.aliyun.com/document_detail/84781.html?spm=a2c4g.11186623.6.749.11987a7dRYVSzn * @ param: uploadFile * @return: string * @create: 2020/10/31 14:36 * @author: csp1999 */
    public String upload(MultipartFile uploadFile) {
        // Get the Bucket name of the OSS
        String bucketName = aliyunOssConfig.getBucketName();
        // Get the oss regional node
        String endpoint = aliyunOssConfig.getEndPoint();
        // Obtain AccessKeySecret for oss
        String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
        // Obtain the AccessKeyId of the OSS
        String accessKeyId = aliyunOssConfig.getAccessKeyId();
        // Get the OSS target folder
        String filehost = aliyunOssConfig.getFileHost();
        // Returns the url returned after the image is uploaded
        String returnImgeUrl = "";

        // Verify the image format
        boolean isLegal = false;
        for (String type : IMAGE_TYPE) {
            if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) {
                isLegal = true;
                break; }}if(! isLegal) {// If the image format is illegal
            return StatusCode.ERROR.getMsg();
        }
        // Get the original file name
        String originalFilename = uploadFile.getOriginalFilename();
        // Get the file type
        String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));
        // New file name
        String newFileName = UUID.randomUUID().toString() + fileType;
        // Build date path, for example: OSS target folder /2020/10/31/ file name
        String filePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
        // File upload path address
        String uploadImgeUrl = filehost + "/" + filePath + "/" + newFileName;

        // Get the file input stream
        InputStream inputStream = null;
        try {
            inputStream = uploadFile.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        /** * The following two lines of code are key pits: * Now the default image upload ContentType of Ali Cloud OSS is image/ JPEG * that is to say, after retrieving the image link, the image is downloaded instead of browsing the link online. Change it to image/ JPG */
        ObjectMetadata meta = new ObjectMetadata();
        meta.setContentType("image/jpg");

        // Upload the file to Ali Cloud OSS
        ossClient.putObject(bucketName, uploadImgeUrl, inputStream, meta);
        /** * Note: in a real project, after the file is successfully uploaded, the database stores the file address */
        // Get the return address of the uploaded image of the file
        returnImgeUrl = "http://" + bucketName + "." + endpoint + "/" + uploadImgeUrl;

        return returnImgeUrl;
    }

    /* * File download * @param: fileName * @param: outputStream * @return: void * @create: 2020/10/31 16:19 * @author: csp1999 */
    public String download(String fileName, HttpServletResponse response) throws UnsupportedEncodingException {
// // Sets the response header to download
// response.setContentType("application/x-download");
// // Set the file name for the download
// response.addHeader("Content-Disposition", "attachment; fileName=" + fileName);
// response.setCharacterEncoding("UTF-8");
        // The file name is downloaded as an attachment
        response.setHeader("Content-Disposition"."attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

        // Get the Bucket name of the OSS
        String bucketName = aliyunOssConfig.getBucketName();
        // Get the OSS target folder
        String filehost = aliyunOssConfig.getFileHost();
        // Date directory
        // Note that there is a logical problem with writing a fixed date directory, but in reality filePath's date directory should be queried from the database
        String filePath = new DateTime().toString("yyyy/MM/dd");

        String fileKey = filehost + "/" + filePath + "/" + fileName;
        OssObject contains the name of the storage space where the file resides, the file name, the file meta-information, and an input stream.
        OSSObject ossObject = ossClient.getObject(bucketName, fileKey);
        try {
            // Read the contents of the file.
            InputStream inputStream = ossObject.getObjectContent();
            BufferedInputStream in = new BufferedInputStream(inputStream);// stream the input to the cache stream
            ServletOutputStream outputStream = response.getOutputStream();
            BufferedOutputStream out = new BufferedOutputStream(outputStream);// Stream the output to the cache stream
            byte[] buffer = new byte[1024];
            int len = 0;
            while((len = in.read(buffer)) ! = -1) {
                out.write(buffer, 0, len);
            }
            if(out ! =null) {
                out.flush();
                out.close();
            }
            if(in ! =null) {
                in.close();
            }
            return StatusCode.SUCCESS.getMsg();
        } catch (Exception e) {
            returnStatusCode.ERROR.getMsg(); }}/* * File deleted * @param: objectName * @return: java.lang.String * @create: 2020/10/31 16:50 * @author: csp1999 */
    public String delete(String fileName) {
        // Get the Bucket name of the OSS
        String bucketName = aliyunOssConfig.getBucketName();
        // Get the oss regional node
        String endpoint = aliyunOssConfig.getEndPoint();
        // Obtain AccessKeySecret for oss
        String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
        // Obtain the AccessKeyId of the OSS
        String accessKeyId = aliyunOssConfig.getAccessKeyId();
        // Get the OSS target folder
        String filehost = aliyunOssConfig.getFileHost();
        // Date directory
        // Note that there is a logical problem with writing a fixed date directory, but in reality filePath's date directory should be queried from the database
        String filePath = new DateTime().toString("yyyy/MM/dd");

        try {
            /** * Note: In a real project, there is no need to delete files in the OSS file server, * just delete the file path stored in the database! * /
            // It is recommended to create OSSClient in the method instead of using @bean injection, otherwise the Connection pool will shut down easily
            OSSClient ossClient = new OSSClient(endpoint,
                    accessKeyId, accessKeySecret);
            // Delete files according to BucketName,filetName
            // Delete files in the directory. If the last file is fileoath, the directory will be deleted.
            String fileKey = filehost + "/" + filePath + "/" + fileName;
            ossClient.deleteObject(bucketName, fileKey);

            try{}finally {
                ossClient.shutdown();
            }
            System.out.println("File deleted!");
            return StatusCode.SUCCESS.getMsg();
        } catch (Exception e) {
            e.printStackTrace();
            returnStatusCode.ERROR.getMsg(); }}}Copy the code

The controller layer

The controller provides the test interface

/ * * *@Auther: csp1999
 * @Date: 2020/10/31 / they *@Description: OSS file upload controller */
@api (description = "ali cloud OSS file upload, download, delete Api ")
@RequestMapping("api/pri/file")
@RestController
public class OssFileController {
    @Autowired
    private FileUploadService fileUploadService;

    File upload API / * * * @ param: file * @ return: com. Alibaba. Fastjson. JSONObject * @ the create: 2020/10/31 caught * @ author: csp1999 * /
    @apiOperation (value = "file upload ")
    @PostMapping("upload")
    public JSONObject upload(@RequestParam("file") MultipartFile file) {
        JSONObject jsonObject = new JSONObject();
        if(file ! =null) {
            String returnFileUrl = fileUploadService.upload(file);
            if (returnFileUrl.equals("error")) {
                jsonObject.put("error"."File upload failed!");
                return jsonObject;
            }
            jsonObject.put("success"."File uploaded successfully!");
            jsonObject.put("returnFileUrl", returnFileUrl);
            return jsonObject;
        } else {
            jsonObject.put("error"."File upload failed!");
            returnjsonObject; }}/ * * file download API * @ param: fileName * @ param: response * @ return: com. Alibaba. Fastjson. JSONObject * @ the create: 2020/10/31 17:35 * @author: csp1999 */
    @apiOperation (value = "file download ")
    @GetMapping(value = "download/{fileName}")
    public JSONObject download(@PathVariable("fileName") String fileName, HttpServletResponse response) throws Exception {
        JSONObject jsonObject = new JSONObject();

        String status = fileUploadService.download(fileName, response);
        if (status.equals("error")) {
            jsonObject.put("error"."File download failed!");
            return jsonObject;
        } else {
            jsonObject.put("success"."File downloaded successfully!");
            returnjsonObject; }}/ * * * @ param file deletion API: fileName * @ return: com. Alibaba. Fastjson. JSONObject * @ the create: 2020/10/31 caught * @ the author: csp1999 */
    @apiOperation (value = "delete file ")
    @GetMapping("/delete/{fileName}")
    public JSONObject DeleteFile(@PathVariable("fileName") String fileName) {
        JSONObject jsonObject = new JSONObject();

        String status = fileUploadService.delete(fileName);
        if (status.equals("error")) {
            jsonObject.put("error"."File deletion failed!");
            return jsonObject;
        } else {
            jsonObject.put("success"."File deleted successfully!");
            returnjsonObject; }}}Copy the code

4. Run the project test API

Native visit: http://localhost:8083/swagger-ui.html



Test upload:



The result is shown below:



If the upload is successful, let’s see if the link can be accessed:



Upload successful!

Source address: Gitee code repository


  • If it is helpful to everyone, please support sanlian!
  • Have a question welcome to leave a message in the comment area, help you solve in time!