project/모임웹프로젝트

모임 웹 프로젝트 회원가입 백엔드 구성 (6)

naspeciallist 2024. 9. 29. 01:36

이제 회원가입에 관한 서버 로직을 구성해 보겠습니다.

 

먼저 저희 어플리케이션에 시스템 아키텍쳐부터 알려드리겠습니다.

service에서 로직을 처리한 뒤 repository에 요청데이터를 보내서 jpa를 통해 데이터베이스와 메핑을하여 crud가 일어나는 구조입니다. 따라서 위에 아키텍처에 따라 서버 로직을 구성해 보겠습니다.

 

먼저 controller부터 구성하겠습니다.

 

@RequiredArgsConstructor
@Controller
public class UserApiController {

    private final UserService userService;

    @PostMapping("/user")
    public String signup(AddUserRequest request, @RequestParam("profileImages") List<MultipartFile> profileImagesFiles) {
        userService.save(request, profileImagesFiles); // 프로필 이미지 파일도 함께 전달
        return "redirect:/login";
    }
    }

 

회원가입을 위한 컨트롤러 입니다. 폼이 제출이 되면 post방식으로 요청을 받아 요청을 service로 전달 해 준 뒤 login페이지로 리다이렉트 해줍니다.

그 다음에 service로직을 구성하겠습니다.

package org.zerock.wantuproject.service;

import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.zerock.wantuproject.dto.AddUserRequest;
import org.zerock.wantuproject.entity.Interest;
import org.zerock.wantuproject.entity.ProfileImage;
import org.zerock.wantuproject.entity.User;
import org.zerock.wantuproject.repository.UserRepository;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserService {

    private final UserRepository userRepository;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;
    private final FileService fileService; // 파일 저장을 위한 FileService

    public Long save(AddUserRequest dto, List<MultipartFile> profileImagesFiles) {
        // User 객체 생성
        User user = User.builder()
                .email(dto.getEmail())
                .password(bCryptPasswordEncoder.encode(dto.getPassword()))
                .name(dto.getName())
                .uid(dto.getUid())
                .birthDate(dto.getBirthDate())
                .nickname(dto.getNickname())
                .gender(dto.getGender())
                .address(dto.getAddress())
                .build();

        // 프로필 이미지 추가 (여러 개 처리)
        if (profileImagesFiles != null && !profileImagesFiles.isEmpty()) {
            List<ProfileImage> profileImages = profileImagesFiles.stream()
                    .map(file -> {
                        try {
                            // 파일 저장 후 저장된 파일 이름 반환
                            String storedFileName = fileService.saveFile(file);
                            // ProfileImage 엔티티 생성
                            return ProfileImage.builder()
                                    .imageUrl(storedFileName)  // 저장된 파일 이름 저장
                                    .user(user)
                                    .build();
                        } catch (IOException e) {
                            e.printStackTrace();
                            return null;
                        }
                    })
                    .filter(image -> image != null)  // null인 경우 필터링
                    .collect(Collectors.toList());

            user.setProfileImages(profileImages);  // 사용자 객체에 프로필 이미지 추가
        }

        // 관심사 추가
        List<Interest> interests = dto.getInterests().stream()
                .map(interestName -> Interest.builder()
                        .interestName(interestName)
                        .user(user)
                        .build())
                .collect(Collectors.toList());
        user.setInterests(interests);  // 사용자 객체에 관심사 추가

        // User 저장 및 ID 반환
        return userRepository.save(user).getId();
    }
}


서비스 로직입니다 dto와 builder패턴을 이용하여 데이터를 저장 할 수 있게 로직을 구성해 줍니다.

이렇게 구성을 하니까
2024-09-29T00:42:12.448+09:00  WARN 11404 --- [nio-9990-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required part 'profileImages' is not present.]

이런 오류가 떴습니다.

Spring에서는 @RequestParam 또는 @ModelAttribute를 통해 폼 데이터를 받는데, 파일 업로드 시에는 반드시 multipart/form-data 형식으로 데이터를 전송해야 합니다. 이 오류는 서버가 profileImages라는 파일 데이터를 기대했지만, 실제로 클라이언트가 그 데이터를 전송하지 않았기 때문에 발생한 것입니다.

html파일에서 파일을 배열 형식으로 처리하기 위해서 

<input type="file" id="photoInput1" name="profileImages[]" class="hidden-input" accept="image/*" multiple onchange="previewImage(event, 1)">


이런 형식으로 처리를 했기 때문에 @requstParam으로 받을 때도 배열 형식으로 받아야 합니다. controller를 수정하겠습니다.

@PostMapping("/user")
public String signup(AddUserRequest request, @RequestParam("profileImages[]") MultipartFile[] profileImagesFiles) {
    // 파일 저장 로직을 배열로 처리
    List<String> savedFileNames = fileController.handleMultipleFileUpload(profileImagesFiles).getBody();

    // 파일명 리스트를 넘겨서 UserService에서 처리
    userService.save(request, savedFileNames);
    return "redirect:/login";
}

 

controller에서도 배열 형식으로 받도록 처리를 하고

public Long save(AddUserRequest dto, List<String> savedFileNames)

service에서도 배열 형식으로 받을 수 있도록 변환 해 줍니다.

이렇게 하면 회원가입 기능을 구현 할 수 있습니다.