I have a pretty nasty and frustrating problem with a Maven Web Application, holding me back for some time.
Apparently, from my previous google searches, this is a common Spring MVC error, but i am not able to find the solution i need among the ones offered on the internet so far. Note that i am a beginner in Spring and in MVC concepts in general.
I have a web application which is supposed to manage a building administration (inhabitants, rent calculations, etc). I use Spring MVC, Hibernate, Java 1.8, Tomcat 8 server container, and SQL Server 2014.
Firstly, this is my POJO for the bulding residents, a type called Inhabitant:
#Entity
#Table (name = "INHABITANT")
public class Inhabitant {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "ID")
private long id;
#Column(name = "FIRSTNAME")
private String firstName;
#Column(name = "LASTNAME")
private String lastName;
#Column(name = "APARTAMENT_NUMBER")
private String apartamentNumber;
#Column(name = "APARTAMENT_OWNER")
private String apartamentOwner;
#Column(name = "TELEPHONE_NUMBER")
private String telephoneNumber;
#Column(name = "EMAIL_ADDRESS")
private String emailAddress;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getApartamentNumber() {
return apartamentNumber;
}
public void setApartamentNumber(String apartamentNumber) {
this.apartamentNumber = apartamentNumber;
}
public String getApartamentOwner() {
return apartamentOwner;
}
public void setApartamentOwner(String apartamentOwner) {
this.apartamentOwner = apartamentOwner;
}
public String getTelephoneNumber() {
return telephoneNumber;
}
public void setTelephoneNumber(String telephoneNumber) {
this.telephoneNumber = telephoneNumber;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
This is my dispatcher-servlet.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="laura.bachelordegree.controller" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
This is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"> <!-- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1" -->
<display-name>BuildingAdministration</display-name>
<welcome-file-list>
<welcome-file>login/index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
This is my jsp registration form, which should map to the Inhabitant object:
<!DOCTYPE html>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%#taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%#page session="false" %>
<html>
<head>
<meta charset="utf-8" />
<title>Registration</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="login/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="login/font-awesome/css/font-awesome.min.css" />
<script type="text/javascript" src="login/js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="login/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<!-- Registration form - START -->
<div class="container">
<div class="row">
<%-- <form role="form"> --%>
<form:form method="post" modelAttribute="inhabitant" role="form" action="BuildingAdministration/src/main/webapp/login/result">
<div class="col-lg-6">
<div class="well well-sm"><strong><span class="glyphicon glyphicon-asterisk"></span>Required Field</strong></div>
<div class="form-group">
<label for="InputFirstName">Enter First Name</label>
<div class="input-group">
<form:input path="firstName" type="text" cssClass="form-control" id="InputFirstName" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputLastName">Enter Last Name</label>
<div class="input-group">
<form:input path="lastName" type="text" cssClass="form-control" id="InputLastName" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputApartmentNumber">Enter Apartment Number</label>
<div class="input-group">
<form:input path="apartmentNumber" type="text" cssClass="form-control" id="InputApartmentNumber" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputApartmentOwner">Enter Apartment Owner</label>
<div class="input-group">
<form:input path="apartmentOwner" type="text" cssClass="form-control" id="InputApartmentOwner" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputTelephoneNumber">Enter Telephone Number</label>
<div class="input-group">
<form:input path="telephoneNumber" type="text" cssClass="form-control" id="InputTelephoneNumber" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputEmail">Enter Email</label>
<div class="input-group">
<form:input path="emailAddress" type="email" cssClass="form-control" id="InputEmailFirst" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<div class="form-group">
<label for="InputEmail">Confirm Email</label>
<div class="input-group">
<form:input path="emailAddress" type="email" cssClass="form-control" id="InputEmailSecond" />
<span class="input-group-addon"><span class="glyphicon glyphicon-asterisk"></span></span>
</div>
</div>
<input type="submit" name="submit" id="submit" value="Submit" class="btn btn-info pull-right">
</div>
</form:form>
<%-- </form> --%>
<div class="col-lg-5 col-md-push-1">
<div class="col-md-12">
<div class="alert alert-success">
<strong><span class="glyphicon glyphicon-ok"></span> Success! Message sent.</strong>
</div>
<div class="alert alert-danger">
<span class="glyphicon glyphicon-remove"></span><strong> Error! Please check all page inputs.</strong>
</div>
</div>
</div>
</div>
</div>
<!-- Registration form - END -->
</body>
</html>
And finally, the controller class, which should effectively map the data from the jsp form with the java entity, Inhabitant:
#RequestMapping(value = "/index", method = RequestMethod.GET)
public String loadInhabitant(#ModelAttribute("inhabitant")Inhabitant inhabitant,
ModelMap model) {
model.addAttribute("firstName", inhabitant.getFirstName());
model.addAttribute("lastName", inhabitant.getLastName());
model.addAttribute("apartmentNumber", inhabitant.getApartamentNumber());
model.addAttribute("apartmentOwner", inhabitant.getApartamentOwner());
model.addAttribute("apartmentNumber", inhabitant.getApartamentNumber());
model.addAttribute("telephoneNumber", inhabitant.getTelephoneNumber());
model.addAttribute("emailAddress", inhabitant.getEmailAddress());
return "result";
}
Now, this is the error i get whenever i try to run my application on the server:
message java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'inhabitant' available as request attribute
description The server encountered an internal error that prevented it from fulfilling this request.
exception org.apache.jasper.JasperException:
java.lang.IllegalStateException: Neither BindingResult nor plain
target object for bean name 'inhabitant' available as request
attribute
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:555)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:471)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause java.lang.IllegalStateException: Neither BindingResult nor
plain target object for bean name 'inhabitant' available as request
attribute
org.springframework.web.servlet.support.BindStatus.(BindStatus.java:144)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:117)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
org.apache.jsp.login.index_jsp._jspx_meth_form_005finput_005f0(index_jsp.java:322)
org.apache.jsp.login.index_jsp._jspx_meth_form_005fform_005f0(index_jsp.java:216)
org.apache.jsp.login.index_jsp._jspService(index_jsp.java:148)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
I have tried a thousand things, but i just can't get it to work. So, please, can someone point out what i'm doing wrong? How can i correctly build the java object based on the information from the jsp form?
Thanks in advance!
It seems you need to understand more about spring mvc.
You are mapping your form request to a view. you must map your form request to a controller method not a view, your form should look like this :
<form:form action="${pageContext.request.contextPath}/inhabitant/create" method="post" modelAttribute="inhabitant" >
....
// have a look at spring form validation
// have a look at spring form elements eg. how error messages are displayed
</form:form>
You need two methods in controller to create and save inhabitant one for showing a form and another for saving form datas into database. Now your controller should look like this :
#Controller
#RequestMapping(value="/inhabitant")
public class PostController {
#Autowired
private InhabitantService inhabitantService;
//Method that displays the form page
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String createForm(Model model ) {
model.addAttribute("inhabitant", new Inhabitant()); // identifier should be same as modelattribute in your form "inhabitant"
return "formpage"; // your form page name
}
// Method which will have the submitted data
// Validation is also done in this method
#RequestMapping(value="/create", method=RequestMethod.POST)
public String saveForm( #ModelAttribute("inhabitant") #Valid Inhabitant inhabitant, //#valid is used for validation use it If you are doing validation
BindingResult result // use only if you are doing validation)
{
// use only If you are doing validation
// If validation fails users must return to the same form view
if (result.hasErrors()){
return "formpage";
}
//and save the submitted form data
inahabitantService.saveInhabitant(inhabitant);
enter code here
return "success"; // success.jsp is a success page that you will see after creating a inhabitant
}
Do not use '/login' as a url patern in your web.xml Just dont do it.
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/login</url-pattern> //Just Use '/' instead of '/login'
</servlet-mapping>
I doubt that you have configured hibernate properly Post your hibernateConfiguration.xml file and persistence.xml file.
You must learn and understand these: Just take your time.
Spring Model Controller View and how does it really work
Spring Form elements, Spring Form Validation
Jpa / hibernate basics / association in hibernate
Jsp taglibs / JSP inside Jsp / Apache Tiles
Don't do that
model.addAttribute("firstName", inhabitant.getFirstName());
model.addAttribute("lastName", inhabitant.getLastName());
model.addAttribute("apartmentNumber", inhabitant.getApartamentNumber());
model.addAttribute("apartmentOwner", inhabitant.getApartamentOwner());
model.addAttribute("apartmentNumber", inhabitant.getApartamentNumber());
model.addAttribute("telephoneNumber", inhabitant.getTelephoneNumber());
model.addAttribute("emailAddress", inhabitant.getEmailAddress());
Do this instead
model.addAttribute("inhabitant", inhabitant);
Related
I have a form for adding products written in HTML and thymeleaf.
<form th:action="#{/products/get}" th:object="${form}" method="post">
<div id="fields">
<label for="name"></label><input type="text" id="name" name="name" autofocus="autofocus" placeholder="NAME" required/><br>
<label for="label"></label><input type="text" id="label" name="label" autofocus="autofocus" placeholder="LABEL" required/><br>
Below the form, there is a button that adds two input fields to the form every time it's pressed. New input fields are the same as those two input fields above. The idea is that the user can enter data for as many products as he wants using the same form. For example, after pressing the button once the form will look like that:
<form th:action="#{/products/get}" th:object="${form}" method="post">
<div id="fields">
<label for="name"></label><input type="text" id="name" name="name" autofocus="autofocus" placeholder="NAME" required/><br>
<label for="label"></label><input type="text" id="label" name="label" autofocus="autofocus" placeholder="LABEL" required/><br>
<label for="name"></label><input type="text" id="name" name="name" autofocus="autofocus" placeholder="NAME" required/><br>
<label for="label"></label><input type="text" id="label" name="label" autofocus="autofocus" placeholder="LABEL" required/><br>
The thing is I'd like to create ArrayList of class ProductForm using the values from input fields and then pass it to my controller using #ModelAttribute.
public class ProductForm{
private String name;
private String label;
//getters and setters
}
Then created a class that wraps ProductForm into ArrayList
public class ProductFormArray {
ArrayList<ProductForm> forms;
//getters and setters
}
And a Controller
#Controller
#RequestMapping(value = "/products")
public class CreateAccountControllerTemporary {
#RequestMapping(value = "/get", method = RequestMethod.POST)
public String createAccount(#ModelAttribute(name = "form")ProductFormArray form){
//some code
}}
My problem is that I can't figure out how to add objects to form ArrayList using values from input fields? Is that even possible? How should I change my HTML file?
It is certainly possible, I explain this on pages 361 to 389 in my book Taming Thymeleaf.
You can check out the sources of the book for free at https://github.com/wimdeblauwe/taming-thymeleaf-sources/tree/main/chapter16
It is hard to summarize 30 pages into a stackoverflow answer, but briefly, check out:
CreateTeamFormData.java: This is similar to your ProductFormArray class. I do use an array instead of an ArrayList.
public class CreateTeamFormData {
#NotBlank
#Size(max = 100)
private String name;
#NotNull
private UserId coachId;
#NotNull
#Size(min = 1)
#Valid
private TeamPlayerFormData[] players;
TeamPlayerFormData.java: This is similar to your ProductForm class.
public class TeamPlayerFormData {
#NotNull
private UserId playerId;
#NotNull
private PlayerPosition position;
TeamController.java: This the controller that uses the CreateTeamFormData.
#GetMapping("/create")
#Secured("ROLE_ADMIN")
public String createTeamForm(Model model) {
model.addAttribute("team", new CreateTeamFormData());
model.addAttribute("users", userService.getAllUsersNameAndId());
model.addAttribute("positions", PlayerPosition.values()); //<.>
return "teams/edit";
}
#PostMapping("/create")
#Secured("ROLE_ADMIN")
public String doCreateTeam(#Valid #ModelAttribute("team") CreateTeamFormData formData,
BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("editMode", EditMode.CREATE);
model.addAttribute("users", userService.getAllUsersNameAndId());
model.addAttribute("positions", PlayerPosition.values());
return "teams/edit";
}
service.createTeam(formData.toParameters());
return "redirect:/teams";
}
edit.html -> This is the Thymeleaf template. Note that I am using a Thymeleaf fragment edit-teamplayer-fragment for the part of the form that repeats itself (So the name and label fields in your case)
<h3>Players</h3>
<div class="col-span-6 ml-4">
<div id="teamplayer-forms"
th:data-teamplayers-count="${team.players.length}"> <!--.-->
<th:block th:each="player, iter : ${team.players}">
<div th:replace="teams/edit-teamplayer-fragment :: teamplayer-form(index=${iter.index}, teamObjectName='team')"></div>
<!--.-->
</th:block>
</div>
<div class="mt-4">
<a href="#"
class="py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800"
id="add-extra-teamplayer-form-button"
th:text="#{team.player.add.extra}"
#click="addExtraTeamPlayerForm()"
></a> <!--.-->
</div>
</div>
edit-teamplayer-fragment.html: Here is the important part where you need to keep track of the index for each fragment:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
lang="en">
<!-- tag::main[] -->
<div th:fragment="teamplayer-form"
class="col-span-6 flex items-stretch"
th:id="${'teamplayer-form-section-' + __${index}__}"
th:object="${__${teamObjectName}__}"> <!--.-->
<!-- end::main[] -->
<div class="grid grid-cols-1 row-gap-6 col-gap-4 sm:grid-cols-6">
<div class="sm:col-span-2">
<div class="mt-1 rounded-md shadow-sm">
<select class="form-select block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
th:field="*{players[__${index}__].playerId}">
<option th:each="user : ${users}"
th:text="${user.userName.fullName}"
th:value="${user.id.asString()}">
</select>
</div>
</div>
<div class="sm:col-span-2">
<div class="mt-1 rounded-md shadow-sm">
<select class="form-select block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"
th:field="*{players[__${index}__].position}">
<option th:each="position : ${positions}"
th:text="#{'PlayerPosition.' + ${position}}"
th:value="${position}">
</select>
</div>
</div>
<!-- tag::delete[] -->
<div class="ml-1 sm:col-span-2 flex items-center text-green-600 hover:text-green-900">
<div class="h-6 w-6">
<svg th:replace="trash"></svg>
</div>
<a href="#"
class="ml-1"
th:text="#{team.player.remove}"
x-data
th:attr="data-formindex=__${index}__"
#click="removeTeamPlayerForm($el.dataset.formindex)"> <!--.-->
</a>
</div>
<!-- end::delete[] -->
</div>
</div>
</html>
I am working on a Spring web project , I have many JSP files and many controllers , but I am not able to grab how this
<form:form action="updateCustomer" autocomplete="true" commandName="customer">
form is automatically mapped to the respective controller in which the updateCustomer is defined. There are other controllers also but how exactly the url updateCustomer goes to respective controller.
The Customer.jsp file is as follows :
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html lang="en">
<head>
<link
href="${pageContext.request.contextPath}/static/css/bootstrap-nav-wizard.css"
rel="stylesheet">
<link
href="${pageContext.request.contextPath}/static/css/intlTelInput.css"
rel="stylesheet">
<style>
ul.nav-wizard li a i {
margin-right: 15px;
}
</style>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="${pageContext.request.contextPath}/static/js/flickity.pkgd.min.js"></script>
<script src="${pageContext.request.contextPath}/static/js/jquery.fancybox.pack.js"></script>
<script src="${pageContext.request.contextPath}/static/js/waypoints.min.js"></script>
<script src="${pageContext.request.contextPath}/static/js/custom/customer.js"></script>
<script src="${pageContext.request.contextPath}/static/js/jqueryform-validator.js"></script>
<script src="${pageContext.request.contextPath}/static/js/custom/common.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/intlTelInput.min.js"></script>
</head>
<body>
<form:form action="updateCustomer" autocomplete="true" commandName="customer">
<form:hidden path="buyerId"/>
<form:hidden path="user.userId" />
<section>
<div class="container" style="margin-top: 10px;">
<div class="row">
<h3 class="main-title">My Profile</h3>
</div>
<div class="row">
<div>
<!-- Main Content Start -->
<div id="myTabContent" class="tab-content">
<!-- Step 1 Content Start -->
<div class="tab-pane fade active in" id="step1">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Personal Details</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12 col-sm-4 form-group">
<label>First Name</label><span class="req">*</span>
<form:input class="form-control" path="user.firstName"
type="text" maxlength="75"
/>
</div>
<div class="col-xs-12 col-sm-4 form-group">
<label>Middle Name</label>
<form:input class="form-control" path="user.middleName" maxlength="75"
type="text" />
</div>
<div class="col-xs-12 col-sm-4 form-group">
<label>Last Name</label><span class="req">*</span>
<form:input class="form-control" path="user.lastName"
type="text" maxlength="75"
/>
</div>
</div>
</div><!--//panel body over -->
</div><!--//panel panel default over -->
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Company Details</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-xs-12 col-sm-6 form-group">
<label>Company Name</label><span class="req">*</span>
<form:input path="companyName" class="form-control"
type="text"
maxlength="45"
/>
</div>
</div>
</div>
</div>
</div>
<div class="row" style="display: none;" id="mainBtn">
<div class="col-xs-6 col-sm-2 pull-right" style="min-width: 170px;">
<button class="btn" type="submit" name="action" value="2" style= "min-width: 170px;">Save & Continue</button>
</div>
<div class="col-xs-6 col-sm-2 pull-right" style="text-align: right; padding-right:0px;"> <!-- added property padding-right:0px; to style on 17/7 -->
<button class="btn" type="submit" name="action" value="1" style= "min-width: 170px;">Save</button>
</div>
</div>
<div class="row" id="editBtn">
<div class="col-xs-6 col-sm-2 pull-right">
<a class="btn pull-right" id="edit"
href="#" onclick="makeEditable()" style="min-width: 170px;">Edit</a>
</div>
</div>
<br> <br>
</div>
<!-- Step 1 Content End -->
</div>
<!-- Main Content End -->
</div>
</div>
</div>
<!-- /container -->
</section>
</form:form>
</body>
</html>
The controller File is as follows :
package com.htss.web.controller;
//assume all imports
#Controller
#RequestMapping("/buyer")
public class BuyerController {
#Autowired
private BuyerService customerService;
#Autowired
private UserService userService;
#Autowired
private CommonService commonService;
#Autowired
private MessageSource messageSource;
#RequestMapping(value = "/open/customer")
public String customerInfo() {
return "customer";
}
#RequestMapping(value = "/edit_profile")
public String editCustomerProfile(HttpSession session, Model model) {
Integer buyerId = (Integer) session.getAttribute("entityId");
BuyerFormBean bean = customerService.retrieveCustomer(buyerId);
Long userId = (Long) session.getAttribute("userId");
try {
UserFormBean user = userService.getUser(userId);
bean.setUser(user);
} catch (IllegalAccessException | InvocationTargetException e) {
}
model.addAttribute("customer", bean);
model.addAttribute("countries", commonService.getCountryDropdown());
model.addAttribute("action", "updateCustomer");
return "buyerProfile";
}
#RequestMapping(value = "/updateCustomer")
public String updateCustomerProfile(Model model, HttpSession session, BuyerFormBean customer) {
try {
if (action == 1 || action == 2) {
customer = customerService.modifyCustomer(customer);
}
}
catch (Exception e) {
e.printStackTrace();
model.addAttribute("error",messageSource.getMessage("msg.Error",null,Locale.US));
}
Integer buyerId = (Integer) session.getAttribute("entityId");
BuyerFormBean bean = customerService.retrieveCustomer(buyerId);
Long userId = (Long) session.getAttribute("userId");
try {
UserFormBean user = userService.getUser(userId);
bean.setUser(user);
} catch (IllegalAccessException | InvocationTargetException e) {
}
model.addAttribute("customer", bean);
model.addAttribute("message",messageSource.getMessage("msg.Success",null,Locale.US));
return "Customer";
}
}
Now the question is when I click save button the url formed is :
http://localhost:8080/82ism/buyer/updateCustomer
How this happened ? and now when I need a button to some other controller I need to give the whole URL as follows :
${pageContext.request.contextPath}/seller/edit_profile
The project is working all fine I am just trying to understand this concept.
The whole point of spring is so you don't have to worry about that stuff.
jsp's get found cause of the propperty's in application.propperties:
like:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
For the forms and methods... It's not like it magicly happens.
A form you have to cal by name and methods are eighter mapped to a url or action
like:
#RequestMapping("/")
or
#RequestMapping(method=RequestMethod.POST)
To call the values of a form from the controller you first have to bind them to a entity model with the fields of the form as variables.
The method would look like:
#RequestMapping(method = RequestMethod.POST)
public String processRegister(#ModelAttribute("userForm") User user,
Map<String, Object> model) {
...
return "view";
}
I am using Spring security configurations for login authentication in order to check for the valid credentials. How can I redirect the application to my custom login page. I tried to implement form-login as shown below, but it did not work for me, Please help me to resolve this.
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http auto-config='true'>
<intercept-url pattern="/secured/*" access="ROLE_USER" />
<form-login
login-page='/login'
default-target-url="/home"
authentication-failure-url="/error" />
<logout logout-success-url="/logout" />
</http>
<authentication-manager>
<authentication-provider ref="customAuthenticationProvider"/>
</authentication-manager>
</beans:beans>
In the above code, login, logout, error and home are my custom pages.
Following is my controller code.
#Controller
public class LoginController {
#RequestMapping(value="/", method=RequestMethod.GET)
public String dashboard(){
System.out.println("Dashboard method of Login Controller");
return "dashboard";
}
#RequestMapping(value="/login", method=RequestMethod.GET)
public String getLoginForm(){
System.out.println("Login method of Login Controller");
return "login";
}
#RequestMapping(value="/logout", method=RequestMethod.GET)
public String getLogoutForm(){
System.out.println("Logout method of Login Controller");
return "logout";
}
#RequestMapping(value="/error", method=RequestMethod.GET)
public String loginAgain(){
// ModelAndView model = new ModelAndView("Login");
System.out.println("error method of Login Controller");
return "error";
}
#RequestMapping(value="/secured/test", method=RequestMethod.GET)
public String getData(ModelMap model){
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
System.out.println("Returned .... "+principal);
System.out.println("Returned object name is :: "+principal.toString());
model.addAttribute("username", "John");
model.addAttribute("message", "Welcome to the secured page");
return "home";
}
Following is the login page.
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<!DOCTYPE Html>
<html lang="en">
<title>Aventyn®| Login</title>
<head>
<link type="text/css" rel="stylesheet" href='<spring:url value="/resources/css/bootstrap.min.css" />' >
<link type="text/css" rel="stylesheet" href='<spring:url value="/resources/css/loginCSS.css" />'>
</head>
<body>
<div class="container-fluid">
<form action="http://localhost:8080/LoginMavenSpringMVC/secured/test" method="get">
<div class="row margin_Div">
<div class="col-sm-12">
<div class="panel panel-primary">
<div class="panel-heading">
<h2 class="panel-title text-center"><strong>Login Page</strong></h2>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-3 col-md-2">
<b>Login Id:</b>
</div>
<div class="col-sm-4 col-md-3">
<div class="input-group">
<span class="input-group-addon">*</span>
<input type="text" class="form-control input-sm" placeholder="LoginId" name="UserName">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-md-2">
<b>Password:</b>
</div>
<div class="col-sm-4 col-md-3">
<div class="input-group">
<span class="input-group-addon">*</span>
<input type="text" class="form-control input-sm" placeholder="Password" name="Password">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-3 col-md-2"></div>
<div class="col-sm-4 col-md-3">
<button class="form-control btn-sm btn-primary" type="submit">Login</button>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<p>${SucessMsg}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</body>
<script type="text/javascript" src='<spring:url value=" /resources/js/jquery.min.js"/>'></script>
<script type="text/javascript" src=' <spring:url value="/resources/js/bootstrap.min.js"/>'></script>
</html>
I need some help. I have a trouble working on my pet project. It's simple crud app based on spring mvc. The trouble is that I can't get error messages when input validation fails in my profile.jsp. I have mostly the same code in my signup.jsp but there all works fine.
There is my controller methods:
#RequestMapping(value = "/profile", method = RequestMethod.GET)
public String getUserProfile(Model model) {
model.addAttribute("userDetailsForm", new UserDetailsFormDTO());
model.addAttribute("passwordForm" ,new PasswordFormDTO());
model.addAttribute("profile", getCurrentUser());
return "profile";
}
#RequestMapping(value = "/profile/details/change", method = RequestMethod.POST)
public String changeUserDetails(#ModelAttribute("userDetailsForm") #Valid UserDetailsFormDTO form,
BindingResult result) {
if(result.hasErrors()){
result.getAllErrors().forEach(log::debug);
return "redirect:/profile";
}
userService.changeUserDetails(getCurrentUser(), form);
return "redirect:/profile?success=details";
}
I'm using JSR 303 Validation:
package org.crud.dto;
import java.io.Serializable;
import javax.validation.constraints.Pattern;
import org.crud.validation.InputValidator;
import org.hibernate.validator.constraints.NotEmpty;
public class UserDetailsFormDTO implements Serializable{
private static final long serialVersionUID = -7603395840362468805L;
#NotEmpty(message="{error.null_form_value}")
#Pattern(regexp=InputValidator.FIRSTNAME_PATTERN, message="{error.name_invalid}")
private String firstName;
#NotEmpty(message="{error.null_form_value}")
#Pattern(regexp=InputValidator.LASTNAME_PATTERN, message="{error.name_invalid}")
private String lastName;
public UserDetailsFormDTO() {}
public UserDetailsFormDTO(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
In configuration files I have next beans declared:
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"
p:validationMessageSource-ref="messageSource" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
Also have two .properties files with my labels and error codes on my classpath: messages_ru and messages_en.
My profile.jsp code fragment:
<div id="user-details-upd" class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title">Update user details</h3>
</div>
<div class="panel-body">
<div class="container-fluid">
<form name="userDetailsForm" class="form-horizontal" role="form" method="POST" action="profile/details/change">
<spring:bind path="userDetailsForm"></spring:bind>
<div class="form-group">
<div class="row">
<label for="fname-input" class="col-md-offset-2 col-md-2 control-label">First name:</label>
<div class="col-md-5">
<spring:message code="label.fname_placeholder" var="fNameHolder" />
<spring:bind path="userDetailsForm.firstName">
<input type="text" value="${profile.getFirstName()}" name="<c:out value="${status.expression}"/>" class="form-control" placeholder="${fNameHolder}" required>
<c:if test="${status.error}">
<c:forEach items="${status.errorMessages}" var="error">
<small class="text-danger"> <c:out value="${error}" />
</small>
</c:forEach>
</c:if>
</spring:bind>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<label for="lname-input" class="col-md-offset-2 col-md-2 control-label">Last name:</label>
<div class="col-md-5">
<spring:message code="label.lname_placeholder" var="lNameHolder" />
<spring:bind path="userDetailsForm.lastName">
<input type="text" value="${profile.getLastName()}" name="<c:out value="${status.expression}"/>" class="form-control" placeholder="${lNameHolder}" required>
<c:if test="${status.error}">
<c:forEach items="${status.errorMessages}" var="error">
<small class="text-danger"> <c:out value="${error}" />
</small>
</c:forEach>
</c:if>
</spring:bind>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-offset-4 col-md-5">
<button type="submit" value="Submit" class="btn btn-success">
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span> Update
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
And message from debug when I submit incorrect data in lastName input:
2015-08-07 18:52:29 DEBUG UserController:? - Field error in object 'userDetailsForm' on field 'lastName': rejected value [jh]; codes [Pattern.userDetailsForm.lastName,Pattern.lastName,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userDetailsForm.lastName,lastName]; arguments []; default message [lastName],[Ljavax.validation.constraints.Pattern$Flag;#657f42ee,([A-Z�-�][a-zA-Z�-�]*)([\s\'-][A-Z�-�][a-z�-�]*)*]; default message [Name must contain only characters and first letter must be in uppercase]
I can't understand, why status.errorMessages is empty when BindingResult has got errors?
Any help or suggestions are appreciated.
Thanks in advance
You are using redirects within the request mapping block of your controller. The redirect is a header sent to the browser. The browser initiates the redirect, consequently you get a totally new request from the browser and because http is stateless, you lose anything stored in that previous request/response, such as the BindingResult.
remove the redirects and use a string to forward to the jsp page. You can use the internalviewresolver for this
I have this form and want to process it:
<form id="myForm" class="form-horizontal" action="/user" method="post">
<fieldset>
<div class="control-group">
<!-- Text input-->
<label class="control-label" for="input01">Email:</label>
<div class="controls">
<input name="email" placeholder="email" class="input-xlarge" type="text"
value="<%=?????????">
</div>
</div>
<div class="control-group">
<!-- Text input-->
<label class="control-label" for="input01">Password:</label>
<div class="controls">
<input name="password" placeholder="password" class="input-xlarge" type="text"
value="<%=request.getParameter("password")%>">
</div>
</div>
</fieldset>
</form>
</div>
<div class="modal-footer">
Close
<input class="btn btn-primary" type='button' value='Save Changes'
onclick='document.forms["myForm"].submit();'>
</div>
</div>
However, I have a bean method with two parameters and I tried to handle this by using:
public void insert(String email, String password) {
User entry = new User(email, password);
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.makePersistent(entry);
}
My question is, how to connect the Bean properly with the form, which uses two parameters?
Have you created the bean java file to connect those two? A functional bean file consists of the following three parts:
A constructor working as initialization
Getters
Setters
In the following lines, you will find a plain example concerning a form based on the one you posted above. Remember the old trick of System.out.println's to check everything you are writing is right.
Bean file , let's call it userData.java
package blabla;
import java.io.Serializable;
public class UserData implements Serializable {
private String email;
private String password;
//1.Constructor
public UserData()
{
email="";
password="";
}
//2.Getters
public String getEmail(){
return email;
}
public String getPassword(){
return password;
}
//3.Setters - Caution: we use different variables here
public void setEmail(String eml)
{
this.email=eml;
}
public void setPassword(String pswd)
{
this.password=pswd;
} }
On the other hand, the .jsp file should resemble like this
index.jsp
<%--Blablabla headers and stuff, I will only write the things needing to be added--%>
<jsp:useBean id="entry" class="packagePath.UserData" scope="application"/>
<%--For analytic info about the parameters of the jsp call above, check: http://www.javatpoint.com/jsp-useBean-action--%>
<jsp:setProperty name="entry" property="*"/>
<%--Code to invoke all the setters of the bean--%>
<p><jsp:getProperty name="entry" property="email"/></p>
<p><jsp:getProperty name="entry" property="password"/></p>
<%--The two lines are not obligatory to use; you will need them only if you wan tto print the results on the page--%>
<%-- rest of the code%-->