service계층
: 완충작용
직접 DAO를 쓰는 것이 아니라 service 계층을 통한다.
package com.springbook.view.board;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;
import com.springbook.biz.board.impl.BoardDAO;
/*
@SessionAttributes
Request요청중에 board라는 이름의 객체가 Model에 저장되어있으면
그것을 Session에 저장해라
*/
@Controller
@SessionAttributes("board")
public class BoardController {
@Autowired
private BoardService boardService;
// RequestMapping보다 먼저 적용되어서 아래 Map객체는 자동으로 Model에 저장되고
// 화면 이동시 전달되게 된다
@ModelAttribute("conditionMap")
public Map<String, String> searchConditionMap(){
Map<String, String> conditionMap = new HashMap<String, String>();
conditionMap.put("제목", "TITLE");
conditionMap.put("내용", "CONTENT");
return conditionMap;
}
@RequestMapping("/insertBoard.do")
public String insertBoard(BoardVO vo) {
boardService.insertBoard(vo);
return "getBoardList.do";
}
// @ModelAttribute("board") BoardVO vo
// board 이름의 객체를 찾아서 vo에 값을 담아줘
@RequestMapping("/updateBoard.do")
public String updateBoard(@ModelAttribute("board") BoardVO vo) {
System.out.println(vo);
boardService.updateBoard(vo);
return "getBoardList.do";
}
@RequestMapping("/deleteBoard.do")
public String deleteBoard(BoardVO vo) {
boardService.deleteBoard(vo);
return "getBoardList.do";
}
@RequestMapping("/getBoard.do")
public String getBoard(BoardVO vo, Model model) {
model.addAttribute("board", boardService.getBoard(vo));
return "getBoard.jsp";
}
@RequestMapping("/getBoardList.do")
public String getBoardList(@RequestParam(value="searchCondition",
defaultValue="TITLE", required=false) String condition,
@RequestParam(value="searchKeyword",
defaultValue="", required=false) String keyword
, BoardVO vo, Model model) {
System.out.println("검색 조건 : " + condition);
System.out.println("검색 단어 : " + keyword);
model.addAttribute("boardList", boardService.getBoardList(vo));
return "getBoardList.jsp";
}
}
그런데 boardService는 bean이 아니므로 no such bean이라는 오류가 발생한다.
해결방법에는 세가지가 있다.
1. 직접 대입
2. 경로 추가
service를 빈으로 만들던 applicationContext 파일을 presentation-layer 파일에 통합
-> 디스패처서블릿이 presentation 파일을 읽어 bean들을 생성하도록 기존의 application context파일을 presentation파일에 합친다
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- annotation을 읽어서 bean을 생성 ( springbook.view 패키지의 컴포넌트들을 스캔해서 bean 생성 ) -->
<context:component-scan base-package="com.springbook.view"></context:component-scan>
<context:component-scan base-package="com.springbook.biz" />
<!-- AOP 어노테이션 자동 인식 설정 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<context:property-placeholder
location="classpath:config/database.properties"/>
<!-- DataSource 설정 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Transaction 설정 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- Transaction Advice 설정 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut"
expression="execution(* com.springbook.biz..*(..))"/>
<aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice"/>
</aop:config>
</beans>
biz패키지의 파일도 bean으로 만들게 된다
@Autowired 살리기
3. contextLoaderListener 이용
presentation파일을 원래대로 돌린다.
합쳐진 파일이라면 상관없지만, 파일이 다를 때는 board controller가 생성되려면 boardservice bean이 먼저 만들어져야 한다. 그럴 때 사용하기 좋은 것이 ContextLoaderListener이다.
web.xml
정리
two layer 아키텍쳐 (규모가 커지면 분리할 필요성이 생길 때 쓸 수 있다)
bean을 만드는 파일에는 2가지가 있었다.
application 파일과 presentation파일.
차이점 : 전자는 기존의 db, business, service와 같은 기본 객체들을 넣어놓은 곳
후자는 사용자 요청에 따른 controller를 주로 준비하는 곳