Spring, IllegalStateException when opening page with form - java

I am new to Spring and I get this exception, when entering campaigns.jsp with browser.
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'campaign' available as request attribute
I have this controller :
#Controller
#RequestMapping(value = "/admin")
public class AdminIndexController {
#RequestMapping(value = "/secure/campaigns.jsp", method = RequestMethod.GET)
public String campaigns() {
return "campaigns";
}
#RequestMapping(value = "/secure/create", method = RequestMethod.POST)
public String addContact(#ModelAttribute("campaign")
Campaign campaign) {
return "campaigns";
}
}
Campaings.jsp (if I remove this part, it shows the page correctly) :
<form:form method="post" action="create" commandName="campaign">
<table>
<tr>
<td><form:label path="question">Question</form:label></td>
<td><form:input path="question" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Add Campaign"/>
</td>
</tr>
</table>
</form:form>
I suppose there is a problem with mapping action="create", I am not sure where it is pointing to. I thought it is pointing to the same place as the .jsp is. This is address I use http://localhost:8080/server/rest/admin/secure/campaigns.jsp

This
<form:form method="post" action="create" commandName="campaign">
expects a model attribute (or command object), an HttpServletRequest attribute in reality, with the name campaign to use as a template for the form fields.
You haven't added a request attribute with that name. You need to do that before the view is rendered. For example
#RequestMapping(value = "/secure/campaigns.jsp", method = RequestMethod.GET)
public String campaigns(Model model) {
model.addAttribute("campaign", new Campaign());
return "campaigns";
}
The object doesn't need to have any fields set since it is only used as a template.

Related

JSP Input value To Java Method -> HttpServletRequest gives NULL value

Hello Guys.
I have simple Storage page whichs display all Products from DB.
I set to each of them with Unique name to change the Amount of product.
When i want to catch this value in Java method its returns me null.
Can you help me what i need to do to corretly catching value's in this text inputs ?
Controller :
#Controller
public class StoragePageController extends HttpServlet {
#GET
#RequestMapping(value = "/storage/subamount/{id}")
public String substractTheAmountValue(#PathVariable("id") int id, Model model, HttpServletRequest request) {
String amount_req = request.getParameter("amount_sub_" + id);
System.out.println(amount_req);
return null;
}
}
JSP fragment :
<c:set var="licznik" value="${recordStartCounter }" />
<div align="center">
<table width="1000" border="0" cellpadding="6" cellspacing="2">
<c:forEach var="u" items="${productList }">
<c:set var="licznik" value="${licznik+1}" />
<tr onmouseover="changeTrBg(this)" onmouseout="defaultTrBg(this)">
<td align="right"><c:out value="${licznik }" /></td>
<td align="left"><c:out value="${u.description }" /></td>
<td align="left"><c:out value="${u.amount }" /></td>
<td align="center"><input type="text" name="amount_sub_${licznik}" id="amount_sub_${licznik}"></td>
<td align="center"><input type="button" value="Substract the value" onclick="window.location.href='${pageContext.request.contextPath}/storage/subamount/${licznik}'"/></td>
</tr>
</c:forEach>
</table>
You should be having your API controller like the one given below given that your UI is posting the data to your API / Controller (assuming you are using the latest version of Spring Boot). You have a #Get mapping which does not accept request payload in the body.
#RestController
public class StoragePageController {
#PostMapping(value = "/storage/subamount/{id}", produces = {"application/json"})
public String substractTheAmountValue(#PathVariable("id") int id, Model model) {
String amount_req = id;
System.out.println(amount_req);
return null;
}
}

Spring Thymeleaf - How to map to a URL that requires an ID that is passed from HTML to the controller?

In my application the user clicks a link to edit an exam of their choice.
When they click the link it should open the editExam.html and the URL contains the ID of the exam they selected.
When I click the link the URL is correct (it contains the exam ID) however it doesn't display the editExam.html page it just displays my main page (the default localhost page)
allSubjects.html (the page where the user selects which exam to edit)
<h4> exams:</h4>
<div th:each="exam : ${subject.exam}">
<h4 th:text="${exam.examTitle}"/>
<a th:href="#{/editExam.html(id=${exam.examId})}">Edit Exam</a>
editExam.html (this is the page I can't display)
<form action="#"th:action="#{/editExam.html{examId}}" th:object="${exam}" method="put">
<table>
<tr>
<td> Exam Title:</td>
<td><input type="text" th:field="*{examTitle}" th:text="${exam.examTitle}"/></td>
<!-- <td th:if="${#fields.hasErrors('examTitlee')}" th:errors="*{examTitle}">error message</td> -->
</tr>
<tr>
<td> Exam grade worth </td>
<td><input th:field="*{examGradeWorth}" /></td>
<!-- <td th:if="${#fields.hasErrors('examGradeWorth')}" th:errors="*{examGradeWorth}">error message</td> -->
</tr>
<tr>
<td>examGradeAchieved</td>
<td><input th:field="*{examGradeAchieved}"/></td>
</tr>
<tr>
<td><button type="submit">Submit post</button></td>
</tr>
</table>
</div>
</form>
My controller:
//Update an exam
#RequestMapping(value = "/editExam.html{examId}", method = { RequestMethod.POST, RequestMethod.PUT})
public String editExam(#ModelAttribute("exam") #PathVariable(value = "examId")Long examId, #RequestBody Exam exam,Model model, BindingResult result) {
examRepository.findOne(examId);
model.addAttribute("examTitle", exam.getExamTitle());
model.addAttribute("examGradeWorth", exam.getExamGradeWorth());
model.addAttribute("examGradeAchieved", exam.getExamGradeAchieved());
exam.setExamTitle(exam.getExamTitle());
exam.setExamGradeWorth(exam.getExamGradeWorth());
exam.setExamGradeAchieved(exam.getExamGradeAchieved());
examRepository.save(exam);
return "editExam";
}
This code was displaying the editExam page before I added "RequestMethod.POST" to the controller.
Try to change
<a th:href="#{/editExam.html(id=${exam.examId})}">Edit Exam</a>
to
<a th:href="#{/exam/{id}(id=${exam.examId})}">Edit Exam</a>
and in your Controller
#RequestMapping(value = "/editExam.html{examId}", method = { RequestMethod.POST, RequestMethod.PUT})
to
#RequestMapping(value = "/exam/{examId}", method = { RequestMethod.POST, RequestMethod.PUT})
This url does not look correct. It should be /editExam.html?id=1, without a /.
I noticed that you are mixing request params and path variables. In your controller you expect #PathVariable(value = "examId") but in the view you are specifying request parameter instead of path variable.
Check this post: #RequestParam vs #PathVariable

Passing object's variable to controller in thymeleaf

I'm trying to create my very first CRUD ever.
Here's my journeySite.html table code.
<table>
<tr th:each="trip : ${trips}">
<td th:text="${trip.title}"></td>
<td th:text="${trip.destination}"></td>
<td th:text="${trip.id}"></td>
<form th:action="#{/journeys}" th:object="${trip}" method="post">
<input type="hidden" th:field="${trip.id}" />
<button type="submit">Delete</button>
</form>
</tr>
</table>
And make a my controller looks now like that.
#RequestMapping(value = {"/journeys"}, method = RequestMethod.GET)
public String journeysPage(Model model){
tripRepository.save(new Trip("Asian Trip", "Asia"));
tripRepository.save(new Trip("European Trip", "Europe"));
tripRepository.save(new Trip("African Trip", "Africa"));
model.addAttribute("trips", tripRepository.findAll());
return "journeysSite";
}
#RequestMapping(value = {"/journeys"}, method = RequestMethod.POST)
public String journeysPageTripDeleting(#RequestParam Long id) {
tripRepository.delete(id);
return "journeysSite";
}
All i want is to show my all my trips on the /journeys in table. In each row there'd be a delete button which would POST trip.id, delete it from db and redirect to the exact same page, but with trip deleted.
But obviously error has occured: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'id' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144) ~[spring-webmvc-4.3.6.RELEASE.jar:4.3.6.RELEASE]
Would anyone give me a tip how to do it? Thanks.
At your form, you defined a th:object="${trip}" object which means whenever this form gets submitted this trip object will be sent as request body.
So, to receive this object you have to accept it in controller's method.
#RequestMapping(value = {"/journeys/"}, method = RequestMethod.POST)
public String journeysPageTripDeleting(#ModelAttribute Trip trip){
tripRepository.delete(trip.getId());
return "redirect:/journeys";
}
The th:field="${id}" will be included with the object that model attribute provides so, trip object will have the id you're looking for.
More on this.
UPDATE:
With your current controller's method implementation, I think all you need to change is this,
<input type="hidden" th:field="*{id}" /> // No trip.id
You need to change your controller method post code from #RequestMapping(value = {"/journeys/"}, method = RequestMethod.POST) to #RequestMapping(value = {"/journeys/{id}"}, method = RequestMethod.POST).
As you can see,You forgot to add {id} in your RequestMapping which is required.
Also its standard to use DELETE http method for deleting an entity not POST method.
This is not good practice to create form for each row. Instead do it this way:
<table>
<tr th:each="trip : ${trips}">
<td th:text="${trip.title}"></td>
<td th:text="${trip.destination}"></td>
<td th:text="${trip.id}"></td>
<td><button class='delete' data-id="${trip.id}">Delete</button></td>
</tr>
</table>
Add this js in your html:
<script>
$(document).ready(function () {
$(document).on('click', '.delete', function () {
$.ajax({
url: "<c:url value="/journeys/delete"/>",
data: {
id: $(this).data("id")
},
success: function(data) {
location.reload();
}
})
})
})
</script>
And change your controller method like this:
#RequestMapping(value = {"/journeys/delete"}, method = RequestMethod.GET)
#ResponseBody
public String journeysPageTripDeleting(#RequestParam Long id) {
tripRepository.delete(id);
return "success";
}

Spring Form Tag Error (Binding Result)

I am teaching myself Spring Form tags, and have run into what is probably a simple error that I haven't been able to solve. I get the following error when I launch this app in a browser:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'index' available as request attribute
I've tried most of the fixes that came up in a Google search to no avail. Can someone spot where I went wrong? Below are the relevant components. Thanks very much.
Controller:
#Controller
#RequestMapping("/registration")
public class LoginController {
#RequestMapping(method = RequestMethod.GET)
public String setupForm(ModelMap model) {
Registration registration = new Registration();
model.addAttribute("registration", registration);
return "index";
}
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("registration") Registration registration, Map model) {
return "success";
}
}
JSP (/index.jsp):
<form:form commandName="index">
<table border="0" cellspacing="12">
<tr>
<td>
<form:input path="email"/>
</td>
</tr>
<tr>
<td>
<form:password path="password"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
Command Object (Registration.java) :
public class Registration {
private String password;
private String email;
// getters,setters
Facing same issue few days back, What i understood from hit and trail is, Index page is a static page and no processing happens before the same is rendered. In case i want to use a form model binding in index page i should have a controller's handler method which will create a Registration object and place the same in ModelAndView before index.jsp is rendered
add a method in your controller like the below and try
#RequestMapping(method = RequestMethod.GET, value="/")
public ModelAndView initiate(){
ModelAndView objModView = new ModelAndView("/index.jsp");
objModView.addObject("registration",new Registration());
return objModView;
}
In your index page correct the following and try
<form:form commandName="index"> to <form:form commandName="registration">
You can also do it like this if the above does not work
<form:form modelAttribute="registration" commandName="registration">
Thanks
The error which is seen is because when you submit the form you have to have a Binding Result associated with the #ModelAttribute annotation.
Try changing you code to this :
#RequestMapping(method = RequestMethod.POST)
public String onSubmit(#ModelAttribute("registration") Registration registration, BindingResult result, Map model){
return "success";
}
Also note that the Binding Result object should be followed immediately after the Model Attribute.
And if you are using two #ModelAttributes then each one should have its own binding result object which follows it.
Please refer the spring source guide for all the related documentation
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html

Passing parameters from JSP to Controller in Spring MVC

I am trying out a sample project using Spring MVC annotated Controllers. All the examples I have found online so far bind the JSP to a particular model and the controller uses #ModelAttribute to retrive the model object in the handler method.
How do I go about passing other parameters (not present in the Model object) from the JSP to Controller? Do I use JavaScript to do this? Also can someone clarify what the HttpServletRequest object should be used for.
Thanks.
Just remove the "path" from the jsp input tag and use HttpServletRequest to retrieve the remaining data.
For example I have a bean like
public class SomeData {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then in the jsp i will have the additional data fields to be send in normal html tag
<form:form method="post" action="somepage" commandName="somedata">
<table>
<tr>
<td>name</td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td>age</td>
<!--Notice, this is normal html tag, will not be bound to an object -->
<td><input name="age" type="text"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="send"/>
</td>
</tr>
</table>
</form:form>
Notice, the somedata bean has the name field the age is not. So the age field is added without "path". Without the path attribute the object property wont be bound to this field.
on the Controller i will have to use the HttpServletRequest like,
#RequestMapping("/somepage")
public String someAction(#ModelAttribute("somedata") SomeData data, Map<String, Object> map,
HttpServletRequest request) {
System.out.println("Name=" + data.getName() + " age=" + request.getParameter("age"));
/* do some process and send back the data */
map.put("somedata", data);
map.put("age", request.getParameter("age"));
return "somepage";
}
while accessing the data on the view,
<table>
<tr>
<td>name</td>
<td>${somedata.name}</td>
</tr>
<tr>
<td>age</td>
<td>${age}</td>
</tr>
</table>
somedata is the bean which provides the name property and age is explicitly set attribute by the controller.
If one doesn't want to create another class (bean) though it should be there, then apart from #ModelAttrbute one can also use #RequestParam.
public String someAction(#RequestParam("somedata") String data)
{
------
}

Categories

Resources