본문 바로가기

웹 개발 한걸음

[Mybatis + Ajax] 로그인 구현 해보기

 

 

** 이전에 만들었던 서블릿 프로젝트에서 JDBC가 아닌 Mybatis 프레임워크를, html의 submit 전송이 아닌 jquery를 이용한 ajax 통신을 사용해 로그인을 구현해보았다.

 

[Servlet] 로그인 구현하기

** 이전에 만들었던 JSP 프로젝트를 서블릿을 통해 MVC 패턴을 구현해보는 시간을 가져보았다. [JSP] 4강 - 로그인 기능 구현 // **문제해결** 본 포스팅은 정보 제공용이 아닌 유튜브 동빈나님의 JSP

egu99.tistory.com

 


 

  0. 간단 프로세스  

 

Servlet Controller에서 jsp로 forwarding

-> 로그인 jsp에서 id, pw를 ajax로 요청

-> Servlet Controller에서 dao의 login 메서드 호출

-> login 메서드는 mybatis mapper에 던지고 회원 정보 조회 후 반환

-> Servlet Controller에서 반환 받은 정보에 따라 로그인 성공 혹은 실패를 판단하고 임의의 chk값을 ajax로 응답

-> 응답 받은 jsp에서는 보내온 chk값에 따라 알림을 띄워줌.

 

 

 


 

  1. LoginController2.java - doGet()  

@WebServlet("/login2")
public class LoginControl2 extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		HttpSession session = request.getSession();

		if (session.getAttribute("user") != null) {
			PrintWriter script = response.getWriter();
			script.println("<script>");
			script.println("alert('이미 로그인 되었습니다.');");
			script.println("location.href='main'");
			script.println("</script>");
		} else {
			request.getRequestDispatcher("/WEB-INF/login2.jsp").forward(request, response);
		}
	}
}

 

  • 로그인 버튼을 누르면 이쪽으로 오게 된다. 
  • jsp로 forward해주기 전에 session에서 로그인 회원 정보도 확인해본다.

 


 

  2. login2.jsp  

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="e" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>	
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
	<!-- 로그인 컨테이너 -->
	<div class="container">
		<div class="col-lg-4">
			<!-- 점보트론 -->
			<div class="jumbotron" style="padding-top:20px;">
				<form>
					<h3 style="text-align: center;">로그인 화면</h3>
					<div class="form-group">
						<input type="text" id="loginId" class="form-control"  placeholder="아이디를 입력하세요." name="userID" maxlength="20">
					</div>
					<div class="form-group">
						<input type="password" id="loginPw" class="form-control"  placeholder="비밀번호를 입력하세요." name="userPassword" maxlength="20">
					</div>
					<input type="button" id="login" class="btn btn-primary form-control" value="로그인">
				</form>
			</div>
		</div>
	</div>
<script type="text/javascript">
	var lo = document.getElementById("login");
	
	lo.addEventListener("click", function(event){
		
		if(document.getElementById("loginId").value.length == 0){
			alert("아이디가 누락되었습니다.");
			event.preventDefault();	
		} else if(document.getElementById("loginPw").value.length == 0){
			alert("패스워드가 누락되었습니다.");
			event.preventDefault();	
		}	else {
			var id = $("#loginId").val().trim();
			var pw = $("#loginPw").val().trim();
			
			//비동기식 통신
			$.ajax({
				url : "./login2",
				type: "Post",
				dataType: "json",
				data: {userID : id, userPW : pw}
				
			}).done(function(res) {
				console.log(res.chk);
				if(res.chk == "1") {
					alert("로그인 되었습니다");
					location.href = "main";
				}else {
					alert("회원 정보가 없습니다.");
					location.href = "login2";
				}
                
			}).fail(function(err) {
					console.log(err);
			});
		}	
	});
</script>	
</body>
</html>

 

 

  • 이제 submit을 이용해 전달하지 않을 것이므로 input type을 button으로 바꿔주고 id를 넣어주었다.
  • 이 id를 가지고 자바스크립트에서 addEventListener를 통해 로그인 버튼 클릭시 이벤트를 등록한다. 
  • ajax로 전송 전에 id와 pw의 누락 여부를 확인해준다.
  • 누락되지 않았다면 jquery를 이용한 ajax 통신으로 사용자가 입력한 id와 pw를 컨트롤러로 요청과 함께 보낼 것이다.
  • 요청 성공시 응답받는 결과는 res에 담길 것이고 컨트롤러에서 해당 회원이 있다면 chk라는 키값에 1을, 없다면 0을 보낼 것이므로 그에 따른 알림과 이동을 해준다.

 

 

 ** JQuery를 이용한 Ajax    

// jQuery를 이용한 Ajax
  $.ajax({
    url: ,
    type: ,
    data: ,
    dataType: 	,

    done: function(response) {
      
    },
    fail: function(error) {
     
    },
    always: function(response) {
      
    }
  });
속성 설명
url 요청을 보낼 페이지의 경로
type 요청을 보낼 방식. Get 또는 Post
dataType 리턴할 데이터의 타입을 지정. xml, html, srcipt, json, text 
data 요청과 함께 서버로 전달될 데이터
timeout 살패한 것으로 처리하기까지의 제한 시간. 단위는 ms
async 요청시 동기 유무를 선택. true(비동기, 기본값) 또는 false (동기).
cache 브라우저 cache 처리. true 또는 false.
beforeSend 요청을 전달하기 전 호출될 함수 ( 로딩 중 아이콘 표시 등 )
always 성공 / 실패 이벤트 처리한 다음 실행될 함수 ( 로딩 중 아이콘 제거 등 )
done  요청 성공시 호출될 함수
fail 요청 실패시 호출될 함수
*여기서 get과 post 중 어떤걸 써야할까?
get방식은 전송 데이터가 header에 실려 url에 데이터가 노출되어 보안에 관련된 정보는
body에 포함되어 url에 데이터가 노출이 되지 않는 post방식을 쓰는 것이 바람직하다.

 

 


 

  3. LoginController2.java - doPost()  

@WebServlet("/login2")
public class LoginControl2 extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String userID = request.getParameter("userID");
		String userPassword = request.getParameter("userPW");
		
		HttpSession session = request.getSession();
		HashMap<String, String> map = new HashMap<String, String>();

		 User user = UserDao2.getInstance().login(userID, userPassword); 
		
		 if(user != null) { 
			 map.put("chk", "1");
			 session.setAttribute("user", user); 
		 }else {
			 map.put("chk", "0");
		 }

		String gson = new Gson().toJson(map);
		response.getWriter().write(gson);
		//System.out.println(gson);
	}

}

 

  • 로그인 ID와 PW가 Ajax를 통해 이쪽으로 넘어오고 받은 ID와 PW를 인자로 Dao의 login 메서드를 호출한다.
  • 이 메서드는 Mybatis로 DB에 접근하여 조회한 결과를 매핑한 User라는 VO객체를 반환하는데, 이 때 ID와 PW에 해당하는 회원이 존재시 VO객체가 null이 아닐 것이고 아이디와 패스워드 둘 중 하나라도 틀리다면 VO는 null일 것이다.
  • 따라서 null이 아닐 때는 제대로 입력한 것이므로 map을 하나 만들어 chk라는 키에 1을 담고 회원 정보를 세션에 담아주고 null일 경우는 chk 키에 0을 담아준다. 
  • 이 map을 요청이 왔던 jsp로 응답을 해줘야하는데 위에서 dataType을 json으로 했기 때문에 json으로 응답해주어야하는데 어떻게 응답해야할까?
    • Java 객체인 map을 어떻게 json으로 바꾸는 작업은 구글에서 만든 자바 오브젝트의 직렬화/역직렬화 라이브러리인 Gson이라는 패키지를 이용하면 쉽게 할 수 있다.
    • Gson은 이곳에서 jar파일을 다운 받아 라이브러리를 추가해주면 된다.

성공시 gson을 출력해본 결과.

 


 

 

  4. MybatisConnector.java  

public class MybatisConnector {

	private static MybatisConnector conn;
	SqlSessionFactory factory;
	
	private MybatisConnector() {
		 
		try {
			Reader reader = Resources.getResourceAsReader("config/mybatis/sqlConfig.xml");
			factory = new SqlSessionFactoryBuilder().build(reader);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static MybatisConnector getInstance() {
		if(conn == null) {
			conn = new MybatisConnector();
		}
		return conn;
	}
	
	public SqlSessionFactory getFactory() {
		
		return factory;
	}
	
}

 

  • 환경 설정파일인 sqlConfig.xml을 참조하여 Mybatis에 필요한 SqlSessionFactory를 만들어 반환해주는 클래스. 
  • 이전에 Mybatis 설정할 때 작성했던 방식과 똑같다.
 

[Mybatis] 마이바티스 파헤쳐보기 - 1 -

1. MyBatis란? 관계형 데이터베이스 프로그래밍을 보다 쉽게 도와주는 프레임워크로 JDBC의 근간을 두고 있다. 마이바티스는 개발자가 지정한 SQL, 저장프로시저 그리고 몇가지 고급 매핑을 지원하

egu99.tistory.com

 


 

 

  5. MybatisConnector.java  

public class UserDao2 {

	private static UserDao2 bao;
	SqlSessionFactory factory;
	
	private UserDao2() {
		factory = MybatisConnector.getInstance().getFactory();
	}
	
	public static UserDao2 getInstance() {
		if(bao == null) {
			bao = new UserDao2();
		}
		return bao;
	}
	
	public User login(String userID, String userPassword) {
		
		SqlSession session = factory.openSession();
		
		HashMap<String, String> map = new HashMap<String, String>();
		
		map.put("userID", userID);
		map.put("userPW", userPassword);

		User user  = session.selectOne("user.login", map);
		
		return user;
	}
	
}

 

  • MybatisConnector로부터 SqlSessionFactory를 얻고 이것으로부터 다시 SqlSession을 얻는다.
  • 컨트롤러에서 이 login()을 호출할 때 ID값과 PW값을 인자로 넣어주었고 이것을 다시 여기서 map에 담아 selectOne 메서드로 user라는 네임스페이스를 가진 mapper의 login을 실행할 때 인자로 넣어준다.
  • selectOne의 반환값은 User 클래스로, id와 pw가 제대로 입력했다면 회원정보가 매핑된 User 클래스가, 아니라면 null이 저장될 것이다. 
  • 이 매핑된 User클래스를 login()을 호출한 컨트롤러로 반환해준다.

 


 

  6. userMapper.xml  

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="user">
 	<select id="login" resultType="User" parameterType="java.util.Map">
 		select * from user where userID = #{userID} and userPassword = #{userPW};
 	</select>
 
  
</mapper>

 

  • 바로 위에서 selectOne 메서드를 실행할 때 map을 함께 넣어주었고 여기서 select의 속성인 parameterType으로 java.util.Map을 지정해줌으로써 파라미터로 map을 받을 수 있다. 
  • #{map 키값}으로 sql문에 저장한 map의 value를 꽂아줄 수 있다.
  • resultType으로 User클래스를 지정했으므로 아이디와 비밀번호가 일치한 회원 정보가 User클래스에 매핑되어 반환될 것이다. 일치하지 않는다면 null이 반환된다.

 


 

 

  7. 결과 화면   

 

 

 

 

♣ 참고 및 인용