0

I am trying to send send list of objects which I get from database to my JSP. I managed to successfully send data from JSP to my controller. Method inside my controller takes that parameter, fills List (I checked it in debug mode) and controller returns that list.

@RequestMapping(value="/test.html", method=RequestMethod.GET, produces="application/json")
public @ResponseBody List<ModelVechicle> fetchListModelById(@RequestParam Integer number) {

    System.out.println(number);

    List<ModelVechicle> modelList = vechicleService.fetchModelById(number);

    return  modelList; 
}

When I try to get that List on my JSP, I get

HTTP Status 406 -

type Status report

message

description The resource identified by this request is only capable of generating 
responses with characteristics not acceptable according to the request "accept" headers.

Apache Tomcat/8.0.32

Here is my JSP with AJAX code

<script type="text/javascript">
$(document).ready(function(){
    $("#brand").change(onSelectChange);
});

function onSelectChange() {
    var selected = $("#brand option:selected");     
    var output = "";
    var number = parseInt(selected.val());


      $.ajax({
            type: "GET",
            url: "test.html",
            dataType : 'json',
            data: ({number: number}),
             success: function(response){
                 $('#result').html("");
                    var obj = JSON.parse(response);
                    $('#result').html(obj.modelName);
                },
                error: function(xhr,e){                     
                    alert('Error while request..'+xhr.responseText);
                }
            });

    if(selected.val() != 0){
        output = "You selected brand " + selected.text();

    }
    $("#output").html(number);


}

Also here is my ModelVechicle class, that is the class which objects I am adding into List:

@Entity
@Table(name = "CARDEALERSHIP.MODEL")
public class ModelVechicle implements Serializable {

private static final long serialVersionUID = 7420515051961158192L;

@Id
@Column(name = "ID")
private Integer modelId;

@Column(name = "MODELNAME")
private String modelName;

@ManyToOne
@JoinColumn(name = "BRANDID")
private Brand brand;

public ModelVechicle(Integer modelId, String modelName, Brand brand) {
    super();
    this.modelId = modelId;
    this.modelName = modelName;
    this.brand = brand;
}

public ModelVechicle() {}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((brand == null) ? 0 : brand.hashCode());
    result = prime * result + ((modelId == null) ? 0 : modelId.hashCode());
    result = prime * result + ((modelName == null) ? 0 : modelName.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    ModelVechicle other = (ModelVechicle) obj;
    if (brand == null) {
        if (other.brand != null)
            return false;
    } else if (!brand.equals(other.brand))
        return false;
    if (modelId == null) {
        if (other.modelId != null)
            return false;
    } else if (!modelId.equals(other.modelId))
        return false;
    if (modelName == null) {
        if (other.modelName != null)
            return false;
    } else if (!modelName.equals(other.modelName))
        return false;
    return true;
}

public Integer getModelId() {
    return modelId;
}

public void setModelId(Integer modelId) {
    this.modelId = modelId;
}

public String getModelName() {
    return modelName;
}

public void setModelName(String modelName) {
    this.modelName = modelName;
}

public Brand getBrand() {
    return brand;
}

public void setBrand(Brand brand) {
    this.brand = brand;
}

Can somebody please explain me what to do in order to get the List dynamically to JSP page, and display List members properly?

EDIT: Here is my web.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>CarDealership</display-name>
  <welcome-file-list>
    <welcome-file>addVechicle.html</welcome-file>
  </welcome-file-list>

  <servlet>
    <servlet-name>springDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatchers.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/app-config.xml
    </param-value>
  </context-param>

</web-app>
2
  • Which version of Spring framework are you using? Commented Sep 13, 2016 at 21:17
  • @jlumietu 4.2.6.RELEASE Commented Sep 13, 2016 at 21:23

1 Answer 1

1

As of Spring 3.2+, the content negotiation has other facts in account prior to eval Accept header:

From https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc:

Enabling Content Negotiation in Spring MVC

Spring supports a couple of conventions for selecting the format required: URL suffixes and/or a URL parameter. These work alongside the use of Accept headers. As a result, the content-type can be requested in any of three ways. By default they are checked in this order:

  • Add a path extension (suffix) in the URL. So, if the incoming URL is something like http://myserver/myapp/accounts/list.html then HTML is required. For a spreadsheet the URL should be http://myserver/myapp/accounts/list.xls. The suffix to media-type mapping is automatically defined via the JavaBeans Activation Framework or JAF (so activation.jar must be on the class path).
  • A URL parameter like this: http://myserver/myapp/accounts/list?format=xls. The name of the parameter is format by default, but this may be changed. Using a parameter is disabled by default, but when enabled, it is checked second.

  • Finally the Accept HTTP header property is checked. This is how HTTP is > actually defined to work, but, as previously mentioned, it can be problematic to use.

That actually means that if you map a @Controller method with a .htm(l) suffix, it is intended to return html and won't return json nor any other format even if you sent other format as Accept header.

I allways map my controllers as .htm and had to change the way I used to map @ResponseBody annotated methods when I upgraded to Spring 3.2 and newer.

EDIT: After seeing your web.xml, as I supposed, you are mapping every .html suffix request to the dispatcher servlet:

  `<servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>`

I figure that now the @RequestMapping in your controller is like this:

@RequestMapping(value="/test", method=RequestMethod.GET, produces="application/json")
public @ResponseBody List<ModelVechicle> fetchListModelById(@RequestParam Integer number) {

As /test does not match .html suffix, request is not arriving to springDispatcher, and that's exactly why you are getting a 404.

Now, options to fix this:

1) Add a new mapping in the web.xml which matches this controller:

<servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*/test</url-pattern>
</servlet-mapping>

This way you would be forced to include any new non html returning method. Not seems usable for me.

2) Map all incoming requests to dispatcherServlet

  <servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

I don't really like this option, I prefer to filter what I really want to reach the dispatcher servlet.

3) Find a new matching pattern for this kind of requests. I allways publish some kind of generic suffix, which will not be catched by JAF, such as *.service:

  <servlet-mapping>
    <servlet-name>springDispatcher</servlet-name>
    <url-pattern>*.html</url-pattern>
    <url-pattern>*.service</url-pattern>
  </servlet-mapping>

So in Controller methods which return XML or JSON (or any other format, depending only of the Accept header), I map like this:

@RequestMapping(value="/test.service", method=RequestMethod.GET, produces="application/json")
public @ResponseBody List<ModelVechicle> fetchListModelById(@RequestParam Integer number) {

4) You could as well publish all this kind of @ResponseBody controller method using a 'http://com.xxx.yyy/myApp/service/resource' pattern and use /service/ as servlet mapping in web.xml

      <servlet-mapping>
        <servlet-name>springDispatcher</servlet-name>
        <url-pattern>*.html</url-pattern>
        <url-pattern>/service/</url-pattern>
      </servlet-mapping>
Sign up to request clarification or add additional context in comments.

4 Comments

now I have new one: HTTP Status 404 - /CarDealership/test type Status report message /CarDealership/test description The requested resource is not available. I guess View resorlver is trying to resolve the "/test" into jsp, but I want to stay on the same page, and dynamically send the List to current JSP page.
Show your web.xml please
works like a charm now. Thank you very much for detailed explanation. We used to work with these .html extensions and didn't have the need to do it otherwise. But since I grabbed the hold on AJAX it is now a life saviour. You regained my confidence and faith in humanity :)
First time I made an upgrade to spring 3.2 I nearly became mad when all the working ajax actions suddenly started returning Http 400... glad it worked!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.