Is greeting view and the result view pointing to the same object? - spring

Here our controller may return one of two views.
In such a case where these 2 method signatures both contained Model Model Map and ModelAttribute, do the views share access to the Model and ModelAttribute loaded by a previous request handle?
#Controller
public class GreetingController {
#GetMapping("/greeting")
public String greetingForm(Model model) {
model.addAttribute("greeting", new Greeting());
return "greeting";
}
#PostMapping("/greeting")
public String greetingSubmit(#ModelAttribute Greeting greeting) {
return "result";
}
}

It does not point the same object.
I am assuming you are using https://spring.io/guides/gs/handling-form-submission/
and its code naming convention is quite confusing.
Please see the following test code.
I changed URL, variable name purposely.
Greeting.java
public class Greeting {
private long id;
private String content;
//... getters and setters
}
Greeting2.java
//created for testing
public class Greeting2 {
private long id;
private String content;
//... getters and setters
}
GreetingController.java
#Controller
public class GreetingController {
#GetMapping("/greeting") // greeting URL and GET request method
public String greetingForm(Model model) {
// th:object="${foo}" in template and thymeleaf
model.addAttribute("foo", new Greeting());
return "greeting_tmpl"; // src/main/resources/templates/greeting_tmpl.html
}
#PostMapping("/greeting_post")
public String greetingSubmit(#ModelAttribute Greeting2 bar) {
//I expected using bar variable in result_tmpl, but it used Greeting2(lowercase) as variable
return "result_tmpl"; // src/main/resources/templates/result_tmpl.html
}
}
src/main/resources/templates/greeting_tmpl.html
...
<body>
<h1>Form</h1>
<form action="#" th:action="#{/greeting_post}" th:object="${foo}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Message: <input type="text" th:field="*{content}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
src/main/resources/templates/result_tmpl.html
...
<body>
<h1>Result</h1>
<p th:text="'id: ' + ${greeting2.id}" /> <!-- this name should be like bar.id not greeting2 -->
<p th:text="'content: ' + ${greeting2.content}" />
Submit another message
</body>
</html>
Simply,
Browser triggers #GetMapping.
Server Parses Greeting model to HTML form values in greeting template and response to the browser.
Submit Form Data using POST method triggers #PostMapping.
#ModelAttribute Greeting2(Can be any model which can parse form values(in this case, id,content) will parse form values to Greeting2 model.
Server Parses Greeting2 model to HTML form values in greeting template and response to the browser.

Related

How to transfer the list of strings in DTO using Thymeleaf

I'm developing Spring + Thymeleaf application. I'm implementing search with multiple params. I have a form with the corresponding DTO. Here is the code of the DTO:
public class ClassSearchDto {
private String searchParam;
private Long programId;
private List<String> teacherNames;
//getters, setters and constructor are omitted
}
As you see, I have a list of strings in my DTO called teacherNames. Here is the way I'm displaying my form:
<form th:action="#{/classes/search}" method="get" th:object="${classSearchDto}">
<div class="form-group">
<input type="hidden" class="form-control"
th:value="${classSearchDto.programId}" th:field="*{programId}"/>
<label for="searchParam">Search</label>
<input type="text" class="form-control" id="searchParam" placeholder="keyword"
th:value="${classSearchDto.searchParam}" th:field="*{searchParam}"/>
<div>
<th:block th:each="name, iter ${classSearchDto.teacherNames}">
<input th:value="${name}" th:field="*{teacherNames[__${iter.index}__]}/>
</th:block>
</div>
</div>
<button class="btn btn-default" type="submit">Find</button>
</form>
I want to implement my search with help of #RequestParam annotation on the back-end. This is my controller:
#RequestMapping(value = "/search")
public String findClassByName(#RequestParam("searchParam") final String searchParam,
#RequestParam("programId") final Long programId,
#RequestParam("teacherNames") final List<String> teacherNames,
final Model model) {
...
}
The problem is that I can't get the list of teacher names in this way. I get this exception:
org.springframework.web.bind.MissingServletRequestParameterException:Required List parameter 'teacherNames' is not present
Could you please help me to transfer the list of elements in DTO to my back-end with this approach? Maybe you know how to do it correctly in another way. Thank you in advance.
I can suggest you one thing, I don't know whether it works or not. Try changing
public String findClassByName(#RequestParam("searchParam") final String searchParam,#RequestParam("programId") final Long programId,#RequestParam("teacherNames") final List<String> teacherNames,final Model model)
to
public String findClassByName(#ModelAttribute("classSearchDto") ClassSearchDto classSearchDto,#RequestParam("searchParam") String searchParam,#RequestParam("programId") Long programId,#RequestParam("teacherNames") List<String> teacherNames,Model model)

Request parameter with thymeleaf

In a Spring Boot web app, User wants to reset his password, so he enters Reset password page. Now I want to let him type his email address, push Reset and I want to redirect to myapp/resetPassword?email=HIS_EMAIL to handle password reset.
MY code:
#RequestMapping(value = "/resetPassword", method = RequestMethod.GET)
public String resetPasswordForm(Model model){
model.addAttribute("email", new String());
return "resetPassword";
}
#RequestMapping(value = "/resetPassword", method = RequestMethod.POST)
public String resetPassword(#RequestParam("email") String email) {
User user = userService.findUserByEmail(email);
//playing with logic
return "redirect:/";
}
How can I achieve it on my thymeleaf page? I tried something like this:
<form th:action="#{/resetPassword(email=${email})}" method="post">
<input type="email" th:field="${email}" th:placeholder="Email" />
<div class="clearfix">
<button type="submit">Reset</button>
</div>
</form>
Unfortunately my email is always null. Can somebody help?
"th:field" is for Entity-Beans only. This should work:
#GetMapping(value = "/resetPassword")
public String resetPassword(#RequestParam(value="email",required=false) String email) {
if(email==null)
return "resetPassword";
User user = userService.findUserByEmail(email);
//playing with logic
return "redirect:/";
}
<form th:action="#{/resetPassword}" method="get">
<input type="email" th:name="email" th:placeholder="Email" />
<div class="clearfix">
<button type="submit">Reset</button>
</div>
</form>
And don't forget: Thymeleaf is not Javascript. It is rendered on Server. Things like #{/resetPassword(email=${email})} would output e.g. /resetPassword?email=anValueYouAddedToModelInController

Redirect on Spring Tiles Causing Parameters to be Appended to the URL

I am using Spring 3 and Tiles 3. Below is just a simplified example I made. I have a test controller where I list all the SimpleEntity objects. And there is an input field on the JSP to add a new entity via a POST. Here is the controller.
#Controller
#RequestMapping(value="/admin/test")
public class TestAdminController {
private String TEST_PAGE = "admin/test";
#Autowired
private SimpleEntityRepository simpleEntityRepository;
#ModelAttribute("pageName")
public String pageName() {
return "Test Administration Page";
}
#ModelAttribute("simpleEntities")
public List<SimpleEntity> simpleEntities() {
return simpleEntityRepository.getAll();
}
#RequestMapping(method=RequestMethod.GET)
public String loadPage() {
return TEST_PAGE;
}
#RequestMapping(method=RequestMethod.POST)
public String addEntity(#RequestParam String name) {
SimpleEntity simpleEntity = new SimpleEntity();
simpleEntity.setName(name);
simpleEntityRepository.save(simpleEntity);
return "redirect:/" + TEST_PAGE;
}
}
Everything works fine. However, when I submit the form, the URL adds the pageName parameter, so it goes from /admin/test to /admin/test?pageName=Test+Administration+Page. Is there anyway to prevent this from happening when the page reloads?
UPDATE
Here is the JSP form.
<form:form action="/admin/test" method="POST">
<input type="text" name="name" />
<input type="submit" name="Save" />
</form:form>

#NumberFormat Annotation not working

Trying to show the currency symbol in JSP but I don't see it. Did my research and I just don`t know what more should I add to get it working. This is what I have.
<mvc:annotation-driven />
Controller
#NumberFormat(style = Style.CURRENCY)
private Double value = 50.00;
#ModelAttribute("value")
#NumberFormat(style = Style.CURRENCY)
public Double getValue() {
return value;
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView loadForm(#ModelAttribute("user") User user) {
ModelAndView instance
modelAndView.addObject("value", 100.00);
return modelAndView;
}
JSP
<spring:bind path="value">
<input type="text" name="${value}" value="${value}"/>
</spring:bind>
<spring:bind path="value">
${value}
</spring:bind>
Output
<input type="text" name="value" value="100.0"/>
100.0
Try using the string literal value for the name attribute instead of resolving it with EL
<spring:bind path="value">
<input type="text" name="value" value="${value}"/>
</spring:bind>
Also, move the field value into a new object. Currently I do not believe the code is using the field in the controller or the getter in the controller.
public class MyForm(){
#NumberFormat(style = Style.CURRENCY)
private Double value = 50.00;
#ModelAttribute("value")
#NumberFormat(style = Style.CURRENCY)
public Double getValue() {
return value;
}
}
Then add the object to the model in the controller:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView loadForm(#ModelAttribute("user") User user) {
ModelAndView instance
modelAndView.addObject("myForm", new MyForm());
return modelAndView;
}
Then access via the jsp:
<spring:bind path="myForm.value">
<input type="text" name="${status.expression}" value="${status.value}"/>
</spring:bind>
<spring:bind path="myForm.value">
${status.value}
</spring:bind>
The major issue at the moment with the code is that it is not using the field/accessor, it is simply placing a value in the model, which does not use any of the annotated fields/methods.
References:
http://www.captaindebug.com/2011/08/using-spring-3-numberformat-annotation.html#.UOAO_3fghvA
How is the Spring MVC spring:bind tag working and what are the meanings of status.expression and status.value?

Spring framework bind form array property

// my form
public class myForm {
private double[] myField;
public double[] getMyField(){
return myField;
}
public void setMyField(double[] myField){
this.myField = myField;
}
}
// my jsp
...
...
<c:set var="i" value="0"/>
<c:forEach items="${myList}" var="data">
<form:input path="myField[${$i}]"/>
<c:set var="i">${i + 1}</c:set>
</c:forEach>
...
...
After spring render jsp generate this code ;
<input type="text" value="0.0" name="myField0" id="myField0"/>
<input type="text" value="0.0" name="myField1" id="myField1"/>
<input type="text" value="0.0" name="myField2" id="myField2"/>
...
...
Spring cant bind my form on controller , because form names not valid (myField0, myField1..) . If i change names with firebug (as myField[0], myField[1] etc.) initBinder works and i catch my form data on controller. How can i solve this?
Thanks.
Use a Collection in your form instead of an array :
public class myForm {
private Collection<Double> myField;
public Collection<Double> getMyField(){
return myField;
}
public void setMyField(Collection<Double> myField){
this.myField = myField;
}
}

Resources