I have problem with simple MVC application.
dayoff.html
<div id="dayoff_operations" class="big_box_1">
<form:form modelAttribute="dayOff" enctype="multipart/form-data" action="/dayoff.html" >
<div style="width: 50%; float: left; margin-top: 0px ">
<form:label path="forDate" ><spring:message code="dayoff.fordate.label"/></form:label>
<form:input path="ax_forDate" id="datepicker" style="width:65px" readonly="readonly"/>
</div>
<div style="width: 50%; float: right; margin-top: 0px ">
<form:label path="toDate" ><spring:message code="dayoff.todate.label"/></form:label>
<form:input path="ax_toDate" id="datepicker2" style="width:65px" readonly="readonly" />
</div>
<div style="float: left">
<form:select cssClass="more" path="dayofftype" items="${dayoffTypes.list}" itemLabel="label" itemValue="value" htmlEscape="false" cssErrorClass="errorsField"/>
<form:errors path="dayofftype" cssClass="errors"/>
</div>
<input type="submit" name="add" value="Add"/>
</form:form>
Here is my controller:
#Controller
#RequestMapping("/dayoff")
#SessionAttributes(types = {DayOff.class})
public class DaysOffController {
private Validator validator;
#Autowired
private ReloadableResourceBundleMessageSource messages;
#ModelAttribute("dayoffTypes")
public Map<String, Object> populateDayoffTypes(Locale locale) {
return Utils.createComboMap(DayoffType.values(), messages, locale);
}
#RequestMapping(method = RequestMethod.GET)
public String setupForm(Model model) {
model.addAttribute("dayOff", new DayOff());
model.addAttribute("cur_period",SessionManager.getCurrentPeriod());
return "dayoff";
}
#RequestMapping(method = RequestMethod.POST, params = "add")
public String addNewHoliday(#ModelAttribute DayOff dayOff, BindingResult result, ModelMap model) {
System.out.println("AAA");
return "/dayoff";
}
When I click Add button Error 400: SRVE0295E: Error reported: 400 appears, there is no information at server console.
I assume it is realted to the setupForm() method which is displaying the form and crushing it to future submits. Can you please guide me with this?
Error 400: SRVE0295E occurs also when MVC cannot fill #ModelAttribute Form with values from HTML form.
For example:
class Form has primitive attribute int someCount
your HTML form has <input> to assign value to this primitive attribute
user entered empty value (null) to this <input>
You should not use primitive types such as int, boolean, float and so on.
The return statements from setupForm and addNewHoliday are different. I presume you want to return the same view name from both. As you can see the form in order to submit it, I assume that the addNewHoliday return value of "/dayoff" should in fact be "dayoff"
Related
I familiarize myself with Thymeleaf.
I am trying to get data from a POST-mapping in the controller.
But I got null variables when I call employee.getName().
I looked a lot online but can't find a solution.
My controller class
#GetMapping
public String getEmployees(Model model) {
model.addAttribute("newEmployee", new Employee());
return "employees";
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null
return "employees";
}
HTML form with Thymeleaf
<div class="modal-body">
<form th:action="#{/employees}" th:object="${newEmployee}" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">First Name <span class="text-danger">*</span></label>
<input th:field="*{firstName}" class="form-control" type="text">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">Last Name</label>
<input th:field="*{lastName}" class="form-control" type="text">
</div>
</div>
See tutorials:
Wim Deblauwe: Form handling with Thymeleaf
Baeldung: Binding a List in Thymeleaf
#GetMapping("/all")
public String showAll(Model model) {
model.addAttribute("employees", employeeService.findAll());
return "employees/all";
}
#GetMapping("/add")
public String createForm(Model model) {
model.addAttribute("newEmployee", new Employee()); // the form-data object as blank employee to be filled
return "employees/form"; // the page containing the form
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null if either not set in HTML-form or not mapped from HTML-form to POST correctly
// save new employee or add to a repository
employeeService.save(newEmployee);
model.addAttribute("employees", employeeService.findAll());
return "redirect:/employees/all"; // use a redirect
}
Client-Server interaction:
First in your browser you should navigate to the endpoint adding the form-data-object, i.e. GET /employees/add.
Then the form-page should load and you will have a blank object newEmployee to bind all the input-fields to for submitting.
After submitting the form via the submit-click, a POST /employees is sent. The server/controller should receive the form-data as model-attribute in employee parameter and can save it.
The controller-method redirects back to the list-endpoint (same as navigating in browser to) GET /employees/all
<h1>Create employee</h1>
<form th:object="${newEmployee}"
th:action="#{/employees}"
method="post">
<input type="text" name="firstName" id="firstName" th:field="*{firstName}" />
<input type="text" name="lastName" id="lastName" th:field="*{lastName}" />
<button type="submit">Submit new employee</button>
</form>
The th:object attribute refers to the key under which we put our Employee instance in the model (newEmployee in this example). The th:action has the URL for the #PostMapping method. Finally, the method attribute is set to "post" since we want to use the HTTP POST method.
Using th:field=*{…}, we can setup a two-way binding between the HTML input and the field in our form data object.
I get an Internal Server Error, status=500: java.lang.NumberFormatException
The reason seems to be that my form data, sent via name attribute is not intercepted by #RequestMapping or HttpServletRequest doesn't work..
Here I try to pass the data:
<form action="/tankbeurt" method="get" style="padding: 5px;">
<div style="padding: 10px;">
<label for="huidig">Huidige kilometerstand</label>
<input type="text" name="huidig" id="huidig"></div>
<div style="padding: 10px;">
<label for="vorig">Vorige kilometerstand</label>
<input type="text" name="vorig" id="vorig"></div>
<div style="padding: 10px;">
<label for="liter">Hoeveel liter heb je bijgetankt</label>
<input type="text" name="liter" id="liter"></div>
<div><input type="submit" value="Bereken Verbruik"></div>
And I try to intercept it in the mainController:
#Controller
public class MainController {
#RequestMapping("/tankbeurt")
public String gegevens(HttpServletRequest request, Model model){
int huidigeKm = Integer.parseInt("huidig");
System.out.println(huidigeKm);
int vorigeKm= Integer.parseInt("vorig");
double liter= Double.parseDouble("liter");
Tankbeurt tankinformatie = new Tankbeurt(vorigeKm,huidigeKm,liter);
model.addAttribute("informatieTanken",tankinformatie);
return "tankbeurt";
}
Thankyou for your help. I don't see the problem.
Integer.parseInt("huidig");
You are trying to parse string "huidig" to integer. That's the cause of exception. Try looking for some method that extracts property from the model, like "model.getAttribute("huidig")".
Currently, the methods return only their own links into the required fields, ie. the last html element for available tests returns only availableTestList in the div that is supposed to list all available tests. Same for "/currentTest" and for the dropdown menu, which shows no options at all.
I started trying some fixes from here on SO, and now my html broke down completely, giving me the error:
An error happened during template parsing (template: "templates/Teacher.html")
and in java console:
"Neither BindingResult nor plain target object for bean name 'test' available as request attribute"
Any ideas?
Below is the controller code first, with the html afterwards.
#Controller
public class TeacherController {
TestController testcont = TestController.getInstance();
#RequestMapping(value = "sendTest", method = RequestMethod.POST)
public String sendTest(Model model) throws IOException, ServletException{
for(Test test : testcont.showAllTests()){
if(test.getName().equals("selection")){
testcont.SetActiveTest(test);
System.out.println(testcont.getActiveTest());
//return "Test sent successfully to students! <a href='/Teacher'>Back</a>";
}
}
model.addAttribute("tests", testcont.showAllTests());
return "sendTest";
}
#RequestMapping(value = "resetCurrentTest", method = RequestMethod.POST)
public String resetCurrentTest(Model model){
testcont.SetActiveTest(null);
model.addAttribute("tests", testcont.showAllTests());
return "resetCurrentTest";
}
#RequestMapping(value = "currentTestOptions", method = RequestMethod.GET)
//#ModelAttribute("/currentTestOptions")
//#GetMapping("/currentTestOptions")
public String currentTestOptions(Model model) {
model.addAttribute("tests", testcont.showAllTests());
return "currentTestOptions";
}
#RequestMapping(value = "getActiveTest", method = RequestMethod.GET)
public String getActiveTest(){
return testcont.getActiveTest().toString();
}
}
The HTML
<body>
<p>
<a href='/Teacher/NewTest'>New Test upload</a>
</p>
<div
style='height: 150px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<form th:action='${sendTest}' th:object="${tests}" method='post'>
<fieldset>
<label>Select test</label>
<select id="tests" name="tests" class="form-control" th:field="${tests}">
<option value="">Select test</option>
<option
th:each="test : ${tests}"
th:value="${test.getName}"
th:text="${test.getName}"
></option>
</select>
</fieldset>
<input type='submit' value='Submit'>
</form>
</div>
<form action='${resetCurrentTest}' method='post'>
<input type='submit' value='Clear'>
</form>
<a> Current Test for students: </a>
<p th:text="${getActiveTest}" ></p>
<p>All available tests on server:</p>
<div
style='height: 200px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<th:block th:each="test : ${tests}">
</div>
</body>
in the controller, the 3rd method "currentTestOptions" is supposed to return the full list of objects, and in the HTML I am to iterate through the list using test : currentTestOptions, and then as the value retrieve the test names to show in the dropdown.
Current console error when trying to open the local page /Teacher is:
Neither BindingResult nor plain target object for bean name 'test' available as request attribute
try this code
<option th:each="test : ${currentTestOptions}"
th:value="${test.getName}"
th:text="${test.getName}"></option>
for more thymeleaf-forum/Create-drop-down-list
thymeleaf-select-option
Bolow is my controller code:
ModelAndView view = new ModelAndView("view/index");
UserIdentity userIdentity = (UserIdentity) request.getSession().getAttribute(SessionConstant.ACCOUNT_SESSION_KEY);
if(userIdentity == null){
return null;
}
List<PayBill> payBills = payBillService.getBillDetailByUserId(userIdentity.getId());
if(payBills != null && payBills.size() > 0){
view.addObject("bill",payBills.get(0));
}
return view;
Bolow is my html code:
<div class="centerBox">
<div class="centerBox1" th:if="${bill != null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;" th:text="${bill.paymentAmount}">100.00</p>
</div>
<div class="centerBox1" th:if="${bill == null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;">0.00</p>
</div>
<button type="button" onclick="btn()" class="mui-btn mui-btn-primary" style="width: 100%;border-radius: 20px;margin:30px 0px 10px 0px" data-loading-icon="mui-spinner mui-spinner-custom" >立即缴费</button>
<p>往期水费记录</p>
<!-- image -->
<div class="bottomBox">
<img src="/images/bottom.png" width="100%" alt="" />
</div>
</div>
Attention please, use this code th:if="${bill != null} to avoid get a null value. if it's null, it giving me the error.
In html file you have:
<select class="form-control" th:field="${test.getName}">
Thymeleaf expects that you will pass attribute called test through model. You can do it like this:
model.addAttribute("test", yourObjectRepresentingTest);
Do this in a controller method that returns view to your html. For example:
#GetMapping("/showTests")
public String showTests(Model model) {
// some controller logic if you need
SampleTest sampleTest = new SampleTest(); // <- this is your backing bean object that will be bound to thymeleaf view
model.addAttribute("test", sampleTest);
return "showtests"; // <- this is a file name of a html containing your view
}
You may also need to add th:object to your html file:
<form th:action="#{/sendTest}" th:object="${test}" method='post'>
Hello I'm tryin to developpe a page that can delete users but when I click on submit I have an error Etat HTTP 400 - La requête envoyée par le client était syntaxiquement incorrecte.
Jsp file
</div>
<form method="POST" action="Users">
User ID
<input type="text" name="idUser" /><br><br>
<input type="submit" name="Supprimer" value="Supprimer"/>
</form>
Controller
#RequestMapping(value = "/Users")
public String goUsers(Model model)
{
model.addAttribute("AllUsers", UserS.getAllUsers());
return "Users";
}
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(#ModelAttribute User user,BindingResult result,#RequestParam int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
thank you
Your controller wrong. You expect oen User and one param with name id but you send one param with name idUser.
Eliminate ModelAttribute and force de name of RequestParam:
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(BindingResult result,#RequestParam(name="idUser") int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
1.first you need to add modelattribute to your form like this :
Notice how i am using spring forms. You can use them by adding
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
before DOCTYPE html>
Then you need to add hidden path to attribute "id" so when you controller gets the request you will know which user you will need to delete or edit.
This is example form :
`<form:form method="POST" modelAttribute="User" action="Users">
<form:hidden path="id"/>
<div class="form-group">
<label for="usernameId">Username</label>
<form:input path="username" id="usernameId" class="form-control" />
<form:errors path="username" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="fullNameId">Full Name</label>
<form:input path="firstLastName" id="firstLastName" class="form-control"/>
<form:errors path="firstLastName" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="passwordId">Password</label>
<form:password path="password" id="passwordId" class="form-control"/>
<form:errors path="password" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="emailId">Email</label>
<form:input path="email" id="emailId" class="form-control"/>
<form:errors path="email" style="color:red;"></form:errors>
</div>
<input type="submit" class="btn btn-default" value="Register"/>
</form:form>`
finally you will add to your controller class.
#ModelAttribute("User")
public User getUser(){
return new User();
}
Then you will need to adjust your controller like this :
#RequestMapping(value="/Users", method=RequestMethod.POST)
public String deleteUser(User user){
getRegisterService().deleteUser(user.getId());
return "home";
}
Note : You will have to create class = User : with id attribute(and all others you need). You will also need to create a method for deleting user in your service and repository layer.
P.S. User user in your deleteUser method is actually the same user you created with #modelAttribute annotation.
If you have any additional questions feel free to ask!
I have given you almost exact form i use for register/editing or deleting Users. When you submit form, everything will be saved into object User with annotation #modelAttribute. Hidden id field is crucial here. When you have id, which is primary key you can just create method in repository (something like this)
public void deleteUser(UserJPA userJPA){
getEntityManager().remove(UserJPA);
}
Hope you find this post helpful.
What's the best practice to pre-populate an object before saving this object with hibernate?
What i've done:
My controller:
//The Form
#RequestMapping(value = "user/{id}/edit", method = RequestMethod.GET)
public String edit(#PathVariable("id") Long userId, ModelMap modelMap) {
modelMap.addAttribute("user", userService.find(userId));
return "user/userEdit";
}
//Updating database
#RequestMapping(value = "user/edit", method = RequestMethod.POST)
public String update(#ModelAttribute("user") #Valid User user, BindingResult result,
RedirectAttributes redirectAttrs) {
if (result.hasErrors()) {
return "user/userEdit";
}else{
userService.update(user);
redirectAttrs.addFlashAttribute("message", "Success");
return "redirect:user/userEdit";
}
}
It works if i make a form containing all fields (username, password and id) , but what should i do if i want the user to update only the password?
Since i have a #NotEmpty at username, i get an error that username is null, since its not in the form, but i dont want to put the username field, just the password.
My html form:
<c:url var="url" value="/user/edit" />
<form:form method="post" action="${url}" modelAttribute="user" class="form-horizontal">
<form:hidden path="id"/>
<form:hidden path="version"/>
<fieldset>
<div class="control-group">
<form:label cssClass="control-label" path="password"><spring:message code="user.label.password"/>: </form:label>
<div class="controls">
<form:input cssClass="input-xlarge" path="password" />
</div>
<form:errors path="password"/>
</div>
<div class="control-group">
<form:label cssClass="control-label" path="userRole"><spring:message code="user.label.role"/>: </form:label>
<div class="controls">
<form:select path="userRole">
<form:options items="${userRoleList}" itemValue="id" itemLabel="name"/>
</form:select>
</div>
<form:errors path="userRole"/>
</div>
<div class="control-group">
<form:label cssClass="control-label" path="costumer.id"><spring:message code="user.label.costumer"/>: </form:label>
<div class="controls">
<form:select path="costumer.id">
<form:options items="${costumerList}" itemValue="id" itemLabel="name"/>
</form:select>
</div>
<form:errors path="costumer.id"/>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save changes</button>
<a class="btn cancel link" href="<c:url value="/user" />">Cancel</a>
</div>
</fieldset>
</form:form>
I tried using #Sessionattributes, but it doesnt work well if i try to
edit two or more users using browser tabs.
I tried using property editors, but didnt work with #ModelAtrribute
User user.
I tried using convertors but didnt work.
Is the only way to make a User user = userService.find(id) first, and then set the updated values? Something like:
#RequestMapping(value = "user/edit", method = RequestMethod.POST)
public String update(#RequestParam("password") String password, BindingResult result, RedirectAttributes redirectAttrs) {
User user = userService.find(id);
if (password == null{
return "user/userEdit";
}else{
user.setPassword("password");
userService.update(user);
redirectAttrs.addFlashAttribute("message", "Success");
return "redirect:user/userEdit";
}
}
Which seens wrong, because there is no validation.
An alternate way, that I think is less messy and accident-prone, is to create a class that models the UI form, for example
public class EditUserForm {
// getters and setters for password and other fields...
}
and in the controller's update(EditUserForm,...) method, you simply map any fields populated by the user in the EditUserForm to the instance of User you wish to update.
In the code you posted it's obviously clear that you need some external helper classes to associate with your GUI side updating before you implement the move-control and persistence operations.
I've run into this problem too, if there's only a couple fields I use your second example and validate the fields one by one. Otherwise, you're going to have to do what the other posters have said and make a new class to match your form.
Try to use:
#PrePersist
#PreUpdate
public void prepare(){
//DO SOMETHING WITH YOUR ENTITY
//For example: if(name==null){ name="MYNAMEVALUE";}
}