Spring-MyWeb 회원가입,로그인

정원·2022년 6월 23일

Spring-MyWeb

목록 보기
9/16

22.06.23 회원가입,MyBatis NULL,로그인,인터셉터

회원가입

userJoin.jsp

form태그에 action, id, method 작성,
UserVO로 묶어서 보내는 데이터들의 input창에 name 붙여야지 값이 제대로 넘어간다.

<form action="<c:url value='/user/join'/>" id="joinForm" method="post">
...
<input type="text" class="form-control" id="userId"
name="userId" placeholder="아이디를 (영문포함 4~12자 이상)">
  • 폼 데이터 검증(회원 가입 버튼 눌렀을 시)
    아이디 중복 체크를 했는지의 여부.(아이디 입력창이 readonly인지를 확인)
    비밀번호 확인란이 제대로 인식이 됐는지의 여부
    이름란이 공백이 아닌지를 확인.(이메일 인증, 주소는 필수값이 아니기 때문에 확인 안하겠다.)
    문제가 없다면 폼 데이터 submit으로 처리.

readonly속성의 경우 true/false이기 때문에
$('#userId').attr('readonly') === true 이렇게 물어보지 않는다!! 기억하기!

<script>
	$('#joinBtn').click(function() {
		//아이디 중복체크 여부 확인
		if(!$('#userId').attr('readonly')){
			alert('아이디 중복 체크는 필수입니다.');
			return;
		} else if($('#userPw').val() === '' || $('#userPw').val() !== $('#pwConfirm').val()){
			//비밀번호 확인란 인식 확인
			alert('비밀번호 규칙을 확인하세요.');
			$('#userPw').focus();
			return;
		} else if($('#userName').val() === ''){
			alert('이름은 필수입니다.');
			$('#userName').focus();
			return;
		} else {
			$('#joinForm').submit(); //form태그 submit
		}
	}); //회원가입 끝
</script>

UserController

userJoin.jsp에서 회원가입 버튼 누르면 /user/join 요청이 들어옴.
회원가입 진행 후 로그인 페이지로 이동 요청이 들어간다.

<script>
//회원 가입 진행 요청
@PostMapping("/join")
public String join(UserVO vo, RedirectAttributes ra) {
	System.out.println("param: " + vo);
	service.join(vo);
	ra.addFlashAttribute("msg", "joinSuccess");
	return "redirect:/user/userLogin";
}
    
//로그인 페이지로 이동 요청
@GetMapping("/userLogin")
public void userLogin() {}
</script>

UserService

@Override
public void join(UserVO vo) {
	mapper.join(vo);
}

UserMapper

<insert id="join">
	INSERT INTO users
	(userId, userPw, userName, userPhone1, userPhone2,
	 userEmail1, userEmail2, addrBasic, addrDetail, addrZipNum)
	VALUES
	(#{userId}, #{userPw}, #{userName}, #{userPhone1},
		#{userPhone2}, #{userEmail1}, #{userEmail2}, 
		#{addrBasic}, #{addrDetail}, #{addrZipNum})
</insert>

userLogin.jsp에다가 넘어온 msg뿌리기

<script>
	const msg ='${msg}';
	if(msg === 'joinSuccess'){
		alert('회원 가입 정상 처리 되었습니다.');
	}
</script>

MyBatis NULL

NOT NULL이 아닌 컬럼들은 사용자가 작성하지 않아도 된다.
하지만 MyBatis에서는 쿼리에 매핑되는 파라미터에 NULL이 들어가면 에러가 발생한다.
마이바티스에서 null 값을 받도록 설정을 추가할 수 있다.
마이바티스 공식 홈페이지에서 설정파일에 관련된 내용이 있다.참고하자.
https://mybatis.org/mybatis-3/ko/configuration.html

mybatis-config.xml

  • <setting name="jdbcTypeForNull" value="NULL"/> 태그를 이용.
    value에 전달할 값이 null일 경우에 처리할 값을 지정하면
    그 값으로 데이터베이스에 값이 세팅된다.
    VARCHAR는 빈문자열 NULL은 null
  • defaultStatementTimeout
    : 데이터베이스로부터의 응답을 얼마나 오래 기다릴지를 판단하는 타임아웃을 설정
  • typeAliases
    : Mapper에서 SQL resultType작성할때 별칭으로 사용 가능
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	
	<settings>		
		<!-- <setting name="jdbcTypeForNull" value="VARCHAR"/> -->
		<setting name="jdbcTypeForNull" value="NULL"/>
        
		<!-- 데이터베이스로부터의 응답을 얼마나 오래 기다릴지를 판단하는 타임아웃을 설정 -->
		<setting name="defaultStatementTimeout" value="3000"/>
	</settings>
	
	<typeAliases>
		<!-- Mapper에서 SQL resultType작성할때 별칭으로 사용 가능 -->
		<typeAlias type="com.spring.myweb.command.UserVO" alias="user"/>
		<typeAlias type="com.spring.myweb.command.ReplyVO" alias="reply"/>
		<typeAlias type="com.spring.myweb.command.FreeBoardVO" alias="board"/>
	</typeAliases>
	
	<!-- 인터페이스 mapper 구현체 xml 파일의 경로를 표시하는 태그
		SqlSessionfactoryBean을 등록 할 때 이미 지정했기 떄문에 추가로 작성할 필요는 없다.
		<mappers>
			<mapper resource="classpath:/mappers/*.xml"/>
		</mappers> -->	
		
</configuration>

db-config.xml

위에서 작성한 xml파일 설정 추가

<bean id="sqlSessionFactory"
	class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="ds" />
		
	<property name="configLocation" value="mybatis-config.xml" />
    
	<property name="mapperLocations" value="classpath:/mappers/*.xml" />
</bean>

로그인

header.jsp

Login버튼 누르면 /user/userLogin 요청이 들어간다.

<li><a href="<c:url value='/user/userLogin'/> "><span class="glyphicon glyphicon-log-in"></span>Login</a></li>

userLogin.jsp

form에 action, method, id 작성
넘겨지는 input 값들에도 name 지정.

<c:url value='/user/login'/>
${pagContext.request.contextPath}/user/login
위에 두 코드는 같은 코드이다.

회원가입버튼의 경우는 onclick으로 이벤트 발생시켜서 페이지 옮겨준다.
onclick="location.href=<c:url value='/user/userJoin'/>"

<form action="${pageContext.request.contextPath}/user/login" method="post" id="loginForm">
	<div class="form-group"><!--사용자클래스선언-->
    	<label for="id">아이디</label>
        <input type="text" name="userId" class="form-control" id="id" placeholder="아이디">
	</div>
    <div class="form-group"><!--사용자클래스선언-->
    	<label for="id">비밀번호</label>
    	<input type="password" name="userPw" class="form-control" id="pw" placeholder="비밀번호">
    </div>
    <div class="form-group">
    	<button type="button" id="loginBtn" class="btn btn-info btn-block">로그인</button>
    	<button type="button" class="btn btn-primary btn-block" onclick="location.href=<c:url value='/user/userJoin' />">회원가입</button>
    </div>
</form>  

로그인 버튼 누르면 이벤트 발생.
입력란이 공백인 지를 확인한 후, 공백이 아니라면 submit() 진행.
mapper에 작성한 login 메서드의 리턴 타입은 UserVO
리턴 타입에 맞게 sql문을 작성 해 주시면 되겠습니다.

<script>
   	const msg = '${msg}';
   	if(msg === 'joinSuccess') {
   		alert('회원 가입 정상 처리되었습니다.');
   	} else if(msg === 'loginFail') {
   		alert('로그인 실패! 아이디와 비밀번호를 확인하세요.');
   	}
    	
   	
   	$(function() {
		$('#loginBtn').click(function() {
			if($('#id').val() === '') {
				alert('아이디를 적어야 로그인을 하죠~');
				return;
			} else if($('#pw').val() === '') {
				alert('비밀번호를 작성하세요!');
				return;
			} else {
				$('#loginForm').submit();
			}
		});
	});   	
</script>

UserController

userLogin.jsp에서 /user/login 요청이 넘어온다.

mapper의 login 메서드 리턴 타입이 UserVO이다. 모델에 담아서 보내자.
리턴은 /user/userLogin으로 세팅,
util 패키지 안에 interceptor 패키지에
UserLoginSuccessHandler 클래스를 하나 생성하자.
UserLoginSuccessHandler는 로그인 처리 이후에 실행되는 핸들러를
오버라이딩 해서 -> 모델을 꺼내서
모덜 내의 데이터가 null이라면 로그인 실패입니다.
msg라는 이름으로 loginFail을 담아서
userLogin.jsp 파일로 응답하도록 viewName을 세팅하시고,
null이 아니라면 세션 만드셔서 홈 화면으로 이동시켜 주세요.

<script>
//로그인 요청
@PostMapping("/login")
public String login(String userId, String userPw, Model model) {
		
	model.addAttribute("user", service.login(userId, userPw));
	return "/user/userLogin";
}
</script>

UserService

@Override
public UserVO login(String id, String pw) {
	return mapper.login(id, pw);
}

UserMapper

<select id="login" resultType="user">
	SELECT * FROM users
	WHERE userId=#{id} AND userPw=#{pw}	
</select>

로그인 인터셉터

컨트롤러에서 로그인 진행을 하고 리턴된 UserVO를 인터셉터에서 받아서
결과에 따라 다른 요청을 보낼 것이다.

UserLoginSuccessHandler

컨트롤러 동작 이후에 실행되는 핸들러(postHandle) 오버라이딩.
/login 요청으로 들어올 때 실행되도록 xml 파일에 빈으로 등록 후 매핑.

ModelAndView를 이용하여 넘어온 model값 꺼내는 방법.
1. modelAndView.getModel().get("key")
2. modelAndView.getModelMap()은 ModelMap을 반환한다.
   반환하는 ModelMap을 받아서 .get( )을 호출하고 리턴타입이 Object이기 때문에
   원하는 타입으로 형변환 해서 사용.

<script>
package com.spring.myweb.util.interceptor;

public class UserLoginSuccessHandler implements HandlerInterceptor {		
	
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler,	ModelAndView modelAndView) throws Exception {
		
		System.out.println("로그인 인터셉터 동작!");		
		
//		modelAndView.getModel().get("key"); 가능
		ModelMap mv = modelAndView.getModelMap();
		UserVO vo = (UserVO)mv.get("user"); //리턴타입 Object라서 형변환
		System.out.println("interceptor vo: " + vo);
		
		if(vo != null) { //컨트롤러에서 로그인을 성공했던 사람.
			System.out.println("로그인 성공 로직 동작!");
			//로그인 성공한 회원에게 세션 데이터를 생성해서 로그인 유지를 하게 해 줌.
			HttpSession session = request.getSession();
			session.setAttribute("login", vo);
			response.sendRedirect(request.getContextPath());
			//("/myweb")인데 컨텍스트루트는 변경될수 있기 때문에 request.getContextPath()
		} else { //vo == null 로그인 실패
			modelAndView.addObject("msg", "loginFail");
			modelAndView.setViewName("/user/userLogin");			
		}
	}	
}
</script>

인터셉터 등록

servlet-config.xml에 작성해도 되지만 여러 인터셉터를 작성하면
코드가 길어지니까 파일을 따로 생성하자.

interceptor-config(Spring Bean Definition file).xml 생성

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- namespaces 탭에서 mvc 기능 추가 -->
	<!-- web.xml에 초기 설정 파일로 이 파일을 추가 -->
	
	<!-- 빈등록 -->
	<bean id="userLoginSuccessHandler" class="com.spring.myweb.util.interceptor.UserLoginSuccessHandler"/>
	
	<mvc:interceptors>
		<!-- 로그인 이후에 실행되는 postHandler 등록 -->
		<mvc:interceptor>
			<mvc:mapping path="/user/login"/>
			<ref bean="userLoginSuccessHandler"/>
		</mvc:interceptor>
	</mvc:interceptors>
	
</beans>

web.xml에 초기 설정 파일로 이 파일을 추가.

<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/config/servlet-config.xml
			/WEB-INF/config/email-config.xml				
			/WEB-INF/config/interceptor-config.xml				
		</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

header.jsp

로그인 완료된 사용자는 login세션이 존재하게 된다.
그에 맞게 상단 메뉴를 변경해 준다.

<ul class="dropdown-menu">
	<c:choose>
		<c:when test="${login == null}">
			<li><a href="<c:url value='/user/userJoin'/>"><span class="glyphicon glyphicon-user"></span>Join</a></li>
			<li><a href="<c:url value='/user/userLogin'/> "><span class="glyphicon glyphicon-log-in"></span>Login</a></li>
		</c:when>
		<c:otherwise>
			<li><a href="<c:url vlaue='/user/userMyPage'/> "><span class="glyphicon glyphicon-user"></span>MyPage</a></li>
			<li><a href="<c:url vlaue='/user/userLogout'/>"><span class="glyphicon glyphicon-log-out"></span>Logout</a></li>
		</c:otherwise>
	</c:choose>
</ul>

0개의 댓글