SpringMVC 사용자 정의 보기 + 콘 텐 츠 협상 (RESTful MVC)

이 블 로 그 는 매우 유연 한 SpringMVC 다 중 보기 협상 설정 을 어떻게 실현 하 는 지 소개 합 니 다. 한 프로젝트 가 jsp, freemaker, jasper, velosity 등 을 사용 해 야 한다 면 고객 센터 로 돌아 가 는 데 이 터 는 json, xml 를 사용 해 야 합 니 다.그럼 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/
 
 
 
 

좋은 웹페이지 즐겨찾기