Javascript로 리팩토링 : 회원가입

Feb 20, 2024
Javascript로 리팩토링 : 회원가입

1. 멀티 스레드 VS 단일 스레드

1) 멀티 스레드
- request마다 스레드를 만드는 기법
- 컨텍스트 스위칭이 발생 → 손님이 기다리는 시간은 적으나 전체적인 시간은 느림
- 그림을 동시에 그리거나 할 때 유용함
- IO가 있는 업무 : 스레드들 끼리 웨이트가 걸림
2) 단일 스레드
- 일단 request를 다 받고 이벤트 루프에 다 등록한 이후 틈이 생기면 이벤트 실행, 돌아가고 함
- 컨텍스트 스위칭이 없음
- IO가 있는 업무 : request를 다 받고 동시에 요청함 → 제일 빠름
⇒ 톰캣을 멀티 스레드로 배웠으나 웹에서는 단일 스레드가 최고임
톰캣도 단일과 멀티 스레드 둘 다 제공함
 

2. Javascript 사용의 장점

  • 로그인이 취소됐을 때 redirection이 되면 내용이 다 사라짐
→ 자바스크립트를 쓰면 히스토리 백이 되서 내용이 남아있어 ux가 좋아짐
  • 권한이 없으면 alert창 띄워서 권한이 없습니다 하고 히스토리 백해서 redirection없이 자동 이동
 

3. User에서 username에 unique 제약 설정하기

package shop.mtcoding.blog.user; import jakarta.persistence.*; import lombok.Data; import java.time.LocalDateTime; @Data //GETTER, SETTER, toString 포함된 어노테이션 @Entity // DB의 테이블과 매핑되는 클래스 임을 알려줌 @Table(name = "user_tb") //테이블 이름 : user_tb public class User { // use_tb의 내용 DB에 담기 @Id // PK @GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment private Integer id; @Column(unique=true) // 유니크 설정 private String username; @Column(length = 60, nullable = false) // 길이 조정, 널 불가 private String password; private String email; // 자바 : 카멜 표기법 -> DB : _ (언더스코어 기법) private LocalDateTime createdAt; // created_at }
 

4. UserController 에서 /join주소 수정하기

  • 오류 메세지를 직접 리턴하게 수정하기
  • @Controller // 파일을 리턴함 -> @ResponseBody로 메세지 자체를 리턴
  • 뷰 리졸버가 동작하지 않음 → 메세지 그대로 리턴
package shop.mtcoding.blog.user; import jakarta.servlet.http.HttpSession; import lombok.AllArgsConstructor; import org.springframework.stereotype.Controller; 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.ResponseBody; @AllArgsConstructor @Controller // 파일을 리턴함 -> @ResponseBody로 메세지 자체를 리턴 public class UserController { // fianl 변수는 반드시 초기화 되어야 함 private final UserRepository userRepository; // null private final HttpSession session; // @AllArgsConstructor를 사용하면서 필요 없어짐 // public UserController(UserRepository userRepository, HttpSession session) { // this.userRepository = userRepository; // this.session = session; // } // 원래는 get요청이나 예외 post요청하면 됨 // 민감한 정보는 쿼리 스트링에 담아보낼 수 없음 //원래는 get요청이나 예외 post요청하면 됨 //민감한 정보는 쿼리 스트링에 담아보낼 수 없음 @PostMapping("/login") public String login(UserRequest.LoginDTO requestDTO) { // 1. 유효성 검사 if(requestDTO.getUsername().length() < 3) { return "error/400"; } // 2. 모델 필요 select * from user_tb where username=? and password=? User user = userRepository.findByUsernameAndPassword(requestDTO); // DB에 조회할때 필요하니까 데이터를 받음 if (user == null) { return "error/401"; }else { session.setAttribute("sessionUser", user); return "redirect:/"; } } @PostMapping("/join") public @ResponseBody String join(UserRequest.JoinDTO requestDTO) { System.out.println(requestDTO); try{ userRepository.save(requestDTO); } catch (Exception e) { return "error/400"; } return "redirect:/loginForm"; //리다이렉션불러놓은게 있어서 다시부른거 } @GetMapping("/joinForm") // view만 원함 public String joinForm() { return "user/joinForm"; } @GetMapping("/loginForm") // view만 원함 public String loginForm() { return "user/loginForm"; } @GetMapping("/user/updateForm") public String updateForm() { return "user/updateForm"; } @GetMapping("/logout") public String logout() { // 1번 서랍에 있는 uset를 삭제해야 로그아웃이 됨 session.invalidate(); // 서랍의 내용 삭제 return "redirect:/"; } }
notion image
notion image
 
 

5. _core.util 패키지 만들어서 Script 클래스 만들기

package shop.mtcoding.blog._core.util; public class Script { public static String back(String msg) { StringBuilder sb = new StringBuilder(); sb.append("<script>"); sb.append("alert('"+msg+"');"); sb.append("history.back();"); sb.append("</script>"); return sb.toString(); } public static String href(String path) { StringBuilder sb = new StringBuilder(); sb.append("<script>"); sb.append("location.href='"+path+"';"); sb.append("</script>"); return sb.toString(); } public static String href(String path, String msg) { StringBuilder sb = new StringBuilder(); sb.append("<script>"); sb.append("alert('"+msg+"');"); sb.append("location.href='"+path+"';"); sb.append("</script>"); return sb.toString(); } }
 

6. Junit으로 테스트 해보기

  • 똑같은 패키지를 만들고 class 이름에 @Test만 붙이기
  • _기법 사용
  • 스프링이 STRING을 리턴하면 메세지를 그대로 리턴
  • 브라우저가 랜더링 해줄 때 스크립트가 발동됨 → 자동 TEXT HTML파일로 해줌
package shop.mtcoding.blog._core.util; import org.junit.jupiter.api.Test; public class ScriptTest { @Test public void back_test(){ String result = Script.back("권한이 없어요"); // string으로 받음 System.out.println(result); } }
 

7. UserController에서 /join 수정하기

  • Script.href 사용하기
메세지를 자바스크립트로 주면 302를 줄 필요 없음
package shop.mtcoding.blog.user; import jakarta.servlet.http.HttpSession; import lombok.AllArgsConstructor; import org.springframework.stereotype.Controller; 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.ResponseBody; import shop.mtcoding.blog._core.util.Script; @AllArgsConstructor @Controller // 파일을 리턴함 -> @ResponseBody로 메세지 자체를 리턴 public class UserController { // fianl 변수는 반드시 초기화 되어야 함 private final UserRepository userRepository; // null private final HttpSession session; // @AllArgsConstructor를 사용하면서 필요 없어짐 // public UserController(UserRepository userRepository, HttpSession session) { // this.userRepository = userRepository; // this.session = session; // } // 원래는 get요청이나 예외 post요청하면 됨 // 민감한 정보는 쿼리 스트링에 담아보낼 수 없음 //원래는 get요청이나 예외 post요청하면 됨 //민감한 정보는 쿼리 스트링에 담아보낼 수 없음 @PostMapping("/login") public String login(UserRequest.LoginDTO requestDTO) { // 1. 유효성 검사 if(requestDTO.getUsername().length() < 3) { return "error/400"; } // 2. 모델 필요 select * from user_tb where username=? and password=? User user = userRepository.findByUsernameAndPassword(requestDTO); // DB에 조회할때 필요하니까 데이터를 받음 if (user == null) { return "error/401"; }else { session.setAttribute("sessionUser", user); return "redirect:/"; } } @PostMapping("/join") public @ResponseBody String join(UserRequest.JoinDTO requestDTO) { System.out.println(requestDTO); try{ userRepository.save(requestDTO); } catch (Exception e) { return Script.back("아이디가 중복되었어요"); } return Script.href("/loginForm"); // 메세지를 자바스크립트로 주면 302를 줄 필요 없음 } @GetMapping("/joinForm") // view만 원함 public String joinForm() { return "user/joinForm"; } @GetMapping("/loginForm") // view만 원함 public String loginForm() { return "user/loginForm"; } @GetMapping("/user/updateForm") public String updateForm() { return "user/updateForm"; } @GetMapping("/logout") public String logout() { // 1번 서랍에 있는 uset를 삭제해야 로그아웃이 됨 session.invalidate(); // 서랍의 내용 삭제 return "redirect:/"; } }
notion image
notion image
 
Share article

vosw1