Compare commits
32 Commits
4aa3375f57
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b27f92bbf | ||
|
|
3bd836e5d8 | ||
|
|
630fa76786 | ||
| 1f0874cbc3 | |||
|
|
62daf51e57 | ||
| f5cd4aa873 | |||
|
|
6f707dcacd | ||
|
|
6d903dea2c | ||
|
|
be3ff66110 | ||
| 6ac9689693 | |||
| a1e3d41dcd | |||
| 6183ae350e | |||
| 0b996c5941 | |||
| 979547d2ce | |||
|
|
5c3b867888 | ||
| fc4770679c | |||
| 235ee5e29b | |||
| 4248a9a0a3 | |||
| 31d3402db8 | |||
| 3ddc8bc76e | |||
| 6dfc8279a8 | |||
| f6f6be31ea | |||
| 1b150af17d | |||
|
|
64d355507e | ||
|
|
50e0a007a3 | ||
| 29f8596f2b | |||
|
|
e62d7a3f1c | ||
|
|
4be71e53ec | ||
| 2b01629d12 | |||
| c640bef2b9 | |||
|
|
8687f009df | ||
|
|
fe0db8e701 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -39,6 +39,7 @@ jacoco.exec
|
|||||||
.classpath
|
.classpath
|
||||||
.settings/
|
.settings/
|
||||||
bin/
|
bin/
|
||||||
|
.metadata/
|
||||||
|
|
||||||
# Temporary files created by the OS
|
# Temporary files created by the OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# --- build stage ---
|
||||||
|
FROM gradle:8.10.2-jdk17-alpine AS build
|
||||||
|
WORKDIR /workspace
|
||||||
|
COPY . .
|
||||||
|
# 테스트는 생략(필요시 제거)
|
||||||
|
RUN ./gradlew --no-daemon clean bootJar -x test
|
||||||
|
|
||||||
|
# --- run stage ---
|
||||||
|
FROM eclipse-temurin:17-jre-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime
|
||||||
|
# 로그 디렉터리 생성 및 권한 설정
|
||||||
|
RUN mkdir -p /app/logs && chown -R 1000:1000 /app
|
||||||
|
RUN addgroup -S app && adduser -S app -G app -u 1000
|
||||||
|
USER app
|
||||||
|
COPY --from=build /workspace/build/libs/*.jar /app/app.jar
|
||||||
|
EXPOSE 8080
|
||||||
|
ENV JAVA_OPTS="-Xms256m -Xmx512m"
|
||||||
|
ENTRYPOINT ["sh","-c","java $JAVA_OPTS -jar /app/app.jar"]
|
||||||
36
README.md
36
README.md
@@ -10,6 +10,28 @@
|
|||||||
- **Container**: Docker + Kubernetes
|
- **Container**: Docker + Kubernetes
|
||||||
- **API Documentation**: Swagger (SpringDoc OpenAPI)
|
- **API Documentation**: Swagger (SpringDoc OpenAPI)
|
||||||
|
|
||||||
|
## 개발 환경 설정
|
||||||
|
|
||||||
|
### Eclipse/STS 사용 시 필수 설정
|
||||||
|
|
||||||
|
**Annotation Processing 설정이 필요합니다.**
|
||||||
|
|
||||||
|
STS에서 프로젝트를 열었을 때 컴파일 오류가 발생하는 경우, 다음 설정을 확인하세요:
|
||||||
|
|
||||||
|
1. **프로젝트 우클릭** → **Properties** 선택
|
||||||
|
2. **Java Compiler** → **Annotation Processing** 선택
|
||||||
|
3. 다음 설정을 확인/적용:
|
||||||
|
- **Enable project specific settings** 체크
|
||||||
|
- **Enable annotation processing** 체크
|
||||||
|
- **Enable processing in editor** 체크 해제 (선택사항)
|
||||||
|
- **Generated source directory**: `build/generated/sources/annotationProcessor/java/main`
|
||||||
|
- **Generated test source directory**: `build/generated/sources/annotationProcessor/java/test`
|
||||||
|
|
||||||
|
**설정 이유:**
|
||||||
|
- MapStruct 매퍼 인터페이스의 구현체가 자동 생성됩니다
|
||||||
|
- QueryDSL Q클래스들이 자동 생성됩니다
|
||||||
|
- 이 설정이 없으면 컴파일 오류가 발생할 수 있습니다
|
||||||
|
|
||||||
## 개발 가이드
|
## 개발 가이드
|
||||||
|
|
||||||
### 1. 프로젝트 구조
|
### 1. 프로젝트 구조
|
||||||
@@ -66,7 +88,7 @@ public class ApiResponseDto<T> {
|
|||||||
"success": true,
|
"success": true,
|
||||||
"code": 201,
|
"code": 201,
|
||||||
"message": "COMMON_SUCCESS_CREATED",
|
"message": "COMMON_SUCCESS_CREATED",
|
||||||
"description": "Created successfully",
|
"description": "성공적으로 생성되었습니다",
|
||||||
"data": {
|
"data": {
|
||||||
"seq": 1,
|
"seq": 1,
|
||||||
"userId": "user123",
|
"userId": "user123",
|
||||||
@@ -82,7 +104,7 @@ public class ApiResponseDto<T> {
|
|||||||
"success": false,
|
"success": false,
|
||||||
"code": 409,
|
"code": 409,
|
||||||
"message": "USER_ID_DUPLICATE",
|
"message": "USER_ID_DUPLICATE",
|
||||||
"description": "User ID already exists"
|
"description": "이미 존재하는 사용자 ID입니다"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -142,8 +164,8 @@ public enum ApiResponseCode {
|
|||||||
|
|
||||||
#### 토큰 구성
|
#### 토큰 구성
|
||||||
|
|
||||||
- **Access Token**: 15분 (900,000ms) - API 요청 시 사용
|
- **Access Token** - 쿠키에 저장, 자동 갱신
|
||||||
- **Refresh Token**: 7일 (604,800,000ms) - 쿠키에 저장, 자동 갱신
|
- **Refresh Token** - 쿠키에 저장, 자동 갱신
|
||||||
|
|
||||||
#### 자동 토큰 갱신
|
#### 자동 토큰 갱신
|
||||||
|
|
||||||
@@ -189,10 +211,8 @@ public enum ApiResponseCode {
|
|||||||
@Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
|
@Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
|
||||||
@ApiResponses(value = {
|
@ApiResponses(value = {
|
||||||
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터",
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보", content = @Content)
|
||||||
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
13
build.gradle
13
build.gradle
@@ -62,7 +62,7 @@ dependencies {
|
|||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
|
|
||||||
// querydsl
|
// QueryDSL
|
||||||
implementation 'io.github.openfeign.querydsl:querydsl-jpa:6.11'
|
implementation 'io.github.openfeign.querydsl:querydsl-jpa:6.11'
|
||||||
annotationProcessor 'io.github.openfeign.querydsl:querydsl-apt:6.11:jpa'
|
annotationProcessor 'io.github.openfeign.querydsl:querydsl-apt:6.11:jpa'
|
||||||
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
|
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
|
||||||
@@ -83,13 +83,16 @@ tasks.named('test') {
|
|||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
// querydsl
|
// annotationProcessor(QueryDSL, MapStruct)
|
||||||
def generatedSrcDir = 'build/generated/sources/annotation-processor'
|
// * Annotation Processing 설정이 필요한경우 "build/generated/sources/annotationProcessor/java/main" 경로 등록
|
||||||
|
def generatedSrcDir = layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main").get().asFile
|
||||||
|
|
||||||
clean {
|
clean {
|
||||||
delete file(generatedSrcDir)
|
delete file(generatedSrcDir)
|
||||||
}
|
}
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
options.generatedSourceOutputDirectory = file(generatedSrcDir)
|
options.annotationProcessorGeneratedSourcesDirectory = file(generatedSrcDir)
|
||||||
|
options.encoding = 'UTF-8'
|
||||||
}
|
}
|
||||||
|
|
||||||
jib {
|
jib {
|
||||||
@@ -98,7 +101,7 @@ jib {
|
|||||||
// (선택) 인증서 추가/회사 CA 필요 시 extraDirectories 사용
|
// (선택) 인증서 추가/회사 CA 필요 시 extraDirectories 사용
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
image = 'demo.stam.kr/leejisun9/bio-backend'; tags = ['1.0.0'] // 기본 대상 레지스트리
|
image = 'demo.stam.kr/leejisun9/bio-backend'; //tags = ['1.0.0'] // 기본 대상 레지스트리
|
||||||
// tags는 skaffold가 자동 주입. 로컬 단독 빌드시 -Djib.to.tags=로 지정 가능
|
// tags는 skaffold가 자동 주입. 로컬 단독 빌드시 -Djib.to.tags=로 지정 가능
|
||||||
}
|
}
|
||||||
container {
|
container {
|
||||||
|
|||||||
@@ -1,4 +1,80 @@
|
|||||||
|
|
||||||
|
create table st_auth_group (
|
||||||
|
created_at timestamp(6) not null,
|
||||||
|
created_oid bigint,
|
||||||
|
oid bigint not null,
|
||||||
|
updated_at timestamp(6) not null,
|
||||||
|
updated_oid bigint,
|
||||||
|
name varchar(100),
|
||||||
|
created_id varchar(255),
|
||||||
|
updated_id varchar(255),
|
||||||
|
primary key (oid)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on column st_auth_group.created_at is
|
||||||
|
'생성일시';
|
||||||
|
|
||||||
|
comment on column st_auth_group.created_oid is
|
||||||
|
'생성자 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group.oid is
|
||||||
|
'OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group.updated_at is
|
||||||
|
'수정일시';
|
||||||
|
|
||||||
|
comment on column st_auth_group.updated_oid is
|
||||||
|
'수정자 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group.name is
|
||||||
|
'권한 그룹명';
|
||||||
|
|
||||||
|
comment on column st_auth_group.created_id is
|
||||||
|
'생성자 ID';
|
||||||
|
|
||||||
|
comment on column st_auth_group.updated_id is
|
||||||
|
'수정자 ID';
|
||||||
|
|
||||||
|
create table st_auth_group_resource (
|
||||||
|
auth_group_oid bigint,
|
||||||
|
created_at timestamp(6) not null,
|
||||||
|
created_oid bigint,
|
||||||
|
oid bigint not null,
|
||||||
|
resource_oid bigint,
|
||||||
|
updated_at timestamp(6) not null,
|
||||||
|
updated_oid bigint,
|
||||||
|
created_id varchar(255),
|
||||||
|
updated_id varchar(255),
|
||||||
|
primary key (oid)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.auth_group_oid is
|
||||||
|
'권한 그룹 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.created_at is
|
||||||
|
'생성일시';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.created_oid is
|
||||||
|
'생성자 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.oid is
|
||||||
|
'OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.resource_oid is
|
||||||
|
'리소스 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.updated_at is
|
||||||
|
'수정일시';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.updated_oid is
|
||||||
|
'수정자 OID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.created_id is
|
||||||
|
'생성자 ID';
|
||||||
|
|
||||||
|
comment on column st_auth_group_resource.updated_id is
|
||||||
|
'수정자 ID';
|
||||||
|
|
||||||
create table st_common_code (
|
create table st_common_code (
|
||||||
sort_order integer not null,
|
sort_order integer not null,
|
||||||
use_flag boolean not null,
|
use_flag boolean not null,
|
||||||
@@ -275,6 +351,110 @@
|
|||||||
comment on column st_member.updated_id is
|
comment on column st_member.updated_id is
|
||||||
'수정자 ID';
|
'수정자 ID';
|
||||||
|
|
||||||
|
create table st_member_auth_group (
|
||||||
|
auth_group_oid bigint,
|
||||||
|
created_at timestamp(6) not null,
|
||||||
|
created_oid bigint,
|
||||||
|
member_oid bigint,
|
||||||
|
oid bigint not null,
|
||||||
|
updated_at timestamp(6) not null,
|
||||||
|
updated_oid bigint,
|
||||||
|
created_id varchar(255),
|
||||||
|
updated_id varchar(255),
|
||||||
|
primary key (oid)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.auth_group_oid is
|
||||||
|
'권한 그룹 OID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.created_at is
|
||||||
|
'생성일시';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.created_oid is
|
||||||
|
'생성자 OID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.member_oid is
|
||||||
|
'사용자 OID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.oid is
|
||||||
|
'OID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.updated_at is
|
||||||
|
'수정일시';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.updated_oid is
|
||||||
|
'수정자 OID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.created_id is
|
||||||
|
'생성자 ID';
|
||||||
|
|
||||||
|
comment on column st_member_auth_group.updated_id is
|
||||||
|
'수정자 ID';
|
||||||
|
|
||||||
|
create table st_resource (
|
||||||
|
menu_yn boolean,
|
||||||
|
sort_order integer,
|
||||||
|
created_at timestamp(6) not null,
|
||||||
|
created_oid bigint,
|
||||||
|
oid bigint not null,
|
||||||
|
parent_code bigint,
|
||||||
|
updated_at timestamp(6) not null,
|
||||||
|
updated_oid bigint,
|
||||||
|
type varchar(50),
|
||||||
|
code varchar(100),
|
||||||
|
name varchar(100),
|
||||||
|
path varchar(100),
|
||||||
|
created_id varchar(255),
|
||||||
|
description varchar(255),
|
||||||
|
updated_id varchar(255),
|
||||||
|
primary key (oid)
|
||||||
|
);
|
||||||
|
|
||||||
|
comment on column st_resource.menu_yn is
|
||||||
|
'메뉴여부';
|
||||||
|
|
||||||
|
comment on column st_resource.sort_order is
|
||||||
|
'정렬 순서';
|
||||||
|
|
||||||
|
comment on column st_resource.created_at is
|
||||||
|
'생성일시';
|
||||||
|
|
||||||
|
comment on column st_resource.created_oid is
|
||||||
|
'생성자 OID';
|
||||||
|
|
||||||
|
comment on column st_resource.oid is
|
||||||
|
'OID';
|
||||||
|
|
||||||
|
comment on column st_resource.parent_code is
|
||||||
|
'부모 코드';
|
||||||
|
|
||||||
|
comment on column st_resource.updated_at is
|
||||||
|
'수정일시';
|
||||||
|
|
||||||
|
comment on column st_resource.updated_oid is
|
||||||
|
'수정자 OID';
|
||||||
|
|
||||||
|
comment on column st_resource.type is
|
||||||
|
'리소스 유형(메뉴, 페이지, 컴포넌트)';
|
||||||
|
|
||||||
|
comment on column st_resource.code is
|
||||||
|
'코드';
|
||||||
|
|
||||||
|
comment on column st_resource.name is
|
||||||
|
'리소스명';
|
||||||
|
|
||||||
|
comment on column st_resource.path is
|
||||||
|
'주소';
|
||||||
|
|
||||||
|
comment on column st_resource.created_id is
|
||||||
|
'생성자 ID';
|
||||||
|
|
||||||
|
comment on column st_resource.description is
|
||||||
|
'설명';
|
||||||
|
|
||||||
|
comment on column st_resource.updated_id is
|
||||||
|
'수정자 ID';
|
||||||
|
|
||||||
create index idx_common_code_code
|
create index idx_common_code_code
|
||||||
on st_common_code (code);
|
on st_common_code (code);
|
||||||
|
|
||||||
@@ -289,3 +469,23 @@
|
|||||||
|
|
||||||
create index idx_member_user_id
|
create index idx_member_user_id
|
||||||
on st_member (user_id);
|
on st_member (user_id);
|
||||||
|
|
||||||
|
alter table if exists st_auth_group_resource
|
||||||
|
add constraint FKqw6aih072qipjh1r88f0dbfd6
|
||||||
|
foreign key (auth_group_oid)
|
||||||
|
references st_auth_group;
|
||||||
|
|
||||||
|
alter table if exists st_auth_group_resource
|
||||||
|
add constraint FKrvq0ta0bwef2kt6ahklo7f3k4
|
||||||
|
foreign key (resource_oid)
|
||||||
|
references st_resource;
|
||||||
|
|
||||||
|
alter table if exists st_member_auth_group
|
||||||
|
add constraint FKob027cxsjfyvewjb8xp6hjkbm
|
||||||
|
foreign key (auth_group_oid)
|
||||||
|
references st_auth_group;
|
||||||
|
|
||||||
|
alter table if exists st_member_auth_group
|
||||||
|
add constraint FKqew1t81hap15dmn78p8xhunhj
|
||||||
|
foreign key (member_oid)
|
||||||
|
references st_member;
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
distributionUrl=http\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
Binary file not shown.
BIN
jpa-curd.zip
Normal file
BIN
jpa-curd.zip
Normal file
Binary file not shown.
51
nginx-1.28.0/conf/nginx_docker_bak.conf
Normal file
51
nginx-1.28.0/conf/nginx_docker_bak.conf
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
|
||||||
|
include mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
# (선택) 로그 위치
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
|
||||||
|
# 웹소켓용
|
||||||
|
map $http_upgrade $connection_upgrade {
|
||||||
|
default upgrade;
|
||||||
|
'' close;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
# Nuxt(개발서버 3000)
|
||||||
|
location / {
|
||||||
|
proxy_pass http://frontend:3000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Spring Boot(8080)
|
||||||
|
location /service/ {
|
||||||
|
proxy_pass http://backend:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
# (선택) 업로드 크게 받을 때
|
||||||
|
# client_max_body_size 50m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,8 +38,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "그룹 코드 생성", description = "새로운 그룹 코드를 생성합니다.")
|
@Operation(summary = "그룹 코드 생성", description = "새로운 그룹 코드를 생성합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "201", description = "그룹 코드 생성 성공"),
|
@ApiResponse(responseCode = "201", description = "그룹 코드 생성 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "409", description = "중복된 그룹 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "409", description = "중복된 그룹 코드", content = @Content)
|
||||||
})
|
})
|
||||||
@PostMapping("/group")
|
@PostMapping("/group")
|
||||||
public ResponseEntity<ApiResponseDto<CreateCommonGroupCodeResponseDto>> createGroupCode(@RequestBody @Valid CreateCommonGroupCodeRequestDto requestDto) {
|
public ResponseEntity<ApiResponseDto<CreateCommonGroupCodeResponseDto>> createGroupCode(@RequestBody @Valid CreateCommonGroupCodeRequestDto requestDto) {
|
||||||
@@ -55,8 +55,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "그룹 코드 수정", description = "기존 그룹 코드를 수정합니다.")
|
@Operation(summary = "그룹 코드 수정", description = "기존 그룹 코드를 수정합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "그룹 코드 수정 성공"),
|
@ApiResponse(responseCode = "200", description = "그룹 코드 수정 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@PutMapping("/group/{code}")
|
@PutMapping("/group/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<String>> updateGroupCode(
|
public ResponseEntity<ApiResponseDto<String>> updateGroupCode(
|
||||||
@@ -71,8 +71,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "그룹 코드 삭제", description = "그룹 코드를 삭제합니다.")
|
@Operation(summary = "그룹 코드 삭제", description = "그룹 코드를 삭제합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "그룹 코드 삭제 성공"),
|
@ApiResponse(responseCode = "200", description = "그룹 코드 삭제 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content),
|
||||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@DeleteMapping("/group/{code}")
|
@DeleteMapping("/group/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<Void>> deleteGroupCode(@PathVariable String code) {
|
public ResponseEntity<ApiResponseDto<Void>> deleteGroupCode(@PathVariable String code) {
|
||||||
@@ -84,7 +84,7 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "그룹 코드 조회", description = "특정 그룹 코드를 조회합니다.")
|
@Operation(summary = "그룹 코드 조회", description = "특정 그룹 코드를 조회합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "그룹 코드 조회 성공"),
|
@ApiResponse(responseCode = "200", description = "그룹 코드 조회 성공"),
|
||||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@GetMapping("/group/{code}")
|
@GetMapping("/group/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<CommonGroupCodeDto>> getGroupCode(@PathVariable String code) {
|
public ResponseEntity<ApiResponseDto<CommonGroupCodeDto>> getGroupCode(@PathVariable String code) {
|
||||||
@@ -119,8 +119,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "공통 코드 생성", description = "새로운 공통 코드를 생성합니다.")
|
@Operation(summary = "공통 코드 생성", description = "새로운 공통 코드를 생성합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "201", description = "공통 코드 생성 성공"),
|
@ApiResponse(responseCode = "201", description = "공통 코드 생성 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "409", description = "중복된 공통 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "409", description = "중복된 공통 코드", content = @Content)
|
||||||
})
|
})
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<ApiResponseDto<CreateCommonCodeResponseDto>> createCode(@RequestBody @Valid CreateCommonCodeRequestDto requestDto) {
|
public ResponseEntity<ApiResponseDto<CreateCommonCodeResponseDto>> createCode(@RequestBody @Valid CreateCommonCodeRequestDto requestDto) {
|
||||||
@@ -136,8 +136,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "공통 코드 수정", description = "기존 공통 코드를 수정합니다.")
|
@Operation(summary = "공통 코드 수정", description = "기존 공통 코드를 수정합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "공통 코드 수정 성공"),
|
@ApiResponse(responseCode = "200", description = "공통 코드 수정 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@PutMapping("/{code}")
|
@PutMapping("/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<String>> updateCode(
|
public ResponseEntity<ApiResponseDto<String>> updateCode(
|
||||||
@@ -152,8 +152,8 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "공통 코드 삭제", description = "공통 코드를 삭제합니다.")
|
@Operation(summary = "공통 코드 삭제", description = "공통 코드를 삭제합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "공통 코드 삭제 성공"),
|
@ApiResponse(responseCode = "200", description = "공통 코드 삭제 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content),
|
||||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@DeleteMapping("/{code}")
|
@DeleteMapping("/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<Void>> deleteCode(@PathVariable String code) {
|
public ResponseEntity<ApiResponseDto<Void>> deleteCode(@PathVariable String code) {
|
||||||
@@ -165,7 +165,7 @@ public class CommonCodeController {
|
|||||||
@Operation(summary = "공통 코드 조회", description = "특정 공통 코드를 조회합니다.")
|
@Operation(summary = "공통 코드 조회", description = "특정 공통 코드를 조회합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "공통 코드 조회 성공"),
|
@ApiResponse(responseCode = "200", description = "공통 코드 조회 성공"),
|
||||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content)
|
||||||
})
|
})
|
||||||
@GetMapping("/{code}")
|
@GetMapping("/{code}")
|
||||||
public ResponseEntity<ApiResponseDto<GetCommonCodeResponseDto>> getCode(@PathVariable String code) {
|
public ResponseEntity<ApiResponseDto<GetCommonCodeResponseDto>> getCode(@PathVariable String code) {
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ import org.springframework.stereotype.Repository;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
|
||||||
* QueryDSL을 활용하여 CommonCodeRepositoryCustom 인터페이스를 구현하는 클래스
|
|
||||||
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
|
||||||
*/
|
|
||||||
@Repository
|
@Repository
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom {
|
public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom {
|
||||||
@@ -25,10 +21,6 @@ public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom {
|
|||||||
private final JPAQueryFactory queryFactory;
|
private final JPAQueryFactory queryFactory;
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
|
|
||||||
/**
|
|
||||||
* Q클래스 인스턴스들을 생성하여 쿼리에서 사용합니다.
|
|
||||||
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
|
||||||
*/
|
|
||||||
private final QCommonCode commonCode = QCommonCode.commonCode;
|
private final QCommonCode commonCode = QCommonCode.commonCode;
|
||||||
private final QCommonGroupCode commonGroupCode = QCommonGroupCode.commonGroupCode;
|
private final QCommonGroupCode commonGroupCode = QCommonGroupCode.commonGroupCode;
|
||||||
private final QMember member = QMember.member;
|
private final QMember member = QMember.member;
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.controller;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.dto.AuthGroupDto;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.service.AuthGroupService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/auth_group")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "AuthGroup", description = "")
|
||||||
|
@Slf4j
|
||||||
|
public class AuthGroupController {
|
||||||
|
|
||||||
|
private final AuthGroupService authGroupService;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
public AuthGroupDto create(@RequestBody AuthGroupDto authGroupDto) {
|
||||||
|
return authGroupService.create(authGroupDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public AuthGroupDto getById(@PathVariable Long id) {
|
||||||
|
return authGroupService.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<AuthGroupDto> getAll() {
|
||||||
|
return authGroupService.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public AuthGroupDto update(@PathVariable Long id, @RequestBody AuthGroupDto dto) {
|
||||||
|
return authGroupService.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public void delete(@PathVariable Long id) {
|
||||||
|
authGroupService.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AuthGroupDto {
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.entity;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.constants.AppConstants;
|
||||||
|
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table(name = AppConstants.TABLE_PREFIX + "auth_group")
|
||||||
|
public class AuthGroup extends BaseEntity {
|
||||||
|
|
||||||
|
@Column(name = "name", length = 100)
|
||||||
|
@Comment("권한 그룹명")
|
||||||
|
private String name;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.mapper;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.dto.AuthGroupDto;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(config = GlobalMapperConfig.class)
|
||||||
|
public interface AuthGroupMapper {
|
||||||
|
AuthGroup toEntity(AuthGroupDto dto);
|
||||||
|
|
||||||
|
AuthGroupDto toDto(AuthGroup entity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AuthGroupRepository extends JpaRepository<AuthGroup, Long>, AuthGroupRepositoryCustom {
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||||
|
*/
|
||||||
|
public interface AuthGroupRepositoryCustom {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.QAuthGroup;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용하여 AuthGroupRepositoryCustom 인터페이스를 구현하는 클래스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthGroupRepositoryImpl implements AuthGroupRepositoryCustom {
|
||||||
|
|
||||||
|
private final JPAQueryFactory queryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QAuthGroup 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||||
|
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||||
|
*/
|
||||||
|
private final QAuthGroup authGroup = QAuthGroup.authGroup;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.dto.AuthGroupDto;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AuthGroupService {
|
||||||
|
AuthGroupDto create(AuthGroupDto dto);
|
||||||
|
|
||||||
|
AuthGroupDto getById(Long id);
|
||||||
|
|
||||||
|
List<AuthGroupDto> getAll();
|
||||||
|
|
||||||
|
AuthGroupDto update(Long id, AuthGroupDto dto);
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroup.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.dto.AuthGroupDto;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.repository.AuthGroupRepository;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.mapper.AuthGroupMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class AuthGroupServiceImpl implements AuthGroupService {
|
||||||
|
|
||||||
|
private final AuthGroupRepository repository;
|
||||||
|
private final AuthGroupMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public AuthGroupDto create(AuthGroupDto dto) {
|
||||||
|
AuthGroup entity = mapper.toEntity(dto);
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthGroupDto getById(Long id) {
|
||||||
|
return repository.findById(id).map(mapper::toDto).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AuthGroupDto> getAll() {
|
||||||
|
return repository.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public AuthGroupDto update(Long id, AuthGroupDto dto) {
|
||||||
|
AuthGroup entity = repository.findById(id).orElseThrow();
|
||||||
|
// TODO: update fields
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.controller;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.dto.AuthGroupResourceDto;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.dto.ReplaceAuthGroupResourcesRequest;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.service.AuthGroupResourceService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/auth_group_resource")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "AuthGroupResource", description = "")
|
||||||
|
@Slf4j
|
||||||
|
public class AuthGroupResourceController {
|
||||||
|
|
||||||
|
private final AuthGroupResourceService service;
|
||||||
|
|
||||||
|
@PostMapping("/create")
|
||||||
|
public AuthGroupResourceDto create(@RequestBody AuthGroupResourceDto dto) {
|
||||||
|
return service.create(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public AuthGroupResourceDto getById(@PathVariable Long id) {
|
||||||
|
return service.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<AuthGroupResourceDto> getAll() {
|
||||||
|
return service.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public AuthGroupResourceDto update(@PathVariable Long id, @RequestBody AuthGroupResourceDto dto) {
|
||||||
|
return service.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public void delete(@PathVariable Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/replace")
|
||||||
|
public void replaceAuthGroupResources(@RequestBody ReplaceAuthGroupResourcesRequest request) {
|
||||||
|
service.replaceAuthGroupResources(request.getAuthGroupOid(), request.getResourceOids());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.dto;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AuthGroupResourceDto {
|
||||||
|
private AuthGroup authGroupOid;
|
||||||
|
private Resource resourceOid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ReplaceAuthGroupResourcesRequest {
|
||||||
|
private Long authGroupOid;
|
||||||
|
private List<Long> resourceOids;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.entity;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
import com.bio.bio_backend.global.constants.AppConstants;
|
||||||
|
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table(name = AppConstants.TABLE_PREFIX + "auth_group_resource")
|
||||||
|
|
||||||
|
public class AuthGroupResource extends BaseEntity {
|
||||||
|
|
||||||
|
@JoinColumn(name = "auth_group_oid")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@Comment("권한 그룹 OID")
|
||||||
|
private AuthGroup authGroupOid;
|
||||||
|
|
||||||
|
@JoinColumn(name = "resource_oid")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@Comment("리소스 OID")
|
||||||
|
private Resource resourceOid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.mapper;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.AuthGroupResource;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.dto.AuthGroupResourceDto;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(config = GlobalMapperConfig.class)
|
||||||
|
public interface AuthGroupResourceMapper {
|
||||||
|
AuthGroupResource toEntity(AuthGroupResourceDto dto);
|
||||||
|
|
||||||
|
AuthGroupResourceDto toDto(AuthGroupResource entity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.AuthGroupResource;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AuthGroupResourceRepository
|
||||||
|
extends JpaRepository<AuthGroupResource, Long>, AuthGroupResourceRepositoryCustom {
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("delete from AuthGroupResource agr where agr.authGroupOid.oid = :authGroupOid")
|
||||||
|
void deleteByAuthGroupOid(@Param("authGroupOid") Long authGroupOid);
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.AuthGroupResource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||||
|
*/
|
||||||
|
public interface AuthGroupResourceRepositoryCustom {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.AuthGroupResource;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.QAuthGroupResource;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용하여 AuthGroupResourceRepositoryCustom 인터페이스를 구현하는 클래스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthGroupResourceRepositoryImpl implements AuthGroupResourceRepositoryCustom {
|
||||||
|
|
||||||
|
private final JPAQueryFactory queryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QAuthGroupResource 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||||
|
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||||
|
*/
|
||||||
|
private final QAuthGroupResource authGroupResource = QAuthGroupResource.authGroupResource;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.dto.AuthGroupResourceDto;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AuthGroupResourceService {
|
||||||
|
AuthGroupResourceDto create(AuthGroupResourceDto dto);
|
||||||
|
|
||||||
|
AuthGroupResourceDto getById(Long id);
|
||||||
|
|
||||||
|
List<AuthGroupResourceDto> getAll();
|
||||||
|
|
||||||
|
AuthGroupResourceDto update(Long id, AuthGroupResourceDto dto);
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 authGroupOid의 기존 매핑을 모두 삭제하고, 전달된 resourceOid 목록으로 재등록
|
||||||
|
*/
|
||||||
|
void replaceAuthGroupResources(Long authGroupOid, List<Long> resourceOids);
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.authgroupresource.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.dto.AuthGroupResourceDto;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.AuthGroupResource;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.repository.AuthGroupResourceRepository;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.mapper.AuthGroupResourceMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class AuthGroupResourceServiceImpl implements AuthGroupResourceService {
|
||||||
|
|
||||||
|
private final AuthGroupResourceRepository repository;
|
||||||
|
private final AuthGroupResourceMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public AuthGroupResourceDto create(AuthGroupResourceDto dto) {
|
||||||
|
AuthGroupResource entity = mapper.toEntity(dto);
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthGroupResourceDto getById(Long id) {
|
||||||
|
return repository.findById(id).map(mapper::toDto).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AuthGroupResourceDto> getAll() {
|
||||||
|
return repository.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public AuthGroupResourceDto update(Long id, AuthGroupResourceDto dto) {
|
||||||
|
AuthGroupResource entity = repository.findById(id).orElseThrow();
|
||||||
|
// TODO: update fields
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void replaceAuthGroupResources(Long authGroupOid, List<Long> resourceOids) {
|
||||||
|
repository.deleteByAuthGroupOid(authGroupOid);
|
||||||
|
|
||||||
|
if (resourceOids == null || resourceOids.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthGroup groupRef = new AuthGroup();
|
||||||
|
groupRef.setOid(authGroupOid);
|
||||||
|
|
||||||
|
for (Long resourceOid : resourceOids) {
|
||||||
|
Resource resourceRef = new Resource();
|
||||||
|
resourceRef.setOid(resourceOid);
|
||||||
|
|
||||||
|
AuthGroupResource entity = AuthGroupResource.builder()
|
||||||
|
.authGroupOid(groupRef)
|
||||||
|
.resourceOid(resourceRef)
|
||||||
|
.build();
|
||||||
|
repository.save(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,8 +37,8 @@ public class FileController {
|
|||||||
@Operation(summary = "파일 업로드", description = "단일 파일을 업로드합니다.")
|
@Operation(summary = "파일 업로드", description = "단일 파일을 업로드합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "파일 업로드 성공"),
|
@ApiResponse(responseCode = "200", description = "파일 업로드 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "500", description = "파일 업로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "500", description = "파일 업로드 실패", content = @Content)
|
||||||
})
|
})
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public ResponseEntity<ApiResponseDto<FileUploadResponseDto>> uploadFile(
|
public ResponseEntity<ApiResponseDto<FileUploadResponseDto>> uploadFile(
|
||||||
@@ -53,8 +53,8 @@ public class FileController {
|
|||||||
@Operation(summary = "다중 파일 업로드", description = "여러 파일을 동시에 업로드합니다.")
|
@Operation(summary = "다중 파일 업로드", description = "여러 파일을 동시에 업로드합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "다중 파일 업로드 성공"),
|
@ApiResponse(responseCode = "200", description = "다중 파일 업로드 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "500", description = "다중 파일 업로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "500", description = "다중 파일 업로드 실패", content = @Content)
|
||||||
})
|
})
|
||||||
@PostMapping("/upload-multiple")
|
@PostMapping("/upload-multiple")
|
||||||
public ResponseEntity<ApiResponseDto<MultipleFileUploadResponseDto>> uploadMultipleFiles(
|
public ResponseEntity<ApiResponseDto<MultipleFileUploadResponseDto>> uploadMultipleFiles(
|
||||||
@@ -69,8 +69,8 @@ public class FileController {
|
|||||||
@Operation(summary = "파일 다운로드", description = "파일 ID로 파일을 다운로드합니다.")
|
@Operation(summary = "파일 다운로드", description = "파일 ID로 파일을 다운로드합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "파일 다운로드 성공"),
|
@ApiResponse(responseCode = "200", description = "파일 다운로드 성공"),
|
||||||
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content),
|
||||||
@ApiResponse(responseCode = "500", description = "파일 다운로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "500", description = "파일 다운로드 실패", content = @Content)
|
||||||
})
|
})
|
||||||
@GetMapping("/download/{oid}")
|
@GetMapping("/download/{oid}")
|
||||||
public ResponseEntity<ByteArrayResource> downloadFile(@PathVariable Long oid) {
|
public ResponseEntity<ByteArrayResource> downloadFile(@PathVariable Long oid) {
|
||||||
@@ -90,8 +90,8 @@ public class FileController {
|
|||||||
@Operation(summary = "파일 논리적 삭제", description = "파일 ID로 파일을 논리적으로 삭제합니다. (use_flag를 false로 변경)")
|
@Operation(summary = "파일 논리적 삭제", description = "파일 ID로 파일을 논리적으로 삭제합니다. (use_flag를 false로 변경)")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "파일 논리적 삭제 성공"),
|
@ApiResponse(responseCode = "200", description = "파일 논리적 삭제 성공"),
|
||||||
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content),
|
||||||
@ApiResponse(responseCode = "500", description = "파일 논리적 삭제 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "500", description = "파일 논리적 삭제 실패", content = @Content)
|
||||||
})
|
})
|
||||||
@DeleteMapping("/{oid}")
|
@DeleteMapping("/{oid}")
|
||||||
public ResponseEntity<ApiResponseDto<Void>> deleteFile(@PathVariable Long oid) {
|
public ResponseEntity<ApiResponseDto<Void>> deleteFile(@PathVariable Long oid) {
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ public class MemberController {
|
|||||||
@Operation(summary = "회원 등록", description = "새로운 회원을 등록합니다.")
|
@Operation(summary = "회원 등록", description = "새로운 회원을 등록합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
|
||||||
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보", content = @Content)
|
||||||
})
|
})
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody @Valid CreateMemberRequestDto requestDto) {
|
public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody @Valid CreateMemberRequestDto requestDto) {
|
||||||
@@ -66,7 +66,7 @@ public class MemberController {
|
|||||||
@Operation(summary = "회원 목록 조회", description = "활성화된 모든 회원의 목록을 조회합니다.")
|
@Operation(summary = "회원 목록 조회", description = "활성화된 모든 회원의 목록을 조회합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content)
|
||||||
})
|
})
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity<ApiResponseDto<List<GetMemberResponseDto>>> getMembers(@ModelAttribute GetMembersRequestDto requestDto) {
|
public ResponseEntity<ApiResponseDto<List<GetMemberResponseDto>>> getMembers(@ModelAttribute GetMembersRequestDto requestDto) {
|
||||||
@@ -82,7 +82,7 @@ public class MemberController {
|
|||||||
@Operation(summary = "회원 목록 조회 (페이지네이션)", description = "페이지네이션을 적용한 회원 목록을 조회합니다.")
|
@Operation(summary = "회원 목록 조회 (페이지네이션)", description = "페이지네이션을 적용한 회원 목록을 조회합니다.")
|
||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
@ApiResponse(responseCode = "200", description = "회원 목록 조회 성공"),
|
||||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터", content = @Content)
|
||||||
})
|
})
|
||||||
@GetMapping("/paged")
|
@GetMapping("/paged")
|
||||||
public ResponseEntity<ApiResponseDto<PagedResult<GetMemberResponseDto>>> getMembersPaged(@ModelAttribute GetMembersPagedRequestDto requestDto) {
|
public ResponseEntity<ApiResponseDto<PagedResult<GetMemberResponseDto>>> getMembersPaged(@ModelAttribute GetMembersPagedRequestDto requestDto) {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.controller;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.dto.MemberAuthGroupDto;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.dto.ReplaceMemberAuthGroupsRequest;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.service.MemberAuthGroupService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/member_auth_group")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "MemberAuthGroup", description = "")
|
||||||
|
@Slf4j
|
||||||
|
public class MemberAuthGroupController {
|
||||||
|
|
||||||
|
private final MemberAuthGroupService service;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public MemberAuthGroupDto create(@RequestBody MemberAuthGroupDto dto) {
|
||||||
|
return service.create(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public MemberAuthGroupDto getById(@PathVariable Long id) {
|
||||||
|
return service.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<MemberAuthGroupDto> getAll() {
|
||||||
|
return service.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public MemberAuthGroupDto update(@PathVariable Long id, @RequestBody MemberAuthGroupDto dto) {
|
||||||
|
return service.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public void delete(@PathVariable Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/replace")
|
||||||
|
public void replaceMemberAuthGroups(@RequestBody ReplaceMemberAuthGroupsRequest request) {
|
||||||
|
service.replaceMemberAuthGroups(request.getMemberOid(), request.getAuthGroupOids());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.dto;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class MemberAuthGroupDto {
|
||||||
|
private Member memberOid;
|
||||||
|
private AuthGroup authGroupOid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ReplaceMemberAuthGroupsRequest {
|
||||||
|
private Long memberOid;
|
||||||
|
private List<Long> authGroupOids;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.entity;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||||
|
import com.bio.bio_backend.global.constants.AppConstants;
|
||||||
|
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table(name = AppConstants.TABLE_PREFIX + "member_auth_group")
|
||||||
|
public class MemberAuthGroup extends BaseEntity {
|
||||||
|
|
||||||
|
@Comment("사용자 OID")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "member_oid")
|
||||||
|
private Member memberOid;
|
||||||
|
|
||||||
|
@Comment("권한 그룹 OID")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "auth_group_oid")
|
||||||
|
private AuthGroup authGroupOid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.mapper;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.entity.MemberAuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.dto.MemberAuthGroupDto;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(config = GlobalMapperConfig.class)
|
||||||
|
public interface MemberAuthGroupMapper {
|
||||||
|
MemberAuthGroup toEntity(MemberAuthGroupDto dto);
|
||||||
|
|
||||||
|
MemberAuthGroupDto toDto(MemberAuthGroup entity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.entity.MemberAuthGroup;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface MemberAuthGroupRepository
|
||||||
|
extends JpaRepository<MemberAuthGroup, Long>, MemberAuthGroupRepositoryCustom {
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("delete from MemberAuthGroup mag where mag.memberOid.oid = :memberOid")
|
||||||
|
void deleteByMemberOid(@Param("memberOid") Long memberOid);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||||
|
*/
|
||||||
|
public interface MemberAuthGroupRepositoryCustom {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.entity.QMemberAuthGroup;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용하여 MemberAuthGroupRepositoryCustom 인터페이스를 구현하는 클래스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MemberAuthGroupRepositoryImpl implements MemberAuthGroupRepositoryCustom {
|
||||||
|
|
||||||
|
private final JPAQueryFactory queryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QMemberAuthGroup 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||||
|
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||||
|
*/
|
||||||
|
private final QMemberAuthGroup memberAuthGroup = QMemberAuthGroup.memberAuthGroup;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.dto.MemberAuthGroupDto;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MemberAuthGroupService {
|
||||||
|
MemberAuthGroupDto create(MemberAuthGroupDto dto);
|
||||||
|
|
||||||
|
MemberAuthGroupDto getById(Long id);
|
||||||
|
|
||||||
|
List<MemberAuthGroupDto> getAll();
|
||||||
|
|
||||||
|
MemberAuthGroupDto update(Long id, MemberAuthGroupDto dto);
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 memberOid의 기존 매핑을 모두 삭제하고, 전달된 authGroupOid 목록으로 재등록
|
||||||
|
*/
|
||||||
|
void replaceMemberAuthGroups(Long memberOid, List<Long> authGroupOids);
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.memberauthgroup.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.dto.MemberAuthGroupDto;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.entity.MemberAuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.repository.MemberAuthGroupRepository;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.mapper.MemberAuthGroupMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.AuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class MemberAuthGroupServiceImpl implements MemberAuthGroupService {
|
||||||
|
|
||||||
|
private final MemberAuthGroupRepository repository;
|
||||||
|
private final MemberAuthGroupMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public MemberAuthGroupDto create(MemberAuthGroupDto dto) {
|
||||||
|
MemberAuthGroup entity = mapper.toEntity(dto);
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberAuthGroupDto getById(Long id) {
|
||||||
|
return repository.findById(id).map(mapper::toDto).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MemberAuthGroupDto> getAll() {
|
||||||
|
return repository.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public MemberAuthGroupDto update(Long id, MemberAuthGroupDto dto) {
|
||||||
|
MemberAuthGroup entity = repository.findById(id).orElseThrow();
|
||||||
|
// TODO: update fields
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void replaceMemberAuthGroups(Long memberOid, List<Long> authGroupOids) {
|
||||||
|
repository.deleteByMemberOid(memberOid);
|
||||||
|
|
||||||
|
if (authGroupOids == null || authGroupOids.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Member memberRef = new Member();
|
||||||
|
memberRef.setOid(memberOid);
|
||||||
|
|
||||||
|
for (Long groupOid : authGroupOids) {
|
||||||
|
AuthGroup groupRef = new AuthGroup();
|
||||||
|
groupRef.setOid(groupOid);
|
||||||
|
|
||||||
|
MemberAuthGroup entity = MemberAuthGroup.builder()
|
||||||
|
.memberOid(memberRef)
|
||||||
|
.authGroupOid(groupRef)
|
||||||
|
.build();
|
||||||
|
repository.save(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.controller;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.dto.ResourceDto;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.service.ResourceService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/resource")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "Resource", description = "")
|
||||||
|
@Slf4j
|
||||||
|
public class ResourceController {
|
||||||
|
|
||||||
|
private final ResourceService service;
|
||||||
|
|
||||||
|
@PostMapping("")
|
||||||
|
public ResourceDto create(@RequestBody ResourceDto dto) {
|
||||||
|
return service.createResource(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/list")
|
||||||
|
public List<ResourceDto> createList(@RequestBody List<ResourceDto> list) {
|
||||||
|
return service.createResourceList(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResourceDto getById(@PathVariable Long id) {
|
||||||
|
return service.getById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<ResourceDto> getAll() {
|
||||||
|
return service.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResourceDto update(@PathVariable Long id, @RequestBody ResourceDto dto) {
|
||||||
|
return service.update(id, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public void delete(@PathVariable Long id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ResourceDto {
|
||||||
|
private String code;
|
||||||
|
private String name;
|
||||||
|
private long parentCode;
|
||||||
|
private String type;
|
||||||
|
private String path;
|
||||||
|
private int sortOrder;
|
||||||
|
private String description;
|
||||||
|
private boolean menuYn;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.entity;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.constants.AppConstants;
|
||||||
|
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
@Table(name = AppConstants.TABLE_PREFIX + "resource")
|
||||||
|
public class Resource extends BaseEntity {
|
||||||
|
|
||||||
|
@Column(name = "code", length = 100)
|
||||||
|
@Comment("코드")
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Column(name = "name", length = 100)
|
||||||
|
@Comment("리소스명")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "parent_code")
|
||||||
|
@Comment("부모 코드")
|
||||||
|
private long parentCode;
|
||||||
|
|
||||||
|
@Column(name = "type", length = 50)
|
||||||
|
@Comment("리소스 유형(메뉴, 페이지, 컴포넌트)")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Column(name = "path", length = 100)
|
||||||
|
@Comment("주소")
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Column(name = "sort_order")
|
||||||
|
@Comment("정렬 순서")
|
||||||
|
private int sortOrder;
|
||||||
|
|
||||||
|
@Column(name = "description", length = 255)
|
||||||
|
@Comment("설명")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "menu_yn")
|
||||||
|
@Comment("메뉴여부")
|
||||||
|
private boolean menuYn;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.mapper;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.dto.ResourceDto;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(config = GlobalMapperConfig.class)
|
||||||
|
public interface ResourceMapper {
|
||||||
|
Resource toEntity(ResourceDto dto);
|
||||||
|
|
||||||
|
ResourceDto toDto(Resource entity);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ResourceRepository extends JpaRepository<Resource, Long>, ResourceRepositoryCustom {
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||||
|
*/
|
||||||
|
public interface ResourceRepositoryCustom {
|
||||||
|
|
||||||
|
List<Resource> findResourcesByMemberId(Long memberOId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.repository;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroup.entity.QAuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.authgroupresource.entity.QAuthGroupResource;
|
||||||
|
import com.bio.bio_backend.domain.base.memberauthgroup.entity.QMemberAuthGroup;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.QResource;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QueryDSL을 활용하여 ResourceRepositoryCustom 인터페이스를 구현하는 클래스
|
||||||
|
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ResourceRepositoryImpl implements ResourceRepositoryCustom {
|
||||||
|
|
||||||
|
private final JPAQueryFactory queryFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QResource 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||||
|
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||||
|
*/
|
||||||
|
// private final QMember member = QMember.member;
|
||||||
|
private final QMemberAuthGroup memberAuthGroup = QMemberAuthGroup.memberAuthGroup;
|
||||||
|
private final QAuthGroup authGroup = QAuthGroup.authGroup;
|
||||||
|
private final QAuthGroupResource authGroupResource = QAuthGroupResource.authGroupResource;
|
||||||
|
private final QResource resource = QResource.resource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Resource> findResourcesByMemberId(Long memberOId) {
|
||||||
|
return queryFactory
|
||||||
|
.select(resource).distinct()
|
||||||
|
.from(resource)
|
||||||
|
// join(연결할 Q-Type).on(연결 조건) 형태로 명시적 조인
|
||||||
|
.join(authGroupResource).on(authGroupResource.resourceOid.eq(resource))
|
||||||
|
.join(authGroup).on(authGroupResource.authGroupOid.eq(authGroup))
|
||||||
|
.join(memberAuthGroup).on(memberAuthGroup.authGroupOid.eq(authGroup))
|
||||||
|
// 최종적으로 Member ID로 필터링
|
||||||
|
.where(memberAuthGroup.memberOid.oid.eq(memberOId))
|
||||||
|
.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.dto.ResourceDto;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ResourceService {
|
||||||
|
ResourceDto createResource(ResourceDto dto);
|
||||||
|
|
||||||
|
List<ResourceDto> createResourceList(List<ResourceDto> list);
|
||||||
|
|
||||||
|
ResourceDto getById(Long id);
|
||||||
|
|
||||||
|
List<ResourceDto> getAll();
|
||||||
|
|
||||||
|
ResourceDto update(Long id, ResourceDto dto);
|
||||||
|
|
||||||
|
void delete(Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.bio.bio_backend.domain.base.resource.service;
|
||||||
|
|
||||||
|
import com.bio.bio_backend.domain.base.resource.dto.ResourceDto;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.entity.Resource;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.repository.ResourceRepository;
|
||||||
|
import com.bio.bio_backend.domain.base.resource.mapper.ResourceMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class ResourceServiceImpl implements ResourceService {
|
||||||
|
|
||||||
|
private final ResourceRepository repository;
|
||||||
|
private final ResourceMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public ResourceDto createResource(ResourceDto dto) {
|
||||||
|
try {
|
||||||
|
Resource entity = mapper.toEntity(dto);
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public List<ResourceDto> createResourceList(List<ResourceDto> list) {
|
||||||
|
|
||||||
|
List<ResourceDto> resultList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ResourceDto dto : list) {
|
||||||
|
try {
|
||||||
|
Resource entity = mapper.toEntity(dto);
|
||||||
|
resultList.add(mapper.toDto(repository.save(entity)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
ResourceDto resultDto = null;
|
||||||
|
resultList.add(resultDto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceDto getById(Long id) {
|
||||||
|
return repository.findById(id).map(mapper::toDto).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceDto> getAll() {
|
||||||
|
return repository.findAll().stream().map(mapper::toDto).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public ResourceDto update(Long id, ResourceDto dto) {
|
||||||
|
Resource entity = repository.findById(id).orElseThrow();
|
||||||
|
// TODO: update fields
|
||||||
|
return mapper.toDto(repository.save(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
repository.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,24 +1,55 @@
|
|||||||
package com.bio.bio_backend.global.config;
|
package com.bio.bio_backend.global.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
import org.springframework.web.filter.CorsFilter;
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class CorsConfig {
|
public class CorsConfig {
|
||||||
|
|
||||||
|
@Value("${cors.allowed-origins:http://localhost:3000,http://localhost:8080}")
|
||||||
|
private String allowedOrigins;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CorsFilter corsFilter() {
|
public CorsFilter corsFilter() {
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
config.addAllowedOriginPattern("*");
|
|
||||||
config.addAllowedHeader("*");
|
// 허용할 Origin 설정
|
||||||
config.addAllowedMethod("*");
|
List<String> origins = Arrays.asList(allowedOrigins.split(","));
|
||||||
|
config.setAllowedOrigins(origins);
|
||||||
|
|
||||||
|
// 허용할 헤더 설정
|
||||||
|
config.setAllowedHeaders(Arrays.asList(
|
||||||
|
"Authorization",
|
||||||
|
"Content-Type",
|
||||||
|
"X-Requested-With",
|
||||||
|
"Accept",
|
||||||
|
"Origin",
|
||||||
|
"Access-Control-Request-Method",
|
||||||
|
"Access-Control-Request-Headers"
|
||||||
|
));
|
||||||
|
|
||||||
|
// 허용할 HTTP 메서드 설정
|
||||||
|
config.setAllowedMethods(Arrays.asList(
|
||||||
|
"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"
|
||||||
|
));
|
||||||
|
|
||||||
|
// 인증 정보 포함 허용 (JWT 토큰 등)
|
||||||
config.setAllowCredentials(true);
|
config.setAllowCredentials(true);
|
||||||
|
|
||||||
|
// Preflight 요청 캐시 시간 (초)
|
||||||
|
config.setMaxAge(3600L);
|
||||||
|
|
||||||
|
// 모든 경로에 적용
|
||||||
source.registerCorsConfiguration("/**", config);
|
source.registerCorsConfiguration("/**", config);
|
||||||
|
|
||||||
return new CorsFilter(source);
|
return new CorsFilter(source);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.bio.bio_backend.global.security;
|
|||||||
|
|
||||||
import com.bio.bio_backend.global.filter.JwtTokenIssuanceFilter;
|
import com.bio.bio_backend.global.filter.JwtTokenIssuanceFilter;
|
||||||
import com.bio.bio_backend.global.filter.JwtTokenValidationFilter;
|
import com.bio.bio_backend.global.filter.JwtTokenValidationFilter;
|
||||||
|
import com.bio.bio_backend.global.config.CorsConfig;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
@@ -15,6 +16,7 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.web.filter.CorsFilter;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
@@ -37,6 +39,12 @@ public class WebSecurity {
|
|||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
private final HttpUtils httpUtils;
|
private final HttpUtils httpUtils;
|
||||||
private final MemberMapper memberMapper;
|
private final MemberMapper memberMapper;
|
||||||
|
private final CorsConfig corsConfig; // CorsConfig 주입
|
||||||
|
|
||||||
|
// CORS 필터 빈 가져오기
|
||||||
|
private CorsFilter getCorsFilter() {
|
||||||
|
return corsConfig.corsFilter();
|
||||||
|
}
|
||||||
|
|
||||||
private JwtTokenIssuanceFilter getJwtTokenIssuanceFilter(AuthenticationManager authenticationManager) {
|
private JwtTokenIssuanceFilter getJwtTokenIssuanceFilter(AuthenticationManager authenticationManager) {
|
||||||
JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper, memberService, httpUtils, memberMapper);
|
JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper, memberService, httpUtils, memberMapper);
|
||||||
@@ -86,6 +94,7 @@ public class WebSecurity {
|
|||||||
.sessionManagement(session ->
|
.sessionManagement(session ->
|
||||||
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||||
);
|
);
|
||||||
|
//.addFilterBefore(getCorsFilter(), UsernamePasswordAuthenticationFilter.class); // cors를 nginx 통해 처리 중
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +126,7 @@ public class WebSecurity {
|
|||||||
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||||
)
|
)
|
||||||
.logout(AbstractHttpConfigurer::disable)
|
.logout(AbstractHttpConfigurer::disable)
|
||||||
|
//.addFilterBefore(getCorsFilter(), UsernamePasswordAuthenticationFilter.class) // cors를 nginx 통해 처리 중
|
||||||
.addFilterBefore(getJwtTokenIssuanceFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class) // 토큰 발급
|
.addFilterBefore(getJwtTokenIssuanceFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class) // 토큰 발급
|
||||||
.addFilterBefore(getJwtTokenValidationFilter(), UsernamePasswordAuthenticationFilter.class); // 토큰 검증
|
.addFilterBefore(getJwtTokenValidationFilter(), UsernamePasswordAuthenticationFilter.class); // 토큰 검증
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ spring.jpa.properties.hibernate.order_updates=true
|
|||||||
spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
|
spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
|
||||||
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=ddl/schema_entity.sql
|
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=ddl/schema_entity.sql
|
||||||
spring.jpa.properties.hibernate.hbm2ddl.schema-generation.script.append=false
|
spring.jpa.properties.hibernate.hbm2ddl.schema-generation.script.append=false
|
||||||
|
spring.jpa.properties.hibernate.hbm2ddl.charset_name=UTF-8
|
||||||
|
|
||||||
# ========================================
|
# ========================================
|
||||||
# 로그 레벨 설정
|
# 로그 레벨 설정
|
||||||
|
|||||||
Reference in New Issue
Block a user