본문 바로가기

프로그래밍 /AWS

[AWS] S3 버킷 연동 및 파일 업로드

s3란 ?

simple Storage Service의 약자로 파일 서버의 역할을 하는 서비스다. 

일반적인 파일서버는 트래픽이 증가함에 따라서 장비를 증설하는 작업을 해야 하는데 S3는 이와 같은 것을 대행한다. 

트래픽에 따른 시스템적인 문제는 걱정할 필요가 없어진다. 

또 파일에 대한 접근 권한을 지정 할 수 있어서 서비스를 호스팅 용도로 사용하는 것을 방지 할 수 있다. 


특장점

객체

object, AWS는 S3에 저장된 데이터 하나 하나를 객체라고 명명하는데, 

하나 하나의 파일이라고 생각하면 된다.  

버킷

 bucket, 객체가 파일이라면 버킷은 연관된 객체들을 그룹핑한 최상위 디렉토리라고 할 수 있다.

 버킷 단위로 지역(region)을 지정 할 수 있고, 

 또 버킷에 포함된 모든 객체에 대해서 일괄적으로 인증과 접속 제한을 걸 수 있다. 

버전관리

S3에 저장된 객체들의 변화를 저장. 

객체를 사용자가 삭제하거나 변경해도 각각의 변화를 모두 기록하기 때문에 실수를 만회할 수 있다. 

BitTorrent

분산된 파일 배포 시스템이라고 정의 할 수 있다. 여기서 분산이란 하나의 서버에서 파일을 배포하는 것이 아니라, 파일을 가지고 있는 컴퓨터들로부터 조금씩 파일을 다운받은 후에 이것을 붙여서 완전한 파일을 만드는 방식이다. 대용량의 파일을 배포할 때 BitTorrent를 사용하면 비용을 크게 절감 할 수 있다.

RSS

Reduced Redundancy Storage의 약자로 일반 S3 객체에 비해서 데이터가 손실될 확률이 높은 형태의 저장 방식. 대신에 가력이 저렴하기 때문에 복원이 가능한 데이터, 이를테면 섬네일 이미지와 같은 것을 저장하는데 적합하다. 그럼에도 불구하고 물리적인 하드 디스크 대비 400배 가량 안전하다는 것이 아마존의 주장

Glacier

영어로는 빙하라는 뜻으로 매우 저렴한 가격으로 데이터를 저장 할 수 있는 아마존의 스토리지 서비스


(-생활코딩 참조) 




First 버킷생성!!!

Second버킷생성 후에 버킷 정책을 지정

권한을 설정 해야지만 외부에서도 볼수가 있다



※적용이 잘되었는지 확인하기 위해서 하나 샘플로 파일을 올려서 보면 나온다면 적용 완료


★Pom.xml 의존성 라이브러리 설치

   <!--스프링과 AWS S3 서버 연결 관련 설정 -->
        <!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk -->
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-java-sdk</artifactId>
            <version>1.11.106</version>
        </dependency>
        <dependency>
            <groupId>jca</groupId>
            <artifactId>jca</artifactId>
            <version>1.5</version>
        </dependency>


1. S3Util.java


]public class S3Util {
    
    //bucketName
private String bucketName = "faint1122"; 생성한 버킷 명
    //bucketName getter
public String getBucketName() {
        return bucketName;
    }

    private AmazonS3 conn;

public S3Util() {

this.conn = AmazonS3ClientBuilder.standard()
.withRegion(Regions.AP_NORTHEAST_2)
.build();
}

// 버킷 리스트를 가져오는 메서드이다.
public List<Bucket> getBucketList() {
return conn.listBuckets();
}
// 버킷을 생성하는 메서드이다.
public Bucket createBucket(String bucketName) {
return conn.createBucket(bucketName);
}

// 폴더 생성 (폴더는 파일명 뒤에 "/"를 붙여야한다.)
public void createFolder(String bucketName, String folderName) {
conn.putObject(bucketName, folderName + "/", new ByteArrayInputStream(new byte[0]), new ObjectMetadata());
}
// 파일 업로드
public void fileUpload(String bucketName, String fileName, byte[] fileData) throws FileNotFoundException {

String filePath = (fileName).replace(File.separatorChar, '/'); // 파일 구별자를 `/`로 설정(\->/) 이게 기존에 / 였어도 넘어오면서 \로 바뀌는 거같다.
ObjectMetadata metaData = new ObjectMetadata();
//System.out.println("metaData 정보 : "+metaData);
metaData.setContentLength(fileData.length); //메타데이터 설정 -->원래는 128kB까지 업로드 가능했으나 파일크기만큼 버퍼를 설정시켰다.
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData); //파일 넣음

conn.putObject(bucketName, filePath, byteArrayInputStream, metaData);

}

// 파일 삭제
public void fileDelete(String fileName) {

    System.out.println("fileName : " + fileName);
String imgName = (fileName).replace(File.separatorChar, '/');
conn.deleteObject(this.getBucketName(), imgName);
System.out.println("삭제성공");
}

// 파일 URL
public String getFileURL(String bucketName, String fileName) {
System.out.println("넘어오는 파일명 : "+fileName);
String imgName = (fileName).replace(File.separatorChar, '/');
return conn.generatePresignedUrl(new GeneratePresignedUrlRequest(bucketName, imgName)).toString();
}

// src파일 읽어오기
public S3ObjectInputStream getSrcFile(String bucketName, String fileName) throws IOException{
System.out.println("넘어오는 파일명 : "+fileName);
fileName = (fileName).replace(File.separatorChar, '/');
S3Object s3object = conn.getObject(new GetObjectRequest(bucketName, fileName)); //해당 파일 s3객체에 담기
S3ObjectInputStream objectInputStream = s3object.getObjectContent(); //s3객체를 스트림으로 변환

return objectInputStream;
}



}


2.uploadFilesUtils.java


public class UploadFileUtils {
    private static final Logger logger = LoggerFactory.getLogger(UploadFileUtils.class);

    // String uploadPath 파일의 저장경로
    // String originalName 원본 팡리 이름
    // byte[] fileData 파일 데이터
    public static String uploadFile(String uploadPath, String originalName, byte[] fileData, String userid) throws Exception {
     //S3 서버 관련 설정 // 3/28
        
         S3Util s3 = new S3Util();
     String bucketName = "faint1122";
    
    
        UUID uid = UUID.randomUUID();

        String savedName = uid.toString() + "_" + originalName;

        String savedPath = calcPath(uploadPath);
        
         String imagepath = "profile/"+ uploadPath; //이미패스

//      File target = new File(uploadPath + savedPath, savedName);
//
//      FileCopyUtils.copy(fileData, target);
        
        

        String formatName = originalName.substring(originalName.lastIndexOf(".") + 1);
        
         String uploadedFileName =(savedPath+savedName).replace(File.separatorChar, '/');

    //  String uploadedFileName = null;

//      if (MediaUtils.getMediaType(formatName) != null) {
//          uploadedFileName = makeThumbnail(uploadPath, savedPath, savedName);
//      } else {
//          uploadedFileName = makeIcon(uploadPath, savedPath, savedName);
//      }
        
         s3.fileUpload(bucketName, uploadPath+uploadedFileName, fileData); // 추가

        return uploadedFileName;
    }
    
    //이미지 파일이 아닌경우에 아이콘 생성
    private static String makeIcon(String uploadPath, String path, String fileName) throws Exception {

        String iconName = uploadPath + path + File.separator + fileName;

        return iconName.substring(uploadPath.length()).replace(File.separatorChar, '/');
    }

    // 경로 설정처리
    private static String calcPath(String uploadPath) {
        Calendar cal = Calendar.getInstance();

        // 년도 설정
        String yearPath = File.separator + cal.get(Calendar.YEAR);

        // 월 설정
        String monthPath = yearPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.MONTH) + 1);

        // 날짜 ㄱ설정
        String datePath = monthPath + File.separator + new DecimalFormat("00").format(cal.get(Calendar.DATE));
        
     S3Util s3 = new S3Util();
     String bucketName = "faint1122";


        // 폴더 생성 호출
//      makeDir(uploadPath, yearPath, monthPath, datePath);
//
//      logger.info(datePath);

        return datePath;
    }

    //폴더 생성 처리
    private static void makeDir(String uploadPath, String... paths) {
        
        //중복 파일 존재하면 아무처리 하지 않음
        if (new File(paths[paths.length - 1]).exists()) {
            return;
        }

        for (String path : paths) {
            
            File dirPath = new File(uploadPath + path);
            
            if (!dirPath.exists()) {
                dirPath.mkdir();
            }
        }
    }

    //썸네일 생성
    private static String makeThumbnail(String uploadPath, String path, String fileName) throws Exception {

        BufferedImage sourceImg = ImageIO.read(new File(uploadPath + path, fileName));
    
        BufferedImage destImg = Scalr.resize(sourceImg, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_TO_WIDTH, 600);
        String thumbnailName = uploadPath + path + File.separator + "s_" + fileName;

        File newFile = new File(thumbnailName);
        String formatName = fileName.substring(fileName.lastIndexOf(".") + 1);

        ImageIO.write(destImg, formatName.toUpperCase(), newFile);
        return thumbnailName.substring(uploadPath.length()).replace(File.separatorChar, '/');
    }
}


3.UploadController.java

@Controller
public class UploadController {
    
S3Util s3 = new S3Util();
String bucketName = "faint1122";
    
    @Resource(name="uploadPath")
    private String uploadPath;
    
    private static final Logger logger = LoggerFactory.getLogger(UploadController.class);
    @RequestMapping(value ="/uploadAjax", method =RequestMethod.GET)
    public void uploadAjax(){
        
    }
    //서버에 파일 업로드
    @ResponseBody
    @RequestMapping(value ="/uploadAjax", method = RequestMethod.POST, produces = "text/plain;charset=UTF-8")
    public ResponseEntity<String> uploadAjax(MultipartFile file, HttpSession session) throws Exception{
        logger.info("originalName: " + file.getOriginalFilename());
        logger.info("size : " + file.getSize());
        logger.info("contentType : " + file.getContentType());
        UserVO vo = (UserVO)session.getAttribute("login");
        String userid = vo.getNickname();
        return new ResponseEntity<>(
                UploadFileUtils.uploadFile(uploadPath, file.getOriginalFilename(), file.getBytes(), userid),
                HttpStatus.CREATED);
    }
    
    //파일 표시
@ResponseBody
@RequestMapping("/displayFile")
public ResponseEntity<byte[]> displayFile(String fileName)throws Exception{

InputStream in = null;
ResponseEntity<byte[]> entity = null;
HttpURLConnection uCon = null;
System.out.println("FILE NAME: " + fileName);

//System.out.println("FileName : "+fileName);

try{
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);

MediaType mType = MediaUtils.getMediaType(formatName);
HttpHeaders headers = new HttpHeaders();

String inputDirectory = "faint1122";
URL url;

try {
url = new URL(s3.getFileURL(bucketName, inputDirectory+fileName));
System.out.println(url);
uCon = (HttpURLConnection) url.openConnection();
in = uCon.getInputStream(); // 이미지를 불러옴
} catch (Exception e) {
url = new URL(s3.getFileURL(bucketName, "default.jpg"));
uCon = (HttpURLConnection) url.openConnection();
in = uCon.getInputStream();
}

                                                // 여기
entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in),
headers,
HttpStatus.CREATED);
}catch (FileNotFoundException effe){
System.out.println("File Not found Exception");
String formatName = fileName.substring(fileName.lastIndexOf(".")+1);
MediaType mType = MediaUtils.getMediaType(formatName);
HttpHeaders headers = new HttpHeaders();
in = new FileInputStream(uploadPath+"/noimage.jpeg");

headers.setContentType(mType);

entity = new ResponseEntity<byte[]>(IOUtils.toByteArray(in),
headers,
HttpStatus.CREATED);
}catch (Exception e){
e.printStackTrace();
entity = new ResponseEntity<byte[]>(HttpStatus.BAD_REQUEST);
}finally {
in.close();
}
return entity;
}

    
    //파일 삭제
    @ResponseBody
    @RequestMapping(value="/deleteFile", method=RequestMethod.POST)
    public ResponseEntity<String> deleteFile(String fileName){
        logger.info("delete file: "+fileName);
        
        String inputDirectory = "faint1122";
s3.fileDelete(inputDirectory+fileName);
        
        return new ResponseEntity<String>("deleted", HttpStatus.OK);
    }
}


servelt-context.xml


    <!-- 업로드 패스 설정 -->
     <beans:bean class="java.lang.String" id="uploadPath">

    <beans:constructor-arg value="faint1122"> </beans:constructor-arg>

</beans:bean>
    



이런식으로  Url: 로 읽어 온다


버킷 확인 -> 업로드 잘되었는지 확인