티스토리 뷰
스프링의 기본적인 실행 구조를 간단한 게시판 서비스를 구성하며 순차적으로 알아보자.
1.
우선 프로젝트를 만들고 나서 요청에 따른 controller를 자동 호출하기 위한 DispatcherServlet을 web.xml 문서에 추가해줘야 한다.
◎WEB-INF.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>spring_simple_board</display-name>
<!-- DispatcherServlet 등록 -->
<servlet>
<servlet-name>board</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>board</servlet-name>
<url-pattern>*.do</url-pattern> <!-- 모든 요청사항 뒤에 .do가 붙으면 DispatcherServlet을 사용해! -->
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
이때, servlet의 이름은 dispatcher가 자동으로 찾기 때문에 위와 같이 이름을 작성했다면, servlet.xml은 반드시
board-servlet.xml 과 같이 생성해야 한다.
2.
board-servlet.xml 파일을 생성하고, 해당 문서가 HandlerMapping과 ViewResolver 기능을 수행할 수 있도록 각각 등록해줘야 한다.
◎WEB-INF.board-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 요청에 따른 컨트롤러 반환 담당 : /list.do -->
<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- viewResolver(위치, 이동할 페이지 지정) : "list" -->
<bean id="viewResolover" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
<property name="prefix" value="/"/> <!-- "/list" -->
<property name="suffix" value=".jsp"/> <!-- "/list.jsp" -->
</bean>
</beans>
3.
JNDI를 이용해서 DB를 연동해야 하기 때문에, 해당 DB의 정보를 DAO에서 사용할 수 있도록 Context.xml 파일을 작성해야 한다.
◎META-INF.Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/orcl"
auth="container"
type="javax.sql.DataSource"
username="SPRING_EX"
password="1234"
driverClassName="oracle.jdbc.driver.OracleDriver"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
url="jdbc:oracle:thin:@localhost:1521:XE"
maxActive="20"
maxIdle="10">
</Resource>
</Context>
4.
이제 생성한 Context.xml 파일을 이용하여 Connection 객체를 생성하여 이용하기 위한 DAO를 작성한다.
전체적인 흐름을 알아보는 예제이기 때문에 상세 메서드 & DTO 는 기술하지 않겠다.
중요한 점은 DB를 제어하는 각각의 메서드에서 Connection 객체를 생성자에서 선언한 ds 맴버 변수를 이용하여 생성한다는 점이다.
◎BoardDAO.java
package com.choonham.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import javax.naming.InitialContext; // InitialContext implements Context
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.choonham.command.BoardCommand;
import com.choonham.dto.BoardDTO;
public class BoardDAO {
DataSource ds;
//DataSource 객체는 getConnection() 과 동일한 역할을 담당한다.
public BoardDAO() {
// Context 객체 얻기 : Context.xml 문서에서 name = "jdbc/orcl" 속성 값을 추출
// 방법 : InitialContext 객체를 이용(해당 객체가 가지고 있는 lookUp() 을 통해 name 속성 값을 추출할 수 있다.
// 단, jdbc/orcl을 찾기 위해서는 java:comp/evn/jdbc/orcl 와 같이 적어야 한다.
try {
InitialContext ctv = new InitialContext();
ds = (DataSource)ctv.lookup("java:comp/env/jdbc/orcl");
} catch (NamingException e) {
e.printStackTrace();
}
}
/** 글 목록 조회 **/
public ArrayList<BoardDTO> list() {
//생략
}
/** 새 글에 대한 글 번호를 위한 메서드 **/
public int getNewNum() {
//생략
}
/** 글 저장 메서드 **/
public void write(BoardCommand data) {
//생략
}
}
5.
작성한 DAO를 board-servlet.xml 에 등록해야지만 사용할 수 있기 때문에 등록해준다.
◎WEB-INF.board-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 요청에 따른 컨트롤러 반환 담당 : /list.do -->
<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- DB 접속 : JNDI 방식 -->
<bean id = "boardDAO" class = "com.choonham.dao.BoardDAO"></bean>
<!-- viewResolver(위치, 이동할 페이지 지정) : "list" -->
<bean id="viewResolover" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
<property name="prefix" value="/"/> <!-- "/list" -->
<property name="suffix" value=".jsp"/> <!-- "/list.jsp" -->
</bean>
</beans>
6.
이후 실제 기능을 구현할 컨트롤러를 작성해줘야 한다.
Spring 프레임워크에서 컨트롤러가 요청을 받아 자동적으로 어떤 메서드를 수행하게 하기 위해서는 반드시
ModelAndView() 메서드를 사용해야하는데, 이는 org.springframework.web.servlet.mvc.Controller를 구현 받거나
spring프레임워크에서 제공하는 다른 컨트롤러를 상속받아야 한다.
◎ListActionController.java 는 아래와 같이 따로 인터페이스를 구현받아 작성했다.
◎ListActionController.java
package com.choonham.controller;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import com.choonham.dao.BoardDAO;
import com.choonham.dto.BoardDTO;
public class ListActionController implements Controller {
private BoardDAO dao;
public void setDao(BoardDAO dao) {
this.dao = dao;
System.out.println("setDao() 호출 : " + dao);
}
public ListActionController() {
// TODO Auto-generated constructor stub
}
/** 요청사항이 전달되면 자동 호출되는 메서드 **/
@Override
public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
System.out.println("ListActionController의 handleRequest() 자동호출 ");
ArrayList<BoardDTO> list = dao.list();
ModelAndView mav = new ModelAndView();
mav.setViewName("list"); // list.jsp 를 의미
mav.addObject("list", list); // request.setAttribute("list", list); 개념
return mav;
}
}
또한 글 쓰기 기능을 담당하는 ◎WriteActionController.java 의 경우, 아래와 같이 AbstractCommandController 를 상속 받았다.
◎WriteActionController.java
package com.choonham.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;
import com.choonham.command.BoardCommand;
import com.choonham.dao.BoardDAO;
/** AbstractCommondController를 상속 받은 이유
* 사용자가 입력한 값을 외부로부터 자동으로 전달받기 위해
* 요청시 자동으로 호출되는 handle()의 매개 변수의 역할
* HttpServletRequest : request 객체 (요청 객체)
* HttpServletResponse : response 객체 (응답 객체)
* Object : 입력받은 값을 저장하는 객체
* BindException : 전달 받을 값에 대한 오류를 예외처리
*
* 따라서 이 컨트롤러 등록시, 입력 받은 값을 저장할 수 있는 객체가 필요하고,
* 객체는 commandClass 변수를 통해 자동 전달한다.
* **/
public class WriteActionController extends AbstractCommandController {
private BoardDAO dao;
public void setDao(BoardDAO dao) {
this.dao = dao;
System.out.print("dao 호출" + dao);
}
@Override
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException error)
throws Exception {
BoardCommand data = (BoardCommand) command;
// BoardDAO의 write() 메서드에게 data 객체를 전달
dao.write(data);
// 기존 방식
// String t = request.getParameter("t");
// Spring 방식 : ModelAndView객체 사용
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/list.do");
return mav;
}
}
7.
마지막으로 생성한 각각의 컨트롤러들을 board-servlet.xml에 등록해주면 해당 요청이 들어왔을 때, 자동으로 파라미터를 맵핑하고, 기능을 수행하는 구조가 완성이 된다.
◎WEB-INF.board-servlet.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 요청에 따른 컨트롤러 반환 담당 : /list.do -->
<bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- DB 접속 : JNDI 방식 -->
<bean id = "boardDAO" class = "com.choonham.dao.BoardDAO"></bean>
<!-- 글 목록 보기 컨트롤러 등록 : private dao => setDao(boardDAO) -->
<bean name = "/list.do" class = "com.choonham.controller.ListActionController">
<property name = "dao">
<ref bean = "boardDAO" />
</property>
</bean>
<!-- 글 쓰기 화면 처리 컨트롤러 등록 : 스프링이 제공 -->
<bean name = "/writeui.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController"> <!-- 파라미터 없이 뷰를 내보내주는 spring 클래스 -->
<property name = "viewName" value = "write"></property>
</bean>
<!-- 글 저장 처리 컨트롤러 등록 -->
<bean name = "/write.do" class = "com.choonham.controller.WriteActionController">
<property name = "dao">
<ref bean = "boardDAO"/>
</property>
<property name = "commandClass" value = "com.choonham.command.BoardCommand"></property>
</bean>
<!-- viewResolver(위치, 이동할 페이지 지정) : "list" -->
<bean id="viewResolover" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/>
<property name="prefix" value="/"/> <!-- "/list" -->
<property name="suffix" value=".jsp"/> <!-- "/list.jsp" -->
</bean>
</beans>
화면 구성은 다음과 같이 간단하게 구성했다.
◎index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
response.sendRedirect("http://localhost:9000/spring_simple_board/list.do");
%>
◎list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import = "java.util.ArrayList, com.choonham.dto.BoardDTO" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>list</title>
</head>
<body>
<table border = "1">
<tr>
<td colspan = "5">게시판 목록
<a href = "writeui.do">글 쓰기</a>
</td>
</tr>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
<!-- DispatcherServlet은 Controller 로부터 ModelAndView 객체를 받고
그 중 model 에 해당하는 객체를 list.jsp의 request에게 전달
따라서 list.jsp 는 request의 attribute 영역에서 해당 객체를 추출하여 사용 가능
-->
<%
ArrayList<BoardDTO> list = (ArrayList)request.getAttribute("list");
if(list != null) {
for(BoardDTO dto:list){
int num = dto.getNum();
String title = dto.getTitle();
String author = dto.getAuthor();
String writeday = dto.getDate();
int readcnt = dto.getReadcnt();
%>
<tr>
<td><%= num %></td>
<td><a href = "retrieve.do?num=<%= num %>"><%= title %></a></td>
<td><%= author %></td>
<td><%= writeday.substring(0, 10) %></td>
<td><%= readcnt %></td>
</tr>
<%
}
}
%>
</table>
</body>
</html>
◎write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>write.jsp</title>
</head>
<body>
<form action = "write.do">
<table>
<tr>
<td>제목</td>
<td>
<input type = "text" name = "title" />
</td>
</tr>
<tr>
<td>작성자</td>
<td>
<input type = "text" name = "author" />
</td>
</tr>
<tr>
<td>내용</td>
<td>
<textarea rows = "5" cols = "30" name = "content"></textarea>
</td>
</tr>
<tr>
<td colspan = "2">
<input type = "submit" value = "저장" />
</td>
</tr>
</table>
</form>
</body>
</html>
결과 페이지는 다음과 같이 정상적으로 작동하는 걸 확인할 수 있다.
데이터의 흐름을 눈으로 따라가기가 지금은 좀 힘들지만, 대부분의 업무를 자동으로 맵핑하여 처리해주는 점이 익숙해지면 굉장히 편리할 거 같다.
... 일단 디버깅이 굉장히 어려워진 거 같으니, 최대한 집중해서 코드를 작성해야할 거 같다.
'[JAVA] > Spring' 카테고리의 다른 글
[Spring] 스프링의 DI(Dependency Injection) 의존성 주입 (0) | 2021.06.14 |
---|---|
[Spring] Spring 게시판 예제 마무리 & 구조 정리 (0) | 2021.06.14 |
[Spring] JNDI 을 이용한 DB 연결하기 (0) | 2021.06.10 |
[Spring] spring.xml 문서 작성 (0) | 2021.06.10 |
[Spring] web.xml 문서에 Servlet 등록 (0) | 2021.06.10 |
- 인천 구월동 맛집
- react
- Promise
- AsyncStorage
- 이탈리안 레스토랑
- 파니노구스토
- Async
- javascript
- 인천 구월동 이탈리안 맛집
- react-native
- redux
- 맛집
- await
- redux-thunk
- 정보보안기사 #실기 #정리
- Total
- Today
- Yesterday