Spring EJB 기반으로 개발을 하지 않고, POJO(Plain old java Object)기반으로 개발을 하더라도 가볍고,
제어가 간으한 상호 관련이 적은, AOP을 지원하고, 컴테이너를 통해 라이프 사이클을 관리하고,
XML기반으로 컴포넌트를 개발할수 있도록 지언해주는 Framework이다.
AOP, DI -- Spring 의 특징 : J2EE 를 대체하는 프레임워크로 자리 잡고 있다.
서버측 개발에만 국한되지 않는 모든 Java Applicaiton개발에 활용할수 있다.
단순성, 테스트 용이성, 느슨한 결합성(DI)을 보장받을수 있다.
객체의 라이프 사이클을 관리하기 위햐여 DI를 사용하는 경량 컨테이너
자바 객체의 생성, 소멸과 같은 라이플 사이클을 관리한다.
DI(Dependency Injection) 패턴을 지원한다.
(스프링은 설정 파일을 통해서 객체간이 의존 관계를 설정할수 있도록 하고있다. 따라서 객체는 직접
의존하고 있는 객체를 생서하거나 검색할 필요가 없다.
스프링은 AOP(Aspect oriented Programming)를 지원한다.
(스프링은 자체적으로 AOP를 지원하고 있기 때문에, 트랜잭션이나, 로깅, 보안과 같이 여러 모듈에서
공통으로 필요로 하지만 실제 모듈이 핵심은 아닌 기능들을 분리해서 각 모듈에 적용할 수 있다.
스프링은 POJO(Plain Old Java Object)를 지원한다.
(간단한 자바객체를 가지고도, 구현할수 있다. 특정한 인터페이스를 구현하거나, 상속받을 필요가 없다.)
트랙젝션 처리를 위한 일관된 방법을 제공한다.
JDBC를 사용하든, JTA 를 이용하든 컨테이너가 제공하는 트랜잭션을 사용하든,
설정파일을 통해 트랜잭션 관련정보를 입력하기 때문에 트랜잭션 구현에 상관없이
동일한 코드를 여러 환경에서 사용할수 있다.
영속성과 관련된 다양한 API를 지원한다.
스프링은 JDBC를 비록한 i-BATS, 하이버네이트, JPA, JDO등 데이터베이스 처리와
관련하여 널리 사용되는 라이브러리와의 연동을 지원하고 있다.
다양한 API 에 대한 연동을 지원한다.
Spring의 구조
Core : DI기능을 제공
Context: 컨텍스트라는 정보를 제공하는 설정을 관리한다. JNDI, EJB, 국제화, 스케줄링이 여기에 포마
DAO: DB와 관련된 JDBC 코딩부분을 처리해 주기 위한 JDBC추상화 레이어 제공.
ORM :JDO, Hibernates, iBATS등 O-R Mapping API를 위한 레이어 제공
AOP : 관점 지향 프로그래밍을 제공.
Web : 웹 기반의 여러가지 기능을 제공
Web MVC: Model과 View(Web form) 사이의 구분을 제공하기 위한 관련된 기능을 제공
필요한 준비물들
Eclipse
http://www.eclipse.org
Oracle10g
Tomcat
http://www.apache.org
jdk1.5이상
Spring Framework
http://www.springsource.org
spring-framework-2.5.5-with-dependencies.zip다운로드
spring-framework-2.5.5-with-docs.zip다운로드
웹서버를 실행하기위한 이클립스 세팅
이클립스 적당한 위치에다가 실행
Spring2.5에 압축을 품.(절대로 한글폴더에 풀지 말것)
워크 스페이스를 Spring2.5폴더에 Webapp 폴더에 푼다.
web- dynamic Web Project
jsp에서 실행하면.. apache하고 버젼 선택하고, 실제 톰캣의 경로를 선택해주고
<script type="text/javascript">
location.href="Hello.jsp";
</script>
spring 압축을 풀고, dist/spring.jar, modules /spring-webmvc.jar, ./lib/jakarata-commns/commons-logging.jar 를 워크스페스에 lib폴더에 넣는다.
web.xml을 통해서, spring에서 기본적인 클래스 core를 가져다 써야 한다. 이걸 wiring이라고 한다.(객체와 객체를 연결해야 한다.)
web-inf/web.xml에다가 Spring의 기본 클래스를 적어야 한다. document열어보면..방법이 나와있다.
docs/mvc-step-by-step가 잇는데, 거기 안에pdf파일이 있따..
web.xml in the..머로 시작하는.. 곳으로 가서..
그곳에 web.xml 에 잇는 내용을 추가하고,
<servlet> 노드랑
<servlet-mapping> 노드를 추가한다. *.htm 은 html파일을 열때 스프링을 쓴다는 말 do라는 확장자로 바꿈
index.jsp를
<script type="text/javascript">
location.href="Hello.do";
</script>
java class 를 생성하고, springweb.web 패키지 안에 HelloController 상속을하고 인터페이스를 구현해야 한다. controller라는 인터페이스를 구현해야 한다.
controller 를 오버라이딩 하면.. 기본적인 오버라이딩이 나온다.(다른 방법은 AbstractController를 상속 받는 방법도 있다.)
servlet api 도 잡아줘야 한다... 그래서 이걸 추가할려면.. 프로젝트에 빌드 패스로 가서,
(servlet라이브러리는 톰캣이 제공해준다. tomcat/lib/servlet-api를 libraries탭에 add external jar를 해가지고 추가한다.)
(모델을 처리해서, 뷰에게 넘긴다.)
handleRequest 를 메서드안에, HttpServletRequest req, HttpServletResponse res 로 파라미터를 바꾸고
req.setAttribute("name","홍길동"); 그리고 null값을 리턴하는것이 아니고, new ModelAndView("")//어느페이지로 이동할지
wiring 작업을 하나의 xml을 만드는데 그냥 만드는 것이 아니고,
이름을 내맘데로 만드는것이 아니고, web.xml 에 springapp 이름을 이용해가지고
springapp-servlet.xml로 만들어야 한다.
다큐멘트에서 spring-servlet.xml샘플을 복사한다. (web.xml에, 똑같은 파일을 넣는다.)
<bean name="/Hello.do" class="springweb.web.HelloController"/>//servlet을 맵핑한다.
ModelAndView mav = new ModelAndview();
mav.setViewName("Hello.jsp"")//어떤 페이지로 이동할것인가..
mav.addObject("name","홍길동"); // 이렇게 해서 request뿐만 아니라, 이렇게 파라미터도 보낼수 있다.
return mav;
hello.jsp에다가 request객체의 내용을 뿌릴려면은 EL 로 해가지고,<br>${requestScope.name} 해가지고 뿌릴수 있다.<%=request.getAttribute("name")%> 으로 해도 된다.
----------------------------------------------------------------------------
db연결
아파치에서 제공하는 DBCP API 를 이용(톰캣에 들어있다 tomcat/lib/tomcat-dbcp.jar파일이있다..)
JNDI를 이용함 (네이밍 서비스, 내가 원하는 서비스를 찾아서 이용 이용)
설정방법
이클립스에 servers에, server.xml 에 (tomcat/webapps/docs/index.html(도움말)에 tomcat standard Resource Factories 에 JDBC Data Source에 Configure tomcat`s Resource Factory 에 내용이 나와있다.)
이걸 복사해가지고, Global JNDI resources 에 주석이 있는데, GlobalNamingResources 노드에 넣는다.
name=jdbc/이름 아무거나
username과, password설정하고,
driverClassName = "oracle.jdbc.driver.OracleDriver"(Orace Doc에 나와있음)
url="jdbc:oracle:thin:@localhost:1521:XE(Orace Doc에 나와있음)
maxActive=최대연결수
포트번호를 확인(programfiles/oraclexe/app/product/10.2.0/server/network/ADMIN/tnsnames.ora)
드라이버는 (programfiles/oraclexe/app/product/10.2.0/server/jdbc/lib/에 모든 jar파일을
톰캣에 설치된 폴더에 lib에 복사를 한다.
test_jndi.jsp를 만들고
<@ page import="javax.naming.InitialContext"%>
<@ page impor="java.sql.Connection" %>
<@ page impor="java.sql.Statement" %>
<@ page impor="java.sql.ResultSet" %>
<%
InitialContext ctx = new InitialContext();//InitialContext 에서 검색 객체를 만든다.
Object obj = ctx.lookup("java:comp/env/jdbc/SpringDB");// SpringDB 는tomcat 에 아까 추가한 name과 같아야 한다. 검색을 한다.
if(obj !=null){
javax.sql.DataSource ds = (javax.sql.DataSource)obj;
Connection Con = ds.getConneciton();
Statement stmt = Con.createStatement();
String sql = " select * from board";
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){
out.println(rs.getString(1) + "<br/>);
}
stmt.close();
Con.close();
}else{
out.println("검색실패!");
}
%>
index.jsp를 만들고,
게시판 테스트라고 만들고 tomcat재부팅하고,
실행하고, 이클립스에 servers에 server.xml 밑에 보면, <Context docBase라고 새로 생성이 되는데,
<Context doc...>
</Context> 라고 만들고..
가운데다가 <ResourceLink name="jdbc/SpringDB" global="jdbc/SpringDB" type="java.sql.DataSource"/>라고 등록하고
test_jndi.jsp를 실행한다.
--------------------------------------------------------------------------------
게시판 만들기
wei-inf/lib/ commons-loggin.jar, spring-webmvc.jar, spring.jar 를 넣는다.
web.xml 에
<servlet>
<servlet-name>springapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springapp</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
을 추가한다.
스프링 MVC의 개요
요청을 처리하기 위해 컨트롤러를 선택하는 방법과 결과를 보여주기 위한 뷰를 선택하는 방ㅎ식간에
낮은 결합도를 유지하고 있다는 점이 무엇보다 중요하다.
스프링 MVV 의 라이프사이클
요청===>dispatcher servlet(web.xml에서 씀 Front Controller담당) ==> Handler Mapping(어떤 컨트롤러에게 이 요청을 맞길것인가.)
==> controller(서비스 모델에서 처리하고.) ==>ModelAndView(모델과 뷰를 통합해서 가지고 다님) 이걸 다시 Dispatcher servlet로 넘겨주고
dispatcher servlet 은 ViewResolve 는 어떤 뷰에 넘길지.. 선택하고.. 이것을 View에 넘긴다.
dispatcher에서 설정한 springapp에다가 -servlet.xml로 환경설정을 할수 있다.
1.. Dispatcher-servlet
보안계층, 웹계층, 서비스 계층, 퍼시스턴스계층으로 xml을 나눌것을 권함
서블릿명-security.xml
서블릿명-servlet.xml
서블릿명- service.xml
서블릿명-data.xml(퍼시스턴스계층..은 디비와 관련된 계층)
여러개의 xml을 모두 읽어들일려면..
web.xml에 컨텍스트 로더를 구성해야 한다
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
를 통해서
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/서블릿명-service.xml.....
</paran-value>
</context-param>
springapp-servlet.xml 을 만든다
메인페이지 index.jsp로 만든다.
<h2>게시판 테스트</h2>
<hr></hr>
<a href="board_list.do">게시판 목록으로 가기</a>
WebContent/board폴더에 게시판을 만든다.
list.jsp 를 만든다.
컨트롤러를 만드는데.. 클래스로.. (컨트롤러 종류에는 많다.) 컨트롤러가..다 처리하는건.. 않좋은 예다..
package.springapp.web
BoardController class로 만든다..
public springapp.web
class BaordController extents AbstractController {//컨트롤러에 역할을 수행하기 위해api를 보면.. (Spring2.5/docs/api/index.html) org.springframework.web.servlet.mvc에 controller 인터페이스가 있음 자식들이..컨트롤러의 종류..
protected abstract ModelAndView handleRequestInternal(HttpServletRequest arg0, //리턴값은 어떤 컨트롤러든.. 모두 모델앤 뷰이다.
HttpServletResponse arg1) throws Exception {
ModelAndView mav= new ModelAndView();
mav.setViewName("board/list.jsp"); //ViewResolve를 이용하기 위해서는 여기다가 절대 경로를 넣는것이 아니라, xml설정파일을 통해서 해야 올바른 방법이다.
mav.addObject("board","이것은 게시판 테스트이다.");//모델을 여기다가 넣는다.(즉, 파라미터들..) Request영역에 저장된다.
return mav;
}
}
위에 것이 완성되면springapp-servlet.xml 에
<bean name="/board_list.do" class="springapp.web.BoardController"/>
가..들어간다.
list.jsp에다가
테스트 : ${requestScope.board}
를 넣는다.
web.xml에..
위에서 배운..
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
를 통해서
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-servlet.xml.....
</paran-value>
</context-param>
를 넣는다.
컨트롤러에서 모든 일을 하지 않고, 일처리는 서비스라는 곳에서 한다. 모델의 역할을 하는것이 서비스에서 처리한다.
모델에 해당되는 클래스를 만든다.
package: springapp.dao
BoardDao
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.DataSource;
public class BoardDao{
private DataSource ds ;
public void setDataSource(DataSource ds){
this.ds = ds;
}
public int count()throws Exception{
int result = -1;
Conneciton con = null;
Statement stmt = null;
try{
con = ds.getConnection();
stmt = con.createStatement();
String sql = "select count(*) CNT from board";
ResultSet rs = stmt.executeQuery(sql);
rs.next();
result = rs.getInt("CNT");
}catch(){
}finally{
close(conn,stmt);
}
return result;
}
private void close(Conneciton con, Statement stmt){
try{
if(con != null)con.close();
}catch(Exception err){
}
try{
if(stmt != null)stmt.close();
}catch(Exception err){
}
}
}
springapp-servlet.xml에 가가지고 서비스를 등록하기 위해
<bean name="/board_list.do" class="springapp.web.BoardController">
<property name="boardDao" ref="boardDao"></propery>
</bean>
<bean id="boarddao" class="springapp.dao.BoardDao">//객체를 생성해서 로드를 할수 있게.
<property name="dataSource" ref="dataSource"></propery>//boardDao/setDataSource를 쓴다.
</bean>
<bean id="dataSource" class="org.springframeworkd.jndi.JndiObjectFactoryBean">//dbcpapi를 이용하는 객체 가져오기
<property name="jndiName" value="jdbc/SpringDB"></property> tomcat에 server.xml에 name과 동일 //프로퍼티를 이용해가지고.. 값을 넘길수 있따
<property name="resourceRef" value="true"></property> //톰캣에 등록되어 잇는 애를 가져다 쓰겟다..
</bean>
BoardController.java에다가
import springapp.dao.BoardDao;
//boarddao객체를 넘겨받기 위한
private BoardDao boardDao;
public void setBoardDao(BoardDao dao){
boardDao = dao;
}
그리고 handleReuqestInternal함수에다가
mav.addObject("boardCount", new Integer(boardDao.count());
list.jsp에서는
글의 총갯수 : ${boardCount}
BoardController.java에서 mav.setViewName에서 url을 직접 지정하는건 올바르지 않다..
viewReolver을 이용할려면 InternalViewResolver을 이용해가지고 할수 있다 (뷰를 벨로시티나, jsf로 사용할수도 있다.. jsp도 그렇고)
mav.setViewName("board/list.jsp");를 환경변수로...
mav.setViewName("list")로 바꾸고..
springapp-servlet.xml에
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResouceViewResolver">
<property name ="prefix"> //간단하게 접두사를 붙일수 있다.
<value>/board/</value>
</propery>
<property name ="suffix"> //간단하게 접두사를 붙일수 있다.
<value>.jsp</value>
</propery>
</bean>
----------------------------------------
JDBC Templete(db쿼리를 간단하게 사용할수있다. 자원관리도.. 다 해준다.) --
spring-servlet.xml에다가
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.jdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
package springapp.dao;
public class jdbcTemplateBoardDao{ //예외 처리나 보완관련.. 모든걸.. 다 해결해준다.
private jdbcTemplate jdbcTemplate;
public void setjdbcTemplate(jdbcTemplate temp){
jdbcTemplate= temp;
}
public int count() throws Exception{
return jdbcTemplate.queryForInt("select count(*) from board");
}
}
springapp-servlet.xml로 가서
<bean id="boarddao" 를 주석하고
<bean id="boarddao" class="springapp.dao.jdbcTemplateBoardDao">
<propery name="jdbcTemplate" ref="jdbcTemplate"></propery> //이러면 setJebcTemplete를 실행한다.
</bean>
그리고 boardController.java를
private BoardDao boardDao;
public void setVBoardDao(BoardDao){
boardDao = dao;
}
를 주석하고
private jdbcTemplateBoardDao boardDao;
public void setVoardDao (JdbcTemplateBoardDao dao){
boardDao = dao;
}
springapp-servlet.xml에
<bean name="/board_list.do" class="spring.web.BoardController">
<propery name="boardDao" ref="boarddao"></property>
</bean>
은 주석처리하고
<bean name="/board_list.do" class="springapp.board.BoardListController">
<property name="boardDao" ref= " boardDao"></propery>
</bean>
위에 소스 추가하고..
//spring 에서 제공하는 컨트롤러의 계층 구조
Controller
AbstractController
MultiActionController
BaseCommandController
AbstractCommandController
AbstractFormController
AbstractWizardFromController
SimpleFormcontroller
package springapp.board.BoardListController
public class BoardListController implements Controller {
private JdbcTemplateBoardDao bardDao ;
public void setBoardDao(JdbcTemplateBoardDao boardDao){
this.boardDao = boardDao;
}
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
List boardList = boardDao.list();
return new ModelAndView("list");
}
}
jdbcTempleteBoardDao .java에다가 아래소스 추가
public List list(){
List result = new ArrayList();
String sql = "select * from board order by seq desc";
RowMapper mapper = new RowMapper(){ //레코드 하나를 전달받아서 맵핑해줌
public Object mapRow(ResultSet rs, int rowNum) throws SQLException{
BoardVO vo = new BoardVO();//게시판에 잇는 글들을 저장하고 사용하기 위한 데이터 엔티티클래스
vo.setContent(rs.getString("content"));
vo.setHitcount(rs.getInt("hitcount"));
vo.setPassword(rs.getString("password"));
vo.setRegdate(rs.getString("regdate"));
vo.setSeq(rs.getInt("seq"));
vo.setTitle(rs.getString("title"));
vo.setWriter(rs.getString("writer"));
return vo;
}
};
result = jdbctemplete.query(sql, mapper);//위에 mapper이 들어온다.
return result;
}
package springapp.dao;
public class BoardVO{
private int seq;
private int hitcount;
private String title;
private String content;
private String wirter;
private String gredate;
private String password;
setter함수와 getter함수..만들고
}
BoardListController.java 에
return new ModelAndView("list", "boardList", boardList); //request객체에 담아서 실어보낸다.
톰캣폴더에 webapps에 examples에 web-inf에 lib폴더에 보면.. jstl.jar, standard.jar복사해서,
web-inf에 lib에 넣는다.
list.jsp를
<@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core/"%>//jstl을 사용하기위해서
<jsp:useBean id="boardList" type="java.util.List" scope="request" />
<table>
<tr>
<th>번호</th><th>제목</th><th>등록자</th><th>등록일</th>
</tr>
<c:forEach var="vo" items="${boardList}">
<tr>
<td>${vo.seq}</td>
<td><a href="board_detail.do?seq=${vo.seq}">${vo.title}</a></td>
<td>${vo.wirter}</td>
<td>${vo.regdate}</td>
</tr>
</c:forEach>
</table>
-------------------------
글의 상세보기 detail.jsp
< jsp:useBean id="boardVO" class="springapp.dao.BoardVO" scope="request"/>
<script type="text/javascript">
function fn_update_from(){
locaion.href="board_update.do?seq=${boardVO.seq}";
}
function fn_list_form(){
locaiton.href="board_list.do";
}
function fn_delete_form(){
locaiton.href="board_delete.do?seq=${boardVO.seq}";
}
</script>
<body>
<p align="center">
게시판 상세보기
</p>
<table border="1">
<tr>
<th>글번호</th><td>${boardVO.seq}</td>
</tr>
<tr>
<th>글제목</th><td>${boardVO.title}</td>
</tr>
<tr>
<th>글내용</th><td>${boardVO.content}</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="수정하기" onclick="fn_update_from()"/>
<input type="button" value="삭제하기" onclick="fn_delete_from()" />
<input type="button" value="목록보기" onclick="fn_list_from()" />
</td>
</tr>
</table>
</body>
</html>
springapp-servlet.xml에..
<bean name="/board_detail.do" class="springapp.board.BoardDetailController">
<property name="boardDao" ref="boardDao"></proerty>
</bean>
package springapp.baord;
public class BoardDetailController implements Controller{
private JdbcTemplateBoardDao boardDao;
public void setBoardDao(JdbcTemplateBoardDao boardDao){
this.boardDao=boardDao;
}
public ModelAndview handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception{
BoardVO vo = null
String seq = arg0.getParameter("seq");
vo = boardDao.findBySeq(seq);//서비스에게 맞긴다. 이클립스에서는 vreate method findBySeq(String) in type 어쩌고 저쩌고 해서.. 자동적으로 만들어준다.
ModelAndView mav = new ModelAndView();
mav.setViewName("detail");
return mav;
}
}
JdbcTemplateBoardDao.java //자동적으로 생성
public BoardVO findBySeq(String seq){
BoardVO result = null;
String sql = "select * from board where seq=?";
Object[] values = new Object[]{new Integer(seq)}
RowMapper mapper = new RowMaper(){ //RowMapper가져다 주면.. 자동적으로 오버라이딩 할 메서드가 나타난다.
public Object mapRow(ResultSet rs, ing rowNum) throws SQLException{
BoardVO vo = new BoardVO();
vo.setContent(rs.getString("content"));
vo.setHitcount(rs.getInt("hitcount"));
vo.setPassword(rs.getString("password"));
vo.setRegdate(rs.getString("regdate"));
vo.setSeq(rs.getInt("seq"));
vo.setTitle(rs.getString("title"));
vo.setWriter(rs.getString("writer"));
return vo;
}
};
result = (BoardVO)jdbctemplate.queryForObject(sql, values, mapper);
return result;
}
}
----------------------------------------
update.jsp
<jsp:useBean id="boardVO" class="springapp.dao.boardVO" scope="request"/>
<script type="text/javascript">
function fn_passCheck(){
var pass= document.getElementById("password").value;
if(pass != "${boardVO.password)"{
alert("패스워드가 틀립니다.");
docuemnt.getElementById("password").focus(); //id랑 name이랑 같다.
return;
}
document.forms[0].submit();
}
</script>
<body>
<p align="center">
게시판 수정하기
</p>
<form action="board_updae_action.do" method="post">
<input type="hidden" name="seq" value="${boardVO.seq}"/>
<table border="1">
<tr>
<th>글제목</th><td><input type="text" name="title" value="${boardVO.title}"/></td>
</tr>
<tr>
<th>글쓴이</th><td><input type="text" name="writer" value="${boardVO.writer} "> </td>
</tr>
<tr>
<th>비밀번호</th><td><input type="text" name="password" /></td>
</tr>
<tr>
<th>글내용</th><td><textarea rows="5" cols="60" name="content" >${boardVO.content}</textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="수정하기" onclick="fn_passCheck()" />
</td>
</tr>
</table>
</form>
</body>
</html>
spring-servlet.xml에다가
<bean name="/board_update.do" class="springapp.board.BoardUpdateController">
<property name="boardDao" ref="boardDao"></property>
</bean>
package springapp.board;
public class BoardUpdaeController implement Controller{
private JdbcTemplateBoardDao boardDao;
public void setBoardDao(JdbcTemplateBoardDao boardDao){
this.boardDao. boardDao;
}
public ModeAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1)throws Exception{
String seq = arg0.getParameter("seq");
BoardVO vo = boardDao.findBySeq(seq);
arg0.setAttribute("boardVO", vo); //위에껄로 써도 된다.
ModelAndView mav= new ModelAndView();
mav.setViewName("update");
return mav;
}
}
---------------------------
update 처리
spring-servlet.xml
<bean name="/board_update_action.do" class="springapp.board.BoardUpdateActionCommandController">
<property name="boardDao" ref="boardDao"></property>
<property name="commandClass" value="springapp.dao.BoardVO"></property>//넘어가는 데이터타입..
<property name="commandName" value="boardCmd"></property> //value는 그냥.. 아무렇게나 해도 상관없다..
</bean>
package springapp.board;
public class BoardUpdateActionCommandController extends AbstractCommandController{ // 이걸로 하면, 파라미터 처리가 쉽다.
private JdbcTemplateBoardDao boardDao;
public void setBoardDao(JdbcTemplateBoardDao boardDao){
this.boardDao = boardDao;
}
protected ModelAndView handle(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, BindException arg3) //안에 있는 매개변수가 다르다.파라미터를 용이하게 처리할수 있다.
throws Exception{
BoardVO vo = (BoardVO)arg2; arg2는 모델이 전달된다.
boardDao.update(vo);
//return new ModelAndView(new RedirectView("board_list.do"));//뷰를 바로 이동할수 잇게끔 한다.
return new ModelAndView("redirect:board_list.do"); //이렇게 해도 된다. 둘다..ViewResolver의 영향을 받지 않는다.
}
}
JdbcTemplateBoardDao.java에다가
public void update (BoardVO vo){
String sql = "Update Board set title=?, content=? where seq =?";
Object[] values = new Object[]{vo.getTitle(), vo.getContent(),vo.getSeq()};
jdbctemplate.update(sql,values);
}
}
글을 등록하면 한글이 깨지는 문제는
web.xml에..
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframeworkd.web.filter.CharacterFilter</filter-class>
<init-param>
<param-name>encodint</param-name>
<param-value>euc-kr</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
------------------------------------
글등록
list.jsp에 가서
<script type="text/javascript">
function fn_insert(){
locaiton.href="board_insert.do";
}
</script>
밑에다가
<input type="button" value="글쓰기" onclick="fn_insert()"/>
<hr/>
만든다.
insert.jsp를 만든다.
<body>
<p align="center">
게시판 글 등록하기
</p>
<form action="board_insert_action.do" method="post">
<table border="1">
<tr>
<th>글제목</th><td><input type="text" name="title" /></td>
</tr>
<tr>
<th>글쓴이</th><td><input type="text" name="writer" > </td>
</tr>
<tr>
<th>비밀번호</th><td><input type="text" name="password" /></td>
</tr>
<tr>
<th>글내용</th><td><textarea rows="5" cols="60" name="content" ></textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="등록하기" />
</td>
</tr>
</table>
</form>
</body>
spring-servlet.xml에다가
<bean name="/board_insert.do" class="springapp.board.BoardInsertController"/>
package springapp.board;
public class BoardInsertController implement Controller{
public ModeAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1)throws Exception{
return new ModelAndView("insert");
}
}
----------
insert 처리
spring-servlet.xml
<bean name="/board_insert_action.do" class="springapp.board.BoardInsertActionCommandController">
<property name="boardDao" ref="boardDao"></property>
<property name="commandClass" value="springapp.dao.BoardVO"></property>//넘어가는 데이터타입..
<property name="commandName" value="boardCmd"></property> //value는 그냥.. 아무렇게나 해도 상관없다..
</bean>
package springapp.board;
public class BoardInsertActionCommandController extends AbstractCommandController{ // 이걸로 하면, 파라미터 처리가 쉽다.
private JdbcTemplateBoardDao boardDao;
public void setBoardDao(JdbcTemplateBoardDao boardDao){
this.boardDao = boardDao;
}
protected ModelAndView handle(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, BindException arg3) //안에 있는 매개변수가 다르다.파라미터를 용이하게 처리할수 있다.
throws Exception{
BoardVO vo = (BoardVO)arg2; arg2는 모델이 전달된다.
boardDao.insert(vo);
//return new ModelAndView(new RedirectView("board_list.do"));//뷰를 바로 이동할수 잇게끔 한다.
return new ModelAndView("redirect:board_list.do"); //이렇게 해도 된다. 둘다..ViewResolver의 영향을 받지 않는다.
}
}
JdbcTemplateBoardDao.java에다가
public void insert (BoardVO vo){
String sql = "Insert into Board (seq, title, content, writer ,regdate,password, hitcount) "
+"values (board_seq.nextVal,?,?,?, to_char(sysdate,'yyyy/mm/dd'),?,0 )";
Object[] values = new Object[]{vo.getTitle(), vo.getContent(), vo.getWriter(), vo.getPassword()};
jdbctemplate.update(sql,values);
}
}
-----------------------------------------------------
Dependency Injection 종속객체주입 =IoC(inversion of Control)역제어
의존성은 객체와 객체사이의 관계를 말한다. (낮은 결합도) new라는 생성자를 이용해서, 객체를 생성하지 않는다.
주입 방법
spring설치파일에 docs/reference/pdf/pdf파일 열어보면..
1.생성자를 이용한 주입
public class SimpleMovieLister{
private MovieFinder movieFinder;
public simpleMovieListter(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
어딘가에 만들어진 객체를 위와 같은 소스로 주입한다.
package x,y;
public class Foo{
public Foo(Bar bar, Baz baz){
//..
}
}
어디서 객체가 만들어지나면..
<beans>
<bean name="foo" class="x.y.Foo">
<constructor-arg>
<bean class="x.y.Bar"/>
</constructor-arg>
<constructor-arg>
<bean class="x.y.Baz"/>
</constructor-arg>
</bean>
</beans>
또다른 예 (값도 넘겨줄수 있다.)
package examples;
public class ExampleBean{
private int years;
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer){
this.years=years;
this.ultimateAnswer = ultimateAnswer;
}
}
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="750000"/> //value는 속성으로도 사용할수 잇지만, 자식 엘리먼트로 이용될수도 있다. <value>5200000</value>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
index라는 속성은 여러개의 객체가 넘어갈때의 순서이다.
-----------------------
어플리케이션 DI실습
commons-loggin.jar, spring.jar만 있으면 된다.
window-preferences- java-Build Path- User Libraries 로 해가지고, 라이브러리를 만든다.
Spring_App_Lib 라이브러리를 만들고, addJars를 해가지고, 위 두가지 jar파일을 추가한다.
window-cusmotmize Perspective에서 new를 눌렀을때, 나오는 메뉴들을 조절할수 있다.
Java Project해가지고, SpringApp01 로 프로젝트를 만든다.
프로젝트에 BuildPath addLibrary 를 해가지고, userLibrary해가지고, Spring_App_Lib 를 추가한다.
MessageBean.java
package myspring;
public interface MessageBean{
void sayhello(String name);
}
MessageBeanKo.java
package myspring;
public class MessageBeanKo implements MessageBean{
public void sayHello(String name){
System.out.println("안녕하세요....."+name + "님");
}
}
MessageBeanEn.java
package myspring;
public class MessageBeanEn implements MessageBean{
public void sayHello(String name){
System.out.println("Hello.....Mr."+name );
}
}
xml설정파일은 웹이 아니라서, 어떤걸로도 이름을 지어도 상관은 없지만,
applicationContext.xml로 만든다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="msgBean" class="myspring.MessageBeanEn"></bean>
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring
public class HelloApp{
public static void main(String[] args){
Resource res = new FileSystemResource("applicationContext.xml");//설정파일을 읽어올려면.. 스프링 폴더에 docs에 api를 보면.. org.springframework.core.io라는 패키지를 들어가면 ClasspathResource(패키지 안에 같은경로에 있어야 한다.), FileSystemResource(프로젝트 안에 있어야 한다.)두개의 클래스를 사용할수 있다.
BeanFactory factory = new XmlbeanFactory(res); //xml에 설정되어 잇는 빈객체를 생성하는곳 둘다.. 부모 클래스로 받아준다.
MessageBean bean = (MessageBean)factory.getBean("msgBean"); //위에 xml에 있는 id를 이용할수 있다.
bean.sayHello("Tom");
}
}
2.setter를 이용한 주입
MessageBean.java
package myspring.sample1;
public interface MessageBean{
void sayHello(String name);
}
pacakge myspring.sample1;
public class MessageBeanImpl implemens MessageBean{
private String name; //생성자를 통해서..
private String greeting; //setter를 통해서 초기화 할수 있도록
public MessageBeanImpl(String name){ //source - Generate Constructor using Fields..
super();
this.name = name;
}
//source- Generate Getter/Setter
public void setGreeting(String greeting){
this.greeting = greeting;
}
public String getGreeting(){
return greeting;
}
public void sayHello(){
System.out.println(greeting + name + "!");
}
}
설정파일을 만든다.
applicationContext1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="msgBean" class="myspring.sample1.MessageBeanImpl">
<constructor-arg>///전에는 객체만 생성했었는데..여기서 생성자를 통해서..값을 넘겨 줄수 있다.그리고 setter메서드를 이용해가지고..값을 넘길수 잇다.
<value>홍길동</value>
</constructor-arg>
<property name="greeting">
<value>안녕하세요....</value>
</property> //setter을 이용하는 방법
</bean>
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring.sample1
public class HelloApp{
public static void main(String[] args){
Resource resource = new ClassPathResource("applicationContext1.xml");//설정파일을 읽어올려면.. 스프링 폴더에 docs에 api를 보면.. org.springframework.core.io라는 패키지를 들어가면 ClasspathResource(패키지 안에 같은경로에 있어야 한다.), FileSystemResource(프로젝트 안에 있어야 한다.)두개의 클래스를 사용할수 있다.
BeanFactory factory = new XmlbeanFactory(ressource); //xml에 설정되어 잇는 빈객체를 생성하는곳 둘다.. 부모 클래스로 받아준다.
MessageBean bean = (MessageBean)factory.getBean("msgBean"); //위에 xml에 있는 id를 이용할수 있다.
bean.sayHello();
}
}
--------------------------
//파일로 메시지 출력
pacakge myspring.sample2;
public interface MessageBean{
public void sayHello(); //콘솔에다가 출력
}
pacakge myspring.sample2;
public interface Outputter{
public void output(String msg)throwr IOExceptinon; //파일에다가 출력
}
package myspring.sample2;
public class FileOutputter implements Outputter{
private String filePath;
public void setFilePath(String filePath){
this.filePath = filePath;
}
public void output(String msg) throws IOException{
FileWriter out = new FileWriter(filepath);//파일로 만드는데는 바이트 스트림과, 문자 스트림 방식이 있다
out.wirte(msg);
out.close();
}
}
package myspring.sample2;
public class MessageBeanImpl implements MessageBean{
private String name;
private String greeting;
private Outputter out ;
public MessageBeanImpl(String name){
super();
this.name = name;
}
public void setOut(Outputter out){
this.out = out;
}
public void setGreeting(String greeting){
this.greeting = greeting;
}
public void sayHello(){
String msg = greetin + name + "!";
System.out.println(msg);
try{
out.output(msg);
}catch(IOException e ){
e.printStackTrace();
}
}
}
applicationContext2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="msgBean" class="myspring.sample2.MessageBeanImpl">
<constructor-arg>
<value>임꺽정</value>
</constructor-arg> //생성자
<property name="greeting">
<value>안녕히 계세요.</value>
</property> //setter을 이용하는 방법
<property name="out">
<ref local="outter"/> //객체를 주입해야 한다.
</property>
</bean>
<bean id="outter" class="myspring.sample2.FileOutputter">
<property name="filePath">
<value>out.txt</value> //파일명
</propery>
</bean>
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring.sample2
public class HelloApp{
public static void main(String[] args){
Resource resource = new ClassPathResource("applicationContext2.xml");//설정파일을 읽어올려면.. 스프링 폴더에 docs에 api를 보면.. org.springframework.core.io라는 패키지를 들어가면 ClasspathResource(패키지 안에 같은경로에 있어야 한다.), FileSystemResource(프로젝트 안에 있어야 한다.)두개의 클래스를 사용할수 있다.
BeanFactory factory = new XmlbeanFactory(ressource); //xml에 설정되어 잇는 빈객체를 생성하는곳 둘다.. 부모 클래스로 받아준다.
MessageBean bean = (MessageBean)factory.getBean("msgBean"); //위에 xml에 있는 id를 이용할수 있다.
bean.sayHello();
}
}
-----------------------
DI의 라이프사이클 (어플리케이션에서 중요..웹어플에서는.. 상관없음..)
스프링 컨테이너는 두가지 부류로 나눈다.
1. BeanFactory
XMLBeanFactory를 많이 사용한다.
org.springframework.beans.factory.BeanFactory
2. ApplicaionContext
BeanFactory는 가볍고, 단순하다. 하드웨어 장치가 열악한곳에 쓰이지만..
org.springframework.context.ApplicationContext
ApplicationContextAware도 많이 쓰이는 인터페이스다.
ApplicationContext는 BeanFacotry를 상속받아서 사용한다.
BeanFactory에서 사용하는 리소스들
org.springframework.core.io.ClassPathResource //외부로부터 파일시스템을 읽어들일..
.FileSystemResource
ApplicaitonContext에서 사용하는 리소스들
org.springframework.context.support.ClassPathXmlApplicationContext
.FileSystem.XmlApplicationContext
DI의 LifeCycle
1. BeanFactory
인스턴스화 - 프로퍼티 할당 - BeanNameAware의 setBeanName() (현재 사용되는 빈의 이름은 무엇인가.) - BeanFactoryAware의 setBeanFactory()(빈펙토리가 무엇인지..)- BeanPostProcessor의 사전초기화(두가지로 실행된다. 사전초기화, 후속 초기화 어떤 메서드가 실행되기 전에 한번 실행되고, 나중에 한번 더 실행된다.)
- InitialzingBean의 afterPropertiesSet() (특정 초기화 메서드를 선언을 하면, 그 함수를 실행할수 있게끔.. 하는..) - 커스텀 초기화 메서드 호출 - BeanPostProcessor의 후속초기화 - DisposableBean의 Destory() - 커스텀 소멸 메서드 호출
2. ApplicationContext(BeanFactory에서 하나가 추가된다.)
인스턴스화 - 프로퍼티 할당 - BeanNameAware의 setBeanName() (현재 사용되는 빈의 이름은 무엇인가.) - BeanFactoryAware의 setBeanFactory()(빈펙토리가 무엇인지..)-ApplicationContextAware의 setApplicationContext()(이것이 BeanFactory와 다르다.)- BeanPostProcessor의 사전초기화(두가지로 실행된다. 사전초기화, 후속 초기화 어떤 메서드가 실행되기 전에 한번 실행되고, 나중에 한번 더 실행된다.)
- InitialzingBean의 afterPropertiesSet() (특정 초기화 메서드를 선언을 하면, 그 함수를 실행할수 있게끔.. 하는..) - 커스텀 초기화 메서드 호출 - BeanPostProcessor의 후속초기화 - DisposableBean의 Destory() - 커스텀 소멸 메서드 호출
pacakge myspring.sample3;
public interface MessageBean{
void sayHello();
}
pcakge myspring.sample3;
public class MessageBeanImpl implements MessageBean, BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean{ // Life사이클을 테스트하기 위해서..
private String greeting;
private String beanName;
private BeanFactory factory;
public MessageBeanImpl(){
System.out.prinltn("1.인스턴스화");
}
public void setGreeting(String greeting){
this.greeting = greeting;
System.out.prinltn("2.프로퍼티할당");
}
public void sayHello(){ //핵심주메서드
System.out.prinltn(greeting+beanName + "!");
}
public void setBeanName(String arg0){ //빈네임을 인자로 받을수 있다.
this.beanName = arg0;
System.out.prinltn("3.빈이름 설정" + "---->"+ beanName);
}
public void setBeanFactory(BeanFactory arg0)throws BeansException{//이름설정한다음에, 팩토리를 설정
System.out.prinltn("4.빈팩토리설정");
this.factory = arg0;
System.out.println("--->"+ factory.getClass()); // 현재 실행중인 클래스의 이름을 뽑아낸다.
}
public void afterPropertiesSet()throws Exception{ // 핵심 로직이 실행되기전에, 그리고 끝난후에 실행되는..
//여기서 사용자가 만든 초기화 메서드가 실행된다. init가 실행되게 설정할것이다. init가 설정되기 전에
밑에 클래스 postProcessBeforeInitialization이게 먼저 실행되고, 그다음 이 함수를 벗어나서, 그다음 init가 실행되고, 다음에 postProcessAfterInitialization 이게 실행된다.
System.out.println("6. property설정완료");
}
public void destroy()throws Exception{
System.out.println("종료");
}
public void init(){
System.out.println("7. 초기화 메서드 실행");
}
}
//이 클래스는 BeanPostProcessor를 상속해서.. 빈펙토리 에서는 이거 applicationContext3.xml 에 설정 않해도 되고, ApplicationContext에서는 설정파일에 객체 생성을 해야 한다.
package myspring.sample3;
public class BeanPostProcessorImpl implements BeanPostProcessor{
//초기화 메서드가 실행이 끈나고 나서.. 실행되는 메서드
public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeanException{
System.out.println("8.초기화 후의 빈에 대한 처리 실행");
return arg0;
}
//초기화 메서드가 실행이 되기전에.. 실행되는 메서드
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException{
System.out.println("5.초기화 전의 빈에 대한 처리 실행");
return arg0;
}
}
applicationContext3.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="msgBean" class="myspring.sample3.MessageBeanImpl" init-method="init">//초기화 메서드를 만들었기 때문에 여기에다가 설정한다.
<property name="greeting">
<value>안녕하세요.....</value>
</property>
</bean>
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring.sample3
public class HelloApp{
public static void main(String[] args){
Resource rs = new ClassPathResource("applicationContext3.xml");//설정파일을 읽어올려면.. 스프링 폴더에 docs에 api를 보면.. org.springframework.core.io라는 패키지를 들어가면 ClasspathResource(패키지 안에 같은경로에 있어야 한다.), FileSystemResource(프로젝트 안에 있어야 한다.)두개의 클래스를 사용할수 있다.
XMLBeanFactory factory = new XmlbeanFactory(rs); //xml에 설정되어 잇는 빈객체를 생성하는곳 둘다.. 부모 클래스로 받아준다.
factory.addBeanPostProcessor(new BeanPostProcessorImpl());//BeanPostProcessor 을 궂이 설정하게 되면.. 이렇게 설정하면 된다.
MessageBean bean = (MessageBean)factory.getBean("msgBean"); //위에 xml에 있는 id를 이용할수 있다.
bean.sayHello();
}
}
ApplicationContext에서는
applicationContext4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="msgBean" class="myspring.sample3.MessageBeanImpl" init-method="init">//초기화 메서드를 만들었기 때문에 여기에다가 설정한다.
<property name="greeting">
<value>안녕하세요.....</value>
</property>
</bean>
<bean class="myspring.sample3.BeanPostProcessorImpl"/> //이곳만 설정해주면 된다.
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring.sample3
public class HelloApp2{
public static void main(String[] args){
ApplicationContext factory;
factory = new FileSystemXmlApplicatiionContext("applicationContext4.xml");//프로젝트 루트에다가 설정팔일이 있어야 한다.
MessageBean bean = (MessageBean)factory.getBean("msgBean"); //위에 xml에 있는 id를 이용할수 있다.
bean.sayHello();
}
}
----------------------------------------------
AOP(Aspect Oriented Programming)= 관심사항, 관점
객체지향을 쪼금더 객체지향적으로.. 만들어준다.
관점을 두가지로 보면..
1.공통관점 cross-cutting concern
보안, 트랜젝션, 예외처리..같은 그안에서 필요한것들을.. 모든곳에서 중점적으로 필요로 하는곳
2. 핵심관점
core concern
DI와 AOP의 차이는
DI는 어플리케이션간에 객체간의 결합도를 떨어뜨리는거고..
공통관심사와, 이와 영향을 받는 객체간의 결합도를 떨어뜨리는거다.
AOP의 용어
Join Point : 어떤 메서드의 시작점, 어떤 예외처리의 시작점..(분리를 하기 위해서는 기준점을 말한다.)
Joint Point가 한개이상 모인것을 PointCut이라고 한다.
PoinCut가 모이면 adviece(실제로 코딩을 할수 있는 부분)라고 한다.
advice,PoinCut 함께 모이면 advisor말한다..
advice만 모인것을 aspect라고 한다.
Log4j 를 활용한 AOP의 예
클래스(타겟 클래스) --- AOP프레임워크(Spring)(호출까지 담당) ---- logging
DI패턴처럼 주입을 할수 있는데, 이것을 weaving라고 한다.
waving할때 세가지 분류
1.컴파일할때,
2.클래스가 로딩할때 끼어 넣을건지..
3.런타임할때 끼어넣을건지..
타겟클래스
connons-logging.jar
spring.jar
window-java-buildpath - user Libraries 에 유저 라이브러리를 선택하고..
springframework/lib/cglib/bglib nodcp2.1_3.jar파일을 추가한다.
package myspring.sample4;
public interface MessageBean{
void sayHello();
}
package myspring.sample4;
public class MessageBeanImpl implements MessageBean{
private String name;
public setName(String name){
this.name = name;
}
public void sayHello(){
try{
Thread.sleep(5000);
}
catch(InterruptedException err){
err.printStackTrace();
}
System.out.println("Hello"+name);
}
}
Advisor을 만들려면..
1.Advice클래스를 작성(로그기록을 출력할 내용을 작성)
2.Advice클래스를 어디에서 실행하는지, 설정파일에서 포인트컷에서 설정한다.
3.Advice와 PointCut을 묶어 놓은 Advisor를 설정한다.
4. 설정파일에서 ProxyFactoryBean클래스를 이용하여, sayHello와 advisor을 연결을 한다.
5. getBean()로 빈객체를 가져와서 사용
Advice클래스를 보면
org.aopalliance.intercept.MethodInterceptor ----BeforeAdvice(조인포인트 실행되기 전에 호출되는 어드바이스),AfterReturnningAdvice (핵심 로직이 호출된후에 실행되는 어드바이스), AroundAdvice(둘다 합쳐놓은 형태의 어드바이스)
org.springframework.aop.IntroductionInterception
package myspring.sample4;
public class logginAdvice implements MethodInterceptor{
public Object invoke(MethodInvocation arg0) throws Throwable{
String methodName = arg0.getMethod().getName(); //조인포인트가 될 메서드의 클래스가 arg0에 전달이 된다.
StopWatch sw = new StopWatch();
sw.start(methodName); //어떤 메서드가 시작될때 시작될건지..
System.out.println("[Log] Method :"+ methodName + "is caling" );
Object obj = art0.proceed();//메서드가 실행되었을때의 시점을 가지고 있다.
sw.stop();
System.out.println("[LOG]Method : " + methodName + "was caaled");
System.out.println("[LOG] 처리시간 : "+ sw.getTotalTimeMillis()/1000 + "초" );
return obj; //객체를 돌려준다.
}
}
어느시점에 어드바이즈를 실행할것인지.. 포인트컷을 설정한다.
applicaitonContext5.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
sxi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="targetBean" class="myspring.sample4.MsgBeanImpl">
<property name="name">
<value>홍길동</value>
</property>
</bean>
<bean id="loggingAdvice" class="myspring.sample4.LoggingAdvice"/>
//2번과 3번을 같이 처리
<bean id="helloAdvisor" class="org.springfamework.aop.support.DefaultPointcutAdvisor">
<property name="advice"> //이부분은 변하지 않는다.
<ref local="logginAdvice"/> //타겟클래스를 넣는다.
</property>
<property name="pointcut"> //이부분은 변하지 않는다.
<been class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern">
<value>*sayHello.*</value>//정규표현식으로포인트컷이될 클래스
</property>
</bean>
</property>
</bean>
//위의 Advisor과 타겟빈을 연결한다.
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="targetBean"/>
</property>
<property name="interceptorNames">//이부분은 변하지 않는다.
<list>
<value>helloAdvisor</value>
</list>
</property>
</bean>
</beans>
활용을 하기 위한 클래스를 만든다.
package.myspring.sample4
public class HelloApp{
public static void main(String[] args){
Resource rs = new ClassPathResource("applicationContext5.xml");
XmlBeanFactory factory = new XmlBeanFactory(rs);
MessageBean bean = (MessageBean)factory.getBean("proxy");
bean.sayHello();
}
}