diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/checksums/checksums.lock b/.gradle/8.10/checksums/checksums.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/dependencies-accessors/gc.properties b/.gradle/8.10/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/executionHistory/executionHistory.lock b/.gradle/8.10/executionHistory/executionHistory.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/fileChanges/last-build.bin b/.gradle/8.10/fileChanges/last-build.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/fileHashes/fileHashes.lock b/.gradle/8.10/fileHashes/fileHashes.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10/gc.properties b/.gradle/8.10/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/checksums/checksums.lock b/.gradle/8.13/checksums/checksums.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/executionHistory/executionHistory.bin b/.gradle/8.13/executionHistory/executionHistory.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/executionHistory/executionHistory.lock b/.gradle/8.13/executionHistory/executionHistory.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/fileChanges/last-build.bin b/.gradle/8.13/fileChanges/last-build.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/fileHashes/resourceHashesCache.bin b/.gradle/8.13/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.13/gc.properties b/.gradle/8.13/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..c3f502a --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 디폴트 무시된 파일 +/shelf/ +/workspace.xml +# 에디터 기반 HTTP 클라이언트 요청 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b453fa5 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..bc16866 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,31 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306 + + + + + + $ProjectFileDir$ + + + mysql.8 + true + true + $PROJECT_DIR$/src/main/resources/application.yml + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306/study + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..4568975 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c049206 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..69a5b1e --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/spring.main.iml b/.idea/modules/spring.main.iml new file mode 100644 index 0000000..ded96ef --- /dev/null +++ b/.idea/modules/spring.main.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/HELP.md b/HELP.md new file mode 100644 index 0000000..ec679ff --- /dev/null +++ b/HELP.md @@ -0,0 +1,25 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Gradle documentation](https://docs.gradle.org) +* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.3.11/gradle-plugin) +* [Create an OCI image](https://docs.spring.io/spring-boot/3.3.11/gradle-plugin/packaging-oci-image.html) +* [Spring Web](https://docs.spring.io/spring-boot/3.3.11/reference/web/servlet.html) +* [Spring Data JPA](https://docs.spring.io/spring-boot/3.3.11/reference/data/sql.html#data.sql.jpa-and-spring-data) + +### Guides +The following guides illustrate how to use some features concretely: + +* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) +* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) +* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) +* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) +* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/) + +### Additional Links +These additional references should also help you: + +* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle) + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..65c91ad --- /dev/null +++ b/build.gradle @@ -0,0 +1,64 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.3.11' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'com.example' +version = '0.0.1-SNAPSHOT' +sourceCompatibility = '17' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } +} + +repositories { + mavenCentral() +} + +dependencies { + // Spring Boot + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' // 명시적 추가 + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + // Lombok + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + // MySQL + runtimeOnly 'com.mysql:mysql-connector-j' + + // QueryDSL (jakarta 버전, Hibernate 6 이상 호환) + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' + annotationProcessor 'jakarta.annotation:jakarta.annotation-api' + annotationProcessor 'jakarta.persistence:jakarta.persistence-api' + + // 테스트 + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +sourceSets { + main { + java { + srcDirs = ['src/main/java', 'src/main/resources'] + } + } +} + +tasks.named('test') { + useJUnitPlatform() +} \ No newline at end of file diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QFoodCategory.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QFoodCategory.java new file mode 100644 index 0000000..2559586 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QFoodCategory.java @@ -0,0 +1,47 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QFoodCategory is a Querydsl query type for FoodCategory + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QFoodCategory extends EntityPathBase { + + private static final long serialVersionUID = -1774211307L; + + public static final QFoodCategory foodCategory = new QFoodCategory("foodCategory"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final StringPath name = createString("name"); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QFoodCategory(String variable) { + super(FoodCategory.class, forVariable(variable)); + } + + public QFoodCategory(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QFoodCategory(PathMetadata metadata) { + super(FoodCategory.class, metadata); + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMember.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMember.java new file mode 100644 index 0000000..2827182 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMember.java @@ -0,0 +1,72 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QMember is a Querydsl query type for Member + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMember extends EntityPathBase { + + private static final long serialVersionUID = -1016450829L; + + public static final QMember member = new QMember("member1"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + public final StringPath address = createString("address"); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final StringPath email = createString("email"); + + public final EnumPath gender = createEnum("gender", com.example.domain.enums.Gender.class); + + public final NumberPath id = createNumber("id", Long.class); + + public final DatePath inactiveDate = createDate("inactiveDate", java.time.LocalDate.class); + + public final ListPath memberAgreeList = this.createList("memberAgreeList", com.example.domain.mapping.MemberAgree.class, com.example.domain.mapping.QMemberAgree.class, PathInits.DIRECT2); + + public final ListPath memberMissionList = this.createList("memberMissionList", com.example.domain.mapping.MemberMission.class, com.example.domain.mapping.QMemberMission.class, PathInits.DIRECT2); + + public final ListPath memberPreferList = this.createList("memberPreferList", com.example.domain.mapping.MemberPrefer.class, com.example.domain.mapping.QMemberPrefer.class, PathInits.DIRECT2); + + public final StringPath name = createString("name"); + + public final NumberPath point = createNumber("point", Integer.class); + + public final ListPath reviewList = this.createList("reviewList", Review.class, QReview.class, PathInits.DIRECT2); + + public final EnumPath socialType = createEnum("socialType", com.example.domain.enums.SocialType.class); + + public final StringPath specAddress = createString("specAddress"); + + public final EnumPath status = createEnum("status", com.example.domain.enums.MemberStatus.class); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QMember(String variable) { + super(Member.class, forVariable(variable)); + } + + public QMember(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QMember(PathMetadata metadata) { + super(Member.class, metadata); + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMission.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMission.java new file mode 100644 index 0000000..b5abb4f --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QMission.java @@ -0,0 +1,70 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QMission is a Querydsl query type for Mission + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMission extends EntityPathBase { + + private static final long serialVersionUID = -1324636589L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QMission mission = new QMission("mission"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final DatePath deadline = createDate("deadline", java.time.LocalDate.class); + + public final NumberPath id = createNumber("id", Long.class); + + public final QMember member; + + public final ListPath memberMissionList = this.createList("memberMissionList", com.example.domain.mapping.MemberMission.class, com.example.domain.mapping.QMemberMission.class, PathInits.DIRECT2); + + public final StringPath missionSpec = createString("missionSpec"); + + public final NumberPath reward = createNumber("reward", Integer.class); + + public final QStore store; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QMission(String variable) { + this(Mission.class, forVariable(variable), INITS); + } + + public QMission(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QMission(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QMission(PathMetadata metadata, PathInits inits) { + this(Mission.class, metadata, inits); + } + + public QMission(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new QMember(forProperty("member")) : null; + this.store = inits.isInitialized("store") ? new QStore(forProperty("store"), inits.get("store")) : null; + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QRegion.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QRegion.java new file mode 100644 index 0000000..7e64716 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QRegion.java @@ -0,0 +1,47 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QRegion is a Querydsl query type for Region + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QRegion extends EntityPathBase { + + private static final long serialVersionUID = -873476787L; + + public static final QRegion region = new QRegion("region"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final StringPath name = createString("name"); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QRegion(String variable) { + super(Region.class, forVariable(variable)); + } + + public QRegion(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QRegion(PathMetadata metadata) { + super(Region.class, metadata); + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QReview.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QReview.java new file mode 100644 index 0000000..a5ab4aa --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QReview.java @@ -0,0 +1,66 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QReview is a Querydsl query type for Review + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QReview extends EntityPathBase { + + private static final long serialVersionUID = -873030223L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QReview review = new QReview("review"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final QMember member; + + public final NumberPath score = createNumber("score", Float.class); + + public final QStore store; + + public final StringPath title = createString("title"); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QReview(String variable) { + this(Review.class, forVariable(variable), INITS); + } + + public QReview(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QReview(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QReview(PathMetadata metadata, PathInits inits) { + this(Review.class, metadata, inits); + } + + public QReview(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new QMember(forProperty("member")) : null; + this.store = inits.isInitialized("store") ? new QStore(forProperty("store"), inits.get("store")) : null; + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QStore.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QStore.java new file mode 100644 index 0000000..f43706e --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QStore.java @@ -0,0 +1,69 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QStore is a Querydsl query type for Store + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QStore extends EntityPathBase { + + private static final long serialVersionUID = -996629656L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QStore store = new QStore("store"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + public final StringPath address = createString("address"); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final ListPath missionList = this.createList("missionList", Mission.class, QMission.class, PathInits.DIRECT2); + + public final StringPath name = createString("name"); + + public final QRegion region; + + public final ListPath reviewList = this.createList("reviewList", Review.class, QReview.class, PathInits.DIRECT2); + + public final NumberPath score = createNumber("score", Float.class); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QStore(String variable) { + this(Store.class, forVariable(variable), INITS); + } + + public QStore(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QStore(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QStore(PathMetadata metadata, PathInits inits) { + this(Store.class, metadata, inits); + } + + public QStore(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.region = inits.isInitialized("region") ? new QRegion(forProperty("region")) : null; + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/QTerms.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QTerms.java new file mode 100644 index 0000000..92a430f --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/QTerms.java @@ -0,0 +1,54 @@ +package com.example.domain; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QTerms is a Querydsl query type for Terms + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QTerms extends EntityPathBase { + + private static final long serialVersionUID = -996150258L; + + public static final QTerms terms = new QTerms("terms"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + public final StringPath body = createString("body"); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final ListPath memberAgreeList = this.createList("memberAgreeList", com.example.domain.mapping.MemberAgree.class, com.example.domain.mapping.QMemberAgree.class, PathInits.DIRECT2); + + public final BooleanPath optional = createBoolean("optional"); + + public final StringPath title = createString("title"); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QTerms(String variable) { + super(Terms.class, forVariable(variable)); + } + + public QTerms(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QTerms(PathMetadata metadata) { + super(Terms.class, metadata); + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/common/QBaseEntity.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/common/QBaseEntity.java new file mode 100644 index 0000000..b2097d3 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/common/QBaseEntity.java @@ -0,0 +1,39 @@ +package com.example.domain.common; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; + + +/** + * QBaseEntity is a Querydsl query type for BaseEntity + */ +@Generated("com.querydsl.codegen.DefaultSupertypeSerializer") +public class QBaseEntity extends EntityPathBase { + + private static final long serialVersionUID = 118984254L; + + public static final QBaseEntity baseEntity = new QBaseEntity("baseEntity"); + + public final DateTimePath createdAt = createDateTime("createdAt", java.time.LocalDateTime.class); + + public final DateTimePath updatedAt = createDateTime("updatedAt", java.time.LocalDateTime.class); + + public QBaseEntity(String variable) { + super(BaseEntity.class, forVariable(variable)); + } + + public QBaseEntity(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QBaseEntity(PathMetadata metadata) { + super(BaseEntity.class, metadata); + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberAgree.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberAgree.java new file mode 100644 index 0000000..f9b564e --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberAgree.java @@ -0,0 +1,62 @@ +package com.example.domain.mapping; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QMemberAgree is a Querydsl query type for MemberAgree + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMemberAgree extends EntityPathBase { + + private static final long serialVersionUID = 1811719513L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QMemberAgree memberAgree = new QMemberAgree("memberAgree"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final com.example.domain.QMember member; + + public final com.example.domain.QTerms terms; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QMemberAgree(String variable) { + this(MemberAgree.class, forVariable(variable), INITS); + } + + public QMemberAgree(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QMemberAgree(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QMemberAgree(PathMetadata metadata, PathInits inits) { + this(MemberAgree.class, metadata, inits); + } + + public QMemberAgree(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new com.example.domain.QMember(forProperty("member")) : null; + this.terms = inits.isInitialized("terms") ? new com.example.domain.QTerms(forProperty("terms")) : null; + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberMission.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberMission.java new file mode 100644 index 0000000..171a8e1 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberMission.java @@ -0,0 +1,64 @@ +package com.example.domain.mapping; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QMemberMission is a Querydsl query type for MemberMission + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMemberMission extends EntityPathBase { + + private static final long serialVersionUID = -575554311L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QMemberMission memberMission = new QMemberMission("memberMission"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final NumberPath id = createNumber("id", Long.class); + + public final com.example.domain.QMember member; + + public final com.example.domain.QMission mission; + + public final EnumPath status = createEnum("status", com.example.domain.enums.MissionStatus.class); + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QMemberMission(String variable) { + this(MemberMission.class, forVariable(variable), INITS); + } + + public QMemberMission(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QMemberMission(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QMemberMission(PathMetadata metadata, PathInits inits) { + this(MemberMission.class, metadata, inits); + } + + public QMemberMission(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.member = inits.isInitialized("member") ? new com.example.domain.QMember(forProperty("member")) : null; + this.mission = inits.isInitialized("mission") ? new com.example.domain.QMission(forProperty("mission"), inits.get("mission")) : null; + } + +} + diff --git a/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberPrefer.java b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberPrefer.java new file mode 100644 index 0000000..65ec1e0 --- /dev/null +++ b/build/generated/sources/annotationProcessor/java/main/com/example/domain/mapping/QMemberPrefer.java @@ -0,0 +1,62 @@ +package com.example.domain.mapping; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.processing.Generated; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.PathInits; + + +/** + * QMemberPrefer is a Querydsl query type for MemberPrefer + */ +@Generated("com.querydsl.codegen.DefaultEntitySerializer") +public class QMemberPrefer extends EntityPathBase { + + private static final long serialVersionUID = 767939843L; + + private static final PathInits INITS = PathInits.DIRECT2; + + public static final QMemberPrefer memberPrefer = new QMemberPrefer("memberPrefer"); + + public final com.example.domain.common.QBaseEntity _super = new com.example.domain.common.QBaseEntity(this); + + //inherited + public final DateTimePath createdAt = _super.createdAt; + + public final com.example.domain.QFoodCategory foodCategory; + + public final NumberPath id = createNumber("id", Long.class); + + public final com.example.domain.QMember member; + + //inherited + public final DateTimePath updatedAt = _super.updatedAt; + + public QMemberPrefer(String variable) { + this(MemberPrefer.class, forVariable(variable), INITS); + } + + public QMemberPrefer(Path path) { + this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS)); + } + + public QMemberPrefer(PathMetadata metadata) { + this(metadata, PathInits.getFor(metadata, INITS)); + } + + public QMemberPrefer(PathMetadata metadata, PathInits inits) { + this(MemberPrefer.class, metadata, inits); + } + + public QMemberPrefer(Class type, PathMetadata metadata, PathInits inits) { + super(type, metadata, inits); + this.foodCategory = inits.isInitialized("foodCategory") ? new com.example.domain.QFoodCategory(forProperty("foodCategory")) : null; + this.member = inits.isInitialized("member") ? new com.example.domain.QMember(forProperty("member")) : null; + } + +} + diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html new file mode 100644 index 0000000..e69de29 diff --git a/build/resources/main/application.yml b/build/resources/main/application.yml new file mode 100644 index 0000000..e69de29 diff --git a/build/resources/main/data.sql b/build/resources/main/data.sql new file mode 100644 index 0000000..e69de29 diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin new file mode 100644 index 0000000..e69de29 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..9bbc975 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f853b --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..e69de29 diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e69de29 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..ebf1ef8 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'spring' diff --git a/src/main/java/com/example/Application.java b/src/main/java/com/example/Application.java new file mode 100644 index 0000000..23a4912 --- /dev/null +++ b/src/main/java/com/example/Application.java @@ -0,0 +1,17 @@ +package com.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@SpringBootApplication +//@EnableJpaAuditing +@EntityScan(basePackages = "com.example.domain") +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/src/main/java/com/example/StudyApplication.java b/src/main/java/com/example/StudyApplication.java new file mode 100644 index 0000000..08f409f --- /dev/null +++ b/src/main/java/com/example/StudyApplication.java @@ -0,0 +1,36 @@ +//package com.example; +// +//import com.example.service.StoreService.StoreQueryService; +//import org.springframework.boot.CommandLineRunner; +//import org.springframework.boot.SpringApplication; +//import org.springframework.boot.autoconfigure.SpringBootApplication; +//import org.springframework.context.ApplicationContext; +//import org.springframework.context.annotation.Bean; +//import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +// +//@SpringBootApplication +//@EnableJpaAuditing +//public class StudyApplication { +// public static void main(String[] args) { +// SpringApplication.run(StudyApplication.class, args); +// } +// +// @Bean +// public CommandLineRunner run(ApplicationContext context) { +// return args -> { +// StoreQueryService storeService = context.getBean(StoreQueryService.class); +// +// // 파라미터 값 설정 +// String name = "요아정"; +// Float score = 4.0f; +// +// // 쿼리 메서드 호출 및 쿼리 문자열과 파라미터 출력 +// System.out.println("Executing findStoresByNameAndScore with parameters:"); +// System.out.println("Name: " + name); +// System.out.println("Score: " + score); +// +// storeService.findStoresByNameAndScore(name, score) +// .forEach(System.out::println); +// }; +// } +//} diff --git a/src/main/java/com/example/apiPayload/ApiResponse.java b/src/main/java/com/example/apiPayload/ApiResponse.java new file mode 100644 index 0000000..6be8217 --- /dev/null +++ b/src/main/java/com/example/apiPayload/ApiResponse.java @@ -0,0 +1,38 @@ +package com.example.apiPayload; + +import com.example.apiPayload.code.status.SuccessStatus; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +public class ApiResponse { + + @JsonProperty("isSuccess") + private final Boolean isSuccess; + private final String code; + private final String message; + @JsonInclude(JsonInclude.Include.NON_NULL) + private T result; + + + // 성공한 경우 응답 생성 + + public static ApiResponse onSuccess(T result){ + return new ApiResponse<>(true, SuccessStatus._OK.getCode() , SuccessStatus._OK.getMessage(), result); + } + + public static ApiResponse of(BaseCode code, T result){ + return new ApiResponse<>(true, code.getReasonHttpStatus().getCode() , code.getReasonHttpStatus().getMessage(), result); + } + + + // 실패한 경우 응답 생성 + public static ApiResponse onFailure(String code, String message, T data){ + return new ApiResponse<>(false, code, message, data); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/BaseCode.java b/src/main/java/com/example/apiPayload/BaseCode.java new file mode 100644 index 0000000..e0ba3c7 --- /dev/null +++ b/src/main/java/com/example/apiPayload/BaseCode.java @@ -0,0 +1,10 @@ +package com.example.apiPayload; + +import java.awt.desktop.UserSessionEvent; + +public interface BaseCode { + + ReasonDTO getReason(); + + ReasonDTO getReasonHttpStatus(); +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/BaseErrorCode.java b/src/main/java/com/example/apiPayload/BaseErrorCode.java new file mode 100644 index 0000000..10a9726 --- /dev/null +++ b/src/main/java/com/example/apiPayload/BaseErrorCode.java @@ -0,0 +1,7 @@ +package com.example.apiPayload; + +public interface BaseErrorCode { + ErrorReasonDTO getReason(); + + ErrorReasonDTO getReasonHttpStatus(); +} diff --git a/src/main/java/com/example/apiPayload/ErrorReasonDTO.java b/src/main/java/com/example/apiPayload/ErrorReasonDTO.java new file mode 100644 index 0000000..b9dd976 --- /dev/null +++ b/src/main/java/com/example/apiPayload/ErrorReasonDTO.java @@ -0,0 +1,18 @@ +package com.example.apiPayload; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@Builder +public class ErrorReasonDTO { + + private HttpStatus httpStatus; + + private final boolean isSuccess; + private final String code; + private final String message; + + public boolean getIsSuccess(){return isSuccess;} +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/MemberRequestDTO.java b/src/main/java/com/example/apiPayload/MemberRequestDTO.java new file mode 100644 index 0000000..3a67af0 --- /dev/null +++ b/src/main/java/com/example/apiPayload/MemberRequestDTO.java @@ -0,0 +1,32 @@ +package com.example.apiPayload; + +import com.example.validation.annotation.ExistCategories; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; + +import java.util.List; + +public class MemberRequestDTO { + + @Getter + public static class JoinDto{ + @NotBlank + String name; + @NotNull + Integer gender; + @NotNull + Integer birthYear; + @NotNull + Integer birthMonth; + @NotNull + Integer birthDay; + @Size(min = 5, max = 12) + String address; + @Size(min = 5, max = 12) + String specAddress; + @ExistCategories + List preferCategory; + } +} diff --git a/src/main/java/com/example/apiPayload/MemberResponseDTO.java b/src/main/java/com/example/apiPayload/MemberResponseDTO.java new file mode 100644 index 0000000..1e5ce26 --- /dev/null +++ b/src/main/java/com/example/apiPayload/MemberResponseDTO.java @@ -0,0 +1,19 @@ +package com.example.apiPayload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +public class MemberResponseDTO { + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class JoinResultDTO{ + Long memberId; + LocalDateTime createdAt; + } +} diff --git a/src/main/java/com/example/apiPayload/ReasonDTO.java b/src/main/java/com/example/apiPayload/ReasonDTO.java new file mode 100644 index 0000000..eef5960 --- /dev/null +++ b/src/main/java/com/example/apiPayload/ReasonDTO.java @@ -0,0 +1,18 @@ +package com.example.apiPayload; + +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@Builder +public class ReasonDTO { + + private HttpStatus httpStatus; + + private final boolean isSuccess; + private final String code; + private final String message; + + public boolean getIsSuccess(){return isSuccess;} +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/example/apiPayload/code/status/ErrorStatus.java new file mode 100644 index 0000000..5c33671 --- /dev/null +++ b/src/main/java/com/example/apiPayload/code/status/ErrorStatus.java @@ -0,0 +1,56 @@ +package com.example.apiPayload.code.status; + +import com.example.apiPayload.BaseErrorCode; +import com.example.apiPayload.ErrorReasonDTO; +import com.example.domain.FoodCategory; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ErrorStatus implements BaseErrorCode { + + // 가장 일반적인 응답 + _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500", "서버 에러, 관리자에게 문의 바랍니다."), + _BAD_REQUEST(HttpStatus.BAD_REQUEST,"COMMON400","잘못된 요청입니다."), + _UNAUTHORIZED(HttpStatus.UNAUTHORIZED,"COMMON401","인증이 필요합니다."), + _FORBIDDEN(HttpStatus.FORBIDDEN, "COMMON403", "금지된 요청입니다."), + + // For test + TEMP_EXCEPTION(HttpStatus.BAD_REQUEST, "TEMP4001", "이거는 테스트"), + + // Member Error + MEMBER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MEMBER4001", "사용자가 없습니다."), + NICKNAME_NOT_EXIST(HttpStatus.BAD_REQUEST, "MEMBER4002", "닉네임은 필수 입니다."), + + // Article Error + ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "ARTICLE4001", "게시글이 없습니다."), + + // FoodCategory Error + FOOD_CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "FOOD4001", "해당 음식 카테고리를 찾을 수 없습니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ErrorReasonDTO getReason() { + return ErrorReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(false) + .build(); + } + + @Override + public ErrorReasonDTO getReasonHttpStatus() { + return ErrorReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(false) + .httpStatus(httpStatus) + .build() + ; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/code/status/SuccessStatus.java b/src/main/java/com/example/apiPayload/code/status/SuccessStatus.java new file mode 100644 index 0000000..22ed1d5 --- /dev/null +++ b/src/main/java/com/example/apiPayload/code/status/SuccessStatus.java @@ -0,0 +1,39 @@ +package com.example.apiPayload.code.status; + +import com.example.apiPayload.BaseCode; +import com.example.apiPayload.ReasonDTO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum SuccessStatus implements BaseCode { + + // 일반적인 응답 + _OK(HttpStatus.OK, "COMMON200", "성공입니다."); + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public ReasonDTO getReason() { + return ReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(true) + .build(); + } + + @Override + public ReasonDTO getReasonHttpStatus() { + return ReasonDTO.builder() + .message(message) + .code(code) + .isSuccess(true) + .httpStatus(httpStatus) + .build() + ; + } +} diff --git a/src/main/java/com/example/apiPayload/exception/ExceptionAdvice.java b/src/main/java/com/example/apiPayload/exception/ExceptionAdvice.java new file mode 100644 index 0000000..9c33f74 --- /dev/null +++ b/src/main/java/com/example/apiPayload/exception/ExceptionAdvice.java @@ -0,0 +1,119 @@ +package com.example.apiPayload.exception; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; +import com.example.apiPayload.ApiResponse; +import com.example.apiPayload.ErrorReasonDTO; +import com.example.apiPayload.code.status.ErrorStatus; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + +@Slf4j +@RestControllerAdvice(annotations = {RestController.class}) +public class ExceptionAdvice extends ResponseEntityExceptionHandler { + + + @ExceptionHandler + public ResponseEntity validation(ConstraintViolationException e, WebRequest request) { + String errorMessage = e.getConstraintViolations().stream() + .map(constraintViolation -> constraintViolation.getMessage()) + .findFirst() + .orElseThrow(() -> new RuntimeException("ConstraintViolationException 추출 도중 에러 발생")); + + return handleExceptionInternalConstraint(e, ErrorStatus.valueOf(errorMessage), HttpHeaders.EMPTY,request); + } + + @Override + public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, HttpStatusCode status, WebRequest request) { + + Map errors = new LinkedHashMap<>(); + + e.getBindingResult().getFieldErrors().stream() + .forEach(fieldError -> { + String fieldName = fieldError.getField(); + String errorMessage = Optional.ofNullable(fieldError.getDefaultMessage()).orElse(""); + errors.merge(fieldName, errorMessage, (existingErrorMessage, newErrorMessage) -> existingErrorMessage + ", " + newErrorMessage); + }); + + return handleExceptionInternalArgs(e,HttpHeaders.EMPTY,ErrorStatus.valueOf("_BAD_REQUEST"),request,errors); + } + + @ExceptionHandler + public ResponseEntity exception(Exception e, WebRequest request) { + e.printStackTrace(); + + return handleExceptionInternalFalse(e, ErrorStatus._INTERNAL_SERVER_ERROR, HttpHeaders.EMPTY, ErrorStatus._INTERNAL_SERVER_ERROR.getHttpStatus(),request, e.getMessage()); + } + + @ExceptionHandler(value = GeneralException.class) + public ResponseEntity onThrowException(GeneralException generalException, HttpServletRequest request) { + ErrorReasonDTO errorReasonHttpStatus = generalException.getErrorReasonHttpStatus(); + return handleExceptionInternal(generalException,errorReasonHttpStatus,null,request); + } + + private ResponseEntity handleExceptionInternal(Exception e, ErrorReasonDTO reason, + HttpHeaders headers, HttpServletRequest request) { + + ApiResponse body = ApiResponse.onFailure(reason.getCode(),reason.getMessage(),null); +// e.printStackTrace(); + + WebRequest webRequest = new ServletWebRequest(request); + return super.handleExceptionInternal( + e, + body, + headers, + reason.getHttpStatus(), + webRequest + ); + } + + private ResponseEntity handleExceptionInternalFalse(Exception e, ErrorStatus errorCommonStatus, + HttpHeaders headers, HttpStatus status, WebRequest request, String errorPoint) { + ApiResponse body = ApiResponse.onFailure(errorCommonStatus.getCode(),errorCommonStatus.getMessage(),errorPoint); + return super.handleExceptionInternal( + e, + body, + headers, + status, + request + ); + } + + private ResponseEntity handleExceptionInternalArgs(Exception e, HttpHeaders headers, ErrorStatus errorCommonStatus, + WebRequest request, Map errorArgs) { + ApiResponse body = ApiResponse.onFailure(errorCommonStatus.getCode(),errorCommonStatus.getMessage(),errorArgs); + return super.handleExceptionInternal( + e, + body, + headers, + errorCommonStatus.getHttpStatus(), + request + ); + } + + private ResponseEntity handleExceptionInternalConstraint(Exception e, ErrorStatus errorCommonStatus, + HttpHeaders headers, WebRequest request) { + ApiResponse body = ApiResponse.onFailure(errorCommonStatus.getCode(), errorCommonStatus.getMessage(), null); + return super.handleExceptionInternal( + e, + body, + headers, + errorCommonStatus.getHttpStatus(), + request + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/apiPayload/exception/GeneralException.java b/src/main/java/com/example/apiPayload/exception/GeneralException.java new file mode 100644 index 0000000..ea4fbfa --- /dev/null +++ b/src/main/java/com/example/apiPayload/exception/GeneralException.java @@ -0,0 +1,21 @@ +package com.example.apiPayload.exception; + +import com.example.apiPayload.BaseErrorCode; +import com.example.apiPayload.ErrorReasonDTO; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class GeneralException extends RuntimeException { + + private BaseErrorCode code; + + public ErrorReasonDTO getErrorReason() { + return this.code.getReason(); + } + + public ErrorReasonDTO getErrorReasonHttpStatus(){ + return this.code.getReasonHttpStatus(); + } +} diff --git a/src/main/java/com/example/apiPayload/exception/handler/FoodCategoryHandler.java b/src/main/java/com/example/apiPayload/exception/handler/FoodCategoryHandler.java new file mode 100644 index 0000000..dac4065 --- /dev/null +++ b/src/main/java/com/example/apiPayload/exception/handler/FoodCategoryHandler.java @@ -0,0 +1,11 @@ +package com.example.apiPayload.exception.handler; + +import com.example.apiPayload.code.status.ErrorStatus; +import com.example.apiPayload.exception.GeneralException; + +public class FoodCategoryHandler extends GeneralException { + + public FoodCategoryHandler(ErrorStatus errorStatus) { + super(errorStatus); + } +} diff --git a/src/main/java/com/example/apiPayload/exception/handler/TempHandler.java b/src/main/java/com/example/apiPayload/exception/handler/TempHandler.java new file mode 100644 index 0000000..c976c01 --- /dev/null +++ b/src/main/java/com/example/apiPayload/exception/handler/TempHandler.java @@ -0,0 +1,11 @@ +package com.example.apiPayload.exception.handler; + +import com.example.apiPayload.BaseErrorCode; +import com.example.apiPayload.exception.GeneralException; + +public class TempHandler extends GeneralException { + + public TempHandler(BaseErrorCode errorCode) { + super(errorCode); + } +} diff --git a/src/main/java/com/example/config/QueryDSLConfig.java b/src/main/java/com/example/config/QueryDSLConfig.java new file mode 100644 index 0000000..7cfa06f --- /dev/null +++ b/src/main/java/com/example/config/QueryDSLConfig.java @@ -0,0 +1,18 @@ +package com.example.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import jakarta.persistence.EntityManager; + +@Configuration +@RequiredArgsConstructor +public class QueryDSLConfig { + private final EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory(){ + return new JPAQueryFactory(entityManager); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/config/SwaggerConfig.java b/src/main/java/com/example/config/SwaggerConfig.java new file mode 100644 index 0000000..4677578 --- /dev/null +++ b/src/main/java/com/example/config/SwaggerConfig.java @@ -0,0 +1,40 @@ +package com.example.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI UMCstudyAPI() { + Info info = new Info() + .title("UMC Server WorkBook API") + .description("UMC Server WorkBook API 명세서") + .version("1.0.0"); + + String jwtSchemeName = "JWT TOKEN"; + // API 요청헤더에 인증정보 포함 + SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName); + // SecuritySchemes 등록 + Components components = new Components() + .addSecuritySchemes(jwtSchemeName, new SecurityScheme() + .name(jwtSchemeName) + .type(SecurityScheme.Type.HTTP) // HTTP 방식 + .scheme("bearer") + .bearerFormat("JWT")); + + return new OpenAPI() + .addServersItem(new Server().url("/")) + .info(info) + .addSecurityItem(securityRequirement) + .components(components); + } +} diff --git a/src/main/java/com/example/converter/MemberConverter.java b/src/main/java/com/example/converter/MemberConverter.java new file mode 100644 index 0000000..e6ff219 --- /dev/null +++ b/src/main/java/com/example/converter/MemberConverter.java @@ -0,0 +1,44 @@ +package com.example.converter; + +import com.example.apiPayload.MemberRequestDTO; +import com.example.apiPayload.MemberResponseDTO; +import com.example.domain.Member; +import com.example.domain.enums.Gender; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +public class MemberConverter { + + public static MemberResponseDTO.JoinResultDTO toJoinResultDTO(Member member){ + return MemberResponseDTO.JoinResultDTO.builder() + .memberId(member.getId()) + .createdAt(LocalDateTime.now()) + .build(); + } + + public static Member toMember(MemberRequestDTO.JoinDto request){ + + Gender gender = null; + + switch (request.getGender()){ + case 1: + gender = Gender.MALE; + break; + case 2: + gender = Gender.FEMALE; + break; + case 3: + gender = Gender.NONE; + break; + } + + return Member.builder() + .address(request.getAddress()) + .specAddress(request.getSpecAddress()) + .gender(gender) + .name(request.getName()) + .memberPreferList(new ArrayList<>()) + .build(); + } +} diff --git a/src/main/java/com/example/converter/MemberPreferConverter.java b/src/main/java/com/example/converter/MemberPreferConverter.java new file mode 100644 index 0000000..128695b --- /dev/null +++ b/src/main/java/com/example/converter/MemberPreferConverter.java @@ -0,0 +1,21 @@ +package com.example.converter; + +import com.example.domain.FoodCategory; +import com.example.domain.mapping.MemberPrefer; + +import java.util.List; +import java.util.stream.Collectors; + +public class MemberPreferConverter { + + public static List toMemberPreferList(List foodCategoryList){ + + return foodCategoryList.stream() + .map(foodCategory -> + MemberPrefer.builder() + .foodCategory(foodCategory) + .build() + ).collect(Collectors.toList()); + } +} + diff --git a/src/main/java/com/example/converter/TempConverter.java b/src/main/java/com/example/converter/TempConverter.java new file mode 100644 index 0000000..3ef9d08 --- /dev/null +++ b/src/main/java/com/example/converter/TempConverter.java @@ -0,0 +1,17 @@ +package com.example.converter; + +import com.example.web.dto.TempResponse; + +public class TempConverter { + public static TempResponse.TempTestDTO toTempTestDTO(){ + return TempResponse.TempTestDTO.builder() + .testString("This is Test!") + .build(); + } + + public static TempResponse.TempExceptionDTO toTempExceptionDTO(Integer flag){ + return TempResponse.TempExceptionDTO.builder() + .flag(flag) + .build(); + } +} diff --git a/src/main/java/com/example/domain/FoodCategory.java b/src/main/java/com/example/domain/FoodCategory.java new file mode 100644 index 0000000..bfda424 --- /dev/null +++ b/src/main/java/com/example/domain/FoodCategory.java @@ -0,0 +1,21 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; + +import jakarta.persistence.*; + +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class FoodCategory extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 15) + private String name; +} diff --git a/src/main/java/com/example/domain/Member.java b/src/main/java/com/example/domain/Member.java new file mode 100644 index 0000000..b64b627 --- /dev/null +++ b/src/main/java/com/example/domain/Member.java @@ -0,0 +1,74 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; +import com.example.domain.enums.Gender; +import com.example.domain.enums.MemberStatus; +import com.example.domain.enums.SocialType; +import com.example.domain.mapping.MemberAgree; +import com.example.domain.mapping.MemberMission; +import com.example.domain.mapping.MemberPrefer; + +import jakarta.persistence.*; + +import lombok.*; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@DynamicUpdate +@DynamicInsert +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Member extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 20) + private String name; + + @Column(nullable = false, length = 40) + private String address; + + @Column(nullable = false, length = 40) + private String specAddress; + + @Enumerated(EnumType.STRING) + @Column(columnDefinition = "VARCHAR(10)") + private Gender gender; + + @Enumerated(EnumType.STRING) + private SocialType socialType; + + @Enumerated(EnumType.STRING) + @Column(columnDefinition = "VARCHAR(15) DEFAULT 'ACTIVE'") + private MemberStatus status; + + private LocalDate inactiveDate; + + //@Column(nullable = false, length = 50) + private String email; + + @ColumnDefault("0") + private Integer point; + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + private List memberAgreeList = new ArrayList<>(); + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + private List memberPreferList = new ArrayList<>(); + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + private List reviewList = new ArrayList<>(); + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + private List memberMissionList = new ArrayList<>(); +} \ No newline at end of file diff --git a/src/main/java/com/example/domain/Mission.java b/src/main/java/com/example/domain/Mission.java new file mode 100644 index 0000000..02b2ec0 --- /dev/null +++ b/src/main/java/com/example/domain/Mission.java @@ -0,0 +1,45 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; +import com.example.domain.mapping.MemberMission; + +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Mission extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private Integer reward; + + private LocalDate deadline; + + private String missionSpec; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + private Store store; + + @OneToMany(mappedBy = "mission", cascade = CascadeType.ALL) + private List memberMissionList = new ArrayList<>(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; +} diff --git a/src/main/java/com/example/domain/Region.java b/src/main/java/com/example/domain/Region.java new file mode 100644 index 0000000..86e9300 --- /dev/null +++ b/src/main/java/com/example/domain/Region.java @@ -0,0 +1,25 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Region extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 20) + private String name; +} diff --git a/src/main/java/com/example/domain/Review.java b/src/main/java/com/example/domain/Review.java new file mode 100644 index 0000000..ed1fdce --- /dev/null +++ b/src/main/java/com/example/domain/Review.java @@ -0,0 +1,34 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Review extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + + private Float score; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne + @JoinColumn(name = "store_id") + private Store store; +} \ No newline at end of file diff --git a/src/main/java/com/example/domain/Store.java b/src/main/java/com/example/domain/Store.java new file mode 100644 index 0000000..ee4fdc0 --- /dev/null +++ b/src/main/java/com/example/domain/Store.java @@ -0,0 +1,56 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; + +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Store extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String name; + + @Column(nullable = false, length = 50) + private String address; + + private Float score; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "region_id") + private Region region; + + @OneToMany(mappedBy = "store", cascade = CascadeType.ALL) + private List missionList = new ArrayList<>(); + + @OneToMany(mappedBy = "store", cascade = CascadeType.ALL) + private List reviewList = new ArrayList<>(); + + @Override + public String toString() { + return "Store{" + + "id=" + id + + ", name='" + name + '\'' + + ", address='" + address + '\'' + + ", score=" + score + + ", region=" + (region != null ? region.getName() : "N/A") + // region의 이름 출력 + '}'; + } + +} diff --git a/src/main/java/com/example/domain/Terms.java b/src/main/java/com/example/domain/Terms.java new file mode 100644 index 0000000..0ccb7ff --- /dev/null +++ b/src/main/java/com/example/domain/Terms.java @@ -0,0 +1,37 @@ +package com.example.domain; + +import com.example.domain.common.BaseEntity; +import com.example.domain.mapping.MemberAgree; + +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +import java.util.ArrayList; +import java.util.List; + + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Terms extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + + private String body; + + private Boolean optional; + + @OneToMany(mappedBy = "terms", cascade = CascadeType.ALL) + private List memberAgreeList = new ArrayList<>(); +} diff --git a/src/main/java/com/example/domain/common/BaseEntity.java b/src/main/java/com/example/domain/common/BaseEntity.java new file mode 100644 index 0000000..e03f799 --- /dev/null +++ b/src/main/java/com/example/domain/common/BaseEntity.java @@ -0,0 +1,22 @@ +package com.example.domain.common; + +import jakarta.persistence.*; + +import lombok.Getter; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public abstract class BaseEntity { + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; +} diff --git a/src/main/java/com/example/domain/enums/Gender.java b/src/main/java/com/example/domain/enums/Gender.java new file mode 100644 index 0000000..c486e58 --- /dev/null +++ b/src/main/java/com/example/domain/enums/Gender.java @@ -0,0 +1,5 @@ +package com.example.domain.enums; + +public enum Gender { + MALE, FEMALE, NONE +} diff --git a/src/main/java/com/example/domain/enums/MemberStatus.java b/src/main/java/com/example/domain/enums/MemberStatus.java new file mode 100644 index 0000000..3c8e850 --- /dev/null +++ b/src/main/java/com/example/domain/enums/MemberStatus.java @@ -0,0 +1,5 @@ +package com.example.domain.enums; + +public enum MemberStatus { + ACTIVE, INACTIVE +} diff --git a/src/main/java/com/example/domain/enums/MissionStatus.java b/src/main/java/com/example/domain/enums/MissionStatus.java new file mode 100644 index 0000000..f9ccbff --- /dev/null +++ b/src/main/java/com/example/domain/enums/MissionStatus.java @@ -0,0 +1,5 @@ +package com.example.domain.enums; + +public enum MissionStatus { + CHALLENGING, COMPLETE, +} diff --git a/src/main/java/com/example/domain/enums/SocialType.java b/src/main/java/com/example/domain/enums/SocialType.java new file mode 100644 index 0000000..3d4e9d6 --- /dev/null +++ b/src/main/java/com/example/domain/enums/SocialType.java @@ -0,0 +1,5 @@ +package com.example.domain.enums; + +public enum SocialType { + KAKAO, GOOGLE, NAVER, APPLE +} diff --git a/src/main/java/com/example/domain/mapping/MemberAgree.java b/src/main/java/com/example/domain/mapping/MemberAgree.java new file mode 100644 index 0000000..def3b84 --- /dev/null +++ b/src/main/java/com/example/domain/mapping/MemberAgree.java @@ -0,0 +1,30 @@ +package com.example.domain.mapping; + +import com.example.domain.Member; +import com.example.domain.Terms; +import com.example.domain.common.BaseEntity; + +import jakarta.persistence.*; + +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class MemberAgree extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "terms_id") + private Terms terms; + +} \ No newline at end of file diff --git a/src/main/java/com/example/domain/mapping/MemberMission.java b/src/main/java/com/example/domain/mapping/MemberMission.java new file mode 100644 index 0000000..47b7ee8 --- /dev/null +++ b/src/main/java/com/example/domain/mapping/MemberMission.java @@ -0,0 +1,34 @@ +package com.example.domain.mapping; + +import com.example.domain.common.BaseEntity; +import com.example.domain.enums.MissionStatus; +import com.example.domain.Member; +import com.example.domain.Mission; + +import jakarta.persistence.*; + +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class MemberMission extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + @Column(columnDefinition = "VARCHAR(15) DEFAULT 'ACTIVE'") + private MissionStatus status; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mission_id") + private Mission mission; +} diff --git a/src/main/java/com/example/domain/mapping/MemberPrefer.java b/src/main/java/com/example/domain/mapping/MemberPrefer.java new file mode 100644 index 0000000..17c42df --- /dev/null +++ b/src/main/java/com/example/domain/mapping/MemberPrefer.java @@ -0,0 +1,45 @@ +package com.example.domain.mapping; + +import com.example.domain.FoodCategory; +import com.example.domain.Member; +import com.example.domain.common.BaseEntity; + +import jakarta.persistence.*; + +import lombok.Getter; +import lombok.Builder; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.AccessLevel; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class MemberPrefer extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private FoodCategory foodCategory; + + public void setMember(Member member){ + if(this.member != null) + member.getMemberPreferList().remove(this); + this.member = member; + member.getMemberPreferList().add(this); + } + + public void setFoodCategory(FoodCategory foodCategory){ + this.foodCategory = foodCategory; + } + +} diff --git a/src/main/java/com/example/repository/FoodCategoryRepository/FoodCategoryRepository.java b/src/main/java/com/example/repository/FoodCategoryRepository/FoodCategoryRepository.java new file mode 100644 index 0000000..c587a82 --- /dev/null +++ b/src/main/java/com/example/repository/FoodCategoryRepository/FoodCategoryRepository.java @@ -0,0 +1,7 @@ +package com.example.repository.FoodCategoryRepository; + +import com.example.domain.FoodCategory; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FoodCategoryRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/repository/MemberRepository/MemberRepository.java b/src/main/java/com/example/repository/MemberRepository/MemberRepository.java new file mode 100644 index 0000000..197df51 --- /dev/null +++ b/src/main/java/com/example/repository/MemberRepository/MemberRepository.java @@ -0,0 +1,7 @@ +package com.example.repository.MemberRepository; + +import com.example.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/repository/StoreRepository/StoreRepository.java b/src/main/java/com/example/repository/StoreRepository/StoreRepository.java new file mode 100644 index 0000000..6988e8c --- /dev/null +++ b/src/main/java/com/example/repository/StoreRepository/StoreRepository.java @@ -0,0 +1,7 @@ +package com.example.repository.StoreRepository; + +import com.example.domain.Store; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface StoreRepository extends JpaRepository, StoreRepositoryCustom { +} \ No newline at end of file diff --git a/src/main/java/com/example/repository/StoreRepository/StoreRepositoryCustom.java b/src/main/java/com/example/repository/StoreRepository/StoreRepositoryCustom.java new file mode 100644 index 0000000..18e65e0 --- /dev/null +++ b/src/main/java/com/example/repository/StoreRepository/StoreRepositoryCustom.java @@ -0,0 +1,9 @@ +package com.example.repository.StoreRepository; + +import com.example.domain.Store; +import java.util.List; + + +public interface StoreRepositoryCustom { + List dynamicQueryWithBooleanBuilder(String name, Float score); +} \ No newline at end of file diff --git a/src/main/java/com/example/repository/StoreRepository/StoreRepositoryImpl.java b/src/main/java/com/example/repository/StoreRepository/StoreRepositoryImpl.java new file mode 100644 index 0000000..659d19d --- /dev/null +++ b/src/main/java/com/example/repository/StoreRepository/StoreRepositoryImpl.java @@ -0,0 +1,35 @@ +package com.example.repository.StoreRepository; + +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import com.example.domain.QStore; +import com.example.domain.Store; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class StoreRepositoryImpl implements StoreRepositoryCustom{ + private final JPAQueryFactory jpaQueryFactory; + private final QStore store = QStore.store; + + @Override + public List dynamicQueryWithBooleanBuilder(String name, Float score) { + BooleanBuilder predicate = new BooleanBuilder(); + + if (name != null) { + predicate.and(store.name.eq(name)); + } + + if (score != null) { + predicate.and(store.score.goe(4.0f)); + } + + return jpaQueryFactory + .selectFrom(store) + .where(predicate) + .fetch(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/service/MemberService/MemberCommandService.java b/src/main/java/com/example/service/MemberService/MemberCommandService.java new file mode 100644 index 0000000..f536d28 --- /dev/null +++ b/src/main/java/com/example/service/MemberService/MemberCommandService.java @@ -0,0 +1,9 @@ +package com.example.service.MemberService; + +import com.example.apiPayload.MemberRequestDTO; +import com.example.domain.Member; + +public interface MemberCommandService { + Member joinMember(MemberRequestDTO.JoinDto request); +} + diff --git a/src/main/java/com/example/service/MemberService/MemberCommandServiceImpl.java b/src/main/java/com/example/service/MemberService/MemberCommandServiceImpl.java new file mode 100644 index 0000000..53c08db --- /dev/null +++ b/src/main/java/com/example/service/MemberService/MemberCommandServiceImpl.java @@ -0,0 +1,44 @@ +package com.example.service.MemberService; + +import com.example.apiPayload.MemberRequestDTO; +import com.example.apiPayload.code.status.ErrorStatus; +import com.example.apiPayload.exception.handler.FoodCategoryHandler; +import com.example.converter.MemberConverter; +import com.example.converter.MemberPreferConverter; +import com.example.domain.FoodCategory; +import com.example.domain.Member; +import com.example.domain.mapping.MemberPrefer; +import com.example.repository.FoodCategoryRepository.FoodCategoryRepository; +import com.example.repository.MemberRepository.MemberRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class MemberCommandServiceImpl implements MemberCommandService{ + + private final MemberRepository memberRepository; + + private final FoodCategoryRepository foodCategoryRepository; + + @Override + @Transactional + public Member joinMember(MemberRequestDTO.JoinDto request) { + + Member newMember = MemberConverter.toMember(request); + List foodCategoryList = request.getPreferCategory().stream() + .map(category -> { + return foodCategoryRepository.findById(category).orElseThrow(() -> new FoodCategoryHandler(ErrorStatus.FOOD_CATEGORY_NOT_FOUND)); + }).collect(Collectors.toList()); + + List memberPreferList = MemberPreferConverter.toMemberPreferList(foodCategoryList); + + memberPreferList.forEach(memberPrefer -> {memberPrefer.setMember(newMember);}); + + return memberRepository.save(newMember); + } +} diff --git a/src/main/java/com/example/service/MemberService/MemberQureyService.java b/src/main/java/com/example/service/MemberService/MemberQureyService.java new file mode 100644 index 0000000..9baa803 --- /dev/null +++ b/src/main/java/com/example/service/MemberService/MemberQureyService.java @@ -0,0 +1,4 @@ +package com.example.service.MemberService; + +public interface MemberQureyService { +} diff --git a/src/main/java/com/example/service/MemberService/MemberQureyServiceImpl.java b/src/main/java/com/example/service/MemberService/MemberQureyServiceImpl.java new file mode 100644 index 0000000..e9a9d00 --- /dev/null +++ b/src/main/java/com/example/service/MemberService/MemberQureyServiceImpl.java @@ -0,0 +1,4 @@ +package com.example.service.MemberService; + +public class MemberQureyServiceImpl { +} diff --git a/src/main/java/com/example/service/StoreService/StoreQueryService.java b/src/main/java/com/example/service/StoreService/StoreQueryService.java new file mode 100644 index 0000000..68a1bcf --- /dev/null +++ b/src/main/java/com/example/service/StoreService/StoreQueryService.java @@ -0,0 +1,11 @@ +package com.example.service.StoreService; + +import com.example.domain.Store; + +import java.util.List; +import java.util.Optional; + +public interface StoreQueryService { + Optional findStore(Long id); + List findStoresByNameAndScore(String name, Float score); + } diff --git a/src/main/java/com/example/service/StoreService/StoreQueryServiceImpl.java b/src/main/java/com/example/service/StoreService/StoreQueryServiceImpl.java new file mode 100644 index 0000000..13a5b68 --- /dev/null +++ b/src/main/java/com/example/service/StoreService/StoreQueryServiceImpl.java @@ -0,0 +1,31 @@ +package com.example.service.StoreService; + +import com.example.domain.Store; +import com.example.repository.StoreRepository.StoreRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Transactional +public class StoreQueryServiceImpl implements StoreQueryService{ + private final StoreRepository storeRepository; + + @Override + public Optional findStore(Long id) { + return storeRepository.findById(id); + } + + @Override + public List findStoresByNameAndScore(String name, Float score) { + List filteredStores = storeRepository.dynamicQueryWithBooleanBuilder(name, score); + + filteredStores.forEach(store -> System.out.println("Store: " + store)); + + return filteredStores; + } +} diff --git a/src/main/java/com/example/service/TempService/TempCommandService.java b/src/main/java/com/example/service/TempService/TempCommandService.java new file mode 100644 index 0000000..9641aa4 --- /dev/null +++ b/src/main/java/com/example/service/TempService/TempCommandService.java @@ -0,0 +1,4 @@ +package com.example.service.TempService; + +public interface TempCommandService { +} diff --git a/src/main/java/com/example/service/TempService/TempCommandServiceImpl.java b/src/main/java/com/example/service/TempService/TempCommandServiceImpl.java new file mode 100644 index 0000000..e6beadf --- /dev/null +++ b/src/main/java/com/example/service/TempService/TempCommandServiceImpl.java @@ -0,0 +1,10 @@ +package com.example.service.TempService; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class TempCommandServiceImpl implements TempCommandService{ + +} diff --git a/src/main/java/com/example/service/TempService/TempQueryService.java b/src/main/java/com/example/service/TempService/TempQueryService.java new file mode 100644 index 0000000..3b14128 --- /dev/null +++ b/src/main/java/com/example/service/TempService/TempQueryService.java @@ -0,0 +1,5 @@ +package com.example.service.TempService; + +public interface TempQueryService { + void CheckFlag(Integer flag); +} diff --git a/src/main/java/com/example/service/TempService/TempQueryServiceImpl.java b/src/main/java/com/example/service/TempService/TempQueryServiceImpl.java new file mode 100644 index 0000000..e4eba73 --- /dev/null +++ b/src/main/java/com/example/service/TempService/TempQueryServiceImpl.java @@ -0,0 +1,17 @@ +package com.example.service.TempService; + +import com.example.apiPayload.code.status.ErrorStatus; +import com.example.apiPayload.exception.handler.TempHandler; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class TempQueryServiceImpl implements TempQueryService{ + + @Override + public void CheckFlag(Integer flag) { + if (flag == 1) + throw new TempHandler(ErrorStatus.TEMP_EXCEPTION); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/validation/annotation/ExistCategories.java b/src/main/java/com/example/validation/annotation/ExistCategories.java new file mode 100644 index 0000000..f89a37f --- /dev/null +++ b/src/main/java/com/example/validation/annotation/ExistCategories.java @@ -0,0 +1,18 @@ +package com.example.validation.annotation; + +import com.example.validation.validator.CategoriesExistValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = CategoriesExistValidator.class) +@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExistCategories { + + String message() default "해당하는 카테고리가 존재하지 않습니다."; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/example/validation/validator/CategoriesExistValidator.java b/src/main/java/com/example/validation/validator/CategoriesExistValidator.java new file mode 100644 index 0000000..cd2276e --- /dev/null +++ b/src/main/java/com/example/validation/validator/CategoriesExistValidator.java @@ -0,0 +1,37 @@ +package com.example.validation.validator; + +import com.example.apiPayload.code.status.ErrorStatus; +import com.example.repository.FoodCategoryRepository.FoodCategoryRepository; +import com.example.validation.annotation.ExistCategories; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class CategoriesExistValidator implements ConstraintValidator> { + + private final FoodCategoryRepository foodCategoryRepository; + + @Override + public void initialize(ExistCategories constraintAnnotation) { + ConstraintValidator.super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(List values, ConstraintValidatorContext context) { + boolean isValid = values.stream() + .allMatch(value -> foodCategoryRepository.existsById(value)); + + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(ErrorStatus.FOOD_CATEGORY_NOT_FOUND.toString()).addConstraintViolation(); + } + + return isValid; + + } +} \ No newline at end of file diff --git a/src/main/java/com/example/web/controller/MemberRestController.java b/src/main/java/com/example/web/controller/MemberRestController.java new file mode 100644 index 0000000..fcf4387 --- /dev/null +++ b/src/main/java/com/example/web/controller/MemberRestController.java @@ -0,0 +1,28 @@ +package com.example.web.controller; + +import com.example.apiPayload.ApiResponse; +import com.example.apiPayload.MemberRequestDTO; +import com.example.apiPayload.MemberResponseDTO; +import com.example.converter.MemberConverter; +import com.example.domain.Member; +import com.example.service.MemberService.MemberCommandService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/members") +public class MemberRestController { + + private final MemberCommandService memberCommandService; + + @PostMapping("/") + public ApiResponse join(@RequestBody @Valid MemberRequestDTO.JoinDto request){ + Member member = memberCommandService.joinMember(request); + return ApiResponse.onSuccess(MemberConverter.toJoinResultDTO(member)); + } +} diff --git a/src/main/java/com/example/web/controller/TempRestController.java b/src/main/java/com/example/web/controller/TempRestController.java new file mode 100644 index 0000000..35a437d --- /dev/null +++ b/src/main/java/com/example/web/controller/TempRestController.java @@ -0,0 +1,31 @@ +package com.example.web.controller; + +import com.example.apiPayload.ApiResponse; +import com.example.converter.TempConverter; +import com.example.service.TempService.TempQueryService; +import com.example.web.dto.TempResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/temp") +@RequiredArgsConstructor +public class TempRestController { + + private final TempQueryService tempQueryService; + + @GetMapping("/test") + public ApiResponse testAPI(){ + + return ApiResponse.onSuccess(TempConverter.toTempTestDTO()); + } + + @GetMapping("/exception") + public ApiResponse exceptionAPI(@RequestParam Integer flag){ + tempQueryService.CheckFlag(flag); + return ApiResponse.onSuccess(TempConverter.toTempExceptionDTO(flag)); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/web/dto/TempRequest.java b/src/main/java/com/example/web/dto/TempRequest.java new file mode 100644 index 0000000..26af834 --- /dev/null +++ b/src/main/java/com/example/web/dto/TempRequest.java @@ -0,0 +1,4 @@ +package com.example.web.dto; + +public class TempRequest { +} diff --git a/src/main/java/com/example/web/dto/TempResponse.java b/src/main/java/com/example/web/dto/TempResponse.java new file mode 100644 index 0000000..3cb06dc --- /dev/null +++ b/src/main/java/com/example/web/dto/TempResponse.java @@ -0,0 +1,25 @@ +package com.example.web.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class TempResponse { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class TempTestDTO{ + String testString; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class TempExceptionDTO{ + Integer flag; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..bb2a42f --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + datasource: + url: jdbc:mysql://localhost:3306/study + username: root + password: yejin0618* + driver-class-name: com.mysql.cj.jdbc.Driver + sql: + init: + mode: never + jpa: + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL8Dialect + show_sql: true + format_sql: true + use_sql_comments: true + hbm2ddl: + auto: create + default_batch_fetch_size: 1000 \ No newline at end of file diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..e69de29 diff --git a/src/test/java/umc/spring/ApplicationTests.java b/src/test/java/umc/spring/ApplicationTests.java new file mode 100644 index 0000000..dc36e6c --- /dev/null +++ b/src/test/java/umc/spring/ApplicationTests.java @@ -0,0 +1,13 @@ +package umc.spring; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApplicationTests { + + @Test + void contextLoads() { + } + +}