일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- union #sql99 #외부조인 #오라클조인 #sql조인 #자체조인 #비등가조인 #비등가조인 #테이블복사 #오라클테이블 #null인데이터출력
- 서블릿 #자바모델1 #자바모델2 #mvc #mvc패턴
- Doit #Doit오라클 #Doit시리즈 #연습문제
- 방통대 #방송통신대학교 #컴퓨터과학 #컴퓨터과학과 #컴과 #방통대컴퓨터과학과 #방통대컴과 #방통대파이썬 #방통대C #방통대자바
- spring #스프링 #전자정부표준프레임워크 #표준프레임워크 #자바스프링 #스프링다운로드 #자바스크립트 #웹프로그래밍설정 #웹프로그래밍셋팅
- Init-param #context-param #
- tern다운로드 #메이븐다운로드 #maven #스프링라이브러리 #자바라이브러리 #톰캣설정 #WAS #웹어플리케이션서버
- 서블릿선언 #서블릿선언방법 #
- 자바 #웹자바 #webJava #java #코딩 #코딩초보 #ojdbc #서블릿 #자바서블릿 #javaServelet #servelet #httpServlet
- cos.jar #cos드라이버 #파일업로드드라이버 #루피는귀여워 #마이바티스 #MyBatis #마이바티스sql #마이바티스DB #마이바티스jsp #마이바티스이클립스 #mapper #config.xml #마이바티스다운로드
- 어노테이션 #@WebServlet #WebServlet #
- 기말고사 #방통대기말고사 #방통대후기 #방통대기말고사후기 #방통대2023년1학기 #방통대1학기 #방통대C프로그래밍 #방통대장학금 #방통대영어회화1
- java #array #자바 #배열 #프로그래밍 #코딩 #자바프로그래밍
- 정처기3회 #정보처리기사2023
- Model #
- jsp #게시판만들기 #자바로게시판만들기 #웹테스트 #JNDI #myora #Oracle #오라클 #DAO #DTO #아파치톰캣 #웹자바셋팅 #모델1 #모델1방식 #모델1방식웹프로그래밍 #웹프로그래밍
- 자바 #웹자바 #JAVA #WEB #WEBJAVA #WEBPROGRAMMING #웹 #웹프로그래밍 #코딩 #CODING #모델1 #모델2 #모델1방식 #모델2방식
- 정처기필기합격 #정처기합격후기
- 자바웹프로그래밍
- QUERY #DML #SQL문 #내림차순정렬 #오름차순정렬
- 8 실무에서 가장 많이 사용하는 SQL
- Controller
- html #자바와서블릿 #자바와웹연결 #웹연결
- 갤러리제작 #갤러리만들기 #jsp갤러리 #jsp게시판 #jsp프로그래밍 #jsp웹프로그래밍 #jsp웹 #jsp모델1방식 #사진업로드 #jsp사진업로드 #jdbc6 #jdbc드라이버다운 #jdbc드라이버무료다운
- 정처기 #정처기필기 #정보처리기사 #정보처리기사필기 #정보처리기사2023 #정처기2023 #정처기3회 #정보처리기사3회 #정보처리기사실기 #정처기실기 정처기합격
- sql #오라클 #불리언형 #boolean #webjava #java #jsp #Mybatis #마이바티스 #마이바티스환경설정 #모델1 #모델1프로그래밍 #Batis #마이바티스다운로드 #web설정 #웹프로그래밍 #게시판 #게시판제작 #게시판만
- View #
- 마이바티스환경설정
- ORACLE #TIGER #SCOTT #SCOTT계정 #오라클학습계정 #프로그래밍 #SQL #SQLORACLE #오라클 #오라클연습 #오라클연습계정 #오라클연습문제 #WHERE절 #오라클조건절
- web.xml #배포지시자 #서블릿테스트
- Today
- Total
장미의 개발일기
모델2 방식 웹 개발하기 (MVC 패턴) : 회원가입 파트 제작해보기 본문
- 코드 결합도 낮추기 : 액션 팩토리 패턴 +팩토리 서비스
-셋팅: 이클립스 EE + 톰캣 + 마이바티스 +오라클 + SQL gate 사용
-모델1방식과 모델2 방식+mvc패턴 비교 포스팅:
JSP 개발방식 모델1 과 모델2 방식 비교 + MVC 패턴 (tistory.com)
JSP 개발방식 모델1 과 모델2 방식 비교 + MVC 패턴
*MVC 패턴 (스프링 프레임워크)* Model : 비즈니스 로직과 데이터를 처리 View : 사용자 인터페이스 (웹 브라우저에 보이는 페이지) Controller : 요청과 응답을 처리하며, model과 view 사이의 상호작용을
jangmicoding.tistory.com
- 마이바티스 셋팅 포스팅:
Mybatis 마이바티스 다운로드 및 환경 설정 (tistory.com)
Mybatis 마이바티스 다운로드 및 환경 설정
** 아래 포스팅의 예제 => model 1 타입의 게시판 사이트를 제작한 후, 그걸 복사해와서 마이바티스를 테스트 해보는 포스팅 입니다. ** 아래 모델1방식으로 웹 게시판 만들기 JSP 프로그래밍: 모델1
jangmicoding.tistory.com
controller 패키지 생성 후 ,
1. ActionForward class 생성 -> setter/getter 적용하기
-모델의 인터페이스에 들어갈 ActionForward :
ActionForward: 모델이 수행하고 난 후 이동할 View의 정보와 이동 방식을 저장한 후,
모델이 수행한 후 반환되는 객체다. (원래는 컨트롤러로 지정된 클래스에서 뷰를 반환하도록
설계하지만, 이해를 돕기 위해 분리해서 제작)
쉽게 말해서 ActionForward는 (뷰 = 클라이언트 화면에 보이는 화면 )~.jsp 파일들을 보여주기 위한 수단으로 생각하면 된다.
package controller;
public class ActionForward {
private String url; // 모델이 실행한 후 이동할 viewName
private boolean method; // 모델이 실행한 후 이동할 이동 방식
public ActionForward() {
}
public ActionForward(String url, boolean method) {
this.url = url;
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isMethod() {
return method;
}
public void setMethod(boolean method) {
this.method = method;
}
}
action 패키지 생성 후
2. Action Interface 생성 (다형성을 적용하기 위함)
:모델이 수행하고 난 후 ActionForward에 해당 정보를 저장한 후,
Controller에 의해서 사용될 값을 반환하는 추상메서드를 정의한다.
*팩토리 메서드 패턴 (Factory Method Pattern): 이 패턴에서는 추상 클래스를 사용하여 객체 생성을 정의하는 인터페이스를 제공합니다. 서브 클래스에서 이 추상 클래스를 상속받아 실제 객체 생성을 구현합니다. 각 서브 클래스마다 객체를 생성하는 방식을 조정할 수 있으며, 클라이언트 코드는 추상 클래스를 통해 객체를 생성합니다.
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import controller.ActionForward;
public interface Action {
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException;
}
action패키지 안에
3. 방금 만든 Action Interface를 구현하는 HelloAction클래스를 생성 (테스트 모델)
=> 인터페이스를 구현한 모델을 정의한다.
이때 Forward 방식으로 진행을 하는 것이 일반적이다. 때에 따라서는 redirect 방식도 사용한다.
(Forward방식은 다음페이지로 넘어갈 때, 데이터를 유지한 채로, redirect는 데이터를 유지하지 X)
*로그인을 한 후 : Forward 방식으로 다음페이지로 가기, 회원가입을 한 후: Redirect 로 main페이지로 간다.*
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import controller.ActionForward;
public class HelloAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
request.setAttribute("msg", "안녕하세요 loopy");
// false -> forward, true -> redirect
return new ActionForward("hello", false);
}
}
controller 패키지 안에
4. ActionFactory 클래스를 생성하기
ActionFactory => 컨트럴 서블릿으로부터 요청을 받아서 각 Action들(action패키지에 있는 클래스들)을 관리하는 역할
다형성을 기준으로 관리하고 싱글톤 처리를 한다.
이미 성생한 HelloAction을 getAction()메서드에 등록해준다. 이후에도 다른 action을 생성하면, 이 메소드에 등록해준다.
*싱글톤이란?
싱글톤(Singleton)은 소프트웨어 디자인 패턴 중 하나로, 클래스의 인스턴스를 딱 하나만 생성하고 이 인스턴스에 대한 전역적인 접근점을 제공하는 패턴이다.
자바에서는 new 연산자를 이용하여 인스턴스를 생성하는데, 매번 new를 사용하면 메모리를 많이 사용해야하므로, 하나의 인스턴스를 만들고, 필요할 때마다 그 인스턴스 하나를 공유해서 사용하는 개념이다.
package controller;
import action.Action;
import action.HelloAction;
public class ActionFactory {
private static ActionFactory factory;
private ActionFactory() {
}
// synchronized : 스레드 동기화 처리
// return factory; => 하나의 ActionFactory 인스턴스를 생성 후, 이 인스턴스를 공유하여 사용하도록 한다.
public static synchronized ActionFactory getFactory() {
if (factory == null) {
factory = new ActionFactory();
}
return factory;
}
// CotrollServlet이 사용할 메서드
// cmd는 서블릿으로부터 받는 요청 값
public Action getAction(String cmd) {
// 요청값을 비교해서 다형성 적용
Action action = null;
if (cmd.equals("hello")) {
action = new HelloAction();
}
return action;
}
}
controller 패키지에
5. ControllServlet을 생성
-annotaion으로 서블릿으로 등록 => @WebServlet("*.loopy")
: urlpattern에 loopy가 들어가게 하되, .loopy 앞에 모든 문자를 허용
Ex) www.kkkkk.co.kr/pro.loopy , www.kkkkk.co.kr/main.loopy
이런식으로 가능
*직접 jsp파일(뷰)을 호출 x => 요새 트렌드는 controller를 통해서 뷰를 호출한다.
package controller;
import java.io.IOException;
import java.io.PrintWriter;
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 action.Action;
/**
* Servlet implementation class ControllServlet
*/
@WebServlet("*.loopy")
public class ControllServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doProcess(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doProcess(request, response);
}
protected void doProcess(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("euc-kr");
// pro.loopy?cmd=hello
// pro.loopy?cmd=movielist
String cmd = request.getParameter("cmd");
// 사용자의 요청을 ActionFactory에 전달한 후 해당 모델을 Action인터페이스에 반환받는다.(다형성)
Action action = null;
if (cmd != null) {
ActionFactory factory = ActionFactory.getFactory();
action = factory.getAction(cmd);
ActionForward af = action.execute(request, response);
// 모델에서 결정된 이동방식과 URL을 실제 적용하는 단계
if (af.isMethod()) {
response.sendRedirect(af.getUrl());
} else {
// forward
// /WEB-INF/ 보안폴더이기 때문에 반드시 forward에서만 접근이 가능하다.
String path = "/WEB-INF/views";
RequestDispatcher rd = request.getRequestDispatcher(path + "/" + af.getUrl() + ".jsp");
rd.forward(request, response);
}
} else {
// 오류코드
response.setContentType("text/html;charset=euc-kr");
PrintWriter out = response.getWriter();
out.print("<h2>요청하신 페이지는 존재하지 않습니다.</h2>");
out.close();
}
}
}
5-2. WEB-INF 폴더 안에 views 폴더를 만들고 거기에 hello.jsp 를 만들어서 테스트한다
-ControlServlet 서블렛에서 실행 한 후, 인터넷 창이 뜨면 url을 아래처럼 바꿔서 테스트 한다
url 뒤에 추가=> /pro.loopy?cmd=hello
(hello는 hello.jsp를 의미
(cmd는 getAction() 메서드의 인자, String cmd를 의미
=> 메세지(msg)가 화면에 출력되면 성공!
msg : HelloAction클래스의 execute()메소드에 설명해놓은 부분 => request.setAttribute("msg", "안녕하세요 loopy");
* ${msg } => EL (Expression Language) 로, 시간이 되면 따로 포스팅 할 예정
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>hello.jsp</title>
</head>
<body>
<h1>Hello.jsp</h1>
<p>메세지: ${msg }</p>
</body>
</html>
성공화면
-----테스트 및 환경 구축 끝
6. 새로운 모델을 생성 해보기 (로그인)
1) 뷰 생성
-views/login 폴더 생성 + loginForm.jsp 파일 생성하기
-loginForm.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>login/loginForm.jsp</title>
</head>
<body>
<form method="post" action="pro.loopy" autocomplete="off">
<input type="hidden" name="cmd" value="login">
<input type="hidden" name="sub" value="loginchk">
<p>아이디: <input type="text" name="id" id="id"></p>
<p>비밀번호: <input type="password" name="pwd" id="pwd"></p>
<p><input type="submit" value="send"></p>
</form>
</body>
</html>
2) action 패키지에 LoginAction 클래스를 생성한 후에(Action 인터페이스 구현), ActionFactory에 등록해준다.
- LoginAction
sub => 두 번째 파라미터
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import controller.ActionForward;
//cmd=loginForm 찾아오면
//내부적으로 sub란 파라미터로 분류 -> 로그인폼, 로그인처리, 로그아웃 처리 등등
public class LoginAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
String sub = request.getParameter("sub");
System.out.println("sub => " + sub);
ActionForward af = null;
if (sub.equals("loginForm")) {
af = new ActionForward("login/loginForm", false);
}
return af;
}
}
-ActionFactory의 getAction 메서드
public Action getAction(String cmd) {
// 요청값을 비교해서 다형성 적용
Action action = null;
if (cmd.equals("hello")) {
action = new HelloAction();
} else if (cmd.equals("login")) {
action = new LoginAction();
}
return action;
}
테스트 url : http://localhost/0812_Model2_join/pro.loopy?cmd=login&sub=loginForm
0812_Model2_join는 프로젝트명
성공화면:
7. 프로젝트를 실행하면, 가장 먼저 실행될 메인화면 생성
6번꺼 반복하기
1) views/main 에 index.jsp 생성
footer2.jsp와 header2.jsp를 index.jsp에 include 해주기 (위치: /views )
index.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@include file="../header2.jsp" %>
<h2>여기는 index</h2>
<c:choose>
<%-- 세션이 없는 경우 , 로그인 전 화면 --%>
<c:when test="${sessionScope.id==null }">
<a href="main.loopy?cmd=login&sub=loginForm">Login</a>
<br>
<a href="main.loopy?cmd=member&sub=memForm">Join</a>
<br>
</c:when>
<c:otherwise>
<%-- 세션이 있는 경우 , 로그인 성공 후 화면 --%>
<span>${sessionScope.id }님 반갑습니다.</span>
<a href="main.loopy?cmd=member&sub=myPage">MyPage</a>
<br>
<a href="main.loopy?cmd=login&sub=logout">Logout</a>
</c:otherwise>
</c:choose>
<%@include file="../footer2.jsp" %>
-footer2.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<footer>Page Footer </footer>
</body>
</html>
-header2.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>main/main1.jsp</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet">
<link rel="stylesheet"
href="<%=application.getContextPath()%>/resources/css/mystyle.css">
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
<script
src="<%=application.getContextPath()%>/resources/js/ajaxdemo1.js"></script>
</head>
<body>
<%-- header시작 --%>
<%-- p-5 : padding 5
text-white : text 흰색
text-center : text-align center
--%>
<header class="p-5 bg-primary text-white text-center">
<hgroup>
<h1>연습용 WebPage!</h1>
<p>[연습용 WebPage! 입니다.]</p>
</hgroup>
</header>
<%-- header끝 --%>
<%-- 메뉴 시작 --%>
<nav class="navbar navbar-expand-sm navbar-dark bg-dark">
<%-- 메뉴를 만들 때 검색까지 배치를 적용 --%>
<div class="container-fluid">
<%-- ul => navbar-nav --%>
<ul class="navbar-nav">
<li class="nav-item"><a
href="<%=application.getContextPath()%>/main/main1.jsp"
class="nav-link active">Home</a></li>
<li class="nav-item"><a
href="<%=application.getContextPath()%>/pororo/gallery.jsp"
class="nav-link ">갤러리</a></li>
<li class="nav-item"><a
href="<%=application.getContextPath()%>/tboard/list.jsp"
class="nav-link ">자유게시판</a></li>
<li class="nav-item"><a href="" class="nav-link ">프로필</a></li>
<li class="nav-item dropdown"><a
class="nav-link dropdown-toggle" href="#" id="navbarDropdown"
role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul></li>
<li class="nav-item dropdown"><a
class="nav-link dropdown-toggle" href="#" id="navbarDropdown"
role="button" data-bs-toggle="dropdown" aria-expanded="false">
멤버쉽 </a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item"
href="<%=application.getContextPath()%>/member/join.jsp">회원가입</a></li>
<li><a class="dropdown-item" href="#">로그인</a></li>
<li><a class="dropdown-item"
href="pro.kosmo?cmd=member&sub=pageMemList">페이지처리예제</a></li>
</ul>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search"
aria-label="Search">
<button class="btn btn-primary" type="submit">Search</button>
</form>
</div>
</nav>
(파일 경로 사진 참고
-jstl 다운로드 받은 후 => WEB-INF/lib에 넣기
index.jsp에서 아래 3 번째 줄 코드를 반드시 적어줘야 jstl 사용이 가능하다.
2) IndexAction class 생성 및 Action 인터페이스 오버라이딩
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import controller.ActionForward;
public class IndexAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
return new ActionForward("main/index", false);
}
}
2)ActionFactory - getAction 메소드에 등록해주기
public Action getAction(String cmd) {
// 요청값을 비교해서 다형성 적용
Action action = null;
if (cmd.equals("hello")) {
action = new HelloAction();
} else if (cmd.equals("login")) {
action = new LoginAction();
}else if (cmd.equals("index")) {
action = new IndexAction();
}
return action;
}
테스트 url : http://localhost/0812_Model2_join/pro.loopy?cmd=index
성공화면
8. LoginAction 메서드 구현하기
--Session ( scope obj) : 인터넷 서치를 하다보면 세션과 쿠키라는 단어를 종종 들어보았을 것이다.
둘 다 사용자의 상태를 저장하는 공간으로 Cookie는 클라이언트 측에, Session은 서버에 저장이 된다.
그래서 Cookie는 보안에 매우 취약하다. Session은 서버가 털리지 않는 이상 안전하다.
-LoginAction
아까 만들어둔 로그인 폼에 이어서 로그인 체크 로직 및 로그아웃 로직을 구현한다.
VO 및 Dao 부분은 아직 DB작업을 안했으니 생략.
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import controller.ActionForward;
//cmd=loginForm 찾아오면
//내부적으로 sub란 파라미터로 분류 -> 로그인폼, 로그인처리, 로그아웃 처리 등등
public class LoginAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
String sub = request.getParameter("sub");
System.out.println("sub => " + sub);
ActionForward af = null;
if (sub.equals("loginForm")) {
af = new ActionForward("login/loginForm", false);
} else if (sub.equals("loginchk")) {
// redirect로 보내기 (test용)
af = new ActionForward("pro.loopy?cmd=index", true);
} else if (sub.equals("logout")) {
// 세션을 삭제 - false는 새로운 세션을 생성하지 않는다.(기존값)
HttpSession session = request.getSession(false);
session.removeAttribute("id");
// session.invalidate(); //모든 세션을 삭제
System.out.println("logout");
af = new ActionForward("pro.loopy?cmd=index", true);
}
return af;
}
}
--DB작업
*마이바티스 셋팅
마이바티스 다운로드 후 => WEB-INF/lib에 넣기
마이바티스 자세한 셋팅의 위에 링크 달아둔 포스팅 참고
context.xml => DB 관련 정보 담는 파일 , 위치 중요
-config/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 데이터베이스 접속 -->
<environments default="">
<environment id="">
<transactionManager type="JDBC" />
<dataSource type="JNDI">
<property name="data_source"
value="java:comp/env/jdbc/myora" />
</dataSource>
</environment>
</environments>
<!-- 작업을 진행 할 mapper는 꼭 등록해줘야 한다. -->
<mappers>
<mapper resource="mapper/member.xml" />
</mappers>
</configuration>
-- mapper/member.xml ( mapper)
아래 코드는 로그인 로직 관련 전부 다 구현되어 있음 * mapper에 관한 설명은 생략
-가입시 아이디 중복체크, 로그인시 아이디 및 비번체크 ,가입하기 등
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- member.xml -->
<mapper namespace="mem">
<select id="idcheck" parameterType="String" resultType="int">
SELECT
COUNT(*) cnt FROM MEM1 WHERE id=#{id}
</select>
<!-- loginCheck -> select count(*) cnt from mem1 where id=#{id} and pwd=#{pwd} -->
<select id="loginchk" parameterType="vo.Mem1VO" resultType="int">
select count(*) cnt from mem1 where id=#{id} and pwd=#{pwd}
</select>
<!-- MyPage -> select num, id, name, tel, email from mem1 where id=#{id} -->
<select id="mypage" parameterType="String"
resultType="vo.Mem1VO">
select num, id, name, tel, email from mem1 where id=#{id}
</select>
<!-- Join -> insert into mem1 values (id, pwd, name, email, tel) -->
<insert id="join" parameterType="vo.Mem1VO">
insert into mem1 values
(mem1_seq.nextval, #{id}, #{pwd}, #{name}, #{email}, #{tel},
#{reip},sysdate)
</insert>
<!-- 회원전체 데이터 샘플
파라미터 : stype - 검색구분, svalue -검색값
where 엘리멘트의 특징 => 동적으로 구문적인 역할을 수행한다. sql의 where절 ㅇㅇ
-->
<!-- XML문법 PC DATA : 영역 안에서 < >를 사용할 수가 없기 때문에 그 목적으로 사용하기 위해서 탈출!
<![CDATA[문장]]> -->
<select id="listBack1" resultType="vo.Mem1VO" parameterType="map">
<![CDATA[
SELECT NUM, ID, NAME, TEL, EMAIL, REIP, MDATE FROM MEM1 WHERE NUM < 35
]]>
</select>
<select id="listBack2" resultType="vo.Mem1VO" parameterType="map">
SELECT NUM, ID, NAME, TEL, EMAIL, REIP, MDATE FROM MEM1
<!-- xml 영역으로 봐라 , 영역안은 pc data다 -->
<if test="stype != null and svalue != null">
<where>
<choose>
<when test="stype == 1">
NAME LIKE '%'||#{svalue} ||'%' AND NUM > 10
</when>
<when test="stype == 2">
ID = #{svalue}
</when>
<when test="stype == 3">
EMAIL LIKE '%'||#{svalue}||'%'
</when>
</choose>
</where>
</if>
ORDER BY 1 DESC
</select>
<select id="list" resultType="vo.Mem1VO" parameterType="map">
SELECT
num, id, name, tel, email, reip, mdate FROM(
SELECT ROWNUM r_num, a.*
FROM(
SELECT * FROM mem1 ORDER BY 1 desc
) a
)WHERE r_num BETWEEN
#{begin} AND #{end}
</select>
<select id="totalCount" resultType="int">
select count(*) cnt from mem1
</select>
</mapper>
9. DB작업
-1) 테이블 및 시퀀스 생성 (
SQL gate에서 테이블 및 시퀀스 생성 (MEM1, MEM1_ID_UQ)
CREATE TABLE MEM1(
NUM NUMBER CONSTRAINT MEM1_NUM_PK PRIMARY KEY,
ID VARCHAR2(20) NOT NULL,
PWD VARCHAR2(10),
NAME VARCHAR2(45),
EMAIL VARCHAR2(45),
TEL VARCHAR2(30),
REIP VARCHAR2(30),
MDATE DATE,
CONSTRAINT MEM1_ID_UQ UNIQUE(ID)
);
CREATE SEQUENCE MEM1_SEQ
INCREMENT BY 1
START WITH 1;
-2) 이클립스에서 위의 sql문을 보면서 VO만들기
vo/Mem1VO.java
VO(DTO): DB의 정보를 담는 객체
package vo;
public class Mem1VO {
private int num;
private String id;
private String pwd;
private String name;
private String email;
private String tel;
private String reip;
private String mdate;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getReip() {
return reip;
}
public void setReip(String reip) {
this.reip = reip;
}
public String getMdate() {
return mdate;
}
public void setMdate(String mdate) {
this.mdate = mdate;
}
}
-3) factory 패키지에 FactoryService 클래스 생성
FactoryService => SqlSessionFactory 객체를 반환 => SqlSessionFactory객체는 SqlSession을 생성한다.
*SqlSession : DB에 대한 SQL 문을 실행하고, 그 결과를 반환해주는 객체. (mapper 파일과 연결되어 있다)
MemberDao (Dao는 DB에 접근하는 객체다.)
MemberDao의 모든 메서드에는 아래코드(SqlSession생성)가 첫줄에 들어간다.
SqlSession ss = FactoryService.getFactory().openSession(); |
package factory;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class FactoryService {
private static SqlSessionFactory factory;
// config.xml이 mapper 즉 sql문까지 포함되고 있기 때문에 불러와서 사용 가능한 객체
// SqlSession 반환
static {
try (Reader reader = Resources.getResourceAsReader("config/config.xml");) {
factory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSessionFactory getFactory() {
return factory;
}
}
-4) DAO 만들기
Dao: DB에 접근을 하는 객체
dao/MemberDao.java
package dao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import factory.FactoryService;
import vo.Mem1VO;
public class MemberDao {
private static MemberDao dao;
// 싱글톤
private MemberDao() {
}
// 동기화
public synchronized static MemberDao getDao() {
if (dao == null) {
dao = new MemberDao();
}
return dao;
}
// idcheck를 하기 위한 메서드 정의
// <mapper namespace="mem">
// <select id="idcheck" parameterType="String" resultType="int">
// SELECT COUNT(*) cnt FROM MEM1 WHERE id=#{id}
public int idCheck(String id) {
SqlSession ss = FactoryService.getFactory().openSession();
int cnt = ss.selectOne("mem.idcheck", id);
ss.close();
return cnt;
}
// loginCheck
// <select id="loginchk" parameterType="vo.Mem1VO" resultType="int">
// select count(*) cnt from mem1 where id=#{id} and pwd=#{pwd}
public int loginCheck(Mem1VO v) {
SqlSession ss = FactoryService.getFactory().openSession();
int cnt = ss.selectOne("mem.loginchk", v);
ss.close();
return cnt;
}
// mypage
// <select id="mypage">
// select num, id, name, tel, email from mem1 where id=#{id}
public Mem1VO myPage(String id) {
SqlSession ss = FactoryService.getFactory().openSession();
Mem1VO v = ss.selectOne("mem.mypage", id);
ss.close();
return v;
}
// join
// <insert id="join" parameterType="vo.Mem1VO">
// insert into mem1 values (mem1_seq.nextval, #{id}, #{pwd}, #{name}, #{email}, #{tel})
public void join(Mem1VO v) {
SqlSession ss = FactoryService.getFactory().openSession();
ss.insert("mem.join", v);
ss.commit();
ss.close();
}
//1.회원관리 시스템
//SELECT NUM, ID, NAME, TEL, EMAIL, REIP, MDATE FROM MEM1 ORDER BY 1 DESC
/*
* public List<Mem1VO> memList() { SqlSession ss =
* FactoryService.getFactory().openSession();
*
* 2.검색기능 업데이트 member xml 수정 후에 아래 메소드
* List<Mem1VO> list = ss.selectList("mem.list"); //다중행 쿼리니까 selectlist()
* ss.close(); return list; }
* 3. 페이지처리 -begin, end
* <select id="list" resultType="vo.Mem1VO" parameterType="map">
*/
public List<Mem1VO> memList(Map<String, String> map) {
SqlSession ss = FactoryService.getFactory().openSession();
List<Mem1VO> list = ss.selectList("mem.list",map); //다중행 쿼리니까 selectlist()
ss.close();
return list;
}
//3. total함께 처리
//<select id="totalCount" resultType="int">
public int getCnt() {
SqlSession ss = FactoryService.getFactory().openSession();
int cnt = ss.selectOne("mem.totalCount");
ss.close();
return cnt;
} // Dao 의 위로 ㄱㄱ
}
-5) LoginAction 코드 마무리 및 완성하기
VO 및 Dao 부분 구현
package action;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import controller.ActionForward;
import dao.MemberDao;
import vo.Mem1VO;
//cmd=loginForm 찾아오면
//내부적으로 sub란 파라미터로 분류 -> 로그인폼, 로그인처리, 로그아웃 처리 등등
public class LoginAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
String sub = request.getParameter("sub");
System.out.println("sub => " + sub);
ActionForward af = null;
if (sub.equals("loginForm")) {
af = new ActionForward("login/loginForm", false);
} else if (sub.equals("loginchk")) {
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
System.out.println("id: " + id);
System.out.println("pwd: " + pwd);
// 로그인이 성공/실패
// 성공시 세션 저장
Mem1VO v = new Mem1VO();
v.setId(id);
v.setPwd(pwd);
int cnt = MemberDao.getDao().loginCheck(v);
if (cnt > 0) {
HttpSession session = request.getSession();
session.setAttribute("id", id);
} else {
PrintWriter out = response.getWriter();
out.println("Login에러!");
out.println("<a href='pro.loopy?cmd=index'>Home</a>");
out.close();
}
// redirect로 보내기 (test용)
af = new ActionForward("pro.loopy?cmd=index", true);
} else if (sub.equals("logout")) {
// 세션을 삭제 - false는 새로운 세션을 생성하지 않는다.(기존값)
HttpSession session = request.getSession(false);
session.removeAttribute("id");
// session.invalidate(); //모든 세션을 삭제
System.out.println("logout");
af = new ActionForward("pro.loopy?cmd=index", true);
}
return af;
}
}
로그인 테스트 :
sql gate에서 수동으로 데이터를 넣거본다.
insert into mem1 values(mem1_seq.nextval, 'soso6', '1', '노리1', 'buggl56e@naver.com', '010-222-3333','123.12.13',sysdate);
위의 아이디와 비번으로 로그인 테스트해보기
로그인 성공
로그아웃 성공
10. 회원가입 로직
6번에서 한 과정 다시 반복
-1) views/main/에 join.jsp 생성 (회원가입 폼)
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%@include file="../header2.jsp"%>
<div id="wrap" class="container mt-5">
<div class="row">
<h2>회원가입 폼</h2>
<form method="post" action="pro.loopy" autocomplete="on">
<input type="hidden" name="cmd" value="member">
<input type="hidden" name="sub" value="memAdd">
<p>
아이디 : <input type="text" name="id" id="id">
<button id="idChkBtn" >중복확인</button>
</p>
<p>
<span id="target"></span>
</p>
<p>
비밀번호 : <input type="password" name="pwd" id="pwd">
</p>
<p>
이름 : <input type="text" name="name" id="name">
</p>
<p>
이메일 : <input type="email" name="email" id="email">
</p>
<p>
전화번호 : <input type="tel" name="tel" id="tel">
</p>
<p><input type="hidden" name="reip" value="<%=request.getRemoteAddr() %>"></p>
<p style="text-align: right;">
<input type="submit" value="가입">
</p>
</form>
</div>
</div>
<script>
window.onload = function() {
document.querySelector("#idChkBtn").onclick = function(e) {
//폼전송을 막는 기능
e.preventDefault();
let param = "cmd=member&sub=idChk&id="+ document.getElementById("id").value;
sendRequest("pro.loopy", param, res, "get");
};
function res() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let idCnt = parseInt(xhr.responseText);
console.log(idCnt + ":" + typeof (idCnt));
let msg = "";
if (idCnt === 0) {
msg = "사용 가능한 아이디 입니다!";
document.getElementById("target").style.color = 'blue';
} else {
msg = "이미 사용중인 아이디 입니다!";
document.getElementById("target").style.color = 'red';
}
document.getElementById("target").innerHTML = msg;
}
}
}
};
</script>
<%@include file="../footer2.jsp"%>
-2) action에 Mem1Action 생성
package action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import controller.ActionForward;
import dao.MemberDao;
import vo.Mem1VO;
//가입, 마이페이지
// cmd = member, sub = memForm, memAdd, myPage
public class Mem1Action implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
String sub = request.getParameter("sub");
ActionForward af = null;
if (sub.equals("memForm")) { // 회원가입 폼
af = new ActionForward("main/join", false);
} else if (sub.equals("memAdd")) { /// 회원가입 처리
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
String name = request.getParameter("name");
String email = request.getParameter("email");
String tel = request.getParameter("tel");
String reip = request.getParameter("reip");
Mem1VO v = new Mem1VO();
v.setId(id);
v.setPwd(pwd);
v.setName(name);
v.setEmail(email);
v.setTel(tel);
v.setReip(reip);
MemberDao.getDao().join(v);
//af = new ActionForward("pro.loopy?cmd=member&sub=myPage", true);
af = new ActionForward("pro.loopy?cmd=index", true);
} else if (sub.equals("myPage")) {
// false는 기존의 세션
HttpSession session = request.getSession(false);
System.out.println("Session: " + session.getAttribute("id"));
// 세션이 null이면 로그인하지 않고 접근 한 경로
if (session.getAttribute("id") == null) { // login하지 않고 접속했을 경우
// 로그인 폼으로 강제 이동
af = new ActionForward("pro.loopy?cmd=login&sub=loginForm", true);
} else { // 정상적인 경우
// select num, id, name, tel, email from mem1 where id=로그인한 세션아이디 값
Mem1VO v = MemberDao.getDao().myPage((String) session.getAttribute("id"));
// 상세 정보값을 myPage로 전송한다.
request.setAttribute("v", v);
af = new ActionForward("main/mypage", false);
}
// pro.loopy?cmd=member&sub=idChk&id=div
} else if (sub.equals("idChk")) { // 아이디 중복확인 , Ajax로 요청
String id = request.getParameter("id");
System.out.println("Param: " + id);
int idres = MemberDao.getDao().idCheck(id);
System.out.println("Param:2 " + idres);
request.setAttribute("idres", idres);
af = new ActionForward("main/idchk", false);
//pro.loopy?cmd=member&sub=adminMemList
}
return af;
}
}
-3) ActionFactory에 등록해주기
public Action getAction(String cmd) {
// 요청값을 비교해서 다형성 적용
Action action = null;
if (cmd.equals("hello")) {
action = new HelloAction();
} else if (cmd.equals("login")) {
action = new LoginAction();
}else if (cmd.equals("index")) {
action = new IndexAction();
}else if (cmd.equals("member")) {
action = new Mem1Action();
}
return action;
}
회원가입 테스트 하기
가입 후 성공 화면 (index페이지로 리다이렉트)
DB에 데이터 들어온 거 확인
마이페이지 등등 다른 로직들도 차례대로 구현해주면 된다.
'개발일기 > JSP 프로그래밍 (Java 웹프로그래밍)' 카테고리의 다른 글
Spring Framework(스프링 프레임워크 : 필기 + 다운로드 및 환경설정 (0) | 2023.08.18 |
---|---|
JSP 프로그래밍: 모델1 방식의 웹 개발하기(갤러리 만들기) - 2 (0) | 2023.06.27 |
JSP 프로그래밍: 모델1 방식의 웹 개발하기(갤러리 만들기) - 1 (0) | 2023.06.27 |
Java와 DB 연결 (JDBC) / MyBatis(마이바티스를 사용하는 이유) (0) | 2023.06.22 |
JSP 프로그래밍 : Servlet 서블릿이란? 서블릿 및 Java 웹 프로그래밍 기초지식 / 내장객체 (0) | 2023.06.22 |