다음으로는 회원가입 기능을 만들고, 로그인 로그아웃까지 만들어보자.
INSERT를 이용할 것이기 때문에 기존에 만들어두었던 write를 갖다 쓰도록 하자.
package com.KoreaIT.java.jsp_AM.servlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import com.KoreaIT.java.jsp_AM.util.DBUtil;
import com.KoreaIT.java.jsp_AM.util.SecSql;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/member/dojoin")
public class ArticleDoJoinServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// DB 연결
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("클래스를 찾을 수 없습니다.");
e.printStackTrace();
}
String url = "jdbc:mysql://127.0.0.1:3306/AM_JDBC_2024_07?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul";
String user = "root";
String password = "1234";
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
String loginId = request.getParameter("loginId");
String loginPw = request.getParameter("loginPw");
String name = request.getParameter("name");
SecSql sql = SecSql.from("INSERT INTO `member`");
sql.append("SET regDate = NOW(),");
sql.append("updateDate = NOW(),");
sql.append("loginId = ?,", loginId);
sql.append("loginPw= ?,", loginPw);
sql.append("`name` = ?", name);
int id = DBUtil.insert(conn, sql);
response.getWriter().append(String.format(
"<script>alert('%d번 회원 가입 되었습니다.'); location.replace('.../article/list');</script>", id, id));
} catch (SQLException e) {
System.out.println("SQL 에러: " + e.getMessage());
response.getWriter().append("<script>alert('회원가에 실패했습니다.'); history.back();</script>");
} finally {
try {
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package com.KoreaIT.java.jsp_AM.servlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import com.KoreaIT.java.jsp_AM.util.DBUtil;
import com.KoreaIT.java.jsp_AM.util.SecSql;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/member/join")
public class ArticleJoinServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
request.getRequestDispatcher("/jsp/member/join.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
Map<String, Object> articleRow = (Map<String, Object>) request.getAttribute("articleRow");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
</head>
<body>
<h2>회원가입</h2>
<!-- 게시물 작성 폼 -->
<form action="dojoin" method="post">
<div>
<label for="loginId">아이디:</label>
<input autocomplete = "off" type="text" id="loginId" name="loginId" required>
</div>
<div>
<label for="loginPw">비밀번호:</label>
<input autocomplete = "off" id="content" name="loginPw" required></input>
</div>
<div>
<label for="loginPwConfirm">비밀번호 확인:</label>
<input autocomplete = "off" id="content" name="loginPw" required></input>
</div>
<div>
<label for="name">이름:</label>
<input autocomplete = "off" id="content" name="name" required></input>
</div>
<div>
<button type="submit">가입</button>
</div>
</form>
<div>
<a style="color: green" href="list">리스트로 돌아가기</a>
</div>
</body>
</html>
일단은 이렇게 기본적인 틀을 짜고, 이제 부수적인 것을 확인하고 한단계씩 구현하면 된다.
일단 해야할 것을 써보자면,
아이디, 비번, 비번 확인, 이름 창이 비어있으면 안된다.
비번과 비번확인이 일치해야한다.
데이터베이스상에서 같은 아이디가 존재해서는 안된다.
세가지 조건을 만족하게끔 만들어야한다.
나 같은 경우에는 이미 코드에 빈칸을 전송하려고 하면 required에 의해서 막힌다. 하지만 브라우저 환경은 각자 다 다르고, 또 우리는 이걸 연습을 하기 위해서 만들고 있어서 다른 로직을 추가한다. java까지 데이터를 옮기면서 막는 것이 아니라 자바스크립트로 해당 페이지 내에서 바로 처리하는 방법이 있다.
<script type="text/javascript">
function JoinForm__submit(form) {
// 확인용 콘솔 로
// console.log('form.loginId.value : ' + form.loginId.value);
// console.log('form.loginId.value.trim() : '
// + form.loginId.value.trim());
// console.log('form.loginId.value.trim : ' + form.loginId.value.trim);
// console.log('form.loginPw.value : ' + form.loginPw.value);
// console.log('form.loginPwConfirm.value : '
// + form.loginPwConfirm.value);
// console.log('form.name.value : ' + form.name.value);
// form.loginId.value = form.loginId.value.trim();
// console.log("loginId : " + loginId);
let loginId = form.loginId.value.trim();
let loginPw = form.loginPw.value.trim();
let loginPwConfirm = form.loginPwConfirm.value.trim();
let name = form.name.value.trim();
if (loginId.length == 0) {
alert('아이디 입력해주세요');
return;
}
if (loginPw.length == 0) {
alert('비밀번호 입력해주세요');
return;
}
if (loginPwConfirm.length == 0) {
alert('비밀번호 확인 입력해주세요');
return;
}
if (loginPw != loginPwConfirm) {
alert('비밀번호가 일치하지 않습니다');
form.loginPw.focus();
return;
}
if (name.length == 0) {
alert('이름 입력해주세요');
return;
}
form.submit();
}
</script>
<!-- <a onclick="if(confirm('진짜 이동???') == false) return false;" href="https://www.naver.com" target="_blank">네이버</a> -->
<form action="dojoin" method="post"
onsubmit="JoinForm__submit(this); return false;">
해당 로직을 추가하면 alert로 뭐가 비어있는지 알려준다.
그리고 비밀번호 확인해주는 로직까지 추가했다. 입력받은 비밀번호, 비밀번호 확인을 대조해서 검증하면 된다.
해당 코드가 잘 작동하는지 확인하고 넘어가면 된다. 이제는 검증할 때 편하려고 text로 처리해 두었던 비밀번호 칸을 password로 바꿔주면,
확인하고 이제는 로그인 아이디가 같을 경우에는 회원가입을 막는 코드를 doJoin 서블릿에 SELECT 쿼리로 검증해주면 회원가입은 끝이다.
SecSql sql = SecSql.from("SELECT COUNT(*) AS cnt");
sql.append("FROM `member`");
sql.append("WHERE loginId = ?;", loginId);
boolean isJoinableLoginId = DBUtil.selectRowBooleanValue(conn, sql);
if (isJoinableLoginId == false) {
response.getWriter().append(String.format("<script>alert('%s는 이미 사용중'); location.replace('../member/join');</script>", loginId));
return;
}
INSERT를 하기전에 검증하고 값이 false면 알림문구와 함께 되돌려준다.
어째선지 작동을 안해서 코드를 잘못썻나했는데 새로고침을 안해서 적용이 안됐던 것.. 아무튼 화면상으로는 이렇게 나온다.
test1은 이미 테스트용으로 만들어진 계정이다.
test1으로 회원가입을 시도하면
해당 알림으 뜨면서 다시 회원가입창으로 이동한다.
다음으로 로그인구현!
@WebServlet("/member/login")
public class MemberLoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
request.getRequestDispatcher("/jsp/member/login.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
Map<String, Object> articleRow = (Map<String, Object>) request.getAttribute("articleRow");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<!-- 게시물 작성 폼 -->
<script type="text/javascript">
function JoinForm__submit(form) {
// 확인용 콘솔 로
// console.log('form.loginId.value : ' + form.loginId.value);
// console.log('form.loginId.value.trim() : '
// + form.loginId.value.trim());
// console.log('form.loginId.value.trim : ' + form.loginId.value.trim);
// console.log('form.loginPw.value : ' + form.loginPw.value);
// console.log('form.loginPwConfirm.value : '
// + form.loginPwConfirm.value);
// console.log('form.name.value : ' + form.name.value);
// form.loginId.value = form.loginId.value.trim();
// console.log("loginId : " + loginId);
let loginId = form.loginId.value.trim();
let loginPw = form.loginPw.value.trim();
let loginPwConfirm = form.loginPwConfirm.value.trim();
let name = form.name.value.trim();
if (loginId.length == 0) {
alert('아이디 입력해주세요');
return;
}
if (loginPw.length == 0) {
alert('비밀번호 입력해주세요');
return;
}
form.submit();
}
</script>
<!-- <a onclick="if(confirm('진짜 이동???') == false) return false;" href="https://www.naver.com" target="_blank">네이버</a> -->
<form action="dologin" method="post"
onsubmit="JoinForm__submit(this); return false;">
<div>
<label for="loginId">아이디:</label> <input autocomplete="off"
type="text" id="loginId" name="loginId" required>
</div>
<div>
<label for="loginPw">비밀번호:</label> <input autocomplete="off"
id="content" name="loginPw" type="password" required></input>
</div>
<div>
<button type="submit">로그인</button>
</div>
</form>
<div>
<a style="color: green" href="list">리스트로 돌아가기</a>
</div>
</body>
</html>
마찬가지로 틀부터 짜고 잘 작동되는지 확인한다.
@WebServlet("/member/dologin")
public class MemberDoLoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// DB 연결
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("클래스를 찾을 수 없습니다.");
e.printStackTrace();
}
String url = "jdbc:mysql://127.0.0.1:3306/AM_JDBC_2024_07?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul";
String user = "root";
String password = "1234";
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
String loginId = request.getParameter("loginId");
String loginPw = request.getParameter("loginPw");
SecSql sql = SecSql.from("SELECT *");
sql.append("FROM `member`");
sql.append("WHERE loginId = ?;", loginId);
Map<String, Object> memberRow = DBUtil.selectRow(conn, sql);
if (memberRow.isEmpty()) {
response.getWriter().append(String
.format("<script>alert('%s는 존재하지 않습니다.'); location.replace('../member/login');</script>", loginId));
return;
}
if (memberRow.get("loginPw") != loginPw) {
response.getWriter().append(String
.format("<script>alert('비밀번호가 일치하지 않습니다.'); location.replace('../member/login');</script>"));
return;
}
// sql = SecSql.from("INSERT INTO `member`");
// sql.append("SET regDate = NOW(),");
// sql.append("updateDate = NOW(),");
// sql.append("loginId = ?,", loginId);
// sql.append("loginPw= ?,", loginPw);
// sql.append("`name` = ?", name);
int id = DBUtil.insert(conn, sql);
response.getWriter().append(String.format(
"<script>alert('%d번 회원 가입 되었습니다.'); location.replace('../article/list');</script>", id, id));
} catch (SQLException e) {
System.out.println("SQL 에러: " + e.getMessage());
response.getWriter().append("<script>alert('회원가입에 실패했습니다.'); history.back();</script>");
} finally {
try {
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
이후 서블렛을 구축하면 되는데 일단은 없는 아이디일 경우와 비밀번호가 일치하지 않을 때, 로그인을 할 수 없게 만들었다.
이렇고 test1은 존재하니 그걸로 테스트 해보면.
비밀번호가 일치하지 않는다는 문구까지 잘 뜬다.
이제 로그인할 수 있게, 그리고 로그인한 상태를 저장할 수 있게 하면 로그인 기능은 완성이다.
로그인이 가능하게 하는건 간단하다 이미 저기서 걸러지지 않고 통과했다는 것은 로그인 할 수 있다는 뜻이니까.
response.getWriter().append(String.format(
"<script>alert('%s 회원님 로그인 되었습니다.'); location.replace('../article/list');</script>", memberRow.get("name")));
알림창만 띄워주면 로그인 한 것 처럼 보인다.
하지만 이걸로는 로그인의 상태를 서버가 알지 못한다. 그것을 알기 위해서 우리는 HttpSession과 setAttribute와 getAttribute, 그리고 removeAttribute를 사용할 것이다.
우선 해당 코드들이 무엇인지부터 알아보자.
HttpSession
웹 애플리케이션에서 클라이언트 세션을 관리하는 데 사용되는 객체. 사용자가 웹 애플리케이션을 사용하는 동안 일정 기간 동안 정보를 유지하고 사용자별로 데이터를 관리할 수 있게 한다. 세션은 주로 로그인 상태 유지, 사용자 특정 설정, 사용자가 사이트 내에서 수행하는 활동 추적 등에 사용됨.
setAttribute
setAttribute(String name, Object value) 메소드는 세션에 객체를 저장하는 데 사용됨. 이 메소드를 사용하여 어떤 데이터든 세션에 바인딩(프로그램의 어떤 기본 단위가 가질 수 있는 구성요소의 구체적인 값, 성격을 확정하는 것)할 수 있으며, 이 데이터는 서버가 세션을 유지하는 동안 계속 접근 가능.
getAttribute
getAttribute(String name) 메소드는 세션에서 객체를 검색하는 데 사용. setAttribute로 설정된 값을 이름을 통해 검색할 수 있다.
removeAttribute
removeAttribute(String name) 메소드는 세션에서 특정 객체를 제거하는 데 사용. 이 메소드로 세션에서 객체를 삭제할 수 있으며, 객체가 더 이상 세션에서 참조되지 않으면 가비지 컬렉터에 의해 수집될 수 있음.
이러한 메소드들은 사용자의 세션 데이터를 동적으로 관리할 수 있게 해주며, 웹 애플리케이션의 상태 유지 관리, 보안 향상, 사용자 경험 개선에 기여할 수 있다.
이런 이유로 해당 메서드를 사용하면 로그인 상태나 사용자 정보를 관리하기 쉬워진다.
따라서 doLogin 서블릿에 해당 코드를 추가.
HttpSession session = request.getSession();
session.setAttribute("loginedMemberId", memberRow.get("id"));
session.setAttribute("loginedMemberLoginId", memberRow.get("loginId"));
session.setAttribute("loginedMember", memberRow);
그리고 이 변수를 메인 서블렛에 불러와준다. 로그인 버튼도 메인 JSP에 존재하고 메인에서 로그인 유무를 판단하고 넘어가야 나중에 글 작성 수정 삭제 등에 유저 고유 아이디 대조도 편해질테니까 미리 해둔다. 그리고 로그인 상태를 유지까지 만들었으니 로그아웃 기능까지 함께 만들면서 가겠다. 일단은 메인서블렛의 코드는 이렇다.
package com.KoreaIT.java.jsp_AM.servlet;
import java.io.IOException;
import java.util.Map;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
@WebServlet("/home/main")
public class HomeMainServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
boolean isLogined = false;
int loginedMemberId = -1;
Map<String, Object> loginedMember = null;
if (session.getAttribute("loginedMemberId") != null) {
isLogined = true;
loginedMemberId = (int) session.getAttribute("loginedMemberId");
loginedMember = (Map<String, Object>) session.getAttribute("loginedMember");
}
request.setAttribute("isLogined", isLogined);
request.setAttribute("loginedMemberId", loginedMemberId);
request.setAttribute("loginedMember", loginedMember);
request.getRequestDispatcher("/jsp/home/main.jsp").forward(request, response);
}
}
MAIN JSP는
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
boolean isLogined = (boolean) request.getAttribute("isLogined");
int loginedMemberId = (int) request.getAttribute("loginedMemberId");
Map<String, Object> loginedMember = (Map<String, Object>) request.getAttribute("loginedMember");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>메인페이지</title>
</head>
<body>
<h1>MAIN</h1>
<!-- 로그인상태 확인 임시 div -->
<div><%=loginedMemberId%>번 회원 로그인 중
</div>
<div><%=loginedMember%></div>
<%
if (isLogined) {
%>
<div>
<a href="../member/doLogout">로그아웃</a>
</div>
<%
}
%>
<%
if (!isLogined) {
%>
<div>
<a href="../member/login">로그인</a>
</div>
<%
}
%>
<ul>
<li><a href="../article/list">리스트로 이동</a></li>
</ul>
<ul>
<li><a href="../member/join">회원가입</a></li>
</ul>
<ul>
<li><a href="../member/login">로그인</a></li>
</ul>
</body>
</html>
이렇게 필요한 코드들을 추가해주고, 로그아웃 서블렛을 만들어서
<a href="../member/doLogout">로그아웃</a>
해당 a태그가 작동하게끔 만들어주자.
@WebServlet("/member/dologout")
public class MemberDoLogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
// DB 연결
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("클래스를 찾을 수 없습니다.");
e.printStackTrace();
}
String url = "jdbc:mysql://127.0.0.1:3306/AM_JDBC_2024_07?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Seoul";
String user = "root";
String password = "1234";
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
HttpSession session = request.getSession();
session.removeAttribute("loginedMemberId");
session.removeAttribute("loginedMemberLoginId");
session.removeAttribute("loginedMember");
response.getWriter()
.append(String.format("<script>alert('로그아웃 됨'); location.replace('../article/list');</script>"));
} catch (SQLException e) {
System.out.println("SQL 에러: " + e.getMessage());
response.getWriter().append("<script>alert('로그인에 실패했습니다.'); history.back();</script>");
} finally {
try {
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
Attribute에 저장했던 키와 벨류만 삭제하면 로그아웃이다. 따라서 removeAttribute만 써주면 로그아웃은 간단하게 만들 수 있다.
웹페이지들이 제대로 작동하나 확인중에 오류 하나를 찾았다.
main JSP에 Map을 Immport하지 않았다.
<%@page import="java.util.Map"%>
임포트 해주고!
메인 페이지를 확인하면
-1번 회원은 존재하지 않는 회원이니 로그인 상태가 아니라는 것을 알 수 있고, 로그인 상태가 아니기 때문에 로그인 버튼이 활성화 되어있다. 로그인해보자.
로그인 상태가 잘 저장되고 있다. 마지막으로 로그아웃까지 해보면,
alert 문구도 잘 뜨고,
다시 로그인 상태로 전환도 잘 된다.
오늘은 여기까지!
'Coding History' 카테고리의 다른 글
국비 지원 IT(웹앱개발) 취업반 강의 47일차 (Spring) (0) | 2024.08.11 |
---|---|
국비 지원 IT(웹앱개발) 취업반 강의 46일차 (JSP) (0) | 2024.08.08 |
국비 지원 IT(웹앱개발) 취업반 강의 45일차 1 (HTML, CSS, JS) (0) | 2024.08.07 |
국비 지원 IT(웹앱개발) 취업반 강의 44일차 2 (HTML, CSS, JS) (0) | 2024.08.07 |
국비 지원 IT(웹앱개발) 취업반 강의 44일차 1 (HTML, CSS, JS) (0) | 2024.08.06 |