406 Error when consuming restFul webService in Spr

2019-09-01 11:11发布

问题:

This is a snippet my spring servlet. My pom file has the jackson dependencies added as well but I just can't figure out why I'm getting this 406.

...
    <mvc:annotation-driven/>                
    <context:component-scan base-package="com.ourcalendar.*"/>      
    <!-- Add JPA support -->
    <bean id="emf" class=
    "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="loadTimeWeaver">
    <bean class=
    "org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
    </property>
    </bean> 
    <!-- Add Transaction support -->
    <bean id="myTxManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf"/>
    </bean> 
    <!-- Use @Transaction annotations for managing transactions -->   
    <tx:annotation-driven transaction-manager="myTxManager" />    
    <!-- adding view resolver to show jsp's on browser -->
    <bean id="smViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>     
   </beans>

My Pom file has jackson dependencies

....
    <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.4.0-rc3</version>
    </dependency>
    <dependency>
       <groupId>org.codehaus.jackson</groupId>
       <artifactId>jackson-mapper-asl</artifactId>
       <version>1.9.12</version>
   </dependency>
   <dependency>
       <groupId>org.codehaus.jackson</groupId>
       <artifactId>jackson-core-asl</artifactId>
       <version>1.9.12</version>
    </dependency>
......

Here is my webService

    @Controller
    public class GetEvents {
    @Autowired
    private EventDao eventDao;
    @RequestMapping(value = "/getEvents", method = RequestMethod.GET)
    @ResponseBody
    public /*List<event>*/ JSONArray getAllEvents()
    {

    JSONObject event =new JSONObject();
    JSONArray theArray = new JSONArray();       
    for (Event e : eventDao.getAllEvents()) {           
        event.put("id", e.getEventsID());
        event.put("title", e.getTitle());
        event.put("description", e.getDescription());
        event.put("start", e.getStart());
        event.put("end", e.getEnd());
        event.put("user", e.getUser());
        theArray.put(event);
    }

    System.out.println("call");
    return theArray;        
    //return eventDao.getAllEvents();


}

}

My events class looks like this

    package com.ourcalendar.model;        
    import java.io.Serializable;
    import java.util.Date;        
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;        
    import org.codehaus.jackson.map.annotate.JsonSerialize;
    import org.codehaus.jackson.map.ser.std.DateSerializer;


    @Entity
    @NamedQuery(name="Events.GetAll", query="SELECT e FROM Event e ORDER BY e.id") 
    @Table(name="events_tbl")
    public class Event implements Serializable  {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Id 
    @Column(name="eventsId")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer eventsID;

    @Column(name="title")
    private String title;

    @Column(name="description")
    private String description;


    @Column(name="start")
    private Date start;


    @Column(name="end")
    private Date end;

    @Column(name="user")
    private String user;


    public Event()
    {

    }


    public Event(Integer eventsID, String title, String description,
            Date start, Date end, String user) {
        super();
        this.eventsID = eventsID;
        this.title = title;
        this.description = description;
        this.start = start;
        this.end = end;
        this.user = user;
    }


    public Integer getEventsID() {
        return eventsID;
    }
    public void setEventsID(Integer eventsID) {
        this.eventsID = eventsID;
    }


    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    @JsonSerialize(using=DateSerializer.class)
    public Date getStart() {
        return start;
    }
    public void setStart(Date start) {
        this.start = start;
    }

    @JsonSerialize(using=DateSerializer.class)
    public Date getEnd() {
        return end;
    }
    public void setEnd(Date end) {
        this.end = end;
    }
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
}

And last but not least here's my EventsDao

  @Component
  public class EventDao {

    // Injected database connection:
    @PersistenceContext private EntityManager em;

    // Stores a new Event:
    @Transactional
    public void persist(Event event) {
        em.persist(event);
    }

 // Retrieves all the Events:
    public List<Event> getAllEvents() {
        TypedQuery<Event> query = em.createNamedQuery("Events.GetAll", Event.class);        
        List<Event> results = query.getResultList();
        return results;

    }
}

回答1:

Firstly i'd like to review this stackoverflow question and answer:

What is "406-Not Acceptable Response" in HTTP?1

After that change your function response to a non JSON response. e.g. based on on your code i would try this format:

@RequestMapping(value = "/getEvents", method = RequestMethod.GET)
@ResponseBody
public List<Event> getAllEvents() { 
  return eventDao.getAllEvents(); 
}

After all ResponseBody job is to convert into relevant JSON response so let it do the heavy lifting for you.

If that doesn't work i'll review your code further.



回答2:

So after much back and forth I finally got this to work. There seems to be an issue with spring 3.1 xsd location. After changing it to 3.2 and disabling the getting of media type based on the extension of the requested path (see below) it worked.

<?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:mvc="http://www.springframework.org/schema/mvc"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/mvc  
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

  <context:component-scan base-package="com.ourcalendar.*"/>     
  <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
  <bean id="contentNegotiationManager"  
     class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
     <!-- Turn off working out content type based on URL file extension, should fall back to looking at the Accept headers -->
  <property name="favorPathExtension" value="false" />
  </bean>
 .........................................

for further explanation refer to the below link. http://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-content-negotiation