Skip to content

Commit

Permalink
Merge pull request #46 from 7th-UMC/feature/45
Browse files Browse the repository at this point in the history
Feat : s3설정, 이미지 업로드 api 추가
  • Loading branch information
hyeonda02 authored Aug 28, 2024
2 parents 362a29b + 6f2aee9 commit 39a3c71
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 1 deletion.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/hsu/umc/server/aws/s3/AmazonS3Manager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package hsu.umc.server.aws.s3;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import hsu.umc.server.config.AmazonConfig;
import hsu.umc.server.entity.Uuid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Slf4j
@Component
@RequiredArgsConstructor
public class AmazonS3Manager {
private final AmazonS3 amazonS3;
private final AmazonConfig amazonConfig;
public String uploadFile(String keyName, MultipartFile file)throws IOException {
System.out.println(keyName);
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(file.getSize());
amazonS3.putObject(new PutObjectRequest(amazonConfig.getBucket(), keyName, file.getInputStream(), metadata));
return amazonS3.getUrl(amazonConfig.getBucket(),keyName).toString();
}
public String generatePhotoKeyName(Uuid uuid) {
return amazonConfig.getPhotoPath() + '/' + uuid.getUuid();
}
}
51 changes: 51 additions & 0 deletions src/main/java/hsu/umc/server/config/AmazonConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package hsu.umc.server.config;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@Getter
public class AmazonConfig {

private AWSCredentials awsCredentials;

@Value("${cloud.aws.credentials.accessKey}")
private String accesskey;
@Value("${cloud.aws.credentials.secretKey}")
private String secretKey;
@Value("${cloud.aws.region.static}")
private String region;
@Value("${cloud.aws.s3.bucket}")
private String bucket;


@Value("${cloud.aws.s3.path.photo}")
private String photoPath;

@PostConstruct
public void init(){
this.awsCredentials = new BasicAWSCredentials(accesskey, secretKey);
}
@Bean
public AmazonS3 amazonS3() {
AWSCredentials awsCredentials = new BasicAWSCredentials(accesskey, secretKey);
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}

@Bean
public AWSCredentialsProvider awsCredentialsProvider(){
return new AWSStaticCredentialsProvider(awsCredentials);
}
}
12 changes: 12 additions & 0 deletions src/main/java/hsu/umc/server/converter/PhotoConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package hsu.umc.server.converter;

import hsu.umc.server.entity.Photo;
import hsu.umc.server.web.dto.PhotoResponseDto;

public class PhotoConverter {
public static PhotoResponseDto.CreatePhotoResultDto toCreatePhotoResultDto(Photo photo){
return PhotoResponseDto.CreatePhotoResultDto.builder()
.photoUrl(photo.getPhotoUrl())
.build();
}
}
20 changes: 20 additions & 0 deletions src/main/java/hsu/umc/server/entity/Photo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package hsu.umc.server.entity;


import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.*;

@Entity
@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Photo extends BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String photoUrl;

}
16 changes: 16 additions & 0 deletions src/main/java/hsu/umc/server/entity/Uuid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package hsu.umc.server.entity;

import jakarta.persistence.*;
import lombok.*;

@Entity
@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Uuid extends BaseEntity{
@Id @GeneratedValue(strategy = GenerationType.IDENTITY )
private Long id;
@Column(unique = true)
private String uuid;
}
7 changes: 7 additions & 0 deletions src/main/java/hsu/umc/server/repository/PhotoRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package hsu.umc.server.repository;

import hsu.umc.server.entity.Photo;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PhotoRepository extends JpaRepository<Photo, Long> {
}
7 changes: 7 additions & 0 deletions src/main/java/hsu/umc/server/repository/UuidRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package hsu.umc.server.repository;

import hsu.umc.server.entity.Uuid;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UuidRepository extends JpaRepository<Uuid, Long> {
}
9 changes: 9 additions & 0 deletions src/main/java/hsu/umc/server/service/PhotoCommandService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hsu.umc.server.service;

import hsu.umc.server.entity.Photo;
import org.springframework.web.multipart.MultipartFile;


public interface PhotoCommandService {
Photo createPhoto(MultipartFile request);
}
41 changes: 41 additions & 0 deletions src/main/java/hsu/umc/server/service/PhotoCommandServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package hsu.umc.server.service;

import hsu.umc.server.aws.s3.AmazonS3Manager;
import hsu.umc.server.entity.Photo;
import hsu.umc.server.entity.Uuid;
import hsu.umc.server.repository.PhotoRepository;
import hsu.umc.server.repository.UuidRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class PhotoCommandServiceImpl implements PhotoCommandService{
private final AmazonS3Manager s3Manager;
private final UuidRepository uuidRepository;
private final PhotoRepository photoRepository;
@Override
@Transactional
public Photo createPhoto(MultipartFile photoPicture) {
String uuid = UUID.randomUUID().toString();
Uuid savedUuid = uuidRepository.save(Uuid.builder().uuid(uuid).build());
String pictureUrl = null;
try {
pictureUrl = s3Manager.uploadFile(s3Manager.generatePhotoKeyName(savedUuid), photoPicture);
} catch (IOException e) {
throw new RuntimeException(e);
}

Photo photo = Photo.builder()
.photoUrl(pictureUrl)
.build();

return photoRepository.save(photo);
}
}
29 changes: 29 additions & 0 deletions src/main/java/hsu/umc/server/web/controller/PhotoController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package hsu.umc.server.web.controller;

import hsu.umc.server.apipayload.ApiResponse;
import hsu.umc.server.converter.PhotoConverter;
import hsu.umc.server.entity.Photo;
import hsu.umc.server.service.PhotoCommandService;
import hsu.umc.server.web.dto.PhotoResponseDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


@RestController
@RequestMapping("/api/photo")
@RequiredArgsConstructor
@Tag(name="photo",description = "네컷사진 관련 API")
public class PhotoController {
private final PhotoCommandService photoCommandService;
@PostMapping(value = "/",consumes = "multipart/form-data")
@Operation(summary = "네컷 사진 저장", description = "제공된 사진을 저장하고 url을 반환합니다.")
public ApiResponse<PhotoResponseDto.CreatePhotoResultDto> createPhoto(
@RequestPart("photoPicture") MultipartFile photoPicture) {
Photo photo = photoCommandService.createPhoto(photoPicture);
return ApiResponse.onSuccess(PhotoConverter.toCreatePhotoResultDto(photo));
}

}
16 changes: 16 additions & 0 deletions src/main/java/hsu/umc/server/web/dto/PhotoResponseDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package hsu.umc.server.web.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

public class PhotoResponseDto {
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CreatePhotoResultDto{
private String photoUrl;
}
}
14 changes: 14 additions & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,17 @@ spring:
allowed-headers: "*"
allow-credentials: true

cloud:
aws:
s3:
bucket: umc-7th
path:
photo : photos
region:
static: ap-northeast-2
stack:
auto: false
credentials:
accessKey: ${aws.access.key.id}
secretKey: ${aws.secret.access.key}

16 changes: 15 additions & 1 deletion src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,18 @@ spring:
format_sql: true
use_sql_comments: true
hbm2ddl:
auto: update
auto: update

cloud:
aws:
s3:
bucket: umc-7th
path:
photo : photos
region:
static: ap-northeast-2
stack:
auto: false
credentials:
accessKey: ${aws.access.key.id}
secretKey: ${aws.secret.access.key}

0 comments on commit 39a3c71

Please sign in to comment.