[파일 업로드 개선] 파일 업로드 처리 메서드에 groupOid 매개변수 추가 및 관련 로직 수정. MemberRepository와 MemberService에서 불필요한 메서드 제거 및 활성화된 회원 조회 로직 개선.

This commit is contained in:
2025-08-26 10:39:46 +09:00
parent b5d6d213f3
commit 690724c77c
7 changed files with 16 additions and 280 deletions

View File

@@ -25,6 +25,8 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
@@ -52,7 +54,7 @@ public class FileServiceImpl implements FileService {
} }
// 파일 업로드 처리 // 파일 업로드 처리
File savedFile = processFileUpload(multipartFile, requestDto.getDescription()); File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), generateOid());
// 응답 DTO 생성 및 반환 // 응답 DTO 생성 및 반환
return createUploadResponse(savedFile); return createUploadResponse(savedFile);
@@ -74,7 +76,8 @@ public class FileServiceImpl implements FileService {
List<String> errorMessages = new ArrayList<>(); List<String> errorMessages = new ArrayList<>();
int successCount = 0; int successCount = 0;
int failureCount = 0; int failureCount = 0;
Long groupOid = generateOid();
for (MultipartFile multipartFile : files) { for (MultipartFile multipartFile : files) {
try { try {
// 개별 파일 유효성 검사 // 개별 파일 유효성 검사
@@ -86,7 +89,7 @@ public class FileServiceImpl implements FileService {
} }
// 단일 파일 업로드 처리 // 단일 파일 업로드 처리
File savedFile = processFileUpload(multipartFile, requestDto.getDescription()); File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), groupOid);
FileUploadResponseDto uploadedFile = createUploadResponse(savedFile); FileUploadResponseDto uploadedFile = createUploadResponse(savedFile);
uploadedFiles.add(uploadedFile); uploadedFiles.add(uploadedFile);
@@ -115,7 +118,7 @@ public class FileServiceImpl implements FileService {
/** /**
* 파일 업로드 처리 * 파일 업로드 처리
*/ */
private File processFileUpload(MultipartFile multipartFile, String description) { private File processFileUpload(MultipartFile multipartFile, String description, Long groupOid) {
String originalFileName = FileUtils.cleanFileName(multipartFile.getOriginalFilename()); String originalFileName = FileUtils.cleanFileName(multipartFile.getOriginalFilename());
try { try {
@@ -131,7 +134,7 @@ public class FileServiceImpl implements FileService {
Path targetLocation = FileUtils.saveFileToDisk(multipartFile, uploadDir, storedFileName); Path targetLocation = FileUtils.saveFileToDisk(multipartFile, uploadDir, storedFileName);
// DB에 파일 정보 저장 // DB에 파일 정보 저장
File file = createFileEntity(originalFileName, storedFileName, targetLocation, multipartFile, description); File file = createFileEntity(originalFileName, storedFileName, targetLocation, multipartFile, description, groupOid);
file.setCreator(SecurityUtils.getCurrentUserOid(), SecurityUtils.getCurrentUserId()); file.setCreator(SecurityUtils.getCurrentUserOid(), SecurityUtils.getCurrentUserId());
return fileRepository.save(file); return fileRepository.save(file);
@@ -143,7 +146,7 @@ public class FileServiceImpl implements FileService {
} }
private File createFileEntity(String originalFileName, String storedFileName, Path targetLocation, private File createFileEntity(String originalFileName, String storedFileName, Path targetLocation,
MultipartFile multipartFile, String description) { MultipartFile multipartFile, String description, Long groupOid) {
return File.builder() return File.builder()
.originalFileName(originalFileName) .originalFileName(originalFileName)
.storedFileName(storedFileName) .storedFileName(storedFileName)
@@ -151,7 +154,7 @@ public class FileServiceImpl implements FileService {
.fileSize(multipartFile.getSize()) .fileSize(multipartFile.getSize())
.contentType(multipartFile.getContentType()) .contentType(multipartFile.getContentType())
.description(description) .description(description)
.groupOid(OidUtils.generateOid()) .groupOid(groupOid)
.build(); .build();
} }

View File

@@ -61,7 +61,6 @@ public class MemberController {
try { try {
String userId = SecurityUtils.getCurrentUserId(); String userId = SecurityUtils.getCurrentUserId();
memberService.deleteRefreshToken(userId); memberService.deleteRefreshToken(userId);
log.info("사용자 로그아웃 완료: {}", userId); log.info("사용자 로그아웃 완료: {}", userId);
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS)); return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS));
@@ -71,73 +70,4 @@ public class MemberController {
.body(ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR)); .body(ApiResponseDto.fail(ApiResponseCode.COMMON_INTERNAL_SERVER_ERROR));
} }
} }
// @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 ApiResponseDto<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 ApiResponseDto.success(ApiResponseCode.USER_INFO_CHANGE, null);
// }
// @DeleteMapping("/member")
// public ApiResponseDto<Void> deleteMember(@RequestBody @Valid CreateMemberRequestDTO requestMember){
// MemberDTO member = mapper.map(requestMember, MemberDTO.class);
// memberService.deleteMember(member);
// return ApiResponseDto.success(ApiResponseCode.USER_DELETE_SUCCESSFUL, null);
// }
// @PostMapping("/logout")
// public ApiResponseDto<Void> logout(@AuthenticationPrincipal MemberDTO member) {
// String id = member.getId();
// try {
// memberService.deleteRefreshToken(id);
// } catch (Exception e) {
// return ApiResponseDto.fail(ApiResponseCode.INTERNAL_SERVER_ERROR, null);
// }
// return ApiResponseDto.success(ApiResponseCode.LOGOUT_SUCCESSFUL, null);
// }
} }

View File

@@ -9,22 +9,7 @@ import java.util.List;
@Repository @Repository
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom { public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
// 사용자 ID로 회원 조회 (Optional 반환)
Optional<Member> findByUserId(String userId);
// 사용자 ID로 첫 번째 회원 조회 (userId가 unique하지 않을 경우 대비)
Optional<Member> findFirstByUserId(String userId);
// 사용자 ID로 활성화된 회원 조회
Optional<Member> findByUserIdAndUseFlagTrue(String userId);
// 사용자 ID로 활성화된 회원 첫 번째 조회
Optional<Member> findFirstByUserIdAndUseFlagTrue(String userId);
// 사용자 ID 존재 여부 확인 (활성화된 회원만)
boolean existsByUserIdAndUseFlagTrue(String userId);
// 사용자 ID 존재 여부 확인 // 사용자 ID 존재 여부 확인
boolean existsByUserId(String userId); boolean existsByUserId(String userId);

View File

@@ -20,48 +20,4 @@ public interface MemberRepositoryCustom {
* @return Optional<Member> 회원 정보 (없으면 empty) * @return Optional<Member> 회원 정보 (없으면 empty)
*/ */
Optional<Member> findActiveMemberByUserId(String userId); Optional<Member> findActiveMemberByUserId(String userId);
/**
* 역할(Role)별로 회원 목록을 조회합니다.
*
* @param role 회원 역할
* @return List<Member> 해당 역할을 가진 회원 목록
*/
List<Member> findByRole(String role);
/**
* 사용 여부별로 회원 목록을 조회합니다.
*
* @param useFlag 사용 여부
* @return List<Member> 해당 사용 여부를 가진 회원 목록
*/
List<Member> findByUseFlag(Boolean useFlag);
/**
* 사용자 ID와 사용 여부로 회원을 조회합니다.
*
* @param userId 사용자 ID
* @param useFlag 사용 여부
* @return Optional<Member> 회원 정보
*/
Optional<Member> findByUserIdAndUseFlag(String userId, Boolean useFlag);
/**
* 검색 조건에 따른 회원 목록을 페이징하여 조회합니다.
*
* @param userId 사용자 ID (부분 검색)
* @param role 회원 역할
* @param useFlag 사용 여부
* @param pageable 페이징 정보
* @return Page<Member> 페이징된 회원 목록
*/
Page<Member> findMembersByCondition(String userId, String role, Boolean useFlag, Pageable pageable);
/**
* 마지막 로그인 시간이 특정 시간 이후인 회원들을 조회합니다.
*
* @param lastLoginAfter 마지막 로그인 기준 시간
* @return List<Member> 해당 조건을 만족하는 회원 목록
*/
List<Member> findActiveMembersByLastLogin(java.time.LocalDateTime lastLoginAfter);
} }

View File

@@ -2,17 +2,10 @@ package com.bio.bio_backend.domain.base.member.repository;
import com.bio.bio_backend.domain.base.member.entity.Member; import com.bio.bio_backend.domain.base.member.entity.Member;
import com.bio.bio_backend.domain.base.member.entity.QMember; import com.bio.bio_backend.domain.base.member.entity.QMember;
import com.bio.bio_backend.domain.base.member.enums.MemberRole;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor; 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 org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
@@ -42,89 +35,4 @@ public class MemberRepositoryImpl implements MemberRepositoryCustom {
return Optional.ofNullable(foundMember); return Optional.ofNullable(foundMember);
} }
@Override
public List<Member> findByRole(String role) {
// 역할별로 회원을 조회합니다.
// String을 MemberRole enum으로 변환하여 비교합니다.
return queryFactory
.selectFrom(member)
.where(member.role.eq(MemberRole.fromValue(role)))
.fetch();
}
@Override
public List<Member> findByUseFlag(Boolean useFlag) {
// 사용 여부별로 회원을 조회합니다.
return queryFactory
.selectFrom(member)
.where(member.useFlag.eq(useFlag))
.fetch();
}
@Override
public Optional<Member> findByUserIdAndUseFlag(String userId, Boolean useFlag) {
// 사용자 ID와 사용 여부를 모두 만족하는 회원을 조회합니다.
// and() 메서드를 사용하여 여러 조건을 결합합니다.
Member foundMember = queryFactory
.selectFrom(member)
.where(member.userId.eq(userId)
.and(member.useFlag.eq(useFlag)))
.fetchOne();
return Optional.ofNullable(foundMember);
}
@Override
public Page<Member> findMembersByCondition(String userId, String role, Boolean useFlag, 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(MemberRole.fromValue(role)));
}
// 사용 여부가 제공된 경우 정확한 일치 조건을 추가합니다.
if (useFlag != null) {
builder.and(member.useFlag.eq(useFlag));
}
// 전체 개수를 조회합니다.
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.useFlag.eq(true) // 사용 중인 상태
.and(member.lastLoginAt.isNotNull()) // 마지막 로그인 시간이 존재
.and(member.lastLoginAt.after(lastLoginAfter))) // 특정 시간 이후
.orderBy(member.lastLoginAt.desc()) // 마지막 로그인 시간 기준 내림차순 정렬
.fetch();
}
} }

View File

@@ -20,15 +20,5 @@ public interface MemberService extends UserDetailsService {
List<MemberDto> selectMemberList(Map<String, String> params); List<MemberDto> selectMemberList(Map<String, String> params);
MemberDto selectMember(long seq);
int updateMember(MemberDto member); int updateMember(MemberDto member);
int deleteMember(MemberDto member);
/**
* 현재 로그인한 사용자의 정보를 조회합니다.
* @return 현재 사용자의 MemberDto
*/
MemberDto getCurrentMember();
} }

View File

@@ -8,7 +8,6 @@ import com.bio.bio_backend.domain.base.member.repository.MemberRepository;
import com.bio.bio_backend.global.exception.ApiException; import com.bio.bio_backend.global.exception.ApiException;
import com.bio.bio_backend.global.constants.ApiResponseCode; import com.bio.bio_backend.global.constants.ApiResponseCode;
import com.bio.bio_backend.global.constants.AppConstants; import com.bio.bio_backend.global.constants.AppConstants;
import com.bio.bio_backend.global.utils.SecurityUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@@ -36,11 +35,7 @@ public class MemberServiceImpl implements MemberService {
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException { public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
Member member = memberRepository.findActiveMemberByUserId(id) Member member = memberRepository.findActiveMemberByUserId(id)
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + id)); .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + id));
return memberMapper.toMemberDto(member);
// MapStruct를 사용하여 Member 엔티티를 MemberDto로 변환
MemberDto memberDto = memberMapper.toMemberDto(member);
return memberDto;
} }
@Override @Override
@@ -71,7 +66,7 @@ public class MemberServiceImpl implements MemberService {
@Override @Override
@Transactional @Transactional
public int updateMember(MemberDto memberDto) { public int updateMember(MemberDto memberDto) {
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(memberDto.getUserId()) Member member = memberRepository.findActiveMemberByUserId(memberDto.getUserId())
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND)); .orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
memberMapper.updateMemberFromDto(memberDto, member); memberMapper.updateMemberFromDto(memberDto, member);
@@ -81,7 +76,7 @@ public class MemberServiceImpl implements MemberService {
@Override @Override
public String getRefreshToken(String id) { public String getRefreshToken(String id) {
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(id) Member member = memberRepository.findActiveMemberByUserId(id)
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND)); .orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
return member.getRefreshToken(); return member.getRefreshToken();
@@ -90,12 +85,12 @@ public class MemberServiceImpl implements MemberService {
@Override @Override
@Transactional @Transactional
public int deleteRefreshToken(String id) { public int deleteRefreshToken(String id) {
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(id) Member member = memberRepository.findActiveMemberByUserId(id)
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND)); .orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
member.setRefreshToken(null); member.setRefreshToken(null);
memberRepository.save(member); memberRepository.save(member);
return 1; // 성공 시 1 반환 return 1;
} }
@Override @Override
@@ -104,35 +99,4 @@ public class MemberServiceImpl implements MemberService {
return memberMapper.toMemberDtoList(members); return memberMapper.toMemberDtoList(members);
} }
@Override
public MemberDto selectMember(long seq) {
// JPA 레파지토리를 사용하여 회원 조회
Member member = memberRepository.findById(seq)
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. seq: " + seq));
// MapStruct를 사용하여 Member 엔티티를 MemberDto로 자동 변환
return memberMapper.toMemberDto(member);
}
@Override
public MemberDto getCurrentMember() {
return SecurityUtils.getCurrentMember();
}
@Override
@Transactional
public int deleteMember(MemberDto memberDto) {
Member member = memberRepository.findFirstByUserId(memberDto.getUserId())
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
member.setUseFlag(false);
log.info("회원 삭제 처리: {}", member.toString());
memberRepository.save(member);
return 1; // 성공 시 1 반환
}
} }