Template
public class Template {
// 1. Connection 객체 생성(DB 접속)한 후 Connection을 반환하는 메소드
public static Connection getConnection() {
// Map 계열 컬렉션(key-value)
Properties prop=new Properties();
// 읽어들일 driver.properties 파일의 물리적인 경로 설정
// 실질적으로 배포되는 폴더는 WebContent이기 때문에 src/db/driver/driver.properties로 읽으면 안됨
// WebContent/WEB-INF/classes에 있는 파일을 읽어야 함
String fileName = JDBCTemplate.class.getResource("/db/driver/driver.properties").getPath();
try {
prop.load(new FileInputStream(fileName));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
// 1) JDBC driver 등록
Connection conn=null;
try {
Class.forName(prop.getProperty("driver"));
conn=DriverManager.getConnection(prop.getProperty("url")
, prop.getProperty("username")
, prop.getProperty("password"));
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return conn;
}
// 2. 전달받은 Connection 객체를 가지고 commit해주는 메소드
public static void commit(Connection conn) {
try {
if(conn!=null&&!conn.isClosed()) {
conn.commit();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 3. 전달받은 Connection 객체를 가지고 rollback해주는 메소드
public static void rollback(Connection conn) {
try {
if(conn!=null&&!conn.isClosed()) {
conn.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 4. 전달받은 Connection 객체를 반납하는 메소드
public static void close(Connection conn) {
try {
if(conn!=null&&!conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 5. 전달받은 Statement 객체를 반납시키는 메소드
public static void close(Statement stmt) {
try {
if(stmt!=null&&!stmt.isClosed()) {
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// 6. 전달받은 ResultSet 객체를 반납시키는 메소드
public static void close(ResultSet rset) {
try {
if(rset!=null&&!rset.isClosed()) {
rset.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
VO
- SQL의 COLUMN_NAME와 DATA_TYPE을 Java 형태의 변수로 바꿔서 작성한다.
- 기본 생성자 구문과 매개변수 생성자 구문, setter/getter 메소드, overriding 구문을 작성한다.
public class Member {
private int userNo; //USER_NO NUMBER
private String userId; //USER_ID VARCHAR2(30 BYTE)
private String userPwd; //USER_PWD VARCHAR2(100 BYTE)
private String userName; //USER_NAME VARCHAR2(15 BYTE)
private String phone; //PHONE VARCHAR2(13 BYTE)
private String email; //EMAIL VARCHAR2(100 BYTE)
private String address; //ADDRESS VARCHAR2(100 BYTE)
private String interst; //INTEREST VARCHAR2(100 BYTE)
private Date enrollDate; //ENROLL_DATE DATE
private Date modifyDate; //MODIFY_DATE DATE
private String status; //STATUS VARCHAR2(1 BYTE)
public Member() {}
public Member(int userNo, String userId, String userPwd, String userName, String phone, String email,
String address, String interst, Date enrollDate, Date modifyDate, 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.interst = interst;
this.enrollDate = enrollDate;
this.modifyDate = modifyDate;
this.status = status;
}
public Member(int userNo, String userId, String userPwd, String userName, String phone, String email,
String address, String interst) {
super();
this.userNo = userNo;
this.userId = userId;
this.userPwd = userPwd;
this.userName = userName;
this.phone = phone;
this.email = email;
this.address = address;
this.interst = interst;
}
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 getInterst() {
return interst;
}
public void setInterst(String interst) {
this.interst = interst;
}
public Date getEnrollDate() {
return enrollDate;
}
public void setEnrollDate(Date enrollDate) {
this.enrollDate = enrollDate;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
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 + ", interst=" + interst
+ ", enrollDate=" + enrollDate + ", modifyDate=" + modifyDate + ", status=" + status + "]";
}
}
Controller
- servlet 파일로 작성한다.
- url/mappings에서 기존 파일 이름과 다른 이름으로 바꿔야 한다.
HttpServletRequest 객체와 HttpServletResponse 객체
- request는 서버로 요청할 때의 정보(전달값, 전달방식 등)들이 담긴 객체이다.
- response는 요청에 대해 응답할 객체이다.
응답페이지로 전달할 값이 있을 경우에 해당 전달값을 Servlet Scope 내장 객체에 담아서 보내야 한다.
Servlet Scope 내장 객체에는 application, session, request, page가 있다.
- application: 웹 애플리케이션 전역에서 꺼내쓸 수 있는 가장 넓은 범위의 Scope이다.
- session: session에 담은 데이터는 모든 jsp와 servlet에서 꺼내쓸 수 있다.
- request: request에 담은 데이터는 해당 request를 포워딩한 응답 jsp에서만 꺼내쓸 수 있다.
- page: 해당 jsp 페이지에서만 꺼내쓸 수 있다.
공통적으로 데이터를 담을 때 → .setAttribute("key", "value");
공통적으로 데이터를 얻을 때 → .getAttribute("key");
공통적으로 데이터를 지울 때 → .removeAttribute("key");
- 로그인 컨트롤러
@WebServlet("/login.me")
public class LoginController extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1) 전달값에 한글이 있을 경우 인코딩 처리를 해야 한다.(Post 방식)
request.setCharacterEncoding("UTF-8");
// 2) 요청 시 전달값(request의 parameter 영역)을 꺼내거 변수 또는 객체에 기록하기
String userId = request.getParameter("userId");
String userPwd = request.getParameter("userPwd");
// 3) 해당 요청을 처리하는 서비스 클래스의 메소드를 호출
Member loginUser=new MemberService().loginMember(userId, userPwd);
// 4) 처리된 결과를 가지고 사용자에게 보여줄 뷰를 지정해서 포워딩 또는 url 재요청
if(loginUser==null) { // 로그인 실패 -> 에러페이지 보여주기(RequestDispatcher 객체 사용)
request.setAttribute("errorMsg", "로그인에 실패하였습니다.");
// 응답페이지 jsp에 위임 시 필요한 객체
RequestDispatcher view = request.getRequestDispatcher("views/common/errorPage.jsp");
// 포워딩- 해당 경로로 선택된 뷰에 보내기
view.forward(request, response);
}
// 로그인 성공 -> 인덱스 페이지로 돌아오기, 로그인 정보는 페이지를 이동해도
// 계속 가지고있어야 하므로 session 객체에 담아 사용한다.
// Servlet에서 session을 사용하려면 객체를 얻어와야 한다.
else {
HttpSession session = request.getSession();
session.setAttribute("loginUser", loginUser);
// 1. 포워딩 방식 응답 뷰 출력하기
// RequestDispatcher view = request.getRequestDispatcher("응답페이지");
// RequestDispatcher view = request.getRequestDispatcher("index.jsp");
// view.forward(request, response);
// session.removeAttribute("loginUser");
// 2. url 재요청 방식
response.sendRedirect(request.getContextPath()); // 동적 방식
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
- 로그아웃 컨트롤러
@WebServlet("/logout.me")
public class LogoutController extends HttpServlet {
private static final long serialVersionUID = 1L;
public LogoutController() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 로그아웃 처리 -> session 만료시키기 invalidate() - session을 무효화(초기화)
request.getSession().invalidate();
// 응답페이지 -> JSP
// index.jsp
response.sendRedirect(request.getContextPath());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Service
- Connection을 생성한 후 DB에 접속하고, Connection 객체와 Controller에서 전달받은 데이터를 Dao에 전달한다.
public class MemberService {
// 로그인 요청 서비스
public Member loginMember(String userId, String userPwd) {
Connection conn = JDBCTemplate.getConnection();
Member m = new MemberDao().loginMember(conn, userId, userPwd);
JDBCTemplate.close(conn);
return m;
}
}
Dao
- SQL문을 실행하여 직접 접근하고, ResultSet이나 int형 변수로 결과를 받아 Service로 리턴한다.
public class MemberDao {
private Properties prop = new Properties();
public MemberDao() {
String fileName = MemberDao.class.getResource("/db/member/member-mapper.xml").getPath();
try {
prop.loadFromXML(new FileInputStream(fileName));
} catch (IOException e) {
e.printStackTrace();
}
}
public Member loginMember(Connection conn, String userId, String userPwd) {
// SELECT문 -> 결과행이 1개 또는 0개(userId는 unique가 걸려있어서 중복 불가)
// 결과값인 resultSet을 member 객체에 담아서 응답
Member m = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("loginMember");
try {
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, userId);
pstmt.setString(2, userPwd);
rset=pstmt.executeQuery();
if(rset.next()) {
m=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);
}
return m;
}
}
member-mapper
- xml 파일로 작성한다.
- properties를 사용하여 수정사항이 있어도 서버를 중단시키지 않고 프로그램을 작동시킬 수 있게 한다.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="loginMember">
SELECT *
FROM MEMBER
WHERE USER_ID=?
AND USER_PWD=?
AND STATUS='Y'
</entry>
</properties>
menubar
- jsp 파일로 작성한다.
- 사용자에게 보여져야 하므로 WebContent 폴더 내에 생성한다.
- 로그인 시 로그인 폼을 Controller로 넘어갈 수 있게 경로를 작성한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="com.cd.member.model.vo.Member"%>
// VO(Member 파일)를 import해야 로그인 시도했을 때
// VO부터 Dao까지 단계가 거쳐져서 결과가 돌아온다.
<%
Member loginUser = (Member)session.getAttribute("loginUser");
// loginUser가 null이면 로그인 전 화면을 보여준다.
// loginUser가 null이 아니면 로그인 후 화면을 보여준다.
String contextPath = request.getContextPath();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Menu Bar</title>
<style>
.nav-area{background-color: lightblue;}
.menu{
display: inline-block;
height: 50px;
width: 150px;
}
.menu a{
text-decoration: none;
color: whitesmoke;
font-size: 20px;
font-weight: bold;
display: block;
width: 100%;
height: 100%;
line-height: 50px;
}
.menu a:hover{
background-color: rgb(87, 165, 255);
}
</style>
</head>
<body>
<h1 align="center">게시판</h1>
<div class="login-area">
<%if(loginUser==null){ %>
<!-- 로그인 전에 보여지는 로그인 form -->
<form action="<%=contextPath %>/login.me" method="post">
<table>
<tr>
<th>아이디</th>
<td><input type="text" name="userId" required></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input type="password" name="userPwd" required></td>
</tr>
<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>
<a href="#">마이페이지</a>
<a href="<%=contextPath %>/logout.me">로그아웃</a>
</div>
<%} %>
</div>
<br>
<div class="nav-area" align="center">
<div class="menu"><a href="<%=contextPath %>">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>
</body>
</html>