thesunset 2022. 11. 9. 17:39

C:\web-workspace2 폴더 생성 

 

 

* 추가 셋팅 작업 (자동 주석 지우기)

JAVA-CodeStyle-CodeTemplates-Code탭-catchblock body&method body -edit 

주석 부분지우기

서버 구동환경 작업

Server Runtime Environments - add - 8.5 - 체크 

+ 포트번호 8001로 변경하기 

 

+ SQL Developer로 새로운 실습용 계정 만들기 & 슬랙 #수업자료에서 sql 스크립트 실행

 

1. WebContent - WEP-INF-classes-web.xml

2. 웰컴파일 index.jsp 빼고 다지우기

3. WebContent에 index.jsp 파일 생성 

4. lib폴더에 ojdbc 넣기

ojdbc넣기


<WebContent/ index.jsp>

* CRUD : 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리기능을 묶어서 이르는 말
사용자 인터페이스가 갖춰야 하는 기능을 가리키는 용도로도 사용됨

- C : Create (생성)    => INSERT
- R : Read (읽기 / 인출) => SELECT 
- U : Update (갱신)    => UPDATE
- D : Delete (삭제/갱신) => DELETE

 

< 만들어볼 서비스 > 

* 회원서비스
로그인(R), 회원가입(C)-(아이디중복체크(R)), 내정보변경(U), 회원탈퇴(D/U), 마이페이지(R)

* 공지사항 서비스
공지사항리스트조회(R), 공지사항상세조회(R), 공지사항작성(C), 공지사항수정(U), 공지사항삭제(D/U)

* 일반게시판서비스
게시글리스트조회(R)-페이징처리, 게시글 상세조회(R), 게시글작성(C)-첨부파일(1개 업로드), 게시글수정(U), 게시글삭제(D/U)
(댓글리스트조회(R), 댓글작성(C)=> AJax로 할 예정)

* 사진게시판서비스
사진 게시판 리스트 조회(R)-썸네일, 사진게시글 상세조회(R), 사진게시판작성(C)-다중파일업로드


폴더 구조 셋팅

subwaystore워크스페이스 폴더에서 driver.properties 복사해서 driver에 넣고 userId, userPwd를 SERVER로 변경 

(properties 파일에는 공백이 있어선 절대 안됨 !! 주의 !!) 

 

subway-mapper.xml도 sql-member에 복사 후 이름변경 & entry 지우기

 

C:\web-workspace1\3_SubwayStore\src\com\kh\common의 JDBCTemplate.java파일을

scr > common폴더에 붙여넣기 

 

이렇게!

<WebContent/ index.jsp>

- 실행하기 전 잘 돌아가는지 테스트 

: import하는 이유는 경로가 어디인지 알려주기 위해서이기 때문에 아래처럼 써도 됨

class패키지 경로 제시

<% com.kh.common.JDBCTemplate.getConnection(); %>

=> 아무것도 안뜨면 잘 실행되고 있다는 뜻 

 


- include 활용하기

: 상단에는 메뉴바를 보이게 할 것임 => 하나 만들고 여러 곳에 가져다 쓰기 

<%@ include file="views/common/menubar.jsp" %>

- menu.jsp 파일 생성하기 

 


<WebContent/views/common/menubar.jsp>

form태그 안에 있는 제출버튼(submit) 클릭 시 form태그가 가지고 있는 속성 중
action에 작성된 url로 요청됨(제출)
즉, Controller(Servlet)을 호출한다고 생각하면 됨

Servlet요청 같은 경우 반드시 그 요청값이 현재 웹 어플리케이션의
context Path == /context Root/뒤에 붙는 경로 
형식으로 작성해야 함
=> http://localhost:8001/jsp/test1.do (서블릿 매핑값)

 

* context Root루트 바꾸는 법 : server 더블클릭 > 바꿀 수 있음

* 경로 지정 방식


- 절대경로방식 (/) : /Context Root/요청할 url
      /로 시작하는 경우 
   localhost:8001 뒤에 action에 작성한 값이 붙여지면서 요청

- 상대경로방식(test1.do) : 요청할 url문구로 시작하는 경우
  현재 이 페이지가 보여질 때의 url경로 중에서
  마지막 / 로부터 뒤에 action에 작성한 값이 붙어지면서 요청 

 

- 아이디 비밀번호 영역

<div class="login-area">
	<form action="/jsp/login.me" method="post">
			<table>
				<tr>
					<th>아이디</th>
					<td><input type="text" required name="userId"></td>
				</tr>
					<th>비밀번호</th>
					<td><input type="password" required name="userPwd"></td>
				<tr>
					<th colspan="2">
						<button type="submit">로그인</button>
						<button type="button">회원가입</button>
                </th>
            </tr>
        </table>
    </form>
</div>

- navigator만들기 

<div class="nav-area" align="center"> <!--이번엔 list방식이 아닌 div로 네비바 만들기 -->

    <div class="menu"><a href="#">HOME</a></div>
    <div class="menu"><a href="#">공지사항</a></div>
    <div class="menu"><a href="#">일반게시판</a></div>
    <div class="menu"><a href="#">사진게시판</a></div>

</div>

+ 스타일 부여 

.nav-area{
	background-color: olive;
	
}
.menu{
	display: table-cell; /*가로로 바꾸는 법*/
	height: 50px;
	width: 150px;
}
.menu a{
	text-decoration: none;
	color: white;
	font-size: 22px;
	font-weight: bold;
	display: block; /*크기 지정하기 위해서 블럭요소로 바꿈*/
	width: 100%;
	height: 100%;
	line-height: 50px;
}
.menu a:hover{
	background-color: olivedrab;
}

member만들기

1. vo

Member: <com.kh.member.model.vo>

package com.kh.member.model.vo;

import java.sql.Date;

public class Member {

	private int userNO; 
	private String userId;
	private String userPwd;
	private String userName;
	private String phone;
	private String email;
	private String address;
	private String interest;
	private Date enrollDate; //반드시 sql의 date import하기**
	private Date modifuDate;
	private String status;

	//기본생성자, 모든필드에 대한 매개변수를 가지고 있는 생성자, 각각 getter/setter, toString
	
	public Member() {
		super();
	}

	public Member(int userNO, String userId, String userPwd, String userName, String phone, String email,
			String address, String interest, Date enrollDate, Date modifuDate, String status) {
		super();
		this.userNO = userNO;
		this.userId = userId;
		this.userPwd = userPwd;
		this.userName = userName;
		this.phone = phone;
		this.email = email;
		this.address = address;
		this.interest = interest;
		this.enrollDate = enrollDate;
		this.modifuDate = modifuDate;
		this.status = status;
	}

	public int getUserNO() {
		return userNO;
	}

	public void setUserNO(int userNO) {
		this.userNO = userNO;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public String getUserPwd() {
		return userPwd;
	}

	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getInterest() {
		return interest;
	}

	public void setInterest(String interest) {
		this.interest = interest;
	}

	public Date getEnrollDate() {
		return enrollDate;
	}

	public void setEnrollDate(Date enrollDate) {
		this.enrollDate = enrollDate;
	}

	public Date getModifuDate() {
		return modifuDate;
	}

	public void setModifuDate(Date modifuDate) {
		this.modifuDate = modifuDate;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	@Override
	public String toString() {
		return "Member [userNO=" + userNO + ", userId=" + userId + ", userPwd=" + userPwd + ", userName=" + userName
				+ ", phone=" + phone + ", email=" + email + ", address=" + address + ", interest=" + interest
				+ ", enrollDate=" + enrollDate + ", modifuDate=" + modifuDate + ", status=" + status + "]";
	}
}

2. Controller

LoginController < com.kh.member.controller >

매핑값 login.me로 한 Servlet 생성

 

<HttpServletRequest, HttpServletResponse 객체>
- request : 서버로 요청할 때 정보들이 담겨있음(요청 시 전달값, 요청전달 방식 등) 
- response : 요청에 대해 응답하고자 할 때 사용하는 객체 

 

1) POST방식의 경우 인코딩 설정 

request.setCharacterEncoding("UTF-8");

2) 요청 시 전달값을 꺼내서 변수에 기록 => request의 getParameter영역

request.getParameter("키값"); : String

request.getParameterValues("키값") : String[] => checkbox일 경우 사용

String userId = request.getParameter("userId");
String userPwd = request.getParameter("userPwd");

3) 해당 요청을 처리해주는 서비스 클래스의 메소드를 호출

new MemberService().loginMember(userId, userPwd);

<응답>

3_2) Member객체 형태로 돌아왔으므로 Member로 받아주기

Member loginUser = new MemberService().loginMember(userId, userPwd);

일치하는 회원이 있다면 loginUser객체에 필드값이 회원정보로 꽉 차있을 것
일치하는 회원이 없다면 null;(초기값그대로=>if문 안에 못들어와서)

 

4) 처리된 결과를 가지고 사용자가 보게될 응답화면을 지정 

* 로그인의 경우 특별한 경우이기 때문에 기본 request방식이 맞지 않음

더보기

기본 STEP
STEP1. request객체에 응답화면에 보여질 값 담기 -> request의 attribute영역에
STEP2. RequestDispatcher객체 생성 => 응답할 뷰 화면을 지정
STEP3. RequestDispatcher객체로부터 forward메소드 호출 
로그인 기능의 경우 적합하지 않음(다음페이지로 넘어가도 로그인이 유지되어야하기 때문에)

STEP1. 어딘가에 응답화면에 보여질 값 담기(request, session, application, page)

* 응답페이지에 전달할 값 담을 객체 4종류 * (ServletScope 내장객체)

: 모두 다 Attribute 영역이 존재함 

큰(위로갈 수록 큰)
(1) application : 웹 어플리케이션 전역에서 언제나 꺼내쓸 수 있음 (자바클래스에서 쓸 수 있음)

(2) session : 모든 jsp와 servlet에서 꺼내쓸 수 있음
단, 내가 직접적으로 session객체에 담은 값을 지우기 전까지 
세션이 끊기는 경우 : 브라우저가 종료될 때, 서버가 멈춘 경우
=> 로그인


(3) request : 해당 request를 forwarding한 응답 jsp페이지에서만 쓸 수 있음
요청페이지부터 응답페이지까지에서만 쓸 수 있음

(4) page : 담은 값을 해당 jsp페이지에서만 쓸 수 있음(화면이 넘어가면 담은 값은 소멸)
작은(아래로갈수록 작은)

=> session, request가 가장 많이 쓰임
=> 공통적으로 데이터를 담고자 한다면 : XXX.setAttribute(key, value)
데이터를 뽑고자 한다면 : XXX.getAttribute(key);
데이터를 지우고자 한다면 : XXX.removeAttribute(key);

예시) 
로그인 시 : session.setAttribute("userInfo", loginUser)
로그아웃 시 : session.removeAttribute("userInfo"); 또는 무효화 시키는 메소드 사용

 

Q. 그럼 매개변수에 있는 HttpServletRequest request는?

 

STEP2. case1. RequestDispatcher 객체 생성(응답할 뷰화면 지정) => forward();

- 로그인 실패했을 경우와 성공했을 때를 나누어서 응답 뷰 지정하기

- 로그인 실패 

if(loginUser==null) { //로그인 실패
    //에러메시지넘기기
    //1) request의 attribute영역 메시지 담기
    request.setAttribute("errorMsg", "로그인에 실패하였습니다.");

    //2) RequestDispatcher객체 생성
    RequestDispatcher view = request.getRequestDispatcher("views/common/errorPage.jsp");

    //3) forward
    view.forward(request, response);
}

- views/common/errorPage.jsp 파일 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	String errorMsg = (String)request.getAttribute("errorMsg");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1 align="center" style="color:red; margin-top:100px;"><%=errorMsg %></h1>
</body>
</html>

만약 로그인 실패 시,

실패했을 때

이런 화면이 나타나게 됨

- 로그인 성공

=> index.jsp페이지 응답

사용자의 정보 넘기기 : 로그인 한 회원의 정보를 로그아웃하기 전까지 계속 가져다 쓸거기 때문에 session에 담기

1) session에 attribute영역에 사용자 정보 담기
=> session 객체의 Type : HttpSession
=> session 객체 생성 방법 : request.getSession();

HttpSession session = request.getSession();
session.setAttribute("loginUser", loginUser);

방식 1. 포워딩 방식

: 요청한 곳에서 다시 응답 줌

2) RequestDispatcher 객체 생성

RequestDispatcher view = request.getRequestDispatcher("index.jsp");

3) forward()

view.forward(request, response);

//http://localhost:8001/jsp/login.me
//내가 요청한 mapping값이 url에 잘 나옴

방식 2. url재요청방식(sendRedirect방식) : 사용자에게 url을 재요청 하게 함으로써 응답페이지가 보여지게끔 해줌

response객체를 이용 => response.sendRedirect(재요청할 경로);

response.sendRedirect("/jsp");

= 내가 요청한 경로가 url에 보임 : http://localhost:8001/jsp

 

* 로그인 실패화면과 성공화면 나누기 (성공했을 때는 XXX님 환영합니다. / 실패했을 때는 로그인창) : if문 이용

* 로그인 성공 시 alert창 띄우기 : 로그인 성공 

if(loginUser==null) { //로그인 실패
    request.setAttribute("errorMsg", "로그인에 실패하였습니다.");
    RequestDispatcher view = request.getRequestDispatcher("views/common/errorPage.jsp");
    view.forward(request, response);

} else { //로그인 성공 => index.jsp페이지 응답
    HttpSession session = request.getSession();
    session.setAttribute("loginUser", loginUser);

    session.setAttribute("alertMsg", "로그인 성공"); //alert창(성공)

    response.sendRedirect("/jsp");
}

menubar.jsp에서 로그인/로그인 전 화면을 나누는 이유는 메뉴는 어느페이지나 존재하기 때문에 매번 나눌 필요가 없음

<WebContent/views/common/menubar.jsp>

+ 스타일 추가부여

.login-area, #user-info{
    float : right;

}

#user-info a{
    text-decoration : none;
    color : ligthgray;
    font-size : 12px;
}

loginController로 부터 가져온 session객체의 attribute에 접근해 값 가져오기 & 변수에 담기 

<% Member loginUser = (Member)session.getAttribute("loginUser"); //Object=>Member
   String alertMsg = (String)session.getAttribute("alertMsg"); %>

>로그인 전 : menubar.jsp가 로딩될 때 null
>로그인 후 : menubar.jsp가 로딩될 때 로그인한 회원의 정보가 담겨있음

> 서비스 요청 전 : alertMsg = null
> 서비스 요청 후 성공 시 : alertMsg = 메시지문구

- body영역 젤 초반에 script태그 만들기 => script태그 안에서도 스크립틀릿 사용가능

<script>
var msg = '<%=alertMsg%>';

case1 : '메시지 문구' / case2: null(만약에 null이면 null에도 ''가 붙게됨)

 

alert창은 한 번 실행 후 더이상 실행되지 않아야 함 

session에 들어있는 alertMsg키값에 대한 벨류를 지우기 => 만약 지우지 않는다면 menubar.jsp가 로딩될 때마다 alert이 계속 뜰 것임

=> XX.removeAttribute("키값");

if(msg != 'null'){
			alert(msg);
    <%session.removeAttribute("alertMsg");%>

- 화면 지정하기

    <% if(loginUser==null) { %>
    <!-- 사용자가 로그인 전 보게 될 화면 -->
    <form action="/jsp/login.me" method="post">
        <table>
            <tr>
                <th>아이디</th>
                <td><input type="text" required name="userId"></td>
            </tr>
                <th>비밀번호</th>
                <td><input type="password" required name="userPwd"></td>
            <tr>
                <th colspan="2">
                    <button type="submit">로그인</button>
                    <button type="button">회원가입</button>
                </th>
            </tr>
        </table>
    </form>

    <% } else { %>
<!-- 로그인 성공 시 보게될 화면 -->
<div id="user-info">
    <b><%=loginUser.getUserName() %></b>님 환영합니다. <br><br>
    <div align="center">
        <a href="#">마이페이지</a>
        <a href="#">로그아웃</a>
    </div>
    <% }  %>

3. Service

MemberService<m.kh.member.model.service>

Service => Connection객체 생성

1) Connection객체 생성 

2) controller에서 넘어온 전달값과 Connection객체를 가지고 DAO메소드 호출

public void loginMember(String userId, String userPwd) {
    Connection conn = JDBCTemplate.getConnection();
    new MemberDao().loginMember(conn, userId, userPwd);
}

< 응답 > 

3) Connection 객체 반납 & 4) Controller로 결과넘기기 

Member loginUser = new MemberDao().loginMember(conn, userId, userPwd);
		JDBCTemplate.close(conn);
		return loginUser;

 

 

 

 

4. Dao

MemberDao<m.kh.member.model.dao>

DAO(Data Access Object) : 데이터가 보관되어있는 공간에 직접 접근해서 데이터를 입출력하는 메소드들을 모아둔 클래스(dao)

0) properties 객체 생성 (바깥에서 쓰지 않을 거니까 private) 

private Properties prop = new Properties();

1) 기본생성자 만들기(예외처리해주기) > 자주쓰니까 호출할 때마다 생성하기 위해서

스트림 연결 & member-mapper에서 xml파일 가져오기 

public MemberDao() {

    String file = MemberDao.class.getResource("/sql/member/member-mapper.xml").getPath();

    try {
        prop.loadFromXML(new FileInputStream(file));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

2) loginMember(Connection conn, String userId, String userPwd)

로그인 요청 => SELECT문 => ResultSet객체 (unique key제약조건에 의해 한 행만 조회됨) => Member

Member loginUser = null;
ResultSet rset = null;
PreparedStatement pstmt= null;

String sql = prop.getProperty("loginMember");

		try {
			//pstmt객체 생성
			pstmt = conn.prepareStatement(sql);
			
			//위치홀더(?)채우기
			pstmt.setString(1, userId);
			pstmt.setString(2, userPwd);
			
			//쿼리문 실행 후 결과 받기
			//쿼리문 실행메소드
			//pstmt.executeQuery(); => SELECT : ResultSet
			//pstmt.executeUpdate(); => INSERT, UPDATE, DELETE : int / 0
			
			rset = pstmt.executeQuery();
			
			//rset으로부터 각각의 컬럼값을 뽑아서 Member객체에 담는다.
			//조회결과가 한 행 일 때 -> if()
			//조회결과가 여러 행일 때  -> while()
			
			if(rset.next()) {
				// 각 컬럼의 값 뽑기 
				// rset.getInt/getString/getDate(뽑아올 컬럼명 또는 컬럼의 순번)
				
				loginUser = new Member(rset.getInt("USER_NO"),
							   rset.getString("USER_ID"),
							   rset.getString("USER_PWD"),
							   rset.getString("USER_NAME"),
							   rset.getString("PHONE"),
							   rset.getString("EMAIL"),
							   rset.getString("ADDRESS"),
							   rset.getString("INTEREST"),
							   rset.getDate("ENROLL_DATE"),
							   rset.getDate("MODIFY_DATE"),
							   rset.getString("STATUS")
						);
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			//자원반납
			JDBCTemplate.close(rset);
			JDBCTemplate.close(pstmt);
		}
		//Service에 결과(Member)넘기기
		return loginUser;
	}