Ошибка Spring XML 406

Я пытаюсь создать службу RESTful с использованием Java, используя несколько учебных пособий и множество записей StackOverflow. К сожалению, похоже, я не могу заставить свой код работать, я постоянно получаю Http 406, когда пытаюсь попасть в конечную точку. Любая помощь приветствуется.

ПриветствиеКонтроллер.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));
    }
}

Приветствие.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

log при запуске 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

person sparks    schedule 18.02.2014    source источник
comment
Переключите регистраторы в режим DEBUG и повторите попытку. Он должен сказать вам, где проблема.   -  person Sotirios Delimanolis    schedule 19.02.2014
comment
Да, у меня отлично работает на Spring 4.0.0. Нам нужно увидеть эти журналы.   -  person Sotirios Delimanolis    schedule 19.02.2014
comment
Добавлены журналы и операторы регистрации.   -  person sparks    schedule 19.02.2014
comment
Ваши журналы кажутся совершенно не связанными. Установите уровень журнала на DEBUG и отправьте запрос, который получит ответ 406.   -  person Sotirios Delimanolis    schedule 19.02.2014
comment
Мое ведение журнала было испорчено, правильное ведение журнала, связанное с обращением к странице, обновлено. Я думаю, что Java неправильно маршалируется в XML. Я искал mashaller для XML, такой как плагин JSON jackson, но пока не смог его найти.   -  person sparks    schedule 20.02.2014


Ответы (4)


Я только что наткнулся на это, пытаясь решить ту же проблему. Посмотрев на ответ pfac, я обнаружил, что могу решить свою проблему, просто добавив в свой проект библиотеку jackson-dataformat-xml.

Если вы используете мавен:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.3.2</version>
</dependency>
person Adam Erstelle    schedule 19.03.2015

Просто потратил несколько часов на поиски этого, поэтому я оставляю здесь то, что сработало для меня (я использую Spring 4.0.6) и то, что, как мне кажется, сработает для вас (Spring 3.0.x).

Весна 4.0.x

Поскольку MappingJackson2HttpMessageConverter автоматически получает библиотеку связывания данных Джексона и позволяет методам контроллера, аннотированным @ResponseBody, автоматически возвращать JSON, обычно предполагается, что такой инструмент существует и для XML, но это не так.

Чтобы включить XML, мне пришлось вручную создать RequestMappingHandlerAdapter с двумя преобразователями сообщений, MarshallingHttpMessageConverter, за которым следует MappingJackson2HttpMessageConverter.

Это также позволяет использовать любой маршаллер, предоставляемый Spring, просто установив его как свойство 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>

Весна 3.0.x

ПРИМЕЧАНИЕ. Я предполагаю, что эта версия находится в расположении схемы в вашем файле 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 его не предоставляет. Второй пост в блоге показывает, как реализовать простой.

person pfac    schedule 19.08.2014

406 означает, что содержимое запроса считается сервером неприемлемым. Попробуйте удалить заголовок Accept или добавить headers="Accept=*/*" к аннотациям @RequestMapping.

person Angular University    schedule 18.02.2014
comment
Я упал, как будто ты говоришь это неправильно. Это не имеет ничего общего с содержанием запроса. Запрос указывает тип контента, который он принимает, в заголовке Accept. Если сервер не может сгенерировать этот контент, он отвечает кодом 406. - person Sotirios Delimanolis; 19.02.2014
comment
Я попытался добавить заголовок [code]header=Accept=*/*[/code], но он все еще не работает. См. редактирование. Я понимаю, что проблема в ответе, проблема в том, что я не знаю, как исправить ответ. - person sparks; 19.02.2014

Я боролся с аналогичной проблемой. Оказалось, что по какой-то причине мое веб-приложение не предоставляло тип данных xml по умолчанию, даже несмотря на то, что я устанавливал параметр «produces=application/xml» в аннотациях.

Я решил это, только добавив дополнительную конфигурацию bean-компонента для моего applicationContext.xml:

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
   <property name="defaultContentType" value="application/xml" />
</bean>
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

или через класс конфигурации Java:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_XML);
    }
}
person sashk0    schedule 29.05.2018