Compare commits
	
		
			3 Commits
		
	
	
		
			a21d9909ec
			...
			9468d19736
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9468d19736 | |||
| fcf150922e | |||
| 544cec0e81 | 
							
								
								
									
										41
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								build.gradle
									
									
									
									
									
								
							@@ -1,3 +1,9 @@
 | 
				
			|||||||
 | 
					buildscript {
 | 
				
			||||||
 | 
						ext {
 | 
				
			||||||
 | 
							queryDslVersion = "5.0.0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugins {
 | 
					plugins {
 | 
				
			||||||
	id 'java'
 | 
						id 'java'
 | 
				
			||||||
	id 'org.springframework.boot' version '3.5.4'
 | 
						id 'org.springframework.boot' version '3.5.4'
 | 
				
			||||||
@@ -30,13 +36,48 @@ dependencies {
 | 
				
			|||||||
	// PostgreSQL JDBC 드라이버
 | 
						// PostgreSQL JDBC 드라이버
 | 
				
			||||||
    runtimeOnly 'org.postgresql:postgresql'
 | 
					    runtimeOnly 'org.postgresql:postgresql'
 | 
				
			||||||
	implementation 'org.springframework.boot:spring-boot-starter-web'
 | 
						implementation 'org.springframework.boot:spring-boot-starter-web'
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Spring Security 추가
 | 
				
			||||||
 | 
						implementation 'org.springframework.boot:spring-boot-starter-security'
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Validation 추가
 | 
				
			||||||
 | 
						implementation 'org.springframework.boot:spring-boot-starter-validation'
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// ModelMapper 추가
 | 
				
			||||||
 | 
						implementation 'org.modelmapper:modelmapper:3.0.0'
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// MyBatis 추가
 | 
				
			||||||
 | 
						implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	compileOnly 'org.projectlombok:lombok'
 | 
						compileOnly 'org.projectlombok:lombok'
 | 
				
			||||||
	annotationProcessor 'org.projectlombok:lombok'
 | 
						annotationProcessor 'org.projectlombok:lombok'
 | 
				
			||||||
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
 | 
						testImplementation 'org.springframework.boot:spring-boot-starter-test'
 | 
				
			||||||
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
 | 
						testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// querydsl
 | 
				
			||||||
 | 
						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"
 | 
				
			||||||
 | 
						// p6spy
 | 
				
			||||||
 | 
						implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tasks.named('test') {
 | 
					tasks.named('test') {
 | 
				
			||||||
	useJUnitPlatform()
 | 
						useJUnitPlatform()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// querydsl
 | 
				
			||||||
 | 
					def querydslDir = "$buildDir/generated/querydsl"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sourceSets {
 | 
				
			||||||
 | 
						main.java.srcDirs += [ querydslDir ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.withType(JavaCompile) {
 | 
				
			||||||
 | 
						options.annotationProcessorGeneratedSourcesDirectory = file(querydslDir)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clean.doLast {
 | 
				
			||||||
 | 
						file(querydslDir).deleteDir()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								ddl/schema.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ddl/schema.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					    create table member (
 | 
				
			||||||
 | 
					        status varchar(1) not null,
 | 
				
			||||||
 | 
					        created_at timestamp(6) not null,
 | 
				
			||||||
 | 
					        last_login_at timestamp(6),
 | 
				
			||||||
 | 
					        oid bigint generated by default as identity,
 | 
				
			||||||
 | 
					        updated_at timestamp(6) not null,
 | 
				
			||||||
 | 
					        role varchar(40) 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)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
@@ -2,8 +2,10 @@ package com.bio.bio_backend;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import org.springframework.boot.SpringApplication;
 | 
					import org.springframework.boot.SpringApplication;
 | 
				
			||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
					import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
				
			||||||
 | 
					import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@SpringBootApplication
 | 
					@SpringBootApplication
 | 
				
			||||||
 | 
					@EnableJpaAuditing
 | 
				
			||||||
public class BioBackendApplication {
 | 
					public class BioBackendApplication {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static void main(String[] args) {
 | 
						public static void main(String[] args) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
package com.bio.bio_backend.controller;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RequestBody;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
					 | 
				
			||||||
import org.springframework.web.bind.annotation.RestController;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.bio.bio_backend.entity.Test;
 | 
					 | 
				
			||||||
import com.bio.bio_backend.repository.TestRepository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@RestController
 | 
					 | 
				
			||||||
@RequestMapping("/api/test")
 | 
					 | 
				
			||||||
public class TestController {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private final TestRepository repository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public TestController(TestRepository repository){
 | 
					 | 
				
			||||||
            this.repository = repository;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @GetMapping
 | 
					 | 
				
			||||||
    public List<Test> getAllUsers(){
 | 
					 | 
				
			||||||
        System.out.println("test10099!!");
 | 
					 | 
				
			||||||
        return repository.findAll();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @PostMapping
 | 
					 | 
				
			||||||
    public Test creatTest(@RequestBody Test test){
 | 
					 | 
				
			||||||
        return repository.save(test);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,129 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,127 @@
 | 
				
			|||||||
 | 
					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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.domain.user.member.repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.data.jpa.repository.JpaRepository;
 | 
				
			||||||
 | 
					import org.springframework.stereotype.Repository;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.bio.bio_backend.domain.user.member.entity.Member;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Repository
 | 
				
			||||||
 | 
					public interface MemberRepository extends JpaRepository<Member, Long> {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // 사용자 ID로 회원 조회
 | 
				
			||||||
 | 
					    Member findByUserId(String userId);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // 사용자 ID 존재 여부 확인
 | 
				
			||||||
 | 
					    boolean existsByUserId(String userId);
 | 
				
			||||||
 | 
					} 
 | 
				
			||||||
@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					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();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,19 +0,0 @@
 | 
				
			|||||||
package com.bio.bio_backend.entity;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import jakarta.persistence.Entity;
 | 
					 | 
				
			||||||
import jakarta.persistence.GeneratedValue;
 | 
					 | 
				
			||||||
import jakarta.persistence.GenerationType;
 | 
					 | 
				
			||||||
import jakarta.persistence.Id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@Entity
 | 
					 | 
				
			||||||
public class Test {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Id
 | 
					 | 
				
			||||||
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Long id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private String name;
 | 
					 | 
				
			||||||
    private String email;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					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.stereotype.Component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Repository 계층의 메서드 호출을 로깅하는 AOP(Aspect-Oriented Programming) 클래스
 | 
				
			||||||
 | 
					 * 모든 Repository 인터페이스의 메서드 호출 시점과 실행 시간을 로그로 기록합니다.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Aspect  // AOP 기능을 활성화하는 어노테이션
 | 
				
			||||||
 | 
					@Component  // Spring Bean으로 등록하는 어노테이션
 | 
				
			||||||
 | 
					@Slf4j  // Lombok의 로깅 기능을 제공하는 어노테이션
 | 
				
			||||||
 | 
					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 {
 | 
				
			||||||
 | 
					        // 메서드 실행 시작 시간을 기록
 | 
				
			||||||
 | 
					        long t0 = System.currentTimeMillis();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // 실행될 메서드의 클래스명과 메서드명을 추출
 | 
				
			||||||
 | 
					        String type = pjp.getSignature().getDeclaringTypeName();
 | 
				
			||||||
 | 
					        String method = pjp.getSignature().getName();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // 메서드 호출 시 전달되는 매개변수들을 추출
 | 
				
			||||||
 | 
					        Object[] args = pjp.getArgs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 메서드 호출 시작을 로그로 기록
 | 
				
			||||||
 | 
					        log.info("[QUERY CALL] {}.{}(args={})", type, method, java.util.Arrays.toString(args));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // 원본 메서드를 실행
 | 
				
			||||||
 | 
					            Object result = pjp.proceed();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // 메서드 실행 완료를 로그로 기록 (실행 시간 포함)
 | 
				
			||||||
 | 
					            log.info("[QUERY DONE] {}.{}() in {}ms", type, method, (System.currentTimeMillis() - t0));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // 원본 메서드의 결과를 반환
 | 
				
			||||||
 | 
					            return result;
 | 
				
			||||||
 | 
					        } catch (Throwable ex) {
 | 
				
			||||||
 | 
					            // 메서드 실행 중 예외 발생 시 로그로 기록
 | 
				
			||||||
 | 
					            log.warn("[QUERY FAIL] {}.{}() -> {}", type, method, ex.toString());
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // 예외를 다시 던져서 원래의 예외 처리 흐름을 유지
 | 
				
			||||||
 | 
					            throw ex;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.global.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.modelmapper.ModelMapper;
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					public class AppConfig {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public BCryptPasswordEncoder bCryptPasswordEncoder() {
 | 
				
			||||||
 | 
					        return new BCryptPasswordEncoder();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public ModelMapper modelMapper() {
 | 
				
			||||||
 | 
					        return new ModelMapper();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.global.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.querydsl.jpa.impl.JPAQueryFactory;
 | 
				
			||||||
 | 
					import jakarta.persistence.EntityManager;
 | 
				
			||||||
 | 
					import jakarta.persistence.PersistenceContext;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * QueryDSL 설정을 위한 Configuration 클래스
 | 
				
			||||||
 | 
					 * JPAQueryFactory Bean을 등록하여 QueryDSL을 사용할 수 있도록 합니다.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Configuration
 | 
				
			||||||
 | 
					public class QuerydslConfig {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * JPA EntityManager를 주입받습니다.
 | 
				
			||||||
 | 
					     * @PersistenceContext 어노테이션을 사용하여 Spring이 관리하는 EntityManager를 주입받습니다.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @PersistenceContext
 | 
				
			||||||
 | 
					    private EntityManager entityManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * JPAQueryFactory Bean을 생성하여 등록합니다.
 | 
				
			||||||
 | 
					     * 이 Bean은 QueryDSL을 사용하는 Repository에서 주입받아 사용됩니다.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return JPAQueryFactory 인스턴스
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    public JPAQueryFactory jpaQueryFactory() {
 | 
				
			||||||
 | 
					        return new JPAQueryFactory(entityManager);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.global.constants;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Member 엔티티에서 사용하는 상수들을 정의하는 클래스
 | 
				
			||||||
 | 
					 * 역할(Role)과 상태(Status) 등의 상수값을 관리합니다.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class MemberConstants {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 회원 역할 상수
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final String ROLE_MEMBER = "MEMBER";        // 일반 회원
 | 
				
			||||||
 | 
					    public static final String ROLE_ADMIN = "ADMIN";          // 관리자
 | 
				
			||||||
 | 
					    public static final String ROLE_USER = "USER";            // 사용자
 | 
				
			||||||
 | 
					    public static final String ROLE_SYSTEM_ADMIN = "SYSTEM_ADMIN"; // 시스템 관리자
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 회원 상태 상수
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final String MEMBER_ACTIVE = "A";           // 활성 상태 (Active)
 | 
				
			||||||
 | 
					    public static final String MEMBER_INACTIVE = "I";         // 비활성 상태 (Inactive)
 | 
				
			||||||
 | 
					    public static final String MEMBER_SUSPENDED = "S";        // 정지 상태 (Suspended)
 | 
				
			||||||
 | 
					    public static final String MEMBER_DELETED = "D";          // 삭제 상태 (Deleted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 기본값 상수
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final String DEFAULT_ROLE = ROLE_MEMBER;    // 기본 역할
 | 
				
			||||||
 | 
					    public static final String DEFAULT_STATUS = MEMBER_ACTIVE; // 기본 상태
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 유효성 검사 상수
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static final int MIN_USER_ID_LENGTH = 4;           // 사용자 ID 최소 길이
 | 
				
			||||||
 | 
					    public static final int MAX_USER_ID_LENGTH = 20;          // 사용자 ID 최대 길이
 | 
				
			||||||
 | 
					    public static final int MIN_PASSWORD_LENGTH = 8;          // 비밀번호 최소 길이
 | 
				
			||||||
 | 
					    public static final int MAX_PASSWORD_LENGTH = 100;        // 비밀번호 최대 길이
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					package com.bio.bio_backend.global.entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jakarta.persistence.*;
 | 
				
			||||||
 | 
					import lombok.Getter;
 | 
				
			||||||
 | 
					import lombok.Setter;
 | 
				
			||||||
 | 
					import org.springframework.data.annotation.CreatedDate;
 | 
				
			||||||
 | 
					import org.springframework.data.annotation.LastModifiedDate;
 | 
				
			||||||
 | 
					import org.springframework.data.jpa.domain.support.AuditingEntityListener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.time.LocalDateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 모든 엔티티가 상속받는 기본 엔티티 클래스
 | 
				
			||||||
 | 
					 * 공통 필드들을 정의하고 JPA Auditing을 지원합니다.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Getter
 | 
				
			||||||
 | 
					@Setter
 | 
				
			||||||
 | 
					@MappedSuperclass
 | 
				
			||||||
 | 
					@EntityListeners(AuditingEntityListener.class)
 | 
				
			||||||
 | 
					public abstract class BaseEntity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 엔티티의 고유 식별자 (Primary Key)
 | 
				
			||||||
 | 
					     * 자동 증가하는 Long 타입으로 설정
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Id
 | 
				
			||||||
 | 
					    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
				
			||||||
 | 
					    @Column(name = "oid", nullable = false)
 | 
				
			||||||
 | 
					    private Long oid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 엔티티 생성 시간
 | 
				
			||||||
 | 
					     * JPA Auditing을 통해 자동으로 설정됨
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @CreatedDate
 | 
				
			||||||
 | 
					    @Column(name = "created_at", nullable = false, updatable = false)
 | 
				
			||||||
 | 
					    private LocalDateTime createdAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 엔티티 수정 시간
 | 
				
			||||||
 | 
					     * JPA Auditing을 통해 자동으로 설정됨
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @LastModifiedDate
 | 
				
			||||||
 | 
					    @Column(name = "updated_at", nullable = false)
 | 
				
			||||||
 | 
					    private LocalDateTime updatedAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 엔티티 저장 전에 실행되는 메서드
 | 
				
			||||||
 | 
					     * 생성 시간과 수정 시간을 자동으로 설정
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @PrePersist
 | 
				
			||||||
 | 
					    protected void onCreate() {
 | 
				
			||||||
 | 
					        LocalDateTime now = LocalDateTime.now();
 | 
				
			||||||
 | 
					        this.createdAt = now;
 | 
				
			||||||
 | 
					        this.updatedAt = now;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 엔티티 수정 전에 실행되는 메서드
 | 
				
			||||||
 | 
					     * 수정 시간을 자동으로 설정
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @PreUpdate
 | 
				
			||||||
 | 
					    protected void onUpdate() {
 | 
				
			||||||
 | 
					        this.updatedAt = LocalDateTime.now();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
package com.bio.bio_backend.repository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.bio.bio_backend.entity.Test;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public interface TestRepository extends JpaRepository<Test,Long>{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -9,9 +9,9 @@ spring.devtools.restart.additional-paths=src/main/java
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# 데이터베이스 연결 정보
 | 
					# 데이터베이스 연결 정보
 | 
				
			||||||
# URL 형식: jdbc:postgresql://[호스트명]:[포트번호]/[데이터베이스명]
 | 
					# URL 형식: jdbc:postgresql://[호스트명]:[포트번호]/[데이터베이스명]
 | 
				
			||||||
spring.datasource.url=jdbc:postgresql://stam.kr:15432/mms
 | 
					spring.datasource.url=jdbc:postgresql://stam.kr:15432/imas
 | 
				
			||||||
spring.datasource.username=mms_user
 | 
					spring.datasource.username=imas_user
 | 
				
			||||||
spring.datasource.password=tam1201
 | 
					spring.datasource.password=stam1201
 | 
				
			||||||
spring.datasource.driver-class-name=org.postgresql.Driver
 | 
					spring.datasource.driver-class-name=org.postgresql.Driver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# JPA/Hibernate 설정
 | 
					# JPA/Hibernate 설정
 | 
				
			||||||
@@ -21,13 +21,26 @@ spring.datasource.driver-class-name=org.postgresql.Driver
 | 
				
			|||||||
# - update: 엔티티 변경 시 스키마 업데이트 (개발용)
 | 
					# - update: 엔티티 변경 시 스키마 업데이트 (개발용)
 | 
				
			||||||
# - validate: 엔티티와 스키마 일치 여부만 검증 (운영용)
 | 
					# - validate: 엔티티와 스키마 일치 여부만 검증 (운영용)
 | 
				
			||||||
# - none: 아무 작업도 하지 않음
 | 
					# - none: 아무 작업도 하지 않음
 | 
				
			||||||
spring.jpa.hibernate.ddl-auto=update
 | 
					spring.jpa.hibernate.ddl-auto=none
 | 
				
			||||||
 | 
					spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
 | 
				
			||||||
 | 
					spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=ddl/schema.sql
 | 
				
			||||||
 | 
					spring.jpa.properties.hibernate.hbm2ddl.schema-generation.script.append=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# SQL 쿼리를 콘솔에 표시
 | 
					# Hibernate log
 | 
				
			||||||
spring.jpa.show-sql=true
 | 
					spring.jpa.show-sql=false
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Hibernate가 SQL을 포맷하여 보여줌
 | 
					 | 
				
			||||||
spring.jpa.properties.hibernate.format_sql=true
 | 
					spring.jpa.properties.hibernate.format_sql=true
 | 
				
			||||||
 | 
					spring.jpa.properties.hibernate.highlight_sql=true
 | 
				
			||||||
 | 
					spring.jpa.properties.hibernate.use_sql_comments=false
 | 
				
			||||||
 | 
					logging.level.org.hibernate.SQL=DEBUG
 | 
				
			||||||
 | 
					logging.level.org.hibernate.orm.jdbc.bind=TRACE
 | 
				
			||||||
 | 
					logging.level.org.springframework.data.jpa=DEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# P6Spy
 | 
				
			||||||
 | 
					decorator.datasource.p6spy.enable-logging=true
 | 
				
			||||||
 | 
					decorator.datasource.p6spy.log-format=%(sqlSingleLine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# CONSOLE
 | 
				
			||||||
 | 
					spring.output.ansi.enabled=always
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# HikariCP 연결 풀 크기 설정 (선택사항)
 | 
					# HikariCP 연결 풀 크기 설정 (선택사항)
 | 
				
			||||||
# spring.datasource.hikari.maximum-pool-size=10
 | 
					# spring.datasource.hikari.maximum-pool-size=10
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user