써먹는 웹개발

[Spring Boot/IntelliJ] aws s3와 연동하여 파일 업로드/다운로드 구현 - 2편. 업로드/다운로드 기능 구현 본문

Server/Spring

[Spring Boot/IntelliJ] aws s3와 연동하여 파일 업로드/다운로드 구현 - 2편. 업로드/다운로드 기능 구현

kmhan 2021. 5. 2. 10:29


728x90
반응형

1편. 환경설정 : kmhan.tistory.com/504

 

1. jsp 호출

 1) pom.xml에서 dependency에 aws등 필요한 기능 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.901</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
cs

  ※ pom.xml 파일 우클릭 Maven > Reload project를 해야 aws를 import할때 에러가 나지 않는다.

   ex) import com.amazonaws.auth.AWSCredentials;

 

 2) application.properties에서 jsp를 호출하기 위한 경로를 입력

  ...prefix : 폴더경로

  ...suffix : 확장자

 3) Run을 실행하기 위한 콘트롤러 작성

  파일명 : SpringS3AmazonApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.awsfileupload;
 
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class SpringS3AmazonApplication implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(SpringS3AmazonApplication.class, args);
    }
 
    public void run(String... args) throws Exception {
    }
}
cs

org.springframework.boot.CommandLineRunner;</div><div

 

 4) index.jsp 파일 생성

    경로 : webapp/WEB-INF/views/index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>파일 업로드/다운로드</title>
</head>
<body>
    <h1>파일 업로드/다운로드</h1> <hr>
 
    <form id="fileFrm">
        파일 : <input type="file" name="file" onchange="$('#fileList *').remove()" size="35">
        <button type="button" onclick="fileUpload()">업로드</button>
    </form>
    <div id="fileList"></div>
</body>
</html>
cs

 

 

2. S3환경을 사용할 수 있도록 자바 소스에 추가

 1) application.properties에 aws 사이트에서 생성한 버킷을 참고하여 필요한 내용 작성

  1-1) access_key_id : 액세스 키 ID

  1-2) secret_access_key : 보안 액세스 키

※ 찾는 방법

 - 종 모양 오른쪽에 아이디를 클릭한뒤 내 보안 자격 증명 클릭

 - 보안 자격 증명 > 엑세스 키 > 새 액세스 키 만들기를 하면 액세스 키 ID와 보안 액세스 키가 나옵니다.

 ※ 이 2가지는 절대로 외부에 공유하면 안되며 공유시 막대한 호스트비를 내게 될 수 있습니다.

 

  1-3) bucket : (생성한) 버킷 명

  1-4) region : AWS 리전 (나라 및 지역)

 

 2) a3client 함수생성 (파일명 : S3Config.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.example.awsfileupload.config;
 
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
 
@Configuration
public class S3Config {
    @Value("${jsa.aws.access_key_id}")
    private String awsId;
 
    @Value("${jsa.aws.secret_access_key}")
    private String awsKey;
 
    @Value("${jsa.s3.region}")
    private String region;
 
    @Bean
    public BasicAWSCredentials basicAWSCredentials() {
        return new BasicAWSCredentials(awsId, awsKey);
    }
 
    @Bean
    public AWSCredentialsProvider awsCredentialProvider(AWSCredentials awsCredentials) {
       return new AWSCredentialsProvider() {
            @Override
            public AWSCredentials getCredentials() { return awsCredentials; }
 
            @Override
            public void refresh() {}
       };
    }
 
    @Bean
    public AmazonS3 s3client() {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(awsId, awsKey);
        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                .withRegion(Regions.fromName(region))
                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                .build();
 
        return s3Client;
    }
}
cs

 

2. 파일 업로드

 1) java 소스 (파일명 : FileUploadDownloadController.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package com.example.awsfileupload;
 
import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3URI;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.util.IOUtils;
import org.apache.logging.log4j.message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.*;
 
@RestController
public class FileUploadDownloadController {
 
    private Logger logger = LoggerFactory.getLogger(FileUploadDownloadController.class);
 
    @Autowired
    private AmazonS3 s3client;
 
    @Value("${jsa.s3.bucket}")
    private String bucketName;
 
    @Value("${jsa.s3.region}")
    private String region;
 
    public File convert(MultipartFile file) throws IOException {
        File convFile = new File(file.getOriginalFilename());
        convFile.createNewFile();
        FileOutputStream fos = new FileOutputStream(convFile);
        fos.write(file.getBytes());
        fos.close();
        return convFile;
    }
 
    // 파일 업로드 요청
    @PostMapping("/upload")
    public String uploadSingle(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request) throws Exception {
        try {
            String fName = multipartFile.getOriginalFilename();
            System.out.println(fName.indexOf("."));
            if (fName.indexOf(".") != -1) {
                String ext = fName.split("\\.")[1];
                PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, UUID.randomUUID() + "." + ext, convert(multipartFile));
                putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
                s3client.putObject(putObjectRequest);
                logger.info("===================== Upload File - Done! =====================");
            }
        } catch (AmazonServiceException ase) {
            logger.info("Caught an AmazonServiceException from PUT requests, rejected reasons:");
            logger.info("Error Message:    " + ase.getMessage());
            logger.info("HTTP Status Code: " + ase.getStatusCode());
            logger.info("AWS Error Code:   " + ase.getErrorCode());
            logger.info("Error Type:       " + ase.getErrorType());
            logger.info("Request ID:       " + ase.getRequestId());
        } catch (AmazonClientException ace) {
            logger.info("Caught an AmazonClientException: ");
            logger.info("Error Message: " + ace.getMessage());
        }
        return "success";
    }
}
cs

 2) jsp에 javascript 소스 (파일명 : index.jsp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%@ page import="java.util.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
    var fileListTag = "";
 
    function fileUpload(){
        $.ajax({
            type: "POST",
            enctype:"multipart/form-data",
            url:"/upload",
            data: new FormData($("#fileFrm")[0]),
            processData:false,
            contentType:false,
            success: function(data) {
// 파일 다운로드 기능 추가예정
            }
        });
    }
</script>
<!DOCTYPE html>
cs

 

3. 파일 다운로드

 1) java 소스에 다음 메소드 추가 (파일명 : FileUploadDownloadController.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    // 파일 다운로드 목록 불러오기
    @RequestMapping(value = "/downloadList", method = RequestMethod.GET)
    public String fileDownloadList(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ObjectListing objectListing = s3client.listObjects(bucketName); //prefix가 필요하지 않은 경우 다음과 같이 사용할 수도 있다. => ObjectListing objectListing = s3Client.listObjects(BucketName);
        List<String> arrayKeyList = new ArrayList<>();
        List<Date> arrayModTimeList = new ArrayList<>();
        for (S3ObjectSummary s : objectListing.getObjectSummaries()) {
            arrayKeyList.add(s.getKey());
            arrayModTimeList.add(s.getLastModified());
        }
        Date max = Collections.max(arrayModTimeList);
        String fileName = arrayKeyList.get(arrayModTimeList.indexOf(max));
        String url = "https://" + bucketName + ".s3." + region + ".amazonaws.com/" + fileName;
        return url;
    }
cs

 

 2) jsp에 javascript 소스 (파일명 : index.jsp)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<%@ page import="java.util.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
    var fileListTag = "";
 
    function fileUpload(){
        $.ajax({
            type: "POST",
            enctype:"multipart/form-data",
            url:"/upload",
            data: new FormData($("#fileFrm")[0]),
            processData:false,
            contentType:false,
            success: function(data) {
                $.ajax({
                    url: "/downloadList",
                    type:"GET",
                    success:function(data){
                        if(data != undefined || data != null) {
                            $("#fileList *").remove();
                            fileListTag = "<a href=\""+data+"\">"+data+"</a>";
                            $("#fileList").append(fileListTag);
                        }
                    }
                });
            }
        });
    }
</script>
<!DOCTYPE html>
cs

 

 3) 생성된 링크 클릭시 파일을 바로 열지않고 다운로드하고 싶을때 주의사항

  - FileUploadDownloadController.java > uploadSingle 메서드에 다음 소스 추가

1
2
3
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setContentType("plain/text");
                putObjectRequest.setMetadata(metadata);
cs

 

 ※ 파일 다운로드 링크 클릭시 에러 페이지가 뜬다면 2가지를 다시 확인할 것

 1) ACL > 모든 사람에 객체는 '나열', 버킷 ACL에는 '읽기'로 되어있는지 확인

 2) 업로드 기능 구현한 자바 파일에 해당 소스가 작성되어있는지 확인

1
putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
cs

 

 


도움이 되셨나면 하트와 댓글 남겨주세요.

728x90
반응형


Comments