빅데이터 Java 개발자 교육 - 35일차 Member 웹 구성 [JSP및 Servelt]

Jun_Gyu·2023년 3월 20일
0
post-thumbnail

이번시간에는 회원가입을 비롯한 마이페이지, 로그인 위한 Web을 구현해보도록 하겠다.

로그인, 회원가입, 마이페이지 생성하기

DB Table 생성하기

-- memtb생성
CREATE TABLE memtb (
  id VARCHAR(50)  PRIMARY KEY,
  password VARCHAR2(200)   ,
  name VARCHAR2(50),
  age NUMBER,
  regdate   TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 주소 seq 생성
CREATE SEQUENCE seq_address_no 
        INCREMENT BY 1
        START WITH 1;

-- memadrtb 생성

CREATE TABLE memadrtb (
  no NUMBER DEFAULT seq_address_no.NEXTVAL PRIMARY KEY,
  postcode VARCHAR2(5) ,
  address VARCHAR2(300),
  memberid VARCHAR(50),
  regdate  TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

ALTER TABLE memadrtb 
  ADD CONSTRAINT fk_emp03_depno
    FOREIGN KEY (memberid )
    REFERENCES memtb (id );

DTO 생성하기

Member.java

package dto;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(exclude = {"password"}) // 보안을 위해서 설정함.
@NoArgsConstructor
@AllArgsConstructor
public class Member {
	
	  private String id; // 아이디(PK)
	  private String password; // 비번
	  private String name; // 이름
	  private int age; // 나이
	  private Date regdate = new Date(); // 고객등록일
	  private String newPassword;
}
/*-----------------------------------------------------------------------------------------*/

Address.java

package dto;

import java.util.Date;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(exclude = {"password"})
@NoArgsConstructor
@AllArgsConstructor
public class Member {
	
	  private String id; // 아이디(PK)
	  private String password; // 비번
	  private String name; // 이름
	  private int age; // 나이
	  private Date regdate = new Date(); // 고객등록일
	  private String newPassword;
}

Mapper 쿼리문 구성하기

package mapper;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import dto.Member;

@Mapper
public interface MemberMapper {

/*------------------------------------------------------------------------*/

	// 회원가입
	@Insert( value = {
			"  INSERT INTO memtb   ",
					"  ( id , password , ",
				      "  name , age )  ",
			"  VALUES (  ",
				      "  #{obj.id}, #{obj.password},  ",
				      "  #{obj.name}, #{obj.age})  ",
	})
	public int insertMemberOne(@Param("obj") Member obj);

/*------------------------------------------------------------------------*/

	@Select( value = {
			"	SELECT id, name, age	",
			"	FROM memtb 	",
			"	WHERE id = #{obj.id} AND password = #{obj.password}	"
	} )
	public Member selectmemberLogin(@Param("obj") Member obj);

/*------------------------------------------------------------------------*/
	
	@Update( value = {
		"	<script>	",
			"	UPDATE memtb SET name =#{obj.name}	",
				"	<if test =	'obj.age != null'>	",
					" ,	age = #{obj.age}	",
				"	</if>	",
			"	WHERE id = #{obj.id}	",
		"	</script>	"
//			"	UPDATE memtb SET name =#{obj.name}	",
//				" ,	age =#{obj.age}	",
//			"	WHERE id =#{obj.id}	",
	} )
	public int updateMemberInfo (@Param("obj") Member obj);
	
/*------------------------------------------------------------------------*/
	
	@Update( value = {
			"	UPDATE memtb SET password = #{obj.newPassword}",
			"	WHERE id = #{obj.id} AND password = #{obj.password}	"
	} )
	public int updateMemberPw(@Param("obj") Member obj);
	
/*------------------------------------------------------------------------*/

	@Update( value = {
			"	UPDATE memtb SET	",
				"	password = null, name = null , age = null, regdate = null	",
			"	WHERE id = #{obj.id} AND password =	#{obj.password}"
	} )
	public int deleteMemberInfo(@Param("obj") Member obj);
}

회원가입화면

join.jsp

이번에는 복잡하지 않도록 짧은 이름으로, WEB-INF에 하위폴더를 생성하여 정리하였다.

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

<html>
	<head>
			<meta charset="UTF-8">	
			<title>${title}</title>
	</head>	
	<body>
		<div class="container">
			<a href="home.pknu">홈화면으로 돌아가기</a>
			<hr />
			<h3>${title}</h3>
			<form action="join.pknu" method="post"> 
			<!--기본적으로는 get, 보안상의 문제가 되는 정보들은 post로 가려서 보냄. -->										
				아이디 : <input type="text" name="id"/><br />
				암호 : <input type="password" name="password"/><br />
				암호확인 :  <input type="password" name="password1"/><br />
				이름 : <input type="text" name="name"/><br />
				나이 : <input type="number" name="age"/><br />
				<input type="submit" value="회원가입하기"/><br />
			</form>
		</div>
	</body>
</html>

JoinServlet.java 생성

@WebServlet(urlPatterns = { "/member/join.pknu" })

public class JoinServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public JoinServlet() {
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setAttribute("title", "환영합니다.");
		request.getRequestDispatcher("/WEB-INF/member/join1.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 이전화면에서 버튼을 눌러서 페이지가 이동되면서 전송된 데이터를 받기
		String id = request.getParameter("id");
		String pw = request.getParameter("password");
		String name = request.getParameter("name");
		int age = Integer.parseInt(request.getParameter("age")); 

		// static클래스 호출해서 기능 사용
		String pwHash = Hash.hashPW(id, pw);
		
		Member member = new Member();
		member.setId(id);
		member.setPassword(pwHash);
		member.setName(name);
		member.setAge(age);
		
		int ret = MyBatisContext.getSqlSession()
				.getMapper(MemberMapper.class).insertMemberOne(member);
		
		// DB에 추가한 이후에jsp를 보여주면 X, 주소를 바꿔서 보여줘야 함.
		if(ret == 1) {
			response.sendRedirect("home.pknu");
		}
		else {
			response.sendRedirect("join.pknu");
		}

		// 주소창의 정보를 바꾸고 엔터키를 수행하는것을 자동화 .. => redirect
		
	}
}

Hash 암호 생성 클래스

package config;

import java.security.MessageDigest;

public class Hash {

	public static String hashPW(String id, String pw) {
		try {
			// 1. Hash알고리즘 SHA-256
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			md.update((pw + id).getBytes());
	        
			byte[] pwdSalt = md.digest();
	        StringBuffer sb = new StringBuffer();
	        for(byte b : pwdSalt) {
	            sb.append(String.format("%02x", b));
	        }
	        String result = sb.toString();
	        return result;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}

로그인 구현

login1.jsp

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

<html>
	<head>
			<meta charset="UTF-8">	
			<title>${title}</title>
	</head>	
	<body>
		<div class="container">
			<a href="home.pknu">홈화면으로 돌아가기</a>
			<hr />
			<h3>${title}</h3>
			<form action="${pageContext.request.contextPath}/member/login.pknu" method="post"> 
			<!--기본적으로는 get, 보안상의 문제가 되는 정보들은 post로 가려서 보냄. -->										
				아이디 : <input type="text" name="id"/><br />
				암호 : <input type="password" name="password"/><br />
				<input type="submit" value="로그인하기"/><br />
			</form>
		</div>
	</body>
</html>

LoginServlet 생성

@WebServlet(urlPatterns = { "/member/login.pknu" }) 
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public LoginServlet() {
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setAttribute("title", "로그인");
		request.getRequestDispatcher("/WEB-INF/member/login1.jsp").forward(request, response);
	}
    
    
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String id = request.getParameter("id");
		String pw = request.getParameter("password");
		String pwHash = Hash.hashPW(id, pw);

		Member member = new Member();
		member.setId(id);
		member.setPassword(pwHash);

		Member ret = MyBatisContext.getSqlSession()
				.getMapper(MemberMapper.class).selectmemberLogin(member);
				
		if (ret != null) { // 로그인 성공
			// 세션에 기록 또는 읽기 위한 객체 생성
			HttpSession httpSession = request.getSession();
			// 세션에 필요한 정보를 기록 ex) 아이디, 이름을 기록 (30분간 유지)
			httpSession.setAttribute("UID", ret.getId());
			httpSession.setAttribute("UNAME", ret.getName());

			response.sendRedirect("home.pknu");
		} else { // 로그인 실패
			response.sendRedirect("login.pknu");
		}
	}
}

여기서 "세션"을 사용해주었다.

🚀 세션 사용하기

HttpSession httpSession = request.getSession(); 코드를 사용하여 로그인후 불러온 회원정보 중 필요로 하는 내용들을 저장하여

다른 웹 화면에서도 로그인 상태를 유지하거나, 회원의 정보를 수정, 삭제 등과 같은 상황에서 사용자가 직접 입력하지 않아도 일부 정보들을 불러올 수 있게끔 할 수 있다.

이는 세션을 이용한 방법으로, 세션에는 데이터의 기록 또는 읽기 위한 객체 생성이 가능하다.

세션을 사용하는 이유로는 위에서 언급했듯이 다른 웹페이지에서도 사용자의 고유 로그인 정보를 가져오려는 이유도 있지만, 외부로부터의 비정상적인 접근을 차단하는 보안적인 취지도 있다.
(예를들면 로그인 하지 않고 URL를 통해서 타고 들어온다던가..)

추가로 세션은 별도의 DB를 사용하여 데이터들을 저장한다.
대표적으로 redis가 세션을 보관하기 위한 세션용 DB로써 많이 사용된다.

이렇게 세션에 저장한 정보들은 이후에 사용하고자 하는 곳에서 객체명을 불러와 사용이 가능하며, 아래와 같이 조건문을 동해서 로그인, 비로그인 상황에서 같은 페이지에서 기능을 활성화하거나 비활성화 하는 용도로써 사용할 수도 있다.

위의 내용을 바탕으로 Home화면을 구성해보았다.

Home 화면 구성하기

(고양이 ㅎㅇㅎㅇ)

HomeServlet 생성


@WebServlet(urlPatterns = { "/member/home.pknu" }) 
public class HomeServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public HomeServlet() {
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setAttribute("title", "회원홈");
		request.getRequestDispatcher("/WEB-INF/member/home1.jsp").forward(request, response);
	}

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

사실 Servlet에서는 별다르게 구현해 줄 부분은 없다. 단지 URL만 할당하기 위한 용도이다.

home.jsp 생성

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

<html>
	<head>
			<meta charset="UTF-8">	
			<title>${title}</title>
	</head>	
	<body>				
	<img src="${pageContext.request.contextPath}/resources/images/5109431_agiLaciMHn_1659098198501.jpeg"
	style="width:90px; height:100px"/>
		<div class="container">
			<h3>${title}</h3><hr />
			
			<!-- 세션이 빈 상태일때  -->
			<c:if test="${sessionScope.UID eq null}">
				<a href="${pageContext.request.contextPath}/member/login.pknu"><button>로그인</button></a>
				<a href="join.pknu"> <input type="button" value="회원가입"/></a>
				</c:if>
				
			<!-- 세션에 로그인 정보가 들어있을때  -->
			<!-- 세션은 모든 jsp에 접근이 가능함.  -->
			<c:if test="${sessionScope.UID ne null}">
			<h4>${sessionScope.UNAME} 님 반갑습니다!</h4>
				<form action="logout.pknu" method="post" style="display:inline-block">
					<input type="submit" value="로그아웃"/>
					</form>
					<a href="mypage.pknu"><button>마이페이지</button></a>
					<a href="${pageContext.request.contextPath}/board/selectlist.do"> <input type="button" value="게시판정보"/></a>
			<a href="${pageContext.request.contextPath}/seller/selectlist.do"> <input type="button" value="판매자정보"/></a><br />
				</c:if>
	
			
			<hr />
			
		</div>
	</body>
</html>

로그인 후의 화면은

이러한 구성을 가지게 되며,
현재 로그인한 아이디의 이름을 불러오게됨과 동시에 마이페이지와 같은 기능들에 접근할 수 있게된다.
하지만, url주소값은 여전히 /member/home.pknu를 보여준다.


마이페이지 구현하기

이번에는 마이페이지를 들어가서 위와 같이 회원들의 정보를 바꿀 수 있도록 기능들을 구현해보겠다.

mypage.jsp

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

<html>
	<head>
			<meta charset="UTF-8">	
			<title>${title}</title>
	</head>	
	<body>
		<div class="container">
			<a href="home.pknu">홈화면으로 돌아가기</a>
			<hr />
			<h3>${title}</h3>
			
			<c:if test="${sessionScope.UID ne null}">
				<a href="mypage.pknu?menu=1"><button>회원정보 변경하기</button></a>
				<a href="mypage.pknu?menu=2"><button>비밀번호 변경하기</button></a>
				<a href="mypage.pknu?menu=3"><button>회원탈퇴하기</button></a>
				
				<c:if test="${param.menu == 1}">
				<form action="${pageContext.request.contextPath}/member/update.pknu" method="post">
					<h3>회원정보변경</h3>
					<hr />
					이름 : <input type="text" name="name" placeholder="${sessionScope.UNAME}"/><br />
					나이 : <input type="number" name="age" placeholder="변경할 나이"/><br />
					<input type="submit" value="변경하기"/><br />
					</form>
				</c:if>
				
				<c:if test="${param.menu == 2}">
					<form action="${pageContext.request.contextPath}/member/updatepw.pknu" method="post">
						<h3>회원암호변경</h3>
					<hr />
					<input type="password" name="oldpw" placeholder="현재암호"/><br />
					<input type="password" name="newpw" placeholder="새로운 암호"/><br />
					<input type="password" name="newpwcheck" placeholder="새로운 암호 확인"/><br />
					<input type="submit" value="변경하기"/><br />
					</form>
				</c:if>
				
				<c:if test="${param.menu == 3}">
					<form action="${pageContext.request.contextPath}/member/delete.pknu" method="post">
						<h3>회원탈퇴</h3>
						<hr />
					탈퇴확인 : <input type="password" name="pw"placeholder="현재암호" /><br />
					<input type="submit" value="회원탈퇴하기"/><br />
					</form>	
				</c:if>
			</c:if>
		</div>
	</body>
</html>

마이페이지의 기능은 다른 jsp들을 생성하지 않고 mypage.jsp에서 모두 사용이 가능하도록 기능을 구현하였다.
각각의 버튼에 주소"mypage.pknu?menu="를 할당하여, 사용하려는 버튼을 눌렀을때만 기능이 활성화되게 JSTLIF문을 활용하여 기능을 구성했으며, 초기화면은 회원 정보를 변경하는 기능인 "mypage.pknu?menu=1"을 default값으로 할당했다.

그렇다면 첫번째부터 순차적으로 Servlet을 구현해보도록 하자.

UpdateServlet

@WebServlet( urlPatterns = { "/member/update.pknu" } ) // 원래라면 이렇게 구성해주어야 함!

public class UpdateServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public UpdateServlet() {
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession httpSession = request.getSession();
		String id = (String) httpSession.getAttribute("UID");
		String name = request.getParameter("name");
		int age = Integer.parseInt(request.getParameter("age"));

		Member member = new Member();
		member.setId(id);
		member.setName(name);
		member.setAge(age);
		int ret = MyBatisContext.getSqlSession()
				.getMapper(MemberMapper.class).updateMemberInfo(member);

		if(ret == 1) {
			response.sendRedirect("home.pknu");
		}else {
			response.sendRedirect("mypage.pknu?menu=1");
		}
	}
}

UpdatePwServlet

@WebServlet(urlPatterns = { "/member/updatepw.pknu" })

public class UpdatePwServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public UpdatePwServlet() {
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession httpSession = request.getSession();
		String id = (String) httpSession.getAttribute("UID");
		String oldPw = request.getParameter("oldpw");
		String oldPwHash = Hash.hashPW(id, oldPw);
		
		String newPw = request.getParameter("newpw");
		String newPwCheck = request.getParameter("newpwcheck");
		
		if(newPw.equals(newPwCheck)) {
			String newPwHash = Hash.hashPW(id, newPwCheck);
			Member member = new Member();
			member.setId(id);
			member.setPassword(oldPwHash);
			member.setNewPassword(newPwHash);
			int ret = MyBatisContext.getSqlSession()
					.getMapper(MemberMapper.class).updateMemberPw(member);
			if(ret == 1) {
				response.sendRedirect("home.pknu");
			}else {
				response.sendRedirect("mypage.pknu?menu=2");
			}
		}else {
			response.sendRedirect("mypage.pknu?menu=2");
		}
	}
}

DeleteServlet

@WebServlet( urlPatterns = { "/member/delete.pknu" })

public class DeleteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public DeleteServlet() {
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession httpSession = request.getSession();
		String id = (String) httpSession.getAttribute("UID");
		String pw = request.getParameter("pw");
		String pwHash = Hash.hashPW(id, pw);

		Member member = new Member();
		member.setId(id);
		member.setPassword(pwHash);
		int ret = MyBatisContext.getSqlSession()
				.getMapper(MemberMapper.class).deleteMemberInfo(member);
		if (ret == 1) {
			httpSession.invalidate();
			response.sendRedirect("home.pknu");

		} else {

			response.sendRedirect("mypage.pknu?menu=3");
		}

	}
}

profile
시작은 미약하지만, 그 끝은 창대하리라

0개의 댓글