본문 바로가기

반응형
저번에 설계한 회원 Table을 이용해서 로그인 기능을 구현해주도록 합니다.

 

1. 로그인 페이지

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<c:set var="path" value="${ pageContext.request.contextPath }" />
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<link rel="stylesheet" href="/resources/assets/css/style.css">
	<title>Login Page</title>
</head>
<body>

	<div class="approval-container">
		<div class="document">
			<h2>로그인</h2>
			<form id="login_form">
				<label for="id-input">ID : </label>
				<input type="text" id="id-input" name="id">
				<hr>
				<label for="pw-input">PW : </label>
				<input type="password" id="pw-input" name="pw">
				<button id='login_btn'>로그인</button>
			</form>
		</div>
	</div>
</body>
</html>

 

2. (로그인 성공 시) 넘어갈 페이지 (list.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

<c:set var="path" value="${ pageContext.request.contextPath }" />
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<link rel="stylesheet" href="/resources/assets/css/style.css">
	<title>List Page</title>
</head>
<body>

	<h3>리스트 페이지</h3>
	<p>${sessionName } ${sessionPst }님 환영합니다.</p>
	<a href="${path }/logout">로그아웃</a>

</body>
</html>

 

3. 로그인 Controller

@Controller
public class MemController {
	
	@Autowired
	private MemService memSer;
	
	//Login
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String login() {
		return "login";
	}
	
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String loginPost(@RequestParam Map<String, Object> param, HttpServletRequest request, RedirectAttributes redirectAttributes) {
		Map<String, Object> getMemInfo = memSer.getMemInfo(param);
		
		if(getMemInfo != null && getMemInfo.get("pw").equals(param.get("pw"))) {
			HttpSession session = request.getSession();
			session.setAttribute("sessionName", getMemInfo.get("memName"));
			session.setAttribute("sessionId", getMemInfo.get("id"));
			session.setAttribute("sessionPst", getMemInfo.get("memPosition"));
			
			return "redirect:/list";
		} else {
			if(getMemInfo == null || getMemInfo.isEmpty()) {
				redirectAttributes.addFlashAttribute("msg", "등록되지 않은 사용자입니다.");
			} else if (getMemInfo != null && !getMemInfo.get("pw").equals(param.get("pw"))) {
				redirectAttributes.addFlashAttribute("msg", "비밀번호가 일치하지 않습니다.");
			}
			
			return "redirect:/login";
		}
	}
}

 

4. 로그인 Service, Dao

// Service
public interface MemService {
	
	Map<String, Object> getMemInfo(Map<String, Object> param);

}

// Service Impl
@Service
public class MemServiceImpl implements MemService{
	
	@Autowired
	private MemDao memDao;
	
	@Override
	public Map<String, Object> getMemInfo(Map<String, Object> param){
		return memDao.getMemInfo(param);
	}

}

// Dao
public interface MemDao {
	
	Map<String, Object> getMemInfo(Map<String, Object> param);

}

// Dao Impl
@Repository
public class MemDaoImpl implements MemDao{
	
	@Autowired
	private SqlSessionTemplate sqlSession;
	
	@Override
	public Map<String, Object> getMemInfo(Map<String, Object> param){
		return sqlSession.selectOne("MemMapper.getMemInfo", param);
	}

}

 

5. Mapper

<?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="MemMapper">
	<resultMap id="Member" type="java.util.HashMap">
		<result column="MEM_SEQ" property="memSeq" />
		<result column="MEM_NAME" property="memName" />
		<result column="MEM_POSITION" property="memPosition" />
		<result column="ID" property="id" />
		<result column="PW" property="pw" />
	</resultMap>
	
	<select id="getMemInfo" resultMap="Member">
		select
			mem_seq,
			mem_name,
			decode(mem_position,'aa','부장','bb','과장','cc','대리','dd','대리') mem_position,
			id,
			pw
		from e_approval_member
		where id = #{id}
	</select>
	
</mapper>

Member의 DB속 계급에는 실제 계급 대신 코드로 저장될 테니 코드를 직급으로 반환해주는 Decode를 작성해 줍니다.

6. 로그아웃 구현 (Controller)

	// Logout
	@RequestMapping(value="/logout")
	public String logout(HttpSession session) {
		session.invalidate();
		return "redirect:/login";
	}

 

7. 로그인 건너 뛰고 리스트 페이지로 갈 수 없게 기능 구현 (list 페이지 Controller)

@Controller
public class AppController {
	
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String list(HttpServletRequest request, RedirectAttributes redirectAttributes) {
		HttpSession session = request.getSession();
		String sessionId = (String) session.getAttribute("sessionId");
		
		if(sessionId == null) {
			redirectAttributes.addFlashAttribute("msg", "로그인 하세요");
			return "redirect:/login";
		}
		
		return "list";
	}

}

세션이 없으면 다시 로그인 화면으로 가도록 처리해 줍니다.

8. 로그인 관련 JQuery (유효성 검사, 로그인 정보 일치 여부 검사)

	<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
	<script>
		$(function(){
			var msg = "${msg}";
			
			if(msg !== "" && msg !== null){
				alert(msg);
			}
			
			$("#login_btn").on('click', function(event){
				event.preventDefault();
				
				var idLength = $("#id-input").val().length;
				var pwLength = $("#pw-input").val().length;
				
				if(idLength == 0 && pwLength == 0){
					alert("로그인 정보를 입력하세요");
				} else if (idLength == 0 && pwLength > 0){
					alert("아이디를 입력하세요");
				} else if (idLength > 0 && pwLength == 0){
					alert("비밀번호를 입력하세요");
				} else {
					var idChk = $("#id-input").val();
					var pwChk = $("#pw-input").val();
					const regexaA0 = /^[a-z|A-Z|0-9|]+$/;
					
					if(!regexaA0.test(idChk) && regexaA0.test(pwChk)){
						alert("아이디가 유효하지 않습니다");
						$("#id-input").val('').focus();
					} else if (regexaA0.test(idChk) && !regexaA0.test(pwChk)){
						alert("비밀번호가 유효하지 않습니다");
						$("#pw-input").val('').focus();
					} else if (!regexaA0.test(idChk) && !regexaA0.test(pwChk)){
						alert("로그인 정보가 유효하지 않습니다");
						$("#pw-input").val('');
						$("#id-input").val('').focus();
					} else {
						$("#login_form").attr({
							"action" : "/login",
							"method" : "post"
						}).submit();
					}
				}
			})
			
		})
	</script>

<input> 태그에 입력 되어 있는 값의 길이를 이용해서 적었는지 안 적었는지 체크를 해주고, 유효성 검사를 통해 제대로 입력하지 않은 곳의 값을 지워주고 바로 입력할 수 있게 .val('').focus()를 해줍니다.

9. 결과물

로그인 화면
입력 여부 체크
유효성 검사
틀린 정보 입력 시
로그인 성공 시 & 로그아웃 결과

후기

로그인과 로그아웃 부분은 상대적으로 간단한 구현이었기 때문에 신속하게 완료했습니다. 보통 아이디와 비밀번호의 조건이 서로 다르기 때문에 제 코드에서처럼 하나의 기준으로만 검사하지 않고 각각의 조건을 고려해야 할 것으로 예상되지만, 테스트를 원활히 진행하기 위해 통일시켰습니다.

또한, URL을 통한 로그인 없이 다른 페이지로의 이동을 방지하기 위한 검사 및 리다이렉트 기능을 구현하는 것은 어려운 일은 아니었지만, 매우 중요한 부분이라고 판단했습니다. 더불어, 로그인이 필요한 페이지에 매번 해당 기능을 작성하는 것은 번거로우므로 별도의 메소드나 클래스로 추상화하는 것이 좋겠다는 생각을 했습니다.
반응형
댓글