【问题标题】:Spring MVC @RequestBody for JAXB Domain object AFTER XSLT transform of received XML在接收到的 XML 的 XSLT 转换之后,用于 JAXB 域对象的 Spring MVC @RequestBody
【发布时间】:2012-09-16 10:53:48
【问题描述】:

情况是供应商为他们的 XML 文档提供了一个 XML 模式,他们可以提交给我的服务。我不喜欢他们的架构,因此我编写了自己的架构以及 XSLT 来转换接收到的 XML。我的模式与 JAXB 的 xjc 工具一起使用来生成 .java 文件,这些文件将一些 pojo 绑定到合适的对象模型中。如果不是因为需要转换步骤,那么在 Spring MVC 中实现这将是微不足道的。

接收到的 XML 在映射到 JAXB 类之前必须先进行转换。大致类似于下面的sn-p:

@RequestMapping(value="/receiveXml", method=RequestMethod.POST )
public ResponseEntity<String> receiveXml( @RequestBody String vendorXmlPayload )         {      
  // 1.  Make sure vendorXmlPayload adheres to vendor's schema
  vendorSchema.newValidator().validate(new StreamSource(new StringReader(vendorXmlPayload)));

  // 2.  Transform xml payload to my schema
  StringWriter sw = new StringWriter();
  transformer.transform(new StreamSource(new StringReader(vendorXmlPayload)), new StreamResult(sw))

  // 3.  Validate transformed XML against my schema
  mySchema.newValidator().validate(new StreamSource(new StringReader(sw.toString())));

  // 4.  Unmarshall to JAXB-annotated classes
  DomainObject obj = (DomainObject) unmarshaller.unmarshal(new StreamSource(new StringReader(sw.toString())));


  (errors != null) ? return ... HttpStatus.BAD_REQUEST : return ..... HttpStatus.OK
}    

是否有一些优雅的 Spring 注释可以将所有这些都浓缩在 MVC 控制器上?即有没有办法使用 @RequestBody 注释或其他东西来执行转换和解组?也许就像这个虚构的sn-p:

@RequestMapping(value="/receiveXml", method=RequestMethod.POST )
@Transform(transformer="myTransform.xslt")
public ResponseEntity<String> receiveXml( @RequestBody DomainObj domainObj)         
{
  // Process my DomainObj as I normally would
  (errors != null) ? return ... HttpStatus.BAD_REQUEST : return ..... HttpStatus.OK
}

@InitBinder 看起来不太适合这种情况。大多数“Spring MVC XSLT”搜索处理的是转换输出而不是输入。

【问题讨论】:

    标签: java xml xslt spring-mvc jaxb


    【解决方案1】:

    我怀疑是否有这样的开箱即用的东西,但你应该能够按照这些思路构建可重用的东西:

    为自己定义一个新的注解,比如@XmlWithTransform,它接受一个参数,比如 xslt 位置,你可以通过这种方式在控制器上指定它:

    @RequestMapping(value="/receiveXml", method=RequestMethod.POST )
        public ResponseEntity<String> receiveXml( @XmlWithTransform(usingxslt="anxsl.xsl")     CustomType customType )
    

    现在编写一个自定义的HandlerMethodArgumentResolver,它可以接收请求正文 xml,使用注释的 xslt 参数对其进行转换,并将其绑定到指定为参数的类型,如下所示:

    import java.io.StringReader;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.transform.stream.StreamSource;
    
    import org.springframework.core.MethodParameter;
    import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
    import org.springframework.http.server.ServletServerHttpRequest;
    import org.springframework.web.bind.support.WebDataBinderFactory;
    import org.springframework.web.context.request.NativeWebRequest;
    import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    import org.springframework.web.method.support.ModelAndViewContainer;
    
    public class XsltTransformingHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver{
    
        Unmarshaller unmarshaller;
        @Override
        public boolean supportsParameter(MethodParameter parameter){
            return (parameter.getMethodAnnotation(XmlWithTransform.class)!=null);
        }
    
        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            XmlWithTransform xmlWithTransform = parameter.getMethodAnnotation(XmlWithTransform.class);
            Class<?> parameterType = parameter.getParameterType();
            String xsltLocation = xmlWithTransform.usingxstl();
            ServletServerHttpRequest servletRequest = new ServletServerHttpRequest(webRequest.getNativeRequest(HttpServletRequest.class));
            String xmlFromVendor = IOUtils.toString(servletRequest.getBody(), "UTF-8");
    
            String xmlInternal = transform(xmlFromVendor, xsltLocation);
            return unmarshaller.unmarshal(new StreamSource(new StringReader(xmlInternal)));
        }
    }
    

    并使用 Spring MVC 注册此参数解析器:

    <mvc:annotation-driven> 
       <mvc:argument-resolvers>
            <bean class="XsltTransformingHandlerMethodArgumentResolver"></bean>
       </mvc:argument-resolvers>
    </mvc:annotation-driven>
    

    【讨论】:

      猜你喜欢
      • 2015-03-08
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-23
      • 1970-01-01
      • 2013-05-08
      相关资源
      最近更新 更多