이전포스팅 내용에서 웹 템플릿 적용 + 회원 테이블을 추가하여 작업하였다.
1. 모델
1) DB생성
2) VO
3) DAO
2. a_controller
3. 메인페이지의 수정
4. 로그인 페이지
5. 회원가입 페이지
6. 마이페이지
수정 완료된 프로젝트 파일을 첨부하였다.
상세한 주석을 통해 전체 내용을 수월히 파악할 수 있으므로,
게시글의 내용보다는 아래의 파일을 통해 직접 내용을 확인하는 것을 추천한다.
1. 모델
1) DB생성
create table member(
mid varchar(20) primary key,
mpw varchar(20) not null,
mname varchar(20) not null,
-- 0이면 관리자, 1이면 사용자권한 --
admin int default 1
);
select * from member;
2) VO
package member;
public class MemberVO {
private String mid;
private String mpw;
private String mname;
public String getMid() {
return mid;
}
public String getMpw() {
return mpw;
}
public String getMname() {
return mname;
}
public void setMid(String mid) {
this.mid = mid;
}
public void setMpw(String mpw) {
this.mpw = mpw;
}
public void setMname(String mname) {
this.mname = mname;
}
@Override
public String toString() {
return "[mid=" + mid + ", mpw=" + mpw + ", mname=" + mname + "]";
}
}
3) DAO
selectOne메서드가 두개로 구분되는데, selectOne은 로그인페이지에서 사용될 목적으로 mid, mpw의 입력이 data와 같다면 data를 반환 받을 수 있는 로직이며, selectOne2는 마이페이지에서 사용될 목적으로 mid의 입력이 data와 같다면 data를 반환 받을 수 있는 로직이다.
package member;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import common.JDBCUtill;
public class MemberDAO {
Connection conn;
PreparedStatement pstmt;
static final String insert="insert into member (mid, mpw, mname) values(?,?,?)";
static final String update="update member set mpw=? where mid=?";
static final String delete="delete from member where mid=?";
static final String selectOne="select * from member where mid=?";
public boolean insert(MemberVO vo) {
conn=JDBCUtill.connect();
try {
pstmt=conn.prepareStatement(insert);
pstmt.setString(1, vo.getMid());
pstmt.setString(2, vo.getMpw());
pstmt.setString(3, vo.getMname());
pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
JDBCUtill.disconnect(pstmt, conn);
return true;
}
public boolean update(MemberVO vo) {
conn=JDBCUtill.connect();
try {
pstmt=conn.prepareStatement(update);
pstmt.setString(1, vo.getMpw());
pstmt.setString(2, vo.getMid());
pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
JDBCUtill.disconnect(pstmt, conn);
return true;
}
public boolean delete(MemberVO vo) {
conn=JDBCUtill.connect();
try {
pstmt=conn.prepareStatement(delete);
pstmt.setString(1, vo.getMid());
pstmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
JDBCUtill.disconnect(pstmt, conn);
return true;
}
public MemberVO selectOne(MemberVO vo) {
MemberVO data=null;
conn=JDBCUtill.connect();
try {
pstmt=conn.prepareStatement(selectOne);
pstmt.setString(1, vo.getMid());
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
System.out.println("로그: 아이디 존재");
if(rs.getString("mpw").equals(vo.getMpw())) {
System.out.println("로그: 비밀번호 일치");
data=new MemberVO();
data.setMid(rs.getString("mid"));
data.setMpw(rs.getString("mpw"));
data.setMname(rs.getString("mname"));
}
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JDBCUtill.disconnect(pstmt, conn);
return data;
}
//마이페이지에서 사용될 비즈니스 메서드!
//비밀번호의 입력 없이 id만으로 data확인 가능
public MemberVO selectOne2(MemberVO vo) {
MemberVO data=null;
conn=JDBCUtill.connect();
try {
pstmt=conn.prepareStatement(selectOne);
pstmt.setString(1, vo.getMid());
ResultSet rs=pstmt.executeQuery();
if(rs.next()) {
data=new MemberVO();
data.setMid(rs.getString("mid"));
data.setMpw(rs.getString("mpw"));
data.setMname(rs.getString("mname"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JDBCUtill.disconnect(pstmt, conn);
return data;
}
}
2. a_controller
주석을 통해 내용 이해가 가능하다.
<%@page import="member.MemberVO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="error.jsp"%>
<%
request.setCharacterEncoding("UTF-8");
%>
<jsp:useBean id="mdao" class="member.MemberDAO"/>
<jsp:useBean id="mvo" class="member.MemberVO"/>
<jsp:setProperty property="*" name="mvo"/>
<%
String action=request.getParameter("action");
if(action.equals("login")){
//view에서 전달된 mid로 selectOne진행
//pw의 입력도 추가로 확인(인자가 두개)
MemberVO data=mdao.selectOne(mvo);
if(data==null){//존재하지 않는 mid라면
out.println("<script>alert('로그인 실패!');history.go(-1);</script>");
}else{//mid가 존재한다면 session(브라우저)에 로그인데이터 저장!
//단, session단에 pw가 돌아다니지 않도록 개별저장 해준다.
session.setAttribute("mname", data.getMname());
session.setAttribute("mid", data.getMid());
//환영글귀가 적힌 main페이지가 제공될 수 있도록 새로고침
response.sendRedirect("controller.jsp?action=main");
}
}else if(action.equals("logout")){
session.invalidate();//session에 존재하는 내용 삭제
out.println("<script>alert('로그아웃 완료');location.href='controller.jsp?action=main';</script>");
}else if(action.equals("signup")){
if(mdao.insert(mvo)){//회원가입에 성공했다면
out.println("<script>alert('회원가입 완료');location.href='controller.jsp?action=main';</script>");
}else{//실패했다면
throw new Exception("회원가입 실패");
}
}else if(action.equals("mypage")){
//mid가 인자로 들어가면 data반환(인자가 한개)
MemberVO data=mdao.selectOne2(mvo);
//반환 data를 변수에 저장(유효범위는 다음페이지까지)
request.setAttribute("data", data);
//데이터 가지고 마이페이지로 가!
pageContext.forward("a_mypage.jsp");
}else if(action.equals("mupdate")){
if(mdao.update(mvo)){
response.sendRedirect("controller.jsp?action=main");
}else{
throw new Exception("수정 실패");
}
}else if(action.equals("mdelete")){
if(mdao.delete(mvo)){
session.invalidate();//세션 비우기
response.sendRedirect("controller.jsp?action=main");
}else{
throw new Exception("삭제 실패");
}
}else{
throw new Exception("잘못된 action");
}
%>
3. 메인페이지의 수정
주석을 통해 내용 이해가 가능하다
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- JSTL:C를 사용할 목적 / 라이브러리 추가 완료 -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 전 페이지(컨트롤러)에서 가져온 datas 쓸건데 걔가 어디의 누구냐하면,(유효범위 다음페이지) -->
<jsp:useBean id="datas" class="java.util.ArrayList" scope="request"/>
<!DOCTYPE HTML>
<!--
Editorial by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>main</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body class="is-preload">
<!-- Wrapper -->
<div id="wrapper">
<!-- Main -->
<div id="main">
<div class="inner">
<!-- Header -->
<header id="header">
<a href="index.html" class="logo"><strong>Editorial</strong> by HTML5 UP</a>
<ul class="icons">
<li><a href="#" class="icon brands fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon brands fa-snapchat-ghost"><span class="label">Snapchat</span></a></li>
<li><a href="#" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon brands fa-medium-m"><span class="label">Medium</span></a></li>
</ul>
</header>
<!-- Banner -->
<section id="banner">
<div class="content">
<header>
<c:choose>
<!-- login되었다면-->
<c:when test="${mname!=null}">
<h1>${mname}님, 반갑습니다</h1>
</c:when>
<!-- 그게 아니라면-->
<c:otherwise>
<h1>로그인</h1>
</c:otherwise>
</c:choose>
</header>
<ul class="actions">
<c:choose>
<!-- login되었다면-->
<c:when test="${mname!=null}">
<!-- mypage -->
<!-- controller거쳐서 준비물(mvo.mid) 챙겨다가 마이페이지로 갈건데, 누구의 마이페이지로 가?-->
<li><a href="a_controller.jsp?action=mypage&mid=${mid}" class="button big">마이페이지</a><a href="a_controller.jsp?action=logout" class="button big primary">로그아웃</a></li>
</c:when>
<!-- 그게 아니라면-->
<c:otherwise>
<li><a href="a_login.jsp" class="button big">로그인</a></li>
</c:otherwise>
</c:choose>
</ul>
</div>
<span class="image object">
<img src="images/pic10.jpg" alt="" />
</span>
</section>
<!-- Section -->
<section>
<header class="major">
<h2>게시글</h2>
</header>
<div class="table-wrap">
<table border="1">
<thead>
<tr>
<th>글번호</th>
<th>작성자</th>
<th>작성일</th>
</tr>
</thead>
<tbody>
<!-- datas변수의 값들을 v라고 부를거야! -->
<c:forEach var="v" items="${datas}">
<tr>
<!-- controller거쳐서 준비물(vo.bid) 챙겨다가 board페이지로 갈건데, 누구의 상세페이지로 가?-->
<td><a href="controller.jsp?action=board&bid=${v.bid}">${v.bid}</a></td>
<td>${v.writer}</td>
<td>${v.regdate}</td>
</tr>
</c:forEach>
</tbody>
<tfoot>
<tr>
<td colspan="3" align="right"><a href="insert.jsp">글쓰기</a></td>
</tr>
</tfoot>
</table>
</div>
</section>
<!-- Sidebar -->
<div id="sidebar">
<div class="inner">
<!-- Search -->
<section id="search" class="alt">
<form method="post" action="#">
<input type="text" name="query" id="query" placeholder="Search" />
</form>
</section>
<!-- Menu -->
<nav id="menu">
<header class="major">
<h2>Menu</h2>
</header>
<ul>
<li><a href="index.html">Homepage</a></li>
<li><a href="generic.html">Generic</a></li>
<li><a href="elements.html">Elements</a></li>
<li>
<span class="opener">Submenu</span>
<ul>
<li><a href="#">Lorem Dolor</a></li>
<li><a href="#">Ipsum Adipiscing</a></li>
<li><a href="#">Tempus Magna</a></li>
<li><a href="#">Feugiat Veroeros</a></li>
</ul>
</li>
<li><a href="#">Etiam Dolore</a></li>
<li><a href="#">Adipiscing</a></li>
<li>
<span class="opener">Another Submenu</span>
<ul>
<li><a href="#">Lorem Dolor</a></li>
<li><a href="#">Ipsum Adipiscing</a></li>
<li><a href="#">Tempus Magna</a></li>
<li><a href="#">Feugiat Veroeros</a></li>
</ul>
</li>
<li><a href="#">Maximus Erat</a></li>
<li><a href="#">Sapien Mauris</a></li>
<li><a href="#">Amet Lacinia</a></li>
</ul>
</nav>
<!-- Section -->
<section>
<header class="major">
<h2>Ante interdum</h2>
</header>
<div class="mini-posts">
<article>
<a href="#" class="image"><img src="images/pic07.jpg" alt="" /></a>
<p>Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore aliquam.</p>
</article>
<article>
<a href="#" class="image"><img src="images/pic08.jpg" alt="" /></a>
<p>Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore aliquam.</p>
</article>
<article>
<a href="#" class="image"><img src="images/pic09.jpg" alt="" /></a>
<p>Aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore aliquam.</p>
</article>
</div>
<ul class="actions">
<li><a href="#" class="button">More</a></li>
</ul>
</section>
<!-- Section -->
<section>
<header class="major">
<h2>Get in touch</h2>
</header>
<p>Sed varius enim lorem ullamcorper dolore aliquam aenean ornare velit lacus, ac varius enim lorem ullamcorper dolore. Proin sed aliquam facilisis ante interdum. Sed nulla amet lorem feugiat tempus aliquam.</p>
<ul class="contact">
<li class="icon solid fa-envelope"><a href="#">information@untitled.tld</a></li>
<li class="icon solid fa-phone">(000) 000-0000</li>
<li class="icon solid fa-home">1234 Somewhere Road #8254<br />
Nashville, TN 00000-0000</li>
</ul>
</section>
<!-- Footer -->
<footer id="footer">
<p class="copyright">© Untitled. All rights reserved. Demo Images: <a href="https://unsplash.com">Unsplash</a>. Design: <a href="https://html5up.net">HTML5 UP</a>.</p>
</footer>
</div>
</div>
</div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/browser.min.js"></script>
<script src="assets/js/breakpoints.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
4. 로그인 페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<!--
Editorial by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>로그인</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body class="is-preload">
<!-- Wrapper -->
<div id="wrapper">
<!-- Main -->
<div id="main">
<div class="inner">
<!-- Header -->
<header id="header">
<a href="index.html" class="logo"><strong>Editorial</strong> by HTML5 UP</a>
<ul class="icons">
<li><a href="#" class="icon brands fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon brands fa-snapchat-ghost"><span class="label">Snapchat</span></a></li>
<li><a href="#" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon brands fa-medium-m"><span class="label">Medium</span></a></li>
</ul>
</header>
<!-- Banner -->
<section id="banner">
<div class="content">
<header>
<h1>로그인</h1>
<p>please enter your ID and Password.</p>
</header>
<!-- -->
<form action="a_controller.jsp?action=login" method="post">
<table>
<thead>
<tr>
<th>id</th>
<th>pw</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="mid" placeholder="id입력" required></td>
<td><input type="password" name="mpw" placeholder="pw입력" required></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2" align="right"><input type="submit" value="로그인"><a class="button primary" href="controller.jsp?action=main">메인페이지로 이동</a></td>
</tr>
</tfoot>
</table>
</form>
가입된 ID가 없다면 지금 <a href="a_signup.jsp">회원가입</a>해보세요
</div>
<span class="image object">
<img src="images/pic10.jpg" alt="" />
</span>
</section>
<!-- Footer -->
<footer id="footer">
<p class="copyright">© Untitled. All rights reserved. Demo Images: <a href="https://unsplash.com">Unsplash</a>. Design: <a href="https://html5up.net">HTML5 UP</a>.</p>
</footer>
</div>
</div>
</div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/browser.min.js"></script>
<script src="assets/js/breakpoints.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
5. 회원가입 페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<!--
Editorial by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>회원가입</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body class="is-preload">
<!-- Wrapper -->
<div id="wrapper">
<!-- Main -->
<div id="main">
<div class="inner">
<!-- Header -->
<header id="header">
<a href="index.html" class="logo"><strong>Editorial</strong> by HTML5 UP</a>
<ul class="icons">
<li><a href="#" class="icon brands fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon brands fa-snapchat-ghost"><span class="label">Snapchat</span></a></li>
<li><a href="#" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon brands fa-medium-m"><span class="label">Medium</span></a></li>
</ul>
</header>
<!-- Banner -->
<section id="banner">
<div class="content">
<header>
<h1>회원가입</h1>
<p>가입할 id와 pw를 입력하세요</p>
</header>
<!-- -->
<form action="a_controller.jsp?action=signup" method="post">
<table>
<thead>
<tr>
<th>id</th>
<th>pw</th>
<th>name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="mid" placeholder="id입력" required></td>
<td><input type="password" name="mpw" placeholder="pw입력" required></td>
<td><input type="text" name="mname" placeholder="이름 입력" required></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2" align="right"><input type="submit" value="가입하기"><a class="button primary" href="controller.jsp?action=main">메인페이지로 이동</a></td>
</tr>
</tfoot>
</table>
</form>
</div>
<span class="image object">
<img src="images/pic10.jpg" alt="" />
</span>
</section>
<!-- Footer -->
<footer id="footer">
<p class="copyright">© Untitled. All rights reserved. Demo Images: <a href="https://unsplash.com">Unsplash</a>. Design: <a href="https://html5up.net">HTML5 UP</a>.</p>
</footer>
</div>
</div>
</div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/browser.min.js"></script>
<script src="assets/js/breakpoints.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
6. 마이페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<!--
Editorial by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>마이페이지</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<link rel="stylesheet" href="assets/css/main.css" />
</head>
<body class="is-preload">
<!-- Wrapper -->
<div id="wrapper">
<!-- Main -->
<div id="main">
<div class="inner">
<!-- Header -->
<header id="header">
<a href="index.html" class="logo"><strong>Editorial</strong> by HTML5 UP</a>
<ul class="icons">
<li><a href="#" class="icon brands fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="#" class="icon brands fa-facebook-f"><span class="label">Facebook</span></a></li>
<li><a href="#" class="icon brands fa-snapchat-ghost"><span class="label">Snapchat</span></a></li>
<li><a href="#" class="icon brands fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="#" class="icon brands fa-medium-m"><span class="label">Medium</span></a></li>
</ul>
</header>
<!-- Content -->
<section>
<header class="main">
<h1>내정보</h1>
</header>
<div class="table-wrap">
<!-- input으로 현재내용 보여주면서 수정할 내용 입력도 받을 수 있도록할거임 -->
<!-- 긍게 일단 action은 update로 가야겠지? -->
<form action="a_controller.jsp?action=mupdate" method="post">
<table>
<thead>
<tr>
<th>ID</th>
<th>PASSWORD</th>
<th>NAME</th>
</tr>
</thead>
<tbody>
<tr>
<!-- pw만 변경 가능 -->
<td><input type="text" name="mid" value="${data.mid}" readonly></td>
<td><input type="text" name="mpw" value="${data.mpw}"></td>
<td><input type="text" name="mname" value="${data.mname}" readonly></td>
</tr>
</tbody>
<tfoot>
<tr>
<!-- 수정, 삭제, 메인페이지 이동 버튼 있음 -->
<td colspan="3" align="right"><input type="submit" value="수정하기"><a class="button" href="a_controller.jsp?action=mdelete&mid=${mid}">삭제하기</a><a class="button primary" href="controller.jsp?action=main">메인페이지로 이동</a></td>
</tr>
</tfoot>
</table>
</form>
</div>
<hr class="major" />
</section>
</div>
</div>
<!-- Footer -->
<footer id="footer">
<p class="copyright">© Untitled. All rights reserved. Demo Images: <a href="https://unsplash.com">Unsplash</a>. Design: <a href="https://html5up.net">HTML5 UP</a>.</p>
</footer>
</div>
<!-- Scripts -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/browser.min.js"></script>
<script src="assets/js/breakpoints.min.js"></script>
<script src="assets/js/util.js"></script>
<script src="assets/js/main.js"></script>
</body>
</html>
main페이지 이동시 controller에서 게시글 목록을 필수로 가져와야하기 때문에 main.jsp가 아닌 controller.jsp?action=main으로 지정해주어서 controller를 거치고 main페이지로 올 수 있도록 해야한다.
pk의 유무를 통해 결과를 반환할 수 있는 로직(selectOne, update, delete)은 반드시 view에서 controller을 통해 vo를 model에게 건내줄 수 있어야하는데, form으로 submit을 할 수 없는 경우 "a_controller.jsp?action=mdelete&mid=${mid}"의 예시와 같이 경로 뒤에 "&보낼 속성=값"으로 별도 지정해주어 정상적으로 vo의 값이 전달될 수 있도록 해야한다.
아래의
out.println(<script>alert("알럿창");location.href='이동경로';</script>); -> 스크립트를 활용한 alert창, location을 활용한 경로이동
response.sendRedirect("이동경로"); -> 내용의 전달 없이 그냥 페이지만 새로 요청할때
pageContext.forward("이동경로"); ->현재페이지의 저장된 내용들을 타겟페이지에 전달해야할때
등을 적절히 활용하여 로직 수행 완료 후의 명령을 지정해야한다.
session단위에 어떠한 변수를 저장했을 경우 session.invalidate( );을 알맞게 활용하여 적절한 타이밍에 session에 저장된 내용을 지워줄 필요가 있다.
'JSP' 카테고리의 다른 글
[controller업그레이드] 서블릿 활용 (0) | 2022.03.08 |
---|---|
[View업그레이드] 커스텀 태그 (0) | 2022.03.07 |
[View업그레이드] EL & JSTL (0) | 2022.03.03 |
[JDBC] MVC나누기_1 : 게시글 (0) | 2022.03.02 |
[JDBC] Bean & JDBC연결 (0) | 2022.03.01 |