Spring HashMap Form - spring-mvc

I am creating an application with Spring Roo for generate documents. First of all the user create a document:
public class Document {
#NotNull
private String titleDocument;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisDateField")
private Set<DateField> dateFields = new HashSet<DateField>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisRadioButton")
private Set<RadioButtonField> radioButtonFields = new HashSet<RadioButtonField>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "relatedDocumentToThisStringField")
private Set<StringField> stringFields = new HashSet<StringField>();
}
There are 3 types of fields, for simplify, this is StringField (the others are almost the same):
public class StringField extends Field {
#NotNull
private String valueString;
#NotNull
private Boolean isEditable;
#ManyToOne
private Document relatedDocumentToThisStringField;
#NotNull
private String nameStringField;
}
When the document with fields is created, another user has to fill it. Since I dont know how much fields the document will have I need to create a HashMap Form (I am following this tutorial)
My HashMap is:
public class DynamicForm {
private Map<String, String> dynamicMap=new HashMap<String, String>();
public Map<String, String> getDynamicMap() {
return dynamicMap;
}
public void setDynamicMap(Map<String, String> dynamicMap) {
this.dynamicMap = dynamicMap;
}
}
In my FillDocumentController I have:
#RequestMapping(value = "/{id}", params = "form", produces = "text/html")
public String updateForm(#PathVariable("id") Long id, Model uiModel) {
...
// Create DynamicForm Map
DynamicForm dynamicForm = new DynamicForm();
for (Field field : allFields) {
// Is StringField?
if (field.getClass().equals(StringField.class) == true) {
StringField stringField = (StringField) field;
if( stringField.getIsEditable() == true ) {
dynamicForm.getDynamicMap().put(stringField.getNameStringField(), stringField.getValueString() );
}
}
}
uiModel.addAttribute("dynamicForm", dynamicForm);
return "filldocuments/update";
}
This is the view:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<jsp:output omit-xml-declaration="yes" />
<form:form action="/DocumentGenerator/filldocuments/add" modelAttribute="dynamicForm" method="post">
<c:forEach items="${dynamicForm.dynamicMap}" var="element">
<input name="element['${element.key}']" value="${element.value}"/>
</c:forEach>
<input type="submit" value="Save" />
</form:form>
</div>
And this is the method that catch the modelAttribute:
#RequestMapping(value="/add", method = RequestMethod.POST, produces = "text/html")
public String update(#ModelAttribute(value="dynamicForm") DynamicForm dynamicForm, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
for( String key : dynamicForm.getDynamicMap().keySet() ) {
System.out.println("key="+key);
}
return "redirect:/filldocuments";
}
My problem is that dynamicForm is empty. There is another DynamicForm inside of uiModel and is empty too (I was in debug mode). Where is the data that the user fill?? I dont know what is wrong!!

My fault, the view has to be like that:
<c:forEach items="${dynamicForm.dynamicMap}" var="dynamicMap">
<input name="dynamicMap['${dynamicMap.key}']" value="${dynamicMap.value}"/>
</c:forEach>
So the error was use the variable element

Related

Why iterate last data from ArrayList<>?

I get data from database perfectly and pass to the Thymeleaf(Template), but the problem is near mdl.addAttribute("number" ,request.getNumber()) in controller to detect last value from foreach loop iteration and send by model
Here down my code:
Dto
public interface ProfileDto {
public Integer getU_id();
public Integer getP_id();
public String getEmail();
public String getUsername();
public String getPassword();
public String getContact();
public String getDate();
public String getProfile();
public String getWebsite();
public String getBio();
public String getGender();
public String getPost();
}
Entity
#Entity
#Table(name = "request_master")
public class Request {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int req_id;
private int sender_id;
private int receiver_id;
private String status;
private String date;
#Transient
private int number;
// getter setter
}
Repository
public interface profileRepo extends JpaRepository<Request, Integer> {
#Query(nativeQuery = true, value = "SELECT * FROM registration_master rm INNER JOIN profile_master pm ON rm.u_id = pm.user_id WHERE rm.u_id != ?")
List<ProfileDto> findByIdUser(Integer Id);
public interface requestRepo extends JpaRepository<Request, Integer> {
#Query(nativeQuery = true, value="SELECT * FROM request_master WHERE sender_id = ? and receiver_id = ?")
List<Request> getSuggetionButton(Integer Sender_id, Integer Receiver_id);
}
Service
#Service
public class ServiceImpl implements Service {
#Autowired
private profileRepo profileRepo;
#Autowired
private requestRepo requestRepo;
#Override
public List<ProfileDto> getSuggestedList(Integer Id) {
return this.profileRepo.findByIdUser(Id);
}
#Override
public List<Request> getSuggestionButton(Integer Sender_id, Integer Receiver_id) {
return this.requestRepo.getSuggetionButton(Sender_id, Receiver_id);
}
}
Controller
#Controller
public class Controller {
#Autowired
private Service service;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model mdl, Request request) {
int SessionId = Integer.parseInt(session.getAttribute("uid").toString());
List<ProfileDto> Suggestion_list = service.getSuggestedList(SessionId);
for(ProfileDto Suggestion_id : Suggestion_list)
{
List<Request> Friend_request = this.service.getSuggestionButton(SessionId, Suggestion_id.getU_id());
if(Friend_request.size() > 0)
{
request.setNumber(Friend_request.size());
}
else
{
request.setNumber(0);
}
}
mdl.addAttribute("number" ,request.getNumber());
mdl.addAttribute("suggestionList", Suggestion_list);
return "post";
}
}
Thymeleaf
<div class="follow-user-list" th:each="suggetionFriend : ${suggestionList}">
<div class="follow-user clearfix" th:id="'follow-user'+${suggetionFriend.u_id}">
<img th:src="${suggetionFriend.profile}" alt="" class="profile-photo-sm pull-left" />
<div class="name clearfix">
<h5>
</h5>
<div class='follow-unfollow-btn' th:id="'follow-unfollow-button'+${suggetionFriend.u_id}">
<div th:text="${number}">
</div>
</div>
</div>
</div>
</div>
in below image 1 is for condition matched and find data and 0 is for condition not matched and not find data
In My output i can get only last iterate data in both user
Output:
Expected output:
I think problem is to pass data from controller to thymeleaf
If you have good idea to transfer value from Controller to Template tell me please
You should maintain request for each profile/user instead of having single request, what I mean by that is you should have number of request for each profileId/userId, you can maintain a map of profileId/userId and number of request for that profile/user, and use that map in your template, try to modify your code as below
Controller
#Controller
public class Controller {
#Autowired
private Service service;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model mdl, Request request) {
Map<Integer, Integer> profileToNoOfRequestMap = new HashMap<>();
int SessionId = Integer.parseInt(session.getAttribute("uid").toString());
List<ProfileDto> Suggestion_list = service.getSuggestedList(SessionId);
for(ProfileDto Suggestion_id : Suggestion_list)
{
List<Request> Friend_request = this.service.getSuggestionButton(SessionId, Suggestion_id.getU_id());
profileToNoOfRequestMap.put(Suggestion_id.getU_id(), Friend_request.size());
}
mdl.addAttribute("profileToNoOfRequestMap", profileToNoOfRequestMap);
mdl.addAttribute("suggestionList", Suggestion_list);
return "post";
}
}
Thymeleaf
<div class="follow-user-list" th:each="suggetionFriend : ${suggestionList}">
<div class="follow-user clearfix" th:id="'follow-user'+${suggetionFriend.u_id}">
<img th:src="${suggetionFriend.profile}" alt="" class="profile-photo-sm pull-left" />
<div class="name clearfix">
<h5>
</h5>
<div class='follow-unfollow-btn' th:id="'follow-unfollow-button'+${suggetionFriend.u_id}">
<div th:text="${profileToNoOfRequestMap.get(suggetionFriend.u_id)}">
</div>
</div>
</div>
</div>
</div>

Checkbox with Thymeleaf and custom List Object in Spring MVC (Boot)

I am using Thymeleaf with Spring Boot and MVC. What I have is a form in which certain checkboxes are being populated with an object(q1) added into the model from the controller
What I want to know is that how can I bind the selected checkboxes with my resulting object(surveyData) into a list of (complex) objects using Thymeleaf properly.
Edit
Also this is the first time I'm working on this combination of Spring Boot, Spring MVC, Spring JPA and entirely the first time I have used Thymeleaf. I'm not exactly sure where the problem may be. I did try debugging a lot but was unable to figure out where the problem is exactly. I tried various different combinations to get this working and got various different outcomes(mostly exceptions of course). It would be difficult for me to post all of them here so if you can suggest something I would love to try it out and post its result.
What I have till now: (The th:field for checkbox is obviously not working)
Code:
HTML Snippet:
<form action="#" th:action="#{/controlleraction}" method="post" th:object="${surveyData}">
<table class="table table-striped jambo_table bulk_action" id="table-resp">
<thead>
<tr>
<th></th>
</tr>
</thead>
<tbody>
<tr th:each="act,iter : ${q1}">
<td>
<input type="checkbox" class="check" th:value="${act.optionId}" th:field="*{keyResponsibilities.optionId.optionId}" />
</td>
</tbody>
</table>
</form>
SurveyData.java
#Entity
#Table(name = "survey_data")
public class SurveyData implements Serializable{
#Id
#Column(name = "some_id")
private Long someId;
#ElementCollection
#CollectionTable(name = "key_responsibilities", joinColumns = #JoinColumn(name = "data_id"))
private List<KeyResponsibilities> keyResponsibilities = new ArrayList<>();
public List<KeyResponsibilities> getKeyResponsibilities() {
return keyResponsibilities;
}
public void setKeyResponsibilities(List<KeyResponsibilities> keyResponsibilities) {
this.keyResponsibilities = keyResponsibilities;
}
}
KeyResponsibilities.java
#Embeddable
public class KeyResponsibilities {
#OneToOne
#JoinColumn(name = "option_id")
private OptionsMaster optionId;
#Column(name = "other")
private String other;
public OptionsMaster getOptionId() {
return optionId;
}
public void setOptionId(OptionsMaster optionId) {
this.optionId = optionId;
}
public String getOther() {
return other;
}
public void setOther(String other) {
this.other = other;
}
}
OptionsMaster.java
#Entity
#Table(name = "options_master")
public class OptionsMaster implements Comparable<OptionsMaster> {
private int optionId;
private String text;
#Id
#Column(name = "option_id")
public int getOptionId() {
return optionId;
}
public void setOptionId(int optionId) {
this.optionId = optionId;
}
#Basic
#Column(name = "text", length = -1)
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#Override
public int compareTo(OptionsMaster o) {
return Integer.compare(this.getOptionId(),o.getOptionId());
}
}

Thymeleaf inserting new item in database generates error Property or field cannot be found on null

I'm in the process of learning spring. I'm using thymeleaf to create a simple web app that adds, edits and removes users from a database.
I'm using an html page to display the database and two separate pages for editing and adding new users.
Edit and remove work perfectly but whenever i try to add a user i get an error in new.html (new.html contains the form to add a new user)
Property or field xxxx cannot be found on null
The error shows up in the from at th:text="#{user.name}" .From what I've found online thymelaf does not take null values, however as this is a new object I am trying to add all values are null.
Is there any way to solve this. Code.
new.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>New User</title>
</head>
<body>
<form method="post" name="comment_form" id="comment_form" th:action="#{/create}" role="form">
Name:<br>
<input type="text" name="name" th:text="${user.name}"><br>
Age:<br>
<input type="text" name="age" th:text="${user.age}"><br>
Email: <br>
<input type="text" name="email" th:text="${user.email}"><br>
<button type="submit" id="submit" class="btn btn-primary">Submit</button>
</form>
</body>
</html>
Controller
#Autowired
UserService service;
#RequestMapping(value="user/new", method = RequestMethod.GET)
public String newUser(Long id, Model md) {
Users user = service.findOne(id);
md.addAttribute("user", user);
return "new";
}
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String create(#RequestParam("id") Long id, #RequestParam("name") String name, #RequestParam("age") int age,
#RequestParam("email") String email, Model md) {
md.addAttribute("users", service.addOrUpdate(new Users(id, name, age)));
return "redirect:/user";
}
Service class
#Autowired
JdbcTemplate template;
public Users findOne(Long id)
{
String sql = "select * from people where id=" +id;
return template.query(sql, new ResultSetExtractor<Users>() {
#Override
public Users extractData(ResultSet resultSet) throws SQLException, DataAccessException {
if (resultSet.next()) {
Users user = new Users(resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getInt("age"));
String email = resultSet.getString("email");
if (email != null) {
user.setEmail(email);
}
return user;
}
return null;
}
});
}
public int addOrUpdate(Users user){
if (user.getId() > 0) {
String sql = "UPDATE people SET name=?, age =?, email=? WHERE id=" +user.getId();
System.out.println(sql);
return template.update(sql, user.getName(), user.getAge(), user.getEmail());
} else {
String sql = "INSERT INTO people ( name, age, email) VALUES ( ?, ?, ?)";
System.out.println(sql);
return template.update(sql, user.getName(), user.getAge(), user.getEmail());
}
}
Users (Model)
package ro.database.jdbcTest.model;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class Users {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Long id;
private String name;
private int age;
private String email;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public Users(Long id, String name, int age){
this.id=id;
this.name=name;
this.age=age;
}
public void setEmail(String email){
this.email=email;
}
}
Since your user object is null you are getting that error.
All you need to do is send a new User() object every time a request with a new user comes.
#RequestMapping(value="user/new", method = RequestMethod.GET)
public String newUser(Long id, Model md) {
Users user = null;
if(id > 0) { // Id is present, fetch from the database.
user = service.findOne(id);
} else { // Create a new user.
user = new User();
}
md.addAttribute("user", user);
return "new";
}
Using the above way you will never have a null user in new.html

PreSelect Value from Dropdown

I was able to populate my dropdown, however I cannot preselect the value of the dropdown base on the value coming from DB.
My Thymeleaf
<select id="inputstatus" name="status" th:field="*{status}" >
<option th:each="enumStatus : ${listStatus}"
th:value="${enumStatus.code}"
th:text="#{${enumStatus.value}}" />
</select>
My Controller:
#RequestMapping(value = "userdetails/{username}")
public String getAccounts(#PathVariable String username, Model model) {
Account accountDetail = rsAccountDetailsService.loadAccountByUserName(username);
model.addAttribute(ACCNTSEARCH_MODEL_ACCNTSTATUS_KEY, AccountDetailsStatus.values());
model.addAttribute("userdetailform",accountDetail);
return "account/userdetails";
}
My ENUM
public enum AccountDetailsStatus {
ACTIVE(0, "status.active"),
EXPIRED(2, "status.expired"),
LOCKED(3, "status.locked");
private int code;
private String value;
private final static class BootstrapSingleton {
public static final Map<String, AccountDetailsStatus> lookupByValue = new HashMap<String, AccountDetailsStatus>();
public static final Map<Integer, AccountDetailsStatus> lookupByCode = new HashMap<Integer, AccountDetailsStatus>();
}
AccountDetailsStatus(int code, String value) {
this.code = code;
this.value = value;
BootstrapSingleton.lookupByValue.put(value, this);
BootstrapSingleton.lookupByCode.put(new Integer(code), this);
}
public int getCode() {
return code;
}
public String getValue() {
return value;
}
}
If the user details were loaded with for example "ACTIVE" status, the active status in the dropdown is not selected.
I think your are looking for something similar use the th:selected tag
<option th:each="i : ${#numbers.sequence(0, 23)}" th:value="${i}" th:text="${i}" th:selected="${ i==9 } ">Options</option>
i linked some similar post here
http://forum.thymeleaf.org/th-selected-not-working-on-multiple-select-td4025883.html
th:selected a number in a select/option with Thymeleaf doesn't work

Form validation with spring mvc annotation

I got some trouble to get spring validation based on annotation form works.
i added this to my spring-servlet.xml
<context:component-scan base-package="com.it.controller" />
(package containing all my controller)
and
<context:component-scan base-package="com.it.form" />
(package containing all my form classes)
class email in package com.it.form :
public class email {
#NotEmpty
#Email
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public email() {
email = "";
// TODO Auto-generated constructor stub
}
}
Form :
<body>
<form:form method="post" action="" commandName='email'>
<div class="requestEmail">
<form:label path="email">Entrez votre email:</form:label>
<form:input path="email" />
<form:errors path="email" />
</div>
<div>
<input type="submit" value="VALIDER" />
</div>
</form:form>
Controller :
#Controller
#SessionAttributes
public class passwordController {
/*
* ##########################################################
*
* Print & valid form Email
*
* ##########################################################
*/
#RequestMapping(value = "/passwordChange.mvc", method = RequestMethod.GET)
public String get(final ModelMap model) {
email email= new email();
model.addAttribute("email", email);
return "passwordChangeRequestEmail"; // jsp form
}
#RequestMapping(value = "/passwordChange.mvc", method = RequestMethod.POST)
public String post(final ModelMap model,
#ModelAttribute("email") #Valid final email email,
final BindingResult result) {
if (result.hasErrors()) {
return "error";
}
return "success";
}
}
it seems when i submit my form i am always redirect to /success page, even if i leave email input blank...
Dunno if i missed something
Thanks in advance :)
You have to add
<mvc:annotation-driven />
to your servlet context file and to import a validator like Hibernate Validator in your classpath.

Resources