2010-12-08 78 views
1

我正在为我的应用程序开发RESTful API。所有getter(使用HTTP GET)都可以正常工作。我无法使保存方法(使用POST)工作。REST + Spring + POST与自定义编组器

我正在使用HTML表单和RESTClient进行测试。

这里是我的控制器

@Controller 
public class EntitiesController { 
@RequestMapping(value="/ci/save/", method = RequestMethod.POST) 
public ModelAndView saveConfigurationItem(@RequestBody ConfigurationItem body) { 
    System.out.println("saveConfigurationItem: body=" + body); 
    return createModelAndView("ci", Collections.emptyList()); 
} 
} 

这种方法有望被调用时,客户端职位形态项目。 我正在使用自定义序列化格式。它不是XML或JSON。它是VCard或VCalendar格式。对于我的第一次测试我用下面的电子名片:

BEGIN:VCARD 
N:Pooh;Winnie 
FN:Winnie the Pooh 
TEL:tel:+441234567 
END:VCARD 

我张贴到URL http://localhost:8080/core.solution-1.0/data/ci/save/。 这是我得到的回应:

415 
The server refused this request because the request entity is in a format not 
supported by the requested resource for the requested method() 

(*)形态项目是一个抽象类。 CardEntry扩展它。我尝试了两个。

我试图将方法参数更改为String。在这种情况下,该方法被调用,但字符串是空的。当遵循我在web中看到的推荐之一时,会发生同样的情况,我将参数类型更改为MultiValueMap并从简单的HTML表单发送请求。

我看到marshal()根本没有被调用。

怎么了?

这是我的。 (我只把这里的相关代码。)

Spring配置

<?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:p="http://www.springframework.org/schema/p" 
xmlns:context="http://www.springframework.org/schema/context" 
xmlns:oxm="http://www.springframework.org/schema/oxm" 
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
    http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd"> 

<import resource="classes/spring-config-prod.xml"/> 
<context:component-scan base-package="com.mycompany.solution.service" /> 


<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" /> 

<bean id="ciCardView" class="com.mycompany.solution.service.VFormatView"> 
    <constructor-arg> 
    <bean class="com.mycompany.solution.service.VFormatMarshaller"> 
    <property name="packagesToScan" value="com.mycompany.solution.entity"/> 
    </bean> 
    </constructor-arg> 
</bean> 
</beans> 

的Marshaller

public class VFormatMarshaller implements Marshaller, Unmarshaller { 
@Override 
public void marshal(Object obj, Result result) 
    throws IOException/*, XmlMappingException*/ { 
    System.out.println("VFormatMarshaller.marshal(" + obj + ")"); 
    marshalStreamResult(obj, (StreamResult)result); 
} 

@Override 
public boolean supports(Class<?> paramClass) { 
    System.out.println("VFormatMarshaller.supports(" + paramClass + ")"); 
    boolean supports = new HashSet<String>(Arrays.asList(packagesToScan)).contains(paramClass.getPackage().getName()); 
    if (supports) { 
    return supports; 
    } 

    return Collection.class.isAssignableFrom(paramClass); 
} 

@Override 
public Object unmarshal(Source source) throws IOException/*, XmlMappingException*/ { 
    System.out.println("VFormatMarshaller.unmarshal(" + source + ")"); 
    return unmarshalStreamSource((StreamSource)source); 
} 
//// ............................. 
} 

查看(这仅写入覆盖内容类型)

public class VFormatView extends MarshallingView { 

public VFormatView() { 
    super(); 
    setContentType("application/vcard"); 
    System.out.println("VFormatView()"); 
} 

public VFormatView(Marshaller marshaller) { 
    super(marshaller); 
    setContentType("application/vcard"); 
    System.out.println("VFormatView(" + marshaller + ")"); 
} 
} 
+0

当你在控制器中使用类型的参数,你得到的日志中的任何异常? – codelark 2010-12-08 15:55:36

回答

2

@RequestBody/@ResponseBody由层次结构HttpMessageConverter s支持,这与ViewResolver完全不同。

在你情况下,你需要配置适当的编组/解组和内容类型MarshallingHttpMessageConverter(或创建自己的HttpMessageConverter如果你不需要依赖于编组/解组的现有的实现),并提供一个配置实例到AnnotationMethodHandlerAdapter

配置自定义HttpMessageConveter侵入性最小的方法是创建一个BeanPostProcessor如下:

public class Configurer implements BeanPostProcessor { 
    public void postProcessAfterInitialization(String name, Object bean) { 
     if (bean instanceof AnnotationMethodHandlerAdapter) { 
      AnnotationMethodHandlerAdapter a = (AnnotationMethodHandlerAdapter) bean; 
      HttpMessageConverter[] convs = a.getMessageConverters(); 
      ... add new converter ... 
      a.setMessageConverters(convs); 
     } 
    } 
    ... 
} 
+0

谢谢!你有一个很好的参考配置示例吗? – AlexR 2010-12-08 16:19:22