blog 예제 로그인(statefull)
[Spring] blog 예제 회원가입, 로그인 까지
Jan 30, 2024
기본 세팅
코드 가져와서 “화면 초기 세팅 완료” 로 reset해서 시작하기
application
application-prod.yml 수정

application-dev.yml 수정

application.yml


-prod이면 application-prod.yml으로 실행됨 개발 환경에서는 -dev로 할것
패키지 구성 변경

전

후
회원가입 코드 작성
요청은 url, uri로 받는다
데이터는 DTO로 받는다.
UserController - join 추가
@PostMapping("/join") public String join() { return "redirect:/loginForm"; }

UserRequest 생성, DTO작성


UserController - join 에 파라미터를 JoinDTO로 넣어줌
H2 DataBase 사용
application-dev.yml 에 h2 DB사용을 위한 코드 작성
spring: datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:test;MODE=MySQL username: sa password: h2: console: enabled: true

http://localhost:8080/h2-console 접속하여 데이터베이스 연결
DB 화면캡처


console url 설정 → url로 접속가능하게 하는 코드

User 클래스 생성, Table 생성 → Java에서 코드로 테이블 생성이 가능

코드
@Data @Entity @Table(name = "user_tb") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String username; private String password; private String email; }

DB화면 캡처

@Entity는 application-dev.yml에

Spring 서버가 실행될때 Entity를 찾아 분석하여 create함 - 개발모드에서만 사용할 것
제약조건 설정
User
@Data @Entity @Table(name = "user_tb") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Column(unique = true) private String username; @Column(length = 60, nullable = false) private String password; private String email; @CreationTimestamp private LocalDateTime createAt; }

application-dev.yml → 코드 추가(Run에서 쿼리 편하게 볼 수있음)



UserRepository 생성(DAO로 생각)

UserRepository
@Repository public class UserRepository { private EntityManager em; // 의존성 주입 // 생성자 public UserRepository(EntityManager em) { this.em = em; } public void save(UserRequest.JoinDTO requestDTO){ System.out.println("UserRequest에 save메서드 호출됨"); } }
의존성 주입
계속 필요할때 마다 new를 하게되면 메모리가 감당하지 못하기 때문에 DI(Dependency Injection)

UserController 코드 전체
package shop.mtcoding.blog.user; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @Controller public class UserController { private UserRepository userRepository; public UserController(UserRepository userRepository) { this.userRepository = userRepository; } @PostMapping("/join") public String join(UserRequest.JoinDTO requestDTO) { System.out.println(requestDTO); // 1. 유효성 검사 if(requestDTO.getUsername().length()<3){ return "error/400"; } // 2. Model에 위임하기 userRepository.save(requestDTO); // 3. 응답 return "redirect:/loginForm"; } @GetMapping("/joinForm") public String joinForm() { return "user/joinForm"; } @GetMapping("/loginForm") public String loginForm() { return "user/loginForm"; } @GetMapping("/user/updateForm") public String updateForm() { return "user/updateForm"; } @GetMapping("/logout") public String logout() { return "redirect:/"; } }
error패키지 만들어서 400이름으로 에러 페이지 하나 만들기
400
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>에러 : 잘못된 요청을 했습니다. 400</h1> </body> </html>

쿼리 작성 UserRepository
save
@Transactional public void save(UserRequest.JoinDTO requestDTO){ Query query = em.createNativeQuery("insert into user_tb(username,password,email) values(?,?,?)"); query.setParameter(1,requestDTO.getUsername()); query.setParameter(2,requestDTO.getPassword()); query.setParameter(3,requestDTO.getEmail()); query.executeUpdate(); }

위에 어노테이션 붙이면됨
@Transactional을 안붙이면 쿼리를 전송하지 않는다(insert, delete, update 같은 경우는 데이터베이스를 바꾸는 위험한 쿼리로 인식하기 때문에)

다른 기술(알아서 쿼리를 작성해준다)
saveV2
@Transactional public void saveV2(UserRequest.JoinDTO requestDTO){ User user = new User(); user.setUsername(requestDTO.getUsername()); user.setPassword(requestDTO.getPassword()); user.setEmail(requestDTO.getEmail()); em.persist(user); }

현재까지의 코드 실행


회원가입 후 DB에 insert된 것을 확인

로그인 코드
UserController-login코드 작성
@PostMapping("/login") public String login(UserRequest.LoginDTO requestDTO){ // 1. 유효성 검사 if(requestDTO.getUsername().length()<3){ return "error/400"; } // 2. Model 필요 userRepository.findByUsernameAndPassword(requestDTO); // 3. 응답 return "redirect:/"; }

findByUsernameAndPassword에 Alt+Enter하면 바로 생성됨
UserRepository
findByUsernameAndPassword
public User findByUsernameAndPassword(UserRequest.LoginDTO requestDTO) { Query query = em.createNativeQuery("select * from user_tb where username=? AND password=?", User.class); query.setParameter(1,requestDTO.getUsername()); query.setParameter(1,requestDTO.getPassword()); User user = (User) query.getSingleResult(); return user; }

실행
회원가입

로그인

로그인 완료

로그인의 목적 → Statefull 만들기
session 영역에 한번이라도 접근하면 session이 만들어짐
@RequiredArgsConstructor → final들만 생성자를만들어줌



session과 Request에 접근할 수 있음
코드
mustache: servlet: expose-session-attributes: true expose-request-attributes: true

응답 유저가 null이 아니면, session 만들고, index 페이지로 이동
코드
User user = userRepository.findByUsernameAndPassword(requestDTO); if(user == null){ return "error/401"; }else{ session.setAttribute("sessionUser",user); return "redirect:/"; }

401
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1>인증에 실패하였습니다. 401</h1> </body> </html>
로그인 전에는 회원가입과 로그인만 navbar에 보이도록
로그인이 완료되면 navbar의 회원가입과 로그인을 안보이게
layout/header.mustache


실행
회원가입 후 로그인

navbar 구성 달라짐

검토사항
테이블생성시 password의 nullable = false 가 안먹힘 null값이 아니라 공백이 입력되는것으로 확인된다.
유효성 검사에서 password의 길이를 어느정도 이상으로 하면 상관없을 것이다.
Share article