22.06.23 회원가입,MyBatis NULL,로그인,인터셉터
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속성의 경우 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>
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>
@Override
public void join(UserVO vo) {
mapper.join(vo);
}
<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>
NOT NULL이 아닌 컬럼들은 사용자가 작성하지 않아도 된다.
하지만 MyBatis에서는 쿼리에 매핑되는 파라미터에 NULL이 들어가면 에러가 발생한다.
마이바티스에서 null 값을 받도록 설정을 추가할 수 있다.
마이바티스 공식 홈페이지에서 설정파일에 관련된 내용이 있다.참고하자.
https://mybatis.org/mybatis-3/ko/configuration.html
<?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>
위에서 작성한 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>
Login버튼 누르면 /user/userLogin 요청이 들어간다.
<li><a href="<c:url value='/user/userLogin'/> "><span class="glyphicon glyphicon-log-in"></span>Login</a></li>
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>
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>
@Override
public UserVO login(String id, String pw) {
return mapper.login(id, pw);
}
<select id="login" resultType="user">
SELECT * FROM users
WHERE userId=#{id} AND userPw=#{pw}
</select>
컨트롤러에서 로그인 진행을 하고 리턴된 UserVO를 인터셉터에서 받아서
결과에 따라 다른 요청을 보낼 것이다.
컨트롤러 동작 이후에 실행되는 핸들러(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에 작성해도 되지만 여러 인터셉터를 작성하면
코드가 길어지니까 파일을 따로 생성하자.
<?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>
<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>
로그인 완료된 사용자는 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>