[진행중]
This commit is contained in:
		
							
								
								
									
										25
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								build.gradle
									
									
									
									
									
								
							@@ -1,3 +1,9 @@
 | 
			
		||||
buildscript {
 | 
			
		||||
	ext {
 | 
			
		||||
		queryDslVersion = "5.0.0"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
	id 'java'
 | 
			
		||||
	id 'org.springframework.boot' version '3.5.4'
 | 
			
		||||
@@ -23,12 +29,6 @@ repositories {
 | 
			
		||||
	mavenCentral()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
	ext {
 | 
			
		||||
		queryDslVersion = "5.0.0"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
	// 개발용 의존성 추가
 | 
			
		||||
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
 | 
			
		||||
@@ -36,6 +36,19 @@ dependencies {
 | 
			
		||||
	// PostgreSQL JDBC 드라이버
 | 
			
		||||
    runtimeOnly 'org.postgresql:postgresql'
 | 
			
		||||
	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.1.1'
 | 
			
		||||
	
 | 
			
		||||
	// MyBatis 추가
 | 
			
		||||
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
 | 
			
		||||
	
 | 
			
		||||
	compileOnly 'org.projectlombok:lombok'
 | 
			
		||||
	annotationProcessor 'org.projectlombok:lombok'
 | 
			
		||||
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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.autoconfigure.SpringBootApplication;
 | 
			
		||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
 | 
			
		||||
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
@EnableJpaAuditing
 | 
			
		||||
public class BioBackendApplication {
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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>{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,125 @@
 | 
			
		||||
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;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @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,4 +1,4 @@
 | 
			
		||||
package com.qsl.qsl_tutorial.base;
 | 
			
		||||
package com.bio.bio_backend.global.aop;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.aspectj.lang.ProceedingJoinPoint;
 | 
			
		||||
@@ -6,24 +6,51 @@ import org.aspectj.lang.annotation.Around;
 | 
			
		||||
import org.aspectj.lang.annotation.Aspect;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
@Aspect
 | 
			
		||||
@Component
 | 
			
		||||
@Slf4j
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
package com.qsl.qsl_tutorial.base;
 | 
			
		||||
package com.bio.bio_backend.global.config;
 | 
			
		||||
 | 
			
		||||
import com.querydsl.jpa.impl.JPAQueryFactory;
 | 
			
		||||
import jakarta.persistence.EntityManager;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
public class AppConfig {
 | 
			
		||||
    
 | 
			
		||||
    @Bean
 | 
			
		||||
  public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
 | 
			
		||||
    return new JPAQueryFactory(entityManager);
 | 
			
		||||
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
 | 
			
		||||
        return new BCryptPasswordEncoder();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user