본문 바로가기

Java 웹 개발

21.10.21 - 웹 개발 입문 49일차

홈페이지 구현하기(4)

 

[ 포인트 구현 ]

- header.jsp 로그인시 포인트충전 메뉴 추가

<%if(login){ %>
<a href="<%=root%>/index.jsp">홈으로</a>
<a href="<%=root%>/member/logout.txt">로그아웃</a>
<a href="<%=root%>/member/mypage.jsp">내정보</a>
<a href="<%=root%>/point/charge.jsp">포인트충전</a>
<a href="#">게시판</a>

 

-MemberFilter에 필터 주소 추가 ( 로그인만 접속가능 )

@WebFilter(urlPatterns = "/point/*")

 

- 포인트 상품 조회 + 충전 기능 만들기

- 포인트 상품 조회 (CoinDao) 만들기

package home.beans;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class CoinDao {

	public static final String USERNAME = "계정아이디", PASSWORD = "계정비밀번호";

//	목록 조회 기능
	public List<CoinDto> list() throws Exception {

		Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

		String sql = "select * from coin order by coin_amount asc";
		PreparedStatement ps = con.prepareStatement(sql);
		ResultSet rs = ps.executeQuery();

		// rs의 내용을 List에 복사
		List<CoinDto> list = new ArrayList<>();
		while (rs.next()) {
			CoinDto coinDto = new CoinDto();

			// (3개 항목 복사)
			coinDto.setCoinNo(rs.getInt("coin_no"));
			coinDto.setCoinName(rs.getString("coin_name"));
			coinDto.setCoinAmount(rs.getInt("coin_amount"));

			list.add(coinDto);
		}

		con.close();

		return list;
	}
	
	public CoinDto get(int coinNo) throws Exception {
		Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

		String sql = "select * from coin where coin_no = ?";
		PreparedStatement ps = con.prepareStatement(sql);
		ps.setInt(1, coinNo);
		ResultSet rs = ps.executeQuery();

		CoinDto coinDto;
		if(rs.next()) {
			coinDto = new CoinDto();

			coinDto.setCoinNo(rs.getInt("coin_no"));
			coinDto.setCoinName(rs.getString("coin_name"));
			coinDto.setCoinAmount(rs.getInt("coin_amount"));
		}
		else {
			coinDto = null;
		}

		con.close();

		return coinDto;
	}
}

 

- 포인트 상품 조회 (CoinDto) 만들기

 

package home.beans;

public class CoinDto {
	private int coinNo;
	private String coinName;
	private int coinAmount;	
	
	public CoinDto() {
		super();
	}
	
	public int getCoinNo() {
		return coinNo;
	}
	public void setCoinNo(int coinNo) {
		this.coinNo = coinNo;
	}
	public String getCoinName() {
		return coinName;
	}

	public void setCoinName(String coinName) {
		this.coinName = coinName;
	}
	public int getCoinAmount() {
		return coinAmount;
	}
	public void setCoinAmount(int coinAmount) {
		this.coinAmount = coinAmount;
	}

	@Override
	public String toString() {
		return "CoinDto [coinNo=" + coinNo + ", coinName=" + coinName + ", coinAmount=" + coinAmount + "]";
	}
	
}

 

- 포인트 충전 페이지 (charge.jsp) 만들기

<%@page import="home.beans.CoinDto"%>
<%@page import="java.util.List"%>
<%@page import="home.beans.CoinDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%-- 입력 : 없음 --%>

<%-- 처리 : 포인트상품 목록 --%>    
<%
	CoinDao coinDao = new CoinDao();
	List<CoinDto> list = coinDao.list();
%>

<%-- 출력 --%>
<jsp:include page="/template/header.jsp"></jsp:include>

<h2>포인트 충전</h2>

<h3>원하시는 상품을 선택하세요</h3>

<form action="charge.txt" method="post">

	<table>
		<tbody>
			<%for(CoinDto coinDto : list){ %>
			<tr>
				<td><input type="radio" name="coinNo" value="<%=coinDto.getCoinNo()%>"></td>
				<td><%=coinDto.getCoinName()%></td>
				<td>(<%=coinDto.getCoinAmount()%> point)</td>
			</tr>
			<%} %>
		</tbody>
		<tfoot>
			<tr align="center">
				<td colspan="3">
					<input type="submit" value="충전">
				</td>
			</tr>
		</tfoot>
	</table>

</form>

<jsp:include page="/template/footer.jsp"></jsp:include>

 

- 포인트 충전 처리 (PointChargeServlet.java) 만들기

package home.servlet.point;

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;

import home.beans.CoinDao;
import home.beans.CoinDto;
import home.beans.HistoryDao;
import home.beans.HistoryDto;
import home.beans.MemberDao;

@WebServlet(urlPatterns = "/point/charge.txt")
public class PointChargeServlet extends HttpServlet{
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {

			//1
			int coinNo = Integer.parseInt(req.getParameter("coinNo"));

			//2
			String memberId = (String)req.getSession().getAttribute("ses");

			//3 - coin 단일조회
			CoinDao coinDao = new CoinDao();
			CoinDto coinDto = coinDao.get(coinNo);

			//4 - history 등록
			HistoryDto historyDto = new HistoryDto();
			historyDto.setMemberId(memberId);
			historyDto.setHistoryAmount(coinDto.getCoinAmount());
			historyDto.setHistoryMemo("포인트상품 구매");

			HistoryDao historyDao = new HistoryDao();
			historyDao.insert(historyDto);

			//5 - member 수정
			//[1] 원래 포인트에서 현재 포인트만 추가 - 회원아이디, 추가된 포인트
			//[2] history에서 해당 회원 내역을 전부 계산하여 재설정 - 회원아이디
			MemberDao memberDao = new MemberDao();
			memberDao.addPoint(memberId, coinDto.getCoinAmount());//1번 방식
			//memberDao.refreshPoint(memberId);//2번 방식

			//완료 시 redirect
			resp.sendRedirect("charge_success.jsp");
		}
		catch(Exception e) {
			e.printStackTrace();
			resp.sendError(500);
		}
	}
}

 

- MemberDao 포인트 증가 감소 2가지 기능 추가

[1 - addPoint ] 원래 포인트에서 현재 포인트만 추가 - 회원아이디, 추가된 포인트
[2 - refreshPoint ] history에서 해당 회원 내역을 전부 계산하여 재설정 - 회원아이디

PointChargeServlet에서 사용

public boolean addPoint(String memberId, int coinAmount) throws Exception {
	Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

	String sql = "update member "
						+ "set member_point = member_point + ? "
						+ "where member_id = ?";
	PreparedStatement ps = con.prepareStatement(sql);
	ps.setInt(1, coinAmount);
	ps.setString(2, memberId);
	int result = ps.executeUpdate();

	con.close();

	return result > 0;
}

public boolean refreshPoint(String memberId) throws Exception {
	Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

	String sql = "update member set member_point = ("
							+ "select sum(history_amount) from history where member_id = ?"
						+ ") where member_id = ?";
	PreparedStatement ps = con.prepareStatement(sql);
	ps.setString(1, memberId);
	ps.setString(2, memberId);
	int result = ps.executeUpdate();

	con.close();

	return result > 0;
}

 

 

- 포인트 충전 완료 페이지 (charge_success.jsp) 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:include page="/template/header.jsp"></jsp:include>

<h2>포인트 충전 완료</h2>

<jsp:include page="/template/footer.jsp"></jsp:include>

 

 

포인트 내역 조회 만들기 

SQL에 코드 먼저 입력

create table history(
history_no number primary key,
member_id references member(member_id) on delete cascade not null,
history_time date default sysdate not null,
history_memo varchar2(100),
history_amount number
);
create sequence history_seq;

 

- 포인트 내역 조회 (TotalHistoryDto) 만들기

package home.beans;

import java.sql.Date;

public class TotalHistoryDto {
	private int historyNo;
	private String memberId;
	private Date historyTime;
	private String historyMemo;
	private int historyAmount;
	private String cancel;
	public TotalHistoryDto() {
		super();
	}
	public int getHistoryNo() {
		return historyNo;
	}
	public void setHistoryNo(int historyNo) {
		this.historyNo = historyNo;
	}
	public String getMemberId() {
		return memberId;
	}
	public void setMemberId(String memberId) {
		this.memberId = memberId;
	}
	public Date getHistoryTime() {
		return historyTime;
	}
	public void setHistoryTime(Date historyTime) {
		this.historyTime = historyTime;
	}
	public String getHistoryMemo() {
		return historyMemo;
	}
	public void setHistoryMemo(String historyMemo) {
		this.historyMemo = historyMemo;
	}
	public int getHistoryAmount() {
		return historyAmount;
	}
	public void setHistoryAmount(int historyAmount) {
		this.historyAmount = historyAmount;
	}
	public String getCancel() {
		return cancel;
	}
	public void setCancel(String cancel) {
		this.cancel = cancel;
	}
	public boolean available() {
		return this.cancel.equals("취소가능");
	}
}

 

 

- 포인트 내역 조회 (TotalHistoryDao) 만들기

package home.beans;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class TotalHistoryDao {
	
	public static final String USERNAME = "계정아이디", PASSWORD = "계정비밀번호";	
	
	//회원의 포인트내역 조회 기능
	//= HistoryDto 대신에 취소 여부도 알 수 있도록 새로 만든 TotalHistoryDto를 사용하여 조회
	public List<TotalHistoryDto> findByMemberId(String memberId) throws Exception {
		Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

		String sql = "select * from total_history where member_id = ? order by history_no desc";
		PreparedStatement ps = con.prepareStatement(sql);
		ps.setString(1, memberId);
		ResultSet rs = ps.executeQuery();

		//copy(rs --> List<TotalHistoryDto>)
		List<TotalHistoryDto> list = new ArrayList<>();
		while(rs.next()) {
			TotalHistoryDto historyDto = new TotalHistoryDto();

			historyDto.setHistoryNo(rs.getInt("history_no"));
			historyDto.setMemberId(rs.getString("member_id"));
			historyDto.setHistoryTime(rs.getDate("history_time"));
			historyDto.setHistoryMemo(rs.getString("history_memo"));
			historyDto.setHistoryAmount(rs.getInt("history_amount"));
			historyDto.setCancel(rs.getString("cancel"));

			list.add(historyDto);
		}

		con.close();

		return list;
	}
}

 

 

포인트 결제 취소 만들기 

Dto는 입력 항목이 하나(=history_no)이기 때문에 만들 필요 없다

-> Dao만 있으면 된다. 

- 포인트 결제 취소 (CancelDao) 만들기

package home.beans;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class CancelDao {
	public static final String USERNAME = "계정아이디", PASSWORD = "계정비밀번호";

	//1. 결제 취소 기능(C)
	public void insert(int historyNo) throws Exception {
		Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

		String sql = "insert into cancel values(?)";
		PreparedStatement ps = con.prepareStatement(sql);
		ps.setInt(1, historyNo);
		ps.execute();

		con.close();
	}

	//2. 결제 취소 가능 여부 확인 기능(R)
	//= true가 반환되면 데이터가 없어서 결제 취소가 가능하다는 의미이다.
	//= false가 반환되면 데이터가 있어서 결제 취소가 불가능하다는 의미이다.
	public boolean available(int historyNo) throws Exception {
		Connection con = JdbcUtils.connect(USERNAME, PASSWORD);

		String sql = "select * from cancel where history_no = ?";
		PreparedStatement ps = con.prepareStatement(sql);
		ps.setInt(1, historyNo);
		ResultSet rs = ps.executeQuery();

		boolean exist = rs.next();

		con.close();

		return !exist;
	}
}

 

 

- 포인트 취소 처리 (PointCancelServlet.java) 만들기

package home.servlet.point;

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;

import home.beans.CancelDao;
import home.beans.HistoryDao;
import home.beans.HistoryDto;
import home.beans.MemberDao;

@WebServlet(urlPatterns = "/point/cancel.txt")
public class PointCancelServlet extends HttpServlet{
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			//입력 : historyNo
			int historyNo = Integer.parseInt(req.getParameter("historyNo"));

			//처리
			CancelDao cancelDao = new CancelDao();
			if(cancelDao.available(historyNo)) {//취소가 가능하다면
				cancelDao.insert(historyNo);//취소

				//회원 포인트도 차감(historyNo ---> historyAmount ---> 차감)
				HistoryDao historyDao = new HistoryDao();
				HistoryDto historyDto = historyDao.get(historyNo);

				MemberDao memberDao = new MemberDao();
				memberDao.addPoint(historyDto.getMemberId(), -historyDto.getHistoryAmount());
				//memberDao.removePoint(historyDto.getMemberId(), historyDto.getHistoryAmount());
				//memberDao.refreshPoint(historyDto.getMemberId());

				//성공페이지로 이동
				resp.sendRedirect("cancel_success.jsp");
			}
			else {//취소가 불가능하다면(이미 취소된 내역이라면)
				//오류페이지로 이동
				resp.sendRedirect("cancel_fail.jsp");
			}
		}
		catch(Exception e) {
			e.printStackTrace();
			resp.sendError(500);
		}
	}
}

 

- 포인트 취소 성공 페이지 (cancel_success.jsp) 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<jsp:include page="/template/header.jsp"></jsp:include>

<h2>결제 취소가 완료되었습니다.</h2>

<h5><a href="<%=request.getContextPath()%>">메인 페이지로</a></h5>
<h5><a href="<%=request.getContextPath()%>/member/mypage.jsp">내 정보 보기</a></h5>

<jsp:include page="/template/footer.jsp"></jsp:include>

 

 

- 포인트 취소 실패 페이지 (cancel_fail.jsp) 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<jsp:include page="/template/header.jsp"></jsp:include>

<h2>결제 취소 실패 - 이미 취소된 내역입니다.</h2>

<h5><a href="<%=request.getContextPath()%>">메인 페이지로</a></h5>
<h5><a href="<%=request.getContextPath()%>/member/mypage.jsp">내 정보 보기</a></h5>

<jsp:include page="/template/footer.jsp"></jsp:include>

 

- 내 정보 보기 (mypage.jsp) 코드 수정

SQL에 코드 먼저 입력

create view total_history as select 
    H.*, 
    nvl2(C.history_no, '취소불가', '취소가능') "cancel"
from history H left outer join cancel C on h.history_no = C.history_no;

 

<%@page import="home.beans.TotalHistoryDto"%>
<%@page import="home.beans.TotalHistoryDao"%>
<%@page import="java.text.DecimalFormat"%>
<%@page import="java.text.Format"%>
<%@page import="home.beans.HistoryDto"%>
<%@page import="home.beans.HistoryDao"%>
<%@page import="java.util.List"%>

<%@page import="home.beans.MemberDto"%>
<%@page import="home.beans.MemberDao"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%-- 입력 : 현재 로그인한 회원ID - String memberId --%>
<%
	String memberId = (String) session.getAttribute("ses");
%>

<%-- 처리 : 회원정보(MemberDto) --%>
<%
	MemberDao memberDao = new MemberDao();
	MemberDto memberDto = memberDao.get(memberId);

// 새롭게 만든 뷰(total_history)를 이용하여 포인트 이력을 조회
	TotalHistoryDao historyDao = new TotalHistoryDao();
	List<TotalHistoryDto> historyList = historyDao.findByMemberId(memberId);
%>

<%-- 출력 --%>   
<jsp:include page="/template/header.jsp"></jsp:include>

<h2>회원 상세 정보</h2>

<table border="1" width="300">
	<tbody>
		<tr>
			<th width="25%">아이디</th>
			<td><%=memberDto.getMemberId()%></td>
		</tr>
		<tr>
			<th>닉네임</th>
			<td><%=memberDto.getMemberNick()%></td>
		</tr>
		<tr>
			<th>생년월일</th>
			<td><%=memberDto.getMemberBirthDay()%></td>
		</tr>	
		<tr>
			<th>이메일</th>
			<td><%=memberDto.getMemberEmailString()%></td>
		</tr>
		<tr>
			<th>전화번호</th>
			<td><%=memberDto.getMemberPhoneString()%></td>
		</tr>		
		<tr>
			<th>가입일시</th>
			<td><%=memberDto.getMemberJoin()%></td>
		</tr>
		<tr>
			<th>포인트</th>
			<td><%=memberDto.getMemberPoint()%></td>
		</tr>
		<tr>
			<th>등급</th>
			<td><%=memberDto.getMemberGrade()%></td>
		</tr>							
	</tbody>
</table>

<h3><a href="password.jsp">비밀번호 변경</a></h3>
<h3><a href="edit.jsp">개인정보 변경</a></h3>
<h3><a href="check.jsp">회원 탈퇴</a></h3>

<hr>

<!-- 포인트 내역 출력 -->
<h2>포인트 상세 내역</h2>

<table border="1" width="500">
	<thead>
		<tr>
			<th>일시</th>
			<th>금액</th>
			<th>메모</th>
			<th>cancel</th>
			<th>취소</th>
		</tr>
	</thead>
	<tbody>
		<%Format f = new DecimalFormat("#,##0"); %>
		<%for(TotalHistoryDto historyDto : historyList) { %>
		<tr>
			<td align="center"><%=historyDto.getHistoryTime()%></td>
			<td align="right"><%=f.format(historyDto.getHistoryAmount())%></td>
			<td align="left"><%=historyDto.getHistoryMemo()%></td>
			<td><%=historyDto.getCancel()%></td>
			<td>
				<%if(historyDto.available()){ %>
				<a href="../point/cancel.txt?historyNo=<%=historyDto.getHistoryNo()%>">취소</a>
				<a href="<%=request.getContextPath()%>/point/cancel.txt?historyNo=<%=historyDto.getHistoryNo()%>">취소</a>
				<%} %>
			</td>
		</tr>
		<%} %>
	</tbody>
</table>

<jsp:include page="/template/footer.jsp"></jsp:include>

 

 

 

 

 

홈페이지 - 관리자 기초 처리

SQL에 관리자로 먼저 설정하기위해 회원가입후 관리자 지정해주기

update member set member_grade='관리자' where member_id = 'homemaster';

 

- 관리자만 접속 가능 한 필터 (AdminFilter.java) 만들기

package home.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebFilter(urlPatterns = {"/admin/*"})
public class AdminFilter implements Filter{
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		/**
		 	현재 세션에는 ses라는 이름으로 회원 아이디가 저장되어 있음
			관리자인지 확인하려면
			[1] 회원아이디를 이용하여 단일조회 실시(DB 접속)
			[2] 로그인 성공 시 세션에 회원 권한(grade)도 저장
			
			우리는 [2]를 사용하여 처리한다.
		 */

		HttpServletRequest req = (HttpServletRequest)request;
		HttpServletResponse resp = (HttpServletResponse)response;
		HttpSession session = req.getSession();

		String grade = (String)session.getAttribute("grade");
		boolean admin = grade != null && grade.equals("관리자");

		if(admin) {
			chain.doFilter(request, response);
		}
		else {
			resp.sendError(403);//forbidden, 권한 부족
		}
	}
}

 

 

- hearder.jsp 코드 수정해서 grade 란 추가

String grade = (String)session.getAttribute("grade");
boolean admin = grade != null && grade.equals("관리자");

<h3>Apple 공식사이트 (ses = <%=ses%>, grade = <%=grade%>, login = <%=login%>)</h3>

 

- MemberLoginServlet에 로그인 시 회원 정보인 회원 등급을 grade라는 이름으로 저장 

( 관리자 / 일반회원 구분하기 )

req.getSession().setAttribute("grade", memberDto.getMemberGrade());

 

- MemberQuitServlet, MemberLogoutServlet에 회원탈퇴, 로그아웃 시

사용자의 등급 정보를 삭제하기 추가

req.getSession().removeAttribute("grade");

 

- 관리자 메인 페이지 (home.jsp) 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:include page="/template/header.jsp"></jsp:include>

<h2>관리자 메인 페이지</h2>

<h4><a href="#">포인트상품 관리</a></h4>
<h4><a href="#">회원 관리</a></h4>
<h4><a href="#">사이트 통계</a></h4>

<jsp:include page="/template/footer.jsp"></jsp:include>