Spring mvc form:select path is custom map in model attribute - spring-mvc

How to bind a map property of the model and send the selected value back to the controller?
i am able to populate the drop down but on submitting the form getting error 400 - bad request.
MyModel.java:
public class MyModel{
private Map<MySubModel, String> subModel = new HashMap<MySubModel, String>();
private SubModel subModelSearched;
}
SubModel.java:
public class SubModel{
public String id;
public String name;
}
JSP:
<form:form action="/mySearch" modelAttribute="myModel" method="post">
<form:select path="subModelSearched">
<form:options items="${myModel.subModel}/>
</form:select>
.....
</form:form>

Related

Getting null values in Spring MVC controller when submitting data from the jsp

I have a jsp form with an input box, a domain object with get/set methods, and a controller. When I submit the form I get null values in the controller. The "set" method is never being called in the domain object when i submit the form but the object itself is being called.
Order.jsp
<portlet:defineObjects />
<portlet:actionURL portletMode="view" var="createNewOrderURL">
<portlet:param name="action" value="createNewOrder" />
</portlet:actionURL>
<div>
<form:form name="form" method="post" commandName="refOrder" action="${createNewOrderURL}" id="createOrder">
TestName : ${refOrder.name}<br/> <!-- here I get the correct value to display -->
<form:input path="referenceNum" />
<input type="submit" value="Submit" />
</form:form>
</div>
Order.java
public class Order {
private String name = "Name1";
private String referenceNum;
public Order(){
System.out.println("Inside Order.java");
System.out.println(getReferenceNum());
}
public Order(String name, String referenceNum) {
this.name = name;
this.referenceNum = referenceNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReferenceNum() {
return referenceNum;
}
public void setReferenceNum(String referenceNum) {
this.referenceNum = referenceNum;
}
SalesOrderController.java
#RenderMapping
public String defaultRender(RenderRequest request, RenderResponse response, Model model) throws SQLException, NamingException{
model.addAttribute("refOrder",new Order());
return "SalesOrderEntry";
}
#ActionMapping(params={"action=createNewOrder"})
public void addNewOrder(ActionRequest request, ActionResponse response, #ModelAttribute("refOrder") Order order)throws NamingException, SQLException{
System.out.println("Inside addNewOrder method");
System.out.println("New Order is --> "+order.toString());
System.out.println("RefNum - "+order.getReferenceNum());
System.out.println("request.getParameter is "+request.getParameter("referenceNum"));
}
I get null for all the print statements in the controller. Have been trying to fix this for two days now and I can't find what's wrong. Would really appreciate if someone can help me get this to work.
Do you have the following in your src/main/webapp/WEB-INF/liferay-portlet.xml descriptor?
<requires-namespaced-parameters>false</requires-namespaced-parameters>
Also, you might want to take a look at the PortletMVC4Spring project, which is the successor to Spring Portlet MVC. The GitHub project contains archetypes that work in Apache Pluto and Liferay Portal. The requires-namespaced-parameters config option is conveniently set in the archetypes.

I want to display data from a list with thymeleaf

I want to display data from a list with thymeleaf
My class user
public class user {
#Id #GeneratedValue
private Long id ;
private String name;
...Getter and setter ...
My controller
private List<user> userList=new ArrayList<user>();
user u1=new user("John");
user u2=new user("Lionel");
userList.add(u1);
userList.add(u2);
#RequestMapping("/listRappel")
public String listRp(Model model){
model.addAttribute("user",userList);
return "UserView" ;
}
My view thymeleaf
<table>
<tr th:each="t:${user}">
<td th:text="${t.name}"></td></tr>
<tabel/>
But when I run it I get the error: "Exception evaluating SpringEL expression: "t.name" "
Can you try using ModelMap argument instead of Model in the method listRp?
method would be:
public String listRp(ModelMap model)

Validating a form if we have two model object data

Usually i have seen a server side validation in spring mvc like this for example there is customer page which contains customer related information like customerName ,customerAddress,customerPhoneNumber for this we going to have
customer model object then in the spring controller we are going to call like this
Spring Controller
#RequestMapping(value = "/customerRegistrationScreen")
public String customerRegistrationScreen(Model model) {
Customer customer= new Customer();
model.addAttribute("customer", customer);
return "customerRegistrationScreen";
}
#RequestMapping(value = "/doCustomerRegistration", method = RequestMethod.POST)
public ModelAndView registerCustomer(#ModelAttribute("customer") #Validated Customer customer, BindingResult result,Model model) {
if (result.hasErrors()) {
} else {
}
}
CustomerValidator class
#Component
public class CustomerValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return Customer.class.equals(clazz);
}
#Override
public void validate(Object obj, Errors err) {
ValidationUtils.rejectIfEmpty(err, "name", "customer.name.empty");
ValidationUtils.rejectIfEmpty(err, "email", "customer.email.empty");
ValidationUtils.rejectIfEmpty(err, "gender", "customer.gender.empty");
ValidationUtils.rejectIfEmpty(err, "languages", "customer.languages.empty");
User user = (User) obj;
Pattern pattern = Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
if (!(pattern.matcher(customer.getEmail()).matches())) {
err.rejectValue("email", "user.email.invalid");
}
}
}
customerRegistration.jsp
<form:form method="post" modelAttribute="customer" action="doCustomerRegistration">
</form:form>
what if the jsp have two model object information like Customer and product information like customerName,customerAddress,customerPhoneNumber,productID,productName,productPrice here i like to have two model object like customer
& Product if i have two model object how can i map model attribute from jsp and Spring contoller and how can i do server side validation for both the validation
Although it is a good idea to keep models separate in each form, but for this particular use case it can be achieved by following below steps.
The best way to achieve this is to wrap both the Model attributes in one wrapper class and use it in validation.
Lets say Product class looks like this.
public class Product{
String productName;
// other fields and their getter setters
}
Create a wrapper class which wraps both models Customer and Product
public class CustomerProductWrapper {
private Customer customer;
private Product product;
//getter setter
}
In your validator class , change the implementation of supports() method as below
#Override
public boolean supports(Class clazz) {
return CustomerProductWrapper .class.equals(clazz);
}
2.1 Change the implementation of Validation Method as below
#Override
public void validate(Object obj, Errors err) {
//The object that you get now is CustomerProductWrapper object
// refer the fields using this object
ValidationUtils.rejectIfEmpty(err, "customer.name", "customer.name.empty");
ValidationUtils.rejectIfEmpty(err, "customer.email", "customer.email.empty");
ValidationUtils.rejectIfEmpty(err, "customer.gender", "customer.gender.empty");
ValidationUtils.rejectIfEmpty(err, "customer.languages", "customer.languages.empty");
CustomerProductWrapper cpw= (CustomerProductWrapper ) obj;
Pattern pattern = Pattern.compile("^[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,6}$",
Pattern.CASE_INSENSITIVE);
if (!(pattern.matcher(cpw.getCustomer().getEmail()).matches())) {
err.rejectValue("customer.email", "user.email.invalid");
}
//validate a Product field
ValidationUtils.rejectIfEmpty(err, "product.productName", "product.name.empty");
}
In your controller mapping ,
public String customerRegistrationScreen(Model model) {
CustomerProductWrapper cpw= new CustomerProductWrapper ();
model.addAttribute("cpw", cpw);
return "customerRegistrationScreen";
}
And
#RequestMapping(value = "/doCustomerRegistration", method = RequestMethod.POST)
public ModelAndView registerCustomer(#ModelAttribute("cpw") #Validated CustomerProductWrapper cpw, BindingResult result,Model model) {
if (result.hasErrors()) {
} else {
}
}
And finally in your view page
<form:form method="post" modelAttribute="cpw" action="doCustomerRegistration">
</form:form>
Also refer fields using cpw's attributes that is
<form:input path="name" />
<form:errors path="name" cssClass="error" />
will change to
<form:input path="customer.name" />
<form:errors path="customer.name" cssClass="error" />
Similarly for product validation you can use
<form:input path="product.productName" />
<form:errors path="product.productName" cssClass="error" />
That's all.

Mapping Multiple Controllers in Spring MVC

Define two controllers user and data as follows:
// 1st Controller
#Controller
#RequestMapping(value = {"/", "user"})
public class UserLoginController {
#Autowired
private UserLoginService userLoginService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String showLoginForm(#ModelAttribute UserLogin userLogin) {
//model.addAttribute(new UserLogin());
//System.out.println("showLoginForm() is called");
return "loginForm";
}
}
//Second COntroller
#Controller
#RequestMapping(value = "user/data/")
public class WorkplanController {
#Autowired
private WorkplanService WorkplanService;
#RequestMapping(value = "importForm", method = RequestMethod.GET)
public ModelAndView importForm(#ModelAttribute SheetUpload sheetUpload){
return new ModelAndView("uploadWorkplan");
}
#RequestMapping(value= "doUpload", method = RequestMethod.POST)
public ModelAndView doUpload(#RequestParam CommonsMultipartFile[] uploadFile, SheetUpload fileUpload, Workplan workplan, HttpServletRequest request) {
return new ModelAndView("uploadSucess");
}
}
When i make request to the doUpload(), it shows HTTP Status 400 Error.
My question is two-fold:
1. Why do have i have to include the user like this: #RequestMapping(value = "user/data/") to make request to the 2nd controller why not like this #RequestMapping(value = "data/")?
2. What do i need to change to make a successful call to the 2nd method in the second controller?
Here is the form am trying to submit:
<form:form action="doUpload" modelAttribute="sheetUpload" method="post"
enctype="multipart/form-data">
<form:select class="createusers_select_menu" path="From">
<form:option value="">Select...</form:option>
<form:option value="A">A</form:option>
<form:option value="B">B</form:option>
<form:option value="C">C</form:option>
</form:select>
<form:input class="browse_btn" path="uploadFile" type="file" />
<input type="submit" class="selct_workplan_2_btn" name="" value=" "/>
</form:form>
Why do have i have to include the user like this: #RequestMapping(value = "user/data/") to make request to the 2nd controller why not like this #RequestMapping(value = "data/")?
You don't have to. Change it to #RequestMapping(value="/data")
What do i need to change to make a successful call to the 2nd method in the second controller?
Try to get it working with a single file field only, then report back. There are lots of tutorials on the web to show how to upload files with Spring.

spring mvc multiple value selection drop down. The values being the domain objects. How to implement this

The below code is for single value selection which is working absolutely fine. But when I add attribue multiple="true" to form:select tag, then country object parameter in save() method is having null value when I select multiple value in Jsp. What will be the change that I have to do in jsp so that I can get the list of country objects in controller method. Please advise.
JSP Code
<form:form modelAttribute="country">
<li>
<form:label cssClass="mandatory" path="state">Select State</form:label>
<form:select path="state" cssErrorClass="error">
<form:option value="" label="Please Select..." />
<!-- Collection<State> listOfStates; This value holds the list of State objects by using controller method.-->
<c:forEach items="${listOfStates}" var="s">
<form:option value="${s.stateUniqueCode}" label="${s.stateName}"/>
</c:forEach>
</form:select>
</li>
</form>
Controller method
#RequestMapping(params = "_save", method = RequestMethod.POST)
public ModelAndView save(#ModelAttribute("country") Country country, BindingResult result, SessionStatus status) {
//some busines logic....
return new ModelAndView(mavString.toString());
}
Country and state classes
_________________________
/** Country object**/
public class Country{
private State state;
//getter and setters
}
/** State object**/
public class State{
private long stateUniqueCode;
private String stateName;
//getter and setters
}
If I convert country variable to List country in Country class. How should be the jsp and controller method be changed.
As per given jsp your model(Java classes of Country and state should be as follows)
public class Country{
private List<State> stateList;
//getter and setters
}
/** State object**/
public class State{
private long stateUniqueCode;
private String stateName;
//getter and setters
}
and you should bind stateList attribute in your path as follows.
<form:form modelAttribute="country">
<li>
<form:label cssClass="mandatory" path="stateList">Select State</form:label>
<form:select path="stateList" cssErrorClass="error">
<form:option value="" label="Please Select..." />
<c:forEach items="${listOfStates}" var="s">
<form:option value="${s.stateUniqueCode}" label="${s.stateName}"/>
</c:forEach>
</form:select>
</li>

Resources