我正在尝试使用Java创建一个RESTful服务,使用多个教程和许多很多StackOverflow条目。不幸的是我似乎无法让我的代码工作,当我尝试命中端点时,我坚持不懈地获得Http 406。任何帮助表示赞赏。
GreetingController.java:
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/greeting")
public class GreetingController {
protected final Logger log = LoggerFactory.getLogger(GreetingController.class);
private static final String template = "Hello, %s!";
private static Random rand = new Random();
@RequestMapping(method = RequestMethod.GET, headers="Accept=*/*")//, value="/{name}")
@ResponseBody
public Greeting greeting() {
log.debug("Entered greeting()");
return new Greeting(rand.nextInt(99999999),
String.format(template, "Stephen"));
}
@RequestMapping(method = RequestMethod.GET, value="/{name}")
@ResponseBody
public Greeting greetingName(@PathVariable String name) {
log.debug("Entered greetingName()");
return new Greeting(rand.nextInt(99999999),
String.format(template, name));
}
}
Greeting.java:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="greeting")
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class Greeting {
private Integer id;
private String content;
public Greeting() {
}
public Greeting(Integer id, String content) {
this.id = id;
this.content = content;
}
@XmlElement
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
@XmlElement
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
的x servlet.xml中:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:mvc="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.package.name" />
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Http标题(通过firebug):
Response Headers
Content-Language en
Content-Length 1067
Content-Type text/html;charset=utf-8
Date Tue, 18 Feb 2014 20:24:13 GMT
Server Apache-Coyote/1.1
Request Headers
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Cookie JSESSIONID=9064B3E9F1C3259B73C65B022C8BDC75
Host localhost:8080
User-Agent Mozilla/5.0 (Windows NT 6.0; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0
启动tomcat并登录所述服务器上的不同页面时记录:
DEBUG o.s.security.web.FilterChainProxy - Converted URL to lowercase, from: '/greeting'; to: '/greeting'
DEBUG o.s.security.web.FilterChainProxy - Candidate is: '/greeting'; pattern is /**; matched=true
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 1 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.access.channel.ChannelProcessingFilter@9a6bbb'
DEBUG o.s.s.w.a.i.DefaultFilterInvocationSecurityMetadataSource - Converted URL to lowercase, from: '/greeting'; to: '/greeting'
DEBUG o.s.s.w.a.i.DefaultFilterInvocationSecurityMetadataSource - Candidate is: '/greeting'; pattern is /**; matched=true
DEBUG o.s.s.w.a.c.ChannelProcessingFilter - Request: FilterInvocation: URL: /greeting; ConfigAttributes: [ANY_CHANNEL]
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 2 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.context.SecurityContextPersistenceFilter@16fcc4'
DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 3 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.logout.LogoutFilter@1db52c8'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 4 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@17d6c1'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 5 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@1144823'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 6 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.www.BasicAuthenticationFilter@8c02cc'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 7 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.savedrequest.RequestCacheAwareFilter@bbd1b'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 8 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@ac576f'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 9 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.AnonymousAuthenticationFilter@15daa9e'
DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 10 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.session.SessionManagementFilter@6c9f0f'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 11 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.access.ExceptionTranslationFilter@13ec758'
DEBUG o.s.security.web.FilterChainProxy - /greeting at position 12 of 12 in additional filter chain; firing Filter: 'org.springframework.security.web.access.intercept.FilterSecurityInterceptor@917cb0'
DEBUG o.s.s.w.a.i.DefaultFilterInvocationSecurityMetadataSource - Converted URL to lowercase, from: '/greeting'; to: '/greeting'
DEBUG o.s.s.w.a.i.DefaultFilterInvocationSecurityMetadataSource - Candidate is: '/greeting'; pattern is /welcome*; matched=false
DEBUG o.s.s.w.a.i.DefaultFilterInvocationSecurityMetadataSource - Candidate is: '/greeting'; pattern is /**; matched=true
DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /greeting; Attributes: [IS_AUTHENTICATED_ANONYMOUSLY]
DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.RoleVoter@1913751, returned: 0
DEBUG o.s.s.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.AuthenticatedVoter@c6b80e, returned: 1
DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - Authorization successful
DEBUG o.s.s.w.a.i.FilterSecurityInterceptor - RunAsManager did not change Authentication object
DEBUG o.s.security.web.FilterChainProxy - /greeting reached end of additional filter chain; proceeding with original chain
DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'spring-tutorial' determining Last-Modified value for [/SpringMVC/greeting]
DEBUG o.s.w.s.m.a.DefaultAnnotationHandlerMapping - Mapping [/greeting] to handler 'com.example.controller.GreetingController@1eb1db2'
DEBUG o.s.web.servlet.DispatcherServlet - Last-Modified value for [/SpringMVC/greeting] is: -1
DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'spring-tutorial' processing GET request for [/SpringMVC/greeting]
DEBUG o.s.w.b.a.s.HandlerMethodInvoker - Invoking request handler method: public com.example.form.Greeting com.example.controller.GreetingController.greeting()
INFO c.s.controller.GreetingController - Entered greeting()
DEBUG o.s.w.s.m.a.AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [com.example.controller.GreetingController@1eb1db2]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [com.example.controller.GreetingController@1eb1db2]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [com.example.controller.GreetingController@1eb1db2]: org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - SecurityContext contents are anonymous - context will not be stored in HttpSession.
DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'spring-tutorial': assuming HandlerAdapter completed request handling
DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chain processed normally
DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
答案 0 :(得分:9)
我在尝试解决同一问题时遇到过这种情况。在查看了pfac的答案之后,我发现只需将jackson-dataformat-xml库添加到我的项目中就可以解决我的问题。
如果使用maven:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.3.2</version>
</dependency>
答案 1 :(得分:3)
花了几个小时追逐这个,所以我离开这里对我有用(我正在使用 Spring 4.0.6 )以及我认为对你有用的东西(Spring 3.0.x) )。
由于MappingJackson2HttpMessageConverter
自动获取Jackson数据绑定库并启用带有@ResponseBody
注释的控制器方法来自动返回JSON,因此通常假设这样的工具也存在于XML中,但这不是情况下。
为了启用XML,我必须手动创建一个包含两个邮件转换器的RequestMappingHandlerAdapter
,MarshallingHttpMessageConverter
后跟MappingJackson2HttpMessageConverter
。
这也允许使用Spring提供的任何marshallers,只需将其设置为MarshallingHttpMessageConverter
的属性。
结果spring-servlet.xml
:
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- ... -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"></bean>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</list>
</property>
</bean>
<!-- ... -->
</beans>
注意:我假设您x-servlet.xml
中的架构位置使用此版本。
根据http://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc和http://spring.io/blog/2013/06/03/content-negotiation-using-views/,有两种方法可以在Spring 3中实现您想要的功能。第一种方法是使用ContentNegotiationManager
,它仅在3.2版本之后可用。 x因此无法用于您的版本。第二个是使用ContentNegotiatingViewResolver
,它根据请求的内容类型将视图的解析权委托给其他解析器(这是由Accept
标头定义,扩展还是默认是可配置的)。
基本上你需要配置一个带有两个解析器的ContentNegotiatingViewResolver
,一个用于XML,另一个用于JSP视图。
spring-servlet.xml
:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location" value="spreadsheet-views.xml"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/views"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
</bean>
例如,您可以为JSON添加视图解析器,但由于Spring不提供,因此您必须实现它。第二篇博客文章展示了如何实现一个简单的。
答案 2 :(得分:1)
406表示服务器认为请求内容不可接受。尝试删除Accept
标题或将headers="Accept=*/*"
添加到@RequestMapping
注释。
答案 3 :(得分:0)
我正在努力解决类似的问题。由于某些原因,我的网络应用程序默认情况下不提供xml数据类型,即使我正在设置&#34; produce = application / xml &#34;注释中的参数。
我只是通过为applicationContext.xml添加额外的bean配置来解决它:
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/xml" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
或通过Java Config类:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_XML);
}
}