Compare commits
77 Commits
9468d19736
...
main
Author | SHA1 | Date | |
---|---|---|---|
499fbc6afb | |||
e78e98ad37 | |||
f10b028e04 | |||
cc2a34403d | |||
e8a785a20d | |||
afef6dfa80 | |||
a0ffeb236e | |||
fa1df19f64 | |||
b0398fccee | |||
92be6caf80 | |||
31aed4bda0 | |||
438bfc3bc5 | |||
![]() |
c07e7511d3 | ||
![]() |
0617347395 | ||
8c5d7c6c3f | |||
75d827bf04 | |||
5abe2932bc | |||
![]() |
9467a1edd0 | ||
![]() |
3fc7debff4 | ||
![]() |
d29bc2dedd | ||
0c141eb397 | |||
6df8409e96 | |||
88a508bd54 | |||
d37986558e | |||
eb2efbb0ea | |||
12aa3ae5a3 | |||
![]() |
1bd499fe10 | ||
![]() |
71bcbbb396 | ||
f9472d1ccd | |||
56c8893f9e | |||
690724c77c | |||
b5d6d213f3 | |||
e7105215b8 | |||
d8fe8399f7 | |||
8cee267f36 | |||
b1218ab9bb | |||
7ae5871ae0 | |||
1ce08cb981 | |||
a4c14c69f0 | |||
9e7929da6b | |||
f9cd84f740 | |||
224006b6cb | |||
dbac9f4702 | |||
2a1f211159 | |||
![]() |
7430f1606f | ||
![]() |
1153f164fc | ||
![]() |
1850227d24 | ||
09e06cd10b | |||
6d1b89609b | |||
baaa003d9a | |||
d9d3be86a9 | |||
1b46b95ad5 | |||
8aa96d5fbd | |||
0dc32f2b39 | |||
bfb87b8e33 | |||
![]() |
33b33ef7a3 | ||
![]() |
331d242ac3 | ||
eff011f9fd | |||
![]() |
0f1c5443ea | ||
baab0352d5 | |||
21f121c490 | |||
77bc400888 | |||
d0612b61e9 | |||
d1c82848a2 | |||
b34636baae | |||
a2c6c83ed7 | |||
6a4388f513 | |||
2ead0f0f12 | |||
e0e868a282 | |||
![]() |
45f3aa0f2c | ||
74f8b65327 | |||
3033582f8e | |||
51a29996f5 | |||
a8e1a15b1d | |||
d1bf1dd477 | |||
c50e8d835b | |||
2ff5a02906 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -43,3 +43,7 @@ bin/
|
||||
# Temporary files created by the OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/nginx-1.28.0/logs/nginx.pid
|
||||
|
||||
# Upload files
|
||||
uploads/
|
||||
|
25
Dockerfile
25
Dockerfile
@@ -1,25 +0,0 @@
|
||||
# ./my-spring-app/Dockerfile
|
||||
|
||||
# 공식 OpenJDK 이미지를 기반으로 사용
|
||||
FROM openjdk:17-jdk-slim
|
||||
|
||||
# 컨테이너의 작업 디렉터리를 설정
|
||||
WORKDIR /app
|
||||
|
||||
# Gradle Wrapper와 빌드 파일을 컨테이너에 복사
|
||||
COPY gradlew .
|
||||
COPY gradle ./gradle
|
||||
|
||||
# 프로젝트 설정 파일들을 복사
|
||||
COPY build.gradle .
|
||||
COPY settings.gradle .
|
||||
|
||||
# 의존성을 미리 다운로드
|
||||
RUN ./gradlew dependencies
|
||||
|
||||
# 소스 파일들을 복사
|
||||
COPY src ./src
|
||||
|
||||
# Gradle Wrapper를 사용하여 애플리케이션을 실행
|
||||
# 이 명령어는 docker-compose.yml에서 개발용 명령으로 덮어쓸 것입니다.
|
||||
CMD ["./gradlew", "bootRun"]
|
354
README.md
354
README.md
@@ -1,2 +1,354 @@
|
||||
# bio_backend
|
||||
# Bio Backend
|
||||
|
||||
## 기술 스택
|
||||
|
||||
- **Framework**: Spring Boot
|
||||
- **Database**: PostgreSQL
|
||||
- **ORM**: Spring Data JPA + QueryDSL
|
||||
- **Security**: Spring Security + JWT
|
||||
- **Build Tool**: Gradle
|
||||
- **Container**: Docker + Kubernetes
|
||||
- **API Documentation**: Swagger (SpringDoc OpenAPI)
|
||||
|
||||
## 개발 가이드
|
||||
|
||||
### 1. 프로젝트 구조
|
||||
|
||||
```
|
||||
src/main/java/com/bio/bio_backend/
|
||||
├── domain/ # 도메인별 패키지
|
||||
│ └── base/ # 기본 도메인
|
||||
│ └── member/ # 회원 도메인
|
||||
│ ├── controller/ # API 엔드포인트
|
||||
│ ├── service/ # 비즈니스 로직
|
||||
│ ├── repository/ # 데이터 접근
|
||||
│ ├── entity/ # JPA 엔티티
|
||||
│ ├── dto/ # 데이터 전송 객체
|
||||
│ ├── mapper/ # MapStruct 매퍼
|
||||
│ └── enums/ # 도메인 열거형
|
||||
├── global/ # 공통 설정
|
||||
│ ├── config/ # 설정 클래스
|
||||
│ ├── security/ # 보안 설정
|
||||
│ ├── exception/ # 예외 처리
|
||||
│ ├── aop/ # AOP 로깅
|
||||
│ ├── filter/ # HTTP 로깅 필터
|
||||
│ ├── utils/ # 유틸리티
|
||||
│ ├── constants/ # 상수 정의
|
||||
│ ├── dto/ # 공통 DTO
|
||||
│ ├── entity/ # 공통 엔티티
|
||||
│ └── annotation/ # 커스텀 어노테이션
|
||||
├── BioBackendApplication.java
|
||||
└── ServletInitializer.java
|
||||
```
|
||||
|
||||
### 2. API 응답 표준화 (ApiResponseDto)
|
||||
|
||||
#### 응답 구조
|
||||
|
||||
모든 API 응답은 `ApiResponseDto<T>` 형태로 표준화되어 있습니다.
|
||||
|
||||
```java
|
||||
public class ApiResponseDto<T> {
|
||||
private boolean success; // 성공/실패 여부 (true/false)
|
||||
private int code; // HTTP 상태 코드
|
||||
private String message; // 응답 메시지 (ApiResponseCode enum 값)
|
||||
private String description; // 응답 설명
|
||||
private T data; // 실제 데이터 (제네릭 타입)
|
||||
}
|
||||
```
|
||||
|
||||
#### 응답 예시
|
||||
|
||||
**성공 응답 (201 Created)**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"code": 201,
|
||||
"message": "COMMON_SUCCESS_CREATED",
|
||||
"description": "Created successfully",
|
||||
"data": {
|
||||
"seq": 1,
|
||||
"userId": "user123",
|
||||
"name": "홍길동"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**실패 응답 (409 Conflict)**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"code": 409,
|
||||
"message": "USER_ID_DUPLICATE",
|
||||
"description": "User ID already exists"
|
||||
}
|
||||
```
|
||||
|
||||
#### 사용 방법
|
||||
|
||||
**Controller에서 응답 생성**
|
||||
|
||||
```java
|
||||
@PostMapping("/members")
|
||||
public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody CreateMemberRequestDto requestDto) {
|
||||
// ... 비즈니스 로직 ...
|
||||
|
||||
// 성공 응답
|
||||
ApiResponseDto<CreateMemberResponseDto> apiResponse =
|
||||
ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
```
|
||||
|
||||
**공용 응답 코드 사용**
|
||||
|
||||
```java
|
||||
// ApiResponseCode.java
|
||||
public enum ApiResponseCode {
|
||||
// 공용 성공 코드
|
||||
COMMON_SUCCESS(HttpStatus.OK.value(), "요청 성공"),
|
||||
COMMON_SUCCESS_CREATED(HttpStatus.CREATED.value(), "성공적으로 생성되었습니다"),
|
||||
COMMON_SUCCESS_UPDATED(HttpStatus.OK.value(), "성공적으로 수정되었습니다"),
|
||||
COMMON_SUCCESS_DELETED(HttpStatus.OK.value(), "성공적으로 삭제되었습니다"),
|
||||
COMMON_SUCCESS_RETRIEVED(HttpStatus.OK.value(), "성공적으로 조회되었습니다"),
|
||||
|
||||
// 공용 오류 코드
|
||||
COMMON_BAD_REQUEST(HttpStatus.BAD_REQUEST.value(), "필수 요청 본문이 누락되었거나 오류가 발생했습니다"),
|
||||
COMMON_UNAUTHORIZED(HttpStatus.UNAUTHORIZED.value(), "인증에 실패했습니다"),
|
||||
COMMON_FORBIDDEN(HttpStatus.FORBIDDEN.value(), "접근이 거부되었습니다"),
|
||||
COMMON_NOT_FOUND(HttpStatus.NOT_FOUND.value(), "리소스를 찾을 수 없습니다"),
|
||||
COMMON_CONFLICT(HttpStatus.CONFLICT.value(), "충돌이 발생했습니다"),
|
||||
COMMON_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버에서 오류가 발생했습니다"),
|
||||
|
||||
// 사용자 관련 코드
|
||||
USER_ID_DUPLICATE(HttpStatus.CONFLICT.value(), "이미 존재하는 사용자 ID입니다"),
|
||||
USER_NOT_FOUND(HttpStatus.UNAUTHORIZED.value(), "사용자를 찾을 수 없습니다. 인증에 실패했습니다"),
|
||||
USER_PASSWORD_INVALID(HttpStatus.UNAUTHORIZED.value(), "비밀번호가 올바르지 않습니다")
|
||||
}
|
||||
```
|
||||
|
||||
#### 핵심 규칙
|
||||
|
||||
- **모든 API 응답**: `ApiResponseDto<T>`로 감싸서 반환
|
||||
- **공용 응답 코드**: `COMMON_` 접두사로 시작하는 범용 코드 사용
|
||||
- **일관된 구조**: `success`, `code`, `message`, `description`, `data` 필드로 표준화
|
||||
- **성공/실패 구분**: `success` 필드로 명확한 성공/실패 여부 전달
|
||||
- **제네릭 활용**: `<T>`를 통해 다양한 데이터 타입 지원
|
||||
|
||||
### 3. JWT 인증 시스템
|
||||
|
||||
#### 토큰 구성
|
||||
|
||||
- **Access Token**: 15분 (900,000ms) - API 요청 시 사용
|
||||
- **Refresh Token**: 7일 (604,800,000ms) - 쿠키에 저장, 자동 갱신
|
||||
|
||||
#### 자동 토큰 갱신
|
||||
|
||||
**모든 API 요청마다 자동으로 처리됩니다:**
|
||||
|
||||
1. **Access Token 유효**: 정상 요청 처리
|
||||
2. **Access Token 만료**: Refresh Token으로 자동 갱신
|
||||
3. **새 Access Token 발급**: 응답 헤더에 자동 설정
|
||||
4. **Refresh Token 갱신**: 보안을 위해 매번 새로운 토큰 발급
|
||||
|
||||
#### 주요 컴포넌트
|
||||
|
||||
- **`JwtTokenIssuanceFilter`**: 로그인 시 토큰 발급
|
||||
- **`JwtTokenValidationFilter`**: 요청마다 토큰 검증 및 갱신
|
||||
- **`JwtUtils`**: 토큰 생성, 검증, 갱신 유틸리티
|
||||
|
||||
### 4. API 문서화 (Swagger)
|
||||
|
||||
#### Swagger UI 접속
|
||||
|
||||
- **URL**: `http://localhost:8080/service/swagger-ui.html`
|
||||
- **API Docs**: `http://localhost:8080/service/api-docs`
|
||||
|
||||
### 5. 시스템 모니터링 (Actuator)
|
||||
|
||||
#### Health 체크
|
||||
|
||||
- **기본 Health**: `http://localhost:8080/service/actuator/health`
|
||||
- **Readiness Probe**: `http://localhost:8080/service/actuator/health/readiness`
|
||||
- **Liveness Probe**: `http://localhost:8080/service/actuator/health/liveness`
|
||||
|
||||
#### 시스템 정보
|
||||
|
||||
- **애플리케이션 정보**: `http://localhost:8080/service/actuator/info`
|
||||
- **환경 설정**: `http://localhost:8080/service/actuator/env`
|
||||
- **설정 속성**: `http://localhost:8080/service/actuator/configprops`
|
||||
- **메트릭**: `http://localhost:8080/service/actuator/metrics`
|
||||
|
||||
#### 주요 어노테이션
|
||||
|
||||
```java
|
||||
@Tag(name = "Member", description = "회원 관리 API")
|
||||
@Operation(summary = "회원 가입", description = "새로운 회원을 등록합니다.")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터",
|
||||
content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보",
|
||||
content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
```
|
||||
|
||||
#### 설정 파일
|
||||
|
||||
- **SwaggerConfig.java**: OpenAPI 기본 정보 설정
|
||||
- **application.properties**: Swagger UI 커스터마이징
|
||||
|
||||
### 6. 트랜잭션 관리
|
||||
|
||||
#### 기본 설정
|
||||
|
||||
```java
|
||||
@Service
|
||||
@Transactional(readOnly = true) // 클래스 레벨: 읽기 전용 기본값
|
||||
public class MemberServiceImpl {
|
||||
|
||||
// 읽기 전용 메서드 (별도 어노테이션 불필요)
|
||||
public MemberDto selectMember(long seq) { ... }
|
||||
|
||||
// 쓰기 작업 메서드 (개별 @Transactional 적용)
|
||||
@Transactional
|
||||
public MemberDto createMember(MemberDto dto) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
#### 핵심 규칙
|
||||
|
||||
- **클래스 레벨**: `@Transactional(readOnly = true)` 기본 설정
|
||||
- **메서드별**: 데이터 수정 시에만 `@Transactional` 개별 적용
|
||||
- **설정**: `spring.jpa.open-in-view=false` (성능 최적화)
|
||||
|
||||
### 7. 오류 등록 및 사용
|
||||
|
||||
#### 오류 코드 등록
|
||||
|
||||
```java
|
||||
// ApiResponseCode.java
|
||||
public enum ApiResponseCode {
|
||||
USER_ID_DUPLICATE(HttpStatus.CONFLICT.value(), "User ID already exists"),
|
||||
}
|
||||
```
|
||||
|
||||
#### 오류 사용 방법
|
||||
|
||||
```java
|
||||
// Service에서 예외 발생
|
||||
throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE);
|
||||
|
||||
// Controller에서 예외 처리 (자동)
|
||||
// GlobalExceptionHandler가 ApiException을 잡아서 응답 변환
|
||||
```
|
||||
|
||||
#### 핵심 규칙
|
||||
|
||||
- **오류 코드**: `ApiResponseCode` enum에 모든 오류 정의
|
||||
- **예외 클래스**: `ApiException`으로 비즈니스 로직 예외 처리
|
||||
- **자동 처리**: `GlobalExceptionHandler`가 일관된 응답 형태로 변환
|
||||
|
||||
### 8. 로깅 시스템
|
||||
|
||||
#### @LogExecution 어노테이션 사용법
|
||||
|
||||
**메서드 실행 로깅을 위한 필수 어노테이션입니다.**
|
||||
|
||||
##### 기본 사용법
|
||||
|
||||
```java
|
||||
@LogExecution("회원 등록")
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody CreateMemberRequestDto requestDto) {
|
||||
// 메서드 실행 시 자동으로 로그 출력
|
||||
}
|
||||
```
|
||||
|
||||
##### 로그 출력 예시
|
||||
|
||||
**메서드 시작 시:**
|
||||
|
||||
```
|
||||
[START] 회원 등록 | 호출경로: MemberController.createMember | 사용자: 고명빈(kmbin92)
|
||||
```
|
||||
|
||||
**메서드 성공 시:**
|
||||
|
||||
```
|
||||
[SUCCESS] 회원 등록 | 호출경로: MemberController.createMember | 사용자: 고명빈(kmbin92) | 시간: 200ms
|
||||
```
|
||||
|
||||
**메서드 실패 시:**
|
||||
|
||||
```
|
||||
[FAILED] 회원 등록 | 호출경로: MemberController.createMember | 사용자: 고명빈(kmbin92) | 시간: 23ms | 오류: 이미 존재하는 사용자 ID입니다
|
||||
```
|
||||
|
||||
##### 어노테이션 설정
|
||||
|
||||
```java
|
||||
@LogExecution("사용자 정보 조회")
|
||||
public UserDto getUserInfo() { }
|
||||
|
||||
@LogExecution("주문 처리")
|
||||
public OrderDto processOrder() { }
|
||||
```
|
||||
|
||||
##### 로깅 시스템 구성
|
||||
|
||||
1. **MethodExecutionLoggingAspect**: 메서드 실행 로깅 (AOP)
|
||||
2. **HttpLoggingFilter**: HTTP 요청/응답 로깅 (필터)
|
||||
3. **logback-spring.xml**: 로그 파일 관리 및 설정
|
||||
|
||||
**중요**: `@LogExecution` 어노테이션이 없으면 메서드 실행 로그가 출력되지 않습니다
|
||||
|
||||
### 9. MapStruct
|
||||
|
||||
**매퍼 인터페이스**
|
||||
|
||||
```java
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface MemberMapper {
|
||||
MemberDto toDto(Member member);
|
||||
Member toEntity(MemberDto dto);
|
||||
}
|
||||
```
|
||||
|
||||
**사용 예시**
|
||||
|
||||
```java
|
||||
// Entity → DTO
|
||||
MemberDto dto = memberMapper.toDto(member);
|
||||
|
||||
// DTO → Entity
|
||||
Member entity = memberMapper.toEntity(dto);
|
||||
```
|
||||
|
||||
**자동 생성**: 컴파일 시 `MemberMapperImpl` 구현체 생성
|
||||
|
||||
### 10. BaseEntity 상속
|
||||
|
||||
**모든 엔티티는 `BaseEntity` 상속을 원칙으로 합니다.**
|
||||
|
||||
#### 자동 생성 필드
|
||||
|
||||
- **OID**: `@PrePersist`에서 자동 생성 (고유 식별자)
|
||||
- **생성일시**: `@CreatedDate`로 자동 설정
|
||||
- **수정일시**: `@LastModifiedDate`로 자동 갱신
|
||||
- **생성자/수정자 OID**: 사용자 추적용
|
||||
|
||||
#### 사용 예시
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "st_members")
|
||||
public class Member extends BaseEntity {
|
||||
// OID, 생성일시, 수정일시 등이 자동으로 관리됨
|
||||
private String userId;
|
||||
private String name;
|
||||
}
|
||||
```
|
||||
|
94
build.gradle
94
build.gradle
@@ -1,13 +1,8 @@
|
||||
buildscript {
|
||||
ext {
|
||||
queryDslVersion = "5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '3.5.4'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id 'com.google.cloud.tools.jib' version '3.4.0' // Jib 플러그인 추가
|
||||
}
|
||||
|
||||
group = 'com.bio'
|
||||
@@ -30,37 +25,54 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// 개발용 의존성 추가
|
||||
developmentOnly 'org.springframework.boot:spring-boot-devtools'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
// PostgreSQL JDBC 드라이버
|
||||
|
||||
// PostgreSQL JDBC
|
||||
runtimeOnly 'org.postgresql:postgresql'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
|
||||
// Spring Security 추가
|
||||
// Spring Securit
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
|
||||
// Validation 추가
|
||||
// Validation
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
|
||||
// ModelMapper 추가
|
||||
implementation 'org.modelmapper:modelmapper:3.0.0'
|
||||
// Spring Boot Actuator
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
|
||||
// MyBatis 추가
|
||||
// MapStruct
|
||||
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
|
||||
|
||||
// MyBatis
|
||||
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
|
||||
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
|
||||
// jwt
|
||||
implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
|
||||
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
|
||||
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5'
|
||||
|
||||
// lombok
|
||||
compileOnly 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok'
|
||||
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
|
||||
// querydsl
|
||||
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}:jakarta"
|
||||
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"
|
||||
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
|
||||
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
|
||||
implementation 'io.github.openfeign.querydsl:querydsl-jpa:6.11'
|
||||
annotationProcessor 'io.github.openfeign.querydsl:querydsl-apt:6.11:jpa'
|
||||
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
|
||||
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
|
||||
|
||||
// p6spy
|
||||
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'
|
||||
|
||||
// SpringDoc OpenAPI (Swagger)
|
||||
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
@@ -68,16 +80,44 @@ tasks.named('test') {
|
||||
}
|
||||
|
||||
// querydsl
|
||||
def querydslDir = "$buildDir/generated/querydsl"
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += [ querydslDir ]
|
||||
def generatedSrcDir = 'build/generated/sources/annotation-processor'
|
||||
clean {
|
||||
delete file(generatedSrcDir)
|
||||
}
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.generatedSourceOutputDirectory = file(generatedSrcDir)
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
|
||||
}
|
||||
|
||||
clean.doLast {
|
||||
file(querydslDir).deleteDir()
|
||||
jib {
|
||||
from {
|
||||
image = 'demo.stam.kr/leejisun9/eclipse-temurin:17-jre' // 가벼운 JRE 베이스
|
||||
// (선택) 인증서 추가/회사 CA 필요 시 extraDirectories 사용
|
||||
}
|
||||
to {
|
||||
image = 'demo.stam.kr/leejisun9/bio-backend'; tags = ['1.0.0'] // 기본 대상 레지스트리
|
||||
// tags는 skaffold가 자동 주입. 로컬 단독 빌드시 -Djib.to.tags=로 지정 가능
|
||||
}
|
||||
container {
|
||||
// Spring Boot 컨테이너 런타임 옵션
|
||||
ports = ['8080']
|
||||
jvmFlags = [
|
||||
'-XX:+UseContainerSupport',
|
||||
'-Dserver.port=8080',
|
||||
'-XX:InitialRAMPercentage=50.0',
|
||||
'-XX:MaxRAMPercentage=75.0'
|
||||
]
|
||||
environment = [ 'SPRING_PROFILES_ACTIVE': 'dev' ]
|
||||
// (선택) non-root 권장 (권한 필요한 리소스 없는 경우)
|
||||
// user = '65532:65532'
|
||||
// workingDirectory = '/app'
|
||||
}
|
||||
// (선택) 계층 최적화/추가 파일
|
||||
// extraDirectories {
|
||||
// paths {
|
||||
// path {
|
||||
// from = file('docker/extra') // 예: CA cert, 설정 템플릿
|
||||
// into = '/opt/extra'
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
@@ -1,14 +1,96 @@
|
||||
|
||||
create table member (
|
||||
status varchar(1) not null,
|
||||
create table st_common_code (
|
||||
sort_order integer not null,
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
last_login_at timestamp(6),
|
||||
oid bigint generated by default as identity,
|
||||
created_oid bigint,
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
role varchar(40) not null,
|
||||
updated_oid bigint,
|
||||
code varchar(50) not null unique,
|
||||
group_code varchar(50) not null,
|
||||
parent_code varchar(50),
|
||||
character_ref1 varchar(100),
|
||||
character_ref2 varchar(100),
|
||||
character_ref3 varchar(100),
|
||||
character_ref4 varchar(100),
|
||||
character_ref5 varchar(100),
|
||||
name varchar(100) not null,
|
||||
description varchar(500),
|
||||
created_id varchar(255),
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create table st_common_group_code (
|
||||
sort_order integer not null,
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
created_oid bigint,
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
updated_oid bigint,
|
||||
code varchar(50) not null unique,
|
||||
character_ref1_title varchar(100),
|
||||
character_ref2_title varchar(100),
|
||||
character_ref3_title varchar(100),
|
||||
character_ref4_title varchar(100),
|
||||
character_ref5_title varchar(100),
|
||||
name varchar(100) not null,
|
||||
created_id varchar(255),
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create table st_file (
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
created_oid bigint,
|
||||
file_size bigint not null,
|
||||
group_oid bigint,
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
updated_oid bigint,
|
||||
content_type varchar(255) not null,
|
||||
created_id varchar(255),
|
||||
description varchar(255),
|
||||
file_path varchar(255) not null,
|
||||
original_file_name varchar(255) not null,
|
||||
stored_file_name varchar(255) not null,
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create table st_member (
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
created_oid bigint,
|
||||
last_login_at timestamp(6),
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
updated_oid bigint,
|
||||
login_ip varchar(45),
|
||||
name varchar(100) not null,
|
||||
password varchar(100) not null,
|
||||
user_id varchar(100) not null,
|
||||
refresh_token varchar(200),
|
||||
primary key (oid),
|
||||
constraint uk_member_user_id unique (user_id)
|
||||
refresh_token varchar(1024),
|
||||
created_id varchar(255),
|
||||
email varchar(255) not null,
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create index idx_common_code_code
|
||||
on st_common_code (code);
|
||||
|
||||
create index idx_common_code_group_code
|
||||
on st_common_code (group_code);
|
||||
|
||||
create index idx_common_code_parent_code
|
||||
on st_common_code (parent_code);
|
||||
|
||||
create index idx_common_group_code_code
|
||||
on st_common_group_code (code);
|
||||
|
||||
create index idx_member_user_id
|
||||
on st_member (user_id);
|
||||
|
BIN
jpa-curd-0.0.1.vsix
Normal file
BIN
jpa-curd-0.0.1.vsix
Normal file
Binary file not shown.
@@ -1,21 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: bio-backend-deployment
|
||||
labels:
|
||||
app: bio-backend
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: bio-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: bio-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: bio-backend
|
||||
image: backend-0.0.1:latest # 여기에 Skaffold가 빌드할 이미지 이름을 사용합니다.
|
||||
ports:
|
||||
- containerPort: 8081
|
26
nginx-1.28.0/conf/fastcgi.conf
Normal file
26
nginx-1.28.0/conf/fastcgi.conf
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_param REQUEST_URI $request_uri;
|
||||
fastcgi_param DOCUMENT_URI $document_uri;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||
fastcgi_param REQUEST_SCHEME $scheme;
|
||||
fastcgi_param HTTPS $https if_not_empty;
|
||||
|
||||
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param REMOTE_PORT $remote_port;
|
||||
fastcgi_param SERVER_ADDR $server_addr;
|
||||
fastcgi_param SERVER_PORT $server_port;
|
||||
fastcgi_param SERVER_NAME $server_name;
|
||||
|
||||
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
25
nginx-1.28.0/conf/fastcgi_params
Normal file
25
nginx-1.28.0/conf/fastcgi_params
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
|
||||
fastcgi_param REQUEST_URI $request_uri;
|
||||
fastcgi_param DOCUMENT_URI $document_uri;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||
fastcgi_param REQUEST_SCHEME $scheme;
|
||||
fastcgi_param HTTPS $https if_not_empty;
|
||||
|
||||
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param REMOTE_PORT $remote_port;
|
||||
fastcgi_param SERVER_ADDR $server_addr;
|
||||
fastcgi_param SERVER_PORT $server_port;
|
||||
fastcgi_param SERVER_NAME $server_name;
|
||||
|
||||
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
109
nginx-1.28.0/conf/koi-utf
Normal file
109
nginx-1.28.0/conf/koi-utf
Normal file
@@ -0,0 +1,109 @@
|
||||
|
||||
# This map is not a full koi8-r <> utf8 map: it does not contain
|
||||
# box-drawing and some other characters. Besides this map contains
|
||||
# several koi8-u and Byelorussian letters which are not in koi8-r.
|
||||
# If you need a full and standard map, use contrib/unicode2nginx/koi-utf
|
||||
# map instead.
|
||||
|
||||
charset_map koi8-r utf-8 {
|
||||
|
||||
80 E282AC ; # euro
|
||||
|
||||
95 E280A2 ; # bullet
|
||||
|
||||
9A C2A0 ; #
|
||||
|
||||
9E C2B7 ; # ·
|
||||
|
||||
A3 D191 ; # small yo
|
||||
A4 D194 ; # small Ukrainian ye
|
||||
|
||||
A6 D196 ; # small Ukrainian i
|
||||
A7 D197 ; # small Ukrainian yi
|
||||
|
||||
AD D291 ; # small Ukrainian soft g
|
||||
AE D19E ; # small Byelorussian short u
|
||||
|
||||
B0 C2B0 ; # °
|
||||
|
||||
B3 D081 ; # capital YO
|
||||
B4 D084 ; # capital Ukrainian YE
|
||||
|
||||
B6 D086 ; # capital Ukrainian I
|
||||
B7 D087 ; # capital Ukrainian YI
|
||||
|
||||
B9 E28496 ; # numero sign
|
||||
|
||||
BD D290 ; # capital Ukrainian soft G
|
||||
BE D18E ; # capital Byelorussian short U
|
||||
|
||||
BF C2A9 ; # (C)
|
||||
|
||||
C0 D18E ; # small yu
|
||||
C1 D0B0 ; # small a
|
||||
C2 D0B1 ; # small b
|
||||
C3 D186 ; # small ts
|
||||
C4 D0B4 ; # small d
|
||||
C5 D0B5 ; # small ye
|
||||
C6 D184 ; # small f
|
||||
C7 D0B3 ; # small g
|
||||
C8 D185 ; # small kh
|
||||
C9 D0B8 ; # small i
|
||||
CA D0B9 ; # small j
|
||||
CB D0BA ; # small k
|
||||
CC D0BB ; # small l
|
||||
CD D0BC ; # small m
|
||||
CE D0BD ; # small n
|
||||
CF D0BE ; # small o
|
||||
|
||||
D0 D0BF ; # small p
|
||||
D1 D18F ; # small ya
|
||||
D2 D180 ; # small r
|
||||
D3 D181 ; # small s
|
||||
D4 D182 ; # small t
|
||||
D5 D183 ; # small u
|
||||
D6 D0B6 ; # small zh
|
||||
D7 D0B2 ; # small v
|
||||
D8 D18C ; # small soft sign
|
||||
D9 D18B ; # small y
|
||||
DA D0B7 ; # small z
|
||||
DB D188 ; # small sh
|
||||
DC D18D ; # small e
|
||||
DD D189 ; # small shch
|
||||
DE D187 ; # small ch
|
||||
DF D18A ; # small hard sign
|
||||
|
||||
E0 D0AE ; # capital YU
|
||||
E1 D090 ; # capital A
|
||||
E2 D091 ; # capital B
|
||||
E3 D0A6 ; # capital TS
|
||||
E4 D094 ; # capital D
|
||||
E5 D095 ; # capital YE
|
||||
E6 D0A4 ; # capital F
|
||||
E7 D093 ; # capital G
|
||||
E8 D0A5 ; # capital KH
|
||||
E9 D098 ; # capital I
|
||||
EA D099 ; # capital J
|
||||
EB D09A ; # capital K
|
||||
EC D09B ; # capital L
|
||||
ED D09C ; # capital M
|
||||
EE D09D ; # capital N
|
||||
EF D09E ; # capital O
|
||||
|
||||
F0 D09F ; # capital P
|
||||
F1 D0AF ; # capital YA
|
||||
F2 D0A0 ; # capital R
|
||||
F3 D0A1 ; # capital S
|
||||
F4 D0A2 ; # capital T
|
||||
F5 D0A3 ; # capital U
|
||||
F6 D096 ; # capital ZH
|
||||
F7 D092 ; # capital V
|
||||
F8 D0AC ; # capital soft sign
|
||||
F9 D0AB ; # capital Y
|
||||
FA D097 ; # capital Z
|
||||
FB D0A8 ; # capital SH
|
||||
FC D0AD ; # capital E
|
||||
FD D0A9 ; # capital SHCH
|
||||
FE D0A7 ; # capital CH
|
||||
FF D0AA ; # capital hard sign
|
||||
}
|
103
nginx-1.28.0/conf/koi-win
Normal file
103
nginx-1.28.0/conf/koi-win
Normal file
@@ -0,0 +1,103 @@
|
||||
|
||||
charset_map koi8-r windows-1251 {
|
||||
|
||||
80 88 ; # euro
|
||||
|
||||
95 95 ; # bullet
|
||||
|
||||
9A A0 ; #
|
||||
|
||||
9E B7 ; # ·
|
||||
|
||||
A3 B8 ; # small yo
|
||||
A4 BA ; # small Ukrainian ye
|
||||
|
||||
A6 B3 ; # small Ukrainian i
|
||||
A7 BF ; # small Ukrainian yi
|
||||
|
||||
AD B4 ; # small Ukrainian soft g
|
||||
AE A2 ; # small Byelorussian short u
|
||||
|
||||
B0 B0 ; # °
|
||||
|
||||
B3 A8 ; # capital YO
|
||||
B4 AA ; # capital Ukrainian YE
|
||||
|
||||
B6 B2 ; # capital Ukrainian I
|
||||
B7 AF ; # capital Ukrainian YI
|
||||
|
||||
B9 B9 ; # numero sign
|
||||
|
||||
BD A5 ; # capital Ukrainian soft G
|
||||
BE A1 ; # capital Byelorussian short U
|
||||
|
||||
BF A9 ; # (C)
|
||||
|
||||
C0 FE ; # small yu
|
||||
C1 E0 ; # small a
|
||||
C2 E1 ; # small b
|
||||
C3 F6 ; # small ts
|
||||
C4 E4 ; # small d
|
||||
C5 E5 ; # small ye
|
||||
C6 F4 ; # small f
|
||||
C7 E3 ; # small g
|
||||
C8 F5 ; # small kh
|
||||
C9 E8 ; # small i
|
||||
CA E9 ; # small j
|
||||
CB EA ; # small k
|
||||
CC EB ; # small l
|
||||
CD EC ; # small m
|
||||
CE ED ; # small n
|
||||
CF EE ; # small o
|
||||
|
||||
D0 EF ; # small p
|
||||
D1 FF ; # small ya
|
||||
D2 F0 ; # small r
|
||||
D3 F1 ; # small s
|
||||
D4 F2 ; # small t
|
||||
D5 F3 ; # small u
|
||||
D6 E6 ; # small zh
|
||||
D7 E2 ; # small v
|
||||
D8 FC ; # small soft sign
|
||||
D9 FB ; # small y
|
||||
DA E7 ; # small z
|
||||
DB F8 ; # small sh
|
||||
DC FD ; # small e
|
||||
DD F9 ; # small shch
|
||||
DE F7 ; # small ch
|
||||
DF FA ; # small hard sign
|
||||
|
||||
E0 DE ; # capital YU
|
||||
E1 C0 ; # capital A
|
||||
E2 C1 ; # capital B
|
||||
E3 D6 ; # capital TS
|
||||
E4 C4 ; # capital D
|
||||
E5 C5 ; # capital YE
|
||||
E6 D4 ; # capital F
|
||||
E7 C3 ; # capital G
|
||||
E8 D5 ; # capital KH
|
||||
E9 C8 ; # capital I
|
||||
EA C9 ; # capital J
|
||||
EB CA ; # capital K
|
||||
EC CB ; # capital L
|
||||
ED CC ; # capital M
|
||||
EE CD ; # capital N
|
||||
EF CE ; # capital O
|
||||
|
||||
F0 CF ; # capital P
|
||||
F1 DF ; # capital YA
|
||||
F2 D0 ; # capital R
|
||||
F3 D1 ; # capital S
|
||||
F4 D2 ; # capital T
|
||||
F5 D3 ; # capital U
|
||||
F6 C6 ; # capital ZH
|
||||
F7 C2 ; # capital V
|
||||
F8 DC ; # capital soft sign
|
||||
F9 DB ; # capital Y
|
||||
FA C7 ; # capital Z
|
||||
FB D8 ; # capital SH
|
||||
FC DD ; # capital E
|
||||
FD D9 ; # capital SHCH
|
||||
FE D7 ; # capital CH
|
||||
FF DA ; # capital hard sign
|
||||
}
|
99
nginx-1.28.0/conf/mime.types
Normal file
99
nginx-1.28.0/conf/mime.types
Normal file
@@ -0,0 +1,99 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/avif avif;
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/wasm wasm;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
49
nginx-1.28.0/conf/nginx.conf
Normal file
49
nginx-1.28.0/conf/nginx.conf
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# (선택) 로그 위치
|
||||
access_log logs/access.log;
|
||||
error_log logs/error.log warn;
|
||||
|
||||
# 웹소켓용
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# Nuxt(개발서버 3000)
|
||||
location / {
|
||||
proxy_pass http://localhost: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 Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
}
|
||||
|
||||
# Spring Boot(8080) — /service 접두어 제거
|
||||
location /service/ {
|
||||
proxy_pass http://localhost:8080; # 끝에 슬래시 넣으면 /service가 제거됨
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# (선택) 업로드 크게 받을 때
|
||||
# client_max_body_size 50m;
|
||||
}
|
||||
}
|
17
nginx-1.28.0/conf/scgi_params
Normal file
17
nginx-1.28.0/conf/scgi_params
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
scgi_param REQUEST_METHOD $request_method;
|
||||
scgi_param REQUEST_URI $request_uri;
|
||||
scgi_param QUERY_STRING $query_string;
|
||||
scgi_param CONTENT_TYPE $content_type;
|
||||
|
||||
scgi_param DOCUMENT_URI $document_uri;
|
||||
scgi_param DOCUMENT_ROOT $document_root;
|
||||
scgi_param SCGI 1;
|
||||
scgi_param SERVER_PROTOCOL $server_protocol;
|
||||
scgi_param REQUEST_SCHEME $scheme;
|
||||
scgi_param HTTPS $https if_not_empty;
|
||||
|
||||
scgi_param REMOTE_ADDR $remote_addr;
|
||||
scgi_param REMOTE_PORT $remote_port;
|
||||
scgi_param SERVER_PORT $server_port;
|
||||
scgi_param SERVER_NAME $server_name;
|
17
nginx-1.28.0/conf/uwsgi_params
Normal file
17
nginx-1.28.0/conf/uwsgi_params
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
uwsgi_param QUERY_STRING $query_string;
|
||||
uwsgi_param REQUEST_METHOD $request_method;
|
||||
uwsgi_param CONTENT_TYPE $content_type;
|
||||
uwsgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
uwsgi_param REQUEST_URI $request_uri;
|
||||
uwsgi_param PATH_INFO $document_uri;
|
||||
uwsgi_param DOCUMENT_ROOT $document_root;
|
||||
uwsgi_param SERVER_PROTOCOL $server_protocol;
|
||||
uwsgi_param REQUEST_SCHEME $scheme;
|
||||
uwsgi_param HTTPS $https if_not_empty;
|
||||
|
||||
uwsgi_param REMOTE_ADDR $remote_addr;
|
||||
uwsgi_param REMOTE_PORT $remote_port;
|
||||
uwsgi_param SERVER_PORT $server_port;
|
||||
uwsgi_param SERVER_NAME $server_name;
|
126
nginx-1.28.0/conf/win-utf
Normal file
126
nginx-1.28.0/conf/win-utf
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
# This map is not a full windows-1251 <> utf8 map: it does not
|
||||
# contain Serbian and Macedonian letters. If you need a full map,
|
||||
# use contrib/unicode2nginx/win-utf map instead.
|
||||
|
||||
charset_map windows-1251 utf-8 {
|
||||
|
||||
82 E2809A ; # single low-9 quotation mark
|
||||
|
||||
84 E2809E ; # double low-9 quotation mark
|
||||
85 E280A6 ; # ellipsis
|
||||
86 E280A0 ; # dagger
|
||||
87 E280A1 ; # double dagger
|
||||
88 E282AC ; # euro
|
||||
89 E280B0 ; # per mille
|
||||
|
||||
91 E28098 ; # left single quotation mark
|
||||
92 E28099 ; # right single quotation mark
|
||||
93 E2809C ; # left double quotation mark
|
||||
94 E2809D ; # right double quotation mark
|
||||
95 E280A2 ; # bullet
|
||||
96 E28093 ; # en dash
|
||||
97 E28094 ; # em dash
|
||||
|
||||
99 E284A2 ; # trade mark sign
|
||||
|
||||
A0 C2A0 ; #
|
||||
A1 D18E ; # capital Byelorussian short U
|
||||
A2 D19E ; # small Byelorussian short u
|
||||
|
||||
A4 C2A4 ; # currency sign
|
||||
A5 D290 ; # capital Ukrainian soft G
|
||||
A6 C2A6 ; # borken bar
|
||||
A7 C2A7 ; # section sign
|
||||
A8 D081 ; # capital YO
|
||||
A9 C2A9 ; # (C)
|
||||
AA D084 ; # capital Ukrainian YE
|
||||
AB C2AB ; # left-pointing double angle quotation mark
|
||||
AC C2AC ; # not sign
|
||||
AD C2AD ; # soft hyphen
|
||||
AE C2AE ; # (R)
|
||||
AF D087 ; # capital Ukrainian YI
|
||||
|
||||
B0 C2B0 ; # °
|
||||
B1 C2B1 ; # plus-minus sign
|
||||
B2 D086 ; # capital Ukrainian I
|
||||
B3 D196 ; # small Ukrainian i
|
||||
B4 D291 ; # small Ukrainian soft g
|
||||
B5 C2B5 ; # micro sign
|
||||
B6 C2B6 ; # pilcrow sign
|
||||
B7 C2B7 ; # ·
|
||||
B8 D191 ; # small yo
|
||||
B9 E28496 ; # numero sign
|
||||
BA D194 ; # small Ukrainian ye
|
||||
BB C2BB ; # right-pointing double angle quotation mark
|
||||
|
||||
BF D197 ; # small Ukrainian yi
|
||||
|
||||
C0 D090 ; # capital A
|
||||
C1 D091 ; # capital B
|
||||
C2 D092 ; # capital V
|
||||
C3 D093 ; # capital G
|
||||
C4 D094 ; # capital D
|
||||
C5 D095 ; # capital YE
|
||||
C6 D096 ; # capital ZH
|
||||
C7 D097 ; # capital Z
|
||||
C8 D098 ; # capital I
|
||||
C9 D099 ; # capital J
|
||||
CA D09A ; # capital K
|
||||
CB D09B ; # capital L
|
||||
CC D09C ; # capital M
|
||||
CD D09D ; # capital N
|
||||
CE D09E ; # capital O
|
||||
CF D09F ; # capital P
|
||||
|
||||
D0 D0A0 ; # capital R
|
||||
D1 D0A1 ; # capital S
|
||||
D2 D0A2 ; # capital T
|
||||
D3 D0A3 ; # capital U
|
||||
D4 D0A4 ; # capital F
|
||||
D5 D0A5 ; # capital KH
|
||||
D6 D0A6 ; # capital TS
|
||||
D7 D0A7 ; # capital CH
|
||||
D8 D0A8 ; # capital SH
|
||||
D9 D0A9 ; # capital SHCH
|
||||
DA D0AA ; # capital hard sign
|
||||
DB D0AB ; # capital Y
|
||||
DC D0AC ; # capital soft sign
|
||||
DD D0AD ; # capital E
|
||||
DE D0AE ; # capital YU
|
||||
DF D0AF ; # capital YA
|
||||
|
||||
E0 D0B0 ; # small a
|
||||
E1 D0B1 ; # small b
|
||||
E2 D0B2 ; # small v
|
||||
E3 D0B3 ; # small g
|
||||
E4 D0B4 ; # small d
|
||||
E5 D0B5 ; # small ye
|
||||
E6 D0B6 ; # small zh
|
||||
E7 D0B7 ; # small z
|
||||
E8 D0B8 ; # small i
|
||||
E9 D0B9 ; # small j
|
||||
EA D0BA ; # small k
|
||||
EB D0BB ; # small l
|
||||
EC D0BC ; # small m
|
||||
ED D0BD ; # small n
|
||||
EE D0BE ; # small o
|
||||
EF D0BF ; # small p
|
||||
|
||||
F0 D180 ; # small r
|
||||
F1 D181 ; # small s
|
||||
F2 D182 ; # small t
|
||||
F3 D183 ; # small u
|
||||
F4 D184 ; # small f
|
||||
F5 D185 ; # small kh
|
||||
F6 D186 ; # small ts
|
||||
F7 D187 ; # small ch
|
||||
F8 D188 ; # small sh
|
||||
F9 D189 ; # small shch
|
||||
FA D18A ; # small hard sign
|
||||
FB D18B ; # small y
|
||||
FC D18C ; # small soft sign
|
||||
FD D18D ; # small e
|
||||
FE D18E ; # small yu
|
||||
FF D18F ; # small ya
|
||||
}
|
21
nginx-1.28.0/contrib/README
Normal file
21
nginx-1.28.0/contrib/README
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
geo2nginx.pl by Andrei Nigmatulin
|
||||
|
||||
The perl script to convert CSV geoip database ( free download
|
||||
at http://www.maxmind.com/app/geoip_country ) to format, suitable
|
||||
for use by the ngx_http_geo_module.
|
||||
|
||||
|
||||
unicode2nginx by Maxim Dounin
|
||||
|
||||
The perl script to convert unicode mappings ( available
|
||||
at http://www.unicode.org/Public/MAPPINGS/ ) to the nginx
|
||||
configuration file format.
|
||||
Two generated full maps for windows-1251 and koi8-r.
|
||||
|
||||
|
||||
vim by Evan Miller
|
||||
|
||||
Syntax highlighting of nginx configuration for vim, to be
|
||||
placed into ~/.vim/.
|
||||
|
58
nginx-1.28.0/contrib/geo2nginx.pl
Normal file
58
nginx-1.28.0/contrib/geo2nginx.pl
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# (c) Andrei Nigmatulin, 2005
|
||||
#
|
||||
# this script provided "as is", without any warranties. use it at your own risk.
|
||||
#
|
||||
# special thanx to Andrew Sitnikov for perl port
|
||||
#
|
||||
# this script converts CSV geoip database (free download at http://www.maxmind.com/app/geoip_country)
|
||||
# to format, suitable for use with nginx_http_geo module (http://sysoev.ru/nginx)
|
||||
#
|
||||
# for example, line with ip range
|
||||
#
|
||||
# "62.16.68.0","62.16.127.255","1041253376","1041268735","RU","Russian Federation"
|
||||
#
|
||||
# will be converted to four subnetworks:
|
||||
#
|
||||
# 62.16.68.0/22 RU;
|
||||
# 62.16.72.0/21 RU;
|
||||
# 62.16.80.0/20 RU;
|
||||
# 62.16.96.0/19 RU;
|
||||
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
while( <STDIN> ){
|
||||
if (/"[^"]+","[^"]+","([^"]+)","([^"]+)","([^"]+)"/){
|
||||
print_subnets($1, $2, $3);
|
||||
}
|
||||
}
|
||||
|
||||
sub print_subnets {
|
||||
my ($a1, $a2, $c) = @_;
|
||||
my $l;
|
||||
while ($a1 <= $a2) {
|
||||
for ($l = 0; ($a1 & (1 << $l)) == 0 && ($a1 + ((1 << ($l + 1)) - 1)) <= $a2; $l++){};
|
||||
print long2ip($a1) . "/" . (32 - $l) . " " . $c . ";\n";
|
||||
$a1 += (1 << $l);
|
||||
}
|
||||
}
|
||||
|
||||
sub long2ip {
|
||||
my $ip = shift;
|
||||
|
||||
my $str = 0;
|
||||
|
||||
$str = ($ip & 255);
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
|
||||
$ip >>= 8;
|
||||
$str = ($ip & 255).".$str";
|
||||
}
|
131
nginx-1.28.0/contrib/unicode2nginx/koi-utf
Normal file
131
nginx-1.28.0/contrib/unicode2nginx/koi-utf
Normal file
@@ -0,0 +1,131 @@
|
||||
charset_map koi8-r utf-8 {
|
||||
|
||||
80 E29480 ; # BOX DRAWINGS LIGHT HORIZONTAL
|
||||
81 E29482 ; # BOX DRAWINGS LIGHT VERTICAL
|
||||
82 E2948C ; # BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
83 E29490 ; # BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
84 E29494 ; # BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
85 E29498 ; # BOX DRAWINGS LIGHT UP AND LEFT
|
||||
86 E2949C ; # BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
87 E294A4 ; # BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
88 E294AC ; # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
89 E294B4 ; # BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
8A E294BC ; # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
8B E29680 ; # UPPER HALF BLOCK
|
||||
8C E29684 ; # LOWER HALF BLOCK
|
||||
8D E29688 ; # FULL BLOCK
|
||||
8E E2968C ; # LEFT HALF BLOCK
|
||||
8F E29690 ; # RIGHT HALF BLOCK
|
||||
90 E29691 ; # LIGHT SHADE
|
||||
91 E29692 ; # MEDIUM SHADE
|
||||
92 E29693 ; # DARK SHADE
|
||||
93 E28CA0 ; # TOP HALF INTEGRAL
|
||||
94 E296A0 ; # BLACK SQUARE
|
||||
95 E28899 ; # BULLET OPERATOR
|
||||
96 E2889A ; # SQUARE ROOT
|
||||
97 E28988 ; # ALMOST EQUAL TO
|
||||
98 E289A4 ; # LESS-THAN OR EQUAL TO
|
||||
99 E289A5 ; # GREATER-THAN OR EQUAL TO
|
||||
9A C2A0 ; # NO-BREAK SPACE
|
||||
9B E28CA1 ; # BOTTOM HALF INTEGRAL
|
||||
9C C2B0 ; # DEGREE SIGN
|
||||
9D C2B2 ; # SUPERSCRIPT TWO
|
||||
9E C2B7 ; # MIDDLE DOT
|
||||
9F C3B7 ; # DIVISION SIGN
|
||||
A0 E29590 ; # BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
A1 E29591 ; # BOX DRAWINGS DOUBLE VERTICAL
|
||||
A2 E29592 ; # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
A3 D191 ; # CYRILLIC SMALL LETTER IO
|
||||
A4 E29593 ; # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
A5 E29594 ; # BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
A6 E29595 ; # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
A7 E29596 ; # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
A8 E29597 ; # BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
A9 E29598 ; # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
AA E29599 ; # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
AB E2959A ; # BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
AC E2959B ; # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
AD E2959C ; # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
AE E2959D ; # BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
AF E2959E ; # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
B0 E2959F ; # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
B1 E295A0 ; # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
B2 E295A1 ; # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
B3 D081 ; # CYRILLIC CAPITAL LETTER IO
|
||||
B4 E295A2 ; # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
B5 E295A3 ; # BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
B6 E295A4 ; # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
B7 E295A5 ; # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
B8 E295A6 ; # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
B9 E295A7 ; # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
BA E295A8 ; # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
BB E295A9 ; # BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
BC E295AA ; # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
BD E295AB ; # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
BE E295AC ; # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
BF C2A9 ; # COPYRIGHT SIGN
|
||||
C0 D18E ; # CYRILLIC SMALL LETTER YU
|
||||
C1 D0B0 ; # CYRILLIC SMALL LETTER A
|
||||
C2 D0B1 ; # CYRILLIC SMALL LETTER BE
|
||||
C3 D186 ; # CYRILLIC SMALL LETTER TSE
|
||||
C4 D0B4 ; # CYRILLIC SMALL LETTER DE
|
||||
C5 D0B5 ; # CYRILLIC SMALL LETTER IE
|
||||
C6 D184 ; # CYRILLIC SMALL LETTER EF
|
||||
C7 D0B3 ; # CYRILLIC SMALL LETTER GHE
|
||||
C8 D185 ; # CYRILLIC SMALL LETTER HA
|
||||
C9 D0B8 ; # CYRILLIC SMALL LETTER I
|
||||
CA D0B9 ; # CYRILLIC SMALL LETTER SHORT I
|
||||
CB D0BA ; # CYRILLIC SMALL LETTER KA
|
||||
CC D0BB ; # CYRILLIC SMALL LETTER EL
|
||||
CD D0BC ; # CYRILLIC SMALL LETTER EM
|
||||
CE D0BD ; # CYRILLIC SMALL LETTER EN
|
||||
CF D0BE ; # CYRILLIC SMALL LETTER O
|
||||
D0 D0BF ; # CYRILLIC SMALL LETTER PE
|
||||
D1 D18F ; # CYRILLIC SMALL LETTER YA
|
||||
D2 D180 ; # CYRILLIC SMALL LETTER ER
|
||||
D3 D181 ; # CYRILLIC SMALL LETTER ES
|
||||
D4 D182 ; # CYRILLIC SMALL LETTER TE
|
||||
D5 D183 ; # CYRILLIC SMALL LETTER U
|
||||
D6 D0B6 ; # CYRILLIC SMALL LETTER ZHE
|
||||
D7 D0B2 ; # CYRILLIC SMALL LETTER VE
|
||||
D8 D18C ; # CYRILLIC SMALL LETTER SOFT SIGN
|
||||
D9 D18B ; # CYRILLIC SMALL LETTER YERU
|
||||
DA D0B7 ; # CYRILLIC SMALL LETTER ZE
|
||||
DB D188 ; # CYRILLIC SMALL LETTER SHA
|
||||
DC D18D ; # CYRILLIC SMALL LETTER E
|
||||
DD D189 ; # CYRILLIC SMALL LETTER SHCHA
|
||||
DE D187 ; # CYRILLIC SMALL LETTER CHE
|
||||
DF D18A ; # CYRILLIC SMALL LETTER HARD SIGN
|
||||
E0 D0AE ; # CYRILLIC CAPITAL LETTER YU
|
||||
E1 D090 ; # CYRILLIC CAPITAL LETTER A
|
||||
E2 D091 ; # CYRILLIC CAPITAL LETTER BE
|
||||
E3 D0A6 ; # CYRILLIC CAPITAL LETTER TSE
|
||||
E4 D094 ; # CYRILLIC CAPITAL LETTER DE
|
||||
E5 D095 ; # CYRILLIC CAPITAL LETTER IE
|
||||
E6 D0A4 ; # CYRILLIC CAPITAL LETTER EF
|
||||
E7 D093 ; # CYRILLIC CAPITAL LETTER GHE
|
||||
E8 D0A5 ; # CYRILLIC CAPITAL LETTER HA
|
||||
E9 D098 ; # CYRILLIC CAPITAL LETTER I
|
||||
EA D099 ; # CYRILLIC CAPITAL LETTER SHORT I
|
||||
EB D09A ; # CYRILLIC CAPITAL LETTER KA
|
||||
EC D09B ; # CYRILLIC CAPITAL LETTER EL
|
||||
ED D09C ; # CYRILLIC CAPITAL LETTER EM
|
||||
EE D09D ; # CYRILLIC CAPITAL LETTER EN
|
||||
EF D09E ; # CYRILLIC CAPITAL LETTER O
|
||||
F0 D09F ; # CYRILLIC CAPITAL LETTER PE
|
||||
F1 D0AF ; # CYRILLIC CAPITAL LETTER YA
|
||||
F2 D0A0 ; # CYRILLIC CAPITAL LETTER ER
|
||||
F3 D0A1 ; # CYRILLIC CAPITAL LETTER ES
|
||||
F4 D0A2 ; # CYRILLIC CAPITAL LETTER TE
|
||||
F5 D0A3 ; # CYRILLIC CAPITAL LETTER U
|
||||
F6 D096 ; # CYRILLIC CAPITAL LETTER ZHE
|
||||
F7 D092 ; # CYRILLIC CAPITAL LETTER VE
|
||||
F8 D0AC ; # CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||
F9 D0AB ; # CYRILLIC CAPITAL LETTER YERU
|
||||
FA D097 ; # CYRILLIC CAPITAL LETTER ZE
|
||||
FB D0A8 ; # CYRILLIC CAPITAL LETTER SHA
|
||||
FC D0AD ; # CYRILLIC CAPITAL LETTER E
|
||||
FD D0A9 ; # CYRILLIC CAPITAL LETTER SHCHA
|
||||
FE D0A7 ; # CYRILLIC CAPITAL LETTER CHE
|
||||
FF D0AA ; # CYRILLIC CAPITAL LETTER HARD SIGN
|
||||
}
|
48
nginx-1.28.0/contrib/unicode2nginx/unicode-to-nginx.pl
Normal file
48
nginx-1.28.0/contrib/unicode2nginx/unicode-to-nginx.pl
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
# Convert unicode mappings to nginx configuration file format.
|
||||
|
||||
# You may find useful mappings in various places, including
|
||||
# unicode.org official site:
|
||||
#
|
||||
# http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1251.TXT
|
||||
# http://www.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT
|
||||
|
||||
# Needs perl 5.6 or later.
|
||||
|
||||
# Written by Maxim Dounin, mdounin@mdounin.ru
|
||||
|
||||
###############################################################################
|
||||
|
||||
require 5.006;
|
||||
|
||||
while (<>) {
|
||||
# Skip comments and empty lines
|
||||
|
||||
next if /^#/;
|
||||
next if /^\s*$/;
|
||||
chomp;
|
||||
|
||||
# Convert mappings
|
||||
|
||||
if (/^\s*0x(..)\s*0x(....)\s*(#.*)/) {
|
||||
# Mapping <from-code> <unicode-code> "#" <unicode-name>
|
||||
my $cs_code = $1;
|
||||
my $un_code = $2;
|
||||
my $un_name = $3;
|
||||
|
||||
# Produce UTF-8 sequence from character code;
|
||||
|
||||
my $un_utf8 = join('',
|
||||
map { sprintf("%02X", $_) }
|
||||
unpack("U0C*", pack("U", hex($un_code)))
|
||||
);
|
||||
|
||||
print " $cs_code $un_utf8 ; $un_name\n";
|
||||
|
||||
} else {
|
||||
warn "Unrecognized line: '$_'";
|
||||
}
|
||||
}
|
||||
|
||||
###############################################################################
|
130
nginx-1.28.0/contrib/unicode2nginx/win-utf
Normal file
130
nginx-1.28.0/contrib/unicode2nginx/win-utf
Normal file
@@ -0,0 +1,130 @@
|
||||
charset_map windows-1251 utf-8 {
|
||||
|
||||
80 D082 ; #CYRILLIC CAPITAL LETTER DJE
|
||||
81 D083 ; #CYRILLIC CAPITAL LETTER GJE
|
||||
82 E2809A ; #SINGLE LOW-9 QUOTATION MARK
|
||||
83 D193 ; #CYRILLIC SMALL LETTER GJE
|
||||
84 E2809E ; #DOUBLE LOW-9 QUOTATION MARK
|
||||
85 E280A6 ; #HORIZONTAL ELLIPSIS
|
||||
86 E280A0 ; #DAGGER
|
||||
87 E280A1 ; #DOUBLE DAGGER
|
||||
88 E282AC ; #EURO SIGN
|
||||
89 E280B0 ; #PER MILLE SIGN
|
||||
8A D089 ; #CYRILLIC CAPITAL LETTER LJE
|
||||
8B E280B9 ; #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
8C D08A ; #CYRILLIC CAPITAL LETTER NJE
|
||||
8D D08C ; #CYRILLIC CAPITAL LETTER KJE
|
||||
8E D08B ; #CYRILLIC CAPITAL LETTER TSHE
|
||||
8F D08F ; #CYRILLIC CAPITAL LETTER DZHE
|
||||
90 D192 ; #CYRILLIC SMALL LETTER DJE
|
||||
91 E28098 ; #LEFT SINGLE QUOTATION MARK
|
||||
92 E28099 ; #RIGHT SINGLE QUOTATION MARK
|
||||
93 E2809C ; #LEFT DOUBLE QUOTATION MARK
|
||||
94 E2809D ; #RIGHT DOUBLE QUOTATION MARK
|
||||
95 E280A2 ; #BULLET
|
||||
96 E28093 ; #EN DASH
|
||||
97 E28094 ; #EM DASH
|
||||
99 E284A2 ; #TRADE MARK SIGN
|
||||
9A D199 ; #CYRILLIC SMALL LETTER LJE
|
||||
9B E280BA ; #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
9C D19A ; #CYRILLIC SMALL LETTER NJE
|
||||
9D D19C ; #CYRILLIC SMALL LETTER KJE
|
||||
9E D19B ; #CYRILLIC SMALL LETTER TSHE
|
||||
9F D19F ; #CYRILLIC SMALL LETTER DZHE
|
||||
A0 C2A0 ; #NO-BREAK SPACE
|
||||
A1 D08E ; #CYRILLIC CAPITAL LETTER SHORT U
|
||||
A2 D19E ; #CYRILLIC SMALL LETTER SHORT U
|
||||
A3 D088 ; #CYRILLIC CAPITAL LETTER JE
|
||||
A4 C2A4 ; #CURRENCY SIGN
|
||||
A5 D290 ; #CYRILLIC CAPITAL LETTER GHE WITH UPTURN
|
||||
A6 C2A6 ; #BROKEN BAR
|
||||
A7 C2A7 ; #SECTION SIGN
|
||||
A8 D081 ; #CYRILLIC CAPITAL LETTER IO
|
||||
A9 C2A9 ; #COPYRIGHT SIGN
|
||||
AA D084 ; #CYRILLIC CAPITAL LETTER UKRAINIAN IE
|
||||
AB C2AB ; #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
AC C2AC ; #NOT SIGN
|
||||
AD C2AD ; #SOFT HYPHEN
|
||||
AE C2AE ; #REGISTERED SIGN
|
||||
AF D087 ; #CYRILLIC CAPITAL LETTER YI
|
||||
B0 C2B0 ; #DEGREE SIGN
|
||||
B1 C2B1 ; #PLUS-MINUS SIGN
|
||||
B2 D086 ; #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
B3 D196 ; #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
|
||||
B4 D291 ; #CYRILLIC SMALL LETTER GHE WITH UPTURN
|
||||
B5 C2B5 ; #MICRO SIGN
|
||||
B6 C2B6 ; #PILCROW SIGN
|
||||
B7 C2B7 ; #MIDDLE DOT
|
||||
B8 D191 ; #CYRILLIC SMALL LETTER IO
|
||||
B9 E28496 ; #NUMERO SIGN
|
||||
BA D194 ; #CYRILLIC SMALL LETTER UKRAINIAN IE
|
||||
BB C2BB ; #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
BC D198 ; #CYRILLIC SMALL LETTER JE
|
||||
BD D085 ; #CYRILLIC CAPITAL LETTER DZE
|
||||
BE D195 ; #CYRILLIC SMALL LETTER DZE
|
||||
BF D197 ; #CYRILLIC SMALL LETTER YI
|
||||
C0 D090 ; #CYRILLIC CAPITAL LETTER A
|
||||
C1 D091 ; #CYRILLIC CAPITAL LETTER BE
|
||||
C2 D092 ; #CYRILLIC CAPITAL LETTER VE
|
||||
C3 D093 ; #CYRILLIC CAPITAL LETTER GHE
|
||||
C4 D094 ; #CYRILLIC CAPITAL LETTER DE
|
||||
C5 D095 ; #CYRILLIC CAPITAL LETTER IE
|
||||
C6 D096 ; #CYRILLIC CAPITAL LETTER ZHE
|
||||
C7 D097 ; #CYRILLIC CAPITAL LETTER ZE
|
||||
C8 D098 ; #CYRILLIC CAPITAL LETTER I
|
||||
C9 D099 ; #CYRILLIC CAPITAL LETTER SHORT I
|
||||
CA D09A ; #CYRILLIC CAPITAL LETTER KA
|
||||
CB D09B ; #CYRILLIC CAPITAL LETTER EL
|
||||
CC D09C ; #CYRILLIC CAPITAL LETTER EM
|
||||
CD D09D ; #CYRILLIC CAPITAL LETTER EN
|
||||
CE D09E ; #CYRILLIC CAPITAL LETTER O
|
||||
CF D09F ; #CYRILLIC CAPITAL LETTER PE
|
||||
D0 D0A0 ; #CYRILLIC CAPITAL LETTER ER
|
||||
D1 D0A1 ; #CYRILLIC CAPITAL LETTER ES
|
||||
D2 D0A2 ; #CYRILLIC CAPITAL LETTER TE
|
||||
D3 D0A3 ; #CYRILLIC CAPITAL LETTER U
|
||||
D4 D0A4 ; #CYRILLIC CAPITAL LETTER EF
|
||||
D5 D0A5 ; #CYRILLIC CAPITAL LETTER HA
|
||||
D6 D0A6 ; #CYRILLIC CAPITAL LETTER TSE
|
||||
D7 D0A7 ; #CYRILLIC CAPITAL LETTER CHE
|
||||
D8 D0A8 ; #CYRILLIC CAPITAL LETTER SHA
|
||||
D9 D0A9 ; #CYRILLIC CAPITAL LETTER SHCHA
|
||||
DA D0AA ; #CYRILLIC CAPITAL LETTER HARD SIGN
|
||||
DB D0AB ; #CYRILLIC CAPITAL LETTER YERU
|
||||
DC D0AC ; #CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||
DD D0AD ; #CYRILLIC CAPITAL LETTER E
|
||||
DE D0AE ; #CYRILLIC CAPITAL LETTER YU
|
||||
DF D0AF ; #CYRILLIC CAPITAL LETTER YA
|
||||
E0 D0B0 ; #CYRILLIC SMALL LETTER A
|
||||
E1 D0B1 ; #CYRILLIC SMALL LETTER BE
|
||||
E2 D0B2 ; #CYRILLIC SMALL LETTER VE
|
||||
E3 D0B3 ; #CYRILLIC SMALL LETTER GHE
|
||||
E4 D0B4 ; #CYRILLIC SMALL LETTER DE
|
||||
E5 D0B5 ; #CYRILLIC SMALL LETTER IE
|
||||
E6 D0B6 ; #CYRILLIC SMALL LETTER ZHE
|
||||
E7 D0B7 ; #CYRILLIC SMALL LETTER ZE
|
||||
E8 D0B8 ; #CYRILLIC SMALL LETTER I
|
||||
E9 D0B9 ; #CYRILLIC SMALL LETTER SHORT I
|
||||
EA D0BA ; #CYRILLIC SMALL LETTER KA
|
||||
EB D0BB ; #CYRILLIC SMALL LETTER EL
|
||||
EC D0BC ; #CYRILLIC SMALL LETTER EM
|
||||
ED D0BD ; #CYRILLIC SMALL LETTER EN
|
||||
EE D0BE ; #CYRILLIC SMALL LETTER O
|
||||
EF D0BF ; #CYRILLIC SMALL LETTER PE
|
||||
F0 D180 ; #CYRILLIC SMALL LETTER ER
|
||||
F1 D181 ; #CYRILLIC SMALL LETTER ES
|
||||
F2 D182 ; #CYRILLIC SMALL LETTER TE
|
||||
F3 D183 ; #CYRILLIC SMALL LETTER U
|
||||
F4 D184 ; #CYRILLIC SMALL LETTER EF
|
||||
F5 D185 ; #CYRILLIC SMALL LETTER HA
|
||||
F6 D186 ; #CYRILLIC SMALL LETTER TSE
|
||||
F7 D187 ; #CYRILLIC SMALL LETTER CHE
|
||||
F8 D188 ; #CYRILLIC SMALL LETTER SHA
|
||||
F9 D189 ; #CYRILLIC SMALL LETTER SHCHA
|
||||
FA D18A ; #CYRILLIC SMALL LETTER HARD SIGN
|
||||
FB D18B ; #CYRILLIC SMALL LETTER YERU
|
||||
FC D18C ; #CYRILLIC SMALL LETTER SOFT SIGN
|
||||
FD D18D ; #CYRILLIC SMALL LETTER E
|
||||
FE D18E ; #CYRILLIC SMALL LETTER YU
|
||||
FF D18F ; #CYRILLIC SMALL LETTER YA
|
||||
}
|
4
nginx-1.28.0/contrib/vim/ftdetect/nginx.vim
Normal file
4
nginx-1.28.0/contrib/vim/ftdetect/nginx.vim
Normal file
@@ -0,0 +1,4 @@
|
||||
au BufRead,BufNewFile *.nginx set ft=nginx
|
||||
au BufRead,BufNewFile */etc/nginx/* set ft=nginx
|
||||
au BufRead,BufNewFile */usr/local/nginx/conf/* set ft=nginx
|
||||
au BufRead,BufNewFile nginx.conf set ft=nginx
|
1
nginx-1.28.0/contrib/vim/ftplugin/nginx.vim
Normal file
1
nginx-1.28.0/contrib/vim/ftplugin/nginx.vim
Normal file
@@ -0,0 +1 @@
|
||||
setlocal commentstring=#\ %s
|
11
nginx-1.28.0/contrib/vim/indent/nginx.vim
Normal file
11
nginx-1.28.0/contrib/vim/indent/nginx.vim
Normal file
@@ -0,0 +1,11 @@
|
||||
if exists("b:did_indent")
|
||||
finish
|
||||
endif
|
||||
let b:did_indent = 1
|
||||
|
||||
setlocal indentexpr=
|
||||
|
||||
" cindent actually works for nginx' simple file structure
|
||||
setlocal cindent
|
||||
" Just make sure that the comments are not reset as defs would be.
|
||||
setlocal cinkeys-=0#
|
1979
nginx-1.28.0/contrib/vim/syntax/nginx.vim
Normal file
1979
nginx-1.28.0/contrib/vim/syntax/nginx.vim
Normal file
File diff suppressed because it is too large
Load Diff
9290
nginx-1.28.0/docs/CHANGES
Normal file
9290
nginx-1.28.0/docs/CHANGES
Normal file
File diff suppressed because it is too large
Load Diff
9453
nginx-1.28.0/docs/CHANGES.ru
Normal file
9453
nginx-1.28.0/docs/CHANGES.ru
Normal file
File diff suppressed because it is too large
Load Diff
126
nginx-1.28.0/docs/CODE_OF_CONDUCT.md
Normal file
126
nginx-1.28.0/docs/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes
|
||||
and learning from the experience
|
||||
- Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances
|
||||
of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards
|
||||
of acceptable behavior and will take appropriate and fair corrective action
|
||||
in response to any behavior that they deem inappropriate, threatening,
|
||||
offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for
|
||||
moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
<nginx-oss-community@f5.com>. All complaints will be reviewed and investigated
|
||||
promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external
|
||||
channels like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the
|
||||
[Contributor Covenant](https://www.contributor-covenant.org), version 2.1,
|
||||
available at
|
||||
<https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion).
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
<https://www.contributor-covenant.org/faq>. Translations are available at
|
||||
<https://www.contributor-covenant.org/translations>.
|
110
nginx-1.28.0/docs/CONTRIBUTING.md
Normal file
110
nginx-1.28.0/docs/CONTRIBUTING.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Contributing Guidelines
|
||||
|
||||
The following is a set of guidelines for contributing to nginx project.
|
||||
We really appreciate that you are considering contributing!
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Ask a Question](#ask-a-question)
|
||||
- [Report a Bug](#report-a-bug)
|
||||
- [Suggest a Feature or Enhancement](#suggest-a-feature-or-enhancement)
|
||||
- [Open a Discussion](#open-a-discussion)
|
||||
- [Submit a Pull Request](#submit-a-pull-request)
|
||||
- [Issue Lifecycle](#issue-lifecycle)
|
||||
|
||||
## Ask a Question
|
||||
|
||||
To ask a question, open an issue on GitHub with the label `question`.
|
||||
|
||||
## Report a Bug
|
||||
|
||||
To report a bug, open an issue on GitHub with the label `bug` using the
|
||||
available bug report issue template. Before reporting a bug, make sure the
|
||||
issue has not already been reported.
|
||||
|
||||
## Suggest a Feature or Enhancement
|
||||
|
||||
To suggest a feature or enhancement, open an issue on GitHub with the label
|
||||
`feature` or `enhancement` using the available feature request issue template.
|
||||
Please ensure the feature or enhancement has not already been suggested.
|
||||
|
||||
## Open a Discussion
|
||||
|
||||
If you want to engage in a conversation with the community and maintainers,
|
||||
we encourage you to use
|
||||
[GitHub Discussions](https://github.com/nginx/nginx/discussions).
|
||||
|
||||
## Submit a Pull Request
|
||||
|
||||
Follow this plan to contribute a change to NGINX source code:
|
||||
|
||||
- Fork the NGINX repository
|
||||
- Create a branch
|
||||
- Implement your changes in this branch
|
||||
- Submit a pull request (PR) when your changes are tested and ready for review
|
||||
|
||||
Refer to
|
||||
[NGINX Development Guide](https://nginx.org/en/docs/dev/development_guide.html)
|
||||
for questions about NGINX programming.
|
||||
|
||||
### Formatting Changes
|
||||
|
||||
- Changes should be formatted according to the
|
||||
[code style](https://nginx.org/en/docs/dev/development_guide.html#code_style)
|
||||
used by NGINX; sometimes, there is no clear rule, in which case examine how
|
||||
existing NGINX sources are formatted and mimic this style; changes will more
|
||||
likely be accepted if style corresponds to the surrounding code
|
||||
|
||||
- Keep a clean, concise and meaningful commit history on your branch, rebasing
|
||||
locally and breaking changes logically into commits before submitting a PR
|
||||
|
||||
- Each commit message should have a single-line subject line followed by verbose
|
||||
description after an empty line
|
||||
|
||||
- Limit the subject line to 67 characters, and the rest of the commit message
|
||||
to 76 characters
|
||||
|
||||
- Use subject line prefixes for commits that affect a specific portion of the
|
||||
code; examples include "Upstream:", "QUIC:", or "Core:"; see the commit history
|
||||
to get an idea of the prefixes used
|
||||
|
||||
- Reference issues in the the subject line; if the commit fixes an issue,
|
||||
[name it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
|
||||
accordingly
|
||||
|
||||
### Before Submitting
|
||||
|
||||
- The proposed changes should work properly on a wide range of
|
||||
[supported platforms](https://nginx.org/en/index.html#tested_os_and_platforms)
|
||||
|
||||
- Try to make it clear why the suggested change is needed, and provide a use
|
||||
case, if possible
|
||||
|
||||
- Passing your changes through the test suite is a good way to ensure that they
|
||||
do not cause a regression; the repository with tests can be cloned with the
|
||||
following command:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nginx/nginx-tests.git
|
||||
```
|
||||
|
||||
- Submitting a change implies granting project a permission to use it under the
|
||||
[BSD-2-Clause license](https://github.com/nginx/nginx/blob/master/LICENSE)
|
||||
|
||||
## Issue Lifecycle
|
||||
|
||||
To ensure a balance between work carried out by the NGINX engineering team
|
||||
while encouraging community involvement on this project, we use the following
|
||||
issue lifecycle:
|
||||
|
||||
- A new issue is created by a community member
|
||||
|
||||
- An owner on the NGINX engineering team is assigned to the issue; this
|
||||
owner shepherds the issue through the subsequent stages in the issue lifecycle
|
||||
|
||||
- The owner assigns one or more
|
||||
[labels](https://github.com/nginx/nginx/issues/labels) to the issue
|
||||
|
||||
- The owner, in collaboration with the wider team (product management and
|
||||
engineering), determines what milestone to attach to an issue;
|
||||
generally, milestones correspond to product releases
|
24
nginx-1.28.0/docs/LICENSE
Normal file
24
nginx-1.28.0/docs/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (C) 2002-2021 Igor Sysoev
|
||||
Copyright (C) 2011-2025 Nginx, Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
177
nginx-1.28.0/docs/OpenSSL.LICENSE
Normal file
177
nginx-1.28.0/docs/OpenSSL.LICENSE
Normal file
@@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
94
nginx-1.28.0/docs/PCRE.LICENCE
Normal file
94
nginx-1.28.0/docs/PCRE.LICENCE
Normal file
@@ -0,0 +1,94 @@
|
||||
PCRE2 LICENCE
|
||||
-------------
|
||||
|
||||
PCRE2 is a library of functions to support regular expressions whose syntax
|
||||
and semantics are as close as possible to those of the Perl 5 language.
|
||||
|
||||
Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD"
|
||||
licence, as specified below, with one exemption for certain binary
|
||||
redistributions. The documentation for PCRE2, supplied in the "doc" directory,
|
||||
is distributed under the same terms as the software itself. The data in the
|
||||
testdata directory is not copyrighted and is in the public domain.
|
||||
|
||||
The basic library functions are written in C and are freestanding. Also
|
||||
included in the distribution is a just-in-time compiler that can be used to
|
||||
optimize pattern matching. This is an optional feature that can be omitted when
|
||||
the library is built.
|
||||
|
||||
|
||||
THE BASIC LIBRARY FUNCTIONS
|
||||
---------------------------
|
||||
|
||||
Written by: Philip Hazel
|
||||
Email local part: Philip.Hazel
|
||||
Email domain: gmail.com
|
||||
|
||||
Retired from University of Cambridge Computing Service,
|
||||
Cambridge, England.
|
||||
|
||||
Copyright (c) 1997-2021 University of Cambridge
|
||||
All rights reserved.
|
||||
|
||||
|
||||
PCRE2 JUST-IN-TIME COMPILATION SUPPORT
|
||||
--------------------------------------
|
||||
|
||||
Written by: Zoltan Herczeg
|
||||
Email local part: hzmester
|
||||
Email domain: freemail.hu
|
||||
|
||||
Copyright(c) 2010-2021 Zoltan Herczeg
|
||||
All rights reserved.
|
||||
|
||||
|
||||
STACK-LESS JUST-IN-TIME COMPILER
|
||||
--------------------------------
|
||||
|
||||
Written by: Zoltan Herczeg
|
||||
Email local part: hzmester
|
||||
Email domain: freemail.hu
|
||||
|
||||
Copyright(c) 2009-2021 Zoltan Herczeg
|
||||
All rights reserved.
|
||||
|
||||
|
||||
THE "BSD" LICENCE
|
||||
-----------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notices,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notices, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the University of Cambridge nor the names of any
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES
|
||||
------------------------------------------
|
||||
|
||||
The second condition in the BSD licence (covering binary redistributions) does
|
||||
not apply all the way down a chain of software. If binary package A includes
|
||||
PCRE2, it must respect the condition, but if package B is software that
|
||||
includes package A, the condition is not imposed on package B unless it uses
|
||||
PCRE2 independently.
|
||||
|
||||
End
|
230
nginx-1.28.0/docs/README.md
Normal file
230
nginx-1.28.0/docs/README.md
Normal file
@@ -0,0 +1,230 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/9335b488-ffcc-4157-8364-2370a0b70ad0">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/3a7eeb08-1133-47f5-859c-fad4f5a6a013">
|
||||
<img alt="NGINX Banner">
|
||||
</picture>
|
||||
|
||||
NGINX (pronounced "engine x" or "en-jin-eks") is the world's most popular Web Server, high performance Load Balancer, Reverse Proxy, API Gateway and Content Cache.
|
||||
|
||||
NGINX is free and open source software, distributed under the terms of a simplified [2-clause BSD-like license](LICENSE).
|
||||
|
||||
Enterprise distributions, commercial support and training are available from [F5, Inc](https://www.f5.com/products/nginx).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The goal of this README is to provide a basic, structured introduction to NGINX for novice users. Please refer to the [full NGINX documentation](https://nginx.org/en/docs/) for detailed information on [installing](https://nginx.org/en/docs/install.html), [building](https://nginx.org/en/docs/configure.html), [configuring](https://nginx.org/en/docs/dirindex.html), [debugging](https://nginx.org/en/docs/debugging_log.html), and more. These documentation pages also contain a more detailed [Beginners Guide](https://nginx.org/en/docs/beginners_guide.html), How-Tos, [Development guide](https://nginx.org/en/docs/dev/development_guide.html), and a complete module and [directive reference](https://nginx.org/en/docs/dirindex.html).
|
||||
|
||||
# Table of contents
|
||||
- [How it works](#how-it-works)
|
||||
- [Modules](#modules)
|
||||
- [Configurations](#configurations)
|
||||
- [Runtime](#runtime)
|
||||
- [Downloading and installing](#downloading-and-installing)
|
||||
- [Stable and Mainline binaries](#stable-and-mainline-binaries)
|
||||
- [Linux binary installation process](#linux-binary-installation-process)
|
||||
- [FreeBSD installation process](#freebsd-installation-process)
|
||||
- [Windows executables](#windows-executables)
|
||||
- [Dynamic modules](#dynamic-modules)
|
||||
- [Getting started with NGINX](#getting-started-with-nginx)
|
||||
- [Installing SSL certificates and enabling TLS encryption](#installing-ssl-certificates-and-enabling-tls-encryption)
|
||||
- [Load Balancing](#load-balancing)
|
||||
- [Rate limiting](#rate-limiting)
|
||||
- [Content caching](#content-caching)
|
||||
- [Building from source](#building-from-source)
|
||||
- [Installing dependencies](#installing-dependencies)
|
||||
- [Cloning the NGINX GitHub repository](#cloning-the-nginx-github-repository)
|
||||
- [Configuring the build](#configuring-the-build)
|
||||
- [Compiling](#compiling)
|
||||
- [Location of binary and installation](#location-of-binary-and-installation)
|
||||
- [Running and testing the installed binary](#running-and-testing-the-installed-binary)
|
||||
- [Asking questions and reporting issues](#asking-questions-and-reporting-issues)
|
||||
- [Contributing code](#contributing-code)
|
||||
- [Additional help and resources](#additional-help-and-resources)
|
||||
- [Changelog](#changelog)
|
||||
- [License](#license)
|
||||
|
||||
# How it works
|
||||
NGINX is installed software with binary packages available for all major operating systems and Linux distributions. See [Tested OS and Platforms](https://nginx.org/en/#tested_os_and_platforms) for a full list of compatible systems.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> While nearly all popular Linux-based operating systems are distributed with a community version of nginx, we highly advise installation and usage of official [packages](https://nginx.org/en/linux_packages.html) or sources from this repository. Doing so ensures that you're using the most recent release or source code, including the latest feature-set, fixes and security patches.
|
||||
|
||||
## Modules
|
||||
NGINX is comprised of individual modules, each extending core functionality by providing additional, configurable features. See "Modules reference" at the bottom of [nginx documentation](https://nginx.org/en/docs/) for a complete list of official modules.
|
||||
|
||||
NGINX modules can be built and distributed as static or dynamic modules. Static modules are defined at build-time, compiled, and distributed in the resulting binaries. See [Dynamic Modules](#dynamic-modules) for more information on how they work, as well as, how to obtain, install, and configure them.
|
||||
|
||||
> [!TIP]
|
||||
> You can issue the following command to see which static modules your NGINX binaries were built with:
|
||||
```bash
|
||||
nginx -V
|
||||
```
|
||||
> See [Configuring the build](#configuring-the-build) for information on how to include specific Static modules into your nginx build.
|
||||
|
||||
|
||||
## Configurations
|
||||
NGINX is highly flexible and configurable. Provisioning the software is achieved via text-based config file(s) accepting parameters called "[Directives](https://nginx.org/en/docs/dirindex.html)". See [Configuration File's Structure](https://nginx.org/en/docs/beginners_guide.html#conf_structure) for a comprehensive description of how NGINX configuration files work.
|
||||
|
||||
> [!NOTE]
|
||||
> The set of directives available to your distribution of NGINX is dependent on which [modules](#modules) have been made available to it.
|
||||
|
||||
## Runtime
|
||||
Rather than running in a single, monolithic process, NGINX is architected to scale beyond Operating System process limitations by operating as a collection of processes. They include:
|
||||
- A "master" process that maintains worker processes, as well as, reads and evaluates configuration files.
|
||||
- One or more "worker" processes that process data (eg. HTTP requests).
|
||||
|
||||
The number of [worker processes](https://nginx.org/en/docs/ngx_core_module.html#worker_processes) is defined in the configuration file and may be fixed for a given configuration or automatically adjusted to the number of available CPU cores. In most cases, the latter option optimally balances load across available system resources, as NGINX is designed to efficiently distribute work across all worker processes.
|
||||
|
||||
> [!TIP]
|
||||
> Processes synchronize data through shared memory. For this reason, many NGINX directives require the allocation of shared memory zones. As an example, when configuring [rate limiting](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req), connecting clients may need to be tracked in a [common memory zone](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_zone) so all worker processes can know how many times a particular client has accessed the server in a span of time.
|
||||
|
||||
# Downloading and installing
|
||||
Follow these steps to download and install precompiled NGINX binaries. You may also choose to [build NGINX locally from source code](#building-from-source).
|
||||
|
||||
## Stable and Mainline binaries
|
||||
NGINX binaries are built and distributed in two versions: stable and mainline. Stable binaries are built from stable branches and only contain critical fixes backported from the mainline version. Mainline binaries are built from the [master branch](https://github.com/nginx/nginx/tree/master) and contain the latest features and bugfixes. You'll need to [decide which is appropriate for your purposes](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#choosing-between-a-stable-or-a-mainline-version).
|
||||
|
||||
## Linux binary installation process
|
||||
The NGINX binary installation process takes advantage of package managers native to specific Linux distributions. For this reason, first-time installations involve adding the official NGINX package repository to your system's package manager. Follow [these steps](https://nginx.org/en/linux_packages.html) to download, verify, and install NGINX binaries using the package manager appropriate for your Linux distribution.
|
||||
|
||||
### Upgrades
|
||||
Future upgrades to the latest version can be managed using the same package manager without the need to manually download and verify binaries.
|
||||
|
||||
## FreeBSD installation process
|
||||
For more information on installing NGINX on FreeBSD system, visit https://nginx.org/en/docs/install.html
|
||||
|
||||
## Windows executables
|
||||
Windows executables for mainline and stable releases can be found on the main [NGINX download page](https://nginx.org/en/download.html). Note that the current implementation of NGINX for Windows is at the Proof-of-Concept stage and should only be used for development and testing purposes. For additional information, please see [nginx for Windows](https://nginx.org/en/docs/windows.html).
|
||||
|
||||
## Dynamic modules
|
||||
NGINX version 1.9.11 added support for [Dynamic Modules](https://nginx.org/en/docs/ngx_core_module.html#load_module). Unlike Static modules, dynamically built modules can be downloaded, installed, and configured after the core NGINX binaries have been built. [Official dynamic module binaries](https://nginx.org/en/linux_packages.html#dynmodules) are available from the same package repository as the core NGINX binaries described in previous steps.
|
||||
|
||||
> [!TIP]
|
||||
> [NGINX JavaScript (njs)](https://github.com/nginx/njs), is a popular NGINX dynamic module that enables the extension of core NGINX functionality using familiar JavaScript syntax.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If desired, dynamic modules can also be built statically into NGINX at compile time.
|
||||
|
||||
# Getting started with NGINX
|
||||
For a gentle introduction to NGINX basics, please see our [Beginner’s Guide](https://nginx.org/en/docs/beginners_guide.html).
|
||||
|
||||
## Installing SSL certificates and enabling TLS encryption
|
||||
See [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html) for a quick guide on how to enable secure traffic to your NGINX installation.
|
||||
|
||||
## Load Balancing
|
||||
For a quick start guide on configuring NGINX as a Load Balancer, please see [Using nginx as HTTP load balancer](https://nginx.org/en/docs/http/load_balancing.html).
|
||||
|
||||
## Rate limiting
|
||||
See our [Rate Limiting with NGINX](https://blog.nginx.org/blog/rate-limiting-nginx) blog post for an overview of core concepts for provisioning NGINX as an API Gateway.
|
||||
|
||||
## Content caching
|
||||
See [A Guide to Caching with NGINX and NGINX Plus](https://blog.nginx.org/blog/nginx-caching-guide) blog post for an overview of how to use NGINX as a content cache (e.g. edge server of a content delivery network).
|
||||
|
||||
# Building from source
|
||||
The following steps can be used to build NGINX from source code available in this repository.
|
||||
|
||||
## Installing dependencies
|
||||
Most Linux distributions will require several dependencies to be installed in order to build NGINX. The following instructions are specific to the `apt` package manager, widely available on most Ubuntu/Debian distributions and their derivatives.
|
||||
|
||||
> [!TIP]
|
||||
> It is always a good idea to update your package repository lists prior to installing new packages.
|
||||
> ```bash
|
||||
> sudo apt update
|
||||
> ```
|
||||
|
||||
### Installing compiler and make utility
|
||||
Use the following command to install the GNU C compiler and Make utility.
|
||||
|
||||
```bash
|
||||
sudo apt install gcc make
|
||||
```
|
||||
|
||||
### Installing dependency libraries
|
||||
|
||||
```bash
|
||||
sudo apt install libpcre3-dev zlib1g-dev
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> This is the minimal set of dependency libraries needed to build NGINX with rewriting and gzip capabilities. Other dependencies may be required if you choose to build NGINX with additional modules. Monitor the output of the `configure` command discussed in the following sections for information on which modules may be missing. For example, if you plan to use SSL certificates to encrypt traffic with TLS, you'll need to install the OpenSSL library. To do so, issue the following command.
|
||||
|
||||
>```bash
|
||||
>sudo apt install libssl-dev
|
||||
|
||||
## Cloning the NGINX GitHub repository
|
||||
Using your preferred method, clone the NGINX repository into your development directory. See [Cloning a GitHub Repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) for additional help.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/nginx/nginx.git
|
||||
```
|
||||
|
||||
## Configuring the build
|
||||
Prior to building NGINX, you must run the `configure` script with [appropriate flags](https://nginx.org/en/docs/configure.html). This will generate a Makefile in your NGINX source root directory that can then be used to compile NGINX with [options specified during configuration](https://nginx.org/en/docs/configure.html).
|
||||
|
||||
From the NGINX source code repository's root directory:
|
||||
|
||||
```bash
|
||||
auto/configure
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Configuring the build without any flags will compile NGINX with the default set of options. Please refer to https://nginx.org/en/docs/configure.html for a full list of available build configuration options.
|
||||
|
||||
## Compiling
|
||||
The `configure` script will generate a `Makefile` in the NGINX source root directory upon successful execution. To compile NGINX into a binary, issue the following command from that same directory:
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
## Location of binary and installation
|
||||
After successful compilation, a binary will be generated at `<NGINX_SRC_ROOT_DIR>/objs/nginx`. To install this binary, issue the following command from the source root directory:
|
||||
|
||||
```bash
|
||||
sudo make install
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> The binary will be installed into the `/usr/local/nginx/` directory.
|
||||
|
||||
## Running and testing the installed binary
|
||||
To run the installed binary, issue the following command:
|
||||
|
||||
```bash
|
||||
sudo /usr/local/nginx/sbin/nginx
|
||||
```
|
||||
|
||||
You may test NGINX operation using `curl`.
|
||||
|
||||
```bash
|
||||
curl localhost
|
||||
```
|
||||
|
||||
The output of which should start with:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to nginx!</title>
|
||||
```
|
||||
|
||||
# Asking questions and reporting issues
|
||||
We encourage you to engage with us.
|
||||
- [NGINX GitHub Discussions](https://github.com/nginx/nginx/discussions), is the go-to place to start asking questions and sharing your thoughts.
|
||||
- Our [GitHub Issues](https://github.com/nginx/nginx/issues) page offers space to submit and discuss specific issues, report bugs, and suggest enhancements.
|
||||
|
||||
# Contributing code
|
||||
Please see the [Contributing](CONTRIBUTING.md) guide for information on how to contribute code.
|
||||
|
||||
# Additional help and resources
|
||||
- See the [NGINX Community Blog](https://blog.nginx.org/) for more tips, tricks and HOW-TOs related to NGINX and related projects.
|
||||
- Access [nginx.org](https://nginx.org/), your go-to source for all documentation, information and software related to the NGINX suite of projects.
|
||||
|
||||
# Changelog
|
||||
See our [changelog](https://nginx.org/en/CHANGES) to keep track of updates.
|
||||
|
||||
# License
|
||||
[2-clause BSD-like license](LICENSE)
|
||||
|
||||
---
|
||||
Additional documentation available at: https://nginx.org/en/docs
|
103
nginx-1.28.0/docs/SECURITY.md
Normal file
103
nginx-1.28.0/docs/SECURITY.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Security Policy
|
||||
|
||||
This document provides an overview of security concerns related to nginx
|
||||
deployments, focusing on confidentiality, integrity, availability, and the
|
||||
implications of configurations and misconfigurations.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report any vulnerabilities via one of the following methods
|
||||
(in order of preference):
|
||||
|
||||
1. [Report a vulnerability](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability)
|
||||
within this repository. We are using the GitHub workflow that allows us to
|
||||
manage vulnerabilities in a private manner and interact with reporters
|
||||
securely.
|
||||
|
||||
2. [Report directly to F5](https://www.f5.com/services/support/report-a-vulnerability).
|
||||
|
||||
3. Report via email to security-alert@nginx.org.
|
||||
This method will be deprecated in the future.
|
||||
|
||||
### Vulnerability Disclosure and Fix Process
|
||||
|
||||
The nginx team expects that all suspected vulnerabilities be reported
|
||||
privately via the
|
||||
[Reporting a Vulnerability](SECURITY.md#reporting-a-vulnerability) guidelines.
|
||||
If a publicly released vulnerability is reported, we
|
||||
may request to handle it according to the private disclosure process.
|
||||
If the reporter agrees, we will follow the private disclosure process.
|
||||
|
||||
Security fixes will be applied to all supported stable releases, as well
|
||||
as the mainline version, as applicable. We recommend using the most recent
|
||||
mainline or stable release of nginx. Fixes are created and tested by the core
|
||||
team using a GitHub private fork for security. If necessary, the reporter
|
||||
may be invited to contribute to the fork and assist with the solution.
|
||||
|
||||
The nginx team is committed to responsible information disclosure with
|
||||
sufficient detail, such as the CVSS score and vector. Privately disclosed
|
||||
vulnerabilities are embargoed by default until the fix is released.
|
||||
Communications and fixes remain private until made public. As nginx is
|
||||
supported by F5, we generally follow the
|
||||
[F5 security vulnerability response policy](https://my.f5.com/manage/s/article/K4602).
|
||||
|
||||
### Vulnerability Disclosure and Fix Service Level Objectives
|
||||
|
||||
- We will acknowledge all vulnerability reports within 1 to 3 days.
|
||||
- Fixes will be developed and released within 90 days from the date of
|
||||
disclosure. If an extension is needed, we will work with the disclosing person.
|
||||
- Publicly disclosed (i.e., Zero-Day vulnerabilities) will be addressed ASAP.
|
||||
|
||||
## Confidentiality, Integrity, and Availability
|
||||
|
||||
### Confidentiality and Integrity
|
||||
|
||||
Vulnerabilities compromising data confidentiality or integrity are considered
|
||||
the highest priority. Any issue leading to unauthorized data access, leaks, or
|
||||
manipulation will trigger the security release process.
|
||||
|
||||
### Availability
|
||||
|
||||
Availability issues must meet the following criteria to trigger the security
|
||||
release process:
|
||||
- Is present in a standard module included with nginx.
|
||||
- Arises from traffic that the module is designed to handle.
|
||||
- Resource exhaustion issues are not mitigated by existing timeout, rate
|
||||
limiting, or buffer size configurations, or applying changes is impractical.
|
||||
- Results in highly asymmetric, extreme resource consumption.
|
||||
|
||||
Availability issues excluded from the security release process:
|
||||
- Local file content or upstream response content resulting only in worker
|
||||
process termination.
|
||||
- Issues with experimental features which result only in availability impact.
|
||||
|
||||
## Trusted Configurations and Misconfigurations
|
||||
|
||||
In nginx, configuration files, modules, certificate/key pairs, nginx JavaScript,
|
||||
and local file content are considered trusted sources. Issues arising from
|
||||
loading or execution of these trusted components are not considered
|
||||
vulnerabilities. Operators are responsible for securing and maintaining the
|
||||
integrity of these sources. Misconfigurations can create vulnerabilities, and
|
||||
operators should implement configurations according to best practices, review
|
||||
them regularly, and apply security updates.
|
||||
|
||||
## Data Plane vs. Control Plane
|
||||
|
||||
The data plane handles traffic through nginx, directly interacting with user
|
||||
data. nginx inherently trusts the content and instructions from upstream
|
||||
servers. The control plane governs configuration, management, and orchestration.
|
||||
Misconfigurations or vulnerabilities in the control plane can cause improper
|
||||
behavior in the data plane.
|
||||
|
||||
## Modules Under Scope
|
||||
|
||||
The policy applies to all nginx modules included in this repository. Security
|
||||
considerations and attack vectors for each module will be identified, with
|
||||
recommended configurations to mitigate risks.
|
||||
|
||||
## Debug Logging and Core Files
|
||||
|
||||
Debug logs and core files produced by nginx may contain un-sanitized data,
|
||||
including sensitive information like client requests, server configurations,
|
||||
and private key material. These artifacts must be handled carefully to avoid
|
||||
exposing confidential data.
|
20
nginx-1.28.0/docs/zlib.LICENSE
Normal file
20
nginx-1.28.0/docs/zlib.LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
(C) 1995-2024 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly Mark Adler
|
||||
jloup@gzip.org madler@alumni.caltech.edu
|
19
nginx-1.28.0/html/50x.html
Normal file
19
nginx-1.28.0/html/50x.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
<style>
|
||||
html { color-scheme: light dark; }
|
||||
body { width: 35em; margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>An error occurred.</h1>
|
||||
<p>Sorry, the page you are looking for is currently unavailable.<br/>
|
||||
Please try again later.</p>
|
||||
<p>If you are the system administrator of this resource then you should check
|
||||
the error log for details.</p>
|
||||
<p><em>Faithfully yours, nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
23
nginx-1.28.0/html/index.html
Normal file
23
nginx-1.28.0/html/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
html { color-scheme: light dark; }
|
||||
body { width: 35em; margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to nginx!</h1>
|
||||
<p>If you see this page, the nginx web server is successfully installed and
|
||||
working. Further configuration is required.</p>
|
||||
|
||||
<p>For online documentation and support please refer to
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
|
||||
<p><em>Thank you for using nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
0
nginx-1.28.0/logs/.gitkeep
Normal file
0
nginx-1.28.0/logs/.gitkeep
Normal file
BIN
nginx-1.28.0/nginx.exe
Normal file
BIN
nginx-1.28.0/nginx.exe
Normal file
Binary file not shown.
0
nginx-1.28.0/temp/.gitkeep
Normal file
0
nginx-1.28.0/temp/.gitkeep
Normal file
@@ -1,12 +0,0 @@
|
||||
apiVersion: skaffold/v4beta13
|
||||
kind: Config
|
||||
metadata:
|
||||
name: bio-backend
|
||||
build:
|
||||
artifacts:
|
||||
- image: backend-0.0.1
|
||||
docker:
|
||||
dockerfile: Dockerfile
|
||||
manifests:
|
||||
rawYaml:
|
||||
- k8s/deployment.yaml
|
@@ -2,10 +2,12 @@ package com.bio.bio_backend;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableJpaAuditing
|
||||
@EnableConfigurationProperties
|
||||
public class BioBackendApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@@ -0,0 +1,208 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.controller;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.*;
|
||||
import com.bio.bio_backend.domain.admin.common_code.service.CommonCodeService;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonGroupCodeMapper;
|
||||
import com.bio.bio_backend.global.dto.ApiResponseDto;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.annotation.LogExecution;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/admin/common-code")
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "공통 코드 관리", description = "공통 코드 및 그룹 코드 관리 API")
|
||||
public class CommonCodeController {
|
||||
|
||||
private final CommonCodeService commonCodeService;
|
||||
private final CommonCodeMapper commonCodeMapper;
|
||||
private final CommonGroupCodeMapper commonGroupCodeMapper;
|
||||
|
||||
// 그룹 코드 관련 API
|
||||
@LogExecution("그룹 코드 생성")
|
||||
@Operation(summary = "그룹 코드 생성", description = "새로운 그룹 코드를 생성합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "201", description = "그룹 코드 생성 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 그룹 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/group")
|
||||
public ResponseEntity<ApiResponseDto<CreateCommonGroupCodeResponseDto>> createGroupCode(@RequestBody @Valid CreateCommonGroupCodeRequestDto requestDto) {
|
||||
CommonGroupCodeDto groupCodeDto = commonGroupCodeMapper.toCommonGroupCodeDto(requestDto);
|
||||
CommonGroupCodeDto createdGroupCode = commonCodeService.createGroupCode(groupCodeDto);
|
||||
CreateCommonGroupCodeResponseDto responseDto = commonGroupCodeMapper.toCreateCommonGroupCodeResponseDto(createdGroupCode);
|
||||
ApiResponseDto<CreateCommonGroupCodeResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 수정")
|
||||
@Operation(summary = "그룹 코드 수정", description = "기존 그룹 코드를 수정합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 수정 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PutMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<String>> updateGroupCode(
|
||||
@PathVariable String code,
|
||||
@RequestBody @Valid UpdateCommonGroupCodeRequestDto requestDto) {
|
||||
CommonGroupCodeDto groupCodeDto = commonGroupCodeMapper.toCommonGroupCodeDto(requestDto);
|
||||
commonCodeService.updateGroupCode(code, groupCodeDto);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_UPDATED));
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 삭제")
|
||||
@Operation(summary = "그룹 코드 삭제", description = "그룹 코드를 삭제합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 삭제 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@DeleteMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<Void>> deleteGroupCode(@PathVariable String code) {
|
||||
commonCodeService.deleteGroupCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_DELETED));
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 조회")
|
||||
@Operation(summary = "그룹 코드 조회", description = "특정 그룹 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 조회 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<CommonGroupCodeDto>> getGroupCode(@PathVariable String code) {
|
||||
CommonGroupCodeDto groupCode = commonCodeService.getGroupCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCode));
|
||||
}
|
||||
|
||||
@LogExecution("전체 그룹 코드 조회")
|
||||
@Operation(summary = "전체 그룹 코드 조회", description = "모든 그룹 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "전체 그룹 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonGroupCodeDto>>> getAllGroupCodes() {
|
||||
List<CommonGroupCodeDto> groupCodes = commonCodeService.getAllGroupCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCodes));
|
||||
}
|
||||
|
||||
@LogExecution("활성 그룹 코드 조회")
|
||||
@Operation(summary = "활성 그룹 코드 조회", description = "사용 중인 그룹 코드만 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "활성 그룹 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group/active")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonGroupCodeDto>>> getActiveGroupCodes() {
|
||||
List<CommonGroupCodeDto> groupCodes = commonCodeService.getActiveGroupCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCodes));
|
||||
}
|
||||
|
||||
// 공통 코드 관련 API
|
||||
@LogExecution("공통 코드 생성")
|
||||
@Operation(summary = "공통 코드 생성", description = "새로운 공통 코드를 생성합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "201", description = "공통 코드 생성 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 공통 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponseDto<CreateCommonCodeResponseDto>> createCode(@RequestBody @Valid CreateCommonCodeRequestDto requestDto) {
|
||||
CommonCodeDto commonCodeDto = commonCodeMapper.toCommonCodeDto(requestDto);
|
||||
CommonCodeDto createdCommonCode = commonCodeService.createCode(commonCodeDto);
|
||||
CreateCommonCodeResponseDto responseDto = commonCodeMapper.toCreateCommonCodeResponseDto(createdCommonCode);
|
||||
ApiResponseDto<CreateCommonCodeResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 수정")
|
||||
@Operation(summary = "공통 코드 수정", description = "기존 공통 코드를 수정합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 수정 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PutMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<String>> updateCode(
|
||||
@PathVariable String code,
|
||||
@RequestBody @Valid UpdateCommonCodeRequestDto requestDto) {
|
||||
CommonCodeDto commonCodeDto = commonCodeMapper.toCommonCodeDto(requestDto);
|
||||
commonCodeService.updateCode(code, commonCodeDto);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_UPDATED));
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 삭제")
|
||||
@Operation(summary = "공통 코드 삭제", description = "공통 코드를 삭제합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 삭제 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@DeleteMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<Void>> deleteCode(@PathVariable String code) {
|
||||
commonCodeService.deleteCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_DELETED));
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 조회")
|
||||
@Operation(summary = "공통 코드 조회", description = "특정 공통 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 조회 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<CommonCodeDto>> getCode(@PathVariable String code) {
|
||||
CommonCodeDto commonCode = commonCodeService.getCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCode));
|
||||
}
|
||||
|
||||
@LogExecution("그룹별 공통 코드 조회")
|
||||
@Operation(summary = "그룹별 공통 코드 조회", description = "특정 그룹에 속한 공통 코드들을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹별 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group/{groupCode}/codes")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getCodesByGroupCode(@PathVariable String groupCode) {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getActiveCodesByGroupCode(groupCode);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
|
||||
@LogExecution("상위 코드별 공통 코드 조회")
|
||||
@Operation(summary = "상위 코드별 공통 코드 조회", description = "특정 상위 코드에 속한 공통 코드들을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "상위 코드별 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/parent/{parentCode}/codes")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getCodesByParentCode(@PathVariable String parentCode) {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getActiveCodesByParentCode(parentCode);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
|
||||
@LogExecution("전체 공통 코드 조회")
|
||||
@Operation(summary = "전체 공통 코드 조회", description = "모든 공통 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "전체 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getAllCodes() {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getAllCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonCodeDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String description;
|
||||
private String groupCode;
|
||||
private String parentCode;
|
||||
private String characterRef1;
|
||||
private String characterRef2;
|
||||
private String characterRef3;
|
||||
private String characterRef4;
|
||||
private String characterRef5;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonGroupCodeDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String characterRef1Title;
|
||||
private String characterRef2Title;
|
||||
private String characterRef3Title;
|
||||
private String characterRef4Title;
|
||||
private String characterRef5Title;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "코드는 필수입니다")
|
||||
@Size(max = 50, message = "코드는 50자를 초과할 수 없습니다")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 500, message = "설명은 500자를 초과할 수 없습니다")
|
||||
private String description;
|
||||
|
||||
@NotBlank(message = "그룹 코드는 필수입니다")
|
||||
@Size(max = 50, message = "그룹 코드는 50자를 초과할 수 없습니다")
|
||||
private String groupCode;
|
||||
|
||||
@Size(max = 50, message = "상위 코드는 50자를 초과할 수 없습니다")
|
||||
private String parentCode;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2는 100자를 초과할 수 없습니다")
|
||||
private String characterRef2;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4는 100자를 초과할 수 없습니다")
|
||||
private String characterRef4;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5는 100자를 초과할 수 없습니다")
|
||||
private String characterRef5;
|
||||
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonCodeResponseDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String description;
|
||||
private String groupCode;
|
||||
private String parentCode;
|
||||
private String characterRef1;
|
||||
private String characterRef2;
|
||||
private String characterRef3;
|
||||
private String characterRef4;
|
||||
private String characterRef5;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonGroupCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "코드는 필수입니다")
|
||||
@Size(max = 50, message = "코드는 50자를 초과할 수 없습니다")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 100, message = "차트 참조1 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조2 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef2Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조3 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조4 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef4Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조5 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef5Title;
|
||||
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonGroupCodeResponseDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String characterRef1Title;
|
||||
private String characterRef2Title;
|
||||
private String characterRef3Title;
|
||||
private String characterRef4Title;
|
||||
private String characterRef5Title;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateCommonCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 500, message = "설명은 500자를 초과할 수 없습니다")
|
||||
private String description;
|
||||
|
||||
@NotBlank(message = "그룹 코드는 필수입니다")
|
||||
@Size(max = 50, message = "그룹 코드는 50자를 초과할 수 없습니다")
|
||||
private String groupCode;
|
||||
|
||||
@Size(max = 50, message = "상위 코드는 50자를 초과할 수 없습니다")
|
||||
private String parentCode;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2는 100자를 초과할 수 없습니다")
|
||||
private String characterRef2;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4는 100자를 초과할 수 없습니다")
|
||||
private String characterRef4;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5는 100자를 초과할 수 없습니다")
|
||||
private String characterRef5;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateCommonGroupCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef2Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef4Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef5Title;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.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;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = AppConstants.TABLE_PREFIX + "common_code",
|
||||
indexes = {
|
||||
@Index(name = "idx_common_code_code", columnList = "code"),
|
||||
@Index(name = "idx_common_code_group_code", columnList = "group_code"),
|
||||
@Index(name = "idx_common_code_parent_code", columnList = "parent_code")
|
||||
}
|
||||
)
|
||||
public class CommonCode extends BaseEntity {
|
||||
|
||||
@Column(name = "code", nullable = false, length = 50, unique = true)
|
||||
private String code;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", length = 500)
|
||||
private String description;
|
||||
|
||||
@Column(name = "group_code", nullable = false, length = 50)
|
||||
private String groupCode;
|
||||
|
||||
@Column(name = "parent_code", length = 50)
|
||||
private String parentCode;
|
||||
|
||||
@Column(name = "character_ref1", length = 100)
|
||||
private String characterRef1;
|
||||
|
||||
@Column(name = "character_ref2", length = 100)
|
||||
private String characterRef2;
|
||||
|
||||
@Column(name = "character_ref3", length = 100)
|
||||
private String characterRef3;
|
||||
|
||||
@Column(name = "character_ref4", length = 100)
|
||||
private String characterRef4;
|
||||
|
||||
@Column(name = "character_ref5", length = 100)
|
||||
private String characterRef5;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Column(name = "use_flag", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
|
||||
// 관계 설정
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(
|
||||
name = "group_code",
|
||||
referencedColumnName = "code",
|
||||
insertable = false,
|
||||
updatable = false,
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT)
|
||||
)
|
||||
private CommonGroupCode commonGroupCode;
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.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;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = AppConstants.TABLE_PREFIX + "common_group_code",
|
||||
indexes = {
|
||||
@Index(name = "idx_common_group_code_code", columnList = "code")
|
||||
}
|
||||
)
|
||||
public class CommonGroupCode extends BaseEntity {
|
||||
|
||||
@Column(name = "code", nullable = false, length = 50, unique = true)
|
||||
private String code;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "character_ref1_title", length = 100)
|
||||
private String characterRef1Title;
|
||||
|
||||
@Column(name = "character_ref2_title", length = 100)
|
||||
private String characterRef2Title;
|
||||
|
||||
@Column(name = "character_ref3_title", length = 100)
|
||||
private String characterRef3Title;
|
||||
|
||||
@Column(name = "character_ref4_title", length = 100)
|
||||
private String characterRef4Title;
|
||||
|
||||
@Column(name = "character_ref5_title", length = 100)
|
||||
private String characterRef5Title;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Column(name = "use_flag", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonCodeResponseDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.UpdateCommonCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface CommonCodeMapper {
|
||||
|
||||
/**
|
||||
* CommonCode 엔티티를 CommonCodeDto로 변환
|
||||
*/
|
||||
CommonCodeDto toCommonCodeDto(CommonCode commonCode);
|
||||
|
||||
/**
|
||||
* CommonCodeDto를 CommonCode 엔티티로 변환
|
||||
*/
|
||||
@Mapping(target = "commonGroupCode", ignore = true)
|
||||
CommonCode toCommonCode(CommonCodeDto commonCodeDto);
|
||||
|
||||
/**
|
||||
* CommonCode 엔티티 리스트를 CommonCodeDto 리스트로 변환
|
||||
*/
|
||||
List<CommonCodeDto> toCommonCodeDtoList(List<CommonCode> commonCodes);
|
||||
|
||||
/**
|
||||
* CommonCodeDto를 CreateCommonCodeResponseDto로 변환
|
||||
*/
|
||||
CreateCommonCodeResponseDto toCreateCommonCodeResponseDto(CommonCodeDto commonCodeDto);
|
||||
|
||||
/**
|
||||
* CreateCommonCodeRequestDto를 CommonCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
CommonCodeDto toCommonCodeDto(CreateCommonCodeRequestDto createRequestDto);
|
||||
|
||||
/**
|
||||
* UpdateCommonCodeRequestDto를 CommonCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "code", ignore = true)
|
||||
CommonCodeDto toCommonCodeDto(UpdateCommonCodeRequestDto updateRequestDto);
|
||||
|
||||
/**
|
||||
* CommonCodeDto의 값으로 CommonCode 엔티티를 업데이트
|
||||
*/
|
||||
@IgnoreBaseEntityMapping
|
||||
@Mapping(target = "commonGroupCode", ignore = true)
|
||||
void updateCommonCodeFromDto(CommonCodeDto commonCodeDto, @org.mapstruct.MappingTarget CommonCode commonCode);
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonGroupCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonGroupCodeResponseDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.UpdateCommonGroupCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface CommonGroupCodeMapper {
|
||||
|
||||
/**
|
||||
* CommonGroupCode 엔티티를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(CommonGroupCode commonGroupCode);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto를 CommonGroupCode 엔티티로 변환
|
||||
*/
|
||||
CommonGroupCode toCommonGroupCode(CommonGroupCodeDto commonGroupCodeDto);
|
||||
|
||||
/**
|
||||
* CommonGroupCode 엔티티 리스트를 CommonGroupCodeDto 리스트로 변환
|
||||
*/
|
||||
List<CommonGroupCodeDto> toCommonGroupCodeDtoList(List<CommonGroupCode> commonGroupCodes);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto를 CreateCommonGroupCodeResponseDto로 변환
|
||||
*/
|
||||
CreateCommonGroupCodeResponseDto toCreateCommonGroupCodeResponseDto(CommonGroupCodeDto commonGroupCodeDto);
|
||||
|
||||
/**
|
||||
* CreateCommonGroupCodeRequestDto를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(CreateCommonGroupCodeRequestDto createRequestDto);
|
||||
|
||||
/**
|
||||
* UpdateCommonGroupCodeRequestDto를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "code", ignore = true)
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(UpdateCommonGroupCodeRequestDto updateRequestDto);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto의 값으로 CommonGroupCode 엔티티를 업데이트
|
||||
*/
|
||||
@IgnoreBaseEntityMapping
|
||||
void updateCommonGroupCodeFromDto(CommonGroupCodeDto commonGroupCodeDto, @org.mapstruct.MappingTarget CommonGroupCode commonGroupCode);
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CommonCodeRepository extends JpaRepository<CommonCode, Long> {
|
||||
|
||||
Optional<CommonCode> findByCode(String code);
|
||||
|
||||
List<CommonCode> findByGroupCodeAndUseFlagOrderBySortOrderAsc(String groupCode, Boolean useFlag);
|
||||
|
||||
List<CommonCode> findByParentCodeAndUseFlagOrderBySortOrderAsc(String parentCode, Boolean useFlag);
|
||||
|
||||
@Query("SELECT cc FROM CommonCode cc WHERE cc.groupCode = :groupCode AND cc.useFlag = :useFlag ORDER BY cc.sortOrder ASC")
|
||||
List<CommonCode> findActiveCodesByGroupCodeOrderBySortOrder(@Param("groupCode") String groupCode, @Param("useFlag") Boolean useFlag);
|
||||
|
||||
@Query("SELECT cc FROM CommonCode cc WHERE cc.parentCode = :parentCode AND cc.useFlag = :useFlag ORDER BY cc.sortOrder ASC")
|
||||
List<CommonCode> findActiveCodesByParentCodeOrderBySortOrder(@Param("parentCode") String parentCode, @Param("useFlag") Boolean useFlag);
|
||||
|
||||
boolean existsByCode(String code);
|
||||
|
||||
boolean existsByGroupCode(String groupCode);
|
||||
|
||||
boolean existsByParentCode(String parentCode);
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CommonGroupCodeRepository extends JpaRepository<CommonGroupCode, Long> {
|
||||
|
||||
Optional<CommonGroupCode> findByCode(String code);
|
||||
|
||||
List<CommonGroupCode> findByUseFlagOrderBySortOrderAsc(Boolean useFlag);
|
||||
|
||||
@Query("SELECT cgc FROM CommonGroupCode cgc WHERE cgc.useFlag = :useFlag ORDER BY cgc.sortOrder ASC")
|
||||
List<CommonGroupCode> findActiveGroupCodesOrderBySortOrder(@Param("useFlag") Boolean useFlag);
|
||||
|
||||
boolean existsByCode(String code);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.service;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommonCodeService {
|
||||
|
||||
// 그룹 코드 관련
|
||||
CommonGroupCodeDto createGroupCode(CommonGroupCodeDto groupCodeDto);
|
||||
void updateGroupCode(String code, CommonGroupCodeDto groupCodeDto);
|
||||
void deleteGroupCode(String code);
|
||||
CommonGroupCodeDto getGroupCode(String code);
|
||||
List<CommonGroupCodeDto> getAllGroupCodes();
|
||||
List<CommonGroupCodeDto> getActiveGroupCodes();
|
||||
|
||||
// 공통 코드 관련
|
||||
CommonCodeDto createCode(CommonCodeDto codeDto);
|
||||
void updateCode(String code, CommonCodeDto codeDto);
|
||||
void deleteCode(String code);
|
||||
CommonCodeDto getCode(String code);
|
||||
List<CommonCodeDto> getCodesByGroupCode(String groupCode);
|
||||
List<CommonCodeDto> getActiveCodesByGroupCode(String groupCode);
|
||||
List<CommonCodeDto> getCodesByParentCode(String parentCode);
|
||||
List<CommonCodeDto> getActiveCodesByParentCode(String parentCode);
|
||||
List<CommonCodeDto> getAllCodes();
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.service;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonGroupCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.repository.CommonCodeRepository;
|
||||
import com.bio.bio_backend.domain.admin.common_code.repository.CommonGroupCodeRepository;
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
import com.bio.bio_backend.global.exception.ApiException;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class CommonCodeServiceImpl implements CommonCodeService {
|
||||
|
||||
private final CommonGroupCodeRepository commonGroupCodeRepository;
|
||||
private final CommonCodeRepository commonCodeRepository;
|
||||
private final CommonCodeMapper commonCodeMapper;
|
||||
private final CommonGroupCodeMapper commonGroupCodeMapper;
|
||||
|
||||
// 그룹 코드 관련 메서드들
|
||||
@Override
|
||||
@Transactional
|
||||
public CommonGroupCodeDto createGroupCode(CommonGroupCodeDto groupCodeDto) {
|
||||
if (commonGroupCodeRepository.existsByCode(groupCodeDto.getCode())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_CODE_DUPLICATE);
|
||||
}
|
||||
|
||||
CommonGroupCode groupCode = commonGroupCodeMapper.toCommonGroupCode(groupCodeDto);
|
||||
CommonGroupCode savedGroupCode = commonGroupCodeRepository.save(groupCode);
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDto(savedGroupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateGroupCode(String code, CommonGroupCodeDto groupCodeDto) {
|
||||
CommonGroupCode existingGroupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_TARGET_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
commonGroupCodeMapper.updateCommonGroupCodeFromDto(groupCodeDto, existingGroupCode);
|
||||
commonGroupCodeRepository.save(existingGroupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteGroupCode(String code) {
|
||||
CommonGroupCode groupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
// 하위 공통 코드가 있는지 확인
|
||||
if (commonCodeRepository.existsByGroupCode(code)) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "하위 공통 코드가 존재하여 삭제할 수 없습니다: " + code);
|
||||
}
|
||||
|
||||
commonGroupCodeRepository.delete(groupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonGroupCodeDto getGroupCode(String code) {
|
||||
CommonGroupCode groupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDto(groupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonGroupCodeDto> getAllGroupCodes() {
|
||||
List<CommonGroupCode> groupCodes = commonGroupCodeRepository.findAll();
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDtoList(groupCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonGroupCodeDto> getActiveGroupCodes() {
|
||||
List<CommonGroupCode> groupCodes = commonGroupCodeRepository.findByUseFlagOrderBySortOrderAsc(true);
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDtoList(groupCodes);
|
||||
}
|
||||
|
||||
// 공통 코드 관련 메서드들
|
||||
@Override
|
||||
@Transactional
|
||||
public CommonCodeDto createCode(CommonCodeDto commonCodeDto) {
|
||||
if (commonCodeRepository.existsByCode(commonCodeDto.getCode())) {
|
||||
throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE, "이미 존재하는 공통 코드입니다: " + commonCodeDto.getCode());
|
||||
}
|
||||
|
||||
// 그룹 코드 존재 여부 확인
|
||||
if (!commonGroupCodeRepository.existsByCode(commonCodeDto.getGroupCode())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "존재하지 않는 그룹 코드입니다: " + commonCodeDto.getGroupCode());
|
||||
}
|
||||
|
||||
CommonCode commonCode = commonCodeMapper.toCommonCode(commonCodeDto);
|
||||
CommonCode savedCommonCode = commonCodeRepository.save(commonCode);
|
||||
return commonCodeMapper.toCommonCodeDto(savedCommonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateCode(String code, CommonCodeDto commonCodeDto) {
|
||||
CommonCode existingCommonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
commonCodeMapper.updateCommonCodeFromDto(commonCodeDto, existingCommonCode);
|
||||
commonCodeRepository.save(existingCommonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteCode(String code) {
|
||||
CommonCode commonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
// 하위 공통 코드가 있는지 확인
|
||||
if (commonCodeRepository.existsByParentCode(code)) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "하위 공통 코드가 존재하여 삭제할 수 없습니다: " + code);
|
||||
}
|
||||
|
||||
commonCodeRepository.delete(commonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonCodeDto getCode(String code) {
|
||||
CommonCode commonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
return commonCodeMapper.toCommonCodeDto(commonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getCodesByGroupCode(String groupCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findByGroupCodeAndUseFlagOrderBySortOrderAsc(groupCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getActiveCodesByGroupCode(String groupCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findActiveCodesByGroupCodeOrderBySortOrder(groupCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getCodesByParentCode(String parentCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findByParentCodeAndUseFlagOrderBySortOrderAsc(parentCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getActiveCodesByParentCode(String parentCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findActiveCodesByParentCodeOrderBySortOrder(parentCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getAllCodes() {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findAll();
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
package com.bio.bio_backend.domain.base.file.controller;
|
||||
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.service.FileService;
|
||||
import com.bio.bio_backend.global.dto.ApiResponseDto;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.annotation.LogExecution;
|
||||
import com.bio.bio_backend.global.utils.FileUtils;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.bio.bio_backend.domain.base.file.entity.File;
|
||||
|
||||
|
||||
@Tag(name = "File", description = "파일 업로드/다운로드 API")
|
||||
@RestController
|
||||
@RequestMapping("/files")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class FileController {
|
||||
|
||||
private final FileService fileService;
|
||||
|
||||
@LogExecution("파일 업로드")
|
||||
@Operation(summary = "파일 업로드", description = "단일 파일을 업로드합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "파일 업로드 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "500", description = "파일 업로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/upload")
|
||||
public ResponseEntity<ApiResponseDto<FileUploadResponseDto>> uploadFile(
|
||||
@ModelAttribute FileUploadRequestDto requestDto) {
|
||||
|
||||
FileUploadResponseDto responseDto = fileService.uploadFile(requestDto);
|
||||
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.FILE_UPLOAD_SUCCESS, responseDto));
|
||||
}
|
||||
|
||||
@LogExecution("다중 파일 업로드")
|
||||
@Operation(summary = "다중 파일 업로드", description = "여러 파일을 동시에 업로드합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "다중 파일 업로드 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "500", description = "다중 파일 업로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/upload-multiple")
|
||||
public ResponseEntity<ApiResponseDto<MultipleFileUploadResponseDto>> uploadMultipleFiles(
|
||||
@ModelAttribute MultipleFileUploadRequestDto requestDto) {
|
||||
|
||||
MultipleFileUploadResponseDto responseDto = fileService.uploadMultipleFiles(requestDto);
|
||||
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.FILE_UPLOAD_SUCCESS, responseDto));
|
||||
}
|
||||
|
||||
@LogExecution("파일 다운로드")
|
||||
@Operation(summary = "파일 다운로드", description = "파일 ID로 파일을 다운로드합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "파일 다운로드 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "500", description = "파일 다운로드 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/download/{oid}")
|
||||
public ResponseEntity<ByteArrayResource> downloadFile(@PathVariable Long oid) {
|
||||
// 파일 정보 먼저 조회
|
||||
File file = fileService.getFileByOid(oid);
|
||||
byte[] fileData = fileService.downloadFile(oid);
|
||||
ByteArrayResource resource = new ByteArrayResource(fileData);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=\"" + file.getOriginalFileName() + "\"")
|
||||
.header(HttpHeaders.CONTENT_TYPE, file.getContentType())
|
||||
.body(resource);
|
||||
}
|
||||
|
||||
@LogExecution("파일 논리적 삭제")
|
||||
@Operation(summary = "파일 논리적 삭제", description = "파일 ID로 파일을 논리적으로 삭제합니다. (use_flag를 false로 변경)")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "파일 논리적 삭제 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "파일을 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "500", description = "파일 논리적 삭제 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@DeleteMapping("/{oid}")
|
||||
public ResponseEntity<ApiResponseDto<Void>> deleteFile(@PathVariable Long oid) {
|
||||
fileService.deleteFile(oid);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.FILE_DELETE_SUCCESS));
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class FileUploadDto {
|
||||
private Long groupOid;
|
||||
private List<FileUploadResponseDto> files; // 파일 정보들
|
||||
private int totalCount;
|
||||
private int successCount;
|
||||
private int failureCount;
|
||||
private List<String> errorMessages;
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Data
|
||||
public class FileUploadRequestDto {
|
||||
private MultipartFile file;
|
||||
private String description;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class FileUploadResponseDto {
|
||||
private Long oid;
|
||||
private Long groupOid;
|
||||
private String originalFileName;
|
||||
private String downloadUrl;
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class MultipleFileUploadRequestDto {
|
||||
private List<MultipartFile> files;
|
||||
private String description;
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class MultipleFileUploadResponseDto {
|
||||
private List<FileUploadResponseDto> files;
|
||||
private Long groupOid;
|
||||
private int totalCount;
|
||||
private int successCount;
|
||||
private int failureCount;
|
||||
private List<String> errorMessages;
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package com.bio.bio_backend.domain.base.file.entity;
|
||||
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = AppConstants.TABLE_PREFIX + "file")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class File extends BaseEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String originalFileName;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String storedFileName;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String filePath;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Long fileSize;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String contentType;
|
||||
|
||||
@Column
|
||||
private String description;
|
||||
|
||||
@Column
|
||||
private Long groupOid;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.bio.bio_backend.domain.base.file.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.file.entity.File;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface FileRepository extends JpaRepository<File, Long> {
|
||||
|
||||
// use_flag가 true인 파일만 조회
|
||||
Optional<File> findByOidAndUseFlagTrue(Long id);
|
||||
|
||||
// use_flag가 true인 파일만 조회 (List 형태로 필요시 사용)
|
||||
@Query("SELECT f FROM File f WHERE f.useFlag = true")
|
||||
List<File> findAllActiveFiles();
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.bio.bio_backend.domain.base.file.service;
|
||||
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.entity.File;
|
||||
|
||||
public interface FileService {
|
||||
FileUploadResponseDto uploadFile(FileUploadRequestDto requestDto);
|
||||
MultipleFileUploadResponseDto uploadMultipleFiles(MultipleFileUploadRequestDto requestDto);
|
||||
File getFileByOid(Long oid);
|
||||
byte[] downloadFile(Long oid);
|
||||
void deleteFile(Long oid); // 논리적 삭제 (use_flag를 false로 변경)
|
||||
}
|
@@ -0,0 +1,207 @@
|
||||
package com.bio.bio_backend.domain.base.file.service;
|
||||
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.entity.File;
|
||||
import com.bio.bio_backend.domain.base.file.repository.FileRepository;
|
||||
import com.bio.bio_backend.global.exception.ApiException;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.utils.FileUtils;
|
||||
import com.bio.bio_backend.global.utils.OidUtils;
|
||||
import com.bio.bio_backend.global.utils.SecurityUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
public class FileServiceImpl implements FileService {
|
||||
|
||||
private final FileRepository fileRepository;
|
||||
|
||||
@Value("${app.file.upload.path}")
|
||||
private String uploadPath;
|
||||
|
||||
@Value("${server.servlet.context-path}")
|
||||
private String contextPath;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public FileUploadResponseDto uploadFile(FileUploadRequestDto requestDto) {
|
||||
MultipartFile multipartFile = requestDto.getFile();
|
||||
|
||||
try {
|
||||
// 파일 유효성 검사
|
||||
FileUtils.validateFile(multipartFile);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ApiException(ApiResponseCode.FILE_EMPTY);
|
||||
}
|
||||
|
||||
// 파일 업로드 처리
|
||||
File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), generateOid());
|
||||
|
||||
// 응답 DTO 생성 및 반환
|
||||
return FileUploadResponseDto.builder()
|
||||
.oid(savedFile.getOid())
|
||||
.groupOid(savedFile.getGroupOid())
|
||||
.originalFileName(savedFile.getOriginalFileName())
|
||||
.downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public MultipleFileUploadResponseDto uploadMultipleFiles(MultipleFileUploadRequestDto requestDto) {
|
||||
List<MultipartFile> files = requestDto.getFiles();
|
||||
|
||||
try {
|
||||
// 파일 리스트 유효성 검사
|
||||
FileUtils.validateFileList(files);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ApiException(ApiResponseCode.FILE_EMPTY);
|
||||
}
|
||||
|
||||
List<FileUploadResponseDto> uploadedFiles = new ArrayList<>();
|
||||
List<String> errorMessages = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
int failureCount = 0;
|
||||
|
||||
Long groupOid = generateOid();
|
||||
for (MultipartFile multipartFile : files) {
|
||||
try {
|
||||
// 개별 파일 유효성 검사
|
||||
if (multipartFile.isEmpty()) {
|
||||
String errorMsg = "파일 '" + multipartFile.getOriginalFilename() + "'이 비어있습니다.";
|
||||
errorMessages.add(errorMsg);
|
||||
failureCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 단일 파일 업로드 처리
|
||||
File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), groupOid);
|
||||
FileUploadResponseDto uploadedFile = FileUploadResponseDto.builder()
|
||||
.oid(savedFile.getOid())
|
||||
.originalFileName(savedFile.getOriginalFileName())
|
||||
.downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
|
||||
.build();
|
||||
|
||||
uploadedFiles.add(uploadedFile);
|
||||
successCount++;
|
||||
|
||||
log.info("파일 업로드 성공: {}", multipartFile.getOriginalFilename());
|
||||
|
||||
} catch (Exception ex) {
|
||||
String fileName = multipartFile.getOriginalFilename() != null ? multipartFile.getOriginalFilename() : "알 수 없는 파일";
|
||||
log.error("파일 업로드 실패: {}", fileName, ex);
|
||||
errorMessages.add("파일 '" + fileName + "' 업로드 실패: " + ex.getMessage());
|
||||
failureCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return MultipleFileUploadResponseDto.builder()
|
||||
.groupOid(groupOid)
|
||||
.files(uploadedFiles)
|
||||
.totalCount(files.size())
|
||||
.successCount(successCount)
|
||||
.failureCount(failureCount)
|
||||
.errorMessages(errorMessages)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 업로드 처리
|
||||
*/
|
||||
private File processFileUpload(MultipartFile multipartFile, String description, Long groupOid) {
|
||||
String originalFileName = FileUtils.cleanFileName(multipartFile.getOriginalFilename());
|
||||
|
||||
try {
|
||||
// 항상 년월일 기반으로 폴더 생성 (예: uploads/2024/01/15/)
|
||||
Path uploadDir = FileUtils.createYearMonthUploadDirectory(uploadPath);
|
||||
log.debug("년월 기반 폴더 사용: {}", uploadDir);
|
||||
|
||||
// 파일명 및 확장자 처리
|
||||
String fileExtension = FileUtils.extractFileExtension(originalFileName);
|
||||
String storedFileName = FileUtils.generateUniqueFileName(fileExtension);
|
||||
|
||||
// 파일 저장
|
||||
Path targetLocation = FileUtils.saveFileToDisk(multipartFile, uploadDir, storedFileName);
|
||||
|
||||
// DB에 파일 정보 저장
|
||||
File file = createFileEntity(originalFileName, storedFileName, targetLocation, multipartFile, description, groupOid);
|
||||
|
||||
return fileRepository.save(file);
|
||||
|
||||
} catch (IOException ex) {
|
||||
log.error("파일 업로드 실패: {}", originalFileName, ex);
|
||||
throw new ApiException(ApiResponseCode.FILE_UPLOAD_FAILED, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private File createFileEntity(String originalFileName, String storedFileName, Path targetLocation,
|
||||
MultipartFile multipartFile, String description, Long groupOid) {
|
||||
return File.builder()
|
||||
.originalFileName(originalFileName)
|
||||
.storedFileName(storedFileName)
|
||||
.filePath(targetLocation.toString())
|
||||
.fileSize(multipartFile.getSize())
|
||||
.contentType(multipartFile.getContentType())
|
||||
.description(description)
|
||||
.groupOid(groupOid)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFileByOid(Long oid) {
|
||||
return fileRepository.findByOidAndUseFlagTrue(oid)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.FILE_NOT_FOUND));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] downloadFile(Long oid) {
|
||||
File file = fileRepository.findByOidAndUseFlagTrue(oid)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.FILE_NOT_FOUND));
|
||||
|
||||
try {
|
||||
Path filePath = Paths.get(file.getFilePath());
|
||||
return Files.readAllBytes(filePath);
|
||||
} catch (IOException ex) {
|
||||
log.error("파일 다운로드 실패: {}", file.getOriginalFileName(), ex);
|
||||
throw new ApiException(ApiResponseCode.FILE_DOWNLOAD_FAILED, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteFile(Long oid) {
|
||||
File file = fileRepository.findByOidAndUseFlagTrue(oid)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.FILE_NOT_FOUND));
|
||||
|
||||
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||
// 현재 사용자가 파일 소유자인지 확인
|
||||
if (currentUserId == null || !currentUserId.equals(file.getCreatedId())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_FORBIDDEN);
|
||||
}
|
||||
|
||||
// 논리적 삭제: use_flag를 false로 변경
|
||||
file.setUseFlag(false);
|
||||
fileRepository.save(file);
|
||||
|
||||
log.info("파일 논리적 삭제 완료: oid={}, fileName={}", oid, file.getOriginalFileName());
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
package com.bio.bio_backend.domain.base.member.controller;
|
||||
|
||||
import com.bio.bio_backend.global.dto.ApiResponseDto;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
|
||||
import com.bio.bio_backend.domain.base.member.mapper.MemberMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.annotation.LogExecution;
|
||||
import com.bio.bio_backend.global.utils.SecurityUtils;
|
||||
import com.bio.bio_backend.global.utils.JwtUtils;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
@Tag(name = "Member", description = "회원 관련 API")
|
||||
@RestController
|
||||
@RequestMapping("/members")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MemberController {
|
||||
|
||||
private final MemberService memberService;
|
||||
private final MemberMapper memberMapper;
|
||||
private final JwtUtils jwtUtils;
|
||||
|
||||
@LogExecution("회원 등록")
|
||||
@Operation(summary = "회원 등록", description = "새로운 회원을 등록합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "201", description = "회원 가입 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 사용자 정보", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<ApiResponseDto<CreateMemberResponseDto>> createMember(@RequestBody @Valid CreateMemberRequestDto requestDto) {
|
||||
MemberDto createdMember = memberService.createMember(memberMapper.toMemberDto(requestDto));
|
||||
CreateMemberResponseDto responseDto = memberMapper.toCreateMemberResponseDto(createdMember);
|
||||
ApiResponseDto<CreateMemberResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("로그아웃")
|
||||
@Operation(summary = "로그아웃", description = "사용자 로그아웃을 처리합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "로그아웃 성공"),
|
||||
@ApiResponse(responseCode = "401", description = "인증 실패", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/logout")
|
||||
public ResponseEntity<ApiResponseDto<Void>> logout(HttpServletResponse response) {
|
||||
try {
|
||||
String userId = SecurityUtils.getCurrentUserId();
|
||||
memberService.deleteRefreshToken(userId);
|
||||
|
||||
// 모든 토큰 쿠키 삭제
|
||||
jwtUtils.deleteAllTokenCookies(response);
|
||||
|
||||
log.info("사용자 로그아웃 완료: {}", userId);
|
||||
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS));
|
||||
} catch (Exception e) {
|
||||
log.error("로그아웃 처리 중 오류 발생: {}", e.getMessage());
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Email;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateMemberRequestDto {
|
||||
|
||||
@NotBlank(message = "아이디는 필수입니다.")
|
||||
private String userId;
|
||||
|
||||
@NotBlank(message = "비밀번호는 필수입니다.")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "사용자명은 필수입니다.")
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "이메일은 필수입니다.")
|
||||
@Email(message = "올바른 이메일 형식이 아닙니다.")
|
||||
private String email;
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateMemberResponseDto {
|
||||
|
||||
private Long oid;
|
||||
private String userId;
|
||||
private Boolean useFlag;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginRequestDto {
|
||||
|
||||
@NotBlank(message = "아이디는 필수입니다.")
|
||||
private String userId;
|
||||
|
||||
@NotBlank(message = "비밀번호는 필수입니다.")
|
||||
private String password;
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginResponseDto {
|
||||
|
||||
private String userId;
|
||||
private String name;
|
||||
private LocalDateTime lastLoginAt;
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package com.bio.bio_backend.domain.base.member.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MemberDto implements UserDetails {
|
||||
|
||||
private Long oid;
|
||||
private String userId;
|
||||
private String password;
|
||||
private String name;
|
||||
private String email;
|
||||
private Boolean useFlag;
|
||||
private String refreshToken;
|
||||
private String loginIp;
|
||||
private LocalDateTime lastLoginAt;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.useFlag != null && this.useFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.useFlag != null && this.useFlag;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package com.bio.bio_backend.domain.base.member.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 java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = AppConstants.TABLE_PREFIX + "member",
|
||||
indexes = {
|
||||
@Index(name = "idx_member_user_id", columnList = "user_id")
|
||||
}
|
||||
)
|
||||
public class Member extends BaseEntity {
|
||||
|
||||
@Column(name = "user_id", nullable = false, length = 100)
|
||||
private String userId;
|
||||
|
||||
@Column(name = "password", nullable = false, length = 100)
|
||||
private String password;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "email", nullable = false, length = 255)
|
||||
private String email;
|
||||
|
||||
|
||||
|
||||
@Column(name = "use_flag", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
|
||||
@Column(name = "refresh_token", length = 1024)
|
||||
private String refreshToken;
|
||||
|
||||
@Column(name = "login_ip", length = 45) // IPv6 지원을 위해 45자
|
||||
private String loginIp;
|
||||
|
||||
@Column(name = "last_login_at")
|
||||
private LocalDateTime lastLoginAt;
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.bio.bio_backend.domain.base.member.mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.CreateMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.LoginResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface MemberMapper {
|
||||
|
||||
/**
|
||||
* CreateMemberRequestDto를 MemberDto로 변환
|
||||
* 기본값 설정: useFlag = true
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "useFlag", constant = "true")
|
||||
@Mapping(target = "refreshToken", ignore = true)
|
||||
@Mapping(target = "loginIp", ignore = true)
|
||||
@Mapping(target = "lastLoginAt", ignore = true)
|
||||
@Mapping(target = "createdAt", ignore = true)
|
||||
@Mapping(target = "updatedAt", ignore = true)
|
||||
MemberDto toMemberDto(CreateMemberRequestDto requestDto);
|
||||
|
||||
/**
|
||||
* Member 엔티티를 MemberDto로 변환
|
||||
*/
|
||||
MemberDto toMemberDto(Member member);
|
||||
|
||||
/**
|
||||
* MemberDto를 Member 엔티티로 변환
|
||||
*/
|
||||
Member toMember(MemberDto memberDto);
|
||||
|
||||
/**
|
||||
* Member 엔티티 리스트를 MemberDto 리스트로 변환
|
||||
*/
|
||||
List<MemberDto> toMemberDtoList(List<Member> members);
|
||||
|
||||
/**
|
||||
* MemberDto를 CreateMemberResponseDto로 변환
|
||||
*/
|
||||
CreateMemberResponseDto toCreateMemberResponseDto(MemberDto memberDto);
|
||||
|
||||
/**
|
||||
* MemberDto의 값으로 기존 Member 엔티티 업데이트 (null이 아닌 필드만)
|
||||
*/
|
||||
@IgnoreBaseEntityMapping
|
||||
void updateMemberFromDto(MemberDto memberDto, @org.mapstruct.MappingTarget Member member);
|
||||
|
||||
/**
|
||||
* MemberDto를 LoginResponseDto로 변환
|
||||
*/
|
||||
LoginResponseDto toLoginResponseDto(MemberDto memberDto);
|
||||
}
|
@@ -1,16 +1,17 @@
|
||||
package com.bio.bio_backend.domain.user.member.repository;
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface MemberRepository extends JpaRepository<Member, Long> {
|
||||
|
||||
// 사용자 ID로 회원 조회
|
||||
Member findByUserId(String userId);
|
||||
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
|
||||
|
||||
// 사용자 ID 존재 여부 확인
|
||||
boolean existsByUserId(String userId);
|
||||
|
||||
// 활성화된 회원 목록 조회
|
||||
List<Member> findByUseFlagTrue();
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||
*/
|
||||
public interface MemberRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 활성화된 사용자 중에서 사용자 ID로 검색하여 조회합니다.
|
||||
*
|
||||
* @param userId 사용자 ID
|
||||
* @return Optional<Member> 회원 정보 (없으면 empty)
|
||||
*/
|
||||
Optional<Member> findActiveMemberByUserId(String userId);
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.bio.bio_backend.domain.base.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.base.member.entity.QMember;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* QueryDSL을 활용하여 MemberRepositoryCustom 인터페이스를 구현하는 클래스
|
||||
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||
*/
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class MemberRepositoryImpl implements MemberRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
/**
|
||||
* QMember 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||
*/
|
||||
private final QMember member = QMember.member;
|
||||
|
||||
@Override
|
||||
public Optional<Member> findActiveMemberByUserId(String userId) {
|
||||
// 활성화된 사용자 중에서 사용자 ID로 검색
|
||||
Member foundMember = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.userId.eq(userId)
|
||||
.and(member.useFlag.eq(true)))
|
||||
.fetchOne();
|
||||
|
||||
return Optional.ofNullable(foundMember);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.domain.base.member.service;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface MemberService extends UserDetailsService {
|
||||
|
||||
UserDetails loadUserByUsername(String id);
|
||||
|
||||
MemberDto createMember(MemberDto memberDTO);
|
||||
|
||||
String getRefreshToken(String id);
|
||||
|
||||
void deleteRefreshToken(String id);
|
||||
|
||||
void updateMember(MemberDto member);
|
||||
|
||||
List<MemberDto> selectMemberList(Map<String, String> params);
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
package com.bio.bio_backend.domain.base.member.service;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.base.member.mapper.MemberMapper;
|
||||
import com.bio.bio_backend.domain.base.member.repository.MemberRepository;
|
||||
import com.bio.bio_backend.global.exception.ApiException;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Transactional(readOnly = true)
|
||||
public class MemberServiceImpl implements MemberService {
|
||||
|
||||
private final MemberMapper memberMapper; // MapStruct Mapper 사용
|
||||
private final MemberRepository memberRepository;
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
|
||||
Member member = memberRepository.findActiveMemberByUserId(id)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + id));
|
||||
return memberMapper.toMemberDto(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public MemberDto createMember(MemberDto memberDto) {
|
||||
// userId 중복 체크
|
||||
if (memberRepository.existsByUserId(memberDto.getUserId())) {
|
||||
throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE);
|
||||
}
|
||||
|
||||
Member member = Member.builder()
|
||||
.userId(memberDto.getUserId())
|
||||
.password(bCryptPasswordEncoder.encode(memberDto.getPassword()))
|
||||
.name(memberDto.getName())
|
||||
.email(memberDto.getEmail())
|
||||
.build();
|
||||
|
||||
member.setCreatedOid(AppConstants.ADMIN_OID);
|
||||
member.setCreatedId(AppConstants.ADMIN_USER_ID);
|
||||
member.setUpdatedOid(AppConstants.ADMIN_OID);
|
||||
member.setUpdatedId(AppConstants.ADMIN_USER_ID);
|
||||
|
||||
Member savedMember = memberRepository.save(member);
|
||||
|
||||
return memberMapper.toMemberDto(savedMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateMember(MemberDto memberDto) {
|
||||
Member member = memberRepository.findActiveMemberByUserId(memberDto.getUserId())
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
memberMapper.updateMemberFromDto(memberDto, member);
|
||||
memberRepository.save(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefreshToken(String id) {
|
||||
Member member = memberRepository.findActiveMemberByUserId(id)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
return member.getRefreshToken();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteRefreshToken(String id) {
|
||||
Member member = memberRepository.findActiveMemberByUserId(id)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
member.setRefreshToken(null);
|
||||
memberRepository.save(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MemberDto> selectMemberList(Map<String, String> params) {
|
||||
List<Member> members = memberRepository.findByUseFlagTrue();
|
||||
|
||||
return memberMapper.toMemberDtoList(members);
|
||||
}
|
||||
}
|
@@ -1,129 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import com.bio.bio_backend.domain.user.member.dto.MemberDTO;
|
||||
import com.bio.bio_backend.domain.user.member.dto.CreateMemberRequestDTO;
|
||||
import com.bio.bio_backend.domain.user.member.dto.CreateMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.user.member.service.MemberService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MemberController {
|
||||
|
||||
private final MemberService memberService;
|
||||
private final ModelMapper mapper;
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
|
||||
@GetMapping("/join")
|
||||
public ResponseEntity<String> createMember1() {
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body("test");
|
||||
}
|
||||
|
||||
@PostMapping("/join")
|
||||
public ResponseEntity<CreateMemberResponseDto> createMember(@RequestBody @Valid CreateMemberRequestDTO requestDto) {
|
||||
|
||||
// RequestMember를 MemberDTO로 변환
|
||||
MemberDTO member = new MemberDTO();
|
||||
member.setId(requestDto.getUserId());
|
||||
member.setPw(requestDto.getPassword());
|
||||
|
||||
int oid = memberService.createMember(member);
|
||||
|
||||
// 생성된 회원 정보를 조회하여 응답
|
||||
MemberDTO createdMember = memberService.selectMember(oid);
|
||||
CreateMemberResponseDto responseDto = mapper.map(createdMember, CreateMemberResponseDto.class);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(responseDto);
|
||||
}
|
||||
|
||||
// @PostMapping("/member/list")
|
||||
// public ResponseEntity<List<ResponseMember>> getMemberList(@RequestBody(required = false) Map<String, String> params) {
|
||||
|
||||
// if(params == null){
|
||||
// params = new HashMap<>();
|
||||
// }
|
||||
|
||||
// Iterable<MemberDTO> memberList = memberService.selectMemberList(params);
|
||||
|
||||
// List<ResponseMember> result = new ArrayList<>();
|
||||
|
||||
// memberList.forEach(m -> {
|
||||
// result.add(new ModelMapper().map(m, ResponseMember.class));
|
||||
// });
|
||||
|
||||
// return ResponseEntity.status(HttpStatus.OK).body(result);
|
||||
// }
|
||||
|
||||
// @GetMapping("/member/{seq}")
|
||||
// public ResponseEntity<ResponseMember> selectMember(@PathVariable("seq") int seq) {
|
||||
|
||||
// MemberDTO member = memberService.selectMember(seq);
|
||||
|
||||
// ResponseMember responseMember = mapper.map(member, ResponseMember.class);
|
||||
|
||||
// return ResponseEntity.status(HttpStatus.OK).body(responseMember);
|
||||
// }
|
||||
|
||||
// @PutMapping("/member")
|
||||
// public CustomApiResponse<Void> updateMember(@RequestBody @Valid CreateMemberRequestDTO requestMember, @AuthenticationPrincipal MemberDTO registrant) {
|
||||
// // 현재 JWT는 사용자 id 값을 통하여 생성, 회원정보 변경 시 JWT 재발급 여부 검토
|
||||
|
||||
// MemberDTO member = mapper.map(requestMember, MemberDTO.class);
|
||||
|
||||
// if (requestMember.getPassword() != null) {
|
||||
// member.setPw(bCryptPasswordEncoder.encode(requestMember.getPassword()));
|
||||
// }
|
||||
|
||||
// member.setRegSeq(registrant.getSeq());
|
||||
// memberService.updateMember(member);
|
||||
|
||||
// return CustomApiResponse.success(ApiResponseCode.USER_INFO_CHANGE, null);
|
||||
// }
|
||||
|
||||
// @DeleteMapping("/member")
|
||||
// public CustomApiResponse<Void> deleteMember(@RequestBody @Valid CreateMemberRequestDTO requestMember){
|
||||
|
||||
// MemberDTO member = mapper.map(requestMember, MemberDTO.class);
|
||||
|
||||
// memberService.deleteMember(member);
|
||||
|
||||
// return CustomApiResponse.success(ApiResponseCode.USER_DELETE_SUCCESSFUL, null);
|
||||
// }
|
||||
|
||||
// @PostMapping("/logout")
|
||||
// public CustomApiResponse<Void> logout(@AuthenticationPrincipal MemberDTO member) {
|
||||
|
||||
// String id = member.getId();
|
||||
|
||||
// try {
|
||||
// memberService.deleteRefreshToken(id);
|
||||
// } catch (Exception e) {
|
||||
// return CustomApiResponse.fail(ApiResponseCode.INTERNAL_SERVER_ERROR, null);
|
||||
// }
|
||||
|
||||
// return CustomApiResponse.success(ApiResponseCode.LOGOUT_SUCCESSFUL, null);
|
||||
// }
|
||||
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class CreateMemberRequestDTO {
|
||||
|
||||
@NotBlank(message = "사용자 ID는 필수입니다")
|
||||
private String userId;
|
||||
|
||||
@NotBlank(message = "비밀번호는 필수입니다")
|
||||
private String password;
|
||||
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class CreateMemberResponseDto {
|
||||
private String id;
|
||||
private String pw;
|
||||
}
|
@@ -1,127 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.dto;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import com.bio.bio_backend.global.constants.MemberConstants;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
/**
|
||||
* 회원
|
||||
*/
|
||||
public class MemberDTO implements UserDetails {
|
||||
/**
|
||||
* 시퀀스 (PK)
|
||||
*/
|
||||
private int seq;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* Password
|
||||
*/
|
||||
private String pw;
|
||||
|
||||
/**
|
||||
* 권한
|
||||
*/
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* 회원 상태
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 가입 일시
|
||||
*/
|
||||
private Timestamp regAt;
|
||||
|
||||
/**
|
||||
* 등록자
|
||||
*/
|
||||
private int regSeq;
|
||||
|
||||
/**
|
||||
* 수정 일시
|
||||
*/
|
||||
private Timestamp udtAt;
|
||||
|
||||
/**
|
||||
* 수정자
|
||||
*/
|
||||
private int udtSeq;
|
||||
|
||||
/**
|
||||
* 최근 로그인 일시
|
||||
*/
|
||||
private Timestamp lastLoginAt;
|
||||
|
||||
/**
|
||||
* Refresh Token
|
||||
*/
|
||||
private String refreshToken;
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
|
||||
Set<GrantedAuthority> roles = new HashSet<>();
|
||||
String auth = "";
|
||||
|
||||
|
||||
if(role.equals("SYSTEM_ADMIN")){
|
||||
auth = MemberConstants.ROLE_SYSTEM_ADMIN + "," +
|
||||
MemberConstants.ROLE_ADMIN + "," + MemberConstants.ROLE_MEMBER;
|
||||
}else if(role.equals("ADMIN")){
|
||||
auth = MemberConstants.ROLE_ADMIN + "," + MemberConstants.ROLE_MEMBER;
|
||||
}else {
|
||||
auth = MemberConstants.ROLE_MEMBER;
|
||||
}
|
||||
|
||||
for (String x : auth.split(",")) {
|
||||
roles.add(new SimpleGrantedAuthority(x));
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return pw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = "member",
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(name = "uk_member_user_id", columnNames = "user_id")
|
||||
}
|
||||
)
|
||||
public class Member extends BaseEntity {
|
||||
|
||||
@Column(name = "user_id", nullable = false, length = 100)
|
||||
private String userId;
|
||||
|
||||
@Column(name = "password", nullable = false, length = 100)
|
||||
private String password;
|
||||
|
||||
@Column(name = "role", nullable = false, length = 40)
|
||||
private String role;
|
||||
|
||||
@Column(name = "status", nullable = false, length = 1)
|
||||
private String status;
|
||||
|
||||
@Column(name = "refresh_token", length = 200)
|
||||
private String refreshToken;
|
||||
|
||||
@Column(name = "last_login_at")
|
||||
private LocalDateTime lastLoginAt;
|
||||
}
|
@@ -1,27 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.dto.MemberDTO;
|
||||
|
||||
@Mapper
|
||||
public interface MemberMapper {
|
||||
int createMember(MemberDTO memberDTO);
|
||||
|
||||
MemberDTO loadUserByUsername(String id);
|
||||
|
||||
void updateRefreshToken(MemberDTO memberDTO);
|
||||
|
||||
String getRefreshToken(String id);
|
||||
|
||||
int deleteRefreshToken(String id);
|
||||
|
||||
List<MemberDTO> selectMemberList(Map<String, String> params);
|
||||
|
||||
MemberDTO selectMemberBySeq(int seq);
|
||||
|
||||
int updateMember(MemberDTO member);
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.entity.Member;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* QueryDSL을 활용한 커스텀 쿼리 메서드들을 정의하는 인터페이스
|
||||
* 복잡한 쿼리나 동적 쿼리가 필요한 경우 이 인터페이스를 구현하여 사용합니다.
|
||||
*/
|
||||
public interface MemberRepositoryCustom {
|
||||
|
||||
/**
|
||||
* 사용자 ID로 회원을 조회합니다.
|
||||
* QueryDSL을 사용하여 더 유연한 쿼리 작성이 가능합니다.
|
||||
*
|
||||
* @param userId 사용자 ID
|
||||
* @return Optional<Member> 회원 정보 (없으면 empty)
|
||||
*/
|
||||
Optional<Member> findByUserIdCustom(String userId);
|
||||
|
||||
/**
|
||||
* 역할(Role)별로 회원 목록을 조회합니다.
|
||||
*
|
||||
* @param role 회원 역할
|
||||
* @return List<Member> 해당 역할을 가진 회원 목록
|
||||
*/
|
||||
List<Member> findByRole(String role);
|
||||
|
||||
/**
|
||||
* 상태(Status)별로 회원 목록을 조회합니다.
|
||||
*
|
||||
* @param status 회원 상태
|
||||
* @return List<Member> 해당 상태를 가진 회원 목록
|
||||
*/
|
||||
List<Member> findByStatus(String status);
|
||||
|
||||
/**
|
||||
* 사용자 ID와 상태로 회원을 조회합니다.
|
||||
*
|
||||
* @param userId 사용자 ID
|
||||
* @param status 회원 상태
|
||||
* @return Optional<Member> 회원 정보
|
||||
*/
|
||||
Optional<Member> findByUserIdAndStatus(String userId, String status);
|
||||
|
||||
/**
|
||||
* 검색 조건에 따른 회원 목록을 페이징하여 조회합니다.
|
||||
*
|
||||
* @param userId 사용자 ID (부분 검색)
|
||||
* @param role 회원 역할
|
||||
* @param status 회원 상태
|
||||
* @param pageable 페이징 정보
|
||||
* @return Page<Member> 페이징된 회원 목록
|
||||
*/
|
||||
Page<Member> findMembersByCondition(String userId, String role, String status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 마지막 로그인 시간이 특정 시간 이후인 회원들을 조회합니다.
|
||||
*
|
||||
* @param lastLoginAfter 마지막 로그인 기준 시간
|
||||
* @return List<Member> 해당 조건을 만족하는 회원 목록
|
||||
*/
|
||||
List<Member> findActiveMembersByLastLogin(java.time.LocalDateTime lastLoginAfter);
|
||||
}
|
@@ -1,130 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.user.member.entity.QMember;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* QueryDSL을 활용하여 MemberRepositoryCustom 인터페이스를 구현하는 클래스
|
||||
* 복잡한 쿼리나 동적 쿼리를 QueryDSL로 작성하여 성능과 가독성을 향상시킵니다.
|
||||
*/
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class MemberRepositoryImpl implements MemberRepositoryCustom {
|
||||
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
/**
|
||||
* QMember 인스턴스를 생성하여 쿼리에서 사용합니다.
|
||||
* QueryDSL의 Q클래스를 통해 타입 안전한 쿼리 작성이 가능합니다.
|
||||
*/
|
||||
private final QMember member = QMember.member;
|
||||
|
||||
@Override
|
||||
public Optional<Member> findByUserIdCustom(String userId) {
|
||||
// QueryDSL을 사용하여 사용자 ID로 회원을 조회합니다.
|
||||
// eq() 메서드를 사용하여 정확한 일치 조건을 설정합니다.
|
||||
Member foundMember = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.userId.eq(userId))
|
||||
.fetchOne();
|
||||
|
||||
return Optional.ofNullable(foundMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Member> findByRole(String role) {
|
||||
// 역할별로 회원을 조회합니다.
|
||||
// eq() 메서드를 사용하여 정확한 일치 조건을 설정합니다.
|
||||
return queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.role.eq(role))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Member> findByStatus(String status) {
|
||||
// 상태별로 회원을 조회합니다.
|
||||
return queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.status.eq(status))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Member> findByUserIdAndStatus(String userId, String status) {
|
||||
// 사용자 ID와 상태를 모두 만족하는 회원을 조회합니다.
|
||||
// and() 메서드를 사용하여 여러 조건을 결합합니다.
|
||||
Member foundMember = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.userId.eq(userId)
|
||||
.and(member.status.eq(status)))
|
||||
.fetchOne();
|
||||
|
||||
return Optional.ofNullable(foundMember);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Member> findMembersByCondition(String userId, String role, String status, Pageable pageable) {
|
||||
// BooleanBuilder를 사용하여 동적 쿼리를 구성합니다.
|
||||
// null이 아닌 조건만 쿼리에 포함시킵니다.
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
// 사용자 ID가 제공된 경우 부분 검색 조건을 추가합니다.
|
||||
if (userId != null && !userId.trim().isEmpty()) {
|
||||
builder.and(member.userId.containsIgnoreCase(userId));
|
||||
}
|
||||
|
||||
// 역할이 제공된 경우 정확한 일치 조건을 추가합니다.
|
||||
if (role != null && !role.trim().isEmpty()) {
|
||||
builder.and(member.role.eq(role));
|
||||
}
|
||||
|
||||
// 상태가 제공된 경우 정확한 일치 조건을 추가합니다.
|
||||
if (status != null && !status.trim().isEmpty()) {
|
||||
builder.and(member.status.eq(status));
|
||||
}
|
||||
|
||||
// 전체 개수를 조회합니다.
|
||||
long total = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(builder)
|
||||
.fetchCount();
|
||||
|
||||
// 페이징 조건을 적용하여 결과를 조회합니다.
|
||||
List<Member> content = queryFactory
|
||||
.selectFrom(member)
|
||||
.where(builder)
|
||||
.orderBy(member.createdAt.desc()) // 생성일 기준 내림차순 정렬
|
||||
.offset(pageable.getOffset())
|
||||
.limit(pageable.getPageSize())
|
||||
.fetch();
|
||||
|
||||
// Page 객체를 생성하여 반환합니다.
|
||||
return new PageImpl<>(content, pageable, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Member> findActiveMembersByLastLogin(LocalDateTime lastLoginAfter) {
|
||||
// 마지막 로그인 시간이 특정 시간 이후인 활성 회원들을 조회합니다.
|
||||
// 여러 조건을 조합하여 복잡한 쿼리를 작성합니다.
|
||||
return queryFactory
|
||||
.selectFrom(member)
|
||||
.where(member.status.eq("A") // 활성 상태
|
||||
.and(member.lastLoginAt.isNotNull()) // 마지막 로그인 시간이 존재
|
||||
.and(member.lastLoginAt.after(lastLoginAfter))) // 특정 시간 이후
|
||||
.orderBy(member.lastLoginAt.desc()) // 마지막 로그인 시간 기준 내림차순 정렬
|
||||
.fetch();
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.dto.MemberDTO;
|
||||
|
||||
public interface MemberService extends UserDetailsService {
|
||||
|
||||
UserDetails loadUserByUsername(String id);
|
||||
|
||||
int createMember(MemberDTO memberDTO);
|
||||
|
||||
void updateRefreshToken(MemberDTO memberDTO);
|
||||
|
||||
String getRefreshToken(String id);
|
||||
|
||||
int deleteRefreshToken(String id);
|
||||
|
||||
List<MemberDTO> selectMemberList(Map<String, String> params);
|
||||
|
||||
MemberDTO selectMember(int seq);
|
||||
|
||||
int updateMember(MemberDTO member);
|
||||
|
||||
int deleteMember(MemberDTO member);
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
package com.bio.bio_backend.domain.user.member.service;
|
||||
|
||||
import com.bio.bio_backend.domain.user.member.dto.MemberDTO;
|
||||
import com.bio.bio_backend.domain.user.member.entity.Member;
|
||||
import com.bio.bio_backend.domain.user.member.mapper.MemberMapper;
|
||||
import com.bio.bio_backend.domain.user.member.repository.MemberRepository;
|
||||
import com.bio.bio_backend.global.constants.MemberConstants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MemberServiceImpl implements MemberService {
|
||||
|
||||
private final MemberMapper memberMapper;
|
||||
private final MemberRepository memberRepository;
|
||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
|
||||
|
||||
MemberDTO member = memberMapper.loadUserByUsername(id);
|
||||
|
||||
if (member == null) {
|
||||
throw new UsernameNotFoundException("User not found with id : " + id);
|
||||
}
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int createMember(MemberDTO memberDTO) {
|
||||
// JPA Entity를 사용하여 회원 생성
|
||||
Member member = Member.builder()
|
||||
.userId(memberDTO.getId())
|
||||
.password(bCryptPasswordEncoder.encode(memberDTO.getPw()))
|
||||
.role(MemberConstants.ROLE_MEMBER)
|
||||
.status(MemberConstants.MEMBER_ACTIVE)
|
||||
.build();
|
||||
|
||||
// JPA 레파지토리를 통해 저장
|
||||
Member savedMember = memberRepository.save(member);
|
||||
|
||||
// 저장된 회원의 oid를 반환
|
||||
return savedMember.getOid().intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRefreshToken(MemberDTO memberDTO) {
|
||||
memberMapper.updateRefreshToken(memberDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefreshToken(String id) {
|
||||
return memberMapper.getRefreshToken(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteRefreshToken(String id) {
|
||||
return memberMapper.deleteRefreshToken(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MemberDTO> selectMemberList(Map<String, String> params) {
|
||||
return memberMapper.selectMemberList(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemberDTO selectMember(int seq) {
|
||||
return memberMapper.selectMemberBySeq(seq);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateMember(MemberDTO member) {
|
||||
return memberMapper.updateMember(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteMember(MemberDTO member) {
|
||||
|
||||
member.setStatus(MemberConstants.MEMBER_INACTIVE);
|
||||
|
||||
log.info(member.toString());
|
||||
|
||||
return memberMapper.updateMember(member);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.global.annotation;
|
||||
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* BaseEntity의 감사 필드들을 ignore 처리하는 MapStruct 커스텀 어노테이션
|
||||
* 여러 매퍼에서 공통으로 사용할 수 있습니다.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "createdAt", ignore = true)
|
||||
@Mapping(target = "updatedAt", ignore = true)
|
||||
@Mapping(target = "createdOid", ignore = true)
|
||||
@Mapping(target = "updatedOid", ignore = true)
|
||||
@Mapping(target = "createdId", ignore = true)
|
||||
@Mapping(target = "updatedId", ignore = true)
|
||||
public @interface IgnoreBaseEntityMapping {
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.bio.bio_backend.global.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 메서드 실행 로깅 어노테이션
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface LogExecution {
|
||||
String value() default "";
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package com.bio.bio_backend.global.aop;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MethodExecutionLoggingAspect {
|
||||
|
||||
@Around("@annotation(logExecution)")
|
||||
public Object logExecution(ProceedingJoinPoint pjp, com.bio.bio_backend.global.annotation.LogExecution logExecution) throws Throwable {
|
||||
String message = logExecution.value().isEmpty() ?
|
||||
pjp.getSignature().getName() : logExecution.value();
|
||||
|
||||
String className = pjp.getTarget().getClass().getSimpleName();
|
||||
String methodName = pjp.getSignature().getName();
|
||||
|
||||
String userInfo = getCurrentUser();
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.info("[START] {} | 호출경로: {}.{} | 사용자: {}",
|
||||
message, className, methodName, userInfo);
|
||||
|
||||
try {
|
||||
Object result = pjp.proceed();
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.info("[SUCCESS] {} | 호출경로: {}.{} | 사용자: {} | 시간: {}ms",
|
||||
message, className, methodName, userInfo, duration);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
long duration = System.currentTimeMillis() - startTime;
|
||||
log.error("[FAILED] {} | 호출경로: {}.{} | 사용자: {} | 시간: {}ms | 오류: {}",
|
||||
message, className, methodName, userInfo, duration, e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private String getCurrentUser() {
|
||||
try {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth != null && auth.isAuthenticated() && !"anonymousUser".equals(auth.getName())) {
|
||||
return auth.getName();
|
||||
}
|
||||
return "인증되지 않은 사용자";
|
||||
} catch (Exception e) {
|
||||
return "알 수 없는 사용자";
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,21 +6,13 @@ import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Repository 계층의 메서드 호출을 로깅하는 AOP(Aspect-Oriented Programming) 클래스
|
||||
* 모든 Repository 인터페이스의 메서드 호출 시점과 실행 시간을 로그로 기록합니다.
|
||||
*/
|
||||
@Aspect // AOP 기능을 활성화하는 어노테이션
|
||||
@Component // Spring Bean으로 등록하는 어노테이션
|
||||
@Slf4j // Lombok의 로깅 기능을 제공하는 어노테이션
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RepositoryLoggingAspect {
|
||||
|
||||
/**
|
||||
* Repository 계층의 모든 메서드 호출을 가로채서 로깅하는 Around 어드바이스
|
||||
*
|
||||
* @param pjp ProceedingJoinPoint - 실행될 메서드의 정보를 담고 있는 객체
|
||||
* @return Object - 원본 메서드의 실행 결과
|
||||
* @throws Throwable - 원본 메서드에서 발생할 수 있는 예외
|
||||
*/
|
||||
@Around("execution(* org.springframework.data.repository.Repository+.*(..))")
|
||||
public Object logQueryCall(ProceedingJoinPoint pjp) throws Throwable {
|
||||
@@ -47,10 +39,7 @@ public class RepositoryLoggingAspect {
|
||||
// 원본 메서드의 결과를 반환
|
||||
return result;
|
||||
} catch (Throwable ex) {
|
||||
// 메서드 실행 중 예외 발생 시 로그로 기록
|
||||
log.warn("[QUERY FAIL] {}.{}() -> {}", type, method, ex.toString());
|
||||
|
||||
// 예외를 다시 던져서 원래의 예외 처리 흐름을 유지
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
package com.bio.bio_backend.global.config;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Configuration
|
||||
public class AppConfig {
|
||||
@@ -20,7 +20,19 @@ public class AppConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ModelMapper modelMapper() {
|
||||
return new ModelMapper();
|
||||
public ObjectMapper objectMapper() {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
// JavaTimeModule 등록
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
|
||||
// LocalDateTime 직렬화/역직렬화 설정
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
|
||||
|
||||
mapper.registerModule(javaTimeModule);
|
||||
|
||||
return mapper;
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.global.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
config.setAllowCredentials(true);
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
|
||||
return new CorsFilter(source);
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package com.bio.bio_backend.global.config;
|
||||
|
||||
import org.mapstruct.*;
|
||||
|
||||
@MapperConfig(
|
||||
componentModel = "spring",
|
||||
|
||||
// null 값은 매핑하지 않음 (부분 업데이트)
|
||||
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
|
||||
|
||||
// NPE 방지용 null 체크
|
||||
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||
|
||||
// 매핑 누락 시 컴파일 오류
|
||||
unmappedTargetPolicy = ReportingPolicy.ERROR,
|
||||
|
||||
// 컬렉션 매핑 전략
|
||||
collectionMappingStrategy = CollectionMappingStrategy.ACCESSOR_ONLY
|
||||
)
|
||||
public interface GlobalMapperConfig {
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user