Spring/전자 결재 Project
[Spring] 전자결재 : 로그인
v조아리v
2023. 12. 28. 13:36
반응형
저번에 설계한 회원 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을 통한 로그인 없이 다른 페이지로의 이동을 방지하기 위한 검사 및 리다이렉트 기능을 구현하는 것은 어려운 일은 아니었지만, 매우 중요한 부분이라고 판단했습니다. 더불어, 로그인이 필요한 페이지에 매번 해당 기능을 작성하는 것은 번거로우므로 별도의 메소드나 클래스로 추상화하는 것이 좋겠다는 생각을 했습니다.
반응형