Facing issue in spring form binding.Say i have two models Category and Product.
#Entity
#Table(name="PRODUCT")
public class Product
{
#Id
#GeneratedValue
private long productID;
#ManyToOne
#JoinColumn(name="categoryID")
private Category category;
//Getters and setters
}
#Entity
#Table(name = "CATEGORY")
public class Category {
#Id
#GeneratedValue
private long categoryID;
private String categoryName;
}
In controller to render add product page
#RequestMapping(value = "/productpage", method=RequestMethod.GET)
private ModelAndView getAddProductPage(){
ModelAndView modelAndView = new ModelAndView("add-product","product",new Product());
Map<Category,String> categoriesMap = new HashMap<Category, String>();
List<Category> categories = categoryService.getAllCategories();
if(categories != null && !categories.isEmpty())
{
for(Category category : categories)
{
categoriesMap.put(category, category.getCategoryName());
}
}
modelAndView.addObject("categoryList",categories);
return modelAndView;
}
I am able to populate the drop down values of categories in JSP page using below code :
<form:select path="category" >
<form:options items="${categoryList}"/>
</form:select>
While submitting the form i'm facing error 400 The request sent by the client was syntactically incorrect.Failed to convert property value of type 'java.lang.String' to required type 'com.example.model.Category' for property 'category'.
If i view page source for each option category is assigned correctly. But not understanding why spring throwing that err.. Need help. Thanks in advance!
This worked for me!
<form:select path="category.categoryID" >
<form:options items="${categoryList}" itemValue="categoryID" />
</form:select>
You should make the following change in your Controller's action:
for(Category category : categories)
{
categoriesMap.put(category.geCategorytId(), category.getCategoryName());
}
and in your view change:
<form:select path="category.categoryID" >
The select drop-down will have the category name as the display text and category ID as the value.
<form:select path="category">
<c:forEach items="${categoryList}" var="category">
<form:option value="${category}">${category.categoryName}</form:option>
</c:forEach>
</form:select>
or
<form:select class="form-control" path="site">
<form:option value="-1">Select...</form:option>
<form:options items="${categoryList}" itemValue="categoryID" itemLabel="categoryName"/>
</form:select>
Related
I'm trying to figure out with Spring Boot and databases.
So I have 2 entities with #OneToMany relationship:
#Entity
public class Team {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int teamId;
#Column
private String teamTitle;
#Column
private String teamCity;
#ManyToOne
#JoinColumn(name = "conferenceId", nullable = false)
private Conference teamConference;
public Team() { super(); }
//some getters and setters
}
And the second one:
#Entity
public class Conference {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int conferenceId;
private String conferenceTitle;
#OneToMany(mappedBy = "teamId")
private List<Team> conferenceTeams;
public Conference() {
super();
}
//some getters and setters
}
Jsp page:
<body>
<form:form method="post" modelAttribute="team">
<div>
<form:label path="teamTitle">Title</form:label>
<form:input path="teamTitle" type="text"/>
<form:label path="teamCity">City</form:label>
<form:input path="teamCity" type="text"/>
//DAHELL IS HERE
<div class="form-group">
<label for="conferenceList">Select conference:</label>
<select class="form-control" id="conferenceList">
<c:forEach items="${conference}" var="conf">
<option>${conf.conferenceTitle}</option>
</c:forEach>
</select>
</div>
<button type="submit" class="btn btn-success">Add</button>
</div>
</form:form>
// jquery etc
</body>
And controller class:
#Controller
public class TeamsController {
#Autowired
private TeamDAO teamDAO;
#Autowired
private ConferenceDAO conferenceDAO;
#RequestMapping(value = "/schedule", method = RequestMethod.GET)
public String showSchedule(ModelMap model) {
model.put("conferences", conferenceDAO.findAll());
model.put("teams", teamDAO.findAll());
return "schedule";
}
#RequestMapping(value = "/new-team", method = RequestMethod.GET)
public String addNewTeam(ModelMap model) {
model.addAttribute("conference", conferenceDAO.findAll());
model.addAttribute("team", new Team());
return "new-team";
}
#RequestMapping(value = "/new-team", method = RequestMethod.POST)
public String addTeam(ModelMap model, Team newTeam) {
teamDAO.save(newTeam);
return "redirect:/schedule";
}
}
ConferenceDAO and TeamDAO are just interfaces extended from JpaRepository.
So what I'm trying to understand is how to add new Team. I insert title and city through jsp page and also I should choose which conference this team belongs. But when I press add button I got
There was an unexpected error (type=Internal Server Error, status=500).
No message available
What am I doing wrong? I believe that something with selecting part in jsp page. And I'm 100% sure I'm missing something in my Controller class. Somehow I should save new team to my DB and the Conference column also should show that it contains this new team.
I'd really appreciate guys if you show me the way to dig up.
So yes, comments really helped. So for those who read it - sleep on the problem and read logs before ask dumb questions (as I did :D )
The problem was within jsp page and selection form. I was getting Null for conferenceId and I would know it if I'd read logs.
So comments about checking whole stack trace and changing jsp selection part - worked for me.
Fixed jsp selection is:
<div class="form-group">
<label for="conferenceList">Select conference:</label>
<form:select path="teamConference" id="conferenceList">
<form:options items="${conference}" itemLabel="conferenceTitle"/>
</form:select>
</div>
Thx guys!
I'm doing an application using Spring MVC and I have a problem when I try to register an bank account to a specific person in my application. In this case, one Person has many accounts:
There are two classes in this relationship:
Sumarizing:
#Entity
public class Pessoa {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int idPessoa;
#OneToMany(mappedBy = "pessoa", targetEntity = ContaCorretora.class, fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<ContaCorretora> contaCorretora;
#Entity
public class ContaCorretora {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int idConta;
private TipoConta tipoConta;
private TipoRisco tipoRisco;
private String login;
private String senha;
private BigDecimal valorAtual;
#ManyToOne
#JoinColumn(name="idPessoa")
private Pessoa pessoa;
Controller Class:
#RequestMapping("/pessoa")
#Controller
public class ContaCorretoraController {
#Autowired
private ContaCorretoraDAO contaCorretoraDao;
#Autowired
private PessoaDAO pessoaDao;
#RequestMapping("/pessoacorretora/{id}")
public ModelAndView pessoaCorretora(#PathVariable("id") int id, ContaCorretora contaCorretora ) {
contaCorretora = new ContaCorretora();
Map<String, Object> model = new HashMap<String, Object>();
Pessoa pessoa = pessoaDao.find(id);
model.put("contaCorretora", contaCorretora);
model.put("pessoa", pessoa);
model.put("tipoConta", TipoConta.values());
model.put("tipoRisco", TipoRisco.values());
return new ModelAndView("pessoa/contacorretora", "model", model);
}
#RequestMapping(value="/pessoacorretora/finalizar", method=RequestMethod.POST)
public ModelAndView gravar(ContaCorretora contaCorretora) {
contaCorretoraDao.gravar(contaCorretora);
return new ModelAndView("redirect:pessoa/contacorretora");
}
I really don't know if the controller class is correct, but probably the problem is there. Nevertheless, I'll paste the JSP code as well:
<form:form action="${s:mvcUrl('CCC#gravar').build() }" method="post" commandName="pessoa" enctype="multipart/form-data" >
<div class="form-group" >
<label>Conta</label>
<select name="tipoConta">
<c:forEach items="${model.tipoConta}" var="tipoConta">
<option value=${tipoConta}>${tipoConta}</option>
</c:forEach>
</select>
</div>
<div class="form-group" >
<label>Risco</label>
<select name="tipoRisco">
<c:forEach items="${model.tipoRisco}" var="tipoRisco">
<option value=${tipoRisco}>${tipoRisco}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label>Login</label>
<form:input path="login" cssClass="form-control" />
</div>
<div class="form-group">
<label>Senha</label>
<form:input path="senha" cssClass="form-control" />
</div>
<div class="form-group">
<label>Valor Atual</label>
<form:input path="valorAtual" cssClass="form-control" />
</div>
<button type="submit" class="btn btn-primary">Cadastrar</button>
</form:form>
When I try to open the website (..../pessoa/pessoacorretora/6) - 6 is a valid ID, this is the error:
HTTP Status 500 - java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'pessoa' available as request attribute
type Exception report
message java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'pessoa' available as request attribute
description The server encountered an internal error that prevented it from fulfilling this request.
Actually I really don't know how to handle with a relationship of two classes when I want to do CRUD actions.
The problem is that spring can't bind the commandName="pessoa" in your JSP form.
Are you sure that the value of Pessoa returnd by :
Pessoa pessoa = pessoaDao.find(id); // is not Null ??
try this as a test :
model.put("pessoa", pessoa == null ? new Pessoa() : pessoa );
another way to solve this is to add it through Model Attribute annotation on you controller:
#ModelAttribute("pessoa ")
public Pessoa defaultInstance() {
return new Pessoa();
}
I want to create a bank account register related to a specific Person in a OneToMany relationship.
I have the clas Pessoa (Person):
#Entity
public class Pessoa {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int idPessoa;
private String nome;
#OneToMany(mappedBy = "pessoa", targetEntity = ContaCorretora.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<ContaCorretora> contaCorretora;
...and the class ContaCorretora (Bank account):
#Entity
public class ContaCorretora {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private int idConta;
private TipoConta tipoConta;
private TipoRisco tipoRisco;
private String login;
private String senha;
private BigDecimal valorAtual;
#ManyToOne
#JoinColumn(name="idPessoa")
private Pessoa pessoa;
I'm using this method in Controller for start the process of registration:
#RequestMapping(value = "pessoacorretora/{id}")
public ModelAndView pessoaCorretora(#PathVariable("id") int id, ContaCorretora contaCorretora ) {
Map<String, Object> model = new HashMap<String, Object>();
Pessoa pessoa = pessoaDao.find(id);
model.put("pessoa", pessoa);
model.put("tipoConta", TipoConta.values());
model.put("tipoRisco", TipoRisco.values());
return new ModelAndView("corretora/contacorretora", "model", model);
}
Sumarizining, I have a specific page for recording bank accounts. So, I created this form:
<form:form action="${s:mvcUrl('CC#gravar').build() }" method="post" commandName="contaCorretora" enctype="multipart/form-data" >
<div class="form-group" >
<label>Conta</label>
<select name="tipoConta">
<c:forEach items="${model.tipoConta}" var="tipoConta">
<option value=${tipoConta}>${tipoConta}</option>
</c:forEach>
</select>
</div>
<div class="form-group" >
<label>Risco</label>
<select name="tipoRisco">
<c:forEach items="${model.tipoRisco}" var="tipoRisco">
<option value=${tipoRisco}>${tipoRisco}</option>
</c:forEach>
</select>
</div>
<div class="form-group">
<label>Login</label>
<form:input path="login" cssClass="form-control" />
</div>
<div class="form-group">
<label>Senha</label>
<form:input path="senha" cssClass="form-control" />
</div>
<div class="form-group">
<label>Valor Atual</label>
<form:input path="valorAtual" cssClass="form-control" />
</div>
<form:hidden path="pessoa" cssClass="form-control" value="${pessoa}"/>
<button type="submit" class="btn btn-primary">Cadastrar</button>
</form:form>
When I use the form in this way, I receive the error "description The request sent by the client was syntactically incorrect." I figured out that the problem is in this line, because when I delete, the form post ok:
<form:hidden path="pessoa" cssClass="form-control" value="${pessoa}"/>
Nevertheless, if I delete this line, the program doesn't save the idPessoa as a foreign key, this field is null. I would like to know how to pass an entire object in my JSP form. The post method is:
#RequestMapping(method=RequestMethod.POST)
public ModelAndView gravar(ContaCorretora contaCorretora) {
contaCorretoraDao.gravar(contaCorretora);
return new ModelAndView("pessoa/listageral");
}
all the DAO's methods are okay.
You only need to send the primary key of pessoa to the form.
Change the form attribute
<form:hidden path="pessoa.idPessoa" cssClass="form-control" value="${model.pessoa.idPessoa}"/>
Before persisting the ContaCorretora, make sure you get the Pessoa object from db.
#RequestMapping(method=RequestMethod.POST)
public ModelAndView gravar(ContaCorretora contaCorretora) {
contaCorretora.setPessoa(pessoaDao.find(contaCorretora.getPessoa().getIdPessoa()));
//I escaped null check and not found exceptions, you should apply some logic to take care of that
contaCorretoraDao.gravar(contaCorretora);
return new ModelAndView("pessoa/listageral");
}
Using Entities as form model is not a good approach. Persistance layer should not be on the MVC layer.
In order to pass Java object from your Controller
#RequestMapping(method=RequestMethod.POST)
public ModelAndView gravar(ContaCorretora contaCorretora) {
ModelAndView mav = new ModelAndView("pessoa/listageral");
// retrieve object from DAO
Object myObj = Dao.find(id);
// Put object into model map
mav.addObject("myObj", myObj);
// return model and view
return mav;
}
In JSP you can refer to object using ExpressionLanguage syntax
${myObj}
I am developing Employee Management application using Spring-Hibernate. I have two entities Employee and Department. And Employee entity has a field Department which is mapped to Department entity as #ManyToOne.
#ManyToOne(cascade = {CascadeType.PERSIST})
#JoinColumn(name = "dept")
private Department dept;
And accordingly #OneToMany mapping in Department entity
#OneToMany(mappedBy = "dept")
private List<Employee> employees = new ArrayList<>();
My JSP Spring form is mapped to Employee entity. And it has a form:select element to select department with values as department ids.
<form:form modelAttribute="createEmployee"
action="${pageContext.request.contextPath}/createdemployee"
method="post">
..............
..............
<form:input path="employee.firstName" type="text" width="20px;" />
<form:select>
<form:option value="1001">IT</form:option>
<form:option value="1002">Finance</form:option>
<form:option value="1003">Marketing</form:option>
<form:option value="1004">Sales</form:option>
<form:option value="1005">H.R</form:option>
</form:select>
How can I set Deparment object in Employee entity as per selection made on the form?
Controller
#RequestMapping("/createdemployee")
public String goCreatedEmployee(Model model, Employee employee){
employeeDataServices.addEmployee(employee);
return "created_employee";
}
You can use it like :
<form:select path="employee.department.code">
<form:option value="1001">IT</form:option>
<form:option value="1002">Finance</form:option>
<form:option value="1003">Marketing</form:option>
<form:option value="1004">Sales</form:option>
<form:option value="1005">H.R</form:option>
</form:select>
And from the Controller, get the employee model and get department's name?
Also add the request method in your code - POST/PUT.
#RequestMapping(value = /createdemployee, method = RequestMethod.POST)
public String goCreatedEmployee(Model model, Employee employee){
employeeDataServices.addEmployee(employee);
return "created_employee";
}
Let me know if it works?
I have problem with adding/updating records with relations. Could please some advice how it should work?
I have two entities: Question and Category:
public class Question {
#Id
#GeneratedValue
private Long questionId;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category")
private Category category;
and
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue
private Long categoryId;
private String name;
I have some list of categories and I would like to add new Question with selected Category. So in my QuestionController I have add method:
#RequestMapping(value = "/add", method = RequestMethod.GET)
public ModelAndView add() {
ModelAndView mav = new ModelAndView("question/add");
mav.addObject("question", new Question());
mav.addObject("categoryList", categoryService.getAll());
return mav;
}
and form:
<form:form modelAttribute="question" method="POST" >
Name: <form:input path="name" value="${ques.name}" />
Category: <form:select path="category" items="${categoryList}" />
<input type="submit" value="Add" />
</form:form>
Everything looks good for now (I can fill question name and select category). But I don't know how add POST method should work
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String added(#ModelAttribute Question question, BindingResult bindingResult) {
}
When I try to use above method I have error: Failed to convert property value of type 'java.lang.String' to required type model.Category
I've tried to look for similar problem but I coudln't find anything.. So if someone can help/advice or show link to similar issue I would be grateful!
Cheers!
You need to provide code for Spring that tells it how to convert the string value from the web page back into a Category object. This is done by either:
Adding a PropertyEditor to the DataBinder.
Creating a Converter.
It is a bad practice using hibernate objects to map the form items. There are two solutions
Add another property private transient String categoryString; to the 'Question' class. and map the UI category to this <form:select path="categoryString" items="${categoryList}" />
That way you can avoid the error.
Do not use the hibernate mapping classes for mapping the form items, use POJOs for doing this. and later somewhere in your application map this simple pojo elements onto the hibernate entity.
try changing this line:
<form:select path="category" items="${categoryList}" />
to:
<form:select path="category.categoryId" items="${categoryList}" itemLabel="name" itemValue="categoryId"/>
Then in the added method (post method), retrieve the Category object back from hibernate and set back on question object before saving:
Category selectedCategory = yourHibernateService.getCategoryById(question.getCategory().getCategoryId());
question.setCategory(selectedCategory);