diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/.DS_Store differ
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..2eea525
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1 @@
+.env
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index e8baff1..9836877 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,16 @@ out/
hs_err_pid44980.jfr
hs_err_pid44980.log
+
+build/
+
+docker-compose.yaml
+
+#GCP, FIREBASE KEY
+/src/main/resources/gcp
+/src/main/resources/firebase
+
+data/
+gradle/
+
+buildDockerWindow.sh
diff --git a/Dockerfile b/Dockerfile
index cc15b00..bf87811 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,12 @@
FROM openjdk:17
ARG JAR_FILE=build/libs/*.jar
-COPY ${JAR_FILE} test-app.jar
+COPY ${JAR_FILE} prod.jar
+
+COPY src/main/resources/gcp/ancient-pipe-447417-i4-755ce59fbf03.json /app/ancient-pipe-447417-i4-755ce59fbf03.json
+ENV GOOGLE_APPLICATION_CREDENTIALS="app/ancient-pipe-447417-i4-755ce59fbf03.json"
+
+COPY src/main/resources/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json /app/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json
+
EXPOSE 8080
-CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "test-app.jar"]
\ No newline at end of file
+CMD ["java", "-Dtest.customName=${CUSTOM_NAME}", "-jar", "prod.jar"]
+
diff --git a/README.md b/README.md
index a494f0a..69aec04 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,63 @@
-# backend
+
-## branch 특징
-### main : 배포
-### develop : 개발
+
+
+# 1. OverView(프로젝트 개요)
+- 프로젝트 이름: ComNCheck
+- 프로젝트 설명: 한국외국어대학교 컴퓨터공학부 알리미
+- 프로젝트 시작 계기 : 학창시절 과회장을 하면서 학부 행사 같은 경우 카톡방에 쌓이고, 학교 공지는 홈페이지에 수시로 들어가야 하는 불편함을 하나의 서비스로 해결하기 위해
+- 프로젝트 사이트 : https://www.comncheck.com
+- 프로젝트에서 하고 싶었던 부분 : Spring, FastAPI 백엔드 개발, 쿠버네티스 기반 서버 구축 및 운영
+# 2. Team Members (팀원 및 팀 소개)
+| 조성민 | 노성원 | 이예림 |
+|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|
+| Lead, BE, Server | FE, UI/UX Designer | FE, UI/UX Designer |
+|
|
|
|
+| [@sungmin306](https://github.com/sungmin306) | [@sungwonnoh](https://github.com/sungwonnoh) | [@YerimLee](https://github.com/yerimi00) |
+# 3. Project Preview
+
+
+- 약 134명의 사용자가 현재 접속하여 사용중(2025.03.24 기준)
+
+# 4. Architecture
+

+
+1. 단일 노드에서 `K3s` 기반으로 구축했다.(기존 GCP에서 미니PC 설치 후 서버 이동)
+2. 클라이언트(Client)는 `Nginx` 서버로 접속한다. → 80 또는 **`443`**
+ - Nginx 내부적으로 Certbot을 이용하여 SSL 인증을 진행
+3. `Nginx`는 “/” 경로로 온 요청은 Next.js 컨테이너로 요청을 보낸다.
+4. `Nginx`는 “/api” 경로로 온 요청은 `Spring` 컨테이너로 요청을 보낸다.
+ - 직접적으로 외부 통신 하지 않는 파드 같은 경우 Cluster IP로 설정하여 외부 서버에서 접근하는것을 막았다.
+ - `FastAPI` 및 `Next.js` 같은 경우 Replicaset 기반으로 5개의 파드가 동작해 비스의 확장성과 안정성이 보장한다.
+5. 모든 요청과 응답은 `Nginx`를 통해 전달한다.
+6. DB 서버는 백업기능을 위해 서버 로컬에서 관리한다.
+
+# 5. Service Detail
+| 일정 관리 | 알람 기능 |
+|:---------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|
+|
|
|
+| **익명 질문** | **추가 기능** |
+|
|
|
+
+# 4. Tech stack
+
+### Backend
+
+

+
+
+# 5. 앞으로의 목표
+
+백엔드
+
+- [ ] 테스트코드 작성
+- [ ] 레디스 이용 → 성능 최적화
+- [ ] 코드 리펙토링(클린코드 만들기)
+- [ ] 로직개선
+
+클라우드
+
+- [ ] control-plane, worker 노드 분리(고가용성)
+- [ ] HPA 설정
+- [ ] 모니터링 툴 세팅
+- [ ] CI/CD 환경구성
diff --git a/build.gradle b/build.gradle
index 11d7364..f32fbcb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -23,21 +23,27 @@ repositories {
mavenCentral()
}
+
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
- implementation 'io.github.cdimascio:java-dotenv:5.2.2' // .env 파일
+ implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
- runtimeOnly 'com.h2database:h2'
+ // runtimeOnly 'mysql:mysql-connector-java:8.0.33'
+ runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-web'
+ implementation 'com.google.firebase:firebase-admin:8.1.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
+ implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-starter', version: '6.0.0'
+ implementation group: 'com.google.cloud', name: 'spring-cloud-gcp-storage', version: '6.0.0'
+ implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '4.29.3'
}
tasks.named('test') {
diff --git a/docker-compose.yaml b/docker-compose.yaml
deleted file mode 100644
index 1cc991a..0000000
--- a/docker-compose.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-version: '3.8'
-
-services:
- app:
- image: comncheck/backend-spring-test:1.0.1
- build: .
- ports:
- - "8080:8080"
- env_file:
- - .env
-
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index a4b76b9..0000000
Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index e2847c8..0000000
--- a/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/hs_err_pid44980.jfr b/hs_err_pid44980.jfr
deleted file mode 100644
index 87dc5cf..0000000
Binary files a/hs_err_pid44980.jfr and /dev/null differ
diff --git a/hs_err_pid44980.log b/hs_err_pid44980.log
deleted file mode 100644
index 5d2a9cb..0000000
--- a/hs_err_pid44980.log
+++ /dev/null
@@ -1,1100 +0,0 @@
-#
-# A fatal error has been detected by the Java Runtime Environment:
-#
-# SIGBUS (0xa) at pc=0x00000001248014e4, pid=44980, tid=8707
-#
-# JRE version: OpenJDK Runtime Environment Corretto-17.0.8.8.1 (17.0.8.1+8) (build 17.0.8.1+8-LTS)
-# Java VM: OpenJDK 64-Bit Server VM Corretto-17.0.8.8.1 (17.0.8.1+8-LTS, mixed mode, emulated-client, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, bsd-aarch64)
-# Problematic frame:
-# v ~StubRoutines::SafeFetch32
-#
-# No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
-#
-# JFR recording file will be written. Location: /Users/sungmin/Desktop/ComNCheck/Spring/ComNCheck-backend/hs_err_pid44980.jfr
-#
-# If you would like to submit a bug report, please visit:
-# https://github.com/corretto/corretto-17/issues/
-# The crash happened outside the Java Virtual Machine in native code.
-# See problematic frame for where to report the bug.
-#
-
---------------- S U M M A R Y ------------
-
-Command Line: -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57802:/Applications/IntelliJ IDEA.app/Contents/bin -agentpath:/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/libasyncProfiler.so=start,jfr,event=cpu,interval=10ms,jfrsync=profile,cstack=no,file=/Users/sungmin/IdeaSnapshots/ComNCheckApplication_2025_01_26_233554.jfr,log=/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/ComNCheckApplication_2025_01_26_233554.jfr.log.txt,logLevel=DEBUG -Dfile.encoding=UTF-8 com.ComNCheck.ComNCheck.ComNCheckApplication
-
-Host: "MacBookAir10,1" arm64, 8 cores, 8G, Darwin 23.4.0, macOS 14.4.1 (23E224)
-Time: Sun Jan 26 23:35:58 2025 KST elapsed time: 4.219515 seconds (0d 0h 0m 4s)
-
---------------- T H R E A D ---------------
-
-Current thread (0x000000010e042e00): JavaThread "main" [_thread_in_native, id=8707, stack(0x000000016d98c000,0x000000016db8f000)]
-
-Stack: [0x000000016d98c000,0x000000016db8f000], sp=0x000000016db8c3d0, free space=2048k
-Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
-v ~StubRoutines::SafeFetch32
-V [libjvm.dylib+0x7c8890] os::is_readable_range(void const*, void const*)+0x2c
-V [libjvm.dylib+0x77531c] Method::is_valid_method(Method const*)+0x38
-V [libjvm.dylib+0x35fbb8] forte_fill_call_trace_given_top(JavaThread*, ASGCT_CallTrace*, int, frame)+0x1e0
-V [libjvm.dylib+0x35f9bc] AsyncGetCallTrace+0x1d4
-C [libasyncProfiler.so+0x3ac54] Profiler::getJavaTraceAsync(void*, ASGCT_CallFrame*, int, StackContext*)+0x15c
-C [libasyncProfiler.so+0x3bd04] Profiler::recordSampleForThread(int, void*, unsigned long long, int, Event*, int*)+0x1c4
-C [libasyncProfiler.so+0x4a03c] WallClock::signalHandler(int, __siginfo*, void*)+0xa8
-C [libsystem_platform.dylib+0x4584] _sigtramp+0x38
-C 0x0e41800000000069
-C [libzip.dylib+0x4844] Java_java_util_zip_Inflater_inflateBytesBytes+0xa8
-j java.util.zip.Inflater.inflateBytesBytes(J[BII[BII)J+0 java.base@17.0.8.1
-j java.util.zip.Inflater.inflate([BII)I+77 java.base@17.0.8.1
-j java.util.zip.InflaterInputStream.read([BII)I+53 java.base@17.0.8.1
-j jdk.internal.loader.Resource.getBytes()[B+117 java.base@17.0.8.1
-j jdk.internal.loader.URLClassPath$JarLoader$2.getBytes()[B+1 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.defineClass(Ljava/lang/String;Ljdk/internal/loader/Resource;)Ljava/lang/Class;+84 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(Ljava/lang/String;)Ljava/lang/Class;+37 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Ljava/lang/String;Z)Ljava/lang/Class;+111 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+3 java.base@17.0.8.1
-j jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+36 java.base@17.0.8.1
-j java.lang.ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;+3 java.base@17.0.8.1
-v ~StubRoutines::call_stub
-V [libjvm.dylib+0x473abc] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x390
-V [libjvm.dylib+0x472b28] JavaCalls::call_virtual(JavaValue*, Klass*, Symbol*, Symbol*, JavaCallArguments*, JavaThread*)+0xf8
-V [libjvm.dylib+0x472c80] JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, Handle, JavaThread*)+0x68
-V [libjvm.dylib+0x97f234] SystemDictionary::load_instance_class_impl(Symbol*, Handle, JavaThread*)+0xfc
-V [libjvm.dylib+0x97dcc8] SystemDictionary::load_instance_class(unsigned int, Symbol*, Handle, JavaThread*)+0x30
-V [libjvm.dylib+0x97d3cc] SystemDictionary::resolve_instance_class_or_null(Symbol*, Handle, Handle, JavaThread*)+0x4f0
-V [libjvm.dylib+0x97c9b4] SystemDictionary::resolve_or_fail(Symbol*, Handle, Handle, bool, JavaThread*)+0x80
-V [libjvm.dylib+0x2b9574] ConstantPool::klass_at_impl(constantPoolHandle const&, int, JavaThread*)+0x1e0
-V [libjvm.dylib+0x2ba2e8] ConstantPool::klass_ref_at(int, JavaThread*)+0x6c
-V [libjvm.dylib+0x68df08] LinkInfo::LinkInfo(constantPoolHandle const&, int, methodHandle const&, JavaThread*)+0x48
-V [libjvm.dylib+0x68ff70] LinkResolver::resolve_field_access(fieldDescriptor&, constantPoolHandle const&, int, methodHandle const&, Bytecodes::Code, JavaThread*)+0x30
-V [libjvm.dylib+0x46c140] InterpreterRuntime::resolve_get_put(JavaThread*, Bytecodes::Code)+0x138
-V [libjvm.dylib+0x46d4c8] InterpreterRuntime::resolve_from_cache(JavaThread*, Bytecodes::Code)+0x78
-j io.github.cdimascio.dotenv.internal.DotenvParser.(Lio/github/cdimascio/dotenv/internal/DotenvReader;ZZ)V+26
-j io.github.cdimascio.dotenv.DotenvBuilder.load()Lio/github/cdimascio/dotenv/Dotenv;+27
-j io.github.cdimascio.dotenv.Dotenv$Instance.load()Lio/github/cdimascio/dotenv/Dotenv;+7
-j io.github.cdimascio.dotenv.Dotenv.load()Lio/github/cdimascio/dotenv/Dotenv;+3
-j com.ComNCheck.ComNCheck.ComNCheckApplication.main([Ljava/lang/String;)V+0
-v ~StubRoutines::call_stub
-V [libjvm.dylib+0x473abc] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x390
-V [libjvm.dylib+0x4d8ab0] jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, JavaThread*)+0x110
-V [libjvm.dylib+0x4dc0cc] jni_CallStaticVoidMethod+0x130
-C [libjli.dylib+0x77e8] JavaMain+0xa80
-C [libjli.dylib+0x9ab8] ThreadJavaMain+0xc
-C [libsystem_pthread.dylib+0x6f94] _pthread_start+0x88
-
-Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
-j java.util.zip.Inflater.inflateBytesBytes(J[BII[BII)J+0 java.base@17.0.8.1
-j java.util.zip.Inflater.inflate([BII)I+77 java.base@17.0.8.1
-j java.util.zip.InflaterInputStream.read([BII)I+53 java.base@17.0.8.1
-j jdk.internal.loader.Resource.getBytes()[B+117 java.base@17.0.8.1
-j jdk.internal.loader.URLClassPath$JarLoader$2.getBytes()[B+1 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.defineClass(Ljava/lang/String;Ljdk/internal/loader/Resource;)Ljava/lang/Class;+84 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(Ljava/lang/String;)Ljava/lang/Class;+37 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(Ljava/lang/String;Z)Ljava/lang/Class;+111 java.base@17.0.8.1
-j jdk.internal.loader.BuiltinClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+3 java.base@17.0.8.1
-j jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Ljava/lang/String;Z)Ljava/lang/Class;+36 java.base@17.0.8.1
-j java.lang.ClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;+3 java.base@17.0.8.1
-v ~StubRoutines::call_stub
-j io.github.cdimascio.dotenv.internal.DotenvParser.(Lio/github/cdimascio/dotenv/internal/DotenvReader;ZZ)V+26
-j io.github.cdimascio.dotenv.DotenvBuilder.load()Lio/github/cdimascio/dotenv/Dotenv;+27
-j io.github.cdimascio.dotenv.Dotenv$Instance.load()Lio/github/cdimascio/dotenv/Dotenv;+7
-j io.github.cdimascio.dotenv.Dotenv.load()Lio/github/cdimascio/dotenv/Dotenv;+3
-j com.ComNCheck.ComNCheck.ComNCheckApplication.main([Ljava/lang/String;)V+0
-v ~StubRoutines::call_stub
-
-siginfo: si_signo: 10 (SIGBUS), si_code: 1 (BUS_ADRALN), si_addr: 0x00000001248014e4
-
-Register to memory mapping:
-
- x0=0x0000007000259000 is pointing into metadata
- x1=0x00000000cafebabe is an unknown value
- x2=0x0 is NULL
- x3=0x0 is NULL
- x4=0x000000016db8d230 is pointing into the stack for thread: 0x000000010e042e00
- x5=0x000000016db8d230 is pointing into the stack for thread: 0x000000010e042e00
- x6=0xffffffffffffff97 is an unknown value
- x7=0x000000000000006e is an unknown value
- x8=0x00000001248014e0 is at begin+0 in a stub
-StubRoutines::SafeFetch32 [0x00000001248014e0, 0x00000001248014ec] (12 bytes)
- x9=0x0000000000000450 is an unknown value
-x10=0x0000000124805600 is pointing into interpreter code (not bytecode specific)
-x11=0x00000000000000ab is an unknown value
-x12=0x00000000000000ab is an unknown value
-x13=0x0 is NULL
-x14=0x0 is NULL
-x15=0x0000000787a315c8 is pointing into object: [B
-{0x0000000787a31548} - klass: {type array byte}
- - length: 1024
-x16=0x000000019d7a9da4: pthread_getspecific+0 in /usr/lib/system/libsystem_pthread.dylib at 0x000000019d7a8000
-x17=0x0000600004ac7870 points into unknown readable memory: 0xfffffffffffffffe | fe ff ff ff ff ff ff ff
-x18=0x0 is NULL
-x19=0x0000007000259000 is pointing into metadata
-x20=0x000000010e042e00 is a thread
-x21=0x0000000000000001 is an unknown value
-x22={method} {0x0000007000259e10} 'inflateBytesBytes' '(J[BII[BII)J' in 'java/util/zip/Inflater'
-x23=0x00000001046a3a40: _ZN12StubRoutines18_safefetch32_entryE+0 in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib at 0x0000000103a34000
-x24=0x00000000cafebabe is an unknown value
-x25=0x000000010e0430b0 points into unknown readable memory: 0x00000001046669f8 | f8 69 66 04 01 00 00 00
-x26=0x000000016db8cfb0 is pointing into the stack for thread: 0x000000010e042e00
-x27=0x0000000110014390 points into unknown readable memory: 0x000000000000014d | 4d 01 00 00 00 00 00 00
-x28=0x00000001026b0890: inflate_fast+0x33c in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib at 0x00000001026a4000
-
-
-Registers:
- x0=0x0000007000259000 x1=0x00000000cafebabe x2=0x0000000000000000 x3=0x0000000000000000
- x4=0x000000016db8d230 x5=0x000000016db8d230 x6=0xffffffffffffff97 x7=0x000000000000006e
- x8=0x00000001248014e0 x9=0x0000000000000450 x10=0x0000000124805600 x11=0x00000000000000ab
-x12=0x00000000000000ab x13=0x0000000000000000 x14=0x0000000000000000 x15=0x0000000787a315c8
-x16=0x000000019d7a9da4 x17=0x0000600004ac7870 x18=0x0000000000000000 x19=0x0000007000259000
-x20=0x000000010e042e00 x21=0x0000000000000001 x22=0x0000007000259e10 x23=0x00000001046a3a40
-x24=0x00000000cafebabe x25=0x000000010e0430b0 x26=0x000000016db8cfb0 x27=0x0000000110014390
-x28=0x00000001026b0890 fp=0x000000016db8c400 lr=0x00000001041fc290 sp=0x000000016db8c3d0
-pc=0x00000001248014e4 cpsr=0x0000000060001000
-Top of Stack: (sp=0x000000016db8c3d0)
-0x000000016db8c3d0: 000000010e042e00 00000000000007ff
-0x000000016db8c3e0: 0000007000259e10 000000010e042e00
-0x000000016db8c3f0: 0000007000259000 0000007000259e68
-0x000000016db8c400: 000000016db8c420 00000001041fc890
-0x000000016db8c410: 0000000000000800 0000007000259e10
-0x000000016db8c420: 000000016db8c440 00000001041a931c
-0x000000016db8c430: 0000000000000800 000000016db8d190
-0x000000016db8c440: 000000016db8d0b0 0000000103d93bb8
-0x000000016db8c450: 0000000000000000 0000000000000000
-0x000000016db8c460: 0000000000000000 0000000000000000
-0x000000016db8c470: 0000000000000000 0000000000000000
-0x000000016db8c480: 0000000000000000 0000000000000000
-0x000000016db8c490: 0000000000000000 0000000000000000
-0x000000016db8c4a0: 0000000000000000 0000000000000000
-0x000000016db8c4b0: 0000000000000000 0000000000000000
-0x000000016db8c4c0: 0000000000000000 0000000000000000
-0x000000016db8c4d0: 0000000000000000 0000000000000000
-0x000000016db8c4e0: 0000000000000000 0000000000000000
-0x000000016db8c4f0: 0000000000000000 0000000000000000
-0x000000016db8c500: 0000000000000000 0000000000000000
-0x000000016db8c510: 0000000000000000 0000000000000000
-0x000000016db8c520: 0000000000000000 0000000000000000
-0x000000016db8c530: 0000000000000000 0000000000000000
-0x000000016db8c540: 0000000000000000 0000000000000000
-0x000000016db8c550: 0000000000000000 0000000000000000
-0x000000016db8c560: 0000000000000000 0000000000000000
-0x000000016db8c570: 0000000000000000 0000000000000000
-0x000000016db8c580: 0000000000000000 0000000000000000
-0x000000016db8c590: 0000000000000000 0000000000000000
-0x000000016db8c5a0: 000000010361d7a0 0000000000000000
-0x000000016db8c5b0: 0000000122a47ab0 0000000000000000
-0x000000016db8c5c0: 0000000000000000 0000000000000000
-
-Instructions: (pc=0x00000001248014e4)
-0x00000001248013e4: 1e614000 1400003a d2923809 f2a08ce9
-0x00000001248013f4: f2c00029 6d425935 1e640886 0c402d31
-0x0000000124801404: 1e6408c7 1f5654d0 1e6c1017 1f5050d0
-0x0000000124801414: 1f504cd0 1f5048d0 1e650af6 1f50d8f6
-0x0000000124801424: 1f5694d6 1f5158f6 1e762880 36000501
-0x0000000124801434: 1e614000 14000026 2e251ca5 d2924009
-0x0000000124801444: f2a08ce9 f2c00029 6d425d36 1e600806
-0x0000000124801454: 0c402d32 1f5758c7 1e6c101a 1f4754c7
-0x0000000124801464: 1e650805 1f4750c7 d2866668 f2a7fa68
-0x0000000124801474: 1f474cc7 1e6608c0 1f4748c7 1e6e1019
-0x0000000124801484: eb08007f 540000ac 1f479400 1f460340
-0x0000000124801494: 1e603b20 1400000e d2a7fd29 eb09007f
-0x00000001248014a4: 540000ac 51480069 d3607d29 9e670121
-0x00000001248014b4: 14000002 1e6a5001 1f679417 1f668742
-0x00000001248014c4: 1e613b23 1e773857 1e773860 a8c17ff3
-0x00000001248014d4: 910003bf a8c17bfd d65f03c0 b9400001
-0x00000001248014e4: aa0103e0 d65f03c0 f9400001 aa0103e0
-0x00000001248014f4: d65f03c0 00000000 00000000 00000000
-0x0000000124801504: 00000000 00000000 00000000 00000000
-0x0000000124801514: 00000000 00000000 00000000 00000000
-0x0000000124801524: 00000000 00000000 00000000 00000000
-0x0000000124801534: 00000000 00000000 00000000 00000000
-0x0000000124801544: 00000000 00000000 00000000 00000000
-0x0000000124801554: 00000000 00000000 00000000 00000000
-0x0000000124801564: 00000000 00000000 00000000 00000000
-0x0000000124801574: 00000000 00000000 00000000 00000000
-0x0000000124801584: 00000000 00000000 00000000 00000000
-0x0000000124801594: 00000000 00000000 00000000 00000000
-0x00000001248015a4: 00000000 00000000 00000000 00000000
-0x00000001248015b4: 00000000 00000000 00000000 00000000
-0x00000001248015c4: 00000000 00000000 00000000 00000000
-0x00000001248015d4: 00000000 00000000 00000000 00000000
-
-
-Stack slot to memory mapping:
-stack at sp + 0 slots: 0x000000010e042e00 is a thread
-stack at sp + 1 slots: 0x00000000000007ff is an unknown value
-stack at sp + 2 slots: {method} {0x0000007000259e10} 'inflateBytesBytes' '(J[BII[BII)J' in 'java/util/zip/Inflater'
-stack at sp + 3 slots: 0x000000010e042e00 is a thread
-stack at sp + 4 slots: 0x0000007000259000 is pointing into metadata
-stack at sp + 5 slots: 0x0000007000259e68 is pointing into metadata
-stack at sp + 6 slots: 0x000000016db8c420 is pointing into the stack for thread: 0x000000010e042e00
-stack at sp + 7 slots: 0x00000001041fc890: _ZN2os17is_readable_rangeEPKvS1_+0x2c in /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib at 0x0000000103a34000
-
-StubRoutines::SafeFetch32 [0x00000001248014e0, 0x00000001248014ec] (12 bytes)
-[MachCode]
- 0x00000001248014e0: 0100 40b9 | e003 01aa | c003 5fd6
-[/MachCode]
-
---------------- P R O C E S S ---------------
-
-Threads class SMR info:
-_java_thread_list=0x000060000299b7a0, length=17, elements={
-0x000000010e042e00, 0x000000010e055600, 0x000000010e057e00, 0x000000010e058400,
-0x00000001228fb800, 0x0000000123908600, 0x0000000123908c00, 0x000000010c860e00,
-0x000000010e098a00, 0x000000010e099000, 0x0000000122936a00, 0x000000010c848c00,
-0x0000000123909800, 0x000000010d097e00, 0x000000010d0ac800, 0x000000012219c400,
-0x000000010da13800
-}
-
-Java Threads: ( => current thread )
-=>0x000000010e042e00 JavaThread "main" [_thread_in_native, id=8707, stack(0x000000016d98c000,0x000000016db8f000)]
- 0x000000010e055600 JavaThread "Reference Handler" daemon [_thread_blocked, id=18947, stack(0x000000016e7e0000,0x000000016e9e3000)]
- 0x000000010e057e00 JavaThread "Finalizer" daemon [_thread_blocked, id=19715, stack(0x000000016e9ec000,0x000000016ebef000)]
- 0x000000010e058400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=31235, stack(0x000000016ed10000,0x000000016ef13000)]
- 0x00000001228fb800 JavaThread "Service Thread" daemon [_thread_blocked, id=23299, stack(0x000000016ef1c000,0x000000016f11f000)]
- 0x0000000123908600 JavaThread "Monitor Deflation Thread" daemon [_thread_blocked, id=30723, stack(0x000000016f128000,0x000000016f32b000)]
- 0x0000000123908c00 JavaThread "C1 CompilerThread0" daemon [_thread_in_native, id=30467, stack(0x000000016f334000,0x000000016f537000)]
- 0x000000010c860e00 JavaThread "Sweeper thread" daemon [_thread_blocked, id=29955, stack(0x000000016f540000,0x000000016f743000)]
- 0x000000010e098a00 JavaThread "Common-Cleaner" daemon [_thread_blocked, id=24323, stack(0x000000016f74c000,0x000000016f94f000)]
- 0x000000010e099000 JavaThread "Attach Listener" daemon [_thread_blocked, id=29443, stack(0x000000016f958000,0x000000016fb5b000)]
- 0x0000000122936a00 JavaThread "Monitor Ctrl-Break" daemon [_thread_in_native, id=24835, stack(0x000000016fb64000,0x000000016fd67000)]
- 0x000000010c848c00 JavaThread "JFR Recorder Thread" daemon [_thread_blocked, id=28931, stack(0x000000016fd70000,0x000000016ff73000)]
- 0x0000000123909800 JavaThread "JFR Periodic Tasks" daemon [_thread_blocked, id=28675, stack(0x000000016ff7c000,0x000000017017f000)]
- 0x000000010d097e00 JavaThread "RMI TCP Accept-0" daemon [_thread_in_native, id=27907, stack(0x00000001707ac000,0x00000001709af000)]
- 0x000000010d0ac800 JavaThread "Async-profiler Timer" daemon [_thread_in_native, id=27139, stack(0x0000000170a44000,0x0000000170c47000)]
- 0x000000012219c400 JavaThread "Notification Thread" daemon [_thread_blocked, id=43267, stack(0x0000000170c50000,0x0000000170e53000)]
- 0x000000010da13800 JavaThread "RMI TCP Connection(1)-127.0.0.1" daemon [_thread_in_vm, id=33027, stack(0x0000000171068000,0x000000017126b000)]
-
-Other Threads:
- 0x0000000121f6b3b0 VMThread "VM Thread" [stack: 0x000000016e5d4000,0x000000016e7d7000] [id=20227]
- 0x0000000102837da0 WatcherThread [stack: 0x0000000170e5c000,0x000000017105f000] [id=42755]
- 0x000000010282ba30 GCTaskThread "GC Thread#0" [stack: 0x000000016db98000,0x000000016dd9b000] [id=14339]
- 0x0000000103735f40 GCTaskThread "GC Thread#1" [stack: 0x0000000170188000,0x000000017038b000] [id=25603]
- 0x00000001037367b0 GCTaskThread "GC Thread#2" [stack: 0x0000000170394000,0x0000000170597000] [id=28163]
- 0x0000000121f73800 GCTaskThread "GC Thread#3" [stack: 0x00000001705a0000,0x00000001707a3000] [id=26371]
- 0x000000010282c0e0 ConcurrentGCThread "G1 Main Marker" [stack: 0x000000016dda4000,0x000000016dfa7000] [id=13059]
- 0x000000010361dfb0 ConcurrentGCThread "G1 Conc#0" [stack: 0x000000016dfb0000,0x000000016e1b3000] [id=13827]
- 0x000000010361e820 ConcurrentGCThread "G1 Refine#0" [stack: 0x000000016e1bc000,0x000000016e3bf000] [id=16643]
- 0x0000000121e7c260 ConcurrentGCThread "G1 Service" [stack: 0x000000016e3c8000,0x000000016e5cb000] [id=21251]
-
-Threads with active compile tasks:
-C1 CompilerThread0 4268 1269 1 java.lang.reflect.AccessibleObject::checkCanSetAccessible (368 bytes)
-
-VM state: not at safepoint (normal execution)
-
-VM Mutex/Monitor currently owned by a thread: None
-
-Heap address: 0x0000000780000000, size: 2048 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
-
-CDS archive(s) mapped at: [0x0000007000000000-0x0000007000be0000-0x0000007000be0000), size 12451840, SharedBaseAddress: 0x0000007000000000, ArchiveRelocationMode: 1.
-Compressed class space mapped at: 0x0000007001000000-0x0000007041000000, reserved size: 1073741824
-Narrow klass base: 0x0000007000000000, Narrow klass shift: 0, Narrow klass range: 0x100000000
-
-GC Precious Log:
- CPUs: 8 total, 8 available
- Memory: 8192M
- Large Page Support: Disabled
- NUMA Support: Disabled
- Compressed Oops: Enabled (Zero based)
- Heap Region Size: 1M
- Heap Min Capacity: 8M
- Heap Initial Capacity: 128M
- Heap Max Capacity: 2G
- Pre-touch: Disabled
- Parallel Workers: 8
- Concurrent Workers: 2
- Concurrent Refinement Workers: 8
- Periodic GC: Disabled
-
-Heap:
- garbage-first heap total 133120K, used 14944K [0x0000000780000000, 0x0000000800000000)
- region size 1024K, 9 young (9216K), 3 survivors (3072K)
- Metaspace used 6500K, committed 6720K, reserved 1114112K
- class space used 807K, committed 896K, reserved 1048576K
-
-Heap Regions: E=young(eden), S=young(survivor), O=old, HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, OA=open archive, CA=closed archive, TAMS=top-at-mark-start (previous, next)
-| 0|0x0000000780000000, 0x0000000780100000, 0x0000000780100000|100%|HS| |TAMS 0x0000000780000000, 0x0000000780000000| Complete
-| 1|0x0000000780100000, 0x0000000780200000, 0x0000000780200000|100%|HS| |TAMS 0x0000000780100000, 0x0000000780100000| Complete
-| 2|0x0000000780200000, 0x0000000780300000, 0x0000000780300000|100%| O| |TAMS 0x0000000780200000, 0x0000000780200000| Untracked
-| 3|0x0000000780300000, 0x0000000780400000, 0x0000000780400000|100%| O| |TAMS 0x0000000780300000, 0x0000000780300000| Untracked
-| 4|0x0000000780400000, 0x0000000780500000, 0x0000000780500000|100%| O| |TAMS 0x0000000780400000, 0x0000000780400000| Untracked
-| 5|0x0000000780500000, 0x00000007805a0000, 0x0000000780600000| 62%| O| |TAMS 0x0000000780500000, 0x0000000780500000| Untracked
-| 6|0x0000000780600000, 0x0000000780600000, 0x0000000780700000| 0%| F| |TAMS 0x0000000780600000, 0x0000000780600000| Untracked
-| 7|0x0000000780700000, 0x0000000780700000, 0x0000000780800000| 0%| F| |TAMS 0x0000000780700000, 0x0000000780700000| Untracked
-| 8|0x0000000780800000, 0x0000000780800000, 0x0000000780900000| 0%| F| |TAMS 0x0000000780800000, 0x0000000780800000| Untracked
-| 9|0x0000000780900000, 0x0000000780900000, 0x0000000780a00000| 0%| F| |TAMS 0x0000000780900000, 0x0000000780900000| Untracked
-| 10|0x0000000780a00000, 0x0000000780a00000, 0x0000000780b00000| 0%| F| |TAMS 0x0000000780a00000, 0x0000000780a00000| Untracked
-| 11|0x0000000780b00000, 0x0000000780b00000, 0x0000000780c00000| 0%| F| |TAMS 0x0000000780b00000, 0x0000000780b00000| Untracked
-| 12|0x0000000780c00000, 0x0000000780c00000, 0x0000000780d00000| 0%| F| |TAMS 0x0000000780c00000, 0x0000000780c00000| Untracked
-| 13|0x0000000780d00000, 0x0000000780d00000, 0x0000000780e00000| 0%| F| |TAMS 0x0000000780d00000, 0x0000000780d00000| Untracked
-| 14|0x0000000780e00000, 0x0000000780e00000, 0x0000000780f00000| 0%| F| |TAMS 0x0000000780e00000, 0x0000000780e00000| Untracked
-| 15|0x0000000780f00000, 0x0000000780f00000, 0x0000000781000000| 0%| F| |TAMS 0x0000000780f00000, 0x0000000780f00000| Untracked
-| 16|0x0000000781000000, 0x0000000781000000, 0x0000000781100000| 0%| F| |TAMS 0x0000000781000000, 0x0000000781000000| Untracked
-| 17|0x0000000781100000, 0x0000000781100000, 0x0000000781200000| 0%| F| |TAMS 0x0000000781100000, 0x0000000781100000| Untracked
-| 18|0x0000000781200000, 0x0000000781200000, 0x0000000781300000| 0%| F| |TAMS 0x0000000781200000, 0x0000000781200000| Untracked
-| 19|0x0000000781300000, 0x0000000781300000, 0x0000000781400000| 0%| F| |TAMS 0x0000000781300000, 0x0000000781300000| Untracked
-| 20|0x0000000781400000, 0x0000000781400000, 0x0000000781500000| 0%| F| |TAMS 0x0000000781400000, 0x0000000781400000| Untracked
-| 21|0x0000000781500000, 0x0000000781500000, 0x0000000781600000| 0%| F| |TAMS 0x0000000781500000, 0x0000000781500000| Untracked
-| 22|0x0000000781600000, 0x0000000781600000, 0x0000000781700000| 0%| F| |TAMS 0x0000000781600000, 0x0000000781600000| Untracked
-| 23|0x0000000781700000, 0x0000000781700000, 0x0000000781800000| 0%| F| |TAMS 0x0000000781700000, 0x0000000781700000| Untracked
-| 24|0x0000000781800000, 0x0000000781800000, 0x0000000781900000| 0%| F| |TAMS 0x0000000781800000, 0x0000000781800000| Untracked
-| 25|0x0000000781900000, 0x0000000781900000, 0x0000000781a00000| 0%| F| |TAMS 0x0000000781900000, 0x0000000781900000| Untracked
-| 26|0x0000000781a00000, 0x0000000781a00000, 0x0000000781b00000| 0%| F| |TAMS 0x0000000781a00000, 0x0000000781a00000| Untracked
-| 27|0x0000000781b00000, 0x0000000781b00000, 0x0000000781c00000| 0%| F| |TAMS 0x0000000781b00000, 0x0000000781b00000| Untracked
-| 28|0x0000000781c00000, 0x0000000781c00000, 0x0000000781d00000| 0%| F| |TAMS 0x0000000781c00000, 0x0000000781c00000| Untracked
-| 29|0x0000000781d00000, 0x0000000781d00000, 0x0000000781e00000| 0%| F| |TAMS 0x0000000781d00000, 0x0000000781d00000| Untracked
-| 30|0x0000000781e00000, 0x0000000781e00000, 0x0000000781f00000| 0%| F| |TAMS 0x0000000781e00000, 0x0000000781e00000| Untracked
-| 31|0x0000000781f00000, 0x0000000781f00000, 0x0000000782000000| 0%| F| |TAMS 0x0000000781f00000, 0x0000000781f00000| Untracked
-| 32|0x0000000782000000, 0x0000000782000000, 0x0000000782100000| 0%| F| |TAMS 0x0000000782000000, 0x0000000782000000| Untracked
-| 33|0x0000000782100000, 0x0000000782100000, 0x0000000782200000| 0%| F| |TAMS 0x0000000782100000, 0x0000000782100000| Untracked
-| 34|0x0000000782200000, 0x0000000782200000, 0x0000000782300000| 0%| F| |TAMS 0x0000000782200000, 0x0000000782200000| Untracked
-| 35|0x0000000782300000, 0x0000000782300000, 0x0000000782400000| 0%| F| |TAMS 0x0000000782300000, 0x0000000782300000| Untracked
-| 36|0x0000000782400000, 0x0000000782400000, 0x0000000782500000| 0%| F| |TAMS 0x0000000782400000, 0x0000000782400000| Untracked
-| 37|0x0000000782500000, 0x0000000782500000, 0x0000000782600000| 0%| F| |TAMS 0x0000000782500000, 0x0000000782500000| Untracked
-| 38|0x0000000782600000, 0x0000000782600000, 0x0000000782700000| 0%| F| |TAMS 0x0000000782600000, 0x0000000782600000| Untracked
-| 39|0x0000000782700000, 0x0000000782700000, 0x0000000782800000| 0%| F| |TAMS 0x0000000782700000, 0x0000000782700000| Untracked
-| 40|0x0000000782800000, 0x0000000782800000, 0x0000000782900000| 0%| F| |TAMS 0x0000000782800000, 0x0000000782800000| Untracked
-| 41|0x0000000782900000, 0x0000000782900000, 0x0000000782a00000| 0%| F| |TAMS 0x0000000782900000, 0x0000000782900000| Untracked
-| 42|0x0000000782a00000, 0x0000000782a00000, 0x0000000782b00000| 0%| F| |TAMS 0x0000000782a00000, 0x0000000782a00000| Untracked
-| 43|0x0000000782b00000, 0x0000000782b00000, 0x0000000782c00000| 0%| F| |TAMS 0x0000000782b00000, 0x0000000782b00000| Untracked
-| 44|0x0000000782c00000, 0x0000000782c00000, 0x0000000782d00000| 0%| F| |TAMS 0x0000000782c00000, 0x0000000782c00000| Untracked
-| 45|0x0000000782d00000, 0x0000000782d00000, 0x0000000782e00000| 0%| F| |TAMS 0x0000000782d00000, 0x0000000782d00000| Untracked
-| 46|0x0000000782e00000, 0x0000000782e00000, 0x0000000782f00000| 0%| F| |TAMS 0x0000000782e00000, 0x0000000782e00000| Untracked
-| 47|0x0000000782f00000, 0x0000000782f00000, 0x0000000783000000| 0%| F| |TAMS 0x0000000782f00000, 0x0000000782f00000| Untracked
-| 48|0x0000000783000000, 0x0000000783000000, 0x0000000783100000| 0%| F| |TAMS 0x0000000783000000, 0x0000000783000000| Untracked
-| 49|0x0000000783100000, 0x0000000783100000, 0x0000000783200000| 0%| F| |TAMS 0x0000000783100000, 0x0000000783100000| Untracked
-| 50|0x0000000783200000, 0x0000000783200000, 0x0000000783300000| 0%| F| |TAMS 0x0000000783200000, 0x0000000783200000| Untracked
-| 51|0x0000000783300000, 0x0000000783300000, 0x0000000783400000| 0%| F| |TAMS 0x0000000783300000, 0x0000000783300000| Untracked
-| 52|0x0000000783400000, 0x0000000783400000, 0x0000000783500000| 0%| F| |TAMS 0x0000000783400000, 0x0000000783400000| Untracked
-| 53|0x0000000783500000, 0x0000000783500000, 0x0000000783600000| 0%| F| |TAMS 0x0000000783500000, 0x0000000783500000| Untracked
-| 54|0x0000000783600000, 0x0000000783600000, 0x0000000783700000| 0%| F| |TAMS 0x0000000783600000, 0x0000000783600000| Untracked
-| 55|0x0000000783700000, 0x0000000783700000, 0x0000000783800000| 0%| F| |TAMS 0x0000000783700000, 0x0000000783700000| Untracked
-| 56|0x0000000783800000, 0x0000000783800000, 0x0000000783900000| 0%| F| |TAMS 0x0000000783800000, 0x0000000783800000| Untracked
-| 57|0x0000000783900000, 0x0000000783900000, 0x0000000783a00000| 0%| F| |TAMS 0x0000000783900000, 0x0000000783900000| Untracked
-| 58|0x0000000783a00000, 0x0000000783a00000, 0x0000000783b00000| 0%| F| |TAMS 0x0000000783a00000, 0x0000000783a00000| Untracked
-| 59|0x0000000783b00000, 0x0000000783b00000, 0x0000000783c00000| 0%| F| |TAMS 0x0000000783b00000, 0x0000000783b00000| Untracked
-| 60|0x0000000783c00000, 0x0000000783c00000, 0x0000000783d00000| 0%| F| |TAMS 0x0000000783c00000, 0x0000000783c00000| Untracked
-| 61|0x0000000783d00000, 0x0000000783d00000, 0x0000000783e00000| 0%| F| |TAMS 0x0000000783d00000, 0x0000000783d00000| Untracked
-| 62|0x0000000783e00000, 0x0000000783e00000, 0x0000000783f00000| 0%| F| |TAMS 0x0000000783e00000, 0x0000000783e00000| Untracked
-| 63|0x0000000783f00000, 0x0000000783f00000, 0x0000000784000000| 0%| F| |TAMS 0x0000000783f00000, 0x0000000783f00000| Untracked
-| 64|0x0000000784000000, 0x0000000784000000, 0x0000000784100000| 0%| F| |TAMS 0x0000000784000000, 0x0000000784000000| Untracked
-| 65|0x0000000784100000, 0x0000000784100000, 0x0000000784200000| 0%| F| |TAMS 0x0000000784100000, 0x0000000784100000| Untracked
-| 66|0x0000000784200000, 0x0000000784200000, 0x0000000784300000| 0%| F| |TAMS 0x0000000784200000, 0x0000000784200000| Untracked
-| 67|0x0000000784300000, 0x0000000784300000, 0x0000000784400000| 0%| F| |TAMS 0x0000000784300000, 0x0000000784300000| Untracked
-| 68|0x0000000784400000, 0x0000000784400000, 0x0000000784500000| 0%| F| |TAMS 0x0000000784400000, 0x0000000784400000| Untracked
-| 69|0x0000000784500000, 0x0000000784500000, 0x0000000784600000| 0%| F| |TAMS 0x0000000784500000, 0x0000000784500000| Untracked
-| 70|0x0000000784600000, 0x0000000784600000, 0x0000000784700000| 0%| F| |TAMS 0x0000000784600000, 0x0000000784600000| Untracked
-| 71|0x0000000784700000, 0x0000000784700000, 0x0000000784800000| 0%| F| |TAMS 0x0000000784700000, 0x0000000784700000| Untracked
-| 72|0x0000000784800000, 0x0000000784800000, 0x0000000784900000| 0%| F| |TAMS 0x0000000784800000, 0x0000000784800000| Untracked
-| 73|0x0000000784900000, 0x0000000784900000, 0x0000000784a00000| 0%| F| |TAMS 0x0000000784900000, 0x0000000784900000| Untracked
-| 74|0x0000000784a00000, 0x0000000784a00000, 0x0000000784b00000| 0%| F| |TAMS 0x0000000784a00000, 0x0000000784a00000| Untracked
-| 75|0x0000000784b00000, 0x0000000784b00000, 0x0000000784c00000| 0%| F| |TAMS 0x0000000784b00000, 0x0000000784b00000| Untracked
-| 76|0x0000000784c00000, 0x0000000784c00000, 0x0000000784d00000| 0%| F| |TAMS 0x0000000784c00000, 0x0000000784c00000| Untracked
-| 77|0x0000000784d00000, 0x0000000784d00000, 0x0000000784e00000| 0%| F| |TAMS 0x0000000784d00000, 0x0000000784d00000| Untracked
-| 78|0x0000000784e00000, 0x0000000784e00000, 0x0000000784f00000| 0%| F| |TAMS 0x0000000784e00000, 0x0000000784e00000| Untracked
-| 79|0x0000000784f00000, 0x0000000784f00000, 0x0000000785000000| 0%| F| |TAMS 0x0000000784f00000, 0x0000000784f00000| Untracked
-| 80|0x0000000785000000, 0x0000000785000000, 0x0000000785100000| 0%| F| |TAMS 0x0000000785000000, 0x0000000785000000| Untracked
-| 81|0x0000000785100000, 0x0000000785100000, 0x0000000785200000| 0%| F| |TAMS 0x0000000785100000, 0x0000000785100000| Untracked
-| 82|0x0000000785200000, 0x0000000785200000, 0x0000000785300000| 0%| F| |TAMS 0x0000000785200000, 0x0000000785200000| Untracked
-| 83|0x0000000785300000, 0x0000000785300000, 0x0000000785400000| 0%| F| |TAMS 0x0000000785300000, 0x0000000785300000| Untracked
-| 84|0x0000000785400000, 0x0000000785400000, 0x0000000785500000| 0%| F| |TAMS 0x0000000785400000, 0x0000000785400000| Untracked
-| 85|0x0000000785500000, 0x0000000785500000, 0x0000000785600000| 0%| F| |TAMS 0x0000000785500000, 0x0000000785500000| Untracked
-| 86|0x0000000785600000, 0x0000000785600000, 0x0000000785700000| 0%| F| |TAMS 0x0000000785600000, 0x0000000785600000| Untracked
-| 87|0x0000000785700000, 0x0000000785700000, 0x0000000785800000| 0%| F| |TAMS 0x0000000785700000, 0x0000000785700000| Untracked
-| 88|0x0000000785800000, 0x0000000785800000, 0x0000000785900000| 0%| F| |TAMS 0x0000000785800000, 0x0000000785800000| Untracked
-| 89|0x0000000785900000, 0x0000000785900000, 0x0000000785a00000| 0%| F| |TAMS 0x0000000785900000, 0x0000000785900000| Untracked
-| 90|0x0000000785a00000, 0x0000000785a00000, 0x0000000785b00000| 0%| F| |TAMS 0x0000000785a00000, 0x0000000785a00000| Untracked
-| 91|0x0000000785b00000, 0x0000000785b00000, 0x0000000785c00000| 0%| F| |TAMS 0x0000000785b00000, 0x0000000785b00000| Untracked
-| 92|0x0000000785c00000, 0x0000000785c00000, 0x0000000785d00000| 0%| F| |TAMS 0x0000000785c00000, 0x0000000785c00000| Untracked
-| 93|0x0000000785d00000, 0x0000000785d00000, 0x0000000785e00000| 0%| F| |TAMS 0x0000000785d00000, 0x0000000785d00000| Untracked
-| 94|0x0000000785e00000, 0x0000000785e00000, 0x0000000785f00000| 0%| F| |TAMS 0x0000000785e00000, 0x0000000785e00000| Untracked
-| 95|0x0000000785f00000, 0x0000000785f00000, 0x0000000786000000| 0%| F| |TAMS 0x0000000785f00000, 0x0000000785f00000| Untracked
-| 96|0x0000000786000000, 0x0000000786000000, 0x0000000786100000| 0%| F| |TAMS 0x0000000786000000, 0x0000000786000000| Untracked
-| 97|0x0000000786100000, 0x0000000786100000, 0x0000000786200000| 0%| F| |TAMS 0x0000000786100000, 0x0000000786100000| Untracked
-| 98|0x0000000786200000, 0x0000000786200000, 0x0000000786300000| 0%| F| |TAMS 0x0000000786200000, 0x0000000786200000| Untracked
-| 99|0x0000000786300000, 0x0000000786300000, 0x0000000786400000| 0%| F| |TAMS 0x0000000786300000, 0x0000000786300000| Untracked
-| 100|0x0000000786400000, 0x0000000786400000, 0x0000000786500000| 0%| F| |TAMS 0x0000000786400000, 0x0000000786400000| Untracked
-| 101|0x0000000786500000, 0x0000000786500000, 0x0000000786600000| 0%| F| |TAMS 0x0000000786500000, 0x0000000786500000| Untracked
-| 102|0x0000000786600000, 0x0000000786700000, 0x0000000786700000|100%| S|CS|TAMS 0x0000000786600000, 0x0000000786600000| Complete
-| 103|0x0000000786700000, 0x0000000786800000, 0x0000000786800000|100%| S|CS|TAMS 0x0000000786700000, 0x0000000786700000| Complete
-| 104|0x0000000786800000, 0x0000000786900000, 0x0000000786900000|100%| S|CS|TAMS 0x0000000786800000, 0x0000000786800000| Complete
-| 105|0x0000000786900000, 0x0000000786900000, 0x0000000786a00000| 0%| F| |TAMS 0x0000000786900000, 0x0000000786900000| Untracked
-| 106|0x0000000786a00000, 0x0000000786a00000, 0x0000000786b00000| 0%| F| |TAMS 0x0000000786a00000, 0x0000000786a00000| Untracked
-| 107|0x0000000786b00000, 0x0000000786b00000, 0x0000000786c00000| 0%| F| |TAMS 0x0000000786b00000, 0x0000000786b00000| Untracked
-| 108|0x0000000786c00000, 0x0000000786c00000, 0x0000000786d00000| 0%| F| |TAMS 0x0000000786c00000, 0x0000000786c00000| Untracked
-| 109|0x0000000786d00000, 0x0000000786d00000, 0x0000000786e00000| 0%| F| |TAMS 0x0000000786d00000, 0x0000000786d00000| Untracked
-| 110|0x0000000786e00000, 0x0000000786e00000, 0x0000000786f00000| 0%| F| |TAMS 0x0000000786e00000, 0x0000000786e00000| Untracked
-| 111|0x0000000786f00000, 0x0000000786f00000, 0x0000000787000000| 0%| F| |TAMS 0x0000000786f00000, 0x0000000786f00000| Untracked
-| 112|0x0000000787000000, 0x0000000787000000, 0x0000000787100000| 0%| F| |TAMS 0x0000000787000000, 0x0000000787000000| Untracked
-| 113|0x0000000787100000, 0x0000000787100000, 0x0000000787200000| 0%| F| |TAMS 0x0000000787100000, 0x0000000787100000| Untracked
-| 114|0x0000000787200000, 0x0000000787200000, 0x0000000787300000| 0%| F| |TAMS 0x0000000787200000, 0x0000000787200000| Untracked
-| 115|0x0000000787300000, 0x0000000787300000, 0x0000000787400000| 0%| F| |TAMS 0x0000000787300000, 0x0000000787300000| Untracked
-| 116|0x0000000787400000, 0x0000000787400000, 0x0000000787500000| 0%| F| |TAMS 0x0000000787400000, 0x0000000787400000| Untracked
-| 117|0x0000000787500000, 0x0000000787500000, 0x0000000787600000| 0%| F| |TAMS 0x0000000787500000, 0x0000000787500000| Untracked
-| 118|0x0000000787600000, 0x0000000787600000, 0x0000000787700000| 0%| F| |TAMS 0x0000000787600000, 0x0000000787600000| Untracked
-| 119|0x0000000787700000, 0x0000000787700000, 0x0000000787800000| 0%| F| |TAMS 0x0000000787700000, 0x0000000787700000| Untracked
-| 120|0x0000000787800000, 0x0000000787800000, 0x0000000787900000| 0%| F| |TAMS 0x0000000787800000, 0x0000000787800000| Untracked
-| 121|0x0000000787900000, 0x0000000787900000, 0x0000000787a00000| 0%| F| |TAMS 0x0000000787900000, 0x0000000787900000| Untracked
-| 122|0x0000000787a00000, 0x0000000787ac8340, 0x0000000787b00000| 78%| E| |TAMS 0x0000000787a00000, 0x0000000787a00000| Complete
-| 123|0x0000000787b00000, 0x0000000787c00000, 0x0000000787c00000|100%| E|CS|TAMS 0x0000000787b00000, 0x0000000787b00000| Complete
-| 124|0x0000000787c00000, 0x0000000787d00000, 0x0000000787d00000|100%| E|CS|TAMS 0x0000000787c00000, 0x0000000787c00000| Complete
-| 125|0x0000000787d00000, 0x0000000787e00000, 0x0000000787e00000|100%| E|CS|TAMS 0x0000000787d00000, 0x0000000787d00000| Complete
-| 126|0x0000000787e00000, 0x0000000787f00000, 0x0000000787f00000|100%| E|CS|TAMS 0x0000000787e00000, 0x0000000787e00000| Complete
-| 127|0x0000000787f00000, 0x0000000788000000, 0x0000000788000000|100%| E|CS|TAMS 0x0000000787f00000, 0x0000000787f00000| Complete
-|2046|0x00000007ffe00000, 0x00000007ffe78000, 0x00000007fff00000| 46%|OA| |TAMS 0x00000007ffe00000, 0x00000007ffe00000| Untracked
-|2047|0x00000007fff00000, 0x00000007fff80000, 0x0000000800000000| 50%|CA| |TAMS 0x00000007fff00000, 0x00000007fff00000| Untracked
-
-Card table byte_map: [0x000000010ec00000,0x000000010f000000] _byte_map_base: 0x000000010b000000
-
-Marking Bits (Prev, Next): (CMBitMap*) 0x000000010d032210, (CMBitMap*) 0x000000010d032250
- Prev Bits: [0x0000000158000000, 0x000000015a000000)
- Next Bits: [0x000000015a000000, 0x000000015c000000)
-
-Polling page: 0x0000000102514000
-
-Metaspace:
-
-Usage:
- Non-class: 5.57 MB used.
- Class: 809.43 KB used.
- Both: 6.36 MB used.
-
-Virtual space:
- Non-class space: 64.00 MB reserved, 5.69 MB ( 9%) committed, 1 nodes.
- Class space: 1.00 GB reserved, 896.00 KB ( <1%) committed, 1 nodes.
- Both: 1.06 GB reserved, 6.56 MB ( <1%) committed.
-
-Chunk freelists:
- Non-Class: 10.30 MB
- Class: 15.10 MB
- Both: 25.39 MB
-
-MaxMetaspaceSize: unlimited
-CompressedClassSpaceSize: 1.00 GB
-Initial GC threshold: 21.00 MB
-Current GC threshold: 21.00 MB
-CDS: on
-MetaspaceReclaimPolicy: balanced
- - commit_granule_bytes: 65536.
- - commit_granule_words: 8192.
- - virtual_space_node_default_size: 8388608.
- - enlarge_chunks_in_place: 1.
- - new_chunks_are_fully_committed: 0.
- - uncommit_free_chunks: 1.
- - use_allocation_guard: 0.
- - handle_deallocations: 1.
-
-
-Internal statistics:
-
-num_allocs_failed_limit: 0.
-num_arena_births: 136.
-num_arena_deaths: 0.
-num_vsnodes_births: 2.
-num_vsnodes_deaths: 0.
-num_space_committed: 105.
-num_space_uncommitted: 0.
-num_chunks_returned_to_freelist: 0.
-num_chunks_taken_from_freelist: 195.
-num_chunk_merges: 0.
-num_chunk_splits: 103.
-num_chunks_enlarged: 26.
-num_inconsistent_stats: 0.
-
-CodeCache: size=49152Kb used=3474Kb max_used=3474Kb free=45677Kb
- bounds [0x0000000124800000, 0x0000000124b70000, 0x0000000127800000]
- total_blobs=1771 nmethods=1313 adapters=389
- compilation: enabled
- stopped_count=0, restarted_count=0
- full_count=0
-
-Compilation events (20 events):
-Event: 4.211 Thread 0x0000000123908c00 nmethod 1305 0x0000000124b58710 code [0x0000000124b58880, 0x0000000124b58918]
-Event: 4.211 Thread 0x0000000123908c00 1272 1 java.lang.invoke.MemberName::isCallerSensitive (8 bytes)
-Event: 4.211 Thread 0x0000000123908c00 nmethod 1272 0x0000000124b58a10 code [0x0000000124b58b80, 0x0000000124b58c58]
-Event: 4.211 Thread 0x0000000123908c00 1291 1 java.lang.invoke.MethodType::basicType (8 bytes)
-Event: 4.211 Thread 0x0000000123908c00 nmethod 1291 0x0000000124b58d10 code [0x0000000124b58e80, 0x0000000124b58f58]
-Event: 4.211 Thread 0x0000000123908c00 1303 1 jdk.jfr.internal.PlatformEventType::isLargeSize (5 bytes)
-Event: 4.212 Thread 0x0000000123908c00 nmethod 1303 0x0000000124b59090 code [0x0000000124b59200, 0x0000000124b59298]
-Event: 4.212 Thread 0x0000000123908c00 1304 1 jdk.jfr.internal.PlatformEventType::getStackTraceEnabled (5 bytes)
-Event: 4.212 Thread 0x0000000123908c00 nmethod 1304 0x0000000124b59390 code [0x0000000124b59500, 0x0000000124b59598]
-Event: 4.212 Thread 0x0000000123908c00 1273 1 java.lang.reflect.Modifier::isAbstract (14 bytes)
-Event: 4.212 Thread 0x0000000123908c00 nmethod 1273 0x0000000124b59690 code [0x0000000124b59800, 0x0000000124b59898]
-Event: 4.212 Thread 0x0000000123908c00 1275 1 jdk.internal.org.objectweb.asm.ClassWriter::visitField (53 bytes)
-Event: 4.212 Thread 0x0000000123908c00 nmethod 1275 0x0000000124b59990 code [0x0000000124b59b40, 0x0000000124b59df8]
-Event: 4.212 Thread 0x0000000123908c00 1276 1 jdk.internal.org.objectweb.asm.FieldWriter:: (69 bytes)
-Event: 4.213 Thread 0x0000000123908c00 nmethod 1276 0x0000000124b5a010 code [0x0000000124b5a1c0, 0x0000000124b5a438]
-Event: 4.213 Thread 0x0000000123908c00 1313 1 java.util.WeakHashMap::matchesKey (33 bytes)
-Event: 4.214 Thread 0x0000000123908c00 nmethod 1313 0x0000000124b5a710 code [0x0000000124b5a8c0, 0x0000000124b5aa98]
-Event: 4.214 Thread 0x0000000123908c00 1314 ! 1 jdk.internal.loader.URLClassPath$JarLoader::ensureOpen (36 bytes)
-Event: 4.216 Thread 0x0000000123908c00 nmethod 1314 0x0000000124b5ac90 code [0x0000000124b5ae80, 0x0000000124b5b378]
-Event: 4.216 Thread 0x0000000123908c00 1315 s! 1 jdk.internal.loader.URLClassPath::getLoader (194 bytes)
-
-GC Heap History (2 events):
-Event: 4.100 GC heap before
-{Heap before GC invocations=0 (full 0):
- garbage-first heap total 133120K, used 25568K [0x0000000780000000, 0x0000000800000000)
- region size 1024K, 23 young (23552K), 0 survivors (0K)
- Metaspace used 5388K, committed 5632K, reserved 1114112K
- class space used 667K, committed 768K, reserved 1048576K
-}
-Event: 4.113 GC heap after
-{Heap after GC invocations=1 (full 0):
- garbage-first heap total 133120K, used 9824K [0x0000000780000000, 0x0000000800000000)
- region size 1024K, 3 young (3072K), 3 survivors (3072K)
- Metaspace used 5388K, committed 5632K, reserved 1114112K
- class space used 667K, committed 768K, reserved 1048576K
-}
-
-Dll operation events (10 events):
-Event: 2.839 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjava.dylib
-Event: 3.356 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib
-Event: 3.389 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libinstrument.dylib
-Event: 3.412 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnio.dylib
-Event: 3.427 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib
-Event: 3.543 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjimage.dylib
-Event: 3.609 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnet.dylib
-Event: 3.631 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libextnet.dylib
-Event: 3.803 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement.dylib
-Event: 3.837 Loaded shared library /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement_ext.dylib
-
-Deoptimization events (6 events):
-Event: 3.883 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124a52598 sp=0x000000016db8c970
-Event: 3.883 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8c660 mode 3
-Event: 3.906 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124a0cf0c sp=0x000000016db8da10
-Event: 3.906 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8d780 mode 3
-Event: 4.036 Thread 0x000000010e042e00 DEOPT PACKING pc=0x0000000124ae9d74 sp=0x000000016db8c3b0
-Event: 4.036 Thread 0x000000010e042e00 DEOPT UNPACKING pc=0x000000012484777c sp=0x000000016db8c070 mode 3
-
-Classes unloaded (0 events):
-No events
-
-Classes redefined (20 events):
-Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=sun.nio.ch.SocketChannelImpl, count=1
-Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=java.lang.Throwable, count=1
-Event: 4.092 Thread 0x0000000121f6b3b0 redefined class name=java.lang.Error, count=2
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.internal.event.ProcessStartEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerIOUsageEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerMemoryUsageEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerCPUThrottlingEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerCPUUsageEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ContainerConfigurationEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.InitialSecurityPropertyEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.DirectBufferStatisticsEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ActiveRecordingEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ActiveSettingEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ErrorThrownEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.ExceptionStatisticsEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.SocketWriteEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.SocketReadEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileWriteEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileReadEvent, count=1
-Event: 4.182 Thread 0x0000000121f6b3b0 redefined class name=jdk.jfr.events.FileForceEvent, count=1
-
-Internal exceptions (20 events):
-Event: 3.902 Thread 0x000000010e042e00 Exception (0x0000000787181a78)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.905 Thread 0x000000010e042e00 Exception (0x0000000787193f50)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.908 Thread 0x000000010e042e00 Exception (0x00000007871a3f48)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.909 Thread 0x000000010e042e00 Exception (0x00000007871b0e68)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.912 Thread 0x000000010e042e00 Exception (0x00000007871be7a8)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.917 Thread 0x000000010e099000 Exception (0x00000007871431f0)
-thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759]
-Event: 3.918 Thread 0x000000010e042e00 Exception (0x00000007871e63f8)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.921 Thread 0x000000010e042e00 Exception (0x0000000787001198)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.925 Thread 0x000000010e042e00 Exception (0x0000000787013318)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.930 Thread 0x000000010e042e00 Exception (0x0000000787023520)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.932 Thread 0x000000010e042e00 Exception (0x000000078702ee80)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.937 Thread 0x000000010e042e00 Exception (0x0000000787045768)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.940 Thread 0x000000010e042e00 Exception (0x0000000787055278)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.942 Thread 0x000000010e042e00 Exception (0x0000000787062be0)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.945 Thread 0x000000010e042e00 Exception (0x0000000787070c60)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 3.946 Thread 0x000000010e042e00 Exception (0x00000007870f37d8)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-Event: 4.097 Thread 0x000000010e042e00 Exception (0x00000007869dc758)
-thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759]
-Event: 4.098 Thread 0x000000010e042e00 Exception (0x00000007869e26b0)
-thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759]
-Event: 4.128 Thread 0x000000010e042e00 Exception (0x0000000787f6de50)
-thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 759]
-Event: 4.169 Thread 0x000000010e099000 Exception (0x0000000787da3bd8)
-thrown [src/hotspot/share/classfile/systemDictionary.cpp, line 256]
-
-VM Operations (20 events):
-Event: 3.856 Executing VM operation: ICBufferFull
-Event: 3.856 Executing VM operation: ICBufferFull done
-Event: 4.044 Executing VM operation: ICBufferFull
-Event: 4.044 Executing VM operation: ICBufferFull done
-Event: 4.090 Executing VM operation: RedefineClasses
-Event: 4.096 Executing VM operation: RedefineClasses done
-Event: 4.100 Executing VM operation: G1CollectForAllocation
-Event: 4.114 Executing VM operation: G1CollectForAllocation done
-Event: 4.125 Executing VM operation: HandshakeAllThreads
-Event: 4.125 Executing VM operation: HandshakeAllThreads done
-Event: 4.163 Executing VM operation: JFRCheckpoint
-Event: 4.163 Executing VM operation: JFRCheckpoint done
-Event: 4.167 Executing VM operation: JFROldObject
-Event: 4.167 Executing VM operation: JFROldObject done
-Event: 4.180 Executing VM operation: RedefineClasses
-Event: 4.185 Executing VM operation: RedefineClasses done
-Event: 4.196 Executing VM operation: ClassLoaderStatsOperation
-Event: 4.197 Executing VM operation: ClassLoaderStatsOperation done
-Event: 4.207 Executing VM operation: HandshakeAllThreads
-Event: 4.208 Executing VM operation: HandshakeAllThreads done
-
-Events (20 events):
-Event: 4.195 loading class sun/rmi/server/MarshalOutputStream done
-Event: 4.195 loading class sun/rmi/transport/ConnectionOutputStream done
-Event: 4.197 loading class jdk/internal/agent/ConnectorAddressLink
-Event: 4.198 loading class jdk/internal/agent/ConnectorAddressLink done
-Event: 4.198 loading class sun/management/counter/Units
-Event: 4.198 loading class sun/management/counter/Units done
-Event: 4.205 Thread 0x000000010d0ac800 Thread added: 0x000000010d0ac800
-Event: 4.205 Protecting memory [0x0000000170a44000,0x0000000170a50000] with protection modes 0
-Event: 4.205 Thread 0x000000012219c400 Thread added: 0x000000012219c400
-Event: 4.205 Protecting memory [0x0000000170c50000,0x0000000170c5c000] with protection modes 0
-Event: 4.205 loading class jdk/internal/vm/PostVMInitHook
-Event: 4.205 loading class jdk/internal/vm/PostVMInitHook done
-Event: 4.207 loading class jdk/internal/loader/URLClassPath$FileLoader$1
-Event: 4.207 loading class jdk/internal/loader/URLClassPath$FileLoader$1 done
-Event: 4.209 loading class sun/security/util/ManifestEntryVerifier
-Event: 4.209 loading class sun/security/util/ManifestEntryVerifier done
-Event: 4.215 loading class java/lang/UnsupportedOperationException
-Event: 4.215 loading class java/lang/UnsupportedOperationException done
-Event: 4.216 loading class java/lang/AssertionError
-Event: 4.217 loading class java/lang/AssertionError done
-
-
-Dynamic libraries:
-0x0000000102980000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjli.dylib
-0x00000001b7ac9000 /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
-0x00000001a10aa000 /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
-0x00000001a4118000 /System/Library/Frameworks/CoreData.framework/Versions/A/CoreData
-0x000000019e964000 /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
-0x00000001aa41e000 /usr/lib/libSystem.B.dylib
-0x00000001a23e7000 /System/Library/PrivateFrameworks/UIFoundation.framework/Versions/A/UIFoundation
-0x0000000238046000 /System/Library/PrivateFrameworks/CollectionViewCore.framework/Versions/A/CollectionViewCore
-0x00000001b1680000 /System/Library/PrivateFrameworks/RemoteViewServices.framework/Versions/A/RemoteViewServices
-0x00000001a82d0000 /System/Library/PrivateFrameworks/XCTTargetBootstrap.framework/Versions/A/XCTTargetBootstrap
-0x00000001aca58000 /System/Library/PrivateFrameworks/InternationalSupport.framework/Versions/A/InternationalSupport
-0x00000001acaac000 /System/Library/PrivateFrameworks/UserActivity.framework/Versions/A/UserActivity
-0x000000025b9a2000 /System/Library/PrivateFrameworks/WindowManagement.framework/Versions/A/WindowManagement
-0x000000019e5e4000 /System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration
-0x00000001abec7000 /usr/lib/libspindump.dylib
-0x00000001a259c000 /System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers
-0x00000001a614a000 /usr/lib/libapp_launch_measurement.dylib
-0x00000001a5572000 /System/Library/PrivateFrameworks/CoreAnalytics.framework/Versions/A/CoreAnalytics
-0x00000001a6151000 /System/Library/PrivateFrameworks/CoreAutoLayout.framework/Versions/A/CoreAutoLayout
-0x00000001a7af1000 /System/Library/Frameworks/Metal.framework/Versions/A/Metal
-0x00000001a8a77000 /usr/lib/liblangid.dylib
-0x00000001a82d6000 /System/Library/PrivateFrameworks/CoreSVG.framework/Versions/A/CoreSVG
-0x00000001a2f65000 /System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight
-0x00000001a3405000 /System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics
-0x00000001b1d53000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate
-0x00000001abd22000 /System/Library/PrivateFrameworks/IconServices.framework/Versions/A/IconServices
-0x00000001a7acf000 /System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface
-0x00000001a55a1000 /usr/lib/libDiagnosticMessagesClient.dylib
-0x00000001aa361000 /usr/lib/libz.1.dylib
-0x00000001b54ef000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices
-0x00000001a82b8000 /System/Library/PrivateFrameworks/DFRFoundation.framework/Versions/A/DFRFoundation
-0x00000001a0904000 /usr/lib/libicucore.A.dylib
-0x00000001adab5000 /System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox
-0x00000001aca67000 /System/Library/PrivateFrameworks/DataDetectorsCore.framework/Versions/A/DataDetectorsCore
-0x00000001c6442000 /System/Library/PrivateFrameworks/TextInput.framework/Versions/A/TextInput
-0x00000001a2eb6000 /usr/lib/libMobileGestalt.dylib
-0x00000001a7ff4000 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox
-0x00000001a5a78000 /System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore
-0x00000001a0531000 /System/Library/Frameworks/Security.framework/Versions/A/Security
-0x00000001b16c0000 /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/SpeechRecognition.framework/Versions/A/SpeechRecognition
-0x00000001a5e78000 /System/Library/PrivateFrameworks/CoreUI.framework/Versions/A/CoreUI
-0x000000019fe30000 /System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio
-0x00000001a5685000 /System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration
-0x00000001ac322000 /System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport
-0x00000001a2eb4000 /usr/lib/libenergytrace.dylib
-0x00000001bbbcb000 /System/Library/PrivateFrameworks/RenderBox.framework/Versions/A/RenderBox
-0x00000001a0f5e000 /System/Library/Frameworks/IOKit.framework/Versions/A/IOKit
-0x00000001b1a94000 /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices
-0x00000001a60d6000 /System/Library/PrivateFrameworks/PerformanceAnalysis.framework/Versions/A/PerformanceAnalysis
-0x00000001f3dad000 /System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL
-0x00000001a619b000 /usr/lib/libxml2.2.dylib
-0x00000001a97a6000 /System/Library/PrivateFrameworks/MobileKeyBag.framework/Versions/A/MobileKeyBag
-0x000000019d3d0000 /usr/lib/libobjc.A.dylib
-0x000000019d6c4000 /usr/lib/libc++.1.dylib
-0x00000001b1a11000 /System/Library/Frameworks/Accessibility.framework/Versions/A/Accessibility
-0x00000001a3ae4000 /System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync
-0x000000019d810000 /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
-0x00000001a8632000 /System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage
-0x000000019fc3b000 /System/Library/Frameworks/CoreText.framework/Versions/A/CoreText
-0x00000001f8607000 /System/Library/Frameworks/CoreTransferable.framework/Versions/A/CoreTransferable
-0x00000001f8acc000 /System/Library/Frameworks/DeveloperToolsSupport.framework/Versions/A/DeveloperToolsSupport
-0x00000001a8311000 /System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO
-0x00000001fce33000 /System/Library/Frameworks/Symbols.framework/Versions/A/Symbols
-0x00000001aa424000 /System/Library/PrivateFrameworks/SoftLinking.framework/Versions/A/SoftLinking
-0x00000001ad467000 /usr/lib/swift/libswiftCore.dylib
-0x00000001c30eb000 /usr/lib/swift/libswiftCoreFoundation.dylib
-0x00000001c0bf2000 /usr/lib/swift/libswiftCoreGraphics.dylib
-0x00000001c3135000 /usr/lib/swift/libswiftCoreImage.dylib
-0x00000001c0bf9000 /usr/lib/swift/libswiftDarwin.dylib
-0x00000001b30f9000 /usr/lib/swift/libswiftDispatch.dylib
-0x00000001c3136000 /usr/lib/swift/libswiftIOKit.dylib
-0x00000001ceb3b000 /usr/lib/swift/libswiftMetal.dylib
-0x00000001dc1af000 /usr/lib/swift/libswiftOSLog.dylib
-0x00000001b5968000 /usr/lib/swift/libswiftObjectiveC.dylib
-0x00000001d325c000 /usr/lib/swift/libswiftQuartzCore.dylib
-0x00000001d7343000 /usr/lib/swift/libswiftUniformTypeIdentifiers.dylib
-0x00000001c30fd000 /usr/lib/swift/libswiftXPC.dylib
-0x0000000263e4d000 /usr/lib/swift/libswift_Concurrency.dylib
-0x00000001b596c000 /usr/lib/swift/libswiftos.dylib
-0x00000001c63a7000 /usr/lib/swift/libswiftsimd.dylib
-0x00000001aa5d3000 /usr/lib/libcompression.dylib
-0x00000001ac9b2000 /System/Library/PrivateFrameworks/TextureIO.framework/Versions/A/TextureIO
-0x00000001ab9ce000 /usr/lib/libate.dylib
-0x00000001aa418000 /usr/lib/system/libcache.dylib
-0x00000001aa3d3000 /usr/lib/system/libcommonCrypto.dylib
-0x00000001aa3ff000 /usr/lib/system/libcompiler_rt.dylib
-0x00000001aa3f5000 /usr/lib/system/libcopyfile.dylib
-0x000000019d514000 /usr/lib/system/libcorecrypto.dylib
-0x000000019d5fa000 /usr/lib/system/libdispatch.dylib
-0x000000019d7b5000 /usr/lib/system/libdyld.dylib
-0x00000001aa40e000 /usr/lib/system/libkeymgr.dylib
-0x00000001aa3ab000 /usr/lib/system/libmacho.dylib
-0x00000001a988c000 /usr/lib/system/libquarantine.dylib
-0x00000001aa40b000 /usr/lib/system/libremovefile.dylib
-0x00000001a2f2c000 /usr/lib/system/libsystem_asl.dylib
-0x000000019d4a9000 /usr/lib/system/libsystem_blocks.dylib
-0x000000019d645000 /usr/lib/system/libsystem_c.dylib
-0x00000001aa403000 /usr/lib/system/libsystem_collections.dylib
-0x00000001a8a66000 /usr/lib/system/libsystem_configuration.dylib
-0x00000001a7aa4000 /usr/lib/system/libsystem_containermanager.dylib
-0x00000001aa042000 /usr/lib/system/libsystem_coreservices.dylib
-0x00000001a0bcb000 /usr/lib/system/libsystem_darwin.dylib
-0x000000026419a000 /usr/lib/system/libsystem_darwindirectory.dylib
-0x00000001aa40f000 /usr/lib/system/libsystem_dnssd.dylib
-0x000000026419e000 /usr/lib/system/libsystem_eligibility.dylib
-0x000000019d642000 /usr/lib/system/libsystem_featureflags.dylib
-0x000000019d7e3000 /usr/lib/system/libsystem_info.dylib
-0x00000001aa370000 /usr/lib/system/libsystem_m.dylib
-0x000000019d5bd000 /usr/lib/system/libsystem_malloc.dylib
-0x00000001a2e9a000 /usr/lib/system/libsystem_networkextension.dylib
-0x00000001a1041000 /usr/lib/system/libsystem_notify.dylib
-0x00000001a8a6b000 /usr/lib/system/libsystem_sandbox.dylib
-0x00000002641a2000 /usr/lib/system/libsystem_sanitizers.dylib
-0x00000001aa408000 /usr/lib/system/libsystem_secinit.dylib
-0x000000019d76d000 /usr/lib/system/libsystem_kernel.dylib
-0x000000019d7db000 /usr/lib/system/libsystem_platform.dylib
-0x000000019d7a8000 /usr/lib/system/libsystem_pthread.dylib
-0x00000001a491a000 /usr/lib/system/libsystem_symptoms.dylib
-0x000000019d4f9000 /usr/lib/system/libsystem_trace.dylib
-0x00000001aa3e1000 /usr/lib/system/libunwind.dylib
-0x000000019d4ae000 /usr/lib/system/libxpc.dylib
-0x000000019d751000 /usr/lib/libc++abi.dylib
-0x00000001aa3ed000 /usr/lib/liboah.dylib
-0x00000001ab87a000 /usr/lib/liblzma.5.dylib
-0x00000001aa420000 /usr/lib/libfakelink.dylib
-0x00000001a2ac5000 /System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork
-0x00000001aa474000 /usr/lib/libarchive.2.dylib
-0x00000001af996000 /System/Library/Frameworks/Combine.framework/Versions/A/Combine
-0x000000023805a000 /System/Library/PrivateFrameworks/CollectionsInternal.framework/Versions/A/CollectionsInternal
-0x000000024e0eb000 /System/Library/PrivateFrameworks/ReflectionInternal.framework/Versions/A/ReflectionInternal
-0x000000024e671000 /System/Library/PrivateFrameworks/RuntimeInternal.framework/Versions/A/RuntimeInternal
-0x0000000263fa1000 /usr/lib/swift/libswift_StringProcessing.dylib
-0x00000001a0edc000 /System/Library/PrivateFrameworks/CoreServicesInternal.framework/Versions/A/CoreServicesInternal
-0x00000001a98b3000 /usr/lib/libbsm.0.dylib
-0x00000001aa3b3000 /usr/lib/system/libkxld.dylib
-0x00000001a6112000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents
-0x00000001a0bd6000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore
-0x00000001a55ea000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata
-0x00000001aa048000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices
-0x00000001aa4fd000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit
-0x00000001a489b000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE
-0x000000019dce9000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices
-0x00000001ab823000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices
-0x00000001a611f000 /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList
-0x00000001aa59d000 /usr/lib/libapple_nghttp2.dylib
-0x00000001a450f000 /usr/lib/libsqlite3.dylib
-0x00000001a4923000 /System/Library/Frameworks/Network.framework/Versions/A/Network
-0x000000026285a000 /usr/lib/libCoreEntitlements.dylib
-0x000000024901d000 /System/Library/PrivateFrameworks/MessageSecurity.framework/Versions/A/MessageSecurity
-0x00000001a44f5000 /System/Library/PrivateFrameworks/ProtocolBuffer.framework/Versions/A/ProtocolBuffer
-0x00000001a9f71000 /System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression
-0x00000001a989b000 /usr/lib/libcoretls.dylib
-0x00000001ab899000 /usr/lib/libcoretls_cfhelpers.dylib
-0x00000001aa5cd000 /usr/lib/libpam.2.dylib
-0x00000001ab90b000 /usr/lib/libxar.1.dylib
-0x00000001abcf9000 /usr/lib/libheimdal-asn1.dylib
-0x00000001a2ac4000 /usr/lib/libnetwork.dylib
-0x00000001aa425000 /usr/lib/libpcap.A.dylib
-0x00000001a490f000 /usr/lib/libdns_services.dylib
-0x00000001a8a73000 /System/Library/PrivateFrameworks/AppleSystemInfo.framework/Versions/A/AppleSystemInfo
-0x00000001a959b000 /System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/Versions/A/IOMobileFramebuffer
-0x0000000263ef8000 /usr/lib/swift/libswift_RegexParser.dylib
-0x00000001aa035000 /usr/lib/libbz2.1.0.dylib
-0x00000001a988f000 /usr/lib/libCheckFix.dylib
-0x00000001a2f44000 /System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC
-0x00000001a8a79000 /System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP
-0x00000001a55a3000 /System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities
-0x00000001a98c5000 /usr/lib/libmecab.dylib
-0x000000019e678000 /usr/lib/libCRFSuite.dylib
-0x00000001a9921000 /usr/lib/libgermantok.dylib
-0x00000001aa574000 /usr/lib/libThaiTokenizer.dylib
-0x00000001a568e000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage
-0x00000001b1a6b000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib
-0x00000001ab952000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib
-0x00000001a9476000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib
-0x000000019e0ef000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
-0x00000001aa6a8000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib
-0x00000001a9924000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib
-0x00000001aa5b8000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib
-0x00000001aa6a3000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib
-0x00000001a8ba2000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib
-0x000000019e57d000 /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib
-0x000000024776c000 /System/Library/PrivateFrameworks/MIL.framework/Versions/A/MIL
-0x00000001aa45b000 /usr/lib/libiconv.2.dylib
-0x00000001aa3a7000 /usr/lib/libcharset.1.dylib
-0x00000001a60f2000 /System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory
-0x00000001a60e2000 /System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory
-0x00000001ab89b000 /System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS
-0x00000001a97cc000 /System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation
-0x00000001ab91a000 /usr/lib/libutil.dylib
-0x00000002458f1000 /System/Library/PrivateFrameworks/InstalledContentLibrary.framework/Versions/A/InstalledContentLibrary
-0x00000001a0f1d000 /System/Library/PrivateFrameworks/CoreServicesStore.framework/Versions/A/CoreServicesStore
-0x000000023581f000 /System/Library/PrivateFrameworks/AppleMobileFileIntegrity.framework/Versions/A/AppleMobileFileIntegrity
-0x00000001c30b9000 /usr/lib/libmis.dylib
-0x00000001d3742000 /System/Library/PrivateFrameworks/MobileSystemServices.framework/Versions/A/MobileSystemServices
-0x00000001f11bb000 /System/Library/PrivateFrameworks/ConfigProfileHelper.framework/Versions/A/ConfigProfileHelper
-0x00000001aa576000 /System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce
-0x000000019f5c2000 /System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling
-0x00000001ab91e000 /usr/lib/libxslt.1.dylib
-0x00000001aa462000 /usr/lib/libcmph.dylib
-0x00000001a9567000 /System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji
-0x00000001a8b9c000 /System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData
-0x000000019e48b000 /System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon
-0x00000001a985a000 /System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement
-0x0000000262a48000 /usr/lib/libTLE.dylib
-0x00000001ac1e8000 /System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG
-0x00000001abcde000 /usr/lib/libexpat.1.dylib
-0x00000001ac810000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib
-0x00000001ac83b000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib
-0x00000001ac926000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib
-0x00000001ac22e000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib
-0x00000001ac8cb000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib
-0x00000001ac8c2000 /System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib
-0x00000001a7e8f000 /System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib
-0x00000001a4834000 /System/Library/PrivateFrameworks/RunningBoardServices.framework/Versions/A/RunningBoardServices
-0x00000001b839d000 /System/Library/PrivateFrameworks/IOSurfaceAccelerator.framework/Versions/A/IOSurfaceAccelerator
-0x00000001ac31e000 /System/Library/PrivateFrameworks/WatchdogClient.framework/Versions/A/WatchdogClient
-0x000000019f7a8000 /System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay
-0x00000001a7d47000 /System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia
-0x00000001a7ae7000 /System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator
-0x00000001a6285000 /System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo
-0x00000001aa5cb000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders
-0x00000001ac361000 /System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox
-0x00000001a6321000 /System/Library/PrivateFrameworks/UserManagement.framework/Versions/A/UserManagement
-0x00000001a475b000 /System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard
-0x00000001a8a71000 /System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary
-0x0000000235659000 /System/Library/PrivateFrameworks/AppleKeyStore.framework/Versions/A/AppleKeyStore
-0x00000001ac8bd000 /System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler
-0x00000001ac89d000 /System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment
-0x00000001ac8c5000 /System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay
-0x00000002419dd000 /System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/libllvm-flatbuffers.dylib
-0x00000001f3da0000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib
-0x000000023ebf9000 /System/Library/PrivateFrameworks/GPUCompiler.framework/Versions/32023/Libraries/libGPUCompilerUtils.dylib
-0x00000001ac92c000 /System/Library/PrivateFrameworks/CMCaptureCore.framework/Versions/A/CMCaptureCore
-0x00000001f8bed000 /System/Library/Frameworks/ExtensionFoundation.framework/Versions/A/ExtensionFoundation
-0x00000001b3961000 /System/Library/PrivateFrameworks/CoreTime.framework/Versions/A/CoreTime
-0x00000001abeb1000 /System/Library/PrivateFrameworks/AppServerSupport.framework/Versions/A/AppServerSupport
-0x00000001ae443000 /System/Library/PrivateFrameworks/perfdata.framework/Versions/A/perfdata
-0x000000019f8cc000 /System/Library/PrivateFrameworks/AudioToolboxCore.framework/Versions/A/AudioToolboxCore
-0x00000001a7d1d000 /System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk
-0x00000001adcb1000 /usr/lib/libAudioStatistics.dylib
-0x00000001c23f6000 /System/Library/PrivateFrameworks/SystemPolicy.framework/Versions/A/SystemPolicy
-0x00000001adf8a000 /usr/lib/libSMC.dylib
-0x00000001b794b000 /System/Library/Frameworks/CoreMIDI.framework/Versions/A/CoreMIDI
-0x00000001ac7d7000 /usr/lib/libAudioToolboxUtility.dylib
-0x00000001bd867000 /System/Library/PrivateFrameworks/OSAServicesClient.framework/Versions/A/OSAServicesClient
-0x00000001ae451000 /usr/lib/libperfcheck.dylib
-0x00000001b3419000 /System/Library/PrivateFrameworks/BoardServices.framework/Versions/A/BoardServices
-0x00000001abbc6000 /System/Library/PrivateFrameworks/PlugInKit.framework/Versions/A/PlugInKit
-0x00000001a97be000 /System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices
-0x00000001b6a65000 /System/Library/PrivateFrameworks/ASEProcessing.framework/Versions/A/ASEProcessing
-0x00000001df625000 /System/Library/PrivateFrameworks/Symbolication.framework/Versions/A/Symbolication
-0x000000024cee1000 /System/Library/PrivateFrameworks/PhotosensitivityProcessing.framework/Versions/A/PhotosensitivityProcessing
-0x00000001abe62000 /System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer
-0x00000001f3e02000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib
-0x00000001f3dc1000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib
-0x00000001f3f9a000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib
-0x00000001f3dca000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib
-0x00000001f3dbe000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib
-0x0000000262a00000 /usr/lib/libRosetta.dylib
-0x00000001f3da7000 /System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib
-0x000000023cf93000 /System/Library/PrivateFrameworks/FontServices.framework/Versions/A/FontServices
-0x00000001abe6e000 /System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG
-0x00000001a5e26000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib
-0x00000001abebc000 /System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib
-0x000000023cf94000 /System/Library/PrivateFrameworks/FontServices.framework/libXTFontStaticRegistryData.dylib
-0x00000001a89b8000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/MPSCore
-0x00000001a9edf000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/MPSImage
-0x00000001a9939000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork
-0x00000001a9d84000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix
-0x00000001a9b8f000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector
-0x00000001a9db6000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/MPSNDArray
-0x00000001fa432000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSFunctions.framework/Versions/A/MPSFunctions
-0x00000001fa417000 /System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSBenchmarkLoop.framework/Versions/A/MPSBenchmarkLoop
-0x000000019dfa3000 /System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools
-0x00000001c757b000 /System/Library/PrivateFrameworks/IOAccelMemoryInfo.framework/Versions/A/IOAccelMemoryInfo
-0x00000001d363c000 /System/Library/PrivateFrameworks/kperf.framework/Versions/A/kperf
-0x00000001c30de000 /System/Library/PrivateFrameworks/GPURawCounter.framework/Versions/A/GPURawCounter
-0x00000001b3833000 /System/Library/PrivateFrameworks/CoreSymbolication.framework/Versions/A/CoreSymbolication
-0x00000001c308a000 /System/Library/PrivateFrameworks/MallocStackLogging.framework/Versions/A/MallocStackLogging
-0x00000001aba68000 /System/Library/PrivateFrameworks/CrashReporterSupport.framework/Versions/A/CrashReporterSupport
-0x00000001b37ee000 /System/Library/PrivateFrameworks/DebugSymbols.framework/Versions/A/DebugSymbols
-0x00000001d1fac000 /System/Library/PrivateFrameworks/OSAnalytics.framework/Versions/A/OSAnalytics
-0x0000000259c57000 /System/Library/PrivateFrameworks/VideoToolboxParavirtualizationSupport.framework/Versions/A/VideoToolboxParavirtualizationSupport
-0x00000001abc92000 /System/Library/PrivateFrameworks/AppleVA.framework/Versions/A/AppleVA
-0x00000001adcf9000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS
-0x00000001a3c93000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices
-0x00000001ac93a000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore
-0x00000001ae0e3000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD
-0x00000001ae0d7000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy
-0x00000001adcc9000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis
-0x00000001ac8f6000 /System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATSUI.framework/Versions/A/ATSUI
-0x00000001ae06a000 /usr/lib/libcups.2.dylib
-0x00000001ae45f000 /System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos
-0x00000001ae470000 /System/Library/Frameworks/GSS.framework/Versions/A/GSS
-0x00000001add78000 /usr/lib/libresolv.9.dylib
-0x00000001abecd000 /System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal
-0x00000001b58d6000 /System/Library/Frameworks/Kerberos.framework/Versions/A/Libraries/libHeimdalProxy.dylib
-0x00000001ae4ca000 /System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth
-0x00000001f79da000 /System/Library/Frameworks/AVFAudio.framework/Versions/A/AVFAudio
-0x00000001bd8b6000 /System/Library/PrivateFrameworks/AXCoreUtilities.framework/Versions/A/AXCoreUtilities
-0x0000000246e64000 /System/Library/PrivateFrameworks/IsolatedCoreAudioClient.framework/Versions/A/IsolatedCoreAudioClient
-0x00000001adc35000 /System/Library/PrivateFrameworks/AudioSession.framework/Versions/A/AudioSession
-0x00000001af733000 /System/Library/Frameworks/IOBluetooth.framework/Versions/A/IOBluetooth
-0x00000001abd9d000 /System/Library/PrivateFrameworks/MediaExperience.framework/Versions/A/MediaExperience
-0x00000001ada74000 /System/Library/PrivateFrameworks/AudioSession.framework/libSessionUtility.dylib
-0x00000001ae0ef000 /System/Library/PrivateFrameworks/AudioResourceArbitration.framework/Versions/A/AudioResourceArbitration
-0x00000001b27a9000 /System/Library/PrivateFrameworks/PowerLog.framework/Versions/A/PowerLog
-0x00000001b26c8000 /System/Library/Frameworks/CoreBluetooth.framework/Versions/A/CoreBluetooth
-0x00000001b58d7000 /System/Library/Frameworks/AudioUnit.framework/Versions/A/AudioUnit
-0x00000001a9628000 /System/Library/PrivateFrameworks/CoreUtils.framework/Versions/A/CoreUtils
-0x000000023b2db000 /System/Library/PrivateFrameworks/CoreUtilsExtras.framework/Versions/A/CoreUtilsExtras
-0x000000024577f000 /System/Library/PrivateFrameworks/IO80211.framework/Versions/A/IO80211
-0x00000001b335d000 /System/Library/PrivateFrameworks/FrontBoardServices.framework/Versions/A/FrontBoardServices
-0x00000001b4ea1000 /System/Library/PrivateFrameworks/BackBoardServices.framework/Versions/A/BackBoardServices
-0x00000001abd04000 /System/Library/PrivateFrameworks/IconFoundation.framework/Versions/A/IconFoundation
-0x00000001b16ac000 /System/Library/PrivateFrameworks/SpeechRecognitionCore.framework/Versions/A/SpeechRecognitionCore
-0x00000001bd8d5000 /usr/lib/libAccessibility.dylib
-0x00000001b1d9f000 /System/Library/Frameworks/MediaAccessibility.framework/Versions/A/MediaAccessibility
-0x00000001e2cb6000 /System/Library/Frameworks/OSLog.framework/Versions/A/OSLog
-0x00000001c3018000 /System/Library/PrivateFrameworks/LoggingSupport.framework/Versions/A/LoggingSupport
-0x0000000103a34000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/server/libjvm.dylib
-0x0000000102528000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjimage.dylib
-0x0000000102558000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libinstrument.dylib
-0x00000001025a8000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libjava.dylib
-0x00000001026e4000 /private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/libasyncProfiler.so
-0x00000001026a4000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libzip.dylib
-0x000000010276c000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnio.dylib
-0x000000010278c000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libnet.dylib
-0x0000000102588000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libextnet.dylib
-0x00000001026cc000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement.dylib
-0x00000001027b0000 /Users/sungmin/Library/Java/JavaVirtualMachines/corretto-17.0.8.1-1/Contents/Home/lib/libmanagement_ext.dylib
-0x00000001ad409000 /usr/lib/libusrtcp.dylib
-0x00000001a29fb000 /usr/lib/libboringssl.dylib
-
-
-VM Arguments:
-jvm_args: -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dmanagement.endpoints.jmx.exposure.include=* -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57802:/Applications/IntelliJ IDEA.app/Contents/bin -agentpath:/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/libasyncProfiler.so=start,jfr,event=cpu,interval=10ms,jfrsync=profile,cstack=no,file=/Users/sungmin/IdeaSnapshots/ComNCheckApplication_2025_01_26_233554.jfr,log=/private/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/ComNCheckApplication_2025_01_26_233554.jfr.log.txt,logLevel=DEBUG -Dfile.encoding=UTF-8
-java_command: com.ComNCheck.ComNCheck.ComNCheckApplication
-java_class_path (initial): /Users/sungmin/Desktop/ComNCheck/Spring/ComNCheck-backend/build/classes/java/main:/Users/sungmin/Desktop/ComNCheck/Spring/ComNCheck-backend/build/resources/main:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.36/5a30490a6e14977d97d9c73c924c1f1b5311ea95/lombok-1.18.36.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-oauth2-client/3.4.1/9d39fbd91d9231bf0c9d3259e5152b9bda733f1a/spring-boot-starter-oauth2-client-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-security/3.4.1/6a82a9f484d265c73a203d551b614cd8bdde5825/spring-boot-starter-security-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-impl/0.12.3/e850d2b3f53bd82355cd9ee1c471054aa602b320/jjwt-impl-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-jackson/0.12.3/5e6d0e45441547d892d3273a4ce5dd042e91d162/jjwt-jackson-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.jsonwebtoken/jjwt-api/0.12.3/30b7de9176d17fa347eef14b85480825dab76b58/jjwt-api-0.12.3.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/io.github.cdimascio/java-dotenv/5.2.2/f77d54ff193ed4b07415ab8d7b3d0550716aa8c/java-dotenv-5.2.2.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-data-jpa/3.4.1/f06be4354c339f3f880a5c66a6913cd2366eb225/spring-boot-starter-data-jpa-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter-web/3.4.1/ff7227fc62338e0f6eba3f9f94c12eb952d4da95/spring-boot-starter-web-3.4.1.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springdoc/springdoc-openapi-starter-webmvc-ui/2.7.0/4426174e7fa7428a1c5f2edbd352c89e3e6b9794/springdoc-openapi-starter-webmvc-ui-2.7.0.jar:/Users/sungmin/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-starter/3.4.1/2c97b6fdc451ea69cd04dcfa
-Launcher Type: SUN_STANDARD
-
-[Global flags]
- intx CICompilerCount = 4 {product} {ergonomic}
- uint ConcGCThreads = 2 {product} {ergonomic}
- bool FlightRecorder = true {product} {management}
- uint G1ConcRefinementThreads = 8 {product} {ergonomic}
- size_t G1HeapRegionSize = 1048576 {product} {ergonomic}
- uintx GCDrainStackTargetSize = 64 {product} {ergonomic}
- size_t InitialHeapSize = 134217728 {product} {ergonomic}
- bool ManagementServer = true {product} {command line}
- size_t MarkStackSize = 4194304 {product} {ergonomic}
- size_t MaxHeapSize = 2147483648 {product} {ergonomic}
- size_t MaxNewSize = 1287651328 {product} {ergonomic}
- size_t MinHeapDeltaBytes = 1048576 {product} {ergonomic}
- size_t MinHeapSize = 8388608 {product} {ergonomic}
- uintx NonProfiledCodeHeapSize = 0 {pd product} {ergonomic}
- bool ProfileInterpreter = false {pd product} {command line}
- uintx ProfiledCodeHeapSize = 0 {pd product} {ergonomic}
- size_t SoftMaxHeapSize = 2147483648 {manageable} {ergonomic}
- intx TieredStopAtLevel = 1 {product} {command line}
- bool UseCompressedClassPointers = true {product lp64_product} {ergonomic}
- bool UseCompressedOops = true {product lp64_product} {ergonomic}
- bool UseG1GC = true {product} {ergonomic}
- bool UseNUMA = false {product} {ergonomic}
- bool UseNUMAInterleaving = false {product} {ergonomic}
-
-Logging:
-Log output configuration:
- #0: stdout all=warning,jni+resolve=error uptime,level,tags (reconfigured)
- #1: stderr all=off uptime,level,tags
-
-Environment Variables:
-PATH=/Users/sungmin/opt/anaconda3/bin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/Library/Frameworks/Python.framework/Versions/3.11/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
-SHELL=/bin/zsh
-LC_CTYPE=ko_KR.UTF-8
-TMPDIR=/var/folders/c3/rqkh7s3n2c1gdz85gpftmpjr0000gn/T/
-
-Active Locale:
-LC_ALL=C/ko_KR.UTF-8/C/C/C/C
-LC_COLLATE=C
-LC_CTYPE=ko_KR.UTF-8
-LC_MESSAGES=C
-LC_MONETARY=C
-LC_NUMERIC=C
-LC_TIME=C
-
-Signal Handlers:
- SIGSEGV: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked
- SIGBUS: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked
- SIGFPE: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked
- SIGPIPE: javaSignalHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGXFSZ: javaSignalHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGILL: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked
- SIGUSR2: SR_handler in libjvm.dylib, mask=00100000000000000000000000000000, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGHUP: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGINT: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGTERM: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGQUIT: UserHandler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, blocked
- SIGTRAP: crash_handler in libjvm.dylib, mask=11100110000111110111111111111111, flags=SA_RESTART|SA_SIGINFO, unblocked
-
-
---------------- S Y S T E M ---------------
-
-OS:
-uname: Darwin 23.4.0 Darwin Kernel Version 23.4.0: Fri Mar 15 00:12:41 PDT 2024; root:xnu-10063.101.17~1/RELEASE_ARM64_T8103 arm64
-OS uptime: 3 days 23:18 hours
-rlimit (soft/hard): STACK 8176k/65520k , CORE 0k/infinity , NPROC 1333/2000 , NOFILE 10240/infinity , AS infinity/infinity , CPU infinity/infinity , DATA infinity/infinity , FSIZE infinity/infinity , MEMLOCK infinity/infinity , RSS infinity/infinity
-load average: 4.29 3.02 3.73
-
-CPU: total 8 (initial active 8) 0x61:0x0:0x1b588bb3:0, fp, simd, crc, lse
-machdep.cpu.brand_string:Apple M1
-hw.cachelinesize:128
-hw.l1icachesize:131072
-hw.l1dcachesize:65536
-hw.l2cachesize:4194304
-
-Memory: 16k page, physical 8388608k(149104k free), swap 9437184k(1607680k free)
-
-vm_info: OpenJDK 64-Bit Server VM (17.0.8.1+8-LTS) for bsd-aarch64 JRE (17.0.8.1+8-LTS), built on Aug 18 2023 22:52:47 by "ec2user" with clang Apple LLVM 13.0.0 (clang-1300.0.29.30)
-
-END.
diff --git a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java
index 160ade7..f71d3c8 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/ComNCheckApplication.java
@@ -1,6 +1,5 @@
package com.ComNCheck.ComNCheck;
-import io.github.cdimascio.dotenv.Dotenv;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,16 +8,6 @@ public class ComNCheckApplication {
public static void main(String[] args) {
- //Load .env file
- Dotenv dotenv = Dotenv.load();
- System.setProperty("H2_DB_URL", dotenv.get("H2_DB_URL"));
- System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME"));
- System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD"));
- System.setProperty("JWT_SECRET", dotenv.get("JWT_SECRET"));
- System.setProperty("GOOGLE_CLIENT_ID", dotenv.get("GOOGLE_CLIENT_ID"));
- System.setProperty("GOOGLE_CLIENT_SECRET", dotenv.get("GOOGLE_CLIENT_SECRET"));
- System.setProperty("JWT_EXPIRATIONMS",dotenv.get("JWT_EXPIRATIONMS"));
- System.setProperty("GOOGLE_REDIRECT_URI",dotenv.get("GOOGLE_REDIRECT_URI"));
SpringApplication.run(ComNCheckApplication.class, args);
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store
new file mode 100644
index 0000000..3848306
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/controller/AnotherEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/controller/AnotherEventController.java
new file mode 100644
index 0000000..9ad8d03
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/controller/AnotherEventController.java
@@ -0,0 +1,90 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.controller;
+
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventCreateRequestDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventUpdateRequestDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventListResponseDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventResponseDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.service.AnotherEventService;
+import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+
+@RequestMapping("/api/v1/another-event")
+@RequiredArgsConstructor
+@RestController
+public class AnotherEventController {
+
+ private final AnotherEventService anotherEventService;
+
+ @Operation(
+ summary = "AnotherEvent 게시글 작성",
+ description = "AnotherEvent 게시글을 작성한다. 관리자, 과회장, 학생회만 가능하다."
+ )
+ @PostMapping
+ public ResponseEntity createAnotherEvent(
+ @ModelAttribute EventCreateRequestDTO requestDTO,
+ Authentication authentication
+ ) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ EventResponseDTO responseDTO = anotherEventService.createAnotherEvent(requestDTO, memberId);
+ return ResponseEntity.ok(responseDTO);
+ }
+
+ @Operation(
+ summary = "특정 AnotherEvent 게시글 조회",
+ description = "특정 AnotherEvent 게시글을 조회한다."
+ )
+ @GetMapping("/{anotherEventId}")
+ public ResponseEntity getAnotherEvent(
+ @PathVariable Long anotherEventId
+ ) {
+ EventResponseDTO responseDTO = anotherEventService.getAnotherEvent(anotherEventId);
+ return ResponseEntity.ok(responseDTO);
+ }
+
+ @Operation(
+ summary = "AnotherEvent 게시글 목록 조회",
+ description = "AnotherEvent 게시글 목록을 조회한다. 이미 지난 행사는 제외된다."
+ )
+ @GetMapping
+ public ResponseEntity> getAllAnotherEventsNotPassed() {
+ List list = anotherEventService.getAllAnotherEventsNotPassed();
+ return ResponseEntity.ok(list);
+ }
+
+ @Operation(
+ summary = "AnotherEvent 게시글 수정",
+ description = "작성된 AnotherEvent 게시글을 수정한다. 관리자, 과회장, 학생회만 가능하다."
+ )
+ @PutMapping("/{anotherEventId}")
+ public ResponseEntity updateAnotherEvent(
+ @PathVariable Long anotherEventId,
+ @ModelAttribute EventUpdateRequestDTO requestDTO,
+ Authentication authentication
+ ) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ EventResponseDTO updateDTO = anotherEventService.updateAnotherEvent(anotherEventId, requestDTO, memberId);
+ return ResponseEntity.ok(updateDTO);
+ }
+
+ @Operation(
+ summary = "AnotherEvent 게시글 삭제",
+ description = "작성된 AnotherEvent 게시글을 삭제한다. 관리자, 과회장, 학생회만 가능하다."
+ )
+ @DeleteMapping("/{anotherEventId}")
+ public ResponseEntity deleteAnotherEvent(
+ @PathVariable Long anotherEventId,
+ Authentication authentication
+ ) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ anotherEventService.deleteAnotherEvent(anotherEventId, memberId);
+ return ResponseEntity.noContent().build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java
new file mode 100644
index 0000000..0b45482
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventCreateRequestDTO.java
@@ -0,0 +1,31 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.web.multipart.MultipartFile;
+
+@Getter
+@Setter
+public class EventCreateRequestDTO {
+
+ private String eventName;
+ private String date;
+ private String time;
+ private String location;
+ private String notice;
+ private String googleFormLink;
+
+ private List cardNewsImages;
+
+ public LocalDate getParsedDate() {
+ return date != null ? LocalDate.parse(date) : null;
+ }
+
+ public LocalTime getParsedTime() {
+ return time != null ? LocalTime.parse(time) : null;
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java
new file mode 100644
index 0000000..c2e261c
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/request/EventUpdateRequestDTO.java
@@ -0,0 +1,33 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+
+@Getter
+@Setter
+public class EventUpdateRequestDTO {
+
+ private String eventName;
+ private String date;
+ private String time;
+ private String location;
+ private String notice;
+ private String googleFormLink;
+ private String firstImageUrl;
+
+ private List cardNewsImages;
+
+ public LocalDate getParsedDate() {
+ return date != null ? LocalDate.parse(date) : null;
+ }
+
+ public LocalTime getParsedTime() {
+ return time != null ? LocalTime.parse(time) : null;
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java
new file mode 100644
index 0000000..7b7d9a5
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventListResponseDTO.java
@@ -0,0 +1,29 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+
+@Getter
+@Builder
+public class EventListResponseDTO {
+
+ private Long id;
+ private String eventName;
+ private LocalDate date;
+ private LocalTime time;
+ private String location;
+
+ public static EventListResponseDTO of(AnotherEvent anotherEvent) {
+ return EventListResponseDTO.builder()
+ .id(anotherEvent.getAnotherEventId())
+ .eventName(anotherEvent.getEventName())
+ .date(anotherEvent.getDate())
+ .time(anotherEvent.getTime())
+ .location(anotherEvent.getLocation())
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java
new file mode 100644
index 0000000..7ae08f7
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/EventResponseDTO.java
@@ -0,0 +1,36 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.List;
+
+@Getter
+@Builder
+public class EventResponseDTO {
+
+ private Long id;
+ private String eventName;
+ private LocalDate date;
+ private LocalTime time;
+ private String location;
+ private String notice;
+ private String googleFormLink;
+ private List cardNewsImageUrls;
+
+ public static EventResponseDTO of(AnotherEvent anotherEvent) {
+ return EventResponseDTO.builder()
+ .id(anotherEvent.getAnotherEventId())
+ .eventName(anotherEvent.getEventName())
+ .date(anotherEvent.getDate())
+ .time(anotherEvent.getTime())
+ .location(anotherEvent.getLocation())
+ .notice(anotherEvent.getNotice())
+ .googleFormLink(anotherEvent.getGoogleFormLink())
+ .cardNewsImageUrls(anotherEvent.getCardNewsImageUrls())
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java
new file mode 100644
index 0000000..7b97da6
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/dto/response/PagedEventListResponseDTO.java
@@ -0,0 +1,25 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response;
+
+import java.util.List;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class PagedEventListResponseDTO {
+ private int currentPage;
+ private int totalPages;
+ private long totalElements;
+ private int size;
+ private List content;
+
+ public PagedEventListResponseDTO(int currentPage, int totalPages, long totalElements,
+ int size, List content)
+ {
+ this.currentPage = currentPage;
+ this.totalPages = totalPages;
+ this.totalElements = totalElements;
+ this.size = size;
+ this.content = content;
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java
new file mode 100644
index 0000000..a970c3b
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/model/entity/AnotherEvent.java
@@ -0,0 +1,90 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity;
+
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import jakarta.persistence.CollectionTable;
+import jakarta.persistence.Column;
+import jakarta.persistence.ElementCollection;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToOne;
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+public class AnotherEvent {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long anotherEventId;
+
+ @Column(name = "event_name", nullable = false)
+ private String eventName;
+
+ @Column(name = "date", nullable = false)
+ private LocalDate date;
+
+ @Column(name = "time", nullable = false)
+ private LocalTime time;
+
+ @Column(name = "location", nullable = false)
+ private String location;
+
+ @Column(name = "notice", nullable = false, columnDefinition = "TEXT")
+ private String notice;
+
+ @Column(name = "google_form_link")
+ private String googleFormLink;
+
+ @ElementCollection(fetch = FetchType.LAZY)
+ @CollectionTable(name = "another_event_card_news_images", joinColumns = @JoinColumn(name = "another_event_id"))
+ @Column(name = "image_url")
+ private List cardNewsImageUrls = new ArrayList<>();
+
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JoinColumn(name = "writer_id")
+ private Member writer;
+
+ @Builder
+ public AnotherEvent(Member writer, String eventName, LocalDate date, LocalTime time,
+ String location, String notice, String googleFormLink,
+ List cardNewsImageUrls) {
+ this.writer = writer;
+ this.eventName = eventName;
+ this.date = date;
+ this.time = time;
+ this.location = location;
+ this.notice = notice;
+ this.googleFormLink = googleFormLink;
+ if (cardNewsImageUrls != null) {
+ this.cardNewsImageUrls = cardNewsImageUrls;
+ }
+ }
+
+ public void updateEvent(String eventName, LocalDate date, LocalTime time,
+ String location, String notice, String googleFormLink) {
+ this.eventName = eventName;
+ this.date = date;
+ this.time = time;
+ this.location = location;
+ this.notice = notice;
+ this.googleFormLink = googleFormLink;
+ }
+
+ public void updateCardNewsImages(List newImageUrls) {
+ this.cardNewsImageUrls.clear();
+ this.cardNewsImageUrls.addAll(newImageUrls);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java
new file mode 100644
index 0000000..5dfe0b3
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/repository/AnotherEventRepository.java
@@ -0,0 +1,7 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.repository;
+
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface AnotherEventRepository extends JpaRepository {
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java
new file mode 100644
index 0000000..7b78413
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/anotherEvent/service/AnotherEventService.java
@@ -0,0 +1,178 @@
+package com.ComNCheck.ComNCheck.domain.anotherEvent.service;
+
+import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventCreateRequestDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.request.EventUpdateRequestDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventListResponseDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.dto.response.EventResponseDTO;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.model.entity.AnotherEvent;
+import com.ComNCheck.ComNCheck.domain.anotherEvent.repository.AnotherEventRepository;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
+import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import com.google.cloud.storage.BlobInfo;
+import com.google.cloud.storage.Storage;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+@Service
+public class AnotherEventService {
+
+ private final AnotherEventRepository anotherEventRepository;
+ private final MemberRepository memberRepository;
+ private final FcmService fcmService;
+
+ @Value("${spring.cloud.gcp.storage.bucket}")
+ private String bucketName;
+
+ private final Storage storage;
+
+ @Transactional
+ public EventResponseDTO createAnotherEvent(EventCreateRequestDTO requestDTO, Long writerId) {
+ Member writer = memberRepository.findByMemberId(writerId)
+ .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다."));
+
+ isCheckRole(writer);
+
+ List imageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages());
+
+ LocalDate eventDate = requestDTO.getParsedDate();
+ LocalTime eventTime = requestDTO.getParsedTime();
+ AnotherEvent anotherEvent = AnotherEvent.builder()
+ .writer(writer)
+ .eventName(requestDTO.getEventName())
+ .date(eventDate)
+ .time(eventTime)
+ .location(requestDTO.getLocation())
+ .notice(requestDTO.getNotice())
+ .googleFormLink(requestDTO.getGoogleFormLink())
+ .cardNewsImageUrls(imageUrls)
+ .build();
+ AnotherEvent savedAnotherEvent = anotherEventRepository.save(anotherEvent);
+
+ String title = "새로운 행사 등록";
+ String body = requestDTO.getEventName() + " 행사가 등록되었습니다.";
+ memberRepository.findAll().forEach(member -> {
+ member.getFcmTokens().forEach(fcmToken -> {
+ if (fcmToken.isValid() && fcmToken.getToken() != null && !fcmToken.getToken().isBlank()) {
+ try {
+ fcmService.sendMessageToToken(fcmToken.getToken(), title, body);
+ } catch (FirebaseMessagingException e) {
+ System.out.println("전송 실패");
+ }
+ }
+ });
+ });
+
+ return EventResponseDTO.of(savedAnotherEvent);
+ }
+
+ @Transactional
+ public void deleteAnotherEvent(Long anotherEventId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
+ AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId)
+ .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다."));
+ anotherEventRepository.delete(anotherEvent);
+ }
+
+ public EventResponseDTO getAnotherEvent(Long anotherEventId) {
+ AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId)
+ .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다."));
+ return EventResponseDTO.of(anotherEvent);
+ }
+
+ public List getAllAnotherEventsNotPassed() {
+ List all = anotherEventRepository.findAll();
+
+ LocalDate today = LocalDate.now();
+ LocalTime currentTime = LocalTime.now();
+
+ all.sort(
+ Comparator
+ .comparing(AnotherEvent::getDate, Comparator.reverseOrder())
+ .thenComparing(AnotherEvent::getTime, Comparator.reverseOrder())
+ );
+
+ return all.stream()
+ .map(EventListResponseDTO::of)
+ .collect(Collectors.toList());
+ }
+
+ @Transactional
+ public EventResponseDTO updateAnotherEvent(Long anotherEventId, EventUpdateRequestDTO requestDTO, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
+ AnotherEvent anotherEvent = anotherEventRepository.findById(anotherEventId)
+ .orElseThrow(() -> new PostNotFoundException("요청하신 행사가 없습니다."));
+
+ LocalDate eventDate = requestDTO.getParsedDate();
+ LocalTime eventTime = requestDTO.getParsedTime();
+
+ anotherEvent.updateEvent(
+ requestDTO.getEventName(),
+ eventDate,
+ eventTime,
+ requestDTO.getLocation(),
+ requestDTO.getNotice(),
+ requestDTO.getGoogleFormLink()
+ );
+ if (requestDTO.getCardNewsImages() != null && !requestDTO.getCardNewsImages().isEmpty()) {
+ List newImageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages());
+ anotherEvent.updateCardNewsImages(newImageUrls);
+ }
+
+ return EventResponseDTO.of(anotherEvent);
+ }
+
+ private List uploadImagesToGcs(List images) {
+ if (images == null || images.isEmpty()) {
+ return new ArrayList<>();
+ }
+ List uploadUrls = new ArrayList<>();
+ for (MultipartFile file : images) {
+ try {
+ String uuid = UUID.randomUUID().toString();
+ String contentType = file.getContentType() != null ? file.getContentType() : "application/octet-stream";
+ BlobInfo blobInfo = BlobInfo.newBuilder(bucketName, uuid)
+ .setContentType(contentType)
+ .build();
+ storage.create(blobInfo, file.getInputStream());
+ uploadUrls.add("https://storage.googleapis.com/" + bucketName + "/" + uuid);
+ } catch (IOException e) {
+ throw new RuntimeException("이미지 업로드 실패", e);
+ }
+ }
+ return uploadUrls;
+ }
+
+ public void isCheckRole(Member member) {
+ Role role = member.getRole();
+ if (role != Role.ROLE_ADMIN
+ && role != Role.ROLE_MAJOR_PRESIDENT
+ && role != Role.ROLE_STUDENT_COUNCIL) {
+ throw new ForbiddenException("접근 권한이 없습니다.");
+ }
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store
new file mode 100644
index 0000000..112e67d
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java
index ebbba67..ee354f6 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/controller/DeveloperQuestionController.java
@@ -5,6 +5,7 @@
import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO;
import com.ComNCheck.ComNCheck.domain.developerQuestion.service.DeveloperQuestionService;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
@@ -19,7 +20,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
-@RequestMapping("api/v1/developer/question")
+@RequestMapping("api/v1/developer/questions")
@RequiredArgsConstructor
@RestController
public class DeveloperQuestionController {
@@ -27,15 +28,21 @@ public class DeveloperQuestionController {
private final DeveloperQuestionService developerQuestionService;
@PostMapping
+ @Operation(summary = "개발자 질문 게시글 작성", description = "개발자에게 질문글을 작성할 수 있다.")
public ResponseEntity createDeveloperQuestion(
- @RequestBody DeveloperQuestionRequestDTO requestDTO
+ @RequestBody DeveloperQuestionRequestDTO requestDTO,
+ Authentication authentication
) {
- DeveloperQuestionResponseDTO createdDTO = developerQuestionService.createDeveloperQuestion(requestDTO);
- URI location = URI.create("api/v1/developer/question/" + createdDTO.getId());
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ DeveloperQuestionResponseDTO createdDTO = developerQuestionService
+ .createDeveloperQuestion(memberId, requestDTO);
+ URI location = URI.create("api/v1/developer/questions/" + createdDTO.getId());
return ResponseEntity.created(location).body(createdDTO);
}
@GetMapping("/{developerQuestionId}")
+ @Operation(summary = "특정 개발자 질문 게시글 조회", description = "특정 개발자 질문 게시글 조회한다.")
public ResponseEntity getDeveloperQuestion(
@PathVariable Long developerQuestionId
) {
@@ -44,12 +51,14 @@ public ResponseEntity getDeveloperQuestion(
}
@GetMapping
+ @Operation(summary = "개발자 질문 게시글 목록 조회", description = "개발자 질문 게시글 목록 조회한다.")
public ResponseEntity> getAllDeveloperQuestions() {
List questionList = developerQuestionService.getAllQuestion();
return ResponseEntity.ok(questionList);
}
@PutMapping("/{developerQuestionId}")
+ @Operation(summary = "개발자 질문 게시글 수정", description = "개발자 질문 게시글을 수정한다.")
public ResponseEntity updateDeveloperQuestion(
@PathVariable Long developerQuestionId,
@RequestBody DeveloperQuestionResponseDTO requestDTO,
@@ -64,6 +73,7 @@ public ResponseEntity updateDeveloperQuestion(
}
@DeleteMapping("/{developerQuestionId}")
+ @Operation(summary = "개발자 질문 게시글 삭제", description = "개발자 질문 게시글을 삭제한다.")
public ResponseEntity deleteDeveloperQuestion(
@PathVariable Long developerQuestionId,
Authentication authentication
@@ -73,4 +83,15 @@ public ResponseEntity deleteDeveloperQuestion(
developerQuestionService.deleteDeveloperQuestion(developerQuestionId, writerId);
return ResponseEntity.noContent().build();
}
+
+ @GetMapping("/my")
+ @Operation(summary = "내가 쓴 개발자 질문 게시글 보기", description = "내가 쓴 글만 조회한다.")
+ public ResponseEntity> getAllMyDeveloperQuestion(
+ Authentication authentication
+ ) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long writerId = principal.getMemberDTO().getMemberId();
+ List developerQuestions = developerQuestionService.getAllMyDeveloperQuestion(writerId);
+ return ResponseEntity.ok(developerQuestions);
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store
new file mode 100644
index 0000000..4d55781
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java
index 980b2f3..1aea267 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/dto/request/DeveloperQuestionRequestDTO.java
@@ -8,5 +8,4 @@
@Setter
public class DeveloperQuestionRequestDTO {
private String content;
- private Long writerId;
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java
index f6d19fa..5091989 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/model/entity/DeveloperQuestion.java
@@ -10,6 +10,8 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
+import jakarta.persistence.PrePersist;
+import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -32,9 +34,20 @@ public class DeveloperQuestion {
@JoinColumn(name = "writer_id")
private Member writer;
+ @Column
+ private LocalDateTime createdAt;
+ @Column
+ private LocalDateTime updatedAt;
+
public void updateDeveloperQuestion(String content) {
this.content = content;
}
+ @PrePersist
+ public void prePersist() {
+ this.createdAt = LocalDateTime.now();
+ this.updatedAt = LocalDateTime.now();
+ }
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java
index ca2ac92..cf2000a 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/repository/DeveloperQuestionRepository.java
@@ -1,6 +1,8 @@
package com.ComNCheck.ComNCheck.domain.developerQuestion.repository;
import com.ComNCheck.ComNCheck.domain.developerQuestion.model.entity.DeveloperQuestion;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -9,6 +11,6 @@
public interface DeveloperQuestionRepository extends JpaRepository {
//Optional findByDeveloperQuestionId(Long id);
-
+ List findAllByWriter(Member writer);
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java
index 81341d2..13b3ee4 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/developerQuestion/service/DeveloperQuestionService.java
@@ -1,14 +1,15 @@
package com.ComNCheck.ComNCheck.domain.developerQuestion.service;
-import com.ComNCheck.ComNCheck.domain.member.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.request.DeveloperQuestionRequestDTO;
import com.ComNCheck.ComNCheck.domain.developerQuestion.model.dto.response.DeveloperQuestionResponseDTO;
import com.ComNCheck.ComNCheck.domain.developerQuestion.model.entity.DeveloperQuestion;
import com.ComNCheck.ComNCheck.domain.developerQuestion.repository.DeveloperQuestionRepository;
-import com.ComNCheck.ComNCheck.domain.global.exception.UnauthorizedException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -23,8 +24,8 @@ public class DeveloperQuestionService {
private final DeveloperQuestionRepository developerQuestionRepository;
@Transactional
- public DeveloperQuestionResponseDTO createDeveloperQuestion(DeveloperQuestionRequestDTO requestDTO) {
- Member writer = memberRepository.findById(requestDTO.getWriterId())
+ public DeveloperQuestionResponseDTO createDeveloperQuestion(Long memberId, DeveloperQuestionRequestDTO requestDTO) {
+ Member writer = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다."));
DeveloperQuestion developerQuestion = DeveloperQuestion.builder()
@@ -38,7 +39,7 @@ public DeveloperQuestionResponseDTO createDeveloperQuestion(DeveloperQuestionReq
public DeveloperQuestionResponseDTO getDeveloperQuestion(Long developerQuestionId) {
DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId)
- .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다."));
return DeveloperQuestionResponseDTO.of(developerQuestion);
}
public List getAllQuestion() {
@@ -53,10 +54,10 @@ public DeveloperQuestionResponseDTO updateDeveloperQuestion(Long developerQuesti
DeveloperQuestionResponseDTO requestDTO,
Long writerId) {
DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId)
- .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다."));
if(!developerQuestion.getWriter().getMemberId().equals(writerId))
- throw new UnauthorizedException("게시글 작성자가 아닙니다.");
+ throw new ForbiddenException("게시글 작성자가 아닙니다.");
developerQuestion.updateDeveloperQuestion(requestDTO.getContent());
return DeveloperQuestionResponseDTO.of(developerQuestion);
@@ -65,14 +66,24 @@ public DeveloperQuestionResponseDTO updateDeveloperQuestion(Long developerQuesti
@Transactional
public void deleteDeveloperQuestion(Long developerQuestionId, Long writerId) {
DeveloperQuestion developerQuestion = developerQuestionRepository.findById(developerQuestionId)
- .orElseThrow(() -> new IllegalArgumentException("질문글을 찾을 수 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("질문글을 찾을 수 없습니다."));
if(!developerQuestion.getWriter().getMemberId().equals(writerId))
- throw new UnauthorizedException("게시글 작성자가 아닙니다.");
+ throw new ForbiddenException("게시글 작성자가 아닙니다.");
developerQuestionRepository.delete(developerQuestion);
}
+ public List getAllMyDeveloperQuestion(Long writerId) {
+ Member writer = memberRepository.findById(writerId)
+ .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다."));
+
+ return developerQuestionRepository.findAllByWriter(writer)
+ .stream()
+ .map(DeveloperQuestionResponseDTO::of)
+ .toList();
+ }
+
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store
new file mode 100644
index 0000000..7c31c49
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java
new file mode 100644
index 0000000..afd7b41
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/config/scheduler/EmploymentNoticeScheduler.java
@@ -0,0 +1,27 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.config.scheduler;
+
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.service.EmploymentNoticeService;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+@EnableScheduling
+@RequiredArgsConstructor
+public class EmploymentNoticeScheduler {
+
+ private final EmploymentNoticeService employmentNoticeService;
+
+ @Scheduled(cron = "0 0 * * * *")
+ public void syncEmploymentNoticePeriodically() {
+ employmentNoticeService.syncEmploymentNotices();
+ }
+
+ @PostConstruct
+ public void initLoad() {
+ employmentNoticeService.syncEmploymentNotices();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java
new file mode 100644
index 0000000..50b0417
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/controller/EmploymentController.java
@@ -0,0 +1,40 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.controller;
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.service.EmploymentNoticeService;
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.xml.bind.annotation.XmlType.DEFAULT;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+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;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/v1/employment/notices")
+@RestController
+public class EmploymentController {
+
+ private final EmploymentNoticeService employmentNoticeService;
+
+ @GetMapping
+ @Operation(summary = "취업정보 게시판 목록 조회", description = "취업정보 게시판 목록을 조회한다.")
+ public ResponseEntity> getAllEmploymentNotice() {
+ List lists = employmentNoticeService.getAllEmploymentNotices();
+ return ResponseEntity.ok(lists);
+ }
+
+ @GetMapping("/pages")
+ @Operation(summary = "취업정보 게시판 목록 조회(페이지네이션)", description = "페이지네이션으로 취업정보 게시판 목록을 조회한다.")
+ public ResponseEntity getEmploymentNoticePage(
+ @RequestParam(defaultValue = "1") int page,
+ @RequestParam(defaultValue = "10") int size
+ ) {
+ PageEmploymentNoticeResponseDTO pageResponse = employmentNoticeService.getEmploymentNoticesPage(page, size);
+ return ResponseEntity.ok(pageResponse);
+
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store
new file mode 100644
index 0000000..3f0a476
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java
new file mode 100644
index 0000000..60d6da8
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/EmploymentNoticeResponseDTO.java
@@ -0,0 +1,29 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonFormat.Shape;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.LocalDate;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class EmploymentNoticeResponseDTO {
+ @JsonProperty("notice_id")
+ private int employmentNoticeId;
+ private String title;
+ @JsonFormat(shape = Shape.STRING, pattern = "yyyy.MM.dd")
+ private LocalDate date;
+ private String link;
+
+ public static EmploymentNoticeResponseDTO of(EmploymentNotice employmentNotice) {
+ return EmploymentNoticeResponseDTO.builder()
+ .employmentNoticeId(employmentNotice.getEmploymentNoticeId())
+ .title(employmentNotice.getTitle())
+ .date(employmentNotice.getDate())
+ .link(employmentNotice.getLink())
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java
new file mode 100644
index 0000000..ed475f9
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/FastAPIEmploymentNoticeResponseListDTO.java
@@ -0,0 +1,12 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class FastAPIEmploymentNoticeResponseListDTO {
+ private List notices;
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java
new file mode 100644
index 0000000..ba94486
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/dto/response/PageEmploymentNoticeResponseDTO.java
@@ -0,0 +1,16 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import java.util.List;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class PageEmploymentNoticeResponseDTO {
+ private int currentPage;
+ private int totalPages;
+ private long totalElements;
+ private int size;
+ private List content;
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java
new file mode 100644
index 0000000..6a71558
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/model/entity/EmploymentNotice.java
@@ -0,0 +1,57 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity;
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import java.time.LocalDate;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+
+@Getter
+@Table(name = "employment_notices")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+public class EmploymentNotice {
+ @Id
+ @Column(name = "employment_notice_id")
+ private int employmentNoticeId;
+
+ @Column
+ private String title;
+
+ @Column
+ private LocalDate date;
+
+ @Column
+ private String link;
+
+ public EmploymentNotice(EmploymentNoticeResponseDTO dto) {
+ this.employmentNoticeId = dto.getEmploymentNoticeId();
+ this.title = dto.getTitle();
+ this.date = dto.getDate();
+ this.link = dto.getLink();
+ }
+
+ public boolean updateFromDto(EmploymentNoticeResponseDTO dto) {
+ boolean changed = false;
+
+ if (!this.title.equals(dto.getTitle())) {
+ this.title = dto.getTitle();
+ changed = true;
+ }
+ if (!this.date.isEqual(dto.getDate())) {
+ this.date = dto.getDate();
+ changed = true;
+ }
+ if (!this.link.equals(dto.getLink())) {
+ this.link = dto.getLink();
+ changed = true;
+ }
+ return changed;
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java
new file mode 100644
index 0000000..1db1641
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/repository/EmploymentNoticeRepository.java
@@ -0,0 +1,14 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.repository;
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice;
+import java.util.List;
+import java.util.Optional;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+public interface EmploymentNoticeRepository extends JpaRepository {
+ Optional findByEmploymentNoticeId(int employmentNoticeId);
+
+ @Query("SELECT e FROM EmploymentNotice e ORDER BY e.employmentNoticeId DESC")
+ List findAllOrderedById();
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java
new file mode 100644
index 0000000..436ef44
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/employmentNotice/service/EmploymentNoticeService.java
@@ -0,0 +1,122 @@
+package com.ComNCheck.ComNCheck.domain.employmentNotice.service;
+
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.EmploymentNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.FastAPIEmploymentNoticeResponseListDTO;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.PageEmploymentNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.entity.EmploymentNotice;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.repository.EmploymentNoticeRepository;
+import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService;
+import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+@Service
+public class EmploymentNoticeService {
+
+ private final EmploymentNoticeRepository employmentNoticeRepository;
+ private final FastApiClient fastApiClient;
+ private final MemberRepository memberRepository;
+ private final FcmService fcmService;
+
+ @Transactional
+ public void syncEmploymentNotices() {
+ FastAPIEmploymentNoticeResponseListDTO response = fastApiClient.fetchEmploymentNotices();
+
+ List changeEmploymentNotices = new ArrayList<>();
+
+ if(response != null && response.getNotices() != null) {
+ for(EmploymentNoticeResponseDTO dto : response.getNotices()) {
+ Optional findEmployment = employmentNoticeRepository
+ .findByEmploymentNoticeId(dto.getEmploymentNoticeId());
+ if(findEmployment.isEmpty()) {
+ EmploymentNotice newEmploymentNotice = new EmploymentNotice(dto);
+ employmentNoticeRepository.save(newEmploymentNotice);
+ changeEmploymentNotices.add(newEmploymentNotice);
+ } else {
+ EmploymentNotice existEmploymentNotice = findEmployment.get();
+ if (existEmploymentNotice.updateFromDto(dto)) {
+ employmentNoticeRepository.save(existEmploymentNotice);
+ changeEmploymentNotices.add(existEmploymentNotice);
+ }
+ }
+ }
+ }
+ if (!changeEmploymentNotices.isEmpty()) {
+ // fcm 기능 구현
+ System.out.println("알림 전송");
+ List members = memberRepository.findByAlarmEmploymentNoticeTrue();
+
+ if(!members.isEmpty()) {
+ String title = "취업 공지사항";
+ String body = "새로운 컴퓨터공학부 취업 글이 등록되었습니다.";
+
+ for(Member member : members) {
+ if(!member.getFcmTokens().isEmpty()) {
+ member.getFcmTokens().forEach(fcmToken -> {
+ if(fcmToken.isValid() && fcmToken.getToken() != null
+ && !fcmToken.getToken().isBlank()) {
+ try {
+ fcmService.sendMessageToToken(fcmToken.getToken(), title,body);
+ } catch(FirebaseMessagingException e) { // 예외처리 이후 확인
+ System.out.println("전송 실패");
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ public List getAllEmploymentNotices() {
+ return employmentNoticeRepository.findAll()
+ .stream()
+ .map(EmploymentNoticeResponseDTO::of)
+ .toList();
+ }
+
+ public PageEmploymentNoticeResponseDTO getEmploymentNoticesPage(int page, int size) {
+ List allEmploymentNotices = employmentNoticeRepository.findAllOrderedById();
+
+
+ long totalElements = allEmploymentNotices.size();
+ int totalPages = (int) Math.ceil((double) totalElements / size);
+
+ if (page < 1) {
+ page = 1;
+ } else if (page > totalPages && totalPages > 0) {
+ page = totalPages;
+ }
+
+ int zeroBasedPage = page - 1;
+ int startIndex = zeroBasedPage * size;
+ int endIndex = Math.min(startIndex + size, (int) totalElements);
+
+ List pageList = (startIndex < endIndex)
+ ? allEmploymentNotices.subList(startIndex, endIndex)
+ : Collections.emptyList();
+
+ List content = pageList.stream()
+ .map(EmploymentNoticeResponseDTO::of)
+ .collect(Collectors.toList());
+
+ return PageEmploymentNoticeResponseDTO.builder()
+ .currentPage(page)
+ .totalPages(totalPages)
+ .totalElements(totalElements)
+ .size(size)
+ .content(content)
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/.DS_Store
new file mode 100644
index 0000000..3a07632
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java
new file mode 100644
index 0000000..0759894
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/config/FCMConfig.java
@@ -0,0 +1,40 @@
+package com.ComNCheck.ComNCheck.domain.fcm.config;
+
+import com.google.auth.oauth2.GoogleCredentials;
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.FirebaseOptions;
+import com.google.firebase.messaging.FirebaseMessaging;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+@Configuration
+public class FCMConfig {
+ @Bean
+ FirebaseMessaging firebaseMessaging() throws IOException {
+ ClassPathResource resource = new ClassPathResource("firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json");
+
+ InputStream refreshToken = resource.getInputStream();
+
+ FirebaseApp firebaseApp = null;
+ List firebaseAppList = FirebaseApp.getApps();
+
+ if(firebaseAppList != null && !firebaseAppList.isEmpty()) {
+ for(FirebaseApp app : firebaseAppList) {
+ if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) {
+ firebaseApp = app;
+ }
+ }
+ }
+ else {
+ FirebaseOptions options = FirebaseOptions.builder()
+ .setCredentials(GoogleCredentials.fromStream(refreshToken))
+ .build();
+ firebaseApp = FirebaseApp.initializeApp(options);
+ }
+ return FirebaseMessaging.getInstance(firebaseApp);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java
new file mode 100644
index 0000000..eba7348
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/controller/FcmController.java
@@ -0,0 +1,31 @@
+package com.ComNCheck.ComNCheck.domain.fcm.controller;
+
+import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService;
+import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/v1/fcm")
+public class FcmController {
+
+ private final FcmService fcmTokenService;
+
+ @PostMapping
+ public ResponseEntity registerToken(@RequestParam String token,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ fcmTokenService.registerFcmToken(memberId, token);
+ return ResponseEntity.ok("토큰 등록 완료");
+ }
+
+
+
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store
new file mode 100644
index 0000000..db040e5
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java
new file mode 100644
index 0000000..e702fa6
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/model/entity/FcmToken.java
@@ -0,0 +1,42 @@
+package com.ComNCheck.ComNCheck.domain.fcm.model.entity;
+
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.FetchType;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.ManyToOne;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+public class FcmToken {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "fcm_token")
+ private String token;
+
+ @Column(name = "fcm_valid")
+ private boolean valid = true;
+
+ @Setter
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name ="member_id")
+ private Member member;
+
+ public FcmToken(String token) {
+ this.token = token;
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java
new file mode 100644
index 0000000..fa5e7f8
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/repository/FcmRepository.java
@@ -0,0 +1,9 @@
+package com.ComNCheck.ComNCheck.domain.fcm.repository;
+
+import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken;
+import java.util.Optional;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface FcmRepository extends JpaRepository {
+ Optional findByToken(String token);
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java
new file mode 100644
index 0000000..fa59763
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/fcm/service/FcmService.java
@@ -0,0 +1,49 @@
+package com.ComNCheck.ComNCheck.domain.fcm.service;
+
+import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken;
+import com.ComNCheck.ComNCheck.domain.fcm.repository.FcmRepository;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import com.google.firebase.messaging.FirebaseMessaging;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import com.google.firebase.messaging.Message;
+import com.google.firebase.messaging.Notification;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+@Service
+public class FcmService {
+
+ private final MemberRepository memberRepository;
+ private final FcmRepository fcmRepository;
+
+ public void sendMessageToToken(String token, String title, String body) throws FirebaseMessagingException {
+ Message message = Message.builder()
+ .setToken(token)
+ .setNotification(
+ Notification.builder()
+ .setTitle(title)
+ .setBody(body)
+ .build()
+ )
+ .build();
+ String response = FirebaseMessaging.getInstance().send(message);
+ }
+ @Transactional
+ public void registerFcmToken(Long memberId, String token) {
+ Member member = memberRepository.findById(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다."));
+
+ FcmToken existing = fcmRepository.findByToken(token).orElse(null);
+ if(existing != null) return; // 학습 후 추가 기능 구현해야함
+
+ FcmToken newFcmToken = new FcmToken(token);
+ member.addFcmToken(newFcmToken);
+
+ memberRepository.save(member);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store
new file mode 100644
index 0000000..f5daaeb
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/global/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java
new file mode 100644
index 0000000..b9b52ef
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/MethodSecurityConfig.java
@@ -0,0 +1,10 @@
+package com.ComNCheck.ComNCheck.domain.global.config;
+
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+
+@Configuration
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class MethodSecurityConfig {
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java
new file mode 100644
index 0000000..e732a29
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/RoleHierarchyConfig.java
@@ -0,0 +1,25 @@
+package com.ComNCheck.ComNCheck.domain.global.config;
+
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
+import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
+
+@Configuration
+public class RoleHierarchyConfig {
+
+
+ @Bean
+ public RoleHierarchy roleHierarchy() {
+ RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
+ String hierarchy = "ROLE_ADMIN > ROLE_MAJOR_PRESIDENT \n" +
+ "ROLE_MAJOR_PRESIDENT > ROLE_STUDENT_COUNCIL \n" +
+ "ROLE_STUDENT_COUNCIL > ROLE_STUDENT \n" +
+ "ROLE_STUDENT > ROLE_GRADUATE_STUDENT";
+ roleHierarchy.setHierarchy(hierarchy);
+ return roleHierarchy;
+ }
+
+
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java
index ccd7de2..dac2fdf 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/config/SwaggerConfig.java
@@ -3,15 +3,24 @@
import io.swagger.v3.oas.models.Components;
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.security.SecurityScheme;
+import io.swagger.v3.oas.models.security.SecurityScheme.In;
+import io.swagger.v3.oas.models.security.SecurityScheme.Type;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
+ SecurityScheme securityScheme = new SecurityScheme()
+ .type(Type.APIKEY)
+ .in(In.COOKIE).name("AccessToken");
+ SecurityRequirement securityRequirement = new SecurityRequirement().addList("cookieAuth");
@Bean
public OpenAPI openAPI() {
return new OpenAPI()
- .components(new Components())
+ .components(new Components().addSecuritySchemes("cookieAuth", securityScheme))
+ .addSecurityItem(securityRequirement)
.info(apiInfo());
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java
new file mode 100644
index 0000000..8075724
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/AnswerNotFoundException.java
@@ -0,0 +1,7 @@
+package com.ComNCheck.ComNCheck.domain.global.exception;
+
+public class AnswerNotFoundException extends RuntimeException{
+ public AnswerNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java
new file mode 100644
index 0000000..06cf02a
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ApplyNotFoundException.java
@@ -0,0 +1,7 @@
+package com.ComNCheck.ComNCheck.domain.global.exception;
+
+public class ApplyNotFoundException extends RuntimeException{
+ public ApplyNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java
deleted file mode 100644
index f195630..0000000
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/BadRequestException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.ComNCheck.ComNCheck.domain.global.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-@ResponseStatus(HttpStatus.BAD_REQUEST)
-public class BadRequestException extends RuntimeException {
- public BadRequestException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java
new file mode 100644
index 0000000..38f1729
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ForbiddenException.java
@@ -0,0 +1,7 @@
+package com.ComNCheck.ComNCheck.domain.global.exception;
+
+public class ForbiddenException extends RuntimeException {
+ public ForbiddenException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java
index d1a57ce..169744a 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/GlobalExceptionHandler.java
@@ -1,7 +1,5 @@
package com.ComNCheck.ComNCheck.domain.global.exception;
-import com.ComNCheck.ComNCheck.domain.member.exception.MemberNotFoundException;
-import com.ComNCheck.ComNCheck.domain.member.exception.ValidationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -15,6 +13,21 @@ public ResponseEntity handleMemberNotFound(MemberNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
+ @ExceptionHandler(PostNotFoundException.class)
+ public ResponseEntity handlePostNotFound(PostNotFoundException ex) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
+ }
+
+ @ExceptionHandler(ForbiddenException.class)
+ public ResponseEntity handleForbiddenException(ForbiddenException ex) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ex.getMessage());
+ }
+
+ @ExceptionHandler(AnswerNotFoundException.class)
+ public ResponseEntity handleAnswerNotFoundException(AnswerNotFoundException ex) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
+ }
+
@ExceptionHandler(FastApiException.class)
public ResponseEntity handleFastApiException(FastApiException ex) {
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(ex.getMessage());
@@ -25,9 +38,9 @@ public ResponseEntity handleValidationException(ValidationException ex)
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
}
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleGeneralException(Exception ex) {
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 내부 오류가 발생했습니다.");
+ @ExceptionHandler(ApplyNotFoundException.class)
+ public ResponseEntity handleApplyNotFoundException(ApplyNotFoundException ex) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
@ExceptionHandler(ResourceNotFoundException.class)
@@ -37,12 +50,6 @@ public ResponseEntity handleResourceNotFound(ResourceNotFoundExce
}
- @ExceptionHandler(BadRequestException.class)
- public ResponseEntity handleBadRequest(BadRequestException ex) {
- ErrorResponse error = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
- return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
- }
-
public static class ErrorResponse {
private int status;
private String message;
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java
similarity index 72%
rename from src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java
rename to src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java
index a20acba..cfb3e75 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/MemberNotFoundException.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/MemberNotFoundException.java
@@ -1,4 +1,4 @@
-package com.ComNCheck.ComNCheck.domain.member.exception;
+package com.ComNCheck.ComNCheck.domain.global.exception;
public class MemberNotFoundException extends RuntimeException {
public MemberNotFoundException(String message) {
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java
new file mode 100644
index 0000000..7ed2d41
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/PostNotFoundException.java
@@ -0,0 +1,7 @@
+package com.ComNCheck.ComNCheck.domain.global.exception;
+
+public class PostNotFoundException extends RuntimeException{
+ public PostNotFoundException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java
deleted file mode 100644
index c15755a..0000000
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/UnauthorizedException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.ComNCheck.ComNCheck.domain.global.exception;
-
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.ResponseStatus;
-
-
-@ResponseStatus(HttpStatus.FORBIDDEN)
-public class UnauthorizedException extends RuntimeException {
- public UnauthorizedException(String message) {
- super(message);
- }
-}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java
similarity index 71%
rename from src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java
rename to src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java
index f742872..d92df8a 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/exception/ValidationException.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/exception/ValidationException.java
@@ -1,4 +1,4 @@
-package com.ComNCheck.ComNCheck.domain.member.exception;
+package com.ComNCheck.ComNCheck.domain.global.exception;
public class ValidationException extends RuntimeException {
public ValidationException(String message) {
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java
index cf3d163..d49333d 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/global/infrastructure/FastApiClient.java
@@ -1,11 +1,16 @@
package com.ComNCheck.ComNCheck.domain.global.infrastructure;
+import com.ComNCheck.ComNCheck.domain.employmentNotice.model.dto.response.FastAPIEmploymentNoticeResponseListDTO;
import com.ComNCheck.ComNCheck.domain.global.exception.FastApiException;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO;
+import jakarta.annotation.PostConstruct;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -15,12 +20,29 @@
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.http.HttpHeaders;
+
@Component
@RequiredArgsConstructor
public class FastApiClient {
private final RestTemplate restTemplate;
- private static final String FAST_API_URL_OCR= "http://localhost:8000/api/vi/compare-and-ocr";
+ private static final String LOCAL = "http://localhost:8000";
+ private static final String TEST_DISTRIBUTION = "http://comncheck.iptime.org:8000";
+ @Value("${target.server.ip}")
+ private String PROD_FASTAPI_IP;
+
+ private String PROD_FASTAPI;
+ private String FAST_API_URL_OCR;
+ private String FAST_API_URL_SCRAPE_NOTICE;
+ private String Fast_API_URL_EMPLOYMENT;
+
+ @PostConstruct
+ public void init() {
+ PROD_FASTAPI = "http://" + PROD_FASTAPI_IP;
+ FAST_API_URL_OCR= PROD_FASTAPI + "/api/v1/compare-and-ocr";
+ FAST_API_URL_SCRAPE_NOTICE = PROD_FASTAPI + "/api/v1/scrape/notice";
+ Fast_API_URL_EMPLOYMENT = PROD_FASTAPI + "/api/v1/scrape/employment";
+ }
public FastApiStudentCardDTO sendImage(MultipartFile imageFile) {
MultiValueMap body = new LinkedMultiValueMap<>();
@@ -54,4 +76,54 @@ public String getFilename() {
throw new FastApiException("이미지 처리 중 오류 발생: " + e.getMessage(), e);
}
}
+
+ public FastAPIMajorNoticesResponseListDTO fetchMajorNotices() {
+ try {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+
+ HttpEntity requestEntity = new HttpEntity<>(headers);
+
+ ResponseEntity response = restTemplate.exchange(
+ FAST_API_URL_SCRAPE_NOTICE,
+ HttpMethod.GET,
+ requestEntity,
+ FastAPIMajorNoticesResponseListDTO.class
+ );
+
+ if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
+ throw new FastApiException("FastAPI 호출 실패: " + response.getStatusCode());
+ }
+
+ return response.getBody();
+
+ } catch (Exception e) {
+ throw new FastApiException("공지사항 가져오기 중 오류 발생: " + e.getMessage(), e);
+ }
+ }
+
+ public FastAPIEmploymentNoticeResponseListDTO fetchEmploymentNotices() {
+ try {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+
+ HttpEntity requestEntity = new HttpEntity<>(headers);
+
+ ResponseEntity response = restTemplate.exchange(
+ Fast_API_URL_EMPLOYMENT,
+ HttpMethod.GET,
+ requestEntity,
+ FastAPIEmploymentNoticeResponseListDTO.class
+ );
+
+ if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
+ throw new FastApiException("FastAPI 호출 실패: " + response.getStatusCode());
+ }
+
+ return response.getBody();
+
+ } catch (Exception e) {
+ throw new FastApiException("공지사항 가져오기 중 오류 발생: " + e.getMessage(), e);
+ }
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store
new file mode 100644
index 0000000..f531e70
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java
index f1cecca..406dda8 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/controller/MajorEventController.java
@@ -7,9 +7,13 @@
import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.PagedEventListResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorEvent.service.MajorEventService;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
+import java.time.LocalDate;
+import java.time.LocalTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -18,7 +22,6 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/v1/major-event")
@@ -29,47 +32,54 @@ public class MajorEventController {
private final MajorEventService majorEventService;
@PostMapping
+ @Operation(summary = "과행사 게시글 작성", description = "과행사 게시글을 작성한다. 학생회, 과회장만 가능하다.")
public ResponseEntity createMajorEvent(@ModelAttribute EventCreateRequestDTO requestDTO,
Authentication authentication) {
+ // 문제 발생시 쌍따음표 일수도 있음
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long memberId = principal.getMemberDTO().getMemberId();
EventResponseDTO responseDTO = majorEventService.createMajorEvent(requestDTO, memberId);
return ResponseEntity.ok(responseDTO);
}
+
@GetMapping("/{majorEventId}")
+ @Operation(summary = "특정 과행사 게시글 조회", description = "특정 과행사 게시글을 조회한다.")
public ResponseEntity getMajorEvent(@PathVariable Long majorEventId) {
EventResponseDTO responseDTO = majorEventService.getMajorEvent(majorEventId);
return ResponseEntity.ok(responseDTO);
}
+
@GetMapping
+ @Operation(summary = "과행사 게시글 목록 조회", description = "과행사 게시글 목록을 조회한다. 이미 지난 행사는 보여주지 않는다.")
public ResponseEntity> getAllMajorEventsNotPassed() {
List allMajorEventsNotPassed = majorEventService.getAllMajorEventsNotPassed();
return ResponseEntity.ok(allMajorEventsNotPassed);
}
- @GetMapping("/pages")
- public ResponseEntity getAllMajorEventPage(
- @RequestParam(defaultValue = "1") int page,
- @RequestParam(defaultValue = "10") int size
- ) {
- PagedEventListResponseDTO responseDTO = majorEventService.getAllMajorEventPage(page, size);
- return ResponseEntity.ok(responseDTO);
- }
@PutMapping("/{majorEventId}")
+ @Operation(summary = "과행사 게시글 수정", description = "작성된 과행사 게시글을 수정한다. 작성자가 누구든 과회장과, 학생회는 수정할 수 있다.")
public ResponseEntity updateMajorEvent(
@PathVariable Long majorEventId,
- @ModelAttribute EventUpdateRequestDTO requestDTO
+ @ModelAttribute EventUpdateRequestDTO requestDTO,
+ Authentication authentication
) {
- EventResponseDTO updateDTO = majorEventService.updateMajorEvent(majorEventId, requestDTO);
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ EventResponseDTO updateDTO = majorEventService.updateMajorEvent(majorEventId, requestDTO, memberId);
return ResponseEntity.ok(updateDTO);
}
+
@DeleteMapping("/{majorEventId}")
- public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId) {
- majorEventService.deleteMajorEvent(majorEventId);
+ @Operation(summary = "과행사 게시글 삭제 ", description = "작성된 과행사 게시글을 삭제한다. 작성자가 누구든 과회장과, 학생회는 삭제할 수 있다.")
+ public ResponseEntity deleteMajorEvent(@PathVariable Long majorEventId,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ majorEventService.deleteMajorEvent(majorEventId, memberId);
return ResponseEntity.noContent().build();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store
new file mode 100644
index 0000000..20a2c97
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java
index 816074a..06e5d4c 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventCreateRequestDTO.java
@@ -14,14 +14,20 @@
public class EventCreateRequestDTO {
private String eventName;
- @DateTimeFormat(pattern = "yyyy-MM-dd")
- private LocalDate date;
- @DateTimeFormat(pattern = "HH:mm")
- private LocalTime time;
+ private String date;
+ private String time;
private String location;
private String notice;
private String googleFormLink;
private List cardNewsImages;
+ public LocalDate getParsedDate() {
+ return date != null ? LocalDate.parse(date) : null;
+ }
+
+ public LocalTime getParsedTime() {
+ return time != null ? LocalTime.parse(time) : null;
+ }
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java
index c61d41a..796c7aa 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/request/EventUpdateRequestDTO.java
@@ -14,13 +14,20 @@
public class EventUpdateRequestDTO {
private String eventName;
- @DateTimeFormat(pattern = "yyyy-MM-dd")
- private LocalDate date;
- @DateTimeFormat(pattern = "HH:mm")
- private LocalTime time;
+ private String date;
+ private String time;
private String location;
private String notice;
private String googleFormLink;
+ private String firstImageUrl;
private List cardNewsImages;
+
+ public LocalDate getParsedDate() {
+ return date != null ? LocalDate.parse(date) : null;
+ }
+
+ public LocalTime getParsedTime() {
+ return time != null ? LocalTime.parse(time) : null;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java
index 56aa2bd..b32745a 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/dto/response/EventListResponseDTO.java
@@ -10,15 +10,26 @@
@Getter
@Builder
public class EventListResponseDTO {
+ private Long id;
private String eventName;
private LocalDate date;
private LocalTime time;
+ private String googleFormLink;
+ private String firstImageUrl;
+
public static EventListResponseDTO of(MajorEvent majorEvent) {
+ String firstImage = null;
+ if (majorEvent.getCardNewsImageUrls() != null && !majorEvent.getCardNewsImageUrls().isEmpty()) {
+ firstImage = majorEvent.getCardNewsImageUrls().get(0);
+ }
return EventListResponseDTO.builder()
+ .id(majorEvent.getMajorEventId())
.eventName(majorEvent.getEventName())
.date(majorEvent.getDate())
.time(majorEvent.getTime())
+ .googleFormLink(majorEvent.getGoogleFormLink())
+ .firstImageUrl(firstImage)
.build();
}
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java
index 9876800..1b1300e 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/model/entity/MajorEvent.java
@@ -39,10 +39,10 @@ public class MajorEvent {
@Column(name = "time", nullable = false)
private LocalTime time;
- @Column(name = "localtion", nullable = false)
+ @Column(name = "location", nullable = false)
private String location;
- @Column(name = "notice", nullable = false)
+ @Column(name = "notice", nullable = false, columnDefinition = "TEXT")
private String notice;
@Column(name = "google_form_link")
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java
index fa7abd0..ee14a28 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/repository/MajorEventRepository.java
@@ -9,15 +9,15 @@
import org.springframework.data.repository.query.Param;
public interface MajorEventRepository extends JpaRepository {
- @Query("""
- SELECT e
- FROM MajorEvent e
- WHERE (e.date > :today)
- OR (e.date = :today AND e.time >= :currentTime)
- ORDER BY e.date ASC, e.time ASC
- """)
- List findUpcomingEvents(
- @Param("today") LocalDate today,
- @Param("currentTime") LocalTime currentTime
- );
+// @Query("""
+// SELECT e
+// FROM MajorEvent e
+// WHERE (e.date > :today)
+// OR (e.date = :today AND e.time >= :currentTime)
+// ORDER BY e.date ASC, e.time ASC
+// """)
+// List findUpcomingEvents(
+// @Param("today") LocalDate today,
+// @Param("currentTime") LocalTime currentTime
+// );
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java
index 3e9b6f4..7458cab 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorEvent/service/MajorEventService.java
@@ -1,22 +1,31 @@
package com.ComNCheck.ComNCheck.domain.majorEvent.service;
+import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException;
import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventCreateRequestDTO;
import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.request.EventUpdateRequestDTO;
import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventListResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.EventResponseDTO;
-import com.ComNCheck.ComNCheck.domain.majorEvent.model.dto.response.PagedEventListResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorEvent.model.entity.MajorEvent;
import com.ComNCheck.ComNCheck.domain.majorEvent.repository.MajorEventRepository;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.BlobInfo;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@@ -28,19 +37,27 @@ public class MajorEventService {
private final MajorEventRepository majorEventRepository;
private final MemberRepository memberRepository;
+ private final FcmService fcmService;
+ @Value("${spring.cloud.gcp.storage.bucket}")
+ private String bucketName;
+ private final Storage storage;
@Transactional
public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long writerId) {
Member writer = memberRepository.findByMemberId(writerId)
- .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 회원입니다."));
+ .orElseThrow(() -> new MemberNotFoundException("존재하지 않는 회원입니다."));
+
+ isCheckRole(writer);
List imageUrls = uploadImagesToGcs(requestDTO.getCardNewsImages());
+ LocalDate eventDate = requestDTO.getParsedDate();
+ LocalTime eventTime = requestDTO.getParsedTime();
MajorEvent majorEvent = MajorEvent.builder()
.writer(writer)
.eventName(requestDTO.getEventName())
- .date(requestDTO.getDate())
- .time(requestDTO.getTime())
+ .date(eventDate)
+ .time(eventTime)
.location(requestDTO.getLocation())
.notice(requestDTO.getNotice())
.googleFormLink(requestDTO.getGoogleFormLink())
@@ -48,85 +65,74 @@ public EventResponseDTO createMajorEvent(EventCreateRequestDTO requestDTO, Long
.build();
MajorEvent savedMajorEvent = majorEventRepository.save(majorEvent);
+
+ List members = memberRepository.findByAlarmMajorEventTrue();
+
+ if(!members.isEmpty()) {
+ String title = "공지사항";
+ String body = "새로운 과행사 글이 등록되었습니다.";
+
+ for(Member member : members) {
+ if(!member.getFcmTokens().isEmpty()) {
+ member.getFcmTokens().forEach(fcmToken -> {
+ if(fcmToken.isValid() && fcmToken.getToken() != null
+ && !fcmToken.getToken().isBlank()) {
+ try {
+ fcmService.sendMessageToToken(fcmToken.getToken(), title,body);
+ } catch(FirebaseMessagingException e) {
+ System.out.println("전송 실패");
+ }
+ }
+ });
+ }
+ }
+ }
return EventResponseDTO.of(savedMajorEvent);
}
public EventResponseDTO getMajorEvent(Long majorEventId) {
MajorEvent majorEvent = majorEventRepository.findById(majorEventId)
- .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다."));
return EventResponseDTO.of(majorEvent);
}
public List getAllMajorEventsNotPassed() {
+ // 코드 상에서 정렬 보다는 디비에서 정렬하고 보내는 것이 더 효율적일꺼같음 추후 리펙토링 필요
List all = majorEventRepository.findAll();
LocalDate today = LocalDate.now();
LocalTime currentTime = LocalTime.now();
- List filtered = all.stream()
- .filter(e -> isNotPassed(e, today, currentTime))
- .collect(Collectors.toList());
-
- filtered.sort(Comparator.comparing(MajorEvent::getDate)
- .thenComparing(MajorEvent::getTime));
+// List filtered = all.stream() // 기간 지난 행사 제외
+// .filter(e -> isNotPassed(e, today, currentTime))
+// .collect(Collectors.toList());
+ all.sort(
+ Comparator
+ .comparing(MajorEvent::getDate, Comparator.reverseOrder()) // 날짜 내림차순
+ .thenComparing(MajorEvent::getTime, Comparator.reverseOrder()) // 시간 내림차순
+ );
- return filtered.stream()
+ return all.stream()
.map(EventListResponseDTO::of)
.collect(Collectors.toList());
}
- public PagedEventListResponseDTO getAllMajorEventPage(int page, int size) {
- List all = majorEventRepository.findAll();
-
- LocalDate today = LocalDate.now();
- LocalTime currentTime = LocalTime.now();
-
- List filtered = all.stream()
- .filter(e -> isNotPassed(e, today, currentTime))
- .collect(Collectors.toList());
-
- filtered.sort(Comparator.comparing(MajorEvent::getDate)
- .thenComparing(MajorEvent::getTime));
-
- long totalElements = filtered.size();
- int totalPages = (int) Math.ceil((double) totalElements / size);
-
- if (page < 1) {
- page = 1;
- } else if (page >= totalPages && totalPages > 0) {
- page = totalPages -1;
- }
- int zeroBasedPage = page - 1;
- int startIndex = zeroBasedPage * size;
- int endIndex = Math.min(startIndex + size, (int) totalElements);
-
- List pageList = (startIndex < endIndex)
- ? filtered.subList(startIndex, endIndex)
- : Collections.emptyList();
-
- List content = pageList.stream()
- .map(EventListResponseDTO::of)
- .toList();
-
- return PagedEventListResponseDTO.builder()
- .currentPage(page)
- .totalPages(totalPages)
- .totalElements(totalElements)
- .size(size)
- .content(content)
- .build();
-
- }
-
@Transactional
- public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO) {
+ public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDTO requestDTO, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
MajorEvent majorEvent = majorEventRepository.findById(majorEventId)
- .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다."));
+
+ LocalDate eventDate = requestDTO.getParsedDate();
+ LocalTime eventTime = requestDTO.getParsedTime();
majorEvent.updateEvent(
requestDTO.getEventName(),
- requestDTO.getDate(),
- requestDTO.getTime(),
+ eventDate,
+ eventTime,
requestDTO.getLocation(),
requestDTO.getNotice(),
requestDTO.getGoogleFormLink()
@@ -140,9 +146,13 @@ public EventResponseDTO updateMajorEvent(Long majorEventId, EventUpdateRequestDT
}
@Transactional
- public void deleteMajorEvent(Long majorEventId) {
+ public void deleteMajorEvent(Long majorEventId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
MajorEvent majorEvent = majorEventRepository.findById(majorEventId)
- .orElseThrow(() -> new IllegalArgumentException("해당 학부 행사 정보가 없습니다."));
+ .orElseThrow(() -> new PostNotFoundException("요청하신 학부 행사가 없습니다."));
majorEventRepository.delete(majorEvent);
}
@@ -151,11 +161,27 @@ private List uploadImagesToGcs(List images) {
if (images == null || images.isEmpty()) {
return new ArrayList<>();
}
+
List uploadUrls = new ArrayList<>();
- for(MultipartFile file : images) {
- // gcs 업로드 호출
- String url = "https://gcs.com" + file.getOriginalFilename();
- uploadUrls.add(url);
+ for (MultipartFile file : images) {
+ try {
+ String uuid = UUID.randomUUID().toString();
+ String contentType = file.getContentType();
+ if (contentType == null) {
+ contentType = "application/octet-stream";
+ }
+ BlobInfo blobInfo = storage.create(
+ BlobInfo.newBuilder(bucketName, uuid)
+ .setContentType(contentType)
+ .build(),
+ file.getInputStream()
+ );
+ String url = "https://storage.googleapis.com/" + bucketName + "/" + uuid;
+ uploadUrls.add(url);
+
+ } catch (IOException e) {
+ throw new RuntimeException("이미지 업로드 실패", e);
+ }
}
return uploadUrls;
}
@@ -164,4 +190,11 @@ private boolean isNotPassed(MajorEvent majorEvent, LocalDate today, LocalTime cu
return majorEvent.getDate().isAfter(today)
|| (majorEvent.getDate().isEqual(today) && majorEvent.getTime().isBefore(currentTime));
}
+
+ public void isCheckRole(Member member) {
+ Role checkRole = member.getRole();
+ if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) {
+ throw new ForbiddenException("접근 권한이 없습니다.");
+ }
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store
new file mode 100644
index 0000000..29bbb6e
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java
new file mode 100644
index 0000000..fd28d87
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/config/scheduler/MajorScheduler.java
@@ -0,0 +1,25 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.config.scheduler;
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.service.MajorNoticeService;
+import jakarta.annotation.PostConstruct;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+@Configuration
+@EnableScheduling
+@RequiredArgsConstructor
+public class MajorScheduler {
+ private final MajorNoticeService majorNoticeService;
+
+ @Scheduled(cron = "0 0 * * * *")
+ public void syncNoticesPeriodically() {
+ majorNoticeService.syncMajorNotices();
+ }
+
+ @PostConstruct
+ public void initLoad() {
+ majorNoticeService.syncMajorNotices();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java
new file mode 100644
index 0000000..4a258ca
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/controller/MajorNoticeController.java
@@ -0,0 +1,38 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.controller;
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.service.MajorNoticeService;
+import io.swagger.v3.oas.annotations.Operation;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+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;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/v1/major/notices")
+@RestController
+public class MajorNoticeController {
+
+ private final MajorNoticeService majorNoticeService;
+
+ @GetMapping
+ @Operation(summary = "학부 공지사항 목록 조회", description = "학부 공지사항 목록을 조회한다.")
+ public ResponseEntity> getAllMajorNotices() {
+ List lists = majorNoticeService.getAllMajorNotices();
+ return ResponseEntity.ok(lists);
+ }
+
+ @GetMapping("/pages")
+ @Operation(summary = "학부 공지사항 목록 조회(페이지네이션)", description = "페이지네이션으로 학부 공지사항 목록을 조회한다.")
+ public ResponseEntity getMajorNoticesPage(
+ @RequestParam(defaultValue = "1") int page,
+ @RequestParam(defaultValue = "10") int size
+ ) {
+ PageMajorNoticeResponseDTO pageResponse = majorNoticeService.getMajorNoticesPage(page, size);
+ return ResponseEntity.ok(pageResponse);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store
new file mode 100644
index 0000000..a2f8e3e
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java
new file mode 100644
index 0000000..6440c46
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/FastAPIMajorNoticesResponseListDTO.java
@@ -0,0 +1,11 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response;
+
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class FastAPIMajorNoticesResponseListDTO {
+ private List notices;
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java
new file mode 100644
index 0000000..deecca7
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/MajorNoticeResponseDTO.java
@@ -0,0 +1,29 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response;
+
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.LocalDate;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class MajorNoticeResponseDTO {
+ @JsonProperty("notice_id")
+ private int noticeId;
+ private String title;
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd")
+ private LocalDate date;
+ private String link;
+
+ public static MajorNoticeResponseDTO of(MajorNotice majorNotice) {
+ return MajorNoticeResponseDTO.builder()
+ .noticeId(majorNotice.getNoticeId())
+ .title(majorNotice.getTitle())
+ .date(majorNotice.getDate())
+ .link(majorNotice.getLink())
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java
new file mode 100644
index 0000000..0635760
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/dto/response/PageMajorNoticeResponseDTO.java
@@ -0,0 +1,16 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response;
+
+
+import java.util.List;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class PageMajorNoticeResponseDTO {
+ private int currentPage;
+ private int totalPages;
+ private long totalElements;
+ private int size;
+ private List content;
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java
new file mode 100644
index 0000000..30959ed
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/model/entity/MajorNotice.java
@@ -0,0 +1,64 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.model.entity;
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import java.time.LocalDate;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+
+@Getter
+@Table(name = "major_notices")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+public class MajorNotice {
+
+ @Id
+ @Column(name = "major_notice_id")
+ private int noticeId;
+
+ @Column
+ private String title;
+
+ @Column
+ private LocalDate date;
+
+ @Column
+ private String link;
+
+ public MajorNotice(MajorNoticeResponseDTO dto) {
+ this.noticeId = dto.getNoticeId();
+ this.title = dto.getTitle();
+ this.date = dto.getDate();
+ this.link = dto.getLink();
+ }
+
+ public boolean equalsDTO(MajorNoticeResponseDTO dto) {
+ return this.noticeId== dto.getNoticeId() &&
+ this.title.equals(dto.getTitle()) &&
+ this.date.isEqual(dto.getDate()) &&
+ this.link.equals(dto.getLink());
+ }
+ public boolean updateFromDto(MajorNoticeResponseDTO dto) {
+ boolean changed = false;
+
+ if (!this.title.equals(dto.getTitle())) {
+ this.title = dto.getTitle();
+ changed = true;
+ }
+ if (!this.date.isEqual(dto.getDate())) {
+ this.date = dto.getDate();
+ changed = true;
+ }
+ if (!this.link.equals(dto.getLink())) {
+ this.link = dto.getLink();
+ changed = true;
+ }
+ return changed;
+ }
+
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java
new file mode 100644
index 0000000..f602f06
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/repository/MajorNoticeRepository.java
@@ -0,0 +1,16 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.repository;
+
+
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice;
+import java.util.List;
+import java.util.Optional;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+public interface MajorNoticeRepository extends JpaRepository {
+ Optional findByNoticeId(int noticeId);
+ @Query("SELECT e FROM MajorNotice e ORDER BY e.noticeId DESC")
+ List findAllOrderedById();
+
+
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java
new file mode 100644
index 0000000..41d28ab
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorNotice/service/MajorNoticeService.java
@@ -0,0 +1,122 @@
+package com.ComNCheck.ComNCheck.domain.majorNotice.service;
+
+import com.ComNCheck.ComNCheck.domain.fcm.service.FcmService;
+import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.FastAPIMajorNoticesResponseListDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.MajorNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.dto.response.PageMajorNoticeResponseDTO;
+import com.ComNCheck.ComNCheck.domain.majorNotice.model.entity.MajorNotice;
+import com.ComNCheck.ComNCheck.domain.majorNotice.repository.MajorNoticeRepository;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import com.google.firebase.messaging.FirebaseMessagingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+@Service
+public class MajorNoticeService {
+
+ private final FastApiClient fastApiClient;
+ private final MajorNoticeRepository majorNoticeRepository;
+ private final MemberRepository memberRepository;
+ private final FcmService fcmService;
+
+ @Transactional
+ public void syncMajorNotices() {
+ FastAPIMajorNoticesResponseListDTO response = fastApiClient.fetchMajorNotices();
+
+ List changeMajorNotices = new ArrayList<>();
+
+ if(response != null && response.getNotices() != null) {
+ for(MajorNoticeResponseDTO dto : response.getNotices()) {
+ Optional findNotice = majorNoticeRepository.findByNoticeId(dto.getNoticeId());
+ if(findNotice.isEmpty()) {
+ MajorNotice newMajorNotice = new MajorNotice(dto);
+ majorNoticeRepository.save(newMajorNotice);
+ changeMajorNotices.add(newMajorNotice);
+ } else {
+ MajorNotice existingMajorNotice = findNotice.get();
+ if (existingMajorNotice.updateFromDto(dto)) {
+ majorNoticeRepository.save(existingMajorNotice);
+ changeMajorNotices.add(existingMajorNotice);
+ }
+ }
+ }
+ }
+ if(!changeMajorNotices.isEmpty()) {
+ // fcm 기능 구현
+ System.out.println("알림 전송");
+ List members = memberRepository.findByAlarmMajorNoticeTrue();
+
+ if(!members.isEmpty()) {
+ String title = "전공 공지사항";
+ String body = "새로운 컴퓨터공학부 공지사항 글이 등록되었습니다.";
+
+ for(Member member : members) {
+ if(!member.getFcmTokens().isEmpty()) {
+ member.getFcmTokens().forEach(fcmToken -> {
+ if(fcmToken.isValid() && fcmToken.getToken() != null
+ && !fcmToken.getToken().isBlank()) {
+ try {
+ fcmService.sendMessageToToken(fcmToken.getToken(), title,body);
+ } catch(FirebaseMessagingException e) { // 예외처리 이후 확인
+ System.out.println("전송 실패");
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ public List getAllMajorNotices() {
+ return majorNoticeRepository.findAll()
+ .stream()
+ .map(MajorNoticeResponseDTO::of)
+ .toList();
+ }
+
+ public PageMajorNoticeResponseDTO getMajorNoticesPage(int page, int size) {
+ List allNotices = majorNoticeRepository.findAllOrderedById();
+
+
+ long totalElements = allNotices.size();
+ int totalPages = (int) Math.ceil((double) totalElements / size);
+
+ if (page < 1) {
+ page = 1;
+ } else if (page > totalPages && totalPages > 0) {
+ page = totalPages;
+ }
+
+ int zeroBasedPage = page - 1;
+ int startIndex = zeroBasedPage * size;
+ int endIndex = Math.min(startIndex + size, (int) totalElements);
+
+ List pageList = (startIndex < endIndex)
+ ? allNotices.subList(startIndex, endIndex)
+ : Collections.emptyList();
+
+ List content = pageList.stream()
+ .map(MajorNoticeResponseDTO::of)
+ .collect(Collectors.toList());
+
+ return PageMajorNoticeResponseDTO.builder()
+ .currentPage(page)
+ .totalPages(totalPages)
+ .totalElements(totalElements)
+ .size(size)
+ .content(content)
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store
new file mode 100644
index 0000000..6af873e
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java
index 3314515..3abff5b 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/AnswerController.java
@@ -1,11 +1,14 @@
package com.ComNCheck.ComNCheck.domain.majorQuestion.controller;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerRequestDTO;
+import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerUpdateRequestDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.AnswerResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.service.AnswerService;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
@@ -16,33 +19,40 @@ public class AnswerController {
private final AnswerService answerService;
@PostMapping
+ @Operation(summary = "FAQ 댓글 작성", description = "학생회권한만 댓글을 달 수 있다.")
public ResponseEntity createOrUpdateAnswer(
@RequestBody AnswerRequestDTO requestDTO,
Authentication authentication
) {
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long writerId = principal.getMemberDTO().getMemberId();
- requestDTO.setWriterId(writerId);
- AnswerResponseDTO responseDTO = answerService.createOrUpdateAnswer(requestDTO);
+ AnswerResponseDTO responseDTO = answerService.createOrUpdateAnswer(requestDTO, writerId);
return ResponseEntity.ok(responseDTO);
}
+
@PutMapping("/{answerId}")
+ @Operation(summary = "FAQ 댓글 수정", description = "학생회권한만 댓글 작성자의 관계없이 댓글 수정이 가능하다.")
public ResponseEntity updateAnswer(
@PathVariable Long answerId,
- @RequestBody String content,
+ @RequestBody AnswerUpdateRequestDTO answerUpdateRequestDTO,
Authentication authentication
) {
- AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, content);
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long writerId = principal.getMemberDTO().getMemberId();
+ AnswerResponseDTO responseDTO = answerService.updateAnswer(answerId, answerUpdateRequestDTO.getContent(), writerId);
return ResponseEntity.ok(responseDTO);
}
@DeleteMapping("/{answerId}")
+ @Operation(summary = "FAQ 댓글 삭제", description = "학생회권한만 작성자의 관계없이 댓글 삭제가 가능하다")
public ResponseEntity deleteAnswer(
@PathVariable Long answerId,
Authentication authentication
) {
- answerService.deleteAnswer(answerId);
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long writerId = principal.getMemberDTO().getMemberId();
+ answerService.deleteAnswer(answerId, writerId);
return ResponseEntity.noContent().build();
}
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java
index 3d7c761..7fea237 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/controller/QuestionController.java
@@ -4,9 +4,9 @@
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.QuestionResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.service.QuestionService;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
import java.net.URI;
import java.util.List;
-import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
@@ -27,30 +27,51 @@ public class QuestionController {
private final QuestionService questionService;
+
@PostMapping
- public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO) {
- QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO);
+ @Operation(summary = "FAQ 게시글 작성", description = "학생회에게 질문글을 작성할 수 있다.")
+ public ResponseEntity createQuestion(@RequestBody QuestionRequestDTO requestDTO,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ QuestionResponseDTO responseDTO = questionService.createQuestion(requestDTO, memberId);
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
- .path("/{id}")
- .buildAndExpand(responseDTO.getId())
+ .path("/{majorQuestionId}")
+ .buildAndExpand(responseDTO.getMajorQuestionId())
.toUri();
+
return ResponseEntity.created(location).body(responseDTO);
}
- @GetMapping("/{id}")
- public ResponseEntity getQuestion(@PathVariable Long id) {
- QuestionResponseDTO responseDTO = questionService.getQuestion(id);
+ @GetMapping("/all")
+ @Operation(summary = "FAQ 모든 게시글 - 학생회만 열람 가능", description = "댓글 작성 여부, 공개 여부오 상관없는 모든 질문들")
+ public ResponseEntity> getAllQuestion(
+ Authentication authentication
+ ) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ List questions = questionService.getAllQuestion(memberId);
+ return ResponseEntity.ok(questions);
+ }
+
+ @GetMapping("/{majorQuestionId}")
+ @Operation(summary = "FAQ 특정 게시글 조회", description = "FAQ의 특정 게시글을 클릭했을 때 자세히 볼 수 있다")
+ public ResponseEntity getQuestion(@PathVariable Long majorQuestionId) {
+ QuestionResponseDTO responseDTO = questionService.getQuestion(majorQuestionId);
return ResponseEntity.ok(responseDTO);
}
@GetMapping
- public ResponseEntity> getAllQuestion() {
- List questions = questionService.getAllQuestions();
+ @Operation(summary = "FAQ의 답변이 달린 게시글 목록 조회 공유가 true 인 경우만"
+ , description = "댓글이 달린 모든 게시글 목록을 조회한다.")
+ public ResponseEntity> getAnsweredAllQuestions() {
+ List questions = questionService.getQuestionsWithAnswer();
return ResponseEntity.ok(questions);
}
@GetMapping("/my")
+ @Operation(summary = "내가 작성한 FAQ 게시글 목록 조회", description = "내가 작성한 FAQ 게시글 목록을 조회한다")
public ResponseEntity> getMyQuestions(Authentication authentication) {
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long writerId = principal.getMemberDTO().getMemberId();
@@ -58,23 +79,34 @@ public ResponseEntity> getMyQuestions(Authentication a
return ResponseEntity.ok(myQuestions);
}
- @PutMapping("/{id}")
- public ResponseEntity updateQuestion(@PathVariable Long id,
+ @PutMapping("/{majorQuestionId}")
+ @Operation(summary = "FAQ 게시글 수정", description = "FAQ 게시글을 수정한다. 단, 본인이 작성한 게시글만 가능")
+ public ResponseEntity updateQuestion(@PathVariable Long majorQuestionId,
@RequestBody QuestionRequestDTO requestDTO,
Authentication authentication) {
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long memberId = principal.getMemberDTO().getMemberId();
- QuestionResponseDTO updateDTO = questionService.updateQuestion(id, requestDTO, memberId);
+ QuestionResponseDTO updateDTO = questionService.updateQuestion(majorQuestionId, requestDTO, memberId);
return ResponseEntity.ok(updateDTO);
}
- @DeleteMapping
- public ResponseEntity deleteQuestion(@PathVariable Long id, Authentication authentication) {
+ @DeleteMapping("/{majorQuestionId}")
+ @Operation(summary = "FAQ 게시글 삭제 ", description = "FAQ 게시글을 삭제한다. 단, 본인이 작성한 게시글만 가능")
+ public ResponseEntity deleteQuestion(@PathVariable Long majorQuestionId, Authentication authentication) {
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long memberId = principal.getMemberDTO().getMemberId();
- questionService.deleteQuestion(id, memberId);
+ questionService.deleteQuestion(majorQuestionId, memberId);
return ResponseEntity.noContent().build();
}
+ @GetMapping("/all/unanswerd")
+ @Operation(summary = "FAQ 답변이 달리지 않는 게시글 목록 조회", description = "답변을 아직 하지 않느니 게시글 목록을 조회한다.")
+ public ResponseEntity> getUnansweredAllQuestions(Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ List questions = questionService.getUnanswerdAllQuestion(memberId);
+ return ResponseEntity.ok(questions);
+
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store
new file mode 100644
index 0000000..2417f74
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java
index 2fb621b..df0d454 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerRequestDTO.java
@@ -7,7 +7,6 @@
@Setter
public class AnswerRequestDTO {
private String content;
- private Long questionId;
- private Long writerId;
+ private Long majorQuestionId;
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java
new file mode 100644
index 0000000..e22a5d8
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/AnswerUpdateRequestDTO.java
@@ -0,0 +1,11 @@
+package com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request;
+
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AnswerUpdateRequestDTO {
+ private String content;
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java
index ae1d984..b5a79e7 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/request/QuestionRequestDTO.java
@@ -8,6 +8,5 @@
public class QuestionRequestDTO {
private String title;
private String content;
- private Long writerId;
-
+ private boolean shared;
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java
index 264643f..a115830 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/AnswerResponseDTO.java
@@ -8,18 +8,18 @@
@Getter
@Builder
public class AnswerResponseDTO {
- private Long id;
+ private Long answerId;
private String content;
- private Long questionId;
+ private Long majorQuestionId;
private Long writerId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
public static AnswerResponseDTO of(Answer answer) {
return AnswerResponseDTO.builder()
- .id(answer.getId())
+ .answerId(answer.getId())
.content(answer.getContent())
- .questionId(answer.getQuestion().getId())
+ .majorQuestionId(answer.getQuestion().getId())
.writerId(answer.getWriter().getMemberId())
.createdAt(answer.getCreatedAt())
.updatedAt(answer.getUpdatedAt())
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java
index 89b7b60..024218b 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/dto/response/QuestionResponseDTO.java
@@ -8,19 +8,21 @@
@Getter
@Builder
public class QuestionResponseDTO {
- private Long id;
+ private Long majorQuestionId;
private String title;
private String content;
//private Long writerId;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private AnswerResponseDTO answer;
+ private boolean shared;
public static QuestionResponseDTO of(Question question) {
return QuestionResponseDTO.builder()
- .id(question.getId())
+ .majorQuestionId(question.getId())
.title(question.getTitle())
.content(question.getContent())
+ .shared(question.isShared())
//.writerId(question.getWriter().getId())
.createdAt(question.getCreatedAt())
.updatedAt(question.getUpdatedAt())
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java
index 483b49f..6dcd737 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/model/entity/Question.java
@@ -1,6 +1,7 @@
package com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity;
+import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.QuestionRequestDTO;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
@@ -37,27 +38,33 @@ public class Question {
@Column(nullable = false)
private String content;
+ @Column(nullable = false)
+ private boolean shared;
+
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "writer_id")
private Member writer;
@OneToOne(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
private Answer answer;
+ @Column
private LocalDateTime createdAt;
+ @Column
private LocalDateTime updatedAt;
-
/*
연관관계 편의 메서드
*/
+
public void setAnswer(Answer answer) {
this.answer = answer;
answer.setQuestion(this);
}
- public void updateQuestion(String title, String contest) {
- this.title = title;
- this.content = content;
+ public void updateQuestion(QuestionRequestDTO dto) {
+ this.title = dto.getTitle();
+ this.content = dto.getContent();
+ this.shared = dto.isShared();
this.updatedAt = LocalDateTime.now();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java
index c4d83c6..0fc301e 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/repository/QuestionRepository.java
@@ -2,8 +2,18 @@
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity.Question;
import java.util.List;
+import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
public interface QuestionRepository extends JpaRepository {
List findAllByWriterMemberId(Long writerId);
+ List findByAnswerIsNotNull();
+ Optional findByIdAndSharedTrue(Long id);
+ @Query("SELECT q FROM Question q WHERE q.answer IS NOT NULL AND q.shared = true ORDER BY q.updatedAt DESC")
+ List findByAnswerIsNotNullAndSharedTrue();
+ List findByAnswerIsNull();
+
+ @Query("SELECT q FROM Question q ORDER BY q.updatedAt DESC")
+ List findAllOrderedByUpdatedAt();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java
index 127500c..622eefe 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/AnswerService.java
@@ -1,6 +1,11 @@
package com.ComNCheck.ComNCheck.domain.majorQuestion.service;
+import com.ComNCheck.ComNCheck.domain.global.exception.AnswerNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.AnswerRequestDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.AnswerResponseDTO;
@@ -23,13 +28,13 @@ public class AnswerService {
@Transactional
- public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO) {
- // Role 체크 로직
- Member writer = memberRepository.findByMemberId(requestDTO.getWriterId())
- .orElseThrow(() -> new IllegalArgumentException("해당 회원이 존재하지 않습니다."));
+ public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO, Long memberId) {
+ Member writer = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("해당 회원이 존재하지 않습니다."));
+ isCheckRole(writer);
- Question question = questionRepository.findById(requestDTO.getQuestionId())
- .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다."));
+ Question question = questionRepository.findById(requestDTO.getMajorQuestionId())
+ .orElseThrow(() -> new PostNotFoundException("요청하신 질문이 존재하지 않습니다."));
Answer answer = answerRepository.findByQuestionId(question.getId()).orElse(null);
@@ -49,19 +54,32 @@ public AnswerResponseDTO createOrUpdateAnswer(AnswerRequestDTO requestDTO) {
}
}
@Transactional
- public AnswerResponseDTO updateAnswer(Long answerId, String content) {
+ public AnswerResponseDTO updateAnswer(Long answerId, String content, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
Answer answer = answerRepository.findById(answerId)
- .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다."));
+ .orElseThrow(() -> new AnswerNotFoundException("답변이 존재하지 않습니다."));
answer.updateAnswer(content);
return AnswerResponseDTO.of(answer);
}
@Transactional
- public void deleteAnswer(Long answerId) {
+ public void deleteAnswer(Long answerId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
Answer answer = answerRepository.findById(answerId)
- .orElseThrow(() -> new IllegalArgumentException("해당 답글이 존재하지 않습니다."));
+ .orElseThrow(() -> new AnswerNotFoundException("답변이 존재하지 않습니다."));
answerRepository.delete(answer);
-}
+ }
+
+ public void isCheckRole(Member member) {
+ Role checkRole = member.getRole();
+ if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) {
+ throw new ForbiddenException("접근 권한이 없습니다.");
+ }
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java
index 044b64e..e5b319c 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/majorQuestion/service/QuestionService.java
@@ -1,15 +1,19 @@
package com.ComNCheck.ComNCheck.domain.majorQuestion.service;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.PostNotFoundException;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
-import com.ComNCheck.ComNCheck.domain.global.exception.UnauthorizedException;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.request.QuestionRequestDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.dto.response.QuestionResponseDTO;
import com.ComNCheck.ComNCheck.domain.majorQuestion.model.entity.Question;
import com.ComNCheck.ComNCheck.domain.majorQuestion.repository.QuestionRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -22,13 +26,14 @@ public class QuestionService {
private final MemberRepository memberRepository;
@Transactional
- public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO) {
- Member writer = memberRepository.findByMemberId(requestDTO.getWriterId())
- .orElseThrow(() -> new IllegalArgumentException("회원이 존재하지 않습니다."));
+ public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO, Long memberId) {
+ Member writer = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다."));
Question question = Question.builder()
.title(requestDTO.getTitle())
.content(requestDTO.getContent())
+ .shared(requestDTO.isShared())
.writer(writer)
.build();
@@ -36,14 +41,26 @@ public QuestionResponseDTO createQuestion(QuestionRequestDTO requestDTO) {
return QuestionResponseDTO.of(saveQuestion);
}
+ public List getAllQuestion(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다."));
+ isCheckRole(member);
+
+ return questionRepository.findAllOrderedByUpdatedAt()
+ .stream()
+ .map(QuestionResponseDTO::of)
+ .toList();
+ }
+
public QuestionResponseDTO getQuestion(Long questionId) {
Question question = questionRepository.findById(questionId)
- .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다."));
+ .orElseThrow(() -> new PostNotFoundException("질문이 존재하지 않습니다."));
return QuestionResponseDTO.of(question);
}
- public List getAllQuestions() {
- return questionRepository.findAll()
+ public List getQuestionsWithAnswer() {
+
+ return questionRepository.findByAnswerIsNotNullAndSharedTrue()
.stream()
.map(QuestionResponseDTO::of)
.toList();
@@ -52,23 +69,23 @@ public List getAllQuestions() {
@Transactional
public QuestionResponseDTO updateQuestion(Long questionId, QuestionRequestDTO requestDTO, Long writerId) {
Question question = questionRepository.findById(questionId)
- .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다."));
+ .orElseThrow(() -> new PostNotFoundException("질문이 존재하지 않습니다."));
if (!question.getWriter().getMemberId().equals(writerId)) {
- throw new UnauthorizedException("작성자가 아닙니다.");
+ throw new ForbiddenException("작성자가 아닙니다.");
}
- question.updateQuestion(requestDTO.getTitle(), requestDTO.getContent());
+ question.updateQuestion(requestDTO);
return QuestionResponseDTO.of(question);
}
@Transactional
public void deleteQuestion(Long questionId, Long writerId) {
Question question = questionRepository.findById(questionId)
- .orElseThrow(() -> new IllegalArgumentException("해당 질문이 존재하지 않습니다."));
+ .orElseThrow(() -> new PostNotFoundException("해당 질문이 존재하지 않습니다."));
- if(question.getWriter().getMemberId().equals(writerId)) {
- throw new UnauthorizedException("작성자가 아닙니다.");
+ if(!question.getWriter().getMemberId().equals(writerId)) {
+ throw new ForbiddenException("작성자가 아닙니다.");
}
questionRepository.delete(question);
}
@@ -79,4 +96,22 @@ public List getMyQuestions(Long writerId) {
.map(QuestionResponseDTO::of)
.toList();
}
+
+ @Transactional
+ public List getUnanswerdAllQuestion(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("회원이 존재하지 않습니다."));
+ isCheckRole(member);
+ return questionRepository.findByAnswerIsNull()
+ .stream()
+ .map(QuestionResponseDTO::of)
+ .toList();
+ }
+
+ public void isCheckRole(Member member) {
+ Role checkRole = member.getRole();
+ if(checkRole != Role.ROLE_ADMIN && checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_STUDENT_COUNCIL) {
+ throw new ForbiddenException("접근 권한이 없습니다.");
+ }
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store
new file mode 100644
index 0000000..10fdb6e
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/member/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java
index 6a89151..4585e61 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/controller/MemberController.java
@@ -1,9 +1,14 @@
package com.ComNCheck.ComNCheck.domain.member.controller;
-import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO;
+import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO;
+import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService;
import com.ComNCheck.ComNCheck.domain.member.service.MemberService;
+import com.ComNCheck.ComNCheck.domain.security.handler.CustomSuccessHandler;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
@@ -20,27 +25,66 @@
@RequestMapping("/api/v1/member")
public class MemberController {
private final MemberService memberService;
+ private final CustomSuccessHandler customSuccessHandler;
- @PostMapping("/{memberId}/student/number")
- public ResponseEntity registerStudentNumber(
- @PathVariable Long memberId,
- @RequestParam("studentCardImage") MultipartFile studentCardImage) {
- MemberDTO responseDTO = memberService.registerStudentNumber(memberId, studentCardImage);
+ @PostMapping("/student/number")
+ @Operation(summary = "학번 등록", description = "모바일 학생증으로 학번을 등록한다.")
+ public ResponseEntity registerStudentNumber(
+ @RequestParam("studentCardImage") MultipartFile studentCardImage,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ MemberInformationResponseDTO responseDTO = memberService.registerStudentNumber(memberId, studentCardImage);
return ResponseEntity.ok(responseDTO);
}
@GetMapping("/members/president-council")
+ @Operation(summary = "학생회 목록 조회", description = "학생회 목록을 조회한다.")
public ResponseEntity getPresidentCouncilList() {
PresidentCouncilResponseDTO responseDTO = memberService.getPresidentAndCouncils();
return ResponseEntity.ok(responseDTO);
}
@GetMapping
- public ResponseEntity getMemberInformation(Authentication authentication) {
+ @Operation(summary = "본인 정보 조회", description = "로그인 이후, 학번 변동 이후 본인 정보를 조회한다.")
+ public ResponseEntity getMemberInformation(Authentication authentication) {
CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
Long memberId = principal.getMemberDTO().getMemberId();
- MemberDTO responseDTO = memberService.getMemberInformation(memberId);
+ MemberInformationResponseDTO responseDTO = memberService.getMemberInformation(memberId);
return ResponseEntity.ok(responseDTO);
}
+ @PostMapping("/logout")
+ @Operation(summary = "로그아웃", description = "쿠키의 jwt를 강제로 만료시켜 로그아웃 시킨다.")
+ public ResponseEntity logout(HttpServletRequest request, HttpServletResponse response) {
+ customSuccessHandler.clearAuthenticationSuccess(request, response);
+ return ResponseEntity.ok("로그아웃 성공");
+ }
+
+ @PostMapping("/alarm/major/events")
+ @Operation(summary = "과행사 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.")
+ public ResponseEntity changeAlarmMajorEvent(Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ memberService.changeAlarmMajorEvent(memberId);
+ return ResponseEntity.ok("과행사 알람 변경");
+ }
+
+ @PostMapping("/alarm/major/notices")
+ @Operation(summary = "과공지 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.")
+ public ResponseEntity changeAlarmMajorNotice(Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ memberService.changeAlarmMajorNotice(memberId);
+ return ResponseEntity.ok("과행사 알람 변경");
+ }
+
+ @PostMapping("/alarm/employment/notices")
+ @Operation(summary = "과 취업정보 알람 켜기 및 끄기", description = "과행사 알람이 오는 것을 켜거나 끌 수 있다.")
+ public ResponseEntity changeAlarmEmploymentNotice(Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ memberService.changeAlarmEmploymentNotice(memberId);
+ return ResponseEntity.ok("과행사 알람 변경");
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store
new file mode 100644
index 0000000..f882310
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java
index 6a1d602..f794d96 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberDTO.java
@@ -18,6 +18,7 @@ public class MemberDTO {
private String major;
private int studentNumber;
private Role role;
+ private boolean checkStudentCard;
public MemberDTO() {
}
@@ -30,6 +31,8 @@ public static MemberDTO of(Member member) {
.major(member.getMajor())
.studentNumber(member.getStudentNumber())
.role(member.getRole())
+ .checkStudentCard(member.isCheckStudentCard())
.build();
}
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java
new file mode 100644
index 0000000..2c5727f
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/dto/response/MemberInformationResponseDTO.java
@@ -0,0 +1,35 @@
+package com.ComNCheck.ComNCheck.domain.member.model.dto.response;
+
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
+
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class MemberInformationResponseDTO {
+
+ private Long memberId;
+ private String name;
+ private String major;
+ private int studentNumber;
+ private Role role;
+ private boolean checkStudentCard;
+ private boolean alarmMajorEvent;
+ private boolean alarmMajorNotice;
+ private boolean alarmEmploymentNotice;
+ public static MemberInformationResponseDTO of(Member member) {
+ return MemberInformationResponseDTO.builder()
+ .memberId(member.getMemberId())
+ .name(member.getName())
+ .major(member.getMajor())
+ .studentNumber(member.getStudentNumber())
+ .role(member.getRole())
+ .checkStudentCard(member.isCheckStudentCard())
+ .alarmMajorEvent(member.isAlarmMajorEvent())
+ .alarmMajorNotice(member.isAlarmMajorNotice())
+ .alarmEmploymentNotice(member.isAlarmEmploymentNotice())
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java
index 2184e3b..a9d2f4c 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Member.java
@@ -1,11 +1,15 @@
package com.ComNCheck.ComNCheck.domain.member.model.entity;
+import com.ComNCheck.ComNCheck.domain.fcm.model.entity.FcmToken;
import jakarta.persistence.*;
+import java.util.ArrayList;
+import java.util.List;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
+import lombok.Setter;
@Getter
@@ -24,10 +28,12 @@ public class Member {
@Column(name = "name", nullable = false)
private String name;
- @Column(name = "major", nullable = false)
+ // 실제 배포에서는 nullable 설정 false 해야함
+ @Column(name = "major", nullable = true)
private String major;
- @Column(name = "studnet_number", nullable = false)
+ @Column(name = "student_number")
+ @Setter
private int studentNumber;
@Column(name = "member_role", nullable = false)
@@ -37,6 +43,21 @@ public class Member {
@Column(name = "position")
private String position;
+ @Column(name = "check_student_card", nullable = false)
+ private boolean checkStudentCard;
+
+ @Column(name = "alarm_major_event", nullable = false)
+ private boolean alarmMajorEvent;
+
+ @Column(name = "alarm_major_notice", nullable = false)
+ private boolean alarmMajorNotice;
+
+ @Column(name = "alarm_employment_notice")
+ private boolean alarmEmploymentNotice;
+
+ @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List fcmTokens = new ArrayList<>();
+
@Builder
public Member(Long memberId, String email, String name, String major, int studentNumber, Role role) {
this.memberId = memberId;
@@ -46,20 +67,43 @@ public Member(Long memberId, String email, String name, String major, int studen
this.studentNumber = studentNumber;
this.position = null;
this.role = role;
+ this.checkStudentCard = false;
+ this.alarmMajorNotice = false;
+ this.alarmMajorEvent = false;
+ this.alarmEmploymentNotice = false;
}
- /*
- setter code
- 어노테이션으로 안하고 필요한 경우만 setter 설정
- */
- public void setStudentNumber(int studentNumber) {
- this.studentNumber = studentNumber;
- }
public void updatePosition(String requestPosition) {
this.position = requestPosition;
}
public void updateRole(Role newRole) {
this.role = newRole;
}
+ public void addFcmToken(FcmToken token) {
+ this.fcmTokens.add(token);
+ token.setMember(this);
+ }
+ public void changeCheckStudentCard() {
+ this.checkStudentCard = true;
+ }
+ public void onAlarmMajorEvent() {
+ this.alarmMajorEvent = true;
+ }
+ public void offAlarmMajorEvent() {
+ this.alarmMajorEvent = false;
+ }
+ public void onAlarmMajorNotice() {
+ this.alarmMajorNotice = true;
+ }
+ public void offAlarmMajorNotice() {
+ this.alarmMajorNotice = false;
+ }
+ public void onAlarmEmploymentNotice() {
+ this.alarmEmploymentNotice = true;
+ }
+ public void offAlarmEmploymentNotice() {
+ this.alarmEmploymentNotice = false;
+ }
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java
index 938f7d6..b75fc9f 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/model/entity/Role.java
@@ -12,6 +12,7 @@ public enum Role {
ROLE_STUDENT_COUNCIL("ROLE_STUDENT_COUNCIL"),
ROLE_STUDENT("ROLE_STUDENT"),
ROLE_GRADUATE_STUDENT("ROLE_GRADUATE_STUDENT");
+
private final String value;
Role(String value) {
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java
index 1e9dbd3..f1f025e 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/repository/MemberRepository.java
@@ -14,5 +14,8 @@ public interface MemberRepository extends JpaRepository {
Optional findByRole(Role role);
List findAllByRole(Role role);
+ List findByAlarmMajorNoticeTrue();
+ List findByAlarmEmploymentNoticeTrue();
+ List findByAlarmMajorEventTrue();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java
index 9bac162..4da58a3 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/CustomOAuthMemberService.java
@@ -21,48 +21,52 @@
public class CustomOAuthMemberService extends DefaultOAuth2UserService {
private final MemberRepository memberRepository;
+ private final static String ADMIN_EMAIL_1 = "comncheck0306@gmail.com";
+ private final static String ADMIN_EMAIL_2 = "another0306@gmail.com";
+
@Override
@Transactional
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2User oAuth2User = super.loadUser(userRequest);
- System.out.println( "oAuthUser 정보"+ oAuth2User);
String email = oAuth2User.getAttribute("email");
String name = extractName(oAuth2User.getAttribute("name"));
String major = extractMajor(oAuth2User.getAttribute("name"));
//String sub = oAuth2User.getAttribute("sub"); 이메일 변경 여부 따지고 변경될경우 findByEmail 대신 findBySub 사용
String hd = oAuth2User.getAttribute("hd");
- if (!"hufs.ac.kr".equals(hd)) {
+ if (!isAllowedUser(email, hd)) {
OAuth2Error oauth2Error = new OAuth2Error(
"invalid_hosted_domain",
- "허용되지 않은 호스팅 도메인입니다.",
- null
+ "허용되지 않은 호스팅 도메인 혹은 계정입니다.",
+ "https://www.comncheck.com/login?error=invalid_domain"
);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
- // 이메일 변경 가능시 sub 변
+ // 이메일 변경 가능시 sub 변수
Member member = memberRepository.findByEmail(email).orElseGet(() -> {
Member newMember = Member.builder()
.email(email)
.name(name)
.major(major)
.role(Role.ROLE_STUDENT)
- .studentNumber(12345678)// 난수 변수 값 만드는 메서드 만들어야함
+ .studentNumber(123456789)
.build();
memberRepository.save(newMember);
return newMember;
- });
-
- MemberDTO memberDTO = new MemberDTO();
- memberDTO.setMemberId(member.getMemberId());
- memberDTO.setEmail(member.getEmail());
- memberDTO.setName(member.getName());
- memberDTO.setMajor(member.getMajor());
- memberDTO.setRole(member.getRole());
- memberDTO.setStudentNumber(member.getStudentNumber());
- return new CustomOAuth2Member(memberDTO);
+ });
+
+ return new CustomOAuth2Member(MemberDTO.of(member));
+ }
+
+ private boolean isAllowedUser(String email, String hd) {
+ if ("hufs.ac.kr".equals(hd)
+ || ADMIN_EMAIL_1.equals(email)
+ || ADMIN_EMAIL_2.equals(email)) {
+ return true;
+ }
+ return false;
}
private String cleanString(String input) {
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java
index da8b9b9..b062af5 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/member/service/MemberService.java
@@ -1,16 +1,20 @@
package com.ComNCheck.ComNCheck.domain.member.service;
-import com.ComNCheck.ComNCheck.domain.member.exception.ValidationException;
+import com.ComNCheck.ComNCheck.domain.global.exception.FastApiException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.ValidationException;
import com.ComNCheck.ComNCheck.domain.global.infrastructure.FastApiClient;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.CouncilDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.FastApiStudentCardDTO.ExtractedText;
-import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO;
+import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberInformationResponseDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentCouncilResponseDTO;
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.PresidentDTO;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Member;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.member.repository.MemberRepository;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
@@ -26,9 +30,9 @@ public class MemberService {
private final FastApiClient fastApiClient;
@Transactional
- public MemberDTO registerStudentNumber(Long id, MultipartFile studentCardImage) {
+ public MemberInformationResponseDTO registerStudentNumber(Long id, MultipartFile studentCardImage) {
Member member = memberRepository.findByMemberId(id)
- .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다."));
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
FastApiStudentCardDTO fastApiResponse = fastApiClient.sendImage(studentCardImage);
FastApiStudentCardDTO.ExtractedText extractedText = fastApiResponse.getExtractedText();
@@ -41,9 +45,10 @@ public MemberDTO registerStudentNumber(Long id, MultipartFile studentCardImage)
throw new ValidationException("이름 또는 전공이 일치하지 않습니다.");
}
member.setStudentNumber(studentNumber);
+ member.changeCheckStudentCard();
Member savedMember = memberRepository.save(member);
- return MemberDTO.of(savedMember);
+ return MemberInformationResponseDTO.of(savedMember);
}
public PresidentCouncilResponseDTO getPresidentAndCouncils() {
@@ -73,14 +78,54 @@ private void validateFastApiResponse(ExtractedText extractedText) {
extractedText.getName() == null ||
extractedText.getMajor() == null ||
extractedText.getStudentId() == null) {
- throw new ValidationException("FastAPI 응답이 유효하지 않습니다.");
+ throw new FastApiException("FastAPI 응답이 유효하지 않습니다.");
}
}
- public MemberDTO getMemberInformation(Long memberId) {
+ public MemberInformationResponseDTO getMemberInformation(Long memberId) {
Member member = memberRepository.findByMemberId(memberId)
- .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 학생입니다."));
- return MemberDTO.of(member);
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ return MemberInformationResponseDTO.of(member);
}
+
+
+ @Transactional
+ public void changeAlarmMajorEvent(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ if(member.isAlarmMajorEvent()) {
+ member.offAlarmMajorEvent();
+ }
+ else {
+ member.onAlarmMajorEvent();
+ }
+ memberRepository.save(member);
+ }
+
+ @Transactional
+ public void changeAlarmMajorNotice(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ if(member.isAlarmMajorNotice()) {
+ member.offAlarmMajorNotice();
+ }
+ else {
+ member.onAlarmMajorNotice();
+ }
+ memberRepository.save(member);
+ }
+
+ @Transactional
+ public void changeAlarmEmploymentNotice(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ if(member.isAlarmEmploymentNotice()) {
+ member.offAlarmEmploymentNotice();
+ }
+ else {
+ member.onAlarmEmploymentNotice();
+ }
+ memberRepository.save(member);
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/.DS_Store
new file mode 100644
index 0000000..3606361
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java
index 3ced13f..314157d 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/controller/RoleChangeController.java
@@ -1,13 +1,19 @@
package com.ComNCheck.ComNCheck.domain.roleChange.controller;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO;
+import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeUpdateRequestDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeResponseDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.service.RoleChangeRequestService;
+import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
+import io.swagger.v3.oas.annotations.Operation;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -27,50 +33,68 @@ public class RoleChangeController {
private final RoleChangeRequestService roleChangeRequestService;
@PostMapping
+ @Operation(summary = "학생회 등급 신청", description = "학생회 인원이 학생회 등급으로 신청한다")
public ResponseEntity createRoleChangeRequest(
- @RequestBody RoleChangeRequestDTO requestDTO) {
- RoleChangeResponseDTO createDTO = roleChangeRequestService.createRoleChangeRequest(requestDTO);
+ @RequestBody RoleChangeRequestDTO requestDTO,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ RoleChangeResponseDTO createDTO = roleChangeRequestService.createRoleChangeRequest(memberId, requestDTO);
URI location = URI.create("api/role-change-requests/" + createDTO.getRequestId());
return ResponseEntity.created(location).body(createDTO);
}
@GetMapping
- public ResponseEntity> getAllRequest() {
- List response = roleChangeRequestService.getAllRequests();
+ @Operation(summary = "학생회 등급 신청 목록 조회", description = "학생회 등급 신청 목록을 조회한다.")
+ public ResponseEntity> getAllRequest(Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ List response = roleChangeRequestService.getAllRequests(memberId);
return ResponseEntity.ok(response);
}
+
@GetMapping("/{requestId}")
- public ResponseEntity getRequestDetail(@PathVariable Long requestId) {
- RoleChangeResponseDTO responseDTO = roleChangeRequestService.getRequestDetail(requestId);
+ @Operation(summary = "특정 학생회 등급 신청 조회", description = "특정 학생회 등급 신청을 조회한다.")
+ public ResponseEntity getRequestDetail(@PathVariable Long requestId,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ RoleChangeResponseDTO responseDTO = roleChangeRequestService.getRequestDetail(requestId, memberId);
return ResponseEntity.ok(responseDTO);
}
@PostMapping("{requestId}/approve")
- public ResponseEntity approveRequest(@PathVariable Long requestId) {
- roleChangeRequestService.approveRequest(requestId);
+ @Operation(summary = "학생회 등급 신청 승인", description = "과회장 or 관리자가 학생회 등급 신청을 승인한다.")
+ public ResponseEntity approveRequest(@PathVariable Long requestId
+ , Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ roleChangeRequestService.approveRequest(requestId, memberId);
return ResponseEntity.ok("승인완료");
}
- @GetMapping("/approved")
- public ResponseEntity> getApprovedRequests() {
- List approvedList = roleChangeRequestService.getApproveRequests();
- return ResponseEntity.ok(approvedList);
- }
-
- @PutMapping("/{requestId}/change-role")
- public ResponseEntity changeMemberRole(
- @PathVariable Long requestId, @RequestBody RoleChangeRequestDTO requestDTO
- ) {
- roleChangeRequestService.changeMemberRole(requestId, requestDTO);
- return ResponseEntity.ok("등급 재변경 완료");
- }
-
@DeleteMapping("/{requestId}")
- public ResponseEntity deleteRequest(@PathVariable Long requestId) {
- roleChangeRequestService.deleteRequest(requestId);
+ @Operation(summary = "특정 학생회 등급 신청 요청 삭제", description = "요청온 학생회 등급 신청 요청을 삭제한다.")
+ public ResponseEntity deleteRequest(@PathVariable Long requestId,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ roleChangeRequestService.deleteRequest(requestId, memberId);
return ResponseEntity.noContent().build();
}
+ @PutMapping("/{requestId}")
+ @Operation(summary = "특정 학생회 직책이나 등급을 변경", description = "과회장이 특정 학생회 인원의 직책이나 등급을 변경한다")
+ public ResponseEntity putRoleChange(@PathVariable Long requestId,
+ @RequestBody RoleChangeUpdateRequestDTO roleChangeUpdateRequestDTO,
+ Authentication authentication) {
+ CustomOAuth2Member principal = (CustomOAuth2Member) authentication.getPrincipal();
+ Long memberId = principal.getMemberDTO().getMemberId();
+ String updatePosition = roleChangeUpdateRequestDTO.getRequestPosition();
+ Role updateRole = roleChangeUpdateRequestDTO.getRequestRole();
+ RoleChangeResponseDTO responseDTO = roleChangeRequestService.updateRoleChange(requestId, memberId, updatePosition, updateRole);
+ return ResponseEntity.ok(responseDTO);
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/.DS_Store
new file mode 100644
index 0000000..3187d2a
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java
index 64cc240..be91ed4 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeRequestDTO.java
@@ -7,7 +7,6 @@
@Getter
@Setter
public class RoleChangeRequestDTO {
- private Long memberId;
private String name;
private int studentNumber;
private String major;
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java
new file mode 100644
index 0000000..5dd4b7a
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/request/RoleChangeUpdateRequestDTO.java
@@ -0,0 +1,12 @@
+package com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request;
+
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class RoleChangeUpdateRequestDTO {
+ private String requestPosition;
+ private Role requestRole;
+}
\ No newline at end of file
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java
index 23ee679..884b2fb 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeListDTO.java
@@ -1,6 +1,7 @@
package com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response;
+import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RequestStatus;
import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RoleChange;
import lombok.Builder;
import lombok.Getter;
@@ -12,12 +13,14 @@ public class RoleChangeListDTO {
private Long requestId;
private String name;
private String requestPosition;
+ private RequestStatus status;
public static RoleChangeListDTO of(RoleChange roleChange) {
return RoleChangeListDTO.builder()
.requestId(roleChange.getRequestId())
.name(roleChange.getMember().getName())
.requestPosition(roleChange.getRequestPosition())
+ .status(roleChange.getStatus())
.build();
}
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java
index c027585..e64e9a7 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/dto/response/RoleChangeResponseDTO.java
@@ -27,6 +27,7 @@ public static RoleChangeResponseDTO of(RoleChange entity) {
.major(entity.getMember().getMajor())
.studentNumber(entity.getMember().getStudentNumber())
.position(entity.getRequestPosition())
+ .requestedRole(entity.getRequestRole())
.status(entity.getStatus())
.build();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java
index 11f175d..4f6eb2c 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/model/entity/RoleChange.java
@@ -39,6 +39,7 @@ public class RoleChange {
private String requestPosition;
@Column(name = "request_role", nullable = false)
+ @Enumerated(EnumType.STRING)
private Role requestRole;
@Builder
@@ -53,5 +54,10 @@ public void approve() {
this.status = RequestStatus.APPROVED;
}
+ public void update(String requestPosition, Role requestRole) {
+ this.requestPosition = requestPosition;
+ this.requestRole = requestRole;
+ }
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java
index 37de7e4..e18d02f 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/repository/RoleChangeRequestRepository.java
@@ -1,7 +1,12 @@
package com.ComNCheck.ComNCheck.domain.roleChange.repository;
import com.ComNCheck.ComNCheck.domain.roleChange.model.entity.RoleChange;
+import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
public interface RoleChangeRequestRepository extends JpaRepository {
+
+ @Query("SELECT r FROM RoleChange r ORDER BY r.requestId DESC")
+ List findAllOrderByIdDesc();
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java
index f9da172..257e557 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/roleChange/service/RoleChangeRequestService.java
@@ -1,6 +1,10 @@
package com.ComNCheck.ComNCheck.domain.roleChange.service;
+import com.ComNCheck.ComNCheck.domain.global.exception.ApplyNotFoundException;
+import com.ComNCheck.ComNCheck.domain.global.exception.ForbiddenException;
+import com.ComNCheck.ComNCheck.domain.global.exception.MemberNotFoundException;
+import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.request.RoleChangeRequestDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.ApprovedRoleListDTO;
import com.ComNCheck.ComNCheck.domain.roleChange.model.dto.response.RoleChangeListDTO;
@@ -24,9 +28,9 @@ public class RoleChangeRequestService {
private final MemberRepository memberRepository;
@Transactional
- public RoleChangeResponseDTO createRoleChangeRequest(RoleChangeRequestDTO requestDTO) {
- Member member = memberRepository.findByMemberId(requestDTO.getMemberId())
- .orElseThrow(() -> new IllegalArgumentException("등록된 회원이 없습니다."));
+ public RoleChangeResponseDTO createRoleChangeRequest(Long memberId, RoleChangeRequestDTO requestDTO) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
RoleChange roleChange = RoleChange.builder()
.member(member)
@@ -38,33 +42,49 @@ public RoleChangeResponseDTO createRoleChangeRequest(RoleChangeRequestDTO reques
return RoleChangeResponseDTO.of(saveRoleChange);
}
- public List getAllRequests() {
- List requests = roleChangeRequestRepository.findAll();
+ public List getAllRequests(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
+ List requests = roleChangeRequestRepository.findAllOrderByIdDesc();
return requests.stream()
.map(RoleChangeListDTO::of)
.collect(Collectors.toList());
}
- public RoleChangeResponseDTO getRequestDetail(Long requestId) {
+ public RoleChangeResponseDTO getRequestDetail(Long requestId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
RoleChange request = roleChangeRequestRepository.findById(requestId)
- .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다."));
+ .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다."));
return RoleChangeResponseDTO.of(request);
}
@Transactional
- public void approveRequest(Long requestId) {
+ public void approveRequest(Long requestId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
RoleChange request = roleChangeRequestRepository.findById(requestId)
- .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다."));
+ .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다."));
request.approve();
- Member member = request.getMember();
- member.updateRole(request.getRequestRole());
- member.updatePosition(request.getRequestPosition());
+ Member updateMember = request.getMember();
+ updateMember.updateRole(request.getRequestRole());
+ updateMember.updatePosition(request.getRequestPosition());
}
- public List getApproveRequests() {
+ public List getApproveRequests(Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
List requests = roleChangeRequestRepository.findAll().stream()
.filter(req -> req.getStatus() == RequestStatus.APPROVED)
.collect(Collectors.toList());
@@ -74,24 +94,40 @@ public List getApproveRequests() {
.collect(Collectors.toList());
}
+
@Transactional
- public void changeMemberRole(Long requestId, RoleChangeRequestDTO requestDTO) {
+ public void deleteRequest(Long requestId, Long memberId) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
RoleChange request = roleChangeRequestRepository.findById(requestId)
- .orElseThrow(() -> new IllegalArgumentException("요청이 없습니다."));
+ .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다."));
+ roleChangeRequestRepository.delete(request);
+ }
- if(request.getStatus() != RequestStatus.APPROVED) {
- throw new IllegalArgumentException("한번 변경된 요청만 수정 가능합니다.");
- }
+ @Transactional
+ public RoleChangeResponseDTO updateRoleChange(Long requestId, Long memberId, String updatePosition, Role updateRole) {
+ Member member = memberRepository.findByMemberId(memberId)
+ .orElseThrow(() -> new MemberNotFoundException("등록된 회원이 없습니다."));
+ isCheckRole(member);
+
+ RoleChange role = roleChangeRequestRepository.findById(requestId)
+ .orElseThrow(() -> new ApplyNotFoundException("등록된 학생회 신청이 없습니다."));
- Member member = request.getMember();
- member.updateRole(requestDTO.getRequestRole());
- member.updatePosition(requestDTO.getRequestPosition());
+ role.update(updatePosition, updateRole);
+ Member updateMember = role.getMember();
+ updateMember.updateRole(role.getRequestRole());
+ updateMember.updatePosition(role.getRequestPosition());
+
+ return RoleChangeResponseDTO.of(role);
}
- @Transactional
- public void deleteRequest(Long requestId) {
- RoleChange request = roleChangeRequestRepository.findById(requestId)
- .orElseThrow(() -> new IllegalArgumentException("등록된 학생회 신청이 없습니다."));
- roleChangeRequestRepository.delete(request);
+ public void isCheckRole(Member member) {
+ Role checkRole = member.getRole();
+ if (checkRole != Role.ROLE_MAJOR_PRESIDENT && checkRole != Role.ROLE_ADMIN) {
+ throw new ForbiddenException("접근 권한이 없습니다.");
+ }
}
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/.DS_Store b/src/main/java/com/ComNCheck/ComNCheck/domain/security/.DS_Store
new file mode 100644
index 0000000..dfe2219
Binary files /dev/null and b/src/main/java/com/ComNCheck/ComNCheck/domain/security/.DS_Store differ
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java
index 0a0d397..e720699 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CorsMvcConfig.java
@@ -11,6 +11,8 @@ public class CorsMvcConfig implements WebMvcConfigurer {
public void addCorsMappings(CorsRegistry corsRegistry) {
corsRegistry.addMapping("/**")
.exposedHeaders("Set-Cookie")
- .allowedOrigins("http://localhost:3000");
+ .allowedOrigins("https://www.comncheck.com")
+ .allowedMethods("*")
+ .allowCredentials(true);
}
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java
new file mode 100644
index 0000000..bf6c7a9
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomAuthorizationRequestResolver.java
@@ -0,0 +1,42 @@
+package com.ComNCheck.ComNCheck.domain.security.config;
+
+import jakarta.servlet.http.HttpServletRequest;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+
+public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
+
+ private final OAuth2AuthorizationRequestResolver defaultResolver;
+
+ public CustomAuthorizationRequestResolver(OAuth2AuthorizationRequestResolver defaultResolver) {
+ this.defaultResolver = defaultResolver;
+ }
+
+ @Override
+ public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
+ OAuth2AuthorizationRequest oAuth2AuthorizationRequest = this.defaultResolver.resolve(request);
+ return customizeRequest(oAuth2AuthorizationRequest);
+ }
+
+ @Override
+ public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
+ OAuth2AuthorizationRequest oAuth2AuthorizationRequest = this.defaultResolver.resolve(request, clientRegistrationId);
+ return customizeRequest(oAuth2AuthorizationRequest);
+ }
+
+ private OAuth2AuthorizationRequest customizeRequest(OAuth2AuthorizationRequest oAuth2AuthorizationRequest) {
+ if (oAuth2AuthorizationRequest == null) {
+ return null;
+ }
+
+ Map extraParameters = new LinkedHashMap<>(oAuth2AuthorizationRequest.getAdditionalParameters());
+ extraParameters.put("prompt", "select_account");
+
+ return OAuth2AuthorizationRequest.from(oAuth2AuthorizationRequest)
+ .additionalParameters(extraParameters)
+ .build();
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java
new file mode 100644
index 0000000..ad73d1c
--- /dev/null
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/CustomFailureHandler.java
@@ -0,0 +1,25 @@
+package com.ComNCheck.ComNCheck.domain.security.config;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
+
+public class CustomFailureHandler extends SimpleUrlAuthenticationFailureHandler {
+
+ public CustomFailureHandler(String defaultFailureUrl) {
+ super(defaultFailureUrl);
+ }
+
+ @Override
+ public void onAuthenticationFailure(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException exception
+ ) throws IOException, ServletException {
+
+ super.onAuthenticationFailure(request, response, exception);
+ }
+}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java
index d8ceb76..eac5b56 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/config/SecurityConfig.java
@@ -1,18 +1,23 @@
package com.ComNCheck.ComNCheck.domain.security.config;
+import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService;
import com.ComNCheck.ComNCheck.domain.security.filter.JWTFilter;
import com.ComNCheck.ComNCheck.domain.security.handler.CustomSuccessHandler;
-import com.ComNCheck.ComNCheck.domain.member.service.CustomOAuthMemberService;
import com.ComNCheck.ComNCheck.domain.security.util.JWTUtil;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
+import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
@@ -21,63 +26,74 @@
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig {
+
private final CustomOAuthMemberService customOAuth2MemberService;
private final CustomSuccessHandler customSuccessHandler;
private final JWTUtil jwtUtil;
+ private final ClientRegistrationRepository clientRegistrationRepository;
+ private final OAuth2AuthorizedClientRepository authorizedClientRepository;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
- http
- .cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
- @Override
- public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
- CorsConfiguration configuration = new CorsConfiguration();
- configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
- configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
- configuration.setAllowCredentials(true);
- configuration.setAllowedHeaders(Arrays.asList("*"));
- configuration.setMaxAge(3600L);
- configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization"));
- return configuration;
- }
- }))
- .csrf(csrf -> csrf.disable())
- .formLogin(form -> form.disable())
- .httpBasic(httpBasic -> httpBasic.disable())
- .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
- .authorizeHttpRequests(auth -> auth
- .requestMatchers(
- "/login/**",
- "/oauth2/**",
- "/h2-console/**",
- "/swagger-ui.html",
- "/swagger-ui/**",
- "/V3/api-docs",
- "/v3/api-docs/**",
- "/swagger-resources/**",
- "/webjars/**"
- //"/api/v1/**"
- ).permitAll()
- .anyRequest().authenticated()
- )
- .oauth2Login(oauth2 -> oauth2
- .authorizationEndpoint(authorization -> authorization
- .baseUri("/oauth2/authorize")
- )
- .redirectionEndpoint(redirection -> redirection
- .baseUri("/login/oauth2/code/*")
- )
- .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig
- .userService(customOAuth2MemberService))
- .successHandler(customSuccessHandler)
- );
- System.out.println("시큐리티config");
- // H2 Console 관련 헤더 설정 -> 디비 변경 시 제거
- http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()));
+ http.cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() {
+ @Override
+ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
+ CorsConfiguration configuration = new CorsConfiguration();
+ configuration.setAllowedOrigins(Arrays.asList("https://www.comncheck.com"));
+ configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
+ configuration.setAllowCredentials(true);
+ configuration.setAllowedHeaders(Arrays.asList("*"));
+ configuration.setMaxAge(3600L);
+ configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "AccessToken"));
+ return configuration;
+ }
+ }));
+
+ http.csrf(csrf -> csrf.disable())
+ .formLogin(Customizer.withDefaults()).formLogin(form -> form.disable())
+ .httpBasic(Customizer.withDefaults()).httpBasic(httpBasic -> httpBasic.disable())
+ .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
+
+ http.authorizeHttpRequests(auth -> auth
+ .requestMatchers(
+ "/login/**",
+ "/oauth2/**",
+ "/swagger-ui.html",
+ "/swagger-ui/**",
+ "/V3/api-docs",
+ "/v3/api-docs/**",
+ "/swagger-resources/**",
+ "/webjars/**",
+ "/api/v1/**"
+ ).permitAll()
+ .anyRequest().authenticated()
+ );
+
+ http.oauth2Login(oauth2 -> oauth2
+ .authorizationEndpoint(authorization -> authorization
+ .baseUri("/oauth2/authorize")
+ .authorizationRequestResolver(customAuthorizationRequestResolver())
+ )
+ .redirectionEndpoint(redirection -> redirection
+ .baseUri("/login/oauth2/code/*")
+ )
+ .userInfoEndpoint(userInfoEndpointConfig ->
+ userInfoEndpointConfig.userService(customOAuth2MemberService)
+ )
+ .successHandler(customSuccessHandler)
+ .failureHandler(new CustomFailureHandler("https://www.comncheck.com/login?error=invalid_domain"))
+ );
http.addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
+
+ @Bean
+ public OAuth2AuthorizationRequestResolver customAuthorizationRequestResolver() {
+ DefaultOAuth2AuthorizationRequestResolver defaultResolver =
+ new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, "/oauth2/authorize");
+ return new CustomAuthorizationRequestResolver(defaultResolver);
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java
index 10286a6..924e4d7 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/filter/JWTFilter.java
@@ -2,9 +2,9 @@
import com.ComNCheck.ComNCheck.domain.member.model.dto.response.MemberDTO;
import com.ComNCheck.ComNCheck.domain.member.model.entity.Role;
-import com.ComNCheck.ComNCheck.domain.security.exception.TokenExpiredException;
import com.ComNCheck.ComNCheck.domain.security.oauth.CustomOAuth2Member;
import com.ComNCheck.ComNCheck.domain.security.util.JWTUtil;
+import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
@@ -12,13 +12,13 @@
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@RequiredArgsConstructor
public class JWTFilter extends OncePerRequestFilter {
@@ -34,8 +34,7 @@ public class JWTFilter extends OncePerRequestFilter {
"/webjars/**",
"/login/**",
"/oauth2/**",
- "/h2-console/**"
- //"api/v1/**"
+ "api/v1/**"
};
private final AntPathMatcher pathMatcher = new AntPathMatcher();
@@ -61,45 +60,59 @@ protected void doFilterInternal(HttpServletRequest request,
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
- if ("Authorization".equals(cookie.getName())) { // 쿠키 이름 확인
+ if ("AccessToken".equals(cookie.getName())) {
token = cookie.getValue();
- logger.debug("Found Authorization cookie: " + token);
+ logger.debug("AccessToken 쿠키를 찾았습니다: " + token);
break;
}
}
}
try {
- if (token != null) {
- if (jwtUtil.isExpired(token)) {
- throw new TokenExpiredException("만료된 토큰입니다.");
- }
+ if (token == null || token.trim().isEmpty()) {
+ logger.error("AccessToken 쿠키가 존재하지 않습니다.");
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ response.setCharacterEncoding("UTF-8");
+ response.getWriter().write("{\"error\": \"MISSING_TOKEN\", \"message\": \"AccessToken 쿠키가 존재하지 않습니다.\"}");
+ response.getWriter().flush();
+ return;
+ }
- String username = jwtUtil.getUsername(token);
- Long id = jwtUtil.getId(token);
- Role role = jwtUtil.getRole(token);
+ String username = jwtUtil.getUsername(token);
+ Long id = jwtUtil.getId(token);
+ Role role = jwtUtil.getRole(token);
- MemberDTO memberDTO = new MemberDTO();
- memberDTO.setMemberId(id);
- memberDTO.setName(username);
- memberDTO.setRole(role);
+ MemberDTO memberDTO = new MemberDTO();
+ memberDTO.setMemberId(id);
+ memberDTO.setName(username);
+ memberDTO.setRole(role);
- CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(memberDTO);
+ CustomOAuth2Member customOAuth2Member = new CustomOAuth2Member(memberDTO);
- Authentication authToken =
- new UsernamePasswordAuthenticationToken(
- customOAuth2Member,
- null,
- customOAuth2Member.getAuthorities()
- );
- SecurityContextHolder.getContext().setAuthentication(authToken);
- logger.debug("SecurityContext set with user: " + username);
- } else {
- logger.debug("No JWT token found in cookies.");
- }
+ Authentication authToken = new UsernamePasswordAuthenticationToken(
+ customOAuth2Member,
+ null,
+ customOAuth2Member.getAuthorities()
+ );
+ SecurityContextHolder.getContext().setAuthentication(authToken);
+ logger.debug("SecurityContext에 사용자 정보를 설정했습니다: " + username);
+
+ } catch (ExpiredJwtException e) {
+ logger.error("토큰 만료: " + e.getMessage());
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ response.setCharacterEncoding("UTF-8");
+ response.getWriter().write("{\"error\": \"TOKEN_EXPIRED\", \"message\": \"" + e.getMessage() + "\"}");
+ response.getWriter().flush();
+ return;
} catch (Exception e) {
- logger.error("Authentication error: " + e.getMessage());
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
+ logger.error("인증 오류: " + e.getMessage());
+ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ response.setContentType("application/json;charset=UTF-8");
+ response.setCharacterEncoding("UTF-8");
+ response.getWriter().write("{\"error\": \"AUTHENTICATION_ERROR\", \"message\": \"" + e.getMessage() + "\"}");
+ response.getWriter().flush();
return;
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java
index c000911..0105c1e 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/handler/CustomSuccessHandler.java
@@ -6,10 +6,12 @@
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseCookie;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
@@ -26,29 +28,69 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
Authentication authentication) throws IOException, ServletException {
CustomOAuth2Member customMemberDetails = (CustomOAuth2Member) authentication.getPrincipal();
- Long userId = customMemberDetails.getMemberDTO().getMemberId();
+ Long memberId = customMemberDetails.getMemberDTO().getMemberId();
String username = customMemberDetails.getName();
Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
Iterator extends GrantedAuthority> iterator = authorities.iterator();
GrantedAuthority auth = iterator.next();
String role = auth.getAuthority().toString();
+ boolean checkStudentCard = customMemberDetails.isCheckStudentCard();
+ System.out.println(checkStudentCard);
- String token = jwtUtil.createJwt(userId, username, role, 60*60*60L);
+ String token = jwtUtil.createJwt(memberId, username, role, 365L * 24 * 60 * 60 * 1000); // 60 * 60 * 1000L
- response.addCookie(createCookie("Authorization", token));
- response.sendRedirect("http://localhost:3000/signup?id=" + userId);
+ ResponseCookie cookie = createCookie("AccessToken", token);
+ response.setHeader("Set-Cookie", cookie.toString());
+ //response.addCookie(createCookie("AccessToken", token)); // Cookie로 했을때
+ if(!checkStudentCard) {
+ response.sendRedirect("https://www.comncheck.com/login/first"); //https://com-n-check.vercel.app
+ }
+ else {
+ response.sendRedirect("https://www.comncheck.com/notice");
+ }
+ //response.sendRedirect("http://localhost:3000/login/first");
}
- private Cookie createCookie(String key, String value) {
- Cookie cookie = new Cookie(key, value);
- cookie.setMaxAge(60*60*60);
- //cookie.setSecure(true);
- cookie.setPath("/");
- //cookie.setHttpOnly(true);
+ public void clearAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response) {
+ HttpSession session = request.getSession(false);
+ if (session != null) {
+ session.invalidate();
+ }
- return cookie;
+ Cookie jsessionCookie = new Cookie("JSESSIONID", null);
+ jsessionCookie.setPath("/");
+ jsessionCookie.setMaxAge(0);
+ response.addCookie(jsessionCookie);
+
+ Cookie accessTokenCookie = new Cookie("AccessToken", null);
+ accessTokenCookie.setPath("/");
+ accessTokenCookie.setHttpOnly(true);
+ accessTokenCookie.setMaxAge(0);
+ response.addCookie(accessTokenCookie);
+ }
+
+ private ResponseCookie createCookie(String key, String value) {
+ return ResponseCookie.from(key, value)
+ .maxAge(60 * 60 * 60)
+ .secure(true)
+ .sameSite("None")
+ .path("/")
+ .domain("www.comncheck.com")
+ .httpOnly(true)
+ .build();
}
+// private Cookie createCookie(String key, String value) {
+// Cookie cookie = new Cookie(key, value);
+// cookie.setMaxAge(60 * 60 * 60);
+// cookie.setSecure(true);
+// cookie.setHttpOnly(true);
+// cookie.setPath("/");
+// cookie.setDomain("com-n-check.vercel.app");
+// cookie.setAttribute("SameSite", "None");
+// return cookie;
+// }
+
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java
index 41e541e..b7440ed 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/oauth/CustomOAuth2Member.java
@@ -9,7 +9,8 @@
import org.springframework.security.oauth2.core.user.OAuth2User;
@RequiredArgsConstructor
-public class CustomOAuth2Member implements OAuth2User {
+public class
+CustomOAuth2Member implements OAuth2User {
private final MemberDTO memberDTO;
public MemberDTO getMemberDTO() {
@@ -38,5 +39,8 @@ public String getName() {
return memberDTO.getName();
}
+ public boolean isCheckStudentCard() {
+ return memberDTO.isCheckStudentCard();
+ }
}
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java b/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java
index 37ab0d4..d877de0 100644
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java
+++ b/src/main/java/com/ComNCheck/ComNCheck/domain/security/util/JWTUtil.java
@@ -46,7 +46,7 @@ public String getUsername(String token) {
.build()
.parseSignedClaims(token)
.getPayload()
- .get("username", String.class);
+ .get("name", String.class);
}
public Role getRole(String token) {
diff --git a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java b/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java
deleted file mode 100644
index 0eb39ce..0000000
--- a/src/main/java/com/ComNCheck/ComNCheck/domain/testController/MyController.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.ComNCheck.ComNCheck.domain.testController;
-
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-@Controller
-public class MyController {
-
- @GetMapping("/my")
- @ResponseBody
- public String myAPI() {
- return "my route";
- }
-
-
-}
diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/src/main/resources/.DS_Store differ
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index bf9002c..76acdfa 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -2,21 +2,35 @@ server:
port: 8080
spring:
- jpa:
- hibernate:
- ddl-auto: create-drop
- show-sql: true
application:
name: ComNCheck
- datasource:
- driver-class-name: org.h2.Driver
- url: ${H2_DB_URL} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode)
- username: ${DB_USERNAME}
- password: ${DB_PASSWORD}
- h2:
- console:
- enabled: true
- path: /h2-console
+ config:
+ import:
+ - classpath:/yaml/application-prod.yaml
+ - classpath:/yaml/application-log.yaml
+ profiles:
+ group:
+ setting: prod, log
+ active : setting
+
+ data:
+ redis:
+ host: ${REDIS_HOST:localhost}
+ port: ${REDIS_PORT:6379}
+ password: ${REDIS_PASSWORD}
+
+ cloud:
+ gcp:
+ storage:
+ credentials:
+ location: classpath:/gcp/ancient-pipe-447417-i4-755ce59fbf03.json
+ project-id: ${GCP_PROJECT_ID}
+ bucket: ${GCP_BUCKET_ID}
+ firestore:
+ project-id: ${FIREBASE_PROJECT_ID}
+ credentials:
+ location: classpath:/firebase/comncheck-firebase-adminsdk-fbsvc-1255c6f2ed.json
+
security:
oauth2:
client:
@@ -30,7 +44,10 @@ spring:
scope:
- email
- profile
-
jwt:
secret: ${JWT_SECRET}
- expirationMs: ${JWT_EXPIRATIONMS}
\ No newline at end of file
+ expirationMs: ${JWT_EXPIRATIONMS}
+
+target:
+ server:
+ ip: ${PROD_FASTAPI_IP}
diff --git a/src/main/resources/yaml/application-local.yaml b/src/main/resources/yaml/application-local.yaml
new file mode 100644
index 0000000..089b3b7
--- /dev/null
+++ b/src/main/resources/yaml/application-local.yaml
@@ -0,0 +1,30 @@
+#spring:
+# config:
+# activate:
+# on-profile: local
+# jpa:
+# hibernate:
+# ddl-auto: update
+# properties:
+# hibernate:
+# show_sql: true
+# format_sql: true
+# highlight_sql: true
+# datasource:
+# driver-class-name: org.h2.Driver
+# url: ${H2_DB_URL:jdbc:h2:mem:test} #url: 'jdbc:h2:~/test' -> H2 DB 연결 주소 (Embedded Mode)
+# username: ${H2_DB_USERNAME}
+# password: ${H2_DB_PASSWORD}
+# h2:
+# console:
+# enabled: true
+# path: /h2-console
+# settings:
+# web-allow-others: true
+#
+#logging.level:
+# org.hibernate:
+# type: trace
+# orm:
+# jdbc:
+# bind: trace
diff --git a/src/main/resources/yaml/application-log.yaml b/src/main/resources/yaml/application-log.yaml
new file mode 100644
index 0000000..d96612c
--- /dev/null
+++ b/src/main/resources/yaml/application-log.yaml
@@ -0,0 +1,19 @@
+spring:
+ config:
+ activate:
+ on-profile: log
+ jpa:
+ hibernate:
+ ddl-auto: none
+ properties:
+ hibernate:
+ show_sql: true
+ format_sql: true
+ highlight_sql: true
+
+logging.level:
+ org.hibernate:
+ type: trace
+ orm:
+ jdbc:
+ bind: trace
\ No newline at end of file
diff --git a/src/main/resources/yaml/application-prod.yaml b/src/main/resources/yaml/application-prod.yaml
new file mode 100644
index 0000000..9a40706
--- /dev/null
+++ b/src/main/resources/yaml/application-prod.yaml
@@ -0,0 +1,10 @@
+spring:
+ config:
+ activate:
+ on-profile: prod
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: ${MYSQL_URL}
+ username: ${MYSQL_USERNAME}
+ password: ${MYSQL_PASSWORD}
+