2009년 8월 19일 수요일

스프링에서 Content Type별 View 자동 맵핑 하기

프로젝트를 진행 하다 보면 제일 많이 사용하는 뷰
(org.springframework.web.servlet.view.JstlView)
외에 다양한 뷰가 필요 합니다.
(ajax,pdf,excel 또는 특정 x-internet 전용..등)
이런한 다양한 뷰를 맵핑 하기 위해서 여러 방법이
존재 합니다.
일반적인 방법은 아래와 같습니다.

<bean id="jsonView" class="net.sf.json.spring.web.servlet.view.JsonView"/>



ModelAndView modelAndView = new ModelAndView("jsonView");


하지만 이런 경우는 코드에 특정 뷰에 대한 하드 코딩을
해야 하는 단점이 있습니다.
그래서 제가 생각 하는 방법은 URL extension
부분을 parsing해서 해당되는 Content Type뷰를
리턴해서 찾아가는 방법 입니다.
예를 들어서 http://localhost/foo.json 이면 jsonView로
http://localhost/foo.do 이면 JstlView로 맵핑 되는 것입니다.
이럴경우 각 프로젝트별 ContentType별 URL Extension 정책
이 필요하며 당연히 문서화 해야 겠죠
아래는 개인적으로 사용하는 URL별 Content Type 정책 입니다.
ajax : http://foo.ajax
pdf : http://foo.pdf
excel : http://foo.excel
jsp : http://foo.htm
(다른곳에선 .do,.action,.시스템명 이렇게 많이들 하시죠 ^^)

  • web.xml 설정

<servlet>

<servlet-name>webAppServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/commons/commons-servlet.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>webAppServlet</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>webAppServlet</servlet-name>
<url-pattern>*.ajax</url-pattern>
</servlet-mapping>


  • URLViewNameResolver 클래스 작성




import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.view.AbstractView;

public final class URLViewNameResolver {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private Map<String, AbstractView> resolverMap;

private URLViewNameResolver() {
}

public void setResolverMap(Map resolverMap) {
this.resolverMap = resolverMap;
}

public final String getForward(final HttpServletRequest request) {
String url = request.getServletPath();
return getConvetViewName(request, url);
}

public final String getForward(final HttpServletRequest request,
final String url) {
return getConvetViewName(request, url);
}

private final String getConvetViewName(final HttpServletRequest request,
final String forwardURL) {
String extension = FilenameUtils.getExtension(forwardURL);
AbstractView view = this.resolverMap.get(extension);
if (view != null) {
return view.getBeanName();
}
return convetURL(forwardURL);
}

private String convetURL(final String url) {

if (url == null || StringUtils.contains(url, ":redirect")) {
return url;
}
if (url.lastIndexOf('.') > -1) {
return StringUtils.trimToEmpty(url.substring(0, url
.lastIndexOf('.')));
}
return url;
}
}


  • URLViewNameResolver 빈 설정


<bean id="jsonView" class="net.sf.json.spring.web.servlet.view.JsonView" />

<bean id="URLViewNameResolver"
class="com.beyondweb.framework.core.web.view.URLViewNameResolver">
<property name="resolverMap">
<map>
<entry key="ajax" ref="jsonView">
</entry>
</map>
</property>
</bean>

여기서 중요한 것 resolverMap 부분 입니다. key 값은 web.xml에 선언된
content type을 입력 합니다.
value 값은 View가 선언된 스프링 빈 id 입니다.
여기서는 "jsonView"를 입력 합니다.


  • 사용법

private URLViewNameResolver uRLViewNameResolver;


public void setURLViewNameResolver(URLViewNameResolver viewNameResolver) {
uRLViewNameResolver = viewNameResolver;
}

public final ModelAndView handlerRequest(final HttpServletRequest request,
final HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView(uRLViewNameResolver
.getForward(request));
DummyMember dummyMember = new DummyMember();
dummyMember.setId("xxxxxxx");

modelAndView.addObject(dummyMember);
return modelAndView;
}

기본적으로 JstlView를 사용함으로 jsp는 선언할 필요가 없습니다.
그외에 사용자 뷰만 설정 하면 됩니다.
즉 URL에 맵핑된 설정이 없으면 JstlView를 리턴 합니다.

댓글 없음:

댓글 쓰기