-1

I have gone through so many examples of this nature and proposed solutions from this site, but none of the solutions provided thereon apply to my problem. I believe that this error message, 400, shows up when the information sent to the controller is mulformed. I spent the last two days cross referrencing to another project I worked on in the past, which works, but I cannot pick up the problem.

@RequestMapping(value = {"/", "/home"}, method = RequestMethod.GET)
    public String homePage(ModelMap model) {
       model.addAttribute("user", getPrincipal());
    Catalog catalog = catalogService.getCatalogByCategory(Catalog.CatalogCategory.ALL);

    model.addAttribute("catalog", catalog);
    return "welcome";
}

This sends the data to a JSTL Spring form on my JSP as follows:

<form:form method="POST" modelAttribute="catalog">
        <form:hidden path="id"/>
        <form:hidden path="name"/>
        <form:hidden path="category"/>
        <form:hidden path="orderItems"/>


        <div id="products" class="row list-group">
            <c:forEach var="orderItem" items="${catalog.orderItems}">

                <div class="item  col-xs-4 col-lg-4">
                    <div class="thumbnail">
                        <img class="group list-group-image" src="http://placehold.it/400x250/000/fff" alt=""/>

                        <div class="caption">
                            <h4 class="group inner list-group-item-heading">
                                    ${orderItem.name}</h4>

                            <p class="group inner list-group-item-text">
                                    ${orderItem.description}
                            </p>

                            <div class="row">
                                <div class="col-xs-12 col-md-6">
                                    <p class="lead">
                                        R ${orderItem.price}</p>
                                </div>
                                <div class="col-xs-12 col-md-6">
                                    <label for="${orderItem.id}" class="btn btn-primary">Add to Cart <input
                                            type="checkbox" id="${orderItem.id}" name="orderItem.addedToCart"
                                            class="badgebox"><span class="badge">&check;</span></label>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </c:forEach>
        </div>

        <div class="row">
            <div class="form-group">
                <div class="col-sm-12 pull-right">
                </div>
                <div class="col-sm-2 pull-right">

                    <input type="submit"
                           class="btn btn-default btn-block btn-primary"
                           value="Next" name="action" formmethod="POST"
                           formaction="confirmList"/>

                </div>
            </div>
        </div>
    </form:form>`

At this point I submit the form to the following listener in my controller:

@RequestMapping(value = "/confirmList", method = RequestMethod.POST)
public String confirmList(@ModelAttribute Catalog catalog, @ModelAttribute     String numberOfItemsAdded) {

     List<OrderItem> selectedItems = new ArrayList<OrderItem>();
    for (OrderItem orderItem : catalog.getOrderItems()) {
        if (orderItem.isAddedToCart()) {
            selectedItems.add(orderItem);
        }
    }
    //model.addAttribute("numberOfItemsAdded", selectedItems.size());
    return "welcome";
}

That's it, execution flow does NOT even reach back my controller. Exhausting bug because I really do not understand what I am doing wrong here. Thank you in advance

EDIT:

Catalog.java

 @Entity
 @Table(name="Catalogs")
 public class Catalog{

 private long id; //generated value using hibernate ...
 private String name; //column annotated by @Column
 private String category;// column also annotated by @Column
 private List<OrderItem> orderItems;// one to many mapping

  //getters and setters here
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
kholofelo Maloma
  • 973
  • 3
  • 15
  • 26

2 Answers2

1

I tested your code and I got HTTP 400 too. The thing is that what browser sends does not match whith what the controller method confirmList expects:

This is the form data I saw in Chrome's network tab:

id:1
name:the catalog
category:category
orderItems:[com.eej.ssba2.model.test.catalog.OrderItem@82ea8a, com.eej.ssba2.model.test.catalog.OrderItem@f441ae, com.eej.ssba2.model.test.catalog.OrderItem@40a13, com.eej.ssba2.model.test.catalog.OrderItem@1316c95, com.eej.ssba2.model.test.catalog.OrderItem@1cfc05a, com.eej.ssba2.model.test.catalog.OrderItem@5d725c, com.eej.ssba2.model.test.catalog.OrderItem@ff32b9, com.eej.ssba2.model.test.catalog.OrderItem@5b49a4, com.eej.ssba2.model.test.catalog.OrderItem@13faf31, com.eej.ssba2.model.test.catalog.OrderItem@6d64d]
orderItem.addedToCart:on
orderItem.addedToCart:on
orderItem.addedToCart:on
orderItem.addedToCart:on
action:Next

But controller cannot understand this, as OrderItems shows a toString() of each OrderItem instance and the addedToCart is not binded to any orderItem of the orderItems list.

You must modify your jsp this way:

<form:form method="POST" modelAttribute="catalog">
        <form:hidden path="id"/>
        <form:hidden path="name"/>
        <form:hidden path="category"/>
        <!-- form:hidden path="orderItems"/-->


        <div id="products" class="row list-group">
            <c:forEach var="orderItem" items="${catalog.orderItems}" varStatus="status">

                <div class="item  col-xs-4 col-lg-4">
                    <div class="thumbnail">
                        <img class="group list-group-image" src="http://placehold.it/400x250/000/fff" alt=""/>

                        <div class="caption">
                            <h4 class="group inner list-group-item-heading">
                                    ${orderItem.name}</h4>
                                    <form:hidden path="orderItems[${status.index}].name" />
                            <p class="group inner list-group-item-text">
                                    ${orderItem.description}
                                    <form:hidden path="orderItems[${status.index}].description" />
                            </p>

                            <div class="row">
                                <div class="col-xs-12 col-md-6">
                                    <p class="lead">
                                        R ${orderItem.price}</p>
                                        <form:hidden path="orderItems[${status.index}].price" />
                                </div>
                                <div class="col-xs-12 col-md-6">
                                    <label for="${orderItem.id}" class="btn btn-primary">Add to Cart <input
                                            type="checkbox" id="${orderItem.id}" name="catalog.orderItems[${status.index}].addedToCart"
                                            class="badgebox"><span class="badge">&check;</span></label>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </c:forEach>
        </div>

        <div class="row">
            <div class="form-group">
                <div class="col-sm-12 pull-right">
                </div>
                <div class="col-sm-2 pull-right">

                    <input type="submit"
                           class="btn btn-default btn-block btn-primary"
                           value="Next" name="action" formmethod="POST"
                           formaction="confirmList"/>

                </div>
            </div>
        </div>
    </form:form>

If you do so, you could see the message changes in Chrome's network tab (or the browser you are using). This is the form data right now:

id:1
name:the catalog
category:category
orderItems[0].name:OrderItemName#0
orderItems[0].description:OrderItemDesc#0
orderItems[0].price:0.0
orderItems[1].name:OrderItemName#1
orderItems[1].description:OrderItemDesc#1
orderItems[1].price:0.43645913001303904
orderItems[2].name:OrderItemName#2
orderItems[2].description:OrderItemDesc#2
orderItems[2].price:1.7151992716801088
orderItems[3].name:OrderItemName#3
orderItems[3].description:OrderItemDesc#3
orderItems[3].price:1.303683806806788
orderItems[4].name:OrderItemName#4
orderItems[4].description:OrderItemDesc#4
orderItems[4].price:2.507039003743686
orderItems[5].name:OrderItemName#5
orderItems[5].description:OrderItemDesc#5
orderItems[5].price:3.173744751378154
orderItems[6].name:OrderItemName#6
orderItems[6].description:OrderItemDesc#6
orderItems[6].price:3.183771167856446
catalog.orderItems[6].addedToCart:on
orderItems[7].name:OrderItemName#7
orderItems[7].description:OrderItemDesc#7
orderItems[7].price:6.73370053587355
catalog.orderItems[7].addedToCart:on
orderItems[8].name:OrderItemName#8
orderItems[8].description:OrderItemDesc#8
orderItems[8].price:2.0266022634803216
orderItems[9].name:OrderItemName#9
orderItems[9].description:OrderItemDesc#9
orderItems[9].price:5.251986962977732
catalog.orderItems[9].addedToCart:on
action:Next

And you would see now it returns a HTTP 200 as the request in fact reaches your controller. Delete the @ModelAttribute in your controller method too, as you have been suggested to:

    @RequestMapping(value = "/confirmList", method = RequestMethod.POST)
    public String confirmList(Catalog catalog, String numberOfItemsAdded) {

        List<OrderItem> selectedItems = new ArrayList<OrderItem>();
        for (OrderItem orderItem : catalog.getOrderItems()) {
            if (orderItem.isAddedToCart()) {
                selectedItems.add(orderItem);
            }
        }
        //model.addAttribute("numberOfItemsAdded", selectedItems.size());
        return "catalog";
    }
jlumietu
  • 6,234
  • 3
  • 22
  • 31
  • Thank you so much. I have made the adjustments that you;ve suggested and they helped me a lot. This solution is far from what I could have thought of myself. It's a clear solution and makes sense. Dankie! – kholofelo Maloma Sep 13 '16 at 11:07
-1

try this extra handle in your Controller and Check your Console,

@ExceptionHandler(MissingServletRequestParameterException.class)
public void handleMissingRequestParams(MissingServletRequestParameterException ex) {
    System.out.println();
    System.out.println("------------------------MissingServletRequestParameterException------------------------");
    System.out.println("  Parameter name:-    "+ex.getParameterName());
    System.out.println("  Parameter Type:-    "+ex.getParameterType());
    System.out.println("  Cause:-             "+ex.getCause());
    System.out.println("  LocalizedMessage:-  "+ex.getLocalizedMessage());
    System.out.println("  Message:-           "+ex.getMessage());
    System.out.println("  RootCause:-         "+ex.getRootCause());
    System.out.println("-------------------------------********************-----------------------------");
}

Edit

@kholofelo Maloma I can't see the variable numberOfItemsAdded in your jsp

AND i never used @ModelAttribute String numberOfItemsAdded to String parameter plz check this in documentation, I think it is used along with Bean, plz confirm

rather use @RequestParam

Read Documentation Here

It clears me

Sorry for above handle,

Note however that reference data and all other model content is not available to web views when request processing results in an Exception since the exception could be raised at any time making the content of the model unreliable. For this reason @ExceptionHandler methods do not provide access to a Model argument.

Shantaram Tupe
  • 1,646
  • 3
  • 16
  • 42