Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,22 @@ dependencies {
implementation group: 'org.springdoc', name: 'springdoc-openapi-starter-webmvc-ui', version: '2.1.0'
}

// GPT
implementation 'io.github.flashvayne:chatgpt-spring-boot-starter:1.0.4'


// Amazon S3
implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.1000')
implementation 'com.amazonaws:aws-java-sdk-s3'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

implementation 'org.projectlombok:lombok:1.18.28'

implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation "io.netty:netty-all:4.1.68.Final"
implementation "io.netty:netty-resolver-dns-native-macos:4.1.68.Final"
implementation "io.projectreactor.netty:reactor-netty-core:1.1.0"
implementation "io.projectreactor.netty:reactor-netty-http:1.1.0"

annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/movelog/MoveLogApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
@PropertySource(value = { "classpath:oauth2/application-oauth2.yml" }, factory = YamlPropertySourceFactory.class)
@PropertySource(value = { "classpath:database/application-database.yml" }, factory = YamlPropertySourceFactory.class)
@PropertySource(value = { "classpath:swagger/application-springdoc.yml" }, factory = YamlPropertySourceFactory.class)
//@PropertySource(value = { "classpath:s3/application-s3.yml" }, factory = YamlPropertySourceFactory.class)
@PropertySource(value = { "classpath:s3/application-s3.yml" }, factory = YamlPropertySourceFactory.class)
@PropertySource(value = { "classpath:chatgpt/application-chatgpt.yml" }, factory = YamlPropertySourceFactory.class)
@PropertySource(value = { "classpath:webclient/application-webclient.yml" }, factory = YamlPropertySourceFactory.class)
public class MoveLogApplication {

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

}
14 changes: 7 additions & 7 deletions src/main/java/com/movelog/domain/common/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public class BaseEntity {
@Column(name = "updated_at")
private LocalDateTime updatedAt;

// @Enumerated(value = EnumType.STRING)
// @Column(name = "status")
// private Status status = Status.ACTIVE;
//
// public void updateStatus(Status status) {
// this.status = status;
// }
@Enumerated(value = EnumType.STRING)
@Column(name = "status")
private Status status = Status.ACTIVE;

public void updateStatus(Status status) {
this.status = status;
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/movelog/domain/common/Status.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.movelog.domain.common;

public enum Status {
ACTIVE, DELETE
}
32 changes: 32 additions & 0 deletions src/main/java/com/movelog/domain/record/domain/Keyword.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.movelog.domain.record.domain;

import com.movelog.domain.common.BaseEntity;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "Keyword")
@NoArgsConstructor
@Getter
public class Keyword extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "keyword_id", updatable = false)
private Long keywordId;

private String keyword;

@OneToMany(mappedBy = "keyword")
private List<Record> records = new ArrayList<>();

@Builder
public Keyword(String keyword) {
this.keyword = keyword;
}
}
51 changes: 51 additions & 0 deletions src/main/java/com/movelog/domain/record/domain/Record.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.movelog.domain.record.domain;

import com.movelog.domain.common.BaseEntity;
import com.movelog.domain.user.domain.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.joda.time.LocalDateTime;

@Entity
@Table(name = "Record")
@NoArgsConstructor
@Getter
public class Record extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "record_id", updatable = false)
private Long recordId;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "keyword_id")
private Keyword keyword;

@Enumerated(value = EnumType.STRING)
@Column(name = "verb_type")
private VerbType recordType;

@Column(name = "record_image")
private String recordImage;

@Column(name = "action_time")
private LocalDateTime actionTime;

@Builder
public Record(User user, Keyword keyword, VerbType recordType, String recordImage) {
this.user = user;
this.keyword = keyword;
this.recordType = recordType;
this.recordImage = recordImage;
this.actionTime = actionTime == null? LocalDateTime.now():actionTime;
}



}
6 changes: 6 additions & 0 deletions src/main/java/com/movelog/domain/record/domain/VerbType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.movelog.domain.record.domain;

public enum VerbType {
// 했어요, 먹었어요, 갔어요
DO, EAT, GO
}
4 changes: 4 additions & 0 deletions src/main/java/com/movelog/domain/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.movelog.domain.common.BaseEntity;

import com.movelog.domain.record.domain.Record;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
Expand Down Expand Up @@ -38,6 +39,9 @@ public class User extends BaseEntity {

private String fcmToken;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Record> records = new ArrayList<>();


@Builder
public User(String nickname, String username, String email, String role, String provider, String providerId) {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/movelog/global/config/WebClientConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.movelog.global.config;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

@Value("${chatgpt.url}")
private String gptUrl;

@Bean
public WebClient gptWebClient() {
return createWebClient(gptUrl);
}

private WebClient createWebClient(String baseUrl) {
return WebClient.builder()
.baseUrl(baseUrl)
.codecs(configurer -> configurer
.defaultCodecs()
.maxInMemorySize(1000 * 1024 * 1024))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.movelog.global.config.security;


import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AmazonS3Config {

@Value("${cloud.aws.credentials.access-key}")
private String awsAccessKeyId;

@Value("${cloud.aws.credentials.secret-key}")
private String awsSecretKey;

@Value("${cloud.aws.region.static}")
private String awsRegion;

@Value("${cloud.aws.s3.bucketName}")
private String bucketName;

@Bean
public AmazonS3 amazonS3() {
BasicAWSCredentials awsCredentials = new BasicAWSCredentials(awsAccessKeyId, awsSecretKey);
return AmazonS3ClientBuilder.standard()
.withRegion(awsRegion)
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.build();
}

@Bean
public String bucketName() {
return bucketName;
}
}
105 changes: 105 additions & 0 deletions src/main/java/com/movelog/global/util/S3Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.movelog.global.util;



import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.DeleteObjectRequest;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import jakarta.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
public class S3Util {

private final AmazonS3 s3Client;

@Value("${cloud.aws.credentials.access-key}")
private String accessKey;

@Value("${cloud.aws.credentials.secret-key}")
private String secretKey;

@Value("${cloud.aws.s3.bucketName}")
private String bucket;

@Value("${cloud.aws.region.static}")
private String region;

@PostConstruct
public AmazonS3Client amazonS3Client() {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
return (AmazonS3Client)AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.build();
}

public String upload(MultipartFile file) {
String imageUrl = "";
String fileName = createFileName(file.getOriginalFilename());
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(file.getSize());
objectMetadata.setContentType(file.getContentType());

try (InputStream inputStream = file.getInputStream()) {
s3Client.putObject(new PutObjectRequest(bucket, fileName, inputStream, objectMetadata)
.withCannedAcl(CannedAccessControlList.PublicRead));
imageUrl = s3Client.getUrl(bucket, fileName).toString();
} catch (IOException e) {
throw new IllegalArgumentException("IMAGE_UPLOAD_ERROR");
}
return imageUrl;
}

// 이미지파일명 중복 방지
private String createFileName(String fileName) {
return UUID.randomUUID().toString().concat(getFileExtension(fileName));
}

// 파일 유효성 검사
private String getFileExtension(String fileName) {
if (fileName.length() == 0) {
throw new IllegalArgumentException("IMAGE_UPLOAD_ERROR");
}
ArrayList<String> fileValidate = new ArrayList<>();
fileValidate.add(".jpg");
fileValidate.add(".jpeg");
fileValidate.add(".png");
fileValidate.add(".JPG");
fileValidate.add(".JPEG");
fileValidate.add(".PNG");
fileValidate.add(".mp4");
String idxFileName = fileName.substring(fileName.lastIndexOf("."));
if (!fileValidate.contains(idxFileName)) {
throw new IllegalArgumentException("IMAGE_UPLOAD_ERROR");
}
return fileName.substring(fileName.lastIndexOf("."));
}

// DeleteObject를 통해 S3 파일 삭제
public void deleteFile(String fileName) {
String objectKey = parseObjectKeyFromUrl(fileName);
// 삭제
DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(bucket, objectKey);
s3Client.deleteObject(deleteObjectRequest);
}

private String parseObjectKeyFromUrl(String objectUrl) {
return objectUrl.substring(objectUrl.lastIndexOf('/') + 1);
}

}