복습
전체 흐름
Service 클래스
- 공통적인 내용들을 Action 이라는 인터페이스에 작성, 추상메소드 execute() 가 있다
- 각각의 클래스들은 인터페이스 Action 을 상속함, 반드시 추상메소드 execute() 를 오버라이딩 해야함
- 클라이언트의 요청을 실제로 처리
- DAO 와 함께 실제 DB 쪽에 데이터를 처리해주는 Model 이라고 불린다
- DB에서 검색한 결과를 DAO 에서 Service 클래스로 리턴함
- Service 클래스에서 돌려받은 객체를 공유설정함
- View 페이지에서 공유설정된 값을 EL + JSTL 으로 출력한다
Controller 클래스
- HttpServlet 클래스를 상속받는다, doPost(), doGet() 메소드를 오버라이딩 해야함
- WebServlet 어노테이션 이름값이 하나면 한곳에서 온 요청만 받을 수 있으므로 Controller 클래스를 여러개 만들어야한다
- WebServlet 어노테이션 이름값을 패턴을 지정해서 패턴에 맞으면 다 여기로 오도록 함
- 그 후 폼의 action 값들을 패턴에 맞게 지정한다, 그럼 Contorller 클래스로 찾아갈 수 있음
- 다른 웹사이트의 URL 주소를 보면 확장자가 보인다 ex) .do, .naver
회원관리 프로그램 : Controller 클래스 (이어서)
- MemberController.java (수정 전 1)
package controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class MemberController
*/
@WebServlet("*.do") // do 확장자
public class MemberController extends HttpServlet {
private static final long serialVersionUID = 1L;
// doGet(), doPost() 메소드에서 공통적인 작업을 처리하는 메소드
protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String command = requestURI.substring(contextPath.length());
System.out.println("requestURI : " + requestURI); // requestURI : /model2member/Login.do
System.out.println("contextPath : " + contextPath); // contextPath : /model2member
System.out.println("command : " + command); // command : /Login.do
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get");
doProcess(request, response); // doProcess() 호출
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post");
doProcess(request, response); // doProcess() 호출
}
}
- Controller 클래스에서 매개변수로 받은 request, response 객체를 Service 클래스로 넘어갈때도 전달한다
- doPost(), doGet() 에서 받은 request, response -> doProcess() 호출시 넘겨줌 -> Service 클래스로 갈때도 넘겨줌
- doProcess() 에도 넘겨줘야 거기서 request.getRequestURI() 와 request getContextPath() 메소드를 사용가능
doProcess() 안의 내용 (MemberController.java 부분)
// doGet(), doPost() 메소드에서 공통적인 작업을 처리하는 메소드
protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String command = requestURI.substring(contextPath.length());
System.out.println("requestURI : " + requestURI); // requestURI : /model2member/Login.do
System.out.println("contextPath : " + contextPath); // contextPath : /model2member
System.out.println("command : " + command); // command : /Login.do
}
- command 에 저장되는 값에 구체적으로 어떤 요청이름기값으로 Controller 클래스로 왔는지 확인 가능
- 즉, command 에 저장된 값으로 어디서 요청이 왔는지 확인 가능하다
- command 값을 보고 어떤 서비스 클래스로 보낼지 결정한다
+ substring(13) 은 13 인덱스부터 끝까지를 자른다
- 결과 확인 1
- loginform.jsp form 태그
<form method="post" action="<%=request.getContextPath() %>/Login.do">
- loginform.jsp 파일을 실행해서 '로그인' 을 눌러보자
+ 해당 Service 클래스 이름도 요청 이름값과 똑같이 작성할 것, Login.java
- 결과 확인 2
- memberform.jsp form 태그
<form method="post" action="<%=request.getContextPath() %>/MemberInsert.do">
- memberform.jsp 파일을 실행해서 '회원가입' 을 눌러보자
- 요청 이름값이 command 변수에 저장된다
+ 해당 Service 클래스 이름도 요청 이름값과 똑같이 작성할 것, MemberInsert.java
실행 순서
1. loginform.jsp 또는 memberform.jsp 에서 action 태그로 지정된 곳을 따라 Controller 클래스 도착
2. post 방식으로 요청했으므로 오버라이딩 된 doPost() 실행됨, doProcess() 가 다음으로 실행됨
3. 3개의 변수값이 구해짐
- 최종적으로는 요청 이름값이 저장된 command 변수의 값이 필요하다
- 어떤 서비스 클래스로 보낼지 command 값을 보고 결정
회원관리 프로그램 : Service 클래스 1
- Service 클래스를 통일성 있게 설계하기 위해 부모가 될 인터페이스 Action 먼저 만들기
- 인터페이스 Action 을 만들고 안에는 추상메소드 execute() 만들기
- Service 에서 DAO 로 넘어가야한다
+ ActionForward 클래스
- 이 클래스에서 어떤 방식으로 포워딩 할지, 어디로 포워딩 할지 결정해줌
- redirect 변수는 포워딩 방식을 설정, path 는 포워딩할 페이지명 설정
- request 객체로 공유가 되면 포워딩 하는 방법 2가지가 있다
- request 객체로 공유가 되었을때는 반드시 dispatcher 방식으로 포워딩되어야 뷰페이지에 출력 가능
부모 인터페이스 만들기
- 이제 service 패키지를 만들고 인터페이스 Action 을 만들자
- 현재까지 Action 인터페이스
- Action.java
package service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Action {
// 추상 메소드
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
- 리턴자료형은 아직 만들지 않은 ACtionForward 로 한다
- Controller 클래스의 doProcess() 의 매개변수 request, response 를 그대로 execute() 의 매개변수에 복사
- 추상메소드 execute() 는 형식만 있다
ActionForward 클래스 만들기
- ActionForward.java
package service;
public class ActionForward {
private boolean redirect; // 포워딩 방식 설정
private String path; // 포워딩 페이지명 설정
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
- Service 패키지 안에 ActionForward 클래스 만들기
1. 포워딩 방식을 결정할 변수 redirect 정의, dispatcher, redirect 방식 중 어느 것으로 할지 true, false 로 결정
2. 포워딩할 페이지명이 저장될 변수 path 를 정의
- 두 변수는 private 으로 설정
3. getter, setter 메소드 만들기
+ 이클립스가 redirect 변수의 getter 메소드를 자동으로 만들때 getRedirect() 가 아니라 isRedirect() 로 만들었음을 유심히 보기
- Service 클래스에서 값을 처리하고 View 페이지로 가기 전에 이 ActionForward 로 포워딩 방식, 포워딩 페이지명을 결정
- 다시 Controller 클래스로 돌아와서 Service 클래스로 넘겨주는 작업을 하자
- MemberController.java (수정 전 2)
package controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.Action;
import service.ActionForward;
import service.MemberInsert;
/**
* Servlet implementation class MemberController
*/
@WebServlet("*.do") // do 확장자
public class MemberController extends HttpServlet {
private static final long serialVersionUID = 1L;
// doGet(), doPost() 메소드에서 공통적인 작업을 처리하는 메소드
protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String command = requestURI.substring(contextPath.length());
System.out.println("requestURI : " + requestURI); // requestURI : /model2member/Login.do
System.out.println("contextPath : " + contextPath); // contextPath : /model2member
System.out.println("command : " + command); // command : /Login.do
Action action = null;
ActionForward forward = null;
// 회원가입
if(command.equals("/MemberInsert.do")) {
try {
action = new MemberInsert();
forward = action.execute(request, response);
} catch (Exception e){
e.printStackTrace();
}
}
// 포워딩 처리
if(forward != null) {
if(forward.isRedirect()) { // redirect 방식으로 포워딩
response.sendRedirect(forward.getPath());
} else { // dispatcher 방식으로 포워딩
RequestDispatcher dispatcher =
request.getRequestDispatcher(forward.getPath());
dispatcher.forward(request, response);
}
}
} // doProcess() end
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get");
doProcess(request, response); // doProcess() 호출
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post");
doProcess(request, response); // doProcess() 호출
}
}
- 모두 doProcess() 안에서 작성한다
- service 패키지 안의 Action 인터페이스 객체 action 를 만들고 null 로 초기화
- service 패키지 안의 ActionForward 클래스 객체 forward 를 만들고 null 로 초기화
- 다음은 요청에 따라 적절한 Service 클래스로 넘기기
- 마지막 부분에서 포워딩 처리를 한다, DAO -> Service -> Controller 로 돌아올때 포워딩 처리함
Service 클래스로 전달 (MemberController.java 부분)
// 회원가입
if(command.equals("/MemberInsert.do")) {
try {
action = new MemberInsert();
forward = action.execute(request, response);
} catch (Exception e){
e.printStackTrace();
}
}
- Controller 클래스는 어떤 Service 클래스로 넘겨줄건지 결정
- command 값, 즉 요청 이름값이 "/MemberInsert" 면 회원가입을 처리하는 MemberInsert 클래스로 객체 action 생성
- 왼쪽은 부모 인터페이스, 오른쪽은 상속받는 구현 클래스가 왔다, 업캐스팅을 하고 있음
- action 객체를 통해 MemberInsert() 클래스의 오버라이딩된 메소드인 execute() 를 실행하고 ActionForward 객체 forward 로 리턴받음
- 해당 클래스 MemberInsert 의 객체를 만들고 execute() 를 실행하므로써 그 Service 클래스 MemberInsert 로 가는 것임
+ 메소드 오버라이딩이 되면 오버라이딩 된 메소드만 실행된다
- execute() 를 호출하며 매개변수로는 doGet(), doPost() 의 매개변수인 request, response 를 전달함
+ try-catch 예외처리 해야한다
* MemberInsert 클래스는 아래에서 구현한 회원가입 처리 Service 클래스이다.
포워딩 처리 (MemberController.java 부분)
// 포워딩 처리
if(forward != null) {
if(forward.isRedirect()) { // redirect 방식으로 포워딩
response.sendRedirect(forward.getPath());
} else { // dispatcher 방식으로 포워딩
RequestDispatcher dispatcher =
request.getRequestDispatcher(forward.getPath());
dispatcher.forward(request, response);
}
}
- Controller 클래스에서는 포워딩 처리도 한다
- forward 객체는 한번 Service 클래스로 갔다오면 null 이 아니게 됨
- forward.isRedirect() 는 true, false 를 돌려줌, true면 redirect 방식 포워딩, false 면 diepacher 방식으로 포워딩 하기로 함
- getPath() 메소드로 포워딩할 페이지 불러오기
회원관리 프로그램 : 회원가입 기능
- 이제 잠시 Controller 클래스는 두고, 회원가입 기능을 먼저 구현하자
- 먼저 회원가입 폼 memberform.jsp 를 보자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 가입 폼</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://dmaps.daum.net/map_js_init/postcode.v2.js"></script>
<script>
function openDaumPostcode() {
new daum.Postcode({
oncomplete : function(data) {
// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
// 우편번호와 주소 정보를 해당 필드에 넣고, 커서를 상세주소 필드로 이동한다.
// document.getElementById('join_zip1').value = data.postcode1;
// document.getElementById('join_zip2').value = data.postcode2;
document.getElementById('post').value = data.zonecode;
document.getElementById('address').value = data.address;
}
}).open();
}
</script>
<!-- 외부 자바스크립트 파일 불러오기 -->
<script src="<%=request.getContextPath() %>/member/member.js"></script>
</head>
<body>
<form method="post" action="<%=request.getContextPath() %>/MemberInsert.do">
<table border=1 width=500 align=center>
<caption>회원 가입</caption>
<tr><td>ID</td>
<td><input type=text autofocus="autofocus" id="id" name="id">
<input type=button value="ID중복검사" id="idcheck">
<div id="myid"></div>
</td>
</tr>
<tr><td>비밀번호</td>
<td><input type=password id="passwd" name="passwd"></td>
</tr>
<tr><td>성명</td>
<td><input type=text id="name" name="name"></td>
</tr>
<tr><td>주민번호</td>
<td><input type=text size=6 maxlength=6 id="jumin1" name="jumin1">-
<input type=text size=7 maxlength=7 id="jumin2" name="jumin2">
</td>
</tr>
<tr><td>E-Mail</td>
<td><input type=text size=10 id="mailid" name="mailid">@
<input type=text size=10 id="domain" name="domain">
<select id="email">
<option value="">직접입력</option>
<option value="naver.com">네이버</option>
<option value="daum.net">다음</option>
<option value="nate.com">네이트</option>
<option value="gmail.com">gmail</option>
</select>
</td>
</tr>
<tr><td>전화번호</td>
<td><input type=text size=4 id="tel1" name="tel1" maxlength=4>-
<input type=text size=4 id="tel2" name="tel2" maxlength=4>-
<input type=text size=4 id="tel3" name="tel3" maxlength=4>
</td>
</tr>
<tr><td>핸드폰</td>
<td><select id="phone1" name="phone1">
<option value="">번호선택</option>
<option value="010">010</option>
<option value="011">011</option>
<option value="016">016</option>
<option value="018">018</option>
<option value="019">019</option>
</select>-
<input type=text size=4 id="phone2" name="phone2" maxlength=4>-
<input type=text size=4 id="phone3" name="phone3" maxlength=4>
</td>
</tr>
<tr><td>우편번호</td>
<td><input type=text size=5 id="post" name="post">
<input type=button value="우편번호검색"
onClick="openDaumPostcode()">
</td>
</tr>
<tr><td>주소</td>
<td><input type=text size=45 id="address" name="address"></td>
</tr>
<tr><td>성별</td>
<td>
<input type=radio id="male" name="gender" value="남자">남자
<input type=radio id="female" name="gender" value="여자">여자
</td>
</tr>
<tr><td>취미</td>
<td>
<input type="checkbox" id="h1" name="hobby" value="공부" checked>공부
<input type="checkbox" id="h2" name="hobby" value="게임">게임
<input type="checkbox" id="h3" name="hobby" value="등산">등산
<input type="checkbox" id="h4" name="hobby" value="낚시">낚시
<input type="checkbox" id="h5" name="hobby" value="쇼핑">쇼핑
</td>
</tr>
<tr><td>자기소개</td>
<td>
<textarea id="intro" name="intro" rows="5" cols="50" placeholder="자기소개를 100자 이내로 입력하세요"></textarea>
</td>
</tr>
<tr><td colspan=2 align=center>
<input type=submit value="회원가입">
<input type=reset value="취소">
</td>
</tr>
</table>
</form>
</body>
</html>
유효성 검사를 하는 자바스크립트 불러오기 경로 (memberform.jsp 부분)
<!-- 외부 자바스크립트 파일 불러오기 -->
<script src="<%=request.getContextPath() %>/member/member.js"></script>
- Controller 클래스에 의해 왔다갔다 하면 상대경로이기 때문에 이 경로를 잘 못찾아갈 수도 있다
- 이땐 위의 코드처럼 프로젝트명을 적고 나머지는 WebContent 폴더 기준으로 하위폴더를 모두 쓰고 파일명을 적기
+ request.getContextPath() 메소드는 프로젝트 명을 구해줌 ex) /model2member
form 의 action 태그 (memberform.jsp 부분)
<form method="post" action="<%=request.getContextPath() %>/MemberInsert.do">
- post 방식으로 입력양식의 값들을 전송한다
- model 2 에서는 파일이 아닌 무조건 Controller 클래스로 찾아가야한다, 프로젝트명을 앞에 붙이면 Controller 클래스를 잘 찾아감
- 배포가 되면 프로젝트가 URL 경로상에서 빠지므로 프로젝트명을 직접 적는 것이 아닌 request.getContextPath() 사용
회원관리 프로그램 : 회원가입 Service 클래스
- 실제 회원가입 요청을 처리하는 MemberInsert.java 파일을 만들자
- 회원가입 폼의 요청이름값과 동일하게 설정
- service 패키지에 MemberInsert.java 클래스 생성
package service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dao.MemberDAO;
import model.MemberDTO;
public class MemberInsert implements Action{
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("MeberInsert");
request.setCharacterEncoding("utf-8");
MemberDTO member = new MemberDTO();
member.setId(request.getParameter("id"));
member.setPasswd(request.getParameter("passwd"));
member.setName(request.getParameter("name"));
member.setJumin1(request.getParameter("jumin1"));
member.setJumin2(request.getParameter("jumin2"));
member.setMailid(request.getParameter("mailid"));
member.setDomain(request.getParameter("domain"));
member.setTel1(request.getParameter("tel1"));
member.setTel2(request.getParameter("tel2"));
member.setTel3(request.getParameter("tel3"));
member.setPhone1(request.getParameter("phone1"));
member.setPhone2(request.getParameter("phone2"));
member.setPhone3(request.getParameter("phone3"));
member.setPost(request.getParameter("post"));
member.setAddress(request.getParameter("address"));
member.setGender(request.getParameter("gender"));
String[] hobby = request.getParameterValues("hobby");
String h = "";
for(String h1 : hobby) {
h += h1 + "-"; // h = "공부-게임-"
}
member.setHobby(h);
member.setIntro(request.getParameter("intro"));
MemberDAO dao = MemberDAO.getInstance();
int result = dao.insert(member); // 회원가입
if(result == 1) System.out.println("회원가입 성공");
ActionForward forward = new ActionForward();
forward.setRedirect(false); // dispatcher 방식으로 포워딩
forward.setPath("./member/loginform.jsp"); // 포워딩할 파일명
return forward;
}
}
<회원가입 Service 클래스 형식, 전체적인 흐름>
- 부모 인터페이스인 Action 인터페이스를 상속받기, 이클립스 자동 기능으로 execute() 를 메소드 오버라이딩 하기
- request 객체는 Controller 클래스의 getPost() -> getProcess() -> Service 클래스의 execute() 로 넘어왔다
- 매개변수를 통해 Controller 클래스의 request 객체가 그대로 넘어왔으므로, 폼에서 Controller 클래스로 넘겨준 form 의 각종 입력양식의 값들을 여기 Service 클래스에서 request.getParamter() 로 가져올 수 있다
- 필드값을 설정한 ActionForward 객체를 execute() 를 호출한 Controller 클래스에 돌려줌
<회원가입 Service 클래스 작성 순서>
1. 먼저 post 방식으로 한글값이 넘어올 수 있으므로 한글값 인코딩을 설정한다
2. DTO 객체를 만들고 setter 메소드로 값을 세팅
- jsp 에서 useBean, setProperty 로 DTO 객체 생성하고 값을 세팅했던 코드에 해당함
- 이때 DTO 개체에 설정하는 값은 폼-> 컨트롤러-> 서비스 클래스로 넘어온 request 객체를 사용해서 request.getParamter() 로 폼 입력양식의 입력값을 가져와서 설정
- 취미는 2개이상 선택해야하는 양식이므로 값을 getParamterValues() 로 받고 여러개의 값을 하이픈으로 결합해서 저장
+ Spring 에선 일일히 값을 전달하지 않아도 어노테이션으로 한번에 처리 가능
3. DAO 객체를 생성하고 회원가입 insert 를 하는 DAO 의 insert() 메소드 호출
- 매개변수로 값을 설정한 DTO 객체를 넘긴다
- insert() 가 잘 수행되었으면 1 을 리턴한다
4. insert() 가 끝난다음엔 Service -> 다시 execute() 를 호출한 Controller 로 돌아가야한다
- 이때 Controller 로 ActionForward 객체를 리턴해야한다
- 리턴하기 전에 어떤 방식으로 포워딩할지, 어느 파일로 포워딩할지를 setRedirect(), setPath() 로 설정
- 지금은 request 객체로 공유를 설정하지 않았으므로 dispatcher, redirect 두개의 포워딩 방식 모두 사용 가능, 현재는 dispatcher 방식으로 포워딩하자
- setPath() 메소드 안에는 WebContent 폴더를 기준으로 하위 폴더를 쓰면서 포워딩할 파일명을 적어주기
- 회원가입이 끝나면 loginform 으로 갈 것이므로 loginform.jsp 로 포워딩하자
- 그 후 객체 forward 를 리턴하면서 Controller 클래스의 이곳으로 간다
- MemberController.java 부분
- 요청을 받을때는 forward == null 이므로 만족하지 않았던 포워딩 처리의 조건문
- 이번엔 객체를 돌려받으므로 forward !=null 이 되어 포워딩 처리함
5. 이후 DAO 클래스를 작성 해야함
콘솔창 확인
- memberform.jsp 에서 '회원가입' 클릭시
- 여태까지 회원가입 폼 -> Controller 클래스 -> MemberInsert Service 클래스까지 넘어왔음을 알 수 있음
- 다음으로 DAO 클래스에서 insert() 메소드를 작성하자
- DAO 클래스의 코드는 Model 1 와 거의 같다
DAO 클래스 회원가입 기능 메소드 작성
- MemberDAO.java 전체 코드는 모두 구현 후 올리기
- MemberDAO.java 추가된 insert() 부분 코드만
// 회원가입
public int insert(MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "insert into member2 ";
sql += "values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,sysdate)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getId());
pstmt.setString(2, member.getPasswd());
pstmt.setString(3, member.getName());
pstmt.setString(4, member.getJumin1());
pstmt.setString(5, member.getJumin2());
pstmt.setString(6, member.getMailid());
pstmt.setString(7, member.getDomain());
pstmt.setString(8, member.getTel1());
pstmt.setString(9, member.getTel2());
pstmt.setString(10, member.getTel3());
pstmt.setString(11, member.getPhone1());
pstmt.setString(12, member.getPhone2());
pstmt.setString(13, member.getPhone3());
pstmt.setString(14, member.getPost());
pstmt.setString(15, member.getAddress());
pstmt.setString(16, member.getGender());
pstmt.setString(17, member.getHobby());
pstmt.setString(18, member.getIntro());
result = pstmt.executeUpdate(); // SQL문 실행
} catch(Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
- Model 1 에서 DAO의 insert() 메소드를 작성했던 것과 같은 방식으로 작성하면 된다
- Model1 DAO 회원가입 insert() 메소드 설명 : https://laker99.tistory.com/114?category=1080281
다음 흐름
- DB 에 insert 수행 후 DAO -> Service 클래스(MemberInsert.java) 로 간다
- Service 클래스에서 forward 객체를 생성 후 어디로 포워딩 할지, 어떻게 포워딩 할지 값만 설정한 후 forward 객체 리턴
- Service 클래스의 execute() 메소드를 호출한 Controller 클래스로 돌아가서 실제 포워딩을 수행한다
- Controller 클래스의 이곳으로 다시 돌아간다
- Controller 클래의 객체 forward 가 execute() 에서 리턴으로 ActionForward 객체를 받았으므로 더이상 fowrad 는 null 이 아님
- 처음에는 null 이었기에 실행되지 않았던 포워딩 코드를 이제는 null 이 아니므로 실행함
- getPath() 로 포워딩할 페이지를 불러와서 dispatcher 방식 또는 redirect 방식으로 포워딩 하면 된다
- 여기서는 dispatcher 방식으로 포워딩 했다
실행 캡처
- 먼저 memberform.jsp 회원가입 폼에서 회원가입 시키자
- 회원가입을 하면 로그인 페이지로 포워딩 된다, dispacher 방식 포워딩이므로 URL 변화 없음
- sql 파일에서 DB insert 되었는지 확인
- 삽입되었음을 확인 가능
- 콘솔창 보기
- Controller 클래스("post" 출력) -> Service 클래스("MemberInsert" 출력) -> DAO 클래스에서 DB에 삽입 -> Service 클래스("회원가입 성공" 출력) -> Controller 클래스 -> loginform.jsp 포워딩 을 콘솔창에서 찍혀진 결과로 확인 가능
회원관리 프로그램 : ID 중복검사
- memberform.jsp 파일을 보면
- 비동기적으로 입력창 아래에 사용 가능한 ID 메세지 띄우기
- Ajax는 만들어져 있으므로 저렇게 글자는 뜬다
- 해당 서비스 클래스를 만들어야 실제로 ID중복검사를 하고, 제대로 동작한다
- 이제 member.js 파일에서 Ajax 로 비동기적으로 서버창에 요청하는 코드를 보자
- Idcheck.do 로 요청한다, Controller 클래스로 찾아가서 doPost() 가 실행됨, 이때 URL 에는 /Idcheck.do 가 찍힌다
- 'ID중복검사' 버튼 클릭시 요청 이름값인 Idcheck.do 가 콘솔창에 나온다
- 요청을 했고 그 요청이 Controller 클래스까지 갔다는 의미이다
- 이제 요청을 실제로 처리하는 Service 클래스를 만들어야한다
회원관리 프로그램 : ID중복검사 Service 클래스
- 실제 ID중복검사 요청을 처리하는 Idcheck.java 파일을 만들자
- 회원가입 폼의 요청이름값과 동일하게 설정
- service 패키지에 IdCheck.java 클래스 생성
- IdCheck.java
package service;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dao.MemberDAO;
public class IdCheck implements Action{
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
System.out.println("IdCheck");
// 출력 스트림 객체 생성
PrintWriter out = response.getWriter();
String id = request.getParameter("id");
System.out.println("id:" + id);
MemberDAO dao = MemberDAO.getInstance();
int result = dao.idcheck(); // ID중복검사
System.out.println("result:" + result); // 1 : 중복 ID //-1 : 사용 가능한 ID
// 웹브라우저에 출력되는 값이 callback 함수로 리턴됨
out.println(result);
return null;
}
}
* 아래의 Controller 클래스에서 이 Service 클래스로 가는 코드를 먼저 작성 한 후 다시 이 코드로 돌아와 작성했다
- 먼저 Action 인터페이스를 상속하고 execute() 메소드 오버라이딩
- 지금은 비동기로 처리하므로 Controller 클래스로 돌아가지 않는다! 그래서 return null을 함
- 돌아갈때 member.js 로 돌아가야한다, 이때 브라우저에 출력되는 값이 callback 함수로 리턴되므로 1 또는 -1 이 돌아감
- member.js 에서 요청되면서 넘어온 값을 request.getParamter("id") 로 받는다
- DAO 객체 생성해서 메소드 idcheck() 호출하며 사용자의 id 를 넘기기, 중복이면 1 리턴, 사용가능한 아이디면 -1 리턴
- 브라우저에 출력되는 값이 콜백함수로 리턴되므로, 이 IdCheck.java 에서 출력해야함, 출력위해 out 객체 생성
- out 객체로 DAO 의 idcheck() 에서 돌려받은 값 result 를 출력, 그럼 member.js 에서 data 로 돌려받음
+ Model 2 에선 JSP 의 내장객체 없다, request, response 만 받아서 사용 가능하고 나머지 객체는 직접 만들어야함
- 다음은 다시 Controller 클래스로 돌아가서 ID중복검사에서 요청이 올경우 IdCheck.java Service 클래스로 보내주는 코드 작성
Controller 클래스에서 ID 중복검사 Service 클래스로 가기
- MemberController.java 전체 코드는 나중에
- MemberController.java 부분
// ID중복 검사 (ajax)
} else if (command.equals("/Idcheck.do")) {
try {
action = new IdCheck();
forward = action.execute(request, response);
}
catch (Exception e){
e.printStackTrace();
}
}
- IdCheck() 클래스로 객체 생성하고, 그 객체에서 execute() 실행하기
- 이 코드 작성 후 회원가입 폼에서 'ID중복검사' 버튼 클릭시 콘솔창 확인하면
- IdCheck 가 찍히는 걸 보아, 요청하는 곳 -> Controller -> Service 클래스까지 잘 도착했음을 확인 가능
- id: lay99 이 찍히는 걸 보아, Ajax로 요청하면서 넘어온 값이 Service 클래스에서 잘 받았음을 확인 가능
- 이제 DAO 클래스에 ID중복검사를 하기 위한 메소드 idcheck() 작성하기
DAO 클래스 ID중복검사 메소드 작성
- MemberDAO.java 전체 코드는 모두 구현 후 올리기
- MemberDAO.java 추가된 idchcek() 부분 코드만
- MemberDAO.java (추가)
// ID중복 검사 (ajax)
public int idcheck(String id) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from member2 where id = ?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
result = 1; // 중복 ID
} else {
result = -1; // 사용 가능한 ID
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
- select 문이므로 ResultSet 객체도 생성
- select SQL문 실행 후 rs.next 가 true 인 경우엔 DB 에 중복아이디가 있다는 의미이다
- 중복 ID 면 1 을 리턴, 사용 가능한 ID 면 -1 을 Service 클래스 IdCheck.java 로 돌아가며 리턴
- memberform.jsp 를 실행해서 ID중복검사 를 해보자
- 이미 가입된 ID 입력시
- 콘솔창 확인
- Service 클래스에서 DAO 로 부터 받은 값을 Service 클래스에서 result 로 받아 출력하고 있다, 중복 ID 이므로 1 이 출력
- 가입되지 않은 ID 입력시
- 콘솔창 확인
- Service 클래스에서 DAO 로 부터 받은 값을 Service 클래스에서 result 로 받아 출력하고 있다, 사용 가능한 ID 이므로 -1 이 출력
회원관리 프로그램 : 로그인 기능
- 이제 로그인 기능을 구현하자
- 먼저 로그인 폼인 loginform.jsp 파일을 보자
- loginform.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 폼</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!-- 외부 자바스크립트 파일 불러오기 -->
<script src="<%=request.getContextPath() %>/member/login.js"></script>
</head>
<body>
<form method="post" action="<%=request.getContextPath() %>/Login.do">
<table border=1 width=350 align=center>
<caption>로그인</caption>
<tr>
<td>ID</td>
<td><input type=text size=30 id="id" name="id" autofocus="autofocus"></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" size=30 id="passwd" name="passwd"></td>
</tr>
<tr>
<td colspan=2 align=center>
<input type="button" value="회원가입"
onClick="location.href='<%=request.getContextPath()%>/MemberForm.do' ">
<input type="submit" value="로그인">
<input type="reset" value="취소">
</td>
</tr>
</table>
</form>
</body>
</html>
- 외부 자바스크립트 파일을 불러올때 request.getContext() 로 프로젝트명을 구하고. WebContent 기준 하위 폴더와 파일명 적기
+ '로그인' 버튼만 submit 버튼으로서 클릭시 입력된 값을 post 방식으로 전송, Controller 클래스로 간다
'회원가입' 으로 넘어갈때 주의
- '회원가입' 을 클릭시 바로 memberform.jsp 로 가는 것이 아님
- Model 2 이기 때문에 Controller 클래스를 갔다가 다시 가입 폼 (View)으로 가야함
- '회원가입' 클릭시 Controller 클래스로 먼저 가기 위해 memberform.jsp 대신 MemberForm.do 로 do 확장자로 요청해서 어노테이션으로 Controller 클래스로 찾아가게함
- Controller 클래스의 doGet() 메소드가 실행됨
- 로그인폼에서 '회원가입' 클릭시 콘솔창
- Controller 클래스로 간것을 확인 가능, 요청 이름값은 MemberForm.do
- Controller 클래스에서 MemberForm.do 로 요청이 올때 어떻게 처리할지를 작성해야한다
Controller 클래스에서 회원가입 폼으로 가기
- MemberController.java 전체 코드는 나중에
- MemberController.java 부분
- MemberForm.do 로 요청이 올때의 경우를 처리
// 회원가입 폼
} else if (command.equals("/MemberForm.do")){
forward = new ActionForward();
forward.setRedirect(false);
forward.setPath("./member/memberform.jsp");
}
- DB 연동을 하는 경우가 아니므로 Service 클래스로 가지 않고 바로 회원가입 폼으로 가면 된다
- 바로 forward 객체를 생성하고 setRedirect(), setPath() 로 값을 설정해줌, 원래 이 작업은 Service 클래스 하단에서 해주는 거지만 여기선 Service 클래스로 가지 않으므로 여기서 값 설정
- 여기서 forward 객체는 null 이 아니게 되므로 아래의 코드인 포워딩 코드에서 포워딩되어 회원가입폼으로 간다
+ 모두 Service 클래스로 가는 것이 아님, DB연동 없으면 Service 클래스로 넘어가지 않는다
- 지금까지 로그인 폼에서 '회원가입' 클릭시 회원가입 폼으로 넘어가도록 처리함
- 이제 진짜 로그인 기능을 구현하자
- loginform.jsp 에서 아이디, 비밀번호 입력 후 '로그인' 클릭 시 콘솔창
- Controller 클래스가서 doPost() 를 실행했음을 알 수 있다.
앞으로 해야할 일
1. Service 클래스 명도 맞추서 Login.java 파일로 하자
2. Controller 클래스에서 "/Login.do" 인 경우를 Login.java 로 보내는 것을 처리하자
3. Service 와 DAO 부분 구현
- 로그인 기능 Service 클래스인 Login.java 파일 생성부터 하자
회원관리 프로그램 : 로그인 Service 클래스
- 실제 로그인 요청을 처리하는 Login.java 파일을 만들자
- 로그인 폼의 요청이름값과 동일하게 설정
- service 패키지에 Login.java 클래스 생성
- Login.java (수정 전, 한글 인코딩 전, 한글 인코딩 빼고는 다 작성함)
package service;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import dao.MemberDAO;
public class Login implements Action{
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
System.out.println("Login");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
String id = request.getParameter("id");
String passwd = request.getParameter("passwd");
MemberDAO dao = MemberDAO.getInstance();
int result = dao.memberAuth(id, passwd); // 회원인증
if(result == 1) System.out.println("회원인증 성공");
if(result == 1) { // 회원인증 성공
session.setAttribute("id", id);
} else { // 회원인증 실패
out.println("<script>");
out.println("alert('로그인 실패');");
out.println("history.go(-1);");
out.println("</script>");
out.close();
return null;
}
ActionForward forward = new ActionForward();
forward.setRedirect(false); // dispatcher 방식으로 포워딩
forward.setPath("./member/main.jsp");
return forward;
}
}
<로그인 Service 클래스 형식, 전체적인 흐름>
- 부모 인터페이스인 Action 인터페이스를 상속받기, 이클립스 자동 기능으로 execute() 를 메소드 오버라이딩 하기
- request 객체는 Controller 클래스의 getPost() -> getProcess() -> Service 클래스의 execute() 로 넘어왔다
- 매개변수를 통해 Controller 클래스의 request 객체가 그대로 넘어왔으므로, 폼에서 Controller 클래스로 넘겨준 form 의 각종 입력양식의 값들을 여기 Service 클래스에서 request.getParamter() 로 가져올 수 있다
- 필드값을 설정한 ActionForward 객체를 execute() 를 호출한 Controller 클래스에 돌려줌
<로그인 Service 클래스 작성 순서>
1. 먼저 post 방식으로 한글값이 넘어올 수 있으므로 한글값 인코딩을 설정한다
2. 회원 인증 성공시 공유설정을 해야하므로 session 객체 생성, out 객체도 생성해주자
3. 로그인 폼에서 전달한 id, passwd 를 받아온다
- 다음으로는 이 id, passwd 와 DB의 id, passwd 가 같으면 공유설정해야함
4. DAO 객체를 생성하고 회원 인증 select 를 하는 DAO 의 memberAuth() 메소드 호출
- 매개변수로는 id, passwd 를 전달
- 회원 인증에 성공시 결과값을 1로 받기로 하자
5. 회원 인증 성공시 "id" 를 네임값으로 회원의 id 를 공유 설정을 한다
- 파일을 계속 넘어가도 session 값은 유지됨
6. 회원 인증 실패시 out 객체를 통해 실패 메세지를 뿌린다
- 실패시 알림창을 띄우고 이전 페이지로 돌아간다
- return null 이 없으면 콘솔창에 에러가 뜬다, return null 을 통해 이 메소드를 완전히 빠져나가며 아래 내용 실행 안함
- out 객체를 닫아줌
- 회원 인증 성공시, return null 로 빠져나가지 않고 아래 코드가 실행됨
7. 회원 인증 성공시 Service -> 다시 execute() 를 호출한 Controller 로 돌아가야한다
- 이때 Controller 로 ActionForward 객체를 리턴해야한다, ActionForward 객체 forward 생성
- 리턴하기 전에 어떤 방식으로 포워딩할지, 어느 파일로 포워딩할지를 setRedirect(), setPath() 로 설정
- 지금은 request 객체로 공유를 설정하지 않았으므로 dispatcher, redirect 두개의 포워딩 방식 모두 사용 가능, 현재는 dispatcher 방식으로 포워딩하자
- setPath() 메소드 안에는 WebContent 폴더를 기준으로 하위 폴더를 쓰면서 포워딩할 파일명을 적어주기
- 회원가입이 끝나면 main 페이지로 갈 것이므로 main.jsp 로 포워딩하자
8. 이후 DAO 클래스를 작성 해야함
+ out 객체와 session 객체 만들기
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
- DAO 클래스로 가서 회원 인증 (로그인) 을 해주는 memberAuth() 메소드를 작성하자
DAO 클래스 회원인증 (로그인) 기능 메소드 작성
- MemberDAO.java 전체 코드는 모두 구현 후 올리기
- MemberDAO.java 추가된 memberAuth() 부분 코드만
// 로그인 (회원인증)
public int memberAuth(String id, String passwd) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from member2 where id = ? and passwd=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
pstmt.setString(2, passwd);
rs = pstmt.executeQuery(); //SQL문 실행
if(rs.next()) { // 회원인증 성공
result = 1;
} else { // 회원인증 실패
result = -1;
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
- select * from member2 where id =? and passwd = ? 에서 결과를 가져온다는 것은 아이디, 비번이 모두 일치하는 결과가 있다는 의미
- 회원 인증 성공시 1 리턴, 실패시 -1 리턴
- 이후 이 메소드를 호출한 Service 클래스로 이동 -> Controller 클래스로 이동 -> main.jsp 로 포워딩하게 된다
- Service 클래스 -> Controller 클래스로 갈때 forward 객체를 리턴했음
- Controller 클래스에서 main.jsp 로 포워딩 한다
- 아직 Controller 클래스에서 "/Login.do" 가 요청이름값일때의 Login.java 로 보내는 처리를 하지 않았음
- Controller 클래스에서 Service 클래스로 연결하는 것은
Controller 클래스에서 로그인 Service 클래스로 가기
- MemberController.java 전체 코드는 나중에
- MemberController.java 부분
- Login.do 로 요청이 올때의 경우를 처리
// 로그인 (회원 인증)
} else if(command.equals("/Login.do")) {
try {
action = new Login();
forward = action.execute(request, response);
}
catch (Exception e){
e.printStackTrace();
}
}
- 이제 모든게 연결되었으므로 loginform.jsp 에서 로그인을 시도해보자
- 맞는 비밀번호 입력시
- 아직 main.jsp 가 만들어지지 않았으므로 오류 발생
- 콘솔창을 보면 로그인 폼 -> Controller 클래스("post" 출력) -> Service 클래스("Login" 출력) -> DAO 에서 DB 연결 -> Service 클래스("회원가입 성공" 출력) -> Controller 클래스 -> main.jsp 로 포워딩 잘 되었음을 확인 가능
- 틀린 비밀번호 입력시
- 로그인 실패 라는 메세지 대신 깨진 한글값이 나온다
깨진 한글값 문제 처리
- Login.java 파일에서 회원가입 실패시 출력하는 메세지가 한글이 깨져서 나타난다
- 위에서 "한글값" 을 인코딩하는 setCharacterEncoding("utf-8") 은 있지만 현재 문서의 한글 인코딩은 안했다
- 그래서 alert 로 출력되는 한글이 깨졌던 것
- JSP 에서는 자동으로 생성되었던 현재 문서의 한글을 인코딩하는 코드
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
- 이 코드를 JSP 가 아니라 Java 클래스 내에서 JAVA 에 맞게 작성해야함
response.setContentType("text/html; charset=utf-8");
- 이 한줄을 Login.java 에 추가해야함
+ 이 코드는 한글값 인코딩, 한글 문서 인코딩과 관련없다
request.setCharacterEncoding("utf-8");
- Login.java (수정 후, 한글 인코딩 완료)
package service;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import dao.MemberDAO;
public class Login implements Action{
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
System.out.println("Login");
response.setContentType("text/html; charset=utf-8");
request.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
String id = request.getParameter("id");
String passwd = request.getParameter("passwd");
MemberDAO dao = MemberDAO.getInstance();
int result = dao.memberAuth(id, passwd); // 회원인증
if(result == 1) System.out.println("회원인증 성공");
if(result == 1) { // 회원인증 성공
session.setAttribute("id", id);
} else { // 회원인증 실패
out.println("<script>");
out.println("alert('로그인 실패');");
out.println("history.go(-1);");
out.println("</script>");
out.close();
return null;
}
ActionForward forward = new ActionForward();
forward.setRedirect(false); // dispatcher 방식으로 포워딩
forward.setPath("./member/main.jsp");
return forward;
}
}
- 다시 loginform.jsp 를 실행하고 틀린 아이디나 비밀번호를 입력 후 '로그인' 을 클릭하자
- 문서의 한글 인코딩이 잘 처리 되었다!
- 맞는 비밀번호를 입력했을때도 한글이 깨지는 문제 해결됨
- main.jsp 파일이 아직 생성되지 않아서 아직 404 에러가 뜬다
중간 정리
+ 현재 공유된 값 : 로그인 성공시 session 으로 공유된 id 값
- 그래도 main.jsp 로 포워딩하는 것까지 Controller 클래스에서 다 처리했다
- Service 클래스를 거쳐서 돌아올때는 forward 객체가 null 이 아니므로 조건식을 만족해서 포워딩함
- session 으로 공유를 설정할때는 어느 방식으로 포워딩해도 상관없다
- 지금 로그인 페이지는 session 으로만 공유설정했으므로 상관없음, 나중에 request 객체로 공유 설정시에는 Dispatcher 방식으로 포워딩 해야함
- main.jsp 파일에서는 세션 유무에 따라 보이는 화면이 달라진다
회원관리 프로그램 : 중간 페이지 main.jsp
세션 유무(로그인 성공 유무) 에 따라 다른 화면 보여주기
- WebContent/member 폴더 하위에 main.jsp 파일 생성 및 작성
- main.jsp (수정 전 1)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 세션이 있는 경우 -->
<c:if test="${sessionScope.id != null }">
${sessionScope.id} 님 환영 합니다. <br><br>
회원정보 수정 <br>
로그아웃 <br>
회원탈퇴 <br>
</c:if>
<!-- 세션이 없는 경우 -->
<c:if test="${sessionScope.id == null}">
회원가입 <br>
로그인 <br>
</c:if>
- EL / JSTL 사용하기
- JSTL 코어 라이브러리를 불러온다
- main.jsp 파일에서는 세션 유무에 따라 보이는 화면이 달라진다
- session 값이 있는경우, 없는 경우 두가지 경우로 나눠서 처리, JSTL 의 if 태그 사용
- 조건식은 EL 로 만들고 sessionScope 내장객체를 사용함, sessionScope.id 는 session 으로 공유된 네임 "id" 의 값 의미
- 세션 값이 있을때 (즉, 로그인 (회원인증) 하고 main.jsp 로 왔을때)
- 세션 값이 없을때 (바로 main.jsp 를 그냥 실행했을때)
- 이제 세션이 없는 경우 나타나는 텍스트인 '회원가입' 과 '로그인' 에 링크걸기
- main.jsp (수정 전 2)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 세션이 있는 경우 -->
<c:if test="${sessionScope.id != null }">
${sessionScope.id} 님 환영 합니다. <br><br>
회원정보 수정 <br>
로그아웃 <br>
회원탈퇴 <br>
</c:if>
<!-- 세션이 없는 경우 -->
<c:if test="${sessionScope.id == null}">
<a href="<%=request.getContextPath() %>/MemberForm.do">회원가입 </a> <br>
<a href="<%=request.getContextPath() %>/LoginForm.do">로그인 </a> <br>
</c:if>
<회원가입 링크>
- href = "./MemberForm.do" 만을 설정시 못 찾아간다
- 앞에 프로젝트 명을 붙여서 이동시켜줘야함
- 콘솔창
<로그인 링크>
- 아직 Controller 클래스에 로그인 폼으로 넘겨주는 코드는 없다
- 요청이름값을 "LoginForm.do" 로 하자
- LoginForm.do 로 요청 했으므로 Controller 클래스로 찾아가긴 했다
- 마찬가지로 프로젝트 명을 앞에 써주기 위해 request.getContextPath() 사용
- Controller 클래스에서 /LoginForm.do 로 올때를 처리해주기
- 폼이 아니므로 무조건 Get 방식으로 전달한다,
- 콘솔창
- command 변수에 요청 이름값이 저장되어있다
- Controller 클래스에서 command 가 LoginForm.do 일때 로그인 폼으로 가는 코드를 작성
Controller 클래스에서 로그인 폼으로 가기
- MemberController.java 전체 코드는 나중에
- MemberController.java 부분
- LoginForm.do 로 요청이 올때의 경우를 처리
// 로그인 폼
} else if(command.equals("/LoginForm.do")) {
forward = new ActionForward();
forward.setRedirect(false);
forward.setPath("./member/loginform.jsp");
}
- 지금은 DB연동을 안하므로 Service 클래스로 갈 필요 없다
- 회원가입 폼으로 가는 것과 마찬가지로 처리한다
- ActionForward 객체 forward 를 생성후 바로 값을 세팅해줌
- View 페이지는 member 폴더 하위 loginform.jsp 이다
- dispatcher 방식으로 포워딩 한다
- 그 후에 아래의 포워딩 코드에서 forward != null 을 만족하므로 포워딩한다
- main.jsp 실행 후 '로그인' 누르기
+ 세션값이 없으므로 아래 화면이 뜬다
- 로그인 포믕로 잘 이동했음을 확인 가능
Model 1 vs Model 2
- Model 1 에서는 Loginform.jsp 로 바로 갈 수 있다
- Model 2 에서는 Controller 로 갔다가 다시 View (Loginform.jsp) 로 가도록 설정해야한다
- 다시 main.jsp 를 보자
- sessionScope.id 는 EL 내장객체, session.getAttribute("id") 를 대신한다
- sessionScope.id 대신 다른 방법이 있다, empty 연산자
- 위의 if 조건식을 empty 연산자로 바꿔서 처리해보자
empty 연산자
- '비어있는지', '없는지' 를 묻는 EL연산자
- 비어있으면 true, 비어있지 않으면 false 값이 된다
empty 연산자 코드로 바꾸기 1
- main.jsp 의 '세션이 있는 경우' if 태그 코드를 empty 연산자 코드로 바꾸기
<!-- 세션이 있는 경우 -->
<c:if test="${sessionScope.id != null }">
- 아래 코드로 바꿀 수 있다
<!-- 세션이 있는 경우 -->
<c:if test="${!empty sessionScope.id }">
- empty 연산자는 없으면 true 이므로 세션이 있는 경우는 ! 를 앞에 붙여야함
- empty 연산자는 == null 과 같은 의미, '없으면' 의 의미이다
empty 연산자 코드로 바꾸기2
- 마찬가지로 main.jsp 의 '세션이 없는 경우' if 태그 아래 코드는 이렇게 바꾼다
<!-- 세션이 없는 경우 -->
<c:if test="${sessionScope.id == null}">
- 아래코드로 바꾼다
<!-- 세션이 없는 경우 -->
<c:if test="${empty sessionScope.id }">
- 또한 이렇게 sessionScope 를 빼고 id 만 적어도 똑같이 처리된다
<!-- 세션이 없는 경우 -->
<c:if test="${empty id }">
- 똑같이 처리된다
- sessionScope 를 적는게 원칙이지만 빼도 처리된다
- main.jsp (수정 전 3)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 세션이 있는 경우 -->
<c:if test="${!empty sessionScope.id }">
<%-- <c:if test="${sessionScope.id != null }"> --%>
${sessionScope.id} 님 환영 합니다. <br><br>
회원정보 수정 <br>
로그아웃 <br>
회원탈퇴 <br>
</c:if>
<!-- 세션이 없는 경우 -->
<c:if test="${empty sessionScope.id }">
<%-- <c:if test="${sessionScope.id == null}"> --%>
<a href="<%=request.getContextPath() %>/MemberForm.do">회원가입 </a> <br>
<a href="<%=request.getContextPath() %>/LoginForm.do">로그인 </a> <br>
</c:if>
회원관리 프로그램 : 로그아웃
- main.jsp 세션있는 경우에서 나타나는 차에서 '로그아웃' 을 눌렀을때 로그아웃을 수행하는 기능을 만들자
- main.jsp 에서 링크를 연결하자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 세션이 있는 경우 -->
<c:if test="${!empty sessionScope.id }">
<%-- <c:if test="${sessionScope.id != null }"> --%>
${sessionScope.id} 님 환영 합니다. <br><br>
회원정보 수정 <br>
<a href="./Logout.do">로그아웃</a> <br>
회원탈퇴 <br>
</c:if>
<!-- 세션이 없는 경우 -->
<c:if test="${empty sessionScope.id }">
<%-- <c:if test="${sessionScope.id == null}"> --%>
<a href="<%=request.getContextPath() %>/MemberForm.do">회원가입 </a> <br>
<a href="<%=request.getContextPath() %>/LoginForm.do">로그인 </a> <br>
</c:if>
- 수정한 부분 코드만 캡처
- 요청 이름값은 "/Logout.do" 로 하자
- 로그아웃 처리는 DB연동을 안하므로 Service 클래스로 갈 필요 없음
- 로그인 하고 main.jsp 로 와서 '로그아웃' 을 눌러보자
- command 에 요청 이름값 "/Logout.do" 이 출력되고 있다
- Controller 클래스의 doGet(), doProcess() 메소드 안까지 잘 찾아 간 것
- Controller 클래스로 가서 요청이 "/Logout.do" 로 온 경우에 View 페이지로 넘겨주는 처리를 하자
Controller 클래스에서 회원가입 폼으로 가기
- MemberController.java 전체 코드는 나중에
- MemberController.java 부분
- Logout.do 로 요청이 올때의 경우를 처리
// 로그아웃
} else if(command.equals("/Logout.do")) {
forward = new ActionForward();
forward.setRedirect(false);
forward.setPath("./member/logout.jsp");
}
- 지금은 DB연동 안하므로 Service 클래스 갈 필요 없다
- 로그아웃 View 페이지인 logout.jsp 로 보내주기만 하면 된다.
- 그래서 회원가입 폼으로 갈 때와 비슷하게 처리한다
- ActionForward 객체 forward 를 생성하고 바로 값을 설정함
- 이제 member 폴더 하위에 logout.jsp 파일을 생성하자
- logout.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 세션 삭제
session.invalidate();
%>
<script>
alert("로그 아웃");
location.href="./LoginForm.do"
</script>
logout.jsp 에서 해야할 일
1. session 삭제
- 브라우저 창이 닫히지 않아도 강제로 session 끊기
- session.invalidate() 메소드 사용
2. 로그아웃 되었다는 메세지를 뿌린 후 다시 로그인 폼으로 가기(포워딩)
- 로그인 폼으로 가는 요청이름인 "/LoginForm" 을 사용해서 로그인 폼으로 간다
- 로그인 폼에서 로그인 한 후 main.jsp 에서 '로그아웃' 클릭하자
- 로그인 폼으로 잘 넘어간다.
- Controller 클래스에서 View 페이지로 포워딩되었다
+ 그 상태에서 main.jsp 실행시 이 화면이 뜨는걸 보아 세션이 삭제되었다
- 콘솔창
- 로그아웃 기능 구현 완료
다음에 만들 Model 2 게시판 프로그램
- 이후에 만들 프로그램
- request 객체로 공유를 많이 한다
- lib 폴더에 라이브러리를 저장하는 대신 maven 을 사용한다