Objects in entity associations in JPA - jpa

I have an entity:
package com.igorgorbunov3333.core.entities.domain;
import javax.persistence.*;
/**
* Created by Игорь on 03.04.2016.
*/
#Entity
#Table(name = "cases")
public class Case {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String caseNumber;
private String dataI;
private String dataII;
private String dataIII;
private long judgeID;
private long lawyerID;
private long clientID;
#OneToOne
#JoinColumn(name = "id")
private Judge judge;
#OneToOne
#JoinColumn(name = "id")
private Lawyer lawyer;
#OneToOne
#JoinColumn(name = "id")
private Client client;
#Enumerated(value = EnumType.ORDINAL)
private CaseStatus statusI;
#Enumerated(value = EnumType.ORDINAL)
private CaseStatus statusII;
#Enumerated(value = EnumType.ORDINAL)
private CaseStatus statusIII;
private String document;
// getters and setters
}
As u can see there are three objects: Judge, Lawyer and Client which are associated with my entity. When I am fetching the entity I getting error: NullPointerException. Therefore I am forced to instantiate that objects in CaseServiceImpl.java to avoid exception:
public Case findById(long id) {
Case c = entityManager.find(Case.class, id);
c.setJudge(new JudgeServiceImpl().findById(c.getJudgeID()));
c.setClient(new ClientServiceImpl().findById(c.getClientID()));
c.setLawyer(new LawyerServiceImpl().findById(c.getLawyerID()));
return c;
}
Is it a right way to do so?
My JSP page code:
<%# page import="com.igorgorbunov3333.core.entities.domain.Case" %>
<%# page import="java.util.List" %>
<%# page contentType="text/html; charset=UTF-8" language="java" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<fmt:requestEncoding value="UTF-8"/>
<%-- HEADER --%>
<c:import url="/common/header.jsp">
<c:param name="title" value="Cases"/>
<c:param name="a" value="Дела"/>
</c:import>
<%-- BODY --%>
<div class="table-header">
<div class="first-header-element">№</div>
<div class="header-element">Номер дела</div>
<div class="header-element">Представитель</div>
<div class="header-element">Клиент</div>
<div class="last-header-element"></div>
</div>
<br>
<%List<Case> cases = (List<Case>) request.getAttribute("cases");
int count = 0;
for (Case c : cases) {%>
<div style="text-align: center">
<label>
<textarea class="first-element" readonly><%= ++count%></textarea>
</label>
<label>
<textarea class="element" readonly><%= c.getCaseNumber()%></textarea>
</label>
<label>
<textarea class="element" readonly><%= c.getLawyer().getLawyerName()%></textarea>
</label>
<label>
<textarea class="element" readonly><%= c.getClient().getClientName()%></textarea>
</label>
<a href="${pageContext.request.contextPath}/showSingleCase?caseID=<%=c.getId()%>"><label>
<input type="button" class="button" value="Детальней" style="width: 10%">
</label></a>
</div>
<%}%>
<%-- FOOTER --%>
<c:import url="/common/footer.jsp">
</c:import>
Error occuring at a string:
<textarea class="element" readonly><%= c.getLawyer().getLawyerName()%></textarea>

I see u are missing the implement serialization in entity class, or have already created the interface for the entity class. smth like CaseRepository interface where u can declare the method 'findById' because i suppose the default method of jpa to get by id is 'getById', so that might be a custom method u r trying to create.

Related

Using One Thymeleaf Form for Partial Table Update and #OneToMany Persistence with Validation

I have a user table and a user_details table. The user table gets partially populated by a script and the remaining age and birthplace values get added manually by a user via a Thymeleaf form. As a part of the form I also want to add details in the user_details table. The relationship is a #OneToMany.
I am running into a few issues with Validation that I am not able to figure out properly:
Since only 2 fields of the 5 are in the form to save to table user, is using hidden inputs the best way to pass all the User field values to the save method in the event of a validation failure or is the a cleaner way (i.e., a JPA annotation type way, etc.)?
On the initial loading of the user, the UserDetails are iterated through in the user.html file with th:each="detail: ${user.userDetailsById}". However, when the save method fails validation and the user.html file is returned from the result.hasErrors() block, those details revert to null and do not display. Do I have to manually query those again?
The object in the form is a User object. If I want to pass a user_details comment in the form input how would this be structured and persisted into user.user.userDetailsById.comment?
I've included the code below.
create table user
(
id varchar(10) not null
primary key,
first_name varchar(100) not null,
last_name varchar(100) not null,
age int unsigned null,
birthplace varchar(100) null,
constraint user_id_uindex
unique (id)
);
create table user_details
(
id int unsigned auto_increment
primary key,
user varchar(10) null,
comments longtext null,
constraint user_details_id_uindex
unique (id),
constraint user_details_user_id_fk
foreign key (user) references user (id)
);
#Entity
#Data
#Table(name = "user", schema = "demo")
public class User {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id", nullable = false, length = 10)
private String id;
#Basic
#Column(name = "first_name", nullable = false, length = 100)
private String firstName;
#Basic
#Column(name = "last_name", nullable = false, length = 100)
private String lastName;
#Basic
#Column(name = "age", nullable = true)
private Integer age;
#Basic
#NotEmpty
#Column(name = "birthplace", nullable = true, length = 100)
private String birthplace;
#OneToMany(mappedBy = "userByUser")
private Collection<UserDetails> userDetailsById;
}
#Entity
#Data
#Table(name = "user_details", schema = "demo")
public class UserDetails {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
#Column(name = "id", nullable = false)
private int id;
#Basic
#Column(name = "user", nullable = true, length = 10)
private String user;
#Basic
#Column(name = "comments", nullable = true)
private String comments;
#ManyToOne
#JoinColumn(name = "user", referencedColumnName = "id", insertable = false, updatable = false)
private User userByUser;
}
#Controller
public class UserController {
private final UserRepository userRepository;
private final UserDetailsRepository userDetailsRepository;
public UserController(UserRepository userRepository, UserDetailsRepository userDetailsRepository) {
this.userRepository = userRepository;
this.userDetailsRepository = userDetailsRepository;
}
#GetMapping("/all")
public String getAllUsers(Model model) {
model.addAttribute("users", userRepository.findAll());
return "users";
}
#GetMapping("/{id}")
public String getUser(#PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return "user";
}
#PostMapping("/save")
public String saveUser(#Valid User user, BindingResult result) {
if (result.hasErrors()) {
return "user";
}
userRepository.save(user);
return "redirect:/all";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Users</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/css/bootstrap.min.css">
</head>
<body>
<main class="container p-5">
<section>
<div class="row">
<div class="col">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Birthplace</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td><a class="text-dark" th:href="#{'/' + ${user.id}}" th:text="${user.id}"></a></td>
<td th:text="${user.firstName}"></td>
<td th:text="${user.lastName}"></td>
<td th:text="${user.age}"></td>
<td th:text="${user.birthplace}"></td>
</tbody>
<tfoot></tfoot>
</table>
</div>
</div>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Users</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/css/bootstrap.min.css">
</head>
<body>
<main class="container p-5">
<section>
<p th:text="'User: ' + ${user.firstName + ' ' + user.lastName}"></p>
<!-- THE USER DETAILS BECOME NULL WHEN THE VALIDATION RETURNS BACK TO THE FORM -->
<div th:if="${user.userDetailsById}">
<div th:each="detail: ${user.userDetailsById}">
<p th:text="'Comment: ' + ${detail.comments}"></p>
</div>
</div>
</section>
<section>
<form action="#" th:action="#{'/save'}" th:object="${user}" method="post">
<!-- ARE MULTIPLE HIDDEN INPUTS THE BEST WAY ENSURE THAT WHEN VALIDATION FAILS THE TABLE FIELDS GET PASSED BACK TO THE FORM? -->
<input type="hidden" th:field="*{id}">
<input type="hidden" th:field="*{firstName}">
<input type="hidden" th:field="*{lastName}">
<div class="row">
<div class="col">
<div class="mt-3">
<label class="form-label" for="age">Age</label>
<input class="form-control" id="age" type="number" th:field="*{age}">
<div class="text-danger mt-2" th:if="${#fields.hasErrors('age')}"
th:errors="*{age}"></div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="mt-3">
<label class="form-label" for="birthplace">Birthplace</label>
<input class="form-control" id="birthplace" type="text" th:field="*{birthplace}">
<div class="text-danger mt-2" th:if="${#fields.hasErrors('birthplace')}"
th:errors="*{birthplace}"></div>
</div>
</div>
</div>
<!-- HOW DO I IMPLEMENT THIS 'ADD USER DETAILS' INPUT TO POPULATE A NEW COMMENT TO THE USER DETAILS? -->
<div class="row">
<div class="col">
<div class="mt-3">
<label class="form-label" for="userDetail">User Details</label>
<input class="form-control" id="userDetail" type="text" th:field="*{????????}">
<div class="text-danger mt-2" th:if="${#fields.hasErrors('userDetail')}"
th:errors="*{??????????}"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-2">
<div class="mt-3">
<button class="btn btn-dark w-100" type="submit">Save</button>
</div>
</div>
<div class="col-2">
<div class="mt-3">
<a class="btn btn-secondary w-100" th:href="#{/all}"
role="button">Cancel</a>
</div>
</div>
</div>
</form>
</section>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
When offering a form with a partial edit on an entity I would personally use a seperate bean for the form submit with only the editable fields and a hidden id field, then in the service layer find the entity with that id and edit it's values depending on what was submitted in the form.
No you don't have to manualy query the fields again. The reason those fields are empty is because they'r not correctly bound when posting the form aslong as you post them with your form they wil come back when you return an error.
List fields need a name like *{userDetailsById__[iter.index]__.comments} where iter comes from the each loop th:each="iter, detail: ${user.userDetailsById}". for more details on how to do this you can look at https://www.baeldung.com/thymeleaf-list#list-selection-expression
see 2
P.s. You don't need the SQL in your question nor the overview page html as they do not relate to the question your asking. Just the edit page html, controller and entities (and service if relevant) is enough I'd say

Dynamic queries and JpaSpecificationExecutor in Spring

I am trying to create a simple Spring project where restaurants can add menu items to shared database and users can use a html form to search the dishes based on a range of criteria- especially dietary requirements
Form example:
Restaurant Name: Chez Hans
Gluten Free: (X)
Egg Free: (X)
Vegan: ()
Example SQL command
Select all FROM "dishes" Dish WHERE restaurant_name = "Chez Hans" AND egg_free = TRUE AND
gluten_Free = TRUE;
A list of dishes that fit their criteria would then be returned to the user.
Any field in the form can be left blank, and not checking a box for example, "vegan" does not mean that criteria should be set as 'false', but rather not included within the query.
Because of this it seemed the best way to handle the issue was using JpaSpecificationExecutor to create dynamic SQL queries (similar to the implementation in the answer to the problem below)
Filtering database rows with spring-data-jpa and spring-mvc
I have created a solution based on my research and prior knowledge. However, when I implement my solution, no dishes are returned- even though there are dishes in the database that fit the search criteria. No errors are being produced, but simply a blank table, so I am not sure where I am going wrong.
I have researched countless articles/videos regarding JpaSpecificationExecutor/dynamic queries but there are parts of the that theory I am still unsure about. This is what I gather about JpaSpecificationExecutor/dynamic queries (but I may be wrong)
The meta model is not need to create dynamic queries but to verify the correctness of database query statements
To create queries using meta-model classes a wrapper class is required (In my example- DishSearch)
The following lines are to cast metamodel SingularAttribute class back to the original class value.
Path dname = root.get(Dish_.dname);
Path vegan= root.get(Dish_.vegan);
I am quite new to Spring and still finding it pretty difficult. Any help or advice would be very much appreciated!
Please see below my DishSpecification class:
package com.bron.demoJPA.specification;
public class DishSpecification implements Specification<Dish> {
private final DishSearch criteria;
public DishSpecification(DishSearch ds) {
criteria =ds;
}
#Override
public Predicate toPredicate(Root<Dish> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
Path<String> dname = root.get(Dish_.dname);
Path<Boolean> vegan= root.get(Dish_.vegan);
Path<Boolean> eggFree= root.get(Dish_.eggFree);
Path<Boolean> glutenFree= root.get(Dish_.glutenFree);
final List<Predicate> predicates = new ArrayList<Predicate>();
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
if(criteria.isVegan()!=false) {
predicates.add(cb.equal(vegan, criteria.isVegan()));
}
if(criteria.isEggFree()!=false) {
predicates.add(cb.equal(eggFree, criteria.isEggFree()));
}
if(criteria.isGlutenFree()!=false) {
predicates.add(cb.equal(glutenFree, criteria.isGlutenFree()));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
}
Please see my DishSearch Class:
package com.bron.demoJPA.specification;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class DishSearch {
private Long dishId;
private String dname;
private String description;
private double price;
private boolean vegan;
private boolean glutenFree;
private boolean eggFree;
private AppUser app;
}
Please see my SearchController Class:
#Controller
public class SearchController {
#Autowired
DishRepository drep;
#GetMapping("/showSearchForm")
public String showNewDishForm(Model model) {
// Create model attribute to bind form data
DishSearch dishSearch = new DishSearch();
model.addAttribute("dishSearch", dishSearch);
return "search_Dish";
}
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch")DishSearch dishSearch) {
Specification<Dish> spec = new DishSpecification(dishSearch);
drep.findAll(spec);
return "show_dish_List";
}
}
Please see my DishRepository Class:
#Repository
public interface DishRepository extends JpaRepository<Dish, Long>, JpaSpecificationExecutor<Dish>{
#Transactional
#Modifying
List<Dish> findAll(Specification<Dish> spec);
}
Please see my search_Dish.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Dish Management System</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<div class="container">
<h2> Manage Dishes </h2>
<hr>
</div>
<form action="#" th:action="#{/showDishList}" th:object="${dishSearch}" method="POST">
<div class="col-sm-10 offset-sm-1 text-center">
<input type="text" th:field="*{dname}"
placeholder="Dish Name" class="form-control mb-4 col-10">
</div>
<div class="form-check form-check-inline">
<label class=" form-check-label" for="inlineCheckbox1 ">Vegan?</label>
<input type="checkbox" th:field="*{vegan}" />
<label class="form-check-label" for="inlineCheckbox1">Gluten Free?</label>
<input type="checkbox" th:field="*{glutenFree}" />
<label class="form-check-label" for="inlineCheckbox1">Egg Free?</label>
<input type="checkbox" th:field="*{EggFree}" />
</div>
<br>
<br>
<br>
<br>
<button type="submit" class="btn btn-info col-4"> Search Database</button>
</form>
</div>
<hr>
</body>
</html>
Please see my show_dish_List.html Thymeleaf Template:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Search Results</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
<br>
<div class="col-sm-10 offset-sm-1 text-center">
<h1>Dish List</h1>
</div>
<table border="1" class="table table-striped table-responsive-md">
<thead>
<tr>
<th>Dish Name</th>
<th>Dish description</th>
<th>Dish Price</th>
<th>Restaurant</th>
</tr>
</thead>
<tbody>
<tr th:each="dishSearch : ${listDishSearch}">
<td th:text="${dishSearch.dname}"></td>
<td th:text="${dishSearch.description}"></td>
<td th:text="${dishSearch.price}"></td>
</tr>
</tbody>
</table>
<div class="col-sm-10 offset-sm-1 text-center">
<a th:href="#{/showNewDishForm}"
class="btn btn-primary btn-sm mb-3"> Search Again</a>
</div>
----------------------------Update------------------------------
In addition to the answer provided below, in the Dish Specification Class I changed
if(criteria.getDname()!=null) {
predicates.add(cb.equal(dname, criteria.getDname()));
}
to
if(criteria.getDname()!="") {
predicates.add(cb.equal(dname, criteria.getDname()));
}
and the search is working fine now!
I believe the issue is that you are not adding the result in the Model which is being used to render the page show_dish_List.html, therefore nothing is being populated in the UI. Your UI is expecting the data to be in listDishSearch and there is nothing in that variable.
Update your code to:
#PostMapping("/showDishList")
public String saveUser(#ModelAttribute("dishSearch") DishSearch dishSearch, Model model) {
Specification<Dish> spec = new DishSpecification(dishSearch);
model.addAttribute("listDishSearch", drep.findAll(spec));
return "show_dish_List";
}
and everything should be working fine.
Remove the method findAll from your DishRepository repository. It is already being provided by the interface JpaSpecificationExecutor.

BindingResult nor plain target object for bean name 'fileName' available as request attribute " while trying to update a raw in my db,

I'm getting this exception while trying to update a row in my database. I performed a lot of research in Google all I find is that I should add #modelAttribute which is already done.
I also found that I need to add bindind result after #ModelAttribute but this also didn't work so I removed it. I'm using JPA for persistence to manipulate my data, spring boot and thymeleaf for my views.
These are my Controllers one for updating and rendering views
#GetMapping("/edit/{id}")
public ModelAndView UpdateList(#PathVariable(name="id") String id) {
ModelAndView mav = new ModelAndView("updateList");
com.pfe.ClientRest.model.Files files = fileServ.get(id);
mav.addObject("Files", files);
return mav ;
}
#PostMapping("/Save")
public String saveRepport(#ModelAttribute("Files") com.pfe.ClientRest.model.Files dbfile) {
fileServ.save(dbfile);
return "/redirect:/ListFile";
}
this is my entity class I have getter setters and constructors
#Table( name="Files")
#Entity
public class Files {
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Id
private String id;
private String FileName;
private String Verif;
public String getId() {
return id;
}
this is my template.
<div class="container">
<h1> Modifier les informations du Rapports</h1>
<form action="#" th:action="#{/Save}" th:objects="${Files}"
method="post" >
<input type="text" th:field=*{id} readonly="readonly"/>
<input type="text" th:field="*{fileName}" placeholder="Nom du Fichier"
class="form-control mb-4
col-4">
<input type="text" th:field="*{verif}" placeholder="Accepted/Rejected"
class="form-control mb-4
col-4">
<button type="submit" class="btn btn-info col-2"> Mettre à jour</button>
</form>
</div>
The field names in the html page and entity class does not match. These are case sensitive. So the correct one should be
private String fileName;
private String verif;

Springboot Thymeleaf form validation not working

I've trying to validate the fields in Thymeleaf but the errors are not showing in the view page.
My Controller
#Controller
public class UserController {
private static final String ADD_NEW_USER="user/addUser";
#Autowired
UserService userService;
#RequestMapping(value="/user/new", method=RequestMethod.GET)
public String addUser(Registration register, Model model){
model.addAttribute("register",register);
return ADD_NEW_USER;
}
#RequestMapping(value="/user/new", method=RequestMethod.POST)
public String addUser(#Valid Registration register, BindingResult result, Model model){
model.addAttribute("register",register);
if(result.hasErrors()){
List<FieldError> err=result.getFieldErrors();
for(FieldError e:err){
System.out.println("Error on object ---> "+e.getObjectName()+" on field ---> "+e.getField()+". Message ---> "+e.getDefaultMessage());
}
return ADD_NEW_USER;
}
return INDEX_PAGE;
}
}
View template
<form th:action="#{/user/new}" th:method="post" th:object="${register}" id="addUser" role="form">
<fieldset>
<legend>
<p>Field with <span class="required">*</span> are required</p>
</legend>
<div class="form-group">
<label for="name"><span class="required">* </span>Name: </label>
<input type="text" th:field="*{name}" class="form-control" />
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="alert alert-danger">
<p>Name is invalid</p>
</div>
<p class="help-block">Please provide full name for the user</p>
</div>
<div class="form-group">
<label for="email"><span class="required">* </span> Email Address: </label>
<input class="form-control" type="email" th:field="*{email}"/>
<div th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="alert alert-danger">
<p>Email is invalid</p>
</div>
<p class="help-block">Please provide a valid email address. Activation link will be sent to this email</p>
</div>
<div class="form-group">
<label for="password"><span class="required">* </span> Password: </label>
<input type="password" th:field="*{password}" class="form-control"/>
</div>
<div class="form-group">
<input class="btn btn-success" type="submit" name="Register" value="Register"/>
</div>
</fieldset>
</form><!-- ends register form -->
Modal
#Entity
public class Registration {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#NotEmpty
#Size(min=3, max=50)
#Column(nullable=false)
private String name;
#Email
#NotEmpty
#Column(nullable=false)
private String email;
private String password;
//getters and setters
}
I can output the console error like this.
Error on object ---> registration on field ---> name. Message ---> size must be between 3 and 50
Error on object ---> registration on field ---> email. Message ---> may not be empty
Error on object ---> registration on field ---> name. Message ---> may not be empty
I might be missing something but unable to find.
the problem is that the name of the entity is Registration and that the name of the object that you use is register.
In order this to work add #ModelAttribute("register") next yo your #valid annotation
namely
#RequestMapping(value="/user/new", method=RequestMethod.POST)
public String addUser(#Valid #ModelAttribute("register") Registration register, BindingResult result, Model model){
Hope this helps
I was also facing the same issue. With may hit/trial approach I found that #Valid annotation doesn't work with spring 2.3.0.RELEASE
If you are using spring 2.3.0.RELEASE then add below dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Hope this helps.
I also faced the same issue. My bindingResult.hasErrors() was always returning true in spite of pulling no values in the form. I had to change my validation from #NotNull to #NotEmpty.
#NotNull will only validate if the object is null, #NotEmpty will check if the object has empty strings.

Spring 3 MVC Form not saving data in database

I am trying to run a simple Spring 3 MVC project to save form data but when I submit data the page goes to add.html with empty forms and no data is save in Mysql neither it is shown on the page.
Controller
package com.app.a;
/**
* Handles requests for the application home page.
*/
#Controller
#RequestMapping(value="/")
public class HomeController {
#Autowired
private Personrepo personRepo;
#RequestMapping(method=RequestMethod.GET)
public String showForm(ModelMap model){
List<Person> persons = personRepo.getAll();
model.addAttribute("persons", persons);
Person person = new Person();
person.setId(UUID.randomUUID().toString());
model.addAttribute("person", person);
return "home";
}
#RequestMapping(value="/add", method=RequestMethod.POST)
public ModelAndView add(#ModelAttribute(value="person") Person person,BindingResult result){
ModelAndView mv = new ModelAndView("home");
if(!result.hasErrors()) {
personRepo.add(person);
person = new Person();
person.setId(UUID.randomUUID().toString());
mv.addObject("person", person);
}
mv.addObject("persons", personRepo.getAll());
return mv;
}
#RequestMapping(value="/edit", method=RequestMethod.POST)
public ModelAndView edit(#ModelAttribute(value="person") Person person,BindingResult result) {
ModelAndView mv = new ModelAndView("home");
if(!result.hasErrors()) {
personRepo.edit(person);
person = new Person();
mv.addObject("person", person);
}
mv.addObject("persons", personRepo.getAll());
return mv;
}
#RequestMapping(value="/delete", method=RequestMethod.POST)
public ModelAndView update(#ModelAttribute(value="person") Person person,BindingResult result){
ModelAndView mv = new ModelAndView("home");
if(!result.hasErrors()) {
personRepo.delete(person.getId());
//personRepo.delete(person);
person = new Person();
mv.addObject("person", person);
}
mv.addObject("persons", personRepo.getAll());
return mv;
}
}
Home .jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%#taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<body>
<table align="center">
<c:forEach items="${persons}" var="person">
<tr>
<td>Welcome:</td>
<td><c:out value="${person.firstName}" /></td>
</tr>
<tr>
<td>Your lastname:</td>
<td><c:out value="${person.lastName}" /></td>
</tr>
</c:forEach>
</table>
<form:form modelAttribute="person" method="post" action="add.html">
<form:hidden path="id" />
<table>
<tr>
<td><form:label path="firstName">First Name:</form:label></td>
<td><form:input path="firstName" /></td>
</tr>
<tr>
<td><form:label path="lastName">Last Name</form:label></td>
<td><form:input path="lastName" /></td>
</tr>
<tr>
<td><form:label path="money">Money</form:label></td>
<td><form:input path="money" /></td>
</tr>
</table>
<input type="submit" value="Save" />
</form:form>
</body>
</html>
From the looks of it, unless you are doing content negotiation, you don't have a controller method mapped to the URL add.html.
Compare:
<form:form modelAttribute="person" method="post" action="add.html">
and
#RequestMapping(value="/add", method=RequestMethod.POST)
Make it
<form:form modelAttribute="person" method="post" action="add">
and you should be fine.