STS3에서 로그인과 게시판 생성을 위한 요점 정리
Spring Tool Suite3를 이용한 로그인 및 게시판 기능 구현을 할 때 필요한 요점을 기능별로 정리한 내용입니다.
해당 내용은 국비 지원에서 받은 수업을 기반으로 두어 내용을 정리하였습니다.
1. 데이터베이스 유틸리티 (JDBCUtil.java)
package com.springbook.biz.board;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class JDBCUtil {
// 1. DB 연결 메서드
public static Connection getConnection() {
try {
Class.forName("org.h2.Driver");
return DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test", "sa", "");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 2. AutoCloseable을 이용한 공통 close 메서드
public static void closeMethod(AutoCloseable resource) {
if (resource != null)
try {
resource.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 3. PreparedStatement와 Connection 닫기
public static void close(PreparedStatement stmt, Connection conn) {
closeMethod(stmt);
closeMethod(conn);
}
// 4. ResultSet, PreparsdStatement, Connection 닫기
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
closeMethod(rs);
closeMethod(stmt);
closeMethod(conn);
}
}
1-1. getConnetion() - 데이터베이스 연결
public static Connection getConnection() {
try {
Class.forName("org.h2.Driver"); // 드라이버 클래스 로드
return DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test", "sa", "");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- Class.forName("org.h2.Driver")
- H2 데이터베이스의 JDBC 드라이버를 JVM에 로딩
- DriverManager.getConnection(...)
- DB URL, 사용자 ID, 비밀번호를 이용해 실제 DB에 연결
- 성공 시 Connection 객체 반환, 실패시 null.
1-2. closeMethod(AutoCloseable resource) - 공통 자원 닫기 메서드
public static void closeMethod(AutoCloseable resource) {
if (resource != null)
try {
resource.close(); // try-with-resources 내부에서 사용하는 close()
} catch (Exception e) {
e.printStackTrace();
}
}
- AutoCloseable은 Connection, PreparedStatment, ResultSet 등이 모두 구현하는 인터페이스이기 때문에 하나의 메서드로 통합 처리 가능
- 자원이 null이 아닐 때만 닫기를 시도함 ※NullpointerException 방지
- 예외 발생 출력만 하고 흐름은 유지.
1-3. close(...)
public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
closeMethod(rs);
closeMethod(stmt);
closeMethod(conn);
}
- 자주 사용되는 조합을 한번에 정리하는 편의 메서드
마지막으로
JDBC클래스는 JDCB 연결 및 리소스 해제를 간단하고 안전하게 수행할 수 있도록 도와주는 유틸리티 클래스입니다.
특히 AutoCloseable을 활용해 반복되는 코드 패턴을 줄이고, 예외 처리와 null 체크를 통해 안정적이고 유지보수하기 좋은 JDBC 코드 구조를 제공하는 것이 이 클래스의 핵심 목적입니다.
2. 회원 기능 (User)
✅ UserVO.java
package com.springbook.biz.user;
public class UserVO {
// CREATE TABLE users(
// id VARCHAR2(8) PRIMARY KEY,
// password VARCHAR2(20),
// name VARCHAR2(20),
// role VARCHAR2(5),
// );
private String id;
private String password;
private String name;
private String role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
return "[id=" + id + ", password=" + password + ", name=" + name + ", role=" + role + "]";
}
}
2-1-1. 필드 (멤버 변수)
private String id;
private String password;
private String name;
private String role;
- id : 사용자 ID (Primary key)
- password : 로그인 비밀번호
- name : 사용자 이름
- role : 사용자 역할
2-1-2. Getter & Setter
public String getId() { return id; }
public void setId(String id) { this.id = id; }
- 캡슐화를 위해 private 멤버 변수에 직접 접근하지 않고,
- getter, setter 메서드를 통해 값을 가져오거나 설정
2-1-3. toString() 오버라이딩
@Override
public String toString() {
return "[id=" + id + ", password=" + password + ", name=" + name + ", role=" + role + "]";
}
- 객체의 정보를 문자열로 출력할 때 사용
- 디버깅 또는 로그 출력시 객체의 내용을 쉽게 확인할 수 있도록 도와줌
마지막으로
UserVO클래스는 users 테이블 구조를 그대로 Java 객체로 옮긴 순수 데이터 전달 객체입니다.
비즈니스 로직 없이 데이터를 저장하고 전달하는 역할만 하며, Spring MVC 구조에서 계층간의 데이터 전달과 JSP 출력용 객체로 자주 활용됩니다.
getter/setter 방식은 JavaBean 표준을 따르고 있어 JSP, EL, Spring에서도 문제없이 사용됩니다.
✅ UserDAO.java
package com.springbook.biz.user;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Repository;
import com.springbook.biz.board.JDBCUtil;
@Repository("userDAO")
public class UserDAO {
private Connection conn;
private PreparedStatement stmt;
private ResultSet rs;
private final String USER_INSERT = "INSERT INTO users (id, password, name) "
+ "VALUES (?,?,?)";
private final String USER_DELETE = "DELETE users WHERE id = ? AND password = ?";
private final String USER_GET = "SELECT * FROM users WHERE id = ? AND password = ?";
private final String USER_LIST = "SELECT * FROM users ORDER BY id DESC";
public void insertUser(UserVO vo) {
System.out.println("insertUser 작동");
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_INSERT);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
stmt.setString(3, vo.getName());
stmt.executeUpdate();
System.out.println(vo.getName() + "님의 회원가입이 완료되었습니다.");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(stmt, conn);
}
}
public void deleteUser(UserVO vo) {
System.out.println("deleteUser 작동");
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_DELETE);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(stmt, conn);
}
}
public UserVO getUser(UserVO vo) {
System.out.println("getUser 작동");
UserVO user = null;
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_GET);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
rs = stmt.executeQuery();
if(rs.next()) {
user = new UserVO();
user.setId(rs.getString("id"));
user.setPassword(rs.getString("password"));
user.setName(rs.getString("name"));
user.setRole(rs.getString("role"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.close(rs, stmt, conn);
}
return user;
}
public List<UserVO> getUserList(){
System.out.println("getUserList 작동");
List<UserVO> userList = new ArrayList<UserVO>();
try {
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_LIST);
rs = stmt.executeQuery();
while(rs.next()) {
UserVO user = new UserVO();
user.setId(rs.getString("id"));
user.setPassword(rs.getString("password"));
user.setName(rs.getString("name"));
user.setRole(rs.getString("role"));
userList.add(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.close(rs, stmt, conn);
}
return userList;
}
}
2-2-0. 주요 필드
private Connection conn;
private PreparedStatement stmt;
private ResultSet rs;
- conn : 데이터베이스 연결 객체
- stmt : SQL문을 실행할 수 있는 객체
- rs : SELECT 쿼리 결과를 담는 객체
private final String USER_INSERT = "INSERT INTO users (id, password, name) VALUES (?,?,?)";
private final String USER_DELETE = "DELETE users WHERE id = ? AND password = ?";
private final String USER_GET = "SELECT * FROM users WHERE id = ? AND password = ?";
private final String USER_LIST = "SELECT * FROM users ORDER BY id DESC";
※ 자주 쓰는 쿼리문을 상수로 정의해 코드 중복 방지 및 가독성을 향상합니다.
2-2-1. insertUser(userVO vo) - 회원 가입 처리
conn = JDBCUtil.getConnection();
stmt = conn.prepareStatement(USER_INSERT);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
stmt.setString(3, vo.getName());
stmt.executeUpdate();
- users 테이블에 회원 정보 저장
2-2-2. deleteUser(userVO vo) - 회원 삭제 처리
stmt = conn.prepareStatement(USER_DELETE);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
stmt.executeUpdate();
- 로그인 정보와 일치하는 경우에만 삭제
- 아직 실제로 사용하지 않는 부분
2-2-3. getUser(UserVO vo) - 로그인 시 사용자의 존재 여부 및 정보 확인
stmt = conn.prepareStatement(USER_GET);
stmt.setString(1, vo.getId());
stmt.setString(2, vo.getPassword());
rs = stmt.executeQuery();
if(rs.next()) {
user = new UserVO();
user.setId(rs.getString("id"));
...
}
- 로그인 시 입력한 ID/PW가 DB와 일치하는지 확인
- 일치하면 해당 사용자의 정보를 반환, 아니면 null 반환
2-2-4. getUserList() - 관리자 또는 테스트용 사용자 전체 조회
stmt = conn.prepareStatement(USER_LIST);
rs = stmt.executeQuery();
while(rs.next()) {
UserVO user = new UserVO();
...
userList.add(user);
}
...
return userList;
- id 역순으로 전체 사용자 목록을 반환
- List<UserVO> 형태로 리턴
마지막으로
UserDAO 클래스는 user 테이블을 기반으로 회원의 등록, 삭제, 로그인 조회, 전체 목록 조회를 수행하는 DAO 클래스입니다.
직접 JDBC를 사용하면서도 JDBCUtil을 통해 코드의 중복을 줄이고 안정적인 자원 관리를 실현했으며, @Repository 어노테이션을 통해 Spring 프레임워크와 자연스럽게 연결될 수 있도록 설계되었습니다.
※ 어노테이션이란?
@ 기호로 시작하며, 주석처럼 코드에 추가적인 정보를 표현하는 것을 의미합니다.
주로 컴파일러나 실행 중인 프로그램이 이를 보고 자동처리를 수행합니다.
✅ UserService.java / UserServiceImpl.java
// UserService // 유저 서비스
public interface UserService {
void insertUser(UserVO vo);
void deleteUser(UserVO vo);
UserVO getUser(UserVO vo);
List<UserVO> getUserList();
}
// UserServiceImpl // 유저 서비스 Impl
package com.springbook.biz.user;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
UserDAO userDAO = new UserDAO();
@Override
public void insertUser(UserVO vo) {
userDAO.insertUser(vo);
}
@Override
public void deleteUser(UserVO vo) {
userDAO.deleteUser(vo);
}
@Override
public UserVO getUser(UserVO vo) {
return userDAO.getUser(vo);
}
@Override
public List<UserVO> getUserList() {
return userDAO.getUserList();
}
}
2-3-1. UserService - 서비스 인터페이스
- 인터페이스는 구현을 포함하지 않고, 기능의 목록을 정의합니다.
- 위 코드에서 정의된 기능은 다음과 같습니다.
- insertUser(UserVO vo) : 회원 가입
- deleteUser(UserVO vo) : 회원 삭제
- getUser(UserVO vo) : 회원 1명 조회 (로그인)
- getUserList() : 전체 회원 조회
2-3-2. UserServiceImpl - 서비스 구현 클래스
@Service("userService")
- 이 클래스는 Spring에게 "비즈니스 로직을 처리하는 서비스 객체다" 라고 알려줍니다.
- "userService"는 이 빈의 이름이며, 나중에 필요하면 @Autowired로 주입할 때 사용할 수 있습니다.
// 수업 내용
@Autowired
UserDAO userDAO = new UserDAO();
// 새로운 방법
@Autowired
private UserDAO userDAO;
- Spring이 자동으로 userDAO 객체를 주입합니다.
단, 직접 new userDAO()로 생성하고 있어서 잘못된 사용 방식이라고 합니다.
Spring이 주입하는 객체를 사용하려면 new를 쓰지 않고 "새로운 방법"처럼 선언해야 합니다.
마지막으로
UserService는 사용자 관련 기능들의 계약서 역할을 하는 인터페이스입니다.
UserServiceImpl은 이 계약을 실제로 구현한 클래스이며, 내부적으로 DAO 객체를 호출해 DB 작업을 위임합니다.
@Service와 @Autowired는 Spring에서 자동으로 객체를 등록하고 주입해주는 어노테이션으로, 전체 애플리케이션의 구성 요소를 느슨하게 연결해줍니다.
단, @Autowired 사용 시에는 new UserDAO()를 직접 쓰지 않는 것이 Spring DI 철학에 부합하다고 합니다.
3. 게시판 기능 (Board)
✅ BoardVO.java
게시물 데이터 저장 객체 (seq, title, writer, content, regDate, cnt)
※ 이전 내용과 중복되는 원리로 설명을 간략화 함.
✅ BoardDAO.java
게시글 등록/수정/삭제/조회/목록 기능 구현 (SQL 쿼리 포함)
※ 이전 내용과 중복되는 원리로 설명을 간략화 함.
✅ BoardService.java / BoardServiceImpl.java
게시판 비즈니스 로직 담당, DAO 호출
※ 이전 내용과 중복되는 원리로 설명을 간략화 함.
4. 프론트 컨트롤러 (DispatchServlet.java)
package com.springbook.controller;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.springbook.biz.board.BoardDAO;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.user.UserDAO;
import com.springbook.biz.user.UserVO;
public class DispatchServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public DispatchServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String uri = request.getRequestURI();
String path = uri.substring(uri.lastIndexOf("/"));
System.out.println(path);
// link connect
String login = "/login.do";
String logout = "/logout.do";
String insertBoard = "/insertboard.do";
String updateBoard = "/updateboard.do";
String deleteBoard = "/deleteboard.do";
String getBoardList = "/getboardlist.do";
String getBoard = "/getboard.do";
try {
if (path.equals(login))
loginController(request, response);
else if (path.equals(logout))
logoutController(request, response);
else if (path.equals(insertBoard))
insertBoardController(request, response);
else if (path.equals(updateBoard))
updateBoardController(request, response);
else if (path.equals(deleteBoard))
deleteBoardController(request, response);
else if (path.equals(getBoardList))
getBoardListController(request, response);
else if (path.equals(getBoard))
getBoardController(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
// 로그인 처리
private void loginController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("로그인 처리");
String id = request.getParameter("id");
String pw = request.getParameter("pw");
UserVO vo = new UserVO();
vo.setId(id);
vo.setPassword(pw);
UserDAO userDAO = new UserDAO();
UserVO user = userDAO.getUser(vo);
if (user != null)
response.sendRedirect("getboardlist.do");
else
response.sendRedirect("login.jsp");
}
// 로그아웃
private void logoutController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("로그아웃 처리");
HttpSession session = request.getSession();
session.invalidate();
response.sendRedirect("login.jsp");
}
// 게시글 등록
private void insertBoardController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("글 등록 처리");
request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String content= request.getParameter("content");
String writer = request.getParameter("writer");
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setContent(content);
vo.setWriter(writer);
BoardDAO boardDAO = new BoardDAO();
boardDAO.insertBoard(vo);
response.sendRedirect("getboardlist.do");
}
// 게시글 수정
private void updateBoardController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("글 수정 처리");
request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String content= request.getParameter("content");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setContent(content);
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.updateBoard(vo);
response.sendRedirect("getboardlist.do");
}
//게시글 삭제
private void deleteBoardController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("글 삭제 처리");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.deleteBoard(vo);
response.sendRedirect("getboardlist.do");
}
// 게시글 목록
private void getBoardListController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("글 목록 처리");
BoardDAO boardDAO = new BoardDAO();
List<BoardVO> boardList = boardDAO.getBoardList();
HttpSession session = request.getSession();
session.setAttribute("boardList", boardList);
response.sendRedirect("getboardlist.jsp");
}
// 게시글 상세
private void getBoardController(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("글 상세 처리");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
BoardVO board = boardDAO.getBoard(vo);
HttpSession session = request.getSession();
session.setAttribute("board", board);
response.sendRedirect("getboard.jsp");
}
}
4-0. 구조 및 주요 흐름 설명
- 이 클래스 HttpServlet을 상속받아 HTTP 요청을 처리
- .do로 끝나는 URL이 들어오면 web.xml에서 이 서블릿으로 매핑
4-1. doGet() 메서드
// 메서드
protected void doGet(HttpServletRequest request, HttpServletResponse response) { ... }
// 메서드 내용중에
String uri = request.getRequestURI();
String path = uri.substring(uri.lastIndexOf("/"));
- 클라이언트의 요청 URI를 파악하여 path로 추출
- 각 기능별로 메서드 분기 처리 (if-else문 사용)
- 예시 : /login.do ▶ loginController(request, response) 메서드 사용
4-3. 각 Controller 메서드 설명
✅ loginController()
System.out.println("로그인 처리");
String id = request.getParameter("id");
String pw = request.getParameter("pw");
UserVO vo = new UserVO();
vo.setId(id);
vo.setPassword(pw);
UserDAO userDAO = new UserDAO();
UserVO user = userDAO.getUser(vo);
if (user != null)
response.sendRedirect("getboardlist.do");
else
response.sendRedirect("login.jsp");
- 사용자로부터 입력받은 ID와 비밀번호를 받아 UserDAO.getUser()로 확인
- 일치 시 getboardlist.do로 이동, 실패 시 login.jsp로 다시 이동
✅ logoutController()
System.out.println("로그아웃 처리");
HttpSession session = request.getSession();
session.invalidate();
response.sendRedirect("login.jsp");
- 세션을 초기화해 로그아웃 처리
- 로그인 화면으로 다시 리다이렉트
✅ insertBoardController()
System.out.println("글 등록 처리");
request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String content= request.getParameter("content");
String writer = request.getParameter("writer");
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setContent(content);
vo.setWriter(writer);
BoardDAO boardDAO = new BoardDAO();
boardDAO.insertBoard(vo);
response.sendRedirect("getboardlist.do");
- 글쓰기 폼에서 전달된 제목/작성자/내용을 BoardVO에 담고, BoardDAO.insertBoard() 호출하여 DB에 저장
✅ updateBoardController()
System.out.println("글 수정 처리");
request.setCharacterEncoding("EUC-KR");
String title = request.getParameter("title");
String content= request.getParameter("content");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setTitle(title);
vo.setContent(content);
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.updateBoard(vo);
response.sendRedirect("getboardlist.do");
- seq 번호로 게시글을 수정
- title, content를 변경
✅ deleteBoardController()
System.out.println("글 삭제 처리");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
boardDAO.deleteBoard(vo);
response.sendRedirect("getboardlist.do");
- 특정 게시글 번호(seq)로 게시글 삭제 수행
✅ getBoardListController()
System.out.println("글 목록 처리");
BoardDAO boardDAO = new BoardDAO();
List<BoardVO> boardList = boardDAO.getBoardList();
HttpSession session = request.getSession();
session.setAttribute("boardList", boardList);
response.sendRedirect("getboardlist.jsp");
- 전체 게시글 목록을 DAO에서 가져와서 session.setAttribute("boardList", boardList)로 JSP에 전달
✅ getBoardController()
System.out.println("글 상세 처리");
String seq = request.getParameter("seq");
BoardVO vo = new BoardVO();
vo.setSeq(Integer.parseInt(seq));
BoardDAO boardDAO = new BoardDAO();
BoardVO board = boardDAO.getBoard(vo);
HttpSession session = request.getSession();
session.setAttribute("board", board);
response.sendRedirect("getboard.jsp");
- 특정 게시글 상세보기 (seq로 검색)
- 상세 정보를 JSP에 넘겨서 보여줌
마지막으로
DispatchServlet은 하나의 서블릿으로 모든 .do 요청을 받아, URI에 따라 로그인/로그아웃, 게시글 CRUD 작업을 처리하는 전통적인 MVC 구조의 프론트 컨트롤러입니다.각 기능별로 메서드를 분리하여 깔끔하게 구성되어 있으며, JSP 페이지와 연동하여 사용자에게 결과를 보여주는 방식으로 동작합니다.
5. JSP View
✅ login.jsp : 사용자 로그인 화면
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Login Form</title>
</head>
<body>
<center>
<h1>로그인 화면 구현</h1>
<hr>
<form action="login.do" method="post">
<table border="1" cellpadding="0" cellspacing="0">
<tr>
<td bgcolor="#F0F0F0">아이디</td>
<td><input type="text" name="id" value="12345"></td>
</tr>
<tr>
<td bgcolor="#F0F0F0">비밀번호</td>
<td><input type="password" name="pw" value="12345"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="로그인">
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
5-1-1. JSP 페이지 선언부
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- JSP의 메타 정보
- EUC-KR은 한글 인코딩 (한국어 환경에 맞춤)
- contentType="text/heml"은 클라이언트에게 HTML 문서임을 알리기 위함
5-1-2. HTML 문서 시작
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Login Form</title>
</head>
- HTML 문서의 기본 헤더
- 문자 인코딩을 EUC-KR로 설정 (서버와 동일하게 유지)
- <title></title>은 브라우저 탭 제목을 표시
5-1-3. 로그인 양식(Form)
<form action="login.do" method="post">
- action="login.do" : 로그인 시 요청을 보낼 주소
- 여기서 .do 요청은 DispatchServlet이 받아서 loginController() 실행
- method="post" : 데이터를 URL이 아닌 본문에 포함하여 전송
5-1-4. 입력 필드 구성
<tr>
<td bgcolor="#F0F0F0">아이디</td>
<td><input type="text" name="id" value="12345"></td>
</tr>
<tr>
<td bgcolor="#F0F0F0">비밀번호</td>
<td><input type="password" name="pw" value="12345"></td>
</tr>
- <input type="text"> : 사용자 ID 입력
- name="id" : form에서 제출될 이름 (백엔드에서 request.getParameter("id)로 호출이 가능)
- <input type="password"> : 비밀번호 타입으로 입력
- 입력값은 화면에 표시되지 않음 (ex, testnum → *******)
- value="12345" : 그냥 테스트를 위해 로그인을 빠르게 하기 위함.
5-1-5. 로그인 버튼
<tr>
<td colspan="2" align="center">
<input type="submit" value="로그인">
</td>
</tr>
- 로그인 버튼을 누르면 폼이 전송됨
- submit 버튼은 HTML form 전송의 트리거
5-1-6. 정렬 및 레이아웃
- <center> : 전체 화면을 중앙으로 정렬 (구식으로 추후 CSS 권장)
- <table border="1"> : 입력폼을 테이블 형식으로 구성
- cellpadding="0", cellspacing="0" : 셀 간격 설정
✅ getboardlist.jsp : 전체 게시글 목록 출력 (링크 클릭 시 상세 보기)
<%@page import="java.util.List"%>
<%@page import="com.springbook.biz.board.BoardDAO"%>
<%@page import="com.springbook.biz.board.BoardVO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%
List<BoardVO> boardList = (List) session.getAttribute("boardList");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>게시판</title>
</head>
<body>
<center>
<h1>게시판</h1>
<h3>~님 환영합니다 <a href="logout.do">로그아웃</a>하기</h3>
<form action="getboardlist.jsp" method="post">
<table border="1" cellpadding="0" cellspacing="0" width="700">
<tr>
<td bgcolor="#F0F0F0" width="100" align="center">번호</td>
<td bgcolor="#F0F0F0" width="200" align="center">제목</td>
<td bgcolor="#F0F0F0" width="150" align="center">작성자</td>
<td bgcolor="#F0F0F0" width="150" align="center">등록일</td>
<td bgcolor="#F0F0F0" width="100" align="center">조회수</td>
</tr>
<% for(BoardVO board : boardList){%>
<tr>
<td align="center"><%=board.getSeq() %></td>
<td><a href="getboard.do?seq=<%=board.getSeq() %>">
<%=board.getTitle() %>
</a></td>
<td><%=board.getWriter() %></td>
<td align="center"><%=board.getRegDate() %></td>
<td align="center"><%=board.getCnt() %></td>
</tr>
<%} %>
</table>
<br>
<a href="insertboard.jsp">새글 등록</a>
</form>
</center>
</body>
</html>
5-2-1. JSP 지시어 (Import & Encoding)
<%@page import="java.util.List"%>
<%@page import="com.springbook.biz.board.BoardDAO"%>
<%@page import="com.springbook.biz.board.BoardVO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- import : Java 클래스를 JSP에서 사용하기 위해 import
- List, BoardVO, BoardDAO 클래스 사용
- contentType과 pageEncoding을 EUC-KR로 맞춰 한글이 깨지지 않게 처리
5-2-2. 세션에서 게시글 목록 가져오기
<%
List<BoardVO> boardList = (List) session.getAttribute("boardList");
%>
- DispatchServlet의 getBoardListController()에서 세션에 저장한 게시글 리스트를 받아옴
- 리스트에는 여러 개의 BoardVO 객체가 저장되어 있음
5-2-3. HTML 테이블 형식으로 게시글 출력
<table border="1" cellpadding="0" cellspacing="0" width="700">
- 테이블을 사용해 게시글 목록을 정리
5-2-4. 테이블 헤더 출력
<tr>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
<td>등록일</td>
<td>조회수</td>
</tr>
- 컬럼 헤더 구성
- 배경색은 bgcolor에서 설정
5-2-5. 게시글 목록 반복 출력
<% for(BoardVO board : boardList) { %>
<tr>
<td><%= board.getSeq() %></td>
<td><a href="getboard.do?seq=<%= board.getSeq() %>"><%= board.getTitle() %></a></td>
<td><%= board.getWriter() %></td>
<td><%= board.getRegDate() %></td>
<td><%= board.getCnt() %></td>
</tr>
<% } %>
- for-each문을 통해 각 게시글 정보를 출력
- getboard.do?seq=... : 제목을 클릭하면 해당 글 상세페이지로 이동
- 각 행은 게시글의 번호, 제목, 작성자, 등록일, 조회수로 구성
5-2-6. 기타 UI 요소
<h3>~님 환영합니다 <a href="logout.do">로그아웃</a>하기</h3>
- 상단에 사용자 환영 메세지 ( 현재 로그인한 사용자의 ID나 닉네임 표현은 구현되자 않아 있음)
<a href="insertboard.jsp">새글 등록</a>
- 게시글 작성 폼으로 이동하는 링크
마지막으로
getboardlist.jsp 파일은 서버로부터 전달받은 게시글 목록을 HTML 테이블 형식으로 사용자에게 보여주는 게시판 메인 뷰입니다.
각각의 제목은 링크로 연결되어 있어, 상세 페이지로 이동이 가능하며, 세션을 통해 데이터를 주고 받는 구조입니다.
향후에는 JSTL을 사용하거나, 사용자 이름도 세션에서 받아 표시하는 등 추가 개선이 가능합니다.
✅ getboard.jsp : 게시글 상세 + 수정 + 삭제 기능 포함
<%@page import="com.springbook.biz.board.BoardDAO"%>
<%@page import="com.springbook.biz.board.BoardVO"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<%
BoardVO board = (BoardVO) session.getAttribute("board");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title><%=board.getTitle()%></title>
</head>
<body>
<center>
<h1>글 상세</h1>
<a href="logout.do">로그아웃</a>
<hr>
<form action="updateboard.do" method="post">
<input type="hidden" name="seq" value="<%=board.getSeq()%>">
<table border="1">
<tr>
<td bgcolor="#F0F0F0" width="70">제목</td>
<td><input type="text" name="title" value="<%=board.getTitle()%>"> </td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">작성자</td>
<td><%=board.getWriter()%></td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">내용</td>
<td><textarea rows="10" cols="40" name="content"><%=board.getContent()%></textarea></td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">등록일</td>
<td><%=board.getRegDate()%></td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">조회수</td>
<td><%=board.getCnt()%></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="글 수정">
</td>
</tr>
</table>
</form>
<br>
<a href="insertboard.jsp">글 등록</a>
<a href="deleteboard.do?seq=<%=board.getSeq()%>">글 삭제</a>
<a href="getboardlist.do">목록으로 이동하기</a>
</center>
</body>
</html>
5-3-1. 세션에서 게시글 정보 가져오기
<%
BoardVO board = (BoardVO) session.getAttribute("board");
%>
- DispatchServlet의 getBoardController()에서 세션에 저장한 BoardVO객체를 호출
- 이 객체에는 해당 게시글의 모든 정보(제목, 내용, 작성자 등)가 담겨 있음
5-3-2. HTML + JSP 화면 구성
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title><%=board.getTitle()%></title>
</head>
- 페이지 제목은 해당 게시글의 제목으로 동적으로 설정
- 한글 인코딩은 EUC-KR로 서버와 통일
5-3-3. 게시글 정보 출력 및 수정 폼
<form action="updateboard.do" method="post">
<input type="hidden" name="seq" value="<%=board.getSeq()%>">
- form 태그를 통해 추후에 있을 submit를 작동하면 글을 수정할 수 있음
- action="updateboard.do" : 글 수정 요청을 Servlet으로 보냄
- seq(게시글 번호)는 숨겨진 필드로 전달 → 어떤 글을 수정할지 알 수 있게 해줌
5-3-4. 버튼 및 링크
<input type="submit" value="글 수정">
- 버튼 클릭 시 수정 요청(updateboard.do)으로 전송
<a href="insertboard.jsp">글 등록</a>
<a href="deleteboard.do?seq=<%=board.getSeq()%>">글 삭제</a>
<a href="getboardlist.do">목록으로 이동하기</a>
- 새 글 등록 페이지로 이동
- 현재 글 삭제 요청 (deleteboard.do?seq=...)
- 게시글 목록 페이지로 이동
마지막으로
getBoard.jsp 파일은 사용자가 특정 게시글을 클릭했을 때, 그 글의 내용을 자세히 보여주고, 수정하거나 삭제할 수 있는 뷰(View) 역할을 합니다.
데이터를 세션에서 받아와서 화면에 출력하며, 수정은 POST 방식으로 updateboard.do에 전송됩니다.
전체 MVC 흐름에서 이 JSP는 View 계층이며, Servlet과 DAO가 함께 연동되어 데이터 흐름을 완성합니다.
✅ insertboard.jsp : 새 게시글 작성 폼
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>새 글 작성</title>
</head>
<body>
<center>
<h1>새 글 작성</h1>
<a href="logout.do">로그아웃</a>
<hr>
<form action="insertboard.do" method="post">
<table border="1" cellpading="0" cellspacing="0" >
<tr>
<td bgcolor="#F0F0F0" width="70">제목</td>
<td><input type="text" name="title" value=""> </td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">작성자</td>
<td><input type="text" name="writer"></td>
</tr>
<tr>
<td bgcolor="#F0F0F0" width="70">내용</td>
<td><textarea rows="10" cols="40" name="content"></textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="글 등록">
</td>
</tr>
</table>
</form>
<br>
<a href="getboardlist.do">목록으로 이동하기</a>
</center>
</body>
</html>
5-4-1. JSP 페이지 선언부
<%@ page language="java" contentType="text/html; charset=EUC-KR" pageEncoding="EUC-KR"%>
- 페이지 메타 정보
- contentType="text/html; charset=EUC-KR" : 브라우저에 응답할 문서 유형과 인코딩
- pageEncoding="EUC-KR" : JSP 파일 자체의 문자 인코딩
- 주로 한글 환경에서 인코딩 깨짐을 방지하기 위해 사용
5-4-2. HTML 구조와 제목
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>새 글 작성</title>
</head>
- 브라우저의 제목 표시줄에 새 글 작성 표시
- HTML에서도 EUC-KR 설정 (JSP와 일치)
5-4-3. 본문 구성: <form> 영역
<form action="insertboard.do" method="post">
- 입력된 데이터를 POST 방식으로 전송
- 요청 URL은 insertboard.do ▶ DispatchServlet의 insertBoardControler()가 처리함
5-4-4. 입력 필드 테이블
<table border="1" cellpadding="0" cellspacing="0">
- 이전과 설명이 같음
5-4-5. 폼 외 링크 영역
<a href="getboardlist.do">목록으로 이동하기</a>
- 화면을 중앙 정렬
- HTML5에서는 <center> 태그는 사용이 권장되지 않음, 추후 CSS(text-align:center)로 대체 사용 추천
마지막으로
insertBoard.jsp 파일은 게시판에서 새 글을 작성하는 사용자 인터페이스로, 제목, 작성자, 내용을 입력받아 insertboard.do로 전송하는 폼 기반의 입력 화면입니다.입력된 데이터는 DispatchServlet ▶ BoardDAO로 전달되어 실제 DB에 저장됩니다.전체 게시판 프로젝트의 흐름 중 사용자가 데이터를 생성하는 화면에 해당합니다.
6. Spring 설정 파일
✅ applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:component-scan base-package="com.springbook.biz"></context:component-scan>
</beans>
6-1-1. XML 네임스페이스 선언
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
- xmlns : 기본 네임스페이는 Spring의 <bean> 태그 사용
- xmlns:xsi : XML 스키마 문법 검사용 네임스페이스
- xmlns:context : <context:component-scan>과 같은 context 관련 태그를 사용하기 위함
- xsi:schemaLocation : 각 네임스페이스에 해당하는 스키마 문서의 실제 위치 지정 (버전 4.3 사용중)
6-1-2. 패키지 스캔
<context:component-scan base-package="com.springbook.biz"></context:component-scan>
- com.springbook.biz 패키지를 기준으로 하위 모든 패키지를 스캔
- 예시로
- @Repository("userDAO") → UserDAO 자동 등록
- @Service("userService") → UserServiceImpl 자동 등록
- @Component("boardDAO") → 자동 등록 가능 ( 현재는 다른 것 사용 중)
마지막으로
applicationContext.xml은 Spring 애플리케이션에서 어노테이션 기반 빈 등록을 가능하게 해주는 설정 파일입니다.
현재 설정된 <context:component-scan> 태그는 com.springbook.biz 하위에 있는 모든 클래스를 스캔하여 @Service, @Repository 등의 어노테이션이 붙은 클래스를 자동으로 Bean으로 등록하게 해줍니다.
이로써 개발자는 XML 설정 없이도 객체 생성과 의존성 주입을 간결하게 처리할 수 있게 됩니다.
✅ web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<description></description>
<display-name>action</display-name>
<servlet-name>action</servlet-name>
<servlet-class>com.springbook.controller.DispatchServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
6-2-0. 전체 구조 요약
- web-app : 이 애플리케이션의 웹 컨테이너 설정의 시작
- version="2.5" : Java EE 5 기반의 설정 방식 (Spring 3.x~4.x에서 자주 사용)
6-2-1. <servlet> 태그 설명
<servlet>
<description></description>
<display-name>action</display-name>
<servlet-name>action</servlet-name>
<servlet-class>com.springbook.controller.DispatchServlet</servlet-class>
</servlet>
- <description> : 서블릿 설명 (비워 있어도 무방)
- <display-name> : 서블릿 표시 이름 (관리용, UI에 표시할 수 있음)
- <servlet-name> : 이 서블릿의 이름, 매핑할 때 참조됨
- <servlet-class> : 실제 실행될 서블릿 클래스의 전체 경로
6-2-2. <servlet-mapping> 태그 설명
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
- <servlet-name> : 위에서 등록한 서블릿 이름과 매칭
- <url-pattern> : 어떤 요청 URL을 이 서블릿이 처리할지 설정
- 모든 .do로 끝나는 요청은 DispatchServlet이 처리하게 됨
6-2-3. 핵심 개녕 : Front Controller 패턴
브라우저 요청: login.do
↓
web.xml: *.do → DispatchServlet 매핑
↓
DispatchServlet: 각 기능 별 메서드 호출
↓
DAO/Service 호출 → 결과 반환
↓
JSP로 포워딩
마지막으로
web.xml은 웹 애플리케이션의 서블릿 설정 파일로, DispatchServlet이라는 클래스를 서블릿으로 등록하고, .do로 끝나는 모든 요청을 해당 서블릿이 처리하도록 매핑합니다.
이를 통해 로그인, 게시판 작성, 수정, 조회 등 모든 기능을 하나의 진입점으로 집중 처리할 수 있으며, 이는 전통적인 MVC 구조의 핵심 패턴인 Front Controller를 구현하는 설정입니다.