[사이드 프로젝트] 나만의 도서 관리 서비스6-1

zwon·2023년 9월 1일
0

개발일지

목록 보기
9/23

쿠키-세션을 이용하지않고 우선 단순히 회원가입과 로그인 기능을 구현할 것이다.
기본적은 동작이 다 가능해지면 그때 쿠키와 세션의 개념을 도입해서 코드를 리팩토링할 예정이다.

회원가입

  • 회원 생성, 조회, 수정, 삭제 기능 중 우선 회원 생성 및 조회기능만 구현하겠다.

    • 회원 생성 = 회원 가입
    • 회원 조회
      • findById()
      • findByLoginId() - Optional로 반환. User가 없을 수도 있기 때문임.
      • findAll() - 모든 회원 조회
    • 회원 수정 = 비밀번호 수정
    • 회원 삭제 = 회원 탈퇴

회원 객체

@Data
public class User {

private Long id; // db 식별자

@NotBlank(message = "아이디를 입력해주세요.")
private String loginId; // 로그인 아이디

@NotBlank(message = "이름을 입력해주세요.")
private String name; // 사용자 이름

@NotBlank(message = "비밀번호를 입력해주세요.")
private String password; // 비밀 번호
}

회원 Repository

이 부분도 나중에 저장 방식을 전환할 수 있기 때문에 Repository를 인터페이스로 구현하고 구현체로는 InMemory 방식으로 구현했다.

public interface UserRepository {

Long save(User user);

User findById(Long id);

List<User> findAll();

Optional<User> findByLoginId(String loginId);

// 회원 정보 수정
// 회원 탈퇴
}
@Repository
public class UserRepositoryImpl implements UserRepository {

private static Map<Long, User> store = new HashMap<>();
private static long sequence = 0L;

@Override
public Long save(User user) {
  user.setId(++sequence);
  store.put(user.getId(), user);
  return user.getId();
}

@Override
public User findById(Long id) {
  User user = store.get(id);
  return user;
}

@Override
public List<User> findAll() {
  return new ArrayList<>(store.values());
}

@Override
public Optional<User> findByLoginId(String loginId) {
  List<User> Users = findAll();
  for (User user : Users) {
    if (user.getLoginId().equals(loginId)){
      return Optional.of(user);
    }
  }
  return Optional.empty();
}
}
}
  • 로그인 아이디로 회원을 조회할 때 반환값으로 Optional을 사용했는데 Optional은 T타입의 객체를 감싸는 래퍼 클래스로, 연산 결과를 Optional객체로 감싸서 반환한다.
  • 그러면 반한 결과가 null이어도 조건문을 통해 확인할 필요 없이 option에 정의된 메서드로 쉽게 처리할 수 있rh NullPointerException이 발생하지 않는다는 장점이 있다.

UserService

@Service
@RequiredArgsConstructor
public class UserService {

private final UserRepository userRepository;

// 회원가입(생성)
public Long save(User user){
  Long saveUserId = userRepository.save(user);
  return saveUserId;
}
// 회원 조회
public User findById(Long id){
  User user = userRepository.findById(id);
  return user;
}
public List<User> findAll() {
  List<User> users = userRepository.findAll();
  return users;
}
public Optional<User> findByLoginId(String loginId){
  Optional<User> user = userRepository.findByLoginId(loginId);
  return user;
}
// 회원 정보 수정
// 회원 탈퇴(삭제)
}

UserController

@Controller
@RequiredArgsConstructor
@RequestMapping("/add")
public class UserController {

private final UserService UserService;

// 회원가입 폼 보여주기
@GetMapping("/user")
public String addUserForm(Model model){
  model.addAttribute("user", new User());
  return "login/addForm";
}
// 회원가입 하기
@PostMapping("/user")
public String addUser(@Validated @ModelAttribute User user, BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
    return "login/addForm";
  }
  UserService.save(user);
  return "login/home";
}
}

로그인 객체

@Data
public class Login {

@NotBlank(message = "아이디를 입력해주세요.")
private String loginId;

@NotBlank(message = "비밀번호를 입력해주세요.")
private String password;
}

LoginService

  • 이 코드에는 회원가입한 회원이 맞는지 아닌지를 확인하는 로직이 구현되어있다.
  @Service
@RequiredArgsConstructor
public class LoginService {

  private final UserService userService;
  public User login(String loginId, String password) {
    Optional<User> findUserByLoginID = userService.findByLoginId(loginId);
    User user = findUserByLoginID.get();
    if (user.getPassword().equals(password)) {
      // 로그인 성공
      return user;
    }
    // 로그인 실패
    return null;
  }
}
  - UserService에서 구현한 findbyLoginId를 통해 사용자가 입력한 로그인 아이디를 가지고 회원을 찾고, 찾은 회원의 비밀번호는 getPassword()를 통해 가져온다.

LoginController

@PostMapping("/login")
public String login(@Validated @ModelAttribute Login login, BindingResult bindingResult){
  if (bindingResult.hasErrors()){
    return "login/loginForm";
  }
  Optional<User> addUserCheck = userService.findByLoginId(login.getLoginId());
  if (addUserCheck.isEmpty()) {
    bindingResult.reject("addFail", "존재하지 않는 회원입니다. 회원가입을 해주세요.");
    return "login/loginForm";
  }

  User loginUser = loginService.login(login.getLoginId(), login.getPassword());

  if (loginUser == null) {
    // 로그인 인증 과정에서 오류가 발생했을 때,
    bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다. 다시 입력해주세요.");
    return "login/loginForm";
  }
  return "redirect:/library";
}
  • 먼저 로그인 아이디로 존재하는 회원인지 파악한다.
  • 그 다음 존재하는 회원이라면 로그인 인증 절차를 진행하는데 로그인 과정에서 실패가 되면 글로벌 오류를 띄워줌으로써 사용자가 인지할 수 있게 했다.
  • 로그인 인증 실패는 특정한 필드 오류가 아니어서 rejectValue()가 아닌 reject()를 사용했다.

화면

홈화면

회원가입 폼 및 검증

  • 이름 : spring
  • id : spring
  • pwd : asd

로그인 화면 및 검증

  • id는 spring, pwd : spring 입력시

    로그인 성공

    • 로그인을 성공하면 도서 관리 서비스 사용 가능

아직 쿠키-세션 기능은 도입하지 않았으며 회원 탈퇴, 회원 정보 수정, 아이디 중복 확인 등의 로직은 구현하지 않았다.
우선 기본적인 회원가입 및 로그인 기능은 구현했으니 점차 추가할 생각이다.
디자인도 좀 해야겠다.........

profile
Backend 관련 지식을 정리하는 Back과사전

0개의 댓글