I want to update some user’s data and have issue with receiving parameters from JSP dropdown menu. I want to receive entered compId from “Enter PC” block and pass it as a PathVariable. But it is not seen. If I hardcode action="${app}/adminEdit.do/${user.userId}/${any number}" it works. So, question is – now to get this parameter from dropdown and set it to path? Thanks in advance.
Update.jsp snippet
<c:set var="app" value="${pageContext.request.contextPath}"/>
............
<DIV class="admin_redaction_block">
<sf:form name="adminUserUpdate"
method="POST"
modelAttribute="userForm"
action="${app}/adminEdit.do/${user.userId}/${comp.compId}"
enctype="application/x-www-form-urlencoded">
<c:if test="${not empty errorMsg}">
<div class="error">
<c:out value="${errorMsg}"/>
</div>
</c:if>
<sf:label path="password"><strong>Enter new password:</strong></sf:label> <br>
<sf:input path="password" type="text" size="20"/><br>
<sf:errors path="password" cssClass="error"/>
<br>
<sf:label path="email"><strong>Enter new Email:</strong></sf:label> <br>
<sf:input path="email" type="text" size="20"/><br>
<sf:errors path="email" cssClass="error"/>
<strong>PC Assigned:</strong>
<h3 class="h3">
<td>
<c:choose>
<c:when test="${user.computers!= null && !user.computers['empty']}">
<c:forEach items="${user.computers}" var="comp">
<c:out value="${comp.pcName}"/>
</c:forEach>
</c:when>
<c:otherwise>
<p class="h3_error">No PC Assigned</p>
</c:otherwise>
</c:choose>
</td>
</h3>
<sf:label path="computers">Enter PC:</sf:label> <br>
<sf:select path="computers" size="3">
<c:forEach items="${computers}" var="comp">
<sf:option value="${comp.compId}">
<c:out value="${comp.compId}"/>
</sf:option>
</c:forEach>
</sf:select>
<br> <br>
<input type="SUBMIT" name="SUBMIT" value="Update User"/>
</sf:form>
Controller
#RequestMapping(value = "/adminEdit.do/{userId}/{compId}", method = RequestMethod.POST)
public ModelAndView updateUserProcess(#ModelAttribute(value = "userForm")
UserForm userForm,
#PathVariable("userId") Integer userId,
#PathVariable("compId") Integer compId,
BindingResult result, Model model,
HttpSession session,
HttpServletRequest request) {
User user = userService.getUserById(userId);
model.addAttribute("computers", computerService.getAllComputers());
............
model.addAttribute("userForm", userForm);
return updatingUser(user, model, userForm);
}
You cannot.
You simply forgot that thing are written at different time.
<sf:form name="adminUserUpdate" ...
action="${app}/adminEdit.do/${user.userId}/${comp.compId}" ...>
is written at the time of answering the request that generates the form. At that time, your app (server side) is simply generating a HTML page, and the $comp.compid} does not exist. You can verify it by looking at the HTML source code of the page in your browser.
Later, when you click on the submitbutton, the browser gather data from input fields encode all and send it via a POST request to the action URL without changing it. Browser does not even know that you wrote ${app}/adminEdit.do/${user.userId}/${comp.compId} in your jsp : it only recieved a plain text string localhost:8080/adminEdit.do/2/
So ... try to get comp.compid from an input field of your form using a <sf:select> or <sf:checkboxes> tag.
Well, after long time of searching I've found now I can pass parameters from JSP to Controller. There are special class CustomCollectionEditor which helps pass even multiple select values.
Here is good example https://blog.codecentric.de/en/2009/07/multiple-selects-mit-spring-mvc-2/
And my snippet:
#InitBinder("userForm")
private void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Set.class, "computers", new CustomCollectionEditor(Set.class) {
#Override
protected Object convertElement(Object element) {
String pcName = null;
Set<Computer> computerSet = new LinkedHashSet<>();
if (element instanceof String && !((String) element).equals("")) {
pcName = (String) element;
}
return pcName != null ? computerService.getComputerByName(pcName) : null;
}
});
}
Related
I'm creating a web application using Spring MVC framework and forms.
I'm having trouble getting my form to update the field position in my PlayerModel. It simply doesn't save the value when I submit the form (check the controller inline comment on the submit() function).
If I select either radio button (with values 1 and 2) and submit, the model reaches the controller with value 0.
Despite having read countless similar questions/answers here on StackOverflow, I am unable to get this to work. What am I doing wrong here?
[EDIT]
I figured out the problem. For some reason, the value of the name attribute in the radio input is being used to match with the model attribute, instead of using path.
<input type="radio" id="index1" value="1" path="position" name="index" />
So it is trying to match index with the model, which of course does not exist, instead of using the position value in the path attribute.
Shouldn't it be the other way around?
playerView.jsp
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
</head>
<body>
<form:form action="/game/playerView" method="POST" modelAttribute="playerModel">
<table>
<tr>
<th>
<input type="radio" id="index1" value="1" path="position" name="index" />
<input type="radio" id="index2" value="2" path="position" name="index"/>
</th>
</tr>
<tr>
<td><input type="submit" value="Submit"/></td>
</tr>
</table>
</form:form>
</body>
</html>
GameController.java
#Controller
#SessionAttributes("playerModel")
public class GameController {
#RequestMapping(value = "playerView", method = RequestMethod.GET)
public ModelAndView hello(ModelMap map) {
PlayerModel playerModel = new PlayerModel();
playerModel.setPosition(0);
map.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
#RequestMapping(value = "playerView", method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute("playerModel") PlayerModel playerModel, BindingResult result, ModelMap model){
playerModel.getPosition(); // returns 0
model.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
}
PlayerModel.java
#Resource
public class PlayerModel {
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
}
You are using Spring-MVC form tag therefore please do not use this <input type="radio" id="index1" value="1" path="position" name="index" /> insted of use like this (For more details)
<tr>
<td>Sex:</td>
<td>
Male: <form:radiobutton path="sex" value="M"/> <br/>
Female: <form:radiobutton path="sex" value="F"/>
</td>
</tr>
and there is no path variable in HTML <input type="radio"> ,
path should be used in the spring type declaration.
eg :
<form:input path="firstName"/> this code is changed to <input name="firstName" type="text"/> by Spring
Hello i am passing information in a form and everything runs fine but when i fill out the form it doesnt not pass the information and i am getting this error.
There was an unexpected error (type=Internal Server Error, status=500).
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
Caused by: java.sql.SQLIntegrityConstraintViolationException: Column 'movie_id' cannot be null
the code i am using is as folow:
#PostMapping("/save")
public String save(Movie movie) {
savedMovie.save(movie);
return "redirect:/LatestMovies";
}
And
<form th:action="#{/save}" method="post" >
<p><input type="text" id="movie_id" name="movie_id" value="" /></p>
<p><input type="text" id="movie_name" name="movie_name" value="" /></p>
<p><input type="submit" value="save" /></p>
</form>
i belive all other code is correct becuase if i try to render the db information i have no problem.
Update
This is the complete html code.
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form th:action="#{/save}" method="post" th:object="${newMovie}">
<p><input type="text" id="movie_id" th:field="*{movie_Id}"/></p>
<p><input type="text" id="movie_name" th:field="*{movie_Name}"/></p>
<p><input type="submit" value="save" /></p>
</form>
</td>
</tr>
</table>
Your controller is expecting a Movie object, but it is receiving something else, which then produces a null Movie object. You need to use th:object in your form in order to correctly send the respective class. First, let's add a new #ModelAttribute to your controller, so that your form can automatically map your Movie object in your form.
Controller
// In order to use th:object in a form, we must be able to map a new entity to that form.
// In this case we return a Movie entity.
#ModelAttribute(value = "newMovie")
public Movie newMovie() {return new Movie();}
Now, let's change your form, so that it actually sends a Movie object.
<form th:action="#{/save}" method="post" th:object="${newMovie}">
<p><input type="text" id="movie_id" th:field="*{movie_id}"/></p>
<p><input type="text" id="movie_name" th:field="*{movie_name}"/></p>
<p><input type="submit" value="save" /></p>
</form>
Note that I also changed the name attribute in your inputs, for th:field. Have in mind that in order for this to work, the name of each field must match exactly the names in your objects.
Update
In case you want to set a default value to your form, without using js and since you can't combine th:field with th:value, you could set the object's attribute in your controller.
#ModelAttribute(value = "newMovie")
public Movie newMovie() {
Movie movie = new Movie();
movie.setName("Test");
return movie;
}
Update 2
If what you want is to put the current iteration of a Thymeleaf list in your form, you can do the following.
<div class="container">
<table class="table table-hover">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="LatestMovies : ${latestMovies}">
<td th:text="${LatestMovies.id}"></td>
<td th:text="${LatestMovies.movieName}"></td>
<td>
<form th:action="#{/save}" th:object="${LatestMovies}" method="post">
<p><input type="hidden" th:value="*{id}"/></p>
<p><input type="hidden" th:value="*{movieName}"/></p>
<p><input type="submit" value="Submit"/></p>
</form>
</td>
</tr>
</table>
You forgot to mark method param with #RequestBody annotation.
This happens because the movie object you are trying to send from the form to the controller is not mapped properly. This has as a result the constraint of the movie_id you have in your movies table (PK not null I guess) to be violated by trying to insert a not null value into it. If you want the object formed in the frontend page form to be binded in a java object you could try this
front page form
<form:form action="save" modelAttribute="movie" method="POST">
<form:label path = "movie_id"> Movie id</form:label>
<form:input path="movie_id" name="movie_id">
<form:label path = "movie_name"> Movie name</form:label>
<form:input path="movie_name" name="movie_name">
<button type="submit">save</button>
</form:form>
(you should import on your page the springframework form taglib
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>)
Save controller code
#PostMapping("/save")
public String save(#ModelAttribute("movie") Movie movie) {
savedMovie.save(movie);
return "redirect:/LatestMovies";
}
Of course I am assuming that your object has a similar structure like shown below
Movie class
public class Movie{
private String movie_id; // or int or long
private String movie_name;
//getters setters constructors ommitted
}
I have got a html page (with Thymeleaf):
<form action="#" th:action="#{/changeme}">
<fieldset>
<table style="width: 500px">
<tr th:each="esfield : ${esfields}">
<td>
<div>
<div class="checkbox">
<input type="checkbox" name="optionsMulti"
th:text="${esfield}" />
</div>
</div>
</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>
<button type="submit"
class="btn btn-xs btn-primary margin10-right paddingNew"
name="save">Calculate!</button>
</td>
<td></td>
</tr>
</table>
</fieldset>
</form>
When I click Calculate! it goes to my controller
#RequestMapping(value = "/changeme", params = { "save" })
public String save(final ModelMap m) {
m.addAttribute("centers", /*params*/);
return "clustering";
}
I would like to get information about checked boxes in my controller?
How can I do that?
Thank you in advance
You have basically two options :
either you use a different name for each checkbox
or you use spring tag <form:checkbox> instead of native <checkbox>
If you don't posted data will not allow you to know exactly what boxes were actually checked (excepted in cases all and none)
With the approach, you should use in your controller a #ModelAttribute annotated object containing a List<Boolean> and spring will automagically populate it with the values of your checkboxes.
#RequestMapping(value = "/changeme", params = { "save" })
public String save(#ModelAttribute BoxesForm form, final ModelMap m) {
// do what you need with form.getCheckboxes() ...
m.addAttribute("centers", /*params*/);
return "clustering";
}
public class BoxesForm {
List<Boolean> checkboxes;
// getter and setter omitted ...
}
I am trying to write freemarker template but could not able to parse with my object class.
My POJO is
public class Metrix {
#Id
String _id;
String loginId;
Date date;
List<MatrixDetail> headers;
//All getters and setters
}
public class MatrixDetail {
String header;
int time;
String detail;
//All getters and setters
}
//Controller after saving form
#RequestMapping(value = "/matrix/save", method = RequestMethod.POST)
public View saveMatrix(#ModelAttribute Metrix matrix, ModelMap model) {
System.out.println("Reachecd in matrix save" );
return new RedirectView("/TrackerApplication/header.html");
}
FTL template form part
<form name="matrix" action="matrix/save.html" method="post">
<table class="datatable" align:"center">
<tr>
<th>Login Id:</th> <th> <input type="text" name="loginId" value= ${matrixList.loginId} required /> </th>
</tr>
<tr> <td></td><td></td><td></td></tr>
<tr>
<th>Header</th> <th>Time</th> <th>Details</th>
</tr>
**// I am not getting how this nested object which is of type List<MatrixDetail>
// will get parse in my form.**
<#list matrixList.headers as header>
<spring:bind path = "MatrixDetail">
<tr>
<td> <input name = "header" value = ${header.header} /> </td>
<td> <input name = "time" value = ${header.time} /> </td>
<td> <input name = "detail" value = ${header.detail} /></td></tr>
</#list>
</table>
<input type="submit" value="Save" />
</form>
How can we write freemarker template for form processing of such kind of nested object?
I am getting issues in form submission.
I would strongly advise against this.
Forms might be displayable in email in some cases, but they may not always work in the email client, not to mention those that only ever read emails in text-only form won't be able to use them whatsoever.
If you need users to enter a form, link to a page on your site and have the form there instead.
I have a jsp page which uses spring tag lib. I have elements on he page that is bind to properties of an object. I also have button values that are not bind to the POJO i am trying to get these values on the server. Under is the code
JSP
<body>
<form:form id="monitoringList" name="monitoringList" commandName="monitoring">
<h3>Monitoring For Criminals Victims/Wittiness</h3>
<h3>Crime Record - ${crimeRecNo}</h3>
<div id="victims">
<h3>Victims</h3>
<hr>
<input type="hidden" id="records" value="${records}"/>
<div id="citizen_row">
<label class="name"></label>
<form:input class="citizen" type="hidden" name="socialSecurityNumber" path="socialSecurityNumber"/>
<table border="1">
<tr>
<td><form:input type="hidden" path="crimeRecNo" name = "crimeRecNo"/>
<canvas id="photoCvs${citizen.socialSecurityNumber}" class="canvas" height="200" width="200"></canvas></td>
<td><label>Start Date : </label><form:input name= "monitoringStDate" path="monitoringStDate" id="monitoringStDate"/></td>
<td><label>End Date : </label><form:input name="monitoringEndDate" path="monitoringEndDate" id="monitoringEndDate"/></td>
<td>
<label>Monitoring Type : </label>
<form:select path="monitoringTypeId" name="monitoringTypeId" id="monitoringTypeId" title="Monitoring Type">
<form:options items="${monitoringType.monitoringTypeList}" itemValue="monitoringTypeId" itemLabel="monitoringTypeDesc" />
</form:select>
</td>
</tr>
</table>
<div><button id="action" onclick="submitPage('${pageContext.request.contextPath}/monitoringList.htm','POST');" type="button">Create Monitoring Records</button></div>
</div>
<!-- MySql first record starts at 0. So we need to send in the value 0 to get the first record. Create Record Navigation based on record count -->
<div id= "recordNavigation">
<c:forEach begin="0" end="${records - 1}" var="i">
<input type="submit" class="navigationbtns" id="page" onclick="submitPage('${pageContext.request.contextPath}/monitoringList.htm','POST');" value="${i}"/>
</c:forEach>
</div>
</div>
</form:form>
</body>
This is the controller and i am using request.getParameter to get the value of the button however the value id null when i click on the button which post me to the server
Controller
#RequestMapping(value = "monitoringList.htm", method = RequestMethod.POST)
public ModelAndView handleNextMonitoringPage(#ModelAttribute("crimeRecNo")Integer crimeRecNo, Model model,#ModelAttribute Monitoring monitoring, BindingResult result,ModelMap m,HttpServletRequest request,SessionStatus status, HttpSession session) throws Exception {
String p_page = request.getParameter("page");
logger.info("Page request was ::" + p_page);
//int page = 0;
myMonitoringTypeList.put("monitoringTypeList",this.monitoringTypeManager.getListOfMonitoringType());
model.addAttribute("monitoringType",myMonitoringTypeList);
Monitoring aMonitoringRecord = new Monitoring();
aMonitoringRecord = this.monitoringManager.getAMonitoringRecByCrimeRecNo(crimeRecNo, page);
int recordCount = this.monitoringManager.MonitoringRecords_RecordCount(crimeRecNo);
model.addAttribute("records",recordCount);
model.addAttribute("crimeRecNo", crimeRecNo);
model.addAttribute("monitoring", aMonitoringRecord);
return new ModelAndView(new RedirectView("monitoringList.htm"),"page",page);
}
you are missing the name attribute under which the value is being submitted
<button name="page" ....>
and
<input type="submit" name="page" ..../>