SpringMVC 사용자 정의 보기 + 콘 텐 츠 협상 (RESTful MVC)
24507 단어 SpringMVC 다 중 보기 협상
이 예 에서 저 희 는 JSP 파일, freemaker, jasper, SWF 파일 (flash 파일) 과 사용자 정의 접미사 이름 (config 와 txt) 의 파일 을 제공 합 니 다. SWF 보기 와 사용자 정의 파일 접미사 이름 의 보 기 를 더욱 편리 하 게 지원 하기 위해 사용자 정의 보기 대상 을 개 발 했 습 니 다.이 보기 대상 을 사용 하여 SWF 파일 과. config. txt 파일 을 지원 할 수 있 기 를 바 랍 니 다. 또한 두 개의 보기 해석 기 를 개발 하여 이 예 를 실현 합 니 다.
실제로 Spring 은 RESTful 의 다 중 보기 해석 기 - contentNegotiatingView Resolver (이하 CNV) 를 제공 합 니 다. 요청 한 파일 접미사 이름 이나 요청 한 Accept 헤더 나 요청 한 매개 변수 에 따라 보 기 를 찾 을 수 있 습 니 다.CNV 자 체 는 보 기 를 찾 는 것 을 책임 지지 않 습 니 다. 보 기 를 찾 는 작업 대 리 를 등 록 된 보기 해석 기 에 만 맡 깁 니 다. 그러나 실제 개발 에서 보 기 를 모두 CNV 에 맡 기 면 CVN 은 좀 서 툴 러 보 입 니 다. 예 를 들 어 테스트 에서 freemarker 와 Internal Resource View Resolver 를 모두 CNV 의 view Resolvers 에 넣 는 것 을 발 견 했 습 니 다.freemarker 로 돌아 가 는 모든 보 기 는 Internal ResourceView Resolver 로 달 려 가 처 리 했 습 니 다. 결 과 는 404 입 니 다.하지만 제 이 슨 과 xml 를 CNV 로 처리 하 는 것 은 상당히 편리 하 다 고 할 수 있다.이 예 에서 RESTful MVC 는 제 이 슨 과 xml 를 CNV 로 처리 하 는 것 이다.방문http://localhost/sample/message.json 그러면 고객 센터 로 돌아 가 는 데이터 내용 형식 은 json 이 고 데 이 터 는 ModelMap 에 지 니 고 있 는 데이터 입 니 다.
사용자 정의 보기 코드
프로그램 을 간소화 하기 위해 이 보기 클래스 는 브 라 우 저가 직접 표시 할 수 있 는 요청 파일 자원, 예 를 들 어 텍스트 파일, SWF 파일 등 을 처리 하 는 데 만 사 용 됩 니 다.
public class GenericFileView extends AbstractUrlBasedView {
// default content type
private final static String CONTENT_TYPE = "text/plain";
//content of http response
private String responseContent;
public GenericFileView() {
super();
setContentType(CONTENT_TYPE);
}
@Override
public void setContentType(String contentType) {
super.setContentType(contentType);
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType(getContentType());
response.getWriter().write(this.responseContent);
response.getWriter().close();
}
/**
* Set http request content
* @param responseContent
*/
public void setResponseContent(String responseContent) {
this.responseContent = responseContent;
}
}
2. Spring 보기 해석 기
보기 클래스 가 있 으 면 이 보기 클래스 의 보기 해석 기 를 찾 아야 합 니 다.모든 보기 해상도 기 는 인터페이스 org. spring framework. web. servlet. ViewResolver 를 실현 해 야 하지만 보기 의 실현 과 마찬가지 로 Spring 은 추상 적 인 추상 적 인 AbstractCaching ViewResolver 가 자주 사용 하 는 Spring 의 보기 해상도 기 를 제공 하여 이 추상 적 인 종 류 를 계승 하여 우 리 는 똑 같이 이 추상 적 인 종 류 를 실현 함으로써 개발 작업 을 절약 할 수 있다.
public class GenericFileViewResolver extends AbstractCachingViewResolver
implements Ordered {
private Logger logger = Logger.getLogger(GenericFileViewResolver.class
.getName());
private int order = Integer.MIN_VALUE;
// requested file location under web app
private String location;
// View
private String viewName;
public void setViewName(String viewName) {
this.viewName = viewName;
}
public void setOrder(int order) {
this.order = order;
}
public void setLocation(String location) {
this.location = location;
}
public int getOrder() {
return this.order;
}
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
if (location == null) {
throw new Exception(
"No location specified for GenericFileViewResolver.");
}
String requestedFilePath = location + viewName;
Resource resource = null;
//String url = "";
try {
logger.finest(requestedFilePath);
resource = getApplicationContext().getResource(requestedFilePath);
//url = resource.getURI().toString();
} catch (Exception e) {
// this exception should be catched and return null in order to call
// next view resolver
logger.finest("No file found for file: " + requestedFilePath);
return null;
}
logger.fine("Requested file found: " + requestedFilePath + ", viewName:" + viewName);
//get view from application content, scope=prototype
GenericFileView view = this.getApplicationContext().getBean(this.viewName, GenericFileView.class);
view.setUrl(requestedFilePath);
view.setResponseContent(inputStreamTOString(resource.getInputStream(), "UTF-8"));
return view;
}
final static int BUFFER_SIZE = 4096;
/**
* Convert Input to String based on specific encoding
*
* @param in
* @param encoding
* @return
* @throws Exception
*/
public static String inputStreamTOString(InputStream in, String encoding)
throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] data = new byte[BUFFER_SIZE];
int count = -1;
while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
outStream.write(data, 0, count);
data = null;
return new String(outStream.toByteArray(), encoding);
}
}
3. 사용자 정의 다 중 보기 해석 기
package org.mkwu.web.view.viewresolver;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.AbstractCachingViewResolver;
public class MultipleViewResolver extends AbstractCachingViewResolver implements Ordered{
private int order = Integer.MIN_VALUE;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
private Map<String, ViewResolver> resolvers;
public void setResolvers(Map<String, ViewResolver> resolvers) {
this.resolvers = resolvers;
}
private String getViewResolverKey(String fileExtension){
Iterator<String> keyIt = resolvers.keySet().iterator();
while (keyIt.hasNext()) {
String viewResolverKey = (String) keyIt.next();
String[] arr = viewResolverKey.split(",");
for (String subKey : arr) {
if(subKey.equals(fileExtension)) return viewResolverKey;
}
}
return null;
}
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
String fileExtension = StringUtils.getFilenameExtension(viewName);
// return null to invoke next resolver if no extension found
if (fileExtension == null) {
return null;
}
String viewResolverKey = getViewResolverKey(fileExtension);
ViewResolver resolver = resolvers.get(viewResolverKey);
// get resolver by extension
//return null to invoke next resolver if no resolver found
return resolver == null ? null : resolver.resolveViewName(viewName,locale);
}
}
4. SpringMVC 설정 도 본 고의 중점 이다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<!-- @Controller -->
<context:component-scan base-package="com.martinwu.example" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven/>
<!-- -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- json , json java -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
<!-- xml , xml java xml -->
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"p:marshaller-ref="xstreamMarshaller" p:unmarshaller-ref="xstreamMarshaller" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
</list>
</property>
</bean>
<!-- Jaxb2Marshaller,controller shema. pojo,pojo @XmlRootElement , : xstream , shema-->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.martinwu.example.entity.User</value>
</list>
</property>
</bean>
<!-- -->
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="streamDriver">
<bean class="com.thoughtworks.xstream.io.xml.StaxDriver" />
</property>
<property name="annotatedClasses">
<list>
<value>com.martinwu.example.entity.User</value>
</list>
</property>
</bean>
<!-- -->
<bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>i18n/messages</value>
</list>
</property>
<property name="useCodeAsDefaultMessage" value="true"/>
</bean>
<!-- mapping Controller path default servlet handler -->
<!-- web.xml DispatcherServlet <url-pattern>/</url-pattern> , -->
<mvc:default-servlet-handler/>
<!--
<mvc:resources mapping="/images/**" location="/WEB-INF/images/" />
<mvc:resources mapping="/css/**" location="/WEB-INF/css/" />
<mvc:resources mapping="/js/**" location="/WEB-INF/js/" />
-->
<!-- ========================= VIEW ========================= -->
<!-- FreeMarker -->
<!-- freemarker -->
<bean id="freemarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/" />
<property name="defaultEncoding" value="UTF-8" />
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">10</prop>
<prop key="locale">zh_CN</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="number_format">#.##</prop>
</props>
</property>
</bean>
<!-- , -->
<bean id="multipleViewResolver" class="com.martinwu.example.view.viewresolver.MultipleViewResolver" p:order="0">
<property name="resolvers">
<map>
<entry key="config,txt">
<bean class="com.martinwu.example.view.viewresolver.GenericFileViewResolver"
p:location="/WEB-INF/config/" p:cache="false">
<property name="viewName" value="configFileView"/>
</bean>
</entry>
<entry key="swf">
<bean class="com.martinwu.example.view.viewresolver.GenericFileViewResolver"
p:location="/WEB-INF/swf/" p:cache="false">
<property name="viewName" value="swfFileView"/>
</bean>
</entry>
<entry key="ftl">
<bean id="freeMarkerResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" p:order="2">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
</entry>
<entry key="jasper">
<!-- Jasper Report -->
<bean id="jasperReportsViewResolver" class="org.springframework.web.servlet.view.jasperreports.JasperReportsViewResolver"
p:viewClass="com.scinvest.util.support.JasperView"
p:requestContextAttribute="rc"
p:prefix="/WEB-INF/reportView/">
<!-- dataSources key -->
<property name="reportDataKey">
<value>datasource</value>
</property>
<property name="exporterParameters">
<map>
<!-- html ,jasperReport -->
<entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.IMAGES_URI">
<value>#{rpe.resourceRoot}/images/reports/</value>
</entry>
<entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.CHARACTER_ENCODING">
<value>UTF-8</value>
</entry>
<entry key="net.sf.jasperreports.engine.export.JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET">
<bean id="java.lang.Boolean.TRUE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
</entry>
</map>
</property>
</bean>
</entry>
<entry key="jsp">
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="contentType" value="text/html"/>
<property name="prefix" value="/WEB-INF/views/"/>
</bean>
</entry>
</map>
</property>
</bean>
<!-- view , /blog/1.json /blog/1.xml -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<!-- true Accept Header -->
<property name="ignoreAcceptHeader" value="true"/>
<!-- mimeType , /user.json => application/json -->
<property name="favorPathExtension" value="true"/>
<!-- /userinfo/123?format=json -->
<property name="favorParameter" value="false"/>
<property name="parameterName" value="format"/>
<property name="defaultContentType" value="text/html"/>
<property name="mediaTypes"> <!--favorPathExtension, favorParameter true -->
<map>
<!-- <entry key="pdf" value="application/pdf"/> -->
<!-- <entry key="xls" value="application/vnd.ms-excel"/> -->
<entry key="html" value="text/html;charset=UTF-8"/>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- for application/json -->
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
<!-- for application/xml -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView" >
<constructor-arg>
<ref bean="xstreamMarshaller"/>
</constructor-arg>
</bean>
</list>
</property>
</bean>
<bean id="configFileView" class="com.martinwu.example.view.GenericFileView"
p:contentType="text/plain" p:url="" scope="prototype"/>
<bean id="swfFileView" class="com.martinwu.example.view.GenericFileView"
p:contentType="application/x-shockwave-flash" p:url="" scope="prototype"/>
<!-- FreeMarker , controller ftl freemarker , : multipleViewResolver controller .ftl freemaker -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver" p:order="3">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
<!-- bean name view resolver
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" p:order="4"/>
-->
<!-- InternalResourceViewResolver , , 。 , , -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:order="5">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="contentType" value="text/html"/>
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--one of the properties available;the maximum file size in bytes-->
<property name="maxUploadSize" value="100000"/>
</bean>
<!-- Controller path<->view -->
<mvc:view-controller path="/" view-name="redirect:/welcome"/>
</beans>
참고: http://www.ibm.com/developerworks/cn/java/j-lo-springview/