[Spring] HTML 폼과 자바빈 객체


HTML 폼과 자바빈 객체


스프링 MVC는 HTML 폼에 입력한 데이터를 자바빈 객체를 이용해서 전달 받을 수 있도록 하고 있다.

예를 들어 HTML 폼의 항목과 이름과  자바빈 클래스의 프로퍼티 이름이 일치할 경우 폼에 입력한 값을 해당 자바빈 클래스의 프로퍼티 값으로 설정해주는 기능을 제공하고 있다.


<from method="post">

<input type="hidden" name="parantId" value="0" />

제목: <input type="text" name="title" />

내용: <textarea name="content"> </textarea>

<input type="submit"/>

</from>


public class NewArticleCommand{

private String title;

private String content;

private int parentId;


// 입력 항목의 이름과 일치하는 프로퍼티에 값이 저장

public void setTitle(String tilte){

this.title;

}

public void setContent(String content){

this.content;

}

public void setParentId(int parentId){

this.parentId = parentId;

}

}


@Controller

@RequestMapping("/article/newArticle.do")

public class NewArticleController{


@RequestMapping(method = RequestMethod.POST)

public String submit(NewArticleCommand command){

//command.getTitle(): title 파라미터 값 저장

//command.getContent(): content 파라미터의 값 저장

//comman.getParentId(): parentId 파라미터의 값 저장

return "article/newArticleSubmitted";

}

}

HTML 폼에 입력한 데이터를 자바빈 객체로 전달받는 방법은 매우 간단하다. 단지 @RequestMapping 어노테이션이 적용된 메서드의 파라미터로 자바빈 타입을 추가해주기만 하면 된다.

폼에 입력한 값을 NewArticleCommand 클래스로 전달 받고 싶다면 요청 처리 메서드에 NewArticleCommand 타입의 파라미터를 추가해주기만 하면 된다.


1. 뷰에서 커맨드 객체 접근하기

뷰 코드에서는 컨트롤러의 @RequestMapping 어노테이션 메서드에서 전달받은 command 객체에 접근할 수 있다. 예를 들어, 아래와 같이 NewArticleCommand 타입의 command 객체를 전달받는다고 하자.

@RequestMapping(method =ResquestMethod.POST)

public String submit(NewArticleCommand command){

}

 

이 경우 컨트롤러의 처리 결과를 보여주는 뷰 코드에서는 command 객체의 클래스 이름을 이용해서 command 객체에 접근할 수 있다. 즉, command 객체는 자동으로 모델에 추가된다.

<body>

제목:${newArticleCommand.title}


뷰에서 사용할 모델의 이름을 변경하고 싶다면 다음과 같이 @ModelAttribute 어노테이션을 이용해서 command 객체의 모델 이름을 지정할 수 있다.

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


@Controller

@RequestMapping("/article/newArticle.do")

public class NewArticleController {


@RequestMapping(method = RequestMethod.POST)

public String submit(@ModelAttribute("command") NewArticleCommand command) {

articleService.writeArticle(command);

return "article/newArticleSubmitted";

}

}

@ModelAndView 어노테이션을 이용해서 command 객체의 모델 이름을 지정했다면, 뷰 코드에서는 다음과 같이 해당 모델 이름을 사용해서 command 객체에 접근할 수 있다.

제목:${command.title} <---  [기존의 제목:${newArticleCommand.title}]


2. 커맨드 객체로 List 받기

스프링 MVC는 List 타입의 프로퍼티에 대한 바인딩도 처리해준다. 예를 들어, 아래 코드는 OrderItem 목록을 갖는 List타입의 orderItems 프로퍼티를 갖고 있다.


public class OrderCommand {


private List<OrderItem> orderItems; //OrderItem 목록을 갖는 List타입의 orderItems 프로퍼티

private Address address;


public List<OrderItem> getOrderItems() {

return orderItems;

}


public void setOrderItems(List<OrderItem> orderItems) {

this.orderItems = orderItems;

}


public Address getAddress() {

return address;

}


public void setAddress(Address address) {

this.address = address;

}

}


List 타입의 프로퍼티에 값을 전달하고 싶다면 폼에서 "프로퍼티명[index].프로퍼티" 같이 입력 폼의 이름을 구성하면 된다. 예를 들어, 위 코드의 orderItems 프로퍼티에 값을 전달하고 싶다면

아래 코드와 같이 폼을 구성하면 된다.

<form method="post">

상품1: ID - <input type="text" name="orderItems[0].itemId" /> 

개수 - <input type="text" name="orderItems[0].number" />

주의 - <input type="text" name="orderItems[0].remark" />

<br/>

상품2: ID - <input type="text" name="orderItems[1].itemId" /> 

개수 - <input type="text" name="orderItems[1].number" />

주의 - <input type="text" name="orderItems[1].remark" />

<br/>

......

<input type="submit" />

</form>



폼의 <input>이나 <select> 등의 name에 인덱스 값을 포함시키면 List 타입의 프로퍼티에 값을 전달받을 수 있다. 컨트롤러 코드에서는 다음과 같이 커맨드 객체를 @RequestMapping 메서드에 지정해주기만 하면 된다.

@Controller

@RequestMapping("/order/order.do")

public class OrderController {

@RequestMapping(method = RequestMethod.POST)

public String submit(OrderCommand orderCommand) {

return "order/orderCompletion";

}

}



[Spring] 자바 코드 기반 설정


자바 코드 기반 설정


Spring JavaConfig 프로젝트는 XML이 아닌 자바 코드를 이용해서 컨테이너를 설정할 수 있는 기능을 제공하는 프로젝트로서, 이를 사용하면 XML이 아닌 자바 코드를 이용해서 생성할 빈 객체와

각 빈 간의 연관 등을 처리하게 된다.


1. @Configuration 어노테이션과 @Bean 어노테이션을 이용한 코드 기반 설정

org.springframework.context.annoatation 패키지의 @Configuration 어노테이션과 @Bean 어노테이션을 이용해서 스프링 컨테이너에 새로운 빈 객체를 제공할 수 있다. 


다음은 자바 코드를 이용해서 새로운 빈 객체를 스프링 컨테이너에 제공하는 클래스의 예를 보여주고 있다.

import org.springframework.context.annoatation.Bean;

import org.springframework.context.annoatation.Configuration;


@Configuration

public class SpringConfig{

}

@Bean

public AlarmDevice alarmDevice(){// alarmDevice()를 빈의 식별값으로 사용

return new SmsAlarmDevice();

}

}


@Bean 어노테이션은 새로운 빈 객체를 제공할 때 사용되며, @Bean이 적용된 메서드의 이름을 빈의 식별값으로 사용한다. 따라서 위 코드는 다음의 스프링 XML 설정과 동일한 빈을 정의한다.

<bean id="alarmDevice" class="mad.spring.ch4.homecontrol.SmsAlarmDevice"/>


메서드의 이름이 아닌 다른 이름을 빈 객체의 이름으로 사용하고 싶다면 @Bean 어노테이션의 name 속성을 사용하면 된다.

@Bean(name="smsAlarmDevice")//alarmDevice이 아닌 smsAlarmDevice을 사용하고 싶은 경우

public AlarmDevice alarmDevice(){

return new SmsAlarmDevice();

}


(1) @Bean 객체 간의 의존 설정

의존 설정은 매우 간단하다. 다음과 같이 의존할 빈 객체에 대한 메서드를 호출하는 것으로 의존관계를 설정할 수 있다.


@Configuration

public class SpringConfig{


@Bean

public Camera camera1(){

return new camera();

}


@Bean

public infraredRaySensor windowSensor(){

return new infraredRaySensor("창 센서");

}


@Bean

public Viewer viewer(){

MonitorViewer viewer = new MonitorViewer();

viewer.setDisplayStrategy(displayStrategy());

return viewer;

}

@Bean

public DisplayStrategy displayStrategy(){

return new DefaultDisplayStrategy();

}


@Bean

public HomeController homeController(){

HomeContoller homeController = new HomeController();

List<infraredRaySensor> sensors = new ArrayList<infraredRaySensor>();

sensors.add(windowSensor());

sensors.add(doorSensor());

homeController.setSensors(sensors);

...

homeController.setCamera1(camera1());

homeController.setDisplayStrategy(displayStrategy());

return homeController;

}

}

위 코드에서 각 빈 객체들은 의존할 빈에 해당하는 메서드를 호출함으로써 의존 관계를 설정하고 있다.

여기서 눈여겨 볼 부분은 displayStrategy() 메서드가 viewer() 메서드와 homeController() 메서드에서 각각 한 번씩 호출된다는 점이다.

즉, displayStrategy() 메서드가 두 번 호출된다. displayStrategy() 메서드는 호출 횟수에 상관없이 매번 동일한 객체를 리턴한다.


스프링은 CGLIB를 이용해서 @Configuration이 적용된 클래스의 프록시 객체를 생성한다. 이 프록시 객체는 @Bean 어노테이션이 적용된 메서드가 호출될 때 생성할 빈 객체의 범위에 

따라서 알맞은 객체를 제공한다. 예를 들어, 설정한 빈의 범위가 singleton이면 메서드가 리턴하는 객체는 매번 동일한 객체가 되고, 빈의 범위가 prototype이면 메서드가 메번 새로운 빈 객체를 

리턴하게 된다.


(2) @Bean 어노테이션의 autowire 속성을 이용한 연관 자동 설정

<bean id="alarmDevice" class="mad.spring.ch4.homecontrol.SmsAlarmDevice" autowire="byName"/>


@Bean(autowire=autowire.BY_NAME)

Autowire.BY_NAME: 이름을 이용해서 자동 연관을 처리한다.

Autowire.BY_TYPE: 타입을 이용해서 자동 연관을 처리한다.

Autowire.NO: 자동 연관 처리를 하지 않는다.


2. @Configuration 어노테이션 기반 설정 정보 사용

클래스에 @Configuration 어노테이션을 적용한다고 해서 스프링 컨테이너가 해당 클래스로부터 빈 정보를 구할 수 있는 것은 아니다.

@Configuration 어노테이션이 적용된 클래스를 이용해서 스프링 빈을 생성하는 방법 2가지를 살펴보자


(1) AnnotationConfigApplicationContext를 이용한 @Configuration 클래스 사용

@Configuration 어노테이션이 적용된 클래스를 설정 정보로 이용하는 첫 번째 방법은 AnnotationConfigApplicationContext를 이용하는 것이다.


다음과 같이 @Configuration 어노테이션 클래스를 전달해 주기만 하면 된다.

import org.springframework.context.ApplicationContext;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import org.springframework.context.support.AbstractApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;


public class MainConfig {


public static void main(String[] args) {

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);


HomeController homeControl = context.getBean(:homeController", HomeController.class);

....

}

}


cf.) 한 개 이상의 @Configuration 어노테이션 적용 클래스로부터 ApplicationContext를 생성하고 싶다면 다음과 같이 @Configuration 어노테이션 클래스의 목록을 지정하면 된다.

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class, ArticleRepositoryConfig.class);


cf.) AnnotationConfigApplicationContext클래스는 <context:annotation-config> 태그를 사용했을 때와 마찬가지로 각 빈 클래스에서 사용된 @Autowired 어노테이션과 @Resource 어노테이션 등 

앞서 '어노테이션 기반 설정' 절에서 살펴봤던 어노테이션들이 기본을 적용된다.


(2) XML 설정 파일에서 @Configuration 어노테이션 클래스 사용하기

XML 설정 파일에서 @Configuration 클래스를 사용하려면 ConfigurationClassPostProcessor 클래스와 @Configuration 어노테이션이 적용된 클래스를 스프링 설정 파일에 빈 객체로 등록해 주면 된다.

<bean class="org.springframework.context.annotation.ConfigurationClassPostProcessor"/>

<bean class="mad.spring.ch4.config.SpringConfig"/>

ConfigurationClassPostProcessor 클래스는 @Configuration 어노테이션이 적용된 빈 객체에서 @Bean 어노테이션이 적용된 메서드로부터 빈 객체를 가져와 스프링 컨테이너에 등록한다.


@Configuration 어노테이션이 적용된 클래스는 @Component 어노테이션이 적용된 클래스와 마찬가지로 컴포넌트 스캔 대상이다. 따라서, 아래와 같이 컴포넌트 스캔 기능을 이용해서 

@Configuration 어노테이션이 적용된 클래스를 자동으로 빈으로 등록할 수 있다.

<?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-3.0.xsd">

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd">


<context:component-scan base-package="mad.spring.ch4.config"/>

...

</beans>



(3) @Importresource를 통해 @Configuration 설정 클래스에서 XML 사용하기

@Configuration 클래스에서 XML 설정 정보를 사용할 수도 있다.

@Configuration 클래스에서 XML 설정 정보를 함께 사용하고 싶다면 @ImportResource 어노테이션을 사용하면 된다.

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.ImportResource;


@Configuration

@ImportResource({"classpath:/article-repository.xml"})

public class ArticleConfigWithImportResource {


@Autowired

private ArticleRepository articleRepository;

@Bean

public ArticleService articleService() {

return new ArticleServiceImpl(articleRepository);

}

}


3. 서로 다른 @Configuration 어노테이션 클래스 간의 의존 설정
@Configuration 어노테이션 클래스를 작성하다보면, 다른 @Configuration 어노테이션 클래스에서 설정한 빈 객체를 의존하는 경우가 있다. 이런 경우는 주로 레이어 별로 설정 정보를 구분할 때 발생한다.예를 들어, 아래 코드와 같이 서비스 레이어와 리포지토리 레이어에 대한 설정을 별도 클래스로 제공한다고 해보자.
위 코드에서 ArticleServiceConfig에 설정된 articleService 빈은 ArticleRepositoryConfig에 설정된 articleRepository 빈에 의존하고 있다.
이렇게 서로 다른 설정 클래스에 존재하는 빈 객체 간의 의존을 처리할 때에는 @Autowired 어노테이션이나 @Resource 어노테이션을 이용해서 의존에 필요한 빈 객체를 전달 받을 수 있다.

위 코드에서 ArticleServiceConfig 클래스의 articleRepository 필드에 @Autowired 어노테이션이 적용되었기 때문에 articleRepository 필드에는 ArticleServiceConfig 클래스에 정의된
articleRepository() 메서드가 생성한 빈 객체가 할당된다. 따라서, ArticleServiceConfig.srticleService() 메서드에서 ArticleServiceImpl 객체를 생성할 때 사용되는 articleRepository 객체는
ArticleRepositoryConfig 클래스에서 생성한 ArticleRepositoryImpl 객체가 된다.

@Configuration
public class ArticleServiceConfig{
  @Autowired
private ArticleRepositoryConfig repositoryConfig;

@Bean
public ArticleService articleService(){
return new ArticleServiceImpl(repositoryConfig.articleRepository());
}
}
의존 객체를 참조하는 또다른 방법은 @Configuration 클래스를 @Autowired로 전달받는 것이다. 위 코드는 @Configuration 클래스를 전달받아 의존을 처리하는 경우의 예를 보여주고 있다.

cp.) @Import를 이용한 @Configuration 어노테이션 적용 클래스의 조합

@Import 어노테이션을 이용하면 하나의 @Configuration 클래스에서 다수의 @Configuration 클래스를 묶을 수 있다. 아래와 같이 @import 어노테이션에 설정 정보를 가져올 @Configuration 클래스 목록을 지정해주면 된다.

import org.springframework.context.annotaion.Cofiguration;

import org.springframework.context.annotation.Import;


@Configuration

@Import({ArticleServiceConfig.class, ArticleRepositoryConfig.class})

public class ArticleConfigWithImport{

...

}

@Import 어노테이션을 이용할 경우의 장점은 개발자가 모든 @Configuration 클래스 목록을 기억할 필요 없이 @import 어노테이션이 적용된 클래스만 기억하면 손쉽게 설정 정보 추적이 가능하다는 점이다.


[Spring] 어노테이션 기반 설정


어노테이션 기반 설정


1. XML에서의 <context:annotation-config/> 설정

<?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/context"   

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/beans/spring-context-3.0.xsd">

<context:annotation-config/>

  <!-- <context:component-scan> 태그를 이용해서 스프링이 클래스를 검색할 패키지를 지정하면 된다. <context:component-scan> 태그를 추가하면 스프링은 지정한 패키지에서 @Component 어노테이션 등이 적용된 클래스를 검색하여 빈으로 등록하게 된다.

<context:component-scan base-package="mad.spring.ch4.HomeController"/>-->

...

</beans>


<context:annotation-config/> 태그는 어노테이션과 관련해서 다음의 BeanPostProcessor를 등록해 준다.

- RequredAnnotationBeanPostProcessor: @Required 어노테이션 처리

- AutowiredAnnotationBeanPostProcessor:@Autiwired 어노테이션 처리

- CommonAnnotationBeanPostProcessor: @Ressource, @PostConstruct, @PreDestroy 어노테이션 처리

- ConfigurationClassProcessor: @Configuration 어노테이션 처리


2. @Autowired 어노테이션을 이용한 자동 설정

org.springframework.beans.factory.annotation 패키지에 위치한 @Autowired 어노테이션은 의존관계를 자동으로 설정할 때 사용된다.

@Autowired 어노테이션은 스프링 2.5에 추가된 기능으로 타입을 이용하여 의존하는 객체를 삽입해준다.

@Autowired 어노테이션은 타입을 이용한 프로퍼티 자동 설정 기능을 제공한다.


(1) 프로퍼티 설정 메서드에 적용한 예

import org.springframework.beans.factory.annotation.Autowired;


public class MonitorViewer implements Viewer{

private DisplayStrategy displayStrategy;

@Autowired

public void setDisplayStrategy(DisplayStrategy displayStrategy){

this.displayStrategy = displayStrategy;

}

}

위 코드는 displayStrategy 프로퍼티에 DisplayStrategy 타입의 빈 객체를 전달한다.


(2) 일반 메서드에 적용한 예

메서드 이름이 setXXX() 형식이 아니라도 @Autowired 어노테이션을 적용할 수 있다. 아래 코드는 prepare() 메서드에 @Autowired 어노테이션을 적용할 수 있는데,

이 경우 스프링은 HomeController 객체를 생성할 때 prepare() 메서드에 AlarmDevice 타입의 빈 객체와 Viewer 타입의 빈 객체를 전달한다.

import org.springframework.beans.factory.annotation.Autowired;


public class HomeController{

private AlarmDevice alarmDevice;

private Viewer viewer;


@Autowired

public void prepare(AlramDevice alarmDevice, Viewer viewer){

this.alarmDevice = alarmDevice;

this.viewer viewer;

}

...

}


(3) 멤버 필드에 적용한 예

멤버 필드에 직접 @Autowired 어노테이션을 적용해도 된다.

public class MonitorViewer implements Viewer{

@Autowired

private DisplayStrategy displayStrategy;

...

}


(4) 배열에 적용한 예

@Autowired 어노테이션을 배열에 적용하게 되면, 해당 타입의 모든 빈 객체를 배열로 전달 받는다. 예를 들어, 아래 코드와 같이 @Autowired 어노테이션을 적용하면 InfraredRaySensor 타입의 빈 객체가 배열로

setSensor() 메서드에 전달된다. 메서드 뿐만 아니라 배열 타입의 멤버 필드에 @Autowired 어노테이션을 적용해도 동일하게 동작한다.

public class HomeController{

...

private InfraredRaySensor[ ] sensors;

@Autowired

public void setSensors(InfraredRaySensor[ ] sensors){

this.sensors = sensors;

}

...

}


(5) 제네릭이 적용된 컬렉션 타입을 적용한 예

제네릭이 적용된 컬렉션 타입을 사용하는 경우 List 타입이나 Set 타입을 이용해서 특정 타입의 빈 객체 목록을 전달 받을 수 있다.

public class HomeController{

private List<InfraredRaySensor> sensor;


@Autowired

public void setSensors(List<InfraredRaySensor> sensors){

this.sensors=sensors;

}

}


(6) @Autowired 어노테이션 적용 프로퍼티의 필수 여부 지정
@Autowired 어노테이션은 타입을 이용해서 자동적으로 프로퍼티 값을 설정하기 때문에, 해당 타입의 빈 객체가 존재하지 않거나 또는 빈 객체가 두 개 이상 존재할 경우
스프링은 @Autowired 어노테이션이 적용된 빈 객체를 생성할 때 예외를 발생시킨다.

@Autowired 어노테이션을 적용한 프로퍼티를 반드시 설정할 필요가 없는 경우도 있는데, 이런 경우에는 @Autowired 어노테이션에 required 속성의 값을 false로 지해주면 된다.
public class HomeController{
...
@Autowired(requred=false)
public void setSensors(List<InfraredRaySensor> sensors){
this.sensors = sensors;
}
...
}
required 속성의 값을 false로 지정할 경우, 해당 타입의 빈 객체가 존재하지 않더라도 스프링은 예외를 발생하지 않는다.
required 속성의 기본 값은 true이다.


3. @Resource 어노테이션을 이용한 프로퍼티 설정

@Resource 어노테이션은 어플리케이션에서 필요로 하는 자원을 자동 연결할 때 사용된다.

스프링에서는 의존하는 빈 객체를 전달할 때 사용된다.

import javax,annotation.Resource;


public class HomeController{

@Resource(name="camera1")

private Camera camera1;

private Camera camera4;

@Resource(name="camera4);

public void setcamera4(Camera camera4){

this.camera4 = camera4;

}

...

}

스프링에서 @Resource 어노테이션을 사용하려면 name 속성에 자동으로 연결할 빈 객체의 이름을 입력하면 된다.


<bean class="org.springframework.beans.factory.annotation.RequredAnnotationBeanPostProcessor"/>

<context:annotation-config/>를 사용해도 좋다.


'Programing > Spring' 카테고리의 다른 글

[Spring] HTML 폼과 자바빈 객체  (0) 2014.12.18
[Spring] 자바 코드 기반 설정  (0) 2014.12.17
[Spring] 외부 설정 프로퍼티  (0) 2014.12.17
[Spring] iBatis 2  (0) 2014.12.16
[Spring] iBatis 1  (0) 2014.12.16

[Spring] 외부 설정 프로퍼티


외부 설정 프로퍼티


1. 외부 설정 프로퍼티

PropertyPlaceholderConfigurer 클래스를 빈으로 등록하면 외부의 프로퍼티에 저장된 정보를 스프링 설정 파일에서 사용할 수 있다.

예를 들어, 다음과 같은 프로퍼티 파일을 작성했다고 하자.

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://dbserver:3306/springbook

jdbc.username=springbook

jdbc.password=springbook

위 프로퍼티의 파일의 정보를 스프링 설정 파일에서 사용하고 싶다면, 다음과 같이 PropertyPlaceholderConfigurer 클래스를 빈으로 등록한 뒤, 프로퍼티의 이름을 파일에서 사용하면 된다.


<bean class="org.springframwork.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="locations">

<!-- 프로퍼티 파일 경로 지정 -->

<value>classpath:config/jdbc.properties</value>

</property>

</bean>


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-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>

locations 프로퍼티의 값에는 콤마나 공백으로 구분된 프로퍼티 파일 목록이 오며, 프로퍼티 파일에 포함된 프로퍼티의 값은 

'${프로퍼티의 이름}' 형식으로 사용할 수 있다. 즉, 위 코드에서 ${jdbc.driver}는 프로퍼티 파일의 jdbc.driver 프로퍼티의 값으로 대체된다.


 한 개 이상의 프로퍼티 파일을 지정하면 <list> 태그를 이용하여 프로퍼티 목록을 지정해주면 된다.

<bean class="org.springframwork.beans.factory.config.PropertyPlaceholderConfigurer">

<property name="locations">

<list>

<value>classpath:config/jdbc.properties</value>

<value>classpath:config/monitor.properties</value>

</list>

</property>

</bean>

외부 환경에 따라 설정 정보가 변경되는 경우에 프로퍼티 파일을 유용하게 사용할 수 있다.

예를 들어, 로컬에서의 테스트와 테스트 서버에서의 통합 테스트, 그리고 실제 운영 환경에서 사용하는 데이터베이스가 다르다고 하자.

이 경우 각 환경에 맞게 스프링 설정 파일을 변경하는 것 보다는 환경에 맞는 프로퍼티 설정 파일을 작성하고, 

환경에 따라 알맞은 프로퍼티 파일을 사용하도록 배치 스크립트를 작성하는 것이 유지 및 보수에 더 편리하다.


2. <context:property-placeholder> 태그를 사용한 외부 설정 프로퍼티 사용

<context:property-placeholder> 태그를 사용하여 외부 프로퍼티 파일을 로딩하도록 설정할 수 있다.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

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-3.0.xsd">

  http://www.springframework.org/schema/context 

    http://www.springframework.org/schema/beans/spring-context-3.0.xsd

  <!--두 개이상 프로퍼티 사용할 수 있다.(콤마로 구분하여)-->

<context-property-placeholder location="classpath:config/jdbc.properties, classpath:config/monitor.properties"/>


<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close">

<property name="driverCalssName" value="${jdbc.driver}">/>

</bean>

....


</beans>

<context:property-placeholder> 태그를 사용하려면 위 코드와 같이 context 접두어에 대한 네임스페이스를 http://www.springframework.org/schema/context로 지정하고 네임스페이스와 관련된 XML 스키마 경로를 

spring-context-3.0.xsd로 지정해 주어야 한다.


3. PropertyPlaceholderConfigurer 사용시 주의 사항

PropertyPlaceholderConfigurer를 사용할 때 주의할 점은 두 개 이상의 PropertyPlaceholderConfigurer 빈을 설정하면 안 된다는 점이다.

이 경우, 첫 번째 PropertyPlaceholderConfigurer의 설정이 적용되며, 두 번째 설정 내용은 적용되지 않는다.

--> 각각의 PropertyPlaceholderConfigurer 빈은 서로 프로퍼티 정보를 공유하지 않기 때문이다.

스프링을 이용하다보면 두 개 이상의 설정 파일을 사용하는 경우가 빈번한데, 이때 서로 다른 파일에 PropertyPlaceholderConfigurer 빈이 설정되어 있을 경우 프로퍼티 값이 올바르게

처리되지 않아서 올바르게 처리되지 않아서 예외가 발생할 수 있다.




'Programing > Spring' 카테고리의 다른 글

[Spring] 자바 코드 기반 설정  (0) 2014.12.17
[Spring] 어노테이션 기반 설정  (0) 2014.12.17
[Spring] iBatis 2  (0) 2014.12.16
[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13

[Spring] iBatis 2


iBatis 2


1. sqlMapConfig.xml: 설정파일

iBATIS 의 메인 설정 파일인 SQL Map XML Configuration 파일(이하 sqlMapConfig.xml 설정 파일) 작성과 상세한 옵션 설정에 대해 알아본다.


(1) sqlMapConfig.xml

SqlMapClient 설정관련 상세 내역을 제어할 수 있는 메인 설정 파일로 주로 transaction 관리 관련 설정 및 다양한 옵션 설정, Sql Mapping 파일들에 대한 path 설정 등을 포함한다.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"

    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

<properties resource="META-INF/spring/jdbc.properties" />

 

<settings cacheModelsEnabled="true" enhancementEnabled="true"

lazyLoadingEnabled="true" maxRequests="128" maxSessions="10"

maxTransactions="5" useStatementNamespaces="false"

defaultStatementTimeout="1" />

 

<typeHandler javaType="java.util.Calendar" jdbcType="TIMESTAMP"

callback="egovframework.rte.psl.dataaccess.typehandler.CalendarTypeHandler" />

 

<transactionManager type="JDBC">

<dataSource type="DBCP">

<property name="driverClassName" value="${driver}" />

<property name="url" value="${dburl}" />

<property name="username" value="${username}" />

<property name="password" value="${password}" />

<!-- OPTIONAL PROPERTIES BELOW -->

<property name="maxActive" value="10" />

<property name="maxIdle" value="5" />

<property name="maxWait" value="60000" />

<!-- validation query -->

<!--<property name="validationQuery" value="select * from DUAL" />-->

<property name="logAbandoned" value="false" />

<property name="removeAbandoned" value="false" />

<property name="removeAbandonedTimeout" value="50000" />

<property name="Driver.DriverSpecificProperty" value="SomeValue" />

</dataSource>

</transactionManager>

<sqlMap resource="META-INF/sqlmap/mappings/testcase-basic.xml" />

<sqlMap ../>

..

</sqlMapConfig>

- properties : 표준 java properties (key=value 형태)파일에 대한 연결을 지원하며 설정 파일내에서 ${key} 와 같은 형태로 properties 형태로 외부화 해놓은 실제의 값(여기서는 DB 접속 관련 driver, url, id/pw)을 참조할 수 있다. resource 속성으로 classpath, url 속성으로 유효한 URL 상에 있는 자원을 지정 가능하다.


- settings : 이 설정 파일을 통해 생성된 SqlMapClient instance 에 대하여 다양한 옵션 설정을 통해 최적화할 수 있도록 지원한다. 모든 속성은 선택사항(optional) 이다.

 속 성

설 명 

example, default 

 maxRequests

 같은 시간대에 SQL문을 실행한 수 있는 thread 의 최대 갯수 지정.

 maxRequests=“256”, 512

 maxSessions

 주어진 시간에 활성화될 수 있는 session(또는 client) 수 지정.

 maxSessions=“64”, 128

 maxTransactions

 같은 시간대에 SqlMapClient.startTransaction() 에 들어갈 수 있는 최대 갯수    지정.

 maxTransactions=“16”, 32

 cacheModelsEnabled

 SqlMapClient 에 대한 모든 cacheModel 에 대한 사용 여부를 global 하게 지  정.

 cacheModelsEnabled=“true”, true (enabled) 

 lazyLoadingEnabled

 SqlMapClient 에 대한 모든 lazy loading 에 대한 사용 여부를 global 하게 지정

 lazyLoadingEnabled=“true”, true (enabled)

 enhancementEnabled

 runtime bytecode enhancement 기술 사용 여부 지정.

 enhancementEnabled=“true”, false (disabled)

 useStatementNamespaces

 mapped statements 에 대한 참조 시 namespace 조합 사용 여부 지정. true  인 경우  queryForObject(“sqlMapName.statementName”); 과 같이 사용함.

 useStatementNamespaces=“false”, false (disabled)

 defaultStatementTimeout

 모든 JDBC 쿼리에 대한 timeout 시간(초) 지정, 각 statement 의 설정으로  override 가능함. 모든 driver가  이 설정을 지원하는 것은 아님에 유의할 것.

  정하지 않는 경우 timeout 없음(cf. 각 statement 설정에 따라)

 classInfoCacheEnabled

 introspected(java 의 reflection API에 의해 내부 참조된) class의 캐쉬를 유지  할지에 대한 설정

 classInfoCacheEnabled=“true”, true (enabled)

 statementCachingEnabled

 prepared statement 의 local cache 를 유지할지에 대한 설정

 tatementCachingEnabled=“true”, true (enabled)


- typeHandler : javaType ↔ jdbcType 간의 변환(prepared statement 의 파라메터 세팅/resultSet 의 값 얻기)을 처리하는 typeHandler 구현체를 등록할 수 있다.


- transactionManager : 트랜잭션 관리 서비스를 설정할 수 있다. type 속성으로 어떤 트랜잭션 관리자를 사용할지 지시할 수 있는데, JDBC, JTA, EXTERNAL 의 세가지 트랜잭션 관리자가 프레임워크에 포함되어 있다. 위에서는 일반적인 Connection commit()/rollback() 메서드를 통해 트랜잭션을 관리하는 JDBC 타입으로 설정하였다.


- dataSource : transactionManager 설정의 일부 영역으로 DataSource 에 대한 설정이다. type 속성으로 어떤 DataSourceFactory 를 사용할지 지시할 수 있는데, SIMPLE, DBCP, JNDI 의 세가지 설정이 가능하다. 위에서는 Apache Commons DBCP(Database Connection Pool) 를 사용하는 DBCP 타입으로 설정하였다. iBATIS 는 DBCP 속성에 대한 설정을 직접 명시할 수 있도록 지원하고 있다. iBATIS 2 버전 이후로는 단일 dataSource 만 지원한다.


- sqlMap : 명시적으로 각 SQL Map XML 파일을 포함하도록 설정한다. classpath (resource 속성으로 지정) 나 url(url 속성으로 지정) 상의 자원을 stream 형태로 로딩하게 된다. 위에서는 classpath 상에 존재하는 sql 매핑 파일을 지정하였다.


이 외에도 typeAlias(global 한 type 별명-풀패키지명에 비해 간략히), resultObjectFactory (SQL 문의 실행에 의한 결과 객체의 생성을 iBATIS 의 ResultObjectFactory 인터페이스를 구현한 factory 클래스를 통해 처리할 수 있도록 지원) 에 대한 설정이 가능하다. DTD 상 sqlMap 설정은 하나 이상이 필요하고 다른 설정은 선택사항이다.


2. SQL Map XML 파일: 매핑파일

sql 매핑 파일은 iBATIS 의 mapped statement 형태로 처리될 수 있도록 SQL Map 문서 구조에 따라 다양한 옵션 설정 및 매핑 정의, sql 문을 외부화하여 저장하는 파일이다.


(1) sqlMap.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Dept">

<typeAlias alias="deptVO" type="egovframework.DeptVO" />

 

<resultMap id="deptResult" class="deptVO">

<result property="deptNo" column="DEPT_NO" />

<result property="deptName" column="DEPT_NAME" />

<result property="loc" column="LOC" />

</resultMap>

 

<insert id="insertDept" parameterClass="deptVO">

insert into DEPT

          (DEPT_NO,

           DEPT_NAME,

           LOC)

values     (#deptNo#,

           #deptName#,

           #loc#)

</insert>

 

<select id="selectDept" parameterClass="deptVO" resultMap="deptResult">

<![CDATA[

select DEPT_NO,

      DEPT_NAME,

      LOC

from   DEPT

where  DEPT_NO = #deptNo#

]]>

</select>

</sqlMap>

- typeAlias : 현재 매핑 파일내에서 객체에 대한 간략한 alias 명을 지정함. (cf. 매우 자주 쓰이는 class 의 경우 sqlMapConfig.xml 에 global 하게 등록하는 것이 좋음)


- resultMap : DB 칼럼명(select 문의 칼럼 alias) 과 결과 객체의 attribute 에 대한 매핑 및 추가 옵션을 정의함.


- insert, select : 각 statement 타입에 따른 mapped statement 정의 요소 예시. 유형에 따라 insert/update/delete/select/procedure/statement 요소 사용 가능

이 외에도 parameterMap, resultMap 에 대한 상세 정의, cacheModel 설정, sql 문 재사용을 위한 sql 요소 설정이 나타날 수 있다. 각각에 대한 상세 사항은 관련 가이드를 참고한다.


3. sqlMapclientFactoryBean 작성

SqlMapClientFactoryBean 은 iBATIS 의 SqlMapClient 를 생성하는 FactoryBean 구현체로, Spring 의 context 에 iBATIS 의 SqlMapClient 를 셋업하는 일반적인 방법으로 사용된다. 여기서 얻어진 SqlMapClient 는 iBATIS 기반 DAO 에 dependency injection 을 통해 넘겨지게 된다.

<!-- dataSource 설정 -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="${driver}"/>

<property name="url" value="${dburl}"/>

<property name="username" value="${username}"/>

<property name="password" value="${password}"/>

<property name="defaultAutoCommit" value="false"/>

<property name="poolPreparedStatements" value="true"/>

</bean>

 

<!-- SqlMap setup for iBATIS Database Layer -->

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

<property name="configLocation" value="classpath:/META-INF/sqlmap/sqlMapConfig.xml"/>

<property name="dataSource" ref="dataSource"/>

</bean>

- dataSource : 데이터베이스 연결 추상화를 제공하는 DataSource 설정. 위에서는 Apache Commons DBCP 를 사용하였으며 DB 접속과 관련된 설정은 property-placeholder 를 사용하여 외부화 하였다.

- sqlMapClient : Spring의 iBATIS 연동을 위한 SqlMapClientFactoryBean 설정으로 configLocation 속성을 통해 지정한 iBATIS 메인 설정 파일인 sqlMapConfig.xml에 대해 iBATIS 의 SqlMapClient instance 를 생성하여 Spring 환경에서 사용 가능토록 한다. 

Spring 의 dataSource 를 iBATIS 에 넘길 수 있도록 injection 을 지시하고 있으며 이로 인해 iBATIS 설정 파일 자체에서는 dataSource 및 transaction 설정 필요없이(Spring 환경에서는 iBATIS 기반 DAO 호출 이전에 서비스 단에서 선언적인 트랜잭션 처리를 해주었을 것임) Spring 이 제공하는 유연한 dataSource 및 트랜잭션 처리를 사용하게 된다.


Spring 현재 버전에서는 configLocations 속성을 추가하여 sql-map-config.xml 에 대한 패턴 표현식이나 복수 연동(런타임에 하나의 통합 설정으로 merge 됨)도 지원하고 있다. useTransactionAwareDataSource 속성으로 SqlMapClient 에 대해 Spring 이 관리하는 transaction timeout 을 함께 적용할 수 있는 transaction-aware DataSource 를 사용하도록 설정 가능하며(default), lobHandler 속성을 통해 Spring 의 lobHandler 를 설정할 수도 있다.


cp.) mappingLocations 지원

또한 iBATIS 사용 환경에서의 중요한 개선 사항으로 mappingLocations 속성을 통해 기존에 iBATIS 메인 설정 파일 내에서 sqlMap 태그로 일일이 지정하여야만 했던 sql 매핑 파일에 대해 Spring 의 SqlMapClientFactoryBean 빈 설정파일에서 Spring 의 유연한 리소스 추상화를 적용하여 리소스 패턴 형태로 일괄 지정이 가능하다. 이 경우 sql 매핑 파일들의 위치는 sqlMapConfig 설정 파일과 런타임에 merge 되도록 세팅된다. 이 방법은 Spring 2.5.5 이상, iBATIS 2.3.2 이상에서만 지원됨에 유의한다.

<!-- SqlMap setup for iBATIS Database Layer -->

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

<property name="configLocation" value="classpath:/META-INF/sqlmap/sqlMapConfig.xml" />

<property name="mappingLocations" value="classpath:/META-INF/sqlmap/mappings/testcase-*.xml" />

<property name="dataSource" ref="dataSource" />

</bean>

단 위와 같이 일괄 sql 매핑 파일 지정을 Spring 설정 파일에 지시하였더라도 iBATIS 의 sqlMapConfig.xml 의 DTD(http://www.ibatis.com/dtd/sql-map-config-2.dtd) 에 sqlMap 태그가 최소 1개 이상이 나타나야 하도록 지정되어 있으므로 아래와 같이 dummy sql 매핑 파일 하나를 지정하는 sqlMapConfig.xml 로 작성하면 편할 것이다.


4. SQLMapClient를 구현하는 DAO 작성

사원정보의 SELECT, INSERT 작업을 담당하는 DAO를 작성한다.


(1) EmpDAO class 작성

- SqlMapClient를 이용하여 사원정보의 DB 작업을 담당하는 DAO를 작성한다.

- com.spring.mvc.emp.dao 패키지를 생성한다.

- SqlMapClientDaoSupport를 상속받아 getSqlMapClientTemplate() 메소드를 이용하여 등록 및 조회작업을 한다.

cf.) 

@Repository 어노테이션을 EmpDAO의 class선언부에 추가한다.

@Repository 어노테이션을 지정하면 SqlMapClient 클래스에 대한 객체가 자동생성 된다.


Spring 의 SqlMapClientDaoSupport 클래스는 iBATIS 의 SqlMapClient data access object 를 위한 편리한 수퍼 클래스로 이를 extends 하는 서브 클래스에 SqlMapClientTemplate 를 제공한다. 

SqlMapClientTemplate 는 iBATIS 를 통한 data access 를 단순화하는 헬퍼 클래스로 SQLException 을 Spring dao 의 exception Hierarchy 에 맞게 unchecked DataAccessException 으로 변환해 주며 Spring 의 JdbcTemplate 과 동일한 처리 구조의 SQLExceptionTranslator 를 사용할 수 있게 해준다. 또한 iBATIS 의 SqlMapExecutor 의 실행 메서드에 대한 편리한 mirror 메서드를 다양하게 제공하므로 일반적인 쿼리나 insert/update/delete 처리에 대해 편리하게 사용할 수 있도록 권고된다. 

그러나 batch update 와 같은 복잡한 수행에 대해서는 Spring 의 SqlMapClientCallback 에 대한 명시적인 구현(보통 anonymous inner class 로 작성)이 필요하다.

com.spring.mvc.emp.dao.EmpDAO.java

package com.spring.mvc.emp.dao;


import java.util.List;

import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.spring.mvc.emp.model.Emp;


public class EmpDAO extends SqlMapClientDaoSupport {

    private static final String NAMESPACE = "emp.";


    @SuppressWarnings("unchecked")

    public List<Emp> selectEmpList() {

        return (List<Emp>) getSqlMapClientTemplate().queryForList(NAMESPACE + "selectEmpList");

    }


    public void insertEmp(Emp emp) {

        getSqlMapClientTemplate().insert(NAMESPACE + "insertEmp", emp);

    }

}


(2) plicationContext-dao.xml 설정

applicationContext-dao.xml에 EmpDAO 빈등록 작업을 한다.

iBATIS 연동 DAO 에 sqlMapClient 빈을 주입(의존성 주입)해 주어야 한다.

/srping/applicationContext-dao.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:aop="http://www.springframework.org/schema/aop"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

      

    <bean id="empDAO" class="com.spring.mvc.emp.dao.EmpDAO" >

        <property name="sqlMapClient" ref="sqlMapClient"/>           

    </bean>   

</beans>

iBATIS 연동 DAO 는 SqlMapClientDaoSupport 를 extends 하고 있으며, getSqlMapClientTemplate() 를 통해 SqlMapClientTemplate 를 얻어 iBATIS 의 data access 처리를 래핑하여 실행토록 처리하고 있다.


'Programing > Spring' 카테고리의 다른 글

[Spring] 어노테이션 기반 설정  (0) 2014.12.17
[Spring] 외부 설정 프로퍼티  (0) 2014.12.17
[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13

[Spring] iBatis 1


iBatis 1


iBatis는 자바오브젝트와 SQL문 사이의 자동 매핑 기능을 지원하는 ORM 프레임워크이다.

iBatis는 코드 내에서 자바오브젝트만을 이용해 데이터 로직을 작성할 수 있게 해주고, SQL을 별도의 파일로 분리해서 관리하게 해주며, 오브젝트-SQL 사이의 파라미터 매핑 작업을 자동으로 해주기 때문에 많은 인기를 얻고 있는 기술이다.

→ JDBC 코드 작성의 불편함을 제거해주고, 도메인 오브젝트나 DTO를 중심으로 개발이 가능하다는 장점이 있다. iBatis의 가장 큰 특징은 SQL을 자바 코드에서 분리해서 별도의 XML 파일 안에 작성하고 관리할 수 있다는 점이다.

XML에 담긴 SQL과 자바오브젝트 사이의 매핑은 이름 치환자와 빈 프로퍼티 사이의 매핑을 이용한다.

스프링 DataSource 빈 사용, 스프링 트랜잭션 적용, 예외 자동변환, 템플릿/콜백 스타일의 템플릿, SqlMapClient 팩토리 빈 등을 지원한다.


1. Spring과 iBatis의 연동 


(1) Dependency 설정

ibatis와 spring-orm의 dependency 설정을 pom.xml 에서 확인한다.

ibatis 버전이 2.3.4.726 인지 확인한다.

pom.xml

<dependency>

   <oupId>org.apache.ibatis</groupId>

   <artifactId>ibatis-sqlmap</artifactId>

   <version>2.3.4.726</version>

</dependency>

<dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-orm</artifactId>

    <version>${spring-core-version}</version>

</dependency>


(2) Spring datasource 설정

/spring/applicationContext-datasource.xml

<!-- Apache Commons DBCP DataSource -->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

    <property name="driverClassName" value="${JDBC.Driver}"/>

    <property name="url" value="${JDBC.ConnectionURL}"/>

    <property name="username" value="${JDBC.Username}"/>

    <property name="password" value="${JDBC.Password}"/>

    <property name="maxActive" value="15" />

    <property name="initialSize" value="15" />

    <property name="maxIdle" value="15" />

    <property name="minIdle" value="15" />

    <property name="testOnBorrow" value="false" />

    <property name="validationQuery" value="select 1" />

    <property name="timeBetweenEvictionRunsMillis" value="10000" />

    <property name="testWhileIdle" value="true" />  

    <property name="numTestsPerEvictionRun" value="3" />        

    <property name="minEvictableIdleTimeMillis" value="-1" />

</bean>


(3) sqlMapConfig, sqlMap XML 파일 설정

sqlMapConfig, sqlMap XML 파일을 생성한다.


1) sqlMapConfig.xml

cp.) 설정파일 역할: 설정파일에는 데이터소스, 트랜잭션 매니저, 매핑 리소스 파일 목록, 프로퍼티, 타입 별칭과 핸들러, 오브젝트 팩토리와 설정 프로퍼티 값을 넣을 수 있다.

resources/datasource/sqlMapConfig.xml 파일로 생성한 예이다.

/datasource/sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

<settings

cacheModelsEnabled="true"

enhancementEnabled="true"

lazyLoadingEnabled="true"

useStatementNamespaces="true"

/>

// 매핑정보를 담은 파일의 클래스패스를 지정한다. 매핑파일마다 <sqlMap> 태그를 추가하면된다.

<sqlMap resource="sqlmap/Emp.xml"/>

</sqlMapConfig>


2) sqlMap.xml

cp.) 매핑파일 역할: 매핑의 목적--> DB의 데이터인 SQL문(DB의 테이블)을 자바의 객체(클래스)로 전환하는 것이 주목적이다.

SQL-오브젝트 사이의 매핑정보는 XML 파일로 만들어두면 된다. 매핑정보에는 사용할 SQL문과 SQL 파라미터, 실행 결과를 어떻게 자바오브젝트로 변환하는지가 담겨 있다.

sqlMap.xml 파일에 아래와 같이 SELECT, INSERT 문장을 작성한다.

/src/main/resources/sqlmap/sqlMap.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="emp">

  <typeAlias alias="emp" type="com.spring.mvc.emp.model.Emp"/>  

  <select id="selectEmpList" resultClass="emp" >

SELECT empno, ename, job, sal, NVL(mgr,0) mgr, hiredate

FROM  emp

  </select>     

  <insert id="insertEmp"  parameterClass="emp"  >

     INSERT INTO emp (empno, ename, job, sal, mgr,  hiredate, deptno)

        VALUES (#empno#, #ename#, #job#, #sal#, 0, #hiredate#, #deptno#)

    </insert> 

</sqlMap>

테이블의 컬럼 이름과 매핑할 오브젝트의 프로퍼티 이름이 일치하면 특별한 매핑정보 없이도 자동으로 파라미터와 결과의 전환이 가능하다. 이름이 일치하지 않은 경우라면 컬럼-프로퍼티 사이의 매핑정보를 추가해주면 된다.


(4) sqlMapClient 설정

applicationContext-datasource.xml 파일에 sqlMapClient 아이디로 SqlMapClientFactoryBean 빈을 등록한다.

sqlMapClient 등록시 dataSource와 sqlMapConfig XML 파일의 의존성주입을 추가한다.

CLOB 데이터 타입을 사용하기 위해서는 DefaultLobHandler의 의존성 주입을 추가해야 한다.


cp.) iBatis의 핵심 API는 SqlMapClient 인터페이스에 담겨 있다. JDBC가 Connection, statement, ResultSet을 생성해 사용하듯이 iBatis를 이용하려면 이 SqlMapCilent를 구현한 오브젝트가 필요하다. 

SqlMapClient는 SqlMapCilentBuilder를 이용해 코드에서 생성할 수 있다. 

하지만 스프링에서는 SqlMapClient를 빈으로 등록해주는 팩토리 빈의 도움이 필요하다. 스프링이 제공하는 SqlMapClient용 팩토리 빈은 SqlMapClientFactoryBean이다. 

이 빈을 이용해서 DAO에서 사용할 SqlMapClient를 빈으로 등록해줘야 한다.


cp.) DAO가 iBatis 기능을 사용하려면 SqlMapClient가 필요하다. JDBC의 Connection처럼 모든 데이터 액세스 작업에서 필요로 하는 오브젝트이다. 스프링에서는 SqlMapClient를 싱글톤으로 등록해서 DAO에서 DI 받아 사용할 수 있다. SqlMapClient는 멀티스레드에서 공유해서 사용해도 안전한 오브젝트이다. SqlMapClient의 구현 클래스를 직접 빈으로 등록하는 대신 다음과 같이 SqlMapClientFactoryBean을 이용해 팩토리 빈이 생성해줘야 한다. 필요한 프로퍼티는 

Datasource와 앞에서 만들어둔 설정파일의 위치다.

/spring/applicationContext-datasource.xml

<!-- SqlMap setup for iBATIS Database Layer -->

<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

    <property name="configLocation" value="classpath:datasource/sql-map-config.xml"/>

    <property name="dataSource" ref="defaultDataSource" />

    <property name="lobHandler" ref="lobHandler"/>

</bean>


/filter/build-local.filter

JDBC.Driver=oracle.jdbc.driver.OracleDriver

JDBC.ConnectionURL=jdbc:oracle:thin:@127.0.0.1:1521:ORCL

JDBC.Username=scott

JDBC.Password=tiger



'Programing > Spring' 카테고리의 다른 글

[Spring] 외부 설정 프로퍼티  (0) 2014.12.17
[Spring] iBatis 2  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13

[Spring] web.xml 기본 설정


web.xml 기본 설정


1. 특정 xml 환경 파일 바라보기

DispatherServlet은 클라이언트의 요청을 전달받는 서블릿으로서, 컨트롤러나 뷰와 같은 스프링 MVC의 구성 요소를 이용하여 클라이언트에게 서비스를 제공하게 된다.

DispatherServlet의 설정은 웹 어플리케이션의 /WEB-INF/web.xml 파일에 추가하며, 다음과 같이 서블릿과 매핑 정보를 추가하면 DispatherServlet 설정이 완료된다.


web.xml 파일은 J2EE 웹 어플리케이션의 기본이 되는 설정 파일이다. DispatcherServlet 클래스를 서블릿으로 정의하며 context root 아래에 확장자 .html 파일로 요청을 하면 모두

DispatcherServlet 클래스로 랩핑하도록 정의하고 있다. 이 정의에 의해 .html의 확장자가 붙은 파일로의 액세스는 모두 DispatcherServlet로 송신된다.

DispatcherServlet 클래스에는 <servlet-name> 태그에 의해 ‘shopping-1’ 이라고 서블릿 이름을 지정하여 정의하고 있다.

이 서블릿 이름 ‘shopping-1’ 에 ‘-servlet.XML’ 라는 문자열을 부가함으로써 컨테이너 상에 로드된 스프링 설정 파일명이 결정된다. 예제의 경우 shopping-1-servlet.xml ([서블릿이름]-servlet.xml) 파일이 로드되게 된다.

<servlet>

<servlet-name>shopping-1</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>shopping-1</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>


2. ContextLoaderListener 로드 원리

DispatcherServlet 클래스를 정의하고 context root 이하로의 액세스에 대해서 DispatcherServlet을 맵핑하고 있다. 

다만, 앞 장의 예제와 달리 비즈니스 로직용의 스프링 설정 파일 (applicationContext.xml)을 작성했기 때문에 listener로 ContextLoaderListener 클래스를 정의하고 있다.

ContextLoaderListener 클래스는 스프링 설정 파일(디폴트에서 파일명 applicationContext.xml)을 로드하면 ServletContextListener 인터페이스를 구현하고 있기 때문에 ServletContext 인스턴스 생성 시(톰켓으로 어플리케이션이 로드된 때)에 호출된다. 즉, ContextLoaderListener 클래스는 DispatcherServlet 클래스의 로드보다 먼저 동작하여 비즈니스 로직층을 정의한 스프링 설정 파일을 로드한다.

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<servlet>

<servlet-name>shopping-1</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>shopping-1</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>


※ 설정 파일의 로드 순서

여러 개의 설정 파일을 이용할 경우 설정 파일의 참조 관계가 걸리기 때문에 따일의 로드 순서가 중요하다. 

위의 예제에서 사용하는 스프링 MVC의 설정 파일(shopping-1-servlet.xml)에서도 applicationContext.xml 파일로 정의된 인스턴스를 참조하고 있다.

그 때문에 shopping-1-servlet.xml 파일이 로드되기 전에 applicationContext.xml 파일이 로드되어 있어야한다.


cp.) ContextLoaderListener를 이용한 설정

일반적으로 빈 설정 파일은 하나의 파일만 사용되기 보다는 persistance, service, web등 layer 단위로 나뉘게 된다.

또한, 같은 persistance, service layer의 빈을 2개 이상의 DispatcherServlet이 공통으로 사용할 경우도 있다.

이럴때는 공통빈(persistance, service)설정 정보는 ApplicationContext에, web layer의 빈들은 WebApplicationContext에 저장하는 아래와 같은 방법을 추천한다.

공통빈 설정 파일은 서블릿 리스너로 등록된 org.springframework.web.context.ContextLoaderListener로 로딩해서 ApplicationContext을 만들고, web layer의 빈설정 파일은 DispatcherServlet이 로딩해서 WebApplicationContext을 만든다.

<!-- ApplicationContext 빈 설정 파일-->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

              <!--빈 설정 파일들간에 구분은 줄바꿈(\n),컴마(,),세미콜론(;)등으로 한다.-->

                            /WEB-INF/config/easycompany-service.xml,/WEB-INF/config/easycompany-dao.xml 

            </param-value>

</context-param>

<!-- 웹 어플리케이션이 시작되는 시점에 ApplicationContext을 로딩하며, 로딩된 빈정보는 모든 WebApplicationContext들이 참조할 수 있다.-->

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<servlet>

<servlet-name>employee</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/config/easycompany-service.xml</param-value>

</init-param>

</servlet>

        

<servlet>

<servlet-name>webservice</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/config/easycompany-webservice.xml</param-value>

</init-param>

</servlet>

이 ApplicationContext의 빈 정보는 모든 WebApplicationContext들이 참조할 수 있다. 

예를 들어, DispatcherServlet은 2개 사용하지만 같은 Service, DAO를 사용하는 web.xml을 아래와 같이 작성했다면, 

easycompany-servlet.xml에 정의된 빈정보는 easycompany-webservice.xml가 참조할 수 없지만, 

easycompany-service.xml, easycompany-dao.xml에 설정된 빈 정보는 easycompany-servlet.xml, easycompany-webservice.xml 둘 다 참조한다. ApplicationContext과 WebApplicationContext과의 관계를 그림으로 나타내면 아래와 같다.



3. 설정 파일 순서 정하기

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

version="2.5">


<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<servlet>

<servlet-name>shopping3-2</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>


<servlet-mapping>

<servlet-name>shopping3-2</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>

</web-app>

web.xml은 DispatherServlet 클래스를 정의하고, 컨텍스트 루트 이하로 들어오는 접근에 대해 DispatherServlet을 맵핑한다. 그리고 리스너로 ContextLoaderLister 클래스를 정의한다.

설정 파일을 복수로 사용할 때에는, 설정 파일을 읽는 순서가 중요하다. 설정 파일 A에서 참조하는 bean을 다른 설정 파일 B에 정의하고 있는 경우, A보다 먼저 B를 읽지 않으면 오류가 일어난다.

샘플에서 사용하는 설정 파일은 shopping3-2-server.xml과 applicationContext.xml 2가지인데, shopping3-2-server.xml에서 applicationContext.xml에 정의된 bean을 이용한다.

이런 이유로 applicationContext.xml 다음에 shopping3-1-server.xml 순서로 설정 파일을 읽는다.


web.xml에서 사용하는 org.springframework.web.context.ContextLoaderListener 클래스는 javax.servlet.ServletContextListener 인터페이스를 구현하는 클래스이다.

ContextLoaderListener 클래스의 기본은 applicationContext.xml이지만 변경도 가능하다. 샘플에서는 비즈니스 로직 계층용으로 설정 파일 'applicationContext.xml'을 만들고, ContextLoaderListner 클래스를 이용해서 읽는다. ContextLoaderListner 클래스는 ServletContext 인스턴스 생성 시(Tomcat 이 애플리케이션을 읽을 때) 호출되는 것으로, DispatherServlet 클래스가 읽기 전 ContextLoaderListener 클래스가 비즈니스 로직 계층용 설정 파일 'applicationContext.xml'을 읽는다.


4. 한 개 이상의 설정파일 설정하기

경우에 따라 한 개 이상의 설정 파일을 사용해야 하는 경우가 있다. 또는 기본 설정 파일 이름이 아닌 다른 이름의 설정 파일을 사용하고 싶은 경우도 있을 것이다.

(빈 설정 파일을 하나 이상을 사용하거나, 파일 이름과 경로를 직접 지정해주고 싶다면 contextConfigLocation 라는 초기화 파라미터 값에 빈 설정 파일 경로를 설정해준다.)

이런 경우, 다음과 같이 DispatherServlet을 설정할 때 contextConfigLocation 초기화 파라미터에 설정 파일 목록을 지정하면 된다.

 <servlet>

        <servlet-name>dispather</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfiguration</param-value>

<param-value>

/WEB-INF/main.xml

/WEB-INF/dds.xml

</param-value>

</init-param>

</servlet>

contextConfigLocation 초기화 파라미터는 설정 파일 목록을 값으로 갖는데, 이때 각 설정 파일은 콤마(","), 공백 문자(""), 탭(\t), 줄 바꿈(\n), 세미클론(":")을 이용하여 구분한다.

각 설정 파일의 경로는 웹 어플리케이션 루트 디렉터리를 기준으로 한다.


cp.) 또다른 방법

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>

/WEB-INF/security.xml 

/WEB-INF/applicationContext.xml

</param-value>

</context-param>


<servlet>

<servlet-name>shopping3-7</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>


<servlet-mapping>

<servlet-name>shopping3-7</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>

설정 파일이 applicationContext.xml 뿐만 아니라 security.xml도 있다. 복수의 설정 파일을 스프링에 읽게 할 때는 'contextConfigLocation'이라는 파라미터 이름으로, 값에 설정 파일 경로를 지정한다.

복수의 파일을 스페이스로 구획한다.(콤마로 구획 가능)


5. 인코딩 필터 배치하기

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

version="2.5">

<filter>

<filter-name>CharacterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

<init-param>

<param-name>forceEncoding</param-name>

<param-value>true</param-value>

</init-param>

</filter>


<filter-mapping>

<filter-name>CharacterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>


<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<servlet>

<servlet-name>shopping3-3</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>


<servlet-mapping>

<servlet-name>shopping3-3</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>

</web-app>


6. 전체적인 나열 보기

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

version="2.5">

<!-- 필터 설정 -->

<filter>

<filter-name>CharacterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>UTF-8</param-value>

</init-param>

<init-param>

<param-name>forceEncoding</param-name>

<param-value>true</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CharacterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<!-- 리스너 설정 -->

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>


<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>/WEB-INF/security.xml /WEB-INF/applicationContext.xml</param-value>

</context-param>


<!-- DispathcherSerlvet 설정 -->

<servlet>

<servlet-name>shopping3-7</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>shopping3-7</servlet-name>

<url-pattern>*.html</url-pattern>

</servlet-mapping>


<!-- <filter-mapping> 요소에서의 'springSecurityFilterChain'은 'org.springframework.web.filter.DelegatingFilterProxy'에 붙인 필터 이름이다. 

DelegatingFilterProxy 클래스는 스프링이 제공하는 필터이고, 실제 처리를 필터 이름에 일치하는 이름의 Bean에 위임한다. 

스프링 시큐리티는 'springSecurityFilterChain'이라는 이름으로 스프링에 Bean을 등록하기 때문에 이렇게 필터를 정의하면 스프링 시큐리티 기능이 유효해 진다. 

또한 애플리케이션의 모든 URL에 대해 이 필터 체인을 유효하게 하고, 스프링 시큐리티를 작동시킨다.-->

<filter>

<filter-name>springSecurityFilterChain</filter-name>

<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

</filter>

<filter-mapping>

<filter-name>springSecurityFilterChain</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>


<!-- 이중 로그인을 막기 위한 리스너 클래스이다.-->

<listener>

<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>

</listener>


<!-- error 페이지 설정 -->

<error-page>

<error-code>403</error-code>

<location>/WEB-INF/jsp/noAuthority.jsp</location>

</error-page>

</web-app>



'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 2  (0) 2014.12.16
[Spring] iBatis 1  (0) 2014.12.16
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13

[spring] 스프링 MVC 인터페이스 구현 클래스


스프링 MVC 인터페이스 구현 클래스


스프링 MVC를 이용하면, 웹 어플리케이션에서 모델과 뷰, 컨트롤러 사이에 있는 의존관계를 의존 관계 주입 컨테이너인 스프링에서 관리하게 된다.

스프링 MVC는 org.springframework.web 패키지와 org.springframework.servlet.패키지에 포함된 클래스를 사용한다.


1. HandlerMapping 인터페이스 구현 클래스

(1) org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping

웹 요청 URL과 스프링 설정 파일에 정의한 컨트롤러의 name 속성을 맵핑시켜 컨트롤러를 찾는다. 스프링 설정 파일에  HandlerMapping을 전혀 정의하지 않을 때의 기본 클래스

BeanNameUrlHandlerMapping 클래스는 스프링 설정 파일에 컨트롤러를 정의하면서 지정한 name 속성의 값과 웹 요청 URL을 맵핑하는 HandlerMapping 구현 클래스이다.

<bean id="indexController" name="/index.html" class="controller.IndexController"

p:shopService-ref="shopService">

</bean>

BeanNameUrlHandlerMapping 클래스는 기본인 HandlerMapping 구현 클래스이기 때문에 스프링 설정 파일에 정의하지 않아도 된다.

Controller 클래스의 name 속성에 지정한 값을 그대로 경로로 사용한다. 다음 웹 요청 URL을 사용할 때만 IndexController 클래스가 호출된다.

http://localhos:8080/shopping3-1/index.html


(2) org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

웹 요청 URL과 컨트롤러의 맵핑을 일괄 정의한다. 스프링 설정 파일에 컨트롤러의 정의가 분산되는 것을 방지한다.

스프링 MVC에서는, 어떤 URL에 요청이 들어오면 어느 컨트롤러가 처리할지를 컨트롤러와 URL의 맵핑으로 연관 짓는데, SimpleUrlHandlerMapping 클래스를 사용하면 그 맵핑을 설정 파일 한 곳에 모아 작성할 수 있다.

따라서, 스프링 MVC는 컨트롤러 클래스와 URL의 맵핑을 한곳에서 관리하기 위한 SimpleUrlHandlerMapping 클래스를 제공한다.

<!-- HandlerMapping -->

<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<value>

/index.html=indexController

/detail.html=detailController

</value>

</property>

</bean>


<!-- Controller -->

<bean id="indexController" class="controller.IndexController" p:shopService-ref="shopService"></bean>


<bean id="detailController" class="controller.DetailController"

p:shopService-ref="shopService"> 

</bean>

SimpleUrlHanlerMapping 클래스에는 Properties 타입 maapings 프로퍼티가 있다. 이 mapping 프로퍼티에 웹 요청 URL과 컨트롤러를 지정한다. 


(3) org.springframework.web.servlet.handler.ClassNameHandlerMapping

컨트롤러에 어노테이션을 부여해서 웹 요청 URL과의 관련을 정의한다.


(4) org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping

ControllerClassNameHandlerMapping 클래스는 컨트롤러의 클래스 이름에서 URL을 추출한다. 클래스 이름에서 'Controller'를 뺀 나머지를 모두 소문자로 바꾼 문자열이 URL이 된다.

ex.) IndexController : /index*


2. ViewResolver 인터페이스 구현

(1) org.springframework.web.servlet.view.InternalResolverViewResolver

WEB-INF 폴더 안에 있는 뷰 자원을 해결한다. 스프링 설정 파일에 ViewResolver를 전혀 정의하지 않을 때의 기본 클래스이다.

InternalResolverViewResolver 클래스는 컨트롤러가 반환한 뷰 정보를 컨텍스트 상의 경로로 변화시켜 처리하는 클래스이다.

스프링 MVC는 기본 ViewResolver인 InternalResolverViewResolver를 암묵적으로 사용한다.

하지만 뷰 정보에 prefix 프로퍼티나 suffix 프로퍼티를 추가하거나, 뷰의 구현 클래스를 지정할 수 있다.(이를 이용하면 프로그램에 직접 경로를 기술하지 않고, 이동할 뷰 파일을 배치하는 규칙에 유연하게 대응할 수 있다.)

<bean id="internalResourceViewResolver"

class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="viewClass">

<value>org.springframework.web.servlet.view.JstlView</value>

</property>

<property name="prefix">

<value>/WEB-INF/jsp/</value>

</property>

<property name="suffix">

<value>.jsp</value>

</property>

</bean>


(2) org.springframework.web.servlet.view.ResourceBundleViewResolver

프로퍼티 파일에서 뷰 이름과 그 실체인 뷰를 관련 짓는다. 프로퍼티의 파일은 클래스패스 상에 배치한다.

ResourceBundleViewResolver 클래스는 View 인터페이스를 구현하는 클래스와, 이동할 뷰의 지정과 뷰 이름의 맵핑을 프로퍼티 파일로 관리한다.

InternalResolverViewResolver 클래스는 prefix, suffix를 지정해서 이동할 뷰 이름을 간략하게 할 수 있지만, 실제 뷰 이름을 변경하면 관련된 컨트롤러나 설정 파일도 수정해야 한다.

하지만, ResourceBundleViewResolver 클래스에서는 컨트롤러에서 지정한 것은 프로퍼티 파일에 정의된 뷰 이름이고, 뷰 이름은 설제 뷰 파일 이름이 아닌 임의의 이름을 붙일 수 있다.

때문에 뷰 파일 이름을 변경하더라도, 뷰 이름을 변경할 필요가 없고, 프로퍼티 파일 맵핑 내용을 수정할 뿐이다. 컨트롤러를 수정할 필요도 없다.

ResourceBundleViewResolver 클래스에서 사용하는 프로퍼티 파일 이름은 설정 파일의 basename 프로퍼티에 지정한다. 

<!-- ViewResolver -->

<bean id="resourceBundleViewResolver"

class="org.springframework.web.servlet.view.ResourceBundleViewResolver">

<property name="basename">

<value>views</value>

</property>

</bean>

basename 프로퍼티에 'views'라고 지정하고 있으므로, 스프링 MVC는 확장자 '.properties'를 추가해서 'views.properties'를 참조한다.

#userEntry View

userEntry.(class)=org.springframework.web.servlet.view.JstlView

userEntry.url=WEB-INF/jsp/userEntry.jsp

프로퍼티 파일에는, '뷰 이름.(class)'를 키로 해서 값에 View 인터페이스를 구현하는 클래스를, '뷰이름.url'을 키로 해서 값에 이동할 뷰 파일을 지정한다. 뷰 이름은 임의로 정할 수 있다.


(3) org.springframework.web.servlet.view.velocity.VelocityViewResolver

벨로시티 템플릿으로 만든 뷰를 해결한다.


3. View 인터페이스 구현

(1) org.springframework.web.servlet.view.internalResourceView

JSP 등 자원용 뷰, 요청 속성에 모델을 지정하고, RequestDispather클래스를 참조해서 지정된 뷰에 전달한다.


(2) org.springframework.web.servlet.view.JstlView

JSTL를 사용한 페이지용 뷰, InternalResourceView 클래스의 서브 클래스, 스프링의 메시지 자원 파일을 JSTL 포맷 태그에서 참조할 수 있게 된다.

JstlView 클래스는 JSTL을 사용해서 JSP를 만드는 것을 지원하는 클래스이며, View 인터페이스를 구현하고 있다. JstlView 클래스를 사용하면, JSTL 포맷 태그에서 스프링의 메시지 자원에 접근할 수 있다.

JstlView 클래스는 앞에서 사용한 InternalReaourceView 클래스의 서브 클래스이다. 


(3) org.springframework.web.servlet.view.velocity.VelocityView

벨로시티 템플릿용 뷰


org.springframework.web.servlet.view.json.MappingJacksonJsonView

JSON 형식으로 출력하기 위한 뷰, JSON으로의 변환 라이브러리로서 Jackson 라이브러리가 필요




'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13

[Spring] 스프링 MVC 패턴 개요

스프링 MVC 패턴 개요


1. 스프링 MVC 패턴

‘MVC(Model View Controller)’란 비즈니스 규칙은 표현하는 도메인 모델(Model)과 프레젠테이션을 표현하는 View를 분리하기 위하여 양측 사이에 컨트롤러를 배치하도록 설계한 디자인 패턴이다.

‘스프링 MVC ’ 란 스프링이 제공하는 웹 어플리케이션 구축 전용의 MVC 프레임워크이다. 스프링 MVC를 이용함으로써 웹 어플리케이션의 Model, View, Controller 사이의 의존 관계를 DI 컨테이너에서 관리하고 통일된 유연한 웹 어플리케이션을 구축할 수 있다.


2. 스프링 MVC 처리 흐름


스프링 MVC는 스트릿츠 등 웹 어플리케이션 프레임워크와 동일하게 Front Controller 패턴을 채용하고 있다. 

FrontController 패턴이란 핸들러 오브젝트를 매개로 하여 요청을 분배함으로써 요청을 통합하고, 요청에 대한 통일된 처리를 기술할수 있도록하기 위한 패턴이다.

다음 그림에서 보듯이 브라우저로부터 송신된 요청은 모두 스프링 MVC에 의해 제공되는DispatherServlet 클래스에 의해 관리되고 있다.


웹 브라우저로부터의 요청(Request)은 DispatcherServlet 인스턴스로 송신된다. 요청을 받은 DispatcherServlet 인스턴스는 어플리케이션 안에서 공통 처리를 실행한 다음, requestURL 고유의 처리를 실행하는 Request 컨트롤러(Controller 인스턴스)를 호출한다. 일반적으로 Request 컨트롤러는 처리 단위 별로 개발자가 작성하기 때문에 DispatcherServlet 인스턴스는 지정된 RequestURL이 어느 Request 컨트롤러에 맵핑되어 있는기를 알아야 한다. 그러나 DispatcherServlet은 어플리케이션에서 하나의 인스턴스일 뿐 랩핑 정보를 관리하는 기능을 갖고 있지 않는다. 

RequestURL과 Request 컨트롤러의 맵핑을 관리하고 있는 것은 HanadlerMapping 인스턴스이다. DispatcherSerγlet 인스턴스 HandlerMapping 인스턴스를 참조하여 HandlerMapping 인스턴스로부터 반환된 Controller 인스턴스로 처리를 전달한다. 처리가 전달된 Controller 인스턴스는 필요한 비즈니스 로직을 호출하여 처리 결과(모델)와 이동할 View 정보를 DispatcherServlet에 반환한다. 이들의 정보(모델과 View)는 스프링MVC가 제공하는 ModeAndView 인스턴스로 취급된다. 

그리고 Controller 인스턴스로부터 반환된 View는 논리 정보이기 때문에 DispatcherServlet 인스턴스는 그 View의 실체를 ViewResolver 인스턴스에 문의한다. DispatcherServlet은 ViewResolver 인스턴스에 의해 해결된 View 인스턴스에 대해 모댈을 rendering하여 처리 결과를 브라우저에 표시한다 이상이 스프링 MVC 처리의 흐름이다.


위의 그림에 있는 HandlerMapping, Controller, ViewResolver, View는 모두 스프링 MVC가 제공하는 인터페이스이다. 

그러나 인터페이스만으로는 어플리케이션이 이루어지지 않으므로 인터페이스를 구현한 클래스가 필요하다. 

하지만 어플리케이션 개발자가 각각의 인터페이스의 구현 클래스를 준비해야만 하는 것은 아니다. 스프링 MVC에는 인터페이스뿐만 아니라 각각의 인터페이스의 구현 클래스도 포함하고 있다.

통상 개발에서는 Controller를 제외한 HandlerlMapping, Viewresolver, View 인터페이스의 구현 클래스는 스프링 MVC에서 제공히는 구현 클래스를 활용하면 된다(Controller 인터페이스를 구현한 편리한 클래스도 준비되어 있다).

스프링 MVC는 이들의 구성 정보를 DI 컨테이너에서 관리하고 있다. 스프링 설정 파일을 어느 HandlerMapping의 구현 클래스를 사용할 것인지는 Controller 클래스로부터 호출할 비즈니스 로직을 연관 지음으로써 어플리케이션의 구성을 관리하면 된다.


(1) DispatcherServlet

웹 브라우저로부터 송신된 Request를 일괄적으로 관리한다 .

웹 브라우저로부터 요청은 DispatherServlet 인스턴스로 송신된다. DispatherSerlvet 인스턴스는 지정된 RequestURL이 어느 Request 컨트롤러에 맵핑되어 있는 가를 알아야 한다.


cf.) DispatherServlet 설정과 ApplicationContext 관계

DispatherServlet은 클라이언트의 요청을 중앙에서 처리하는 스프링 MVC의 핵심 구성 요소이다. 

web.xml 파일에 한 개 이상의 DispatherServlet을 설정할 수 있으며, 각 DispatherServle은  한 개의 WebApplicationContext를 갖게 된다.

또한, 각 DispatherServlet이 공유할 수 있는 빈을 설정할 수도 있다. 

DispatherServlet과 웹 어플리케이션을 위한 설정 방법 및 둘 사이의 관계에 대해서 살펴보자.


(2) HandlerMapping

- RequestURL과 Controller 클래스의 맵핑을 관리한다.

- HandlerMapping 인스턴스의 정의에 정의된 정보로부터 Controller에 해당하는 클래스(Request 컨트롤러)가 결정된다.

- BeanNameUrlHandlerMapping 클래스는 스프링 설정 파일 내에 정의된 Controller 클래스의 name 속성과 RequestURl과 맵핑하는 HandlerMapping 인터페이스의 구현 클래스이다.

- BeanNameUrlHandlerMapping 클래스는 name 속성으로 지정된 값을 그대로 context root 이하의 패스로 처리한다. 즉, 다음의 RequestURL이 웹 브라우저에서 보내졌을 경우에 여기에서 지정한 Controller 클래스가 호출되게 된다. HandlerMapping 인터페이스의 구현 클래스 중 디폴트 클래스:BeanNameUrlHandlerMapping


(3) Controller

Controller 인스턴스는 필요한 비즈니스 로직을 호출하여 처리 결과(모델)와 이동할 View 정보를 DispatherServlet에 반환된다. 

이들의 정보(모델과 view)는 스프링 MVC가 제공하는 ModelAndView 인스턴스로 취급된다. 

그리고 Controller 인스턴스로부터 반환된 View는 논리정보이기 때문에 DispatherServlet 인스턴스는 그 View의 실체를 ViewResolver 인스턴스에 문의한다. 

DispatherServlet은 ViewResolver 인스턴스에 의해 해결된 View 인스턴스에 대해 모델을 rendering하여 처리 결과를 브라우저에 표시한다. 

cf.) HandlerMapping, Controller, ViewResolver, View는 모두 스프링 MVC가 제공하는 인터페이스이다. 그러나 인터페이스만으로는 어플리케이션이 이루어지지 않으므로 인터페이스를 구현 클래스가 필요한다.

스프링 MVC에는 인터페이스뿐만 아니라 각각의 인터페이스의 구현 클래스도 포함하고 있다.

통상 개발에서는 Controller를 제외한 HandlerMapping, Viewresolver, View 인터페이스의 구현 클래스는 스프링 MVC에서 제공하는 구현 클래스를 활용하면 된다.(Controller 인터페이스를 구현한 편리한 클래스도 준비되어 있다.) 

스프링 MVC는 이들의 구성 정보를 DI 컨테이너에서 관리하고 있다.


(4) ModelAndView

1) Controller 처리 결과 후 응답할 view와 veiw에 전달할 값을 저장.

2) 생성자 

- ModelAndView(String viewName) : 응답할 view설정

- ModelAndView(String viewName, Map values) : 응답할 view와 view로 전달할 값들을 저장 한 Map 객체 

- ModelAndView(String viewName, String name, Object value) : 응답할 view이름, view로 넘길 객체의 name-value

3) 주요 메소드

- setViewName(String view) : 응답할 view이름을 설정

- addObject(String name, Object value) : view에 전달할 값을 설정 – requestScope에 설정됨

- addAllObjects(Map values) : view에 전달할 값을 Map에 name-value로 저장하여 한번에 설정 - requestScope에 설정됨

4) Redirect 방식 전송

- view이름에 redirect: 접두어 붙인다.ex) mv.setViewName(“redirect:/welcome.html”);


protected ModelAndView HandlerequestInternal(HttpServletRequest req,  HttpServletResponse res) throws Exception{

//Business Logic 처리

ModelAndView mv = new ModelAndView();      

mv.setViewName(“/hello.jsp”);

mv.addObject(“greeting”, “hello world”);

return mv;

}


(5) ViewResolver

Controller 클래스로부터 반환된 View 정보가 논리적인 View 이름일 경우에는 bean 설정파일에 정의되어 있는 ViewResolver 클래스를 이용하여 클라이언트에게 출력할 View 객체를 얻게 된다.

InternalResource ViewResolver 클래스는 Request 컨트롤러로부터 반환된 View 정보를 context root 이하의 패스로서 처리한다.

1) Controller가 넘긴 view이름을 통해 알맞은 view를 찾는 역할

- Controller는 ModelAndView 객체에 응답할 view이름을 넣어 return.

- DispatchServlet은 ViewResolver에게 응답할 view를 요청한다.

- ViewResolver는 View 이름을 이용해 알 맞는 view객체를 찾는다.

2) 다양한 ViewResolver를 SpringFramework는 제공한다.

- InternalResourceViewResolver : 뷰의 이름을 JSP, HTML등과 연동한 View를 return

- ViewResolver – Spring 설정파일에 등록한다.

Controller

ModelAndView mv = new ModelAndView();

mv.setViewName(“hello”)

위의 경우

/WEB-INF/jsp/hello.jsp 를 찾는다.


(6) View

프레젠테이션층으로의 출력 데이터를 설정한다.



'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] AOP 용어 설명  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13

[Spring] AOP 용어 설명


AOP 용어 설명



1. Advice

언제 공통 관심 기능을 핵심 로직에 적용할 지를 정의하고 있다. 예를 들어, '메서드를 호출하기 전'(언제)에 '트랜잭션을 시작한다.'(공통기능)기능을 적용한다는 것을 정의하고 있다.

Target 클래스에 조인 포인트에 삽입되어져 동작(적용할 기능)할 수 있는 코드를 '어드바이스'라 한다.

관점으로서 분리되고 실행시 모듈에 위빙된 구체적인 처리를 AOP에서는 Advice라고 한다. Advice를 어디에서 위빙하는지는 뒤에 나오는 PointCut이라는 단위로 정의한다.

또한 Advice가 위빙되는 인스턴스를 '대상객체'라고 한다.

advice는 Pointcut에서 지정한 Jointpoint에서 실행되어야하는 코드이다.


cp.) 스프링의 Advice 타입

- Around Advice: Joinpoint 앞과 뒤에서 실행되는 Adcvice

- Before Advice: Joinpoint 앞에서 실행되는 Advice

- After Returning Advice: Jointpoint 메서드 호출이 정상적으로 종료된 뒤에 실행되는 Advice

- After Throwing Advice: 예외가 던져질 때 실행되는 Advice

- Introduction:  클래스에 인터페이스와 구현을 추가하는 특수한 Advice


2. JoinPoint

Advice를 적용 가능한 지점을 의미한다. 메서드 호출, 필드 값 변경 등이 Joinpoint에 해당한다.

클래스의 인스턴스 생성 시점', '메소드 호출 시점', '예외 발생 시점'과 같이 어플리케이션을 실행할 때 특정 작업이 시작되는 시점을 '조인포인트'라고 한다

실행시의 처리 플로우에서 Advice를 위빙하는 포인트를 JointPoint라고 한다. 구체적으로는 메서드 호출이나 예외발생이라는 포인트를 Joinpoint라고 한다.

인스턴의 생성시점, 메소드를 호출하는 시점, Exception이 발생하는 시점과 같이 어플리케이션이 실행될 때 특정작업이 실행되는 시점을 의미한다.


3. Pointcut

Joinpoint의 부분 집합으로서 실제로 Advice가 적용되는 Jointpoint를 나타낸다. 스프링에서는 정규 표현식이나 AspectJ 문법을 이용하여 Pointcut을 정의할 수 있다.

여러 개의 조인포인트를 하나로 결합한 것을 포인트 컷이라 한다.

하나 또는 복수의 Jointpoint를 하나로 묶은 것을 Pointcut 이라고 한다. Advice의 위빙 정의는 Pointcut을 대상으로 설정한다. 하나의 Pointcut에는 복수 Advice를 연결할 수 있다. 반대로 하나의 Advice를 복수 Pointcut에 연결하는 것도 가능하다.

Pointcut(교차점)은 JoinPoint(결합점)들을 선택하고 결합점의 환경정보를 수집하는 프로그램의 구조물이다. Target 클래스와 Advice가 결합(Weaving)될 때 둘 사이의 결합 규칙을 정의하는 것이다.


4. Weaving

Advice를 핵심 로직 코드에 적용하는 것을 weaving 이라고 한다.(분리한 관점을 여러 차례 모률에 삽입하는 것을 AOP에서는 위빙 (Weaving: 엮기)이라고 부른다.) 즉 공통 코드를 핵심 로직 코드에 삽입하는 것이 weaving이다.

어드바이스를 핵심 로직 코드에 삽입하는 것을  위빙이라고 한다.

Aspect를 target 객체에 제공하여 새로운 프록시 객체를 생성하는 과정을 말한다.


5. Aspect

여러 객체에 공통으로 적용되는 공통 관심 사항을 Aspect라고 한다. 트랜잭션이나 보안 등이 Aspect의 좋은 예이다.

여러 객체에 공통으로 적용되는 공통 관점 사항을 에스펙트라 한다.

Aspect는 AOP의 중심단위, Advice와 Pointcut을 합친 것이다.(Advisor)


6.Target

핵심 로직을 구현하는 클래스를 말한다.

충고를 받는 클래스를 대상(target)이라고 한다. 대상은 여러분이 작성한 클래스는 물론, 별도의 기능을 추가하고자 하는 써드파티 클래스가 될 수 있다.


7. advisor

어드바이스와 포인트컷을 하나로 묶어 취급한 것을 '어드바이저'라 부른다.

advisor와 Pointcut을 하나로 묶어 다루는 것을 Advisor라고 한다. Advisor는 스프링 AOP에만 있는 것인데, 관점 지향에서 관점을 나타내는 개념이라고 할 수 있다.


8. proxy

대상 객체에 Advice가 적용된 후 생성된 객체




cp.) 언제,어디서,누가,무엇을,어떻게, 왜 할 때 AOP 걸어라.....

내가 원하는 메소드 실행할 때(언제)

객체(어디서)

로그를 찍는 기능(누가)

로그를(무엇을)

앞뒤로(어떻게)


cp.) AOP 핵심

1. 대상: Target

2. 적용할 기능: advice

3. 대상의 어디에서 적용할지 구체적인 명시:pointcut


aspect와 advice의 관계(추상 명사와 구체 명사의 관계)

advice라는 코드를 내가 만듬

로그를 찍는 기능 자체를 aspect라고 한다. 




'Programing > Spring' 카테고리의 다른 글

[Spring] iBatis 1  (0) 2014.12.16
[Spring] web.xml 기본 설정  (1) 2014.12.13
[spring] 스프링 MVC 인터페이스 구현 클래스  (0) 2014.12.13
[Spring] 스프링 MVC 패턴 개요  (0) 2014.12.13
[Spring] 의존관계 주입  (0) 2014.12.13