[Spring] Spring 웹 사이트 만들기 4 - 회원가입 기능

2022. 11. 18. 12:17·📗 self-study/📗 KH정보교육원 당산지원

🔥 회원가입 기능 🔥 

 

💻 memberEnrollForm.jsp 생성

👉🏻 header, footer include 후 form 태그 action 속성에 insert.me url 제시

👉🏻 Controller에 커맨드 객체 방식으로 전달할 것이기 때문에 name 속성값도 맞춰 줌!

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    
    <!-- 메뉴바 -->
    <jsp:include page="../common/header.jsp" />

    <div class="content">
        <br><br>
        <div class="innerOuter">
            <h2>회원가입</h2>
            <br>

            <form action="insert.me" method="post">
                <div class="form-group">
                    <label for="userId">* ID : </label>
                    <input type="text" class="form-control" id="userId" placeholder="Please Enter ID" name="userId" required> <br>

                    <label for="userPwd">* Password : </label>
                    <input type="password" class="form-control" id="userPwd" placeholder="Please Enter Password" name="userPwd" required> <br>

                    <label for="checkPwd">* Password Check : </label>
                    <input type="password" class="form-control" id="checkPwd" placeholder="Please Enter Password" required> <br>

                    <label for="userName">* Name : </label>
                    <input type="text" class="form-control" id="userName" placeholder="Please Enter Name" name="userName" required> <br>

                    <label for="email"> &nbsp; Email : </label>
                    <input type="text" class="form-control" id="email" placeholder="Please Enter Email" name="email"> <br>

                    <label for="age"> &nbsp; Age : </label>
                    <input type="number" class="form-control" id="age" placeholder="Please Enter Age" name="age"> <br>

                    <label for="phone"> &nbsp; Phone : </label>
                    <input type="tel" class="form-control" id="phone" placeholder="Please Enter Phone (-없이)" name="phone"> <br>
                    
                    <label for="address"> &nbsp; Address : </label>
                    <input type="text" class="form-control" id="address" placeholder="Please Enter Address" name="address"> <br>
                    
                    <label for=""> &nbsp; Gender : </label> &nbsp;&nbsp;
                    <input type="radio" id="Male" value="M" name="gender" checked>
                    <label for="Male">남자</label> &nbsp;&nbsp;
                    <input type="radio" id="Female" value="F" name="gender">
                    <label for="Female">여자</label> &nbsp;&nbsp;
                </div> 
                <br>
                <div class="btns" align="center">
                    <button type="submit" class="btn btn-primary">회원가입</button>
                    <button type="reset" class="btn btn-danger">초기화</button>
                </div>
            </form>
        </div>
        <br><br>

    </div>

    <!-- 푸터바 -->
    <jsp:include page="../common/footer.jsp" />

</body>
</html>

 

 

 

🙋🏻‍♀️ phone의 tel 속성은 뭔가요?

이렇게 나오게 해 주는 거요

 

 

 

💻 header.jsp에서 화면을 띄워 줄 요청 url 제시

👉🏻 회원가입 a 태그에 url 제시

👉🏻 아이디, 비밀번호 required 속성 추가

// 회원가입 url 요청
<c:when test="${ empty loginUser }">
    <!-- 로그인 전 -->
    <a href="enrollForm.me">회원가입</a>
    <a data-toggle="modal" data-target="#loginModal">로그인</a>
    <!-- 모달의 원리 : 이 버튼 클릭시 data-targer에 제시되어있는 해당 아이디의 div요소를 띄워줌 -->
</c:when>


// 아이디, 비밀번호 required 속성 추가
<form action="login.me" method="post">
    <!-- Modal body -->
    <div class="modal-body">
        <label for="userId" class="mr-sm-2">ID : </label>
        <input type="text" class="form-control mb-2 mr-sm-2" placeholder="Enter ID" id="userId" name="userId" required> <br>
        <label for="userPwd" class="mr-sm-2">Password : </label>
        <input type="password" class="form-control mb-2 mr-sm-2" placeholder="Enter Password" id="userPwd" name="userPwd" required>
    </div>

    <!-- Modal footer -->
    <div class="modal-footer">
        <button type="submit" class="btn btn-primary">로그인</button>
        <button type="button" class="btn btn-danger" data-dismiss="modal">취소</button>
    </div>
</form>

 

💻 MemberController

👉🏻 insertMember 메소드의 경우 커맨드 객체 방식으로 전달받을 것

	@RequestMapping("enrollForm.me")
	public String enrollForm() {
		
		// 회원가입 페이지를 포워딩
		// 포워딩 하고자 하는 경로: /WEB-INF/views/member/memberEnrollForm.jsp
		// 접두어와 접미어를 제외한 경로: member/memberEnrollForm
		return "member/memberEnrollForm";
		
	}
    
    	@RequestMapping("insert.me")
	public void insertMember(Member m) {
		
		System.out.println(m);
		
	}
더보기

1. 필수 입력 사항(required)인 4가지만 입력했을 때 400 오류

 

2. 모든 사항 입력했을 때 404 오류

👉🏻 현재 응답 페이지를 제대로 지정하지 않았으므로 이 오류가 뜨는 것은 맞음!

 

방법 2의 경우 콘솔이 뜨긴 하지만 한글이 깨지고 있음

 

3. DB에 비밀번호가 그대로 노출됨

👉🏻 이거 완전 철컹철컹이에요...

 

 

 

현재의 문제점

1️⃣ 한글 깨짐 문제 발생 👉🏻 요청 시 전달값을 뽑기 전에 먼저 UTF-8 형식으로 인코딩 설정하기

👉🏻 이 시점에서 인코딩 설정을 하면 안 되나?

❌: 이미 읽어 온 후인데 이 시점에서 해 봐야 뭐 하나요 헛고생임!

 

⭕️ 해결책: 요청이 DispatcherServlet에 도달하기 전에 "인코딩 필터"를 거쳐가게끔 해 줄 것

                         스프링에서 제공하는 인코딩 필터를 web.xml에 등록(제일 먼저 읽히니까)

 

필터(Filter)

👉🏻 모든 요청 처리 전 공통적으로 필요로 하는 기능들을 클라이언트의 요청을 Servlet이 받기 전에 먼저 가로채서 해당 작성된 내용이 먼저 수행되도록 하는 개념

스프링에서 제공해 주는 인코딩 필터를 등록
👉🏻경로: spring-web-x.x.xx.jar 파일의 org.springframework.web.filter.CharacterEncodingFilter.class 파일
👉🏻 필터 등록 시 filter 태그와 filter-mapping 태그를 같이 기술

 

💻 web.xml

	 <!-- 필터를 이용하겠다 -->
	 <filter>
	 	<!-- 반드시 filter-name으로 filter명을 지정해야 함 -->
	 	<filter-name>encodingFilter</filter-name>
	 	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	 	<!-- 옵션 1. 인코딩 방식을 지정(UTF-8) -->
	 	<init-param>
	 		<param-name>encoding</param-name>
	 		<param-value>UTF-8</param-value>
	 	</init-param>
	 	<!-- 옵션 2. 혹시나 충돌 시 강제로 인코딩을 UTF-8로 할 수 있게끔 지정 -->
	 	<init-param>
	 		<param-name>forceEncoding</param-name>
	 		<param-value>true</param-value>
	 	</init-param>
	 </filter>
	 
	 <!-- 이 필터를 언제 적용하겠다 -->
	 <filter-mapping>
	 	<!-- 위에서 지정한 encodingFilter를 모든 요청에 적용하겠음 -->
	 	<filter-name>encodingFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

👉🏻 web.xml에서 인코딩 설정을 한 뒤 해당 Controller에 진입하였기 때문에 한글이 더 이상 깨지지 않음!

 

 

 

2️⃣ 필수 입력사항만 입력하고 넘겼을 경우 400 에러?

👉🏻 넘기는 데이터의 형식이 맞지 않을 때 일어나는 오류

콘솔에 뜨고 있는 오류 내용

 

WARN : org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'member' on field 'age': rejected value []; codes [typeMismatch.member.age,typeMismatch.age,typeMismatch.int,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [member.age,age]; arguments []; default message [age]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'int' for property 'age'; nested exception is java.lang.NumberFormatException: For input string: ""]]

👉🏻 콘솔의 내용을 잘 뜯어보니 모두 입력하지 않았을 때가 아니라 '나이'를 제대로 받아오지 못한 것으로 보임

 

즉, 문제 상황은 2️⃣ 필수 입력사항만 입력하고 넘겼을 경우 400 에러? 가 아닌

 

2️⃣  요청 시 나이를 입력하지 않았을 경우 

✔️ 400 에러(Bad Request Error) : 형식에 맞지 않는 데이터가 넘어온 경우 발생함

 

⭕️ 해결책: Member 클래스의 age 필드를 int형에서 String 형으로 변경

해결법 1-1) Member 클래스의 age 필드와 관련 setter, getter, toString을 모두 String으로 바꾸기

해결법 1-2) 롬복 사용하기

📖 코드를 줄여 주는 롬복 설치 후 실행하기

 

👉🏻 결국 age 필드를 int형에서 String 형으로 바꾼다는 것은 동일함! 협업이라면 팀원 중 1명이라도 롬복 사용 불가능하다면 그냥 수기로 바꿔 줄 것!!

 

💻 Member

package com.kh.spring.member.model.vo;

import java.sql.Date;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@NoArgsConstructor // 기본생성자를 만들어 주는 어노테이션
@AllArgsConstructor // 모든 필드를 매개변수로 갖는 생성자를 만들어 주는 어노테이션
@Setter // setter 메소드들
@Getter // getter 메소드들
@ToString // toString 메소드
public class Member {
	
	private String userId; 	 //	USER_ID	VARCHAR2(30 BYTE)
	private String userPwd;  //	USER_PWD	VARCHAR2(100 BYTE)
	private String userName; //	USER_NAME	VARCHAR2(15 BYTE)
	private String email; 	 //	EMAIL	VARCHAR2(100 BYTE)
	private String gender; 	 //	GENDER	VARCHAR2(1 BYTE)
	// private int age; 	 //	AGE	NUMBER
	private String age; 	 // 400 에러 해결방법
	private String phone; 	 //	PHONE	VARCHAR2(13 BYTE)
	private String address;  //	ADDRESS	VARCHAR2(100 BYTE)
	private Date enrollDate; //	ENROLL_DATE	DATE
	private Date modifyDate; //	MODIFY_DATE	DATE
	private String status;   //	STATUS	VARCHAR2(1 BYTE)
    
}

👉🏻 이제 나이를 입력하지 않아도 400 오류가 뜨지 않음!

 

 

 

3️⃣ DB에 비밀번호가 그대로 노출됨

⭕️ 해결책: 📖 비밀번호 암호화 - Bcrypt를 위한 스프링 스큐리티 모듈

 

	// 비밀번호 암호화를 위한 변수
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
    
        @RequestMapping("insert.me")
	public void insertMember(Member m) {

		System.out.println("평문: " + m.getUserPwd());
		
		// 암호화 작업 (암호문을 만들어 내는 과정)
		String encPwd = bcryptPasswordEncoder.encode(m.getUserPwd());
		System.out.println("암호문: " + encPwd);
		// => 같은 평문이어도 매번 다른 암호문 결과가 나옴
		// => 평문 + salt(랜덤값) => 암호화 작업이 이루어지기 때문
	}

👉🏻 권장하지는 않으나 테스트용이라면 나온 값을 직접 수정해 줘도 됨!

👉🏻 이후 커밋은 반드시 해 줄 것!

 

 

 

💻 문제점을 모두 수정한 MemberController

	// 비밀번호 암호화를 위한 변수
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
    
        @RequestMapping("insert.me")
	public void insertMember(Member m) {

		// System.out.println("평문: " + m.getUserPwd());
		
		// 암호화 작업 (암호문을 만들어 내는 과정)
		String encPwd = bcryptPasswordEncoder.encode(m.getUserPwd());
		// System.out.println("암호문: " + encPwd);
		// => 같은 평문이어도 매번 다른 암호문 결과가 나옴
		// => 평문 + salt(랜덤값) => 암호화 작업이 이루어지기 때문
		
        	m.setUserPwd(encPwd);
		
		int result = memberService.insertMember(m);
		
	}

 

💻 MemberServiceImpl

	@Override
	public int insertMember(Member m) {
		
		return memberDao.insertMember(sqlSession, m);
		
	}

 

💻 MemberDao

	public int insertMember(SqlSessionTemplate sqlSession, Member m) {
		
		return sqlSession.insert("memberMapper.insertMember", m);
		
	}

 

💻 member-mapper.xml

	<!-- 회원가입용 쿼리문 -->
	<insert id="insertMember" parameterType="member">
		INSERT INTO MEMBER(USER_ID
						 , USER_PWD
						 , USER_NAME
						 , EMAIL
						 , GENDER
						 , AGE
						 , PHONE
						 , ADDRESS)
					VALUES(#{userId}
						 , #{userPwd}
						 , #{userName}
						 , #{email}
						 , #{gender}
						 , #{age}
						 , #{phone}
						 , #{address})
	</insert>

 

💻 DB까지 다녀온 후의 Controller

👉🏻 매개변수로 Model 추가하기

👉🏻 반환형 String으로 수정하기

	@RequestMapping("insert.me")
	public String insertMember(Member m, Model model, HttpSession session) {
		
		// System.out.println(m);
		
		// System.out.println("평문: " + m.getUserPwd());
		
		// 암호화 작업 (암호문을 만들어 내는 과정)
		String encPwd = bcryptPasswordEncoder.encode(m.getUserPwd());
		
		// Member 객체의 userPwd 필드의 값을 암호문으로 바꿔치기 => setter 메소드
		m.setUserPwd(encPwd);
		
		int result = memberService.insertMember(m);
		
		if(result > 0) { // 성공, 메인페이지 url 재요청
			
			// 일회성 알람 문구
			session.setAttribute("alertMsg", "성공적으로 회원가입이 완료되었습니다.");
			return "redirect:/";
			
		} else { // 실패, 에러 문구를 담아서 에러 페이지 포워딩
			
			model.addAttribute("errorMsg", "회원가입 실패");
			
			// /WEB-INF/views/common/errorPage.jsp
			return "common/errorPage";
			
		}
		
	}

 

💻 header.jsp

👉🏻 alert창을 띄우기 위한 설정 추가

<body>

	<!-- 액션 태그의 특징: script 태그 영역 내부에서 사용할 수 없음 (인식 안 됨) -->
	<c:if test="${ not empty alertMsg }">
		<script>
			alert("${ alertMsg }");
		</script>
		<c:remove var="alertMsg" scope="session" />
	</c:if>
	
    <div id="header">
더보기

👉🏻 alert창 잘 뜸

 

👉🏻 DB 등록 확인

저작자표시 비영리 변경금지 (새창열림)
'📗 self-study/📗 KH정보교육원 당산지원' 카테고리의 다른 글
  • [Spring] 비밀번호 암호화 - Bcrypt를 위한 스프링 시큐리티 모듈
  • [Spring] Lombok (롬복) - 코드를 자동으로 생성해 주는 라이브러리
  • [Spring] Spring 웹 사이트 만들기 3 - 메인 페이지 만들기, 로그인 기능
  • [Spring] 파라미터(요청 시 전달값)를 받는 방법 / 요청 처리 후 응답 페이지를 담고 포워딩 또는 url 재요청 하는 방법
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[Spring] Spring 웹 사이트 만들기 4 - 회원가입 기능
상단으로

티스토리툴바