Spring boot Mongodb Creating a nested document - spring

can any one please tell me what I am missing ?
I am trying to create a Mongo collection using spring boot mongodb.
I want to create something like this
{
"_id":"123456"
"entity_name":"some name"
"entity_desc":"some description"
"events":[
{"title":"some title", "description":"some description"},
{"title":"title2", "description":"description2" }
]
}
but I am getting this
{
"_id":"123456"
"entity_name":"some name"
"entity_desc":"some description"
"events":[ ]
}
my Domain classes are
#Document
public class Entity {
#Id
private BigInteger id;
private String name, description;
private List<Event> events=new ArrayList<Event>();
/* GETTERS AND SETTERS */
}
public class Event {
private String titles;
private String descriptions;
/* GETTERS AND SETTERS */
}
and my repository is
public interface MyRepository extends MongoRepository<Entity, String>{
}
controller is
#Controller
public class RootController {
#Autowired
private MyRepository mr;
/* GET and other methods */
#RequestMapping(value="/", method=RequestMethod.POST)
public String helloPost(#ModelAttribute Entity entity){
mr.save(entity);
return "success";
}
}
and my jsp form is
<form:form modelAttribute="entity" role="form">
<div class="form-group">
Name <input type="text" id="name" name="name" /><br />
</div>
<div class="form-group">
Description <input type="text" id="description" name="description" /><br />
</div>
<div class="form-group">
event <input type="text" id="event" name="event" /><br />
</div>
<div class="form-group" >
title <input type="text" id="title" name="title" /><br />
</div>
<div class="form-group" >
description <input type="text" id="description" name="description" /><br />
</div>
<div>
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form:form>

Shouldn't it be something like below?
public class Event {
private String title;
private String description;
/* GETTERS AND SETTERS */
}
EDIT : Thanks for the jsp, clearly the way you are passing the values are not picked for child. Spring MVC doesn't support ONGL so it won't pick up child object with dot notation. But there are complex mechanism by setting path. Please look at this answer where it did pass child object list through form parameter. So it can be good starting point.

Related

Cannot connect Thymeleaf HTML webpage to my Spring Boot API/DB

I have a Spring Boot application for a school records management system. My API is working perfectly when using Insomnia but I cannot get my hTML webpage to interact with the API. Here are the relevant bits of my Staff entity/controller/repository/service. Any help appreciated!
Entity class:
#Entity
#Data
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#Builder
#ToString
public class Staff {
#Id
#SequenceGenerator(
name = "STAFF_SEQ",
sequenceName = "STAFF_SEQ",
allocationSize = 1
)
#GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "STAFF_SEQ"
)
private Long staffId;
private String firstName;
private String lastName;
private String staffEmail;
#ManyToOne(targetEntity = Department.class)
private Long departmentId;
private String address;
private String contactNumber;
private char gender;
}
...
}
Controller Class
#RestController
public class StaffController {
#Autowired
private StaffService staffService;
#RequestMapping(value = "/saveStaff")
public Staff saveStaff(Staff staff) {
return staffService.saveStaff(staff);
}
...
}
Repository Class
#Repository
public interface StaffRepository extends JpaRepository<Staff, Long> {
Staff findByFirstNameAndLastName(String firstName, String lastName);
}
Service Interface
public interface StaffService {
public Staff saveStaff(Staff staff);
...
}
ServiceImpl
#Service
public class StaffServiceImpl implements StaffService{
#Autowired
StaffRepository staffRepository;
#Override
public Staff saveStaff(Staff staff) {
return staffRepository.save(staff);
}
...
}
HTML file
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<h2>Add Staff</h2>
<form action = "#" method="post" th:action ="#{/saveStaff}" th:object = "${staff}">
<fieldset>
<legend>Staff</legend>
<label for="firstName">First name:</label><br>
<input type="text" th:field ="*{firstName}" class="form-control" id="firstName" name="firstName"><br><br>
<label for="lastName">Last name:</label><br>
<input type="text" th:field ="*{lastName}" class="form-control" id="lastName" name="lastname"><br><br>
<label for="staffEmail">Staff email:</label><br>
<input type="staffEmail" th:field ="*{staffEmail}" class="form-control" id="staffEmail" name="staffEmail"> <br><br>
<label for="address">Address</label><br>
<input type="text" th:field ="*{address}" class="form-control" id="address" name="address"><br><br>
<label for="contactNumber"> Contact number</label><br>
<input type="text" th:field ="*{contactNumber}" class="form-control" id="contactNumber" name="contactNumber"><br><br>
<label for="gender">Gender:</label>
<select th:field ="*{gender}" class="form-control" id="gender" name="gender">
<option value="f">F</option>
<option value="m">M</option>
</select><br><br>
<label for="departmentId"> Department Id</label><br>
<input type="number" th:field ="*{departmentId}" class="form-control" id="departmentId" name="departmentId"><br><br>
<input type="submit" value="Submit">
<input type="reset">
</fieldset>
</form>
</body>
</html>
Your controller class is a #RestController. From view page you need to call the rest controller by using XmlHttpRequest or we can say, Ajax request or fetch API. For your ease, you can try jQuery. If you really want to submit your form the Thymeleaf way, then your controller needs to be a MVC Controller. Long story short, you should replace the annotation #RestController with #Controller. Also remove the action attribute and keep only th:action.
Your Controller class
#Controller
#RequestMapping("/course")
public class CourseController {
#Autowired
CourseService courseService;
#GetMapping("/add")
public String get_saveCourseForm(Model model) {
Course course = new Course();
model.addAttribute("course", course);
return "saveCourse";
}
#PostMapping("/save")
public String post_saveCourseForm(#ModelAttribute("course") Course course, Model model) {
courseService.saveCourse(course);
var courses = courseService.fetchCourseList();
model.addAttribute("courses", courses);
return "displayCourses";
}
}
Replaced #RestController with #Controller annotation
Add MVC methods and return view page names from the MVC methods. Also notice the request mappings. We will view the form by calling /course/add and the form will be submitted to /course/save.
Your Form Page
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<h2>Add Course</h2>
<form method="post" th:action ="#{/course/save}" th:object = "${course}">
<fieldset>
<legend>Staff</legend>
<label for="courseName">Course name:</label><br>
<input type="text" th:field ="*{courseName}" class="form-control" id="courseName" name="courseName"><br><br>
<label for="courseCode">Course code:</label><br>
<input type="text" th:field ="*{courseCode}" class="form-control" id="courseCode" name="courseCode"><br><br>
<label for="departmentId"> Department Id</label><br>
<input type="number" th:field ="*{departmentId}" class="form-control" id="departmentId" name="departmentId"><br><br>
<input type="submit" value="Submit">
<input type="reset">
</fieldset>
</form>
</body>
</html>
Check the form action.
The page will look like below.
When the form will be submitted, it will return the result page. the HTML code is as follows.
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Display Courses</title>
</head>
<body>
<table>
<tr>
<th>Course ID</th>
<th>Course Name</th>
<th>Course Code</th>
</tr>
<tr th:each="course : ${courses}">
<td><span th:text="${course.courseId}"></span></td>
<td><span th:text="${course.courseName}"></span></td>
<td><span th:text="${course.courseCode}"></span></td>
</tr>
</table>
</body>
</html>
The page will look as follows.

Can not save object to MySQL DB using Java Spring Boot

I've got ENTITY Country with all getters and setters + Constructor with no args. Getters and setter are all written by IDEA, not Lombok.
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String code;
private String capital;
private String description;
private String nationality;
private String continent;
#OneToMany(mappedBy="country")
private List<State> states;
public Country() {
}`
Here goes CountryRepository:
#Repository
public interface CountryRepository extends JpaRepository<Country, Integer> {}
Here goes CountryService:
#Service
public class CountryService {
#Autowired
private CountryRepository countryRepository;
public List<Country> getListOfCountries() {
return countryRepository.findAll();
}
public void addNewCountry(Country country) {
countryRepository.save(country);
}
}
and CountryController:
#Controller
public class CountryController {
#Autowired
private CountryService countryService;
#GetMapping("/countries")
private String getListOfCountries(Model model) {
List<Country> listOfCountries = countryService.getListOfCountries();
model.addAttribute("countries", listOfCountries);
return "countries";
}
#PostMapping("/countries/addNew")
private String addNewCountry(#RequestParam String code,
#RequestParam String capital,
#RequestParam String description,
#RequestParam String nationality,
#RequestParam String continent) {
Country country = new Country();
country.setCode(code);
country.setCapital(capital);
country.setDescription(description);
country.setNationality(nationality);
country.setContinent(continent);
countryService.addNewCountry(country);
return "redirect:/countries";
}
}
and here is the form that's supposed to take input, but unfortunately nothing happens(
<div class="modal-body">
<form th:action="#{/countries/addNew}" method="post">
<div class="form-group">
<label for="recipient-name" class="col-form-label">Code:</label>
<input type="text" class="form-control" id="recipient-name" name="code">
</div>
<div class="form-group">
<label for="recipient-name1" class="col-form-label">Capital:</label>
<input type="text" class="form-control" id="recipient-name1" name="capital">
</div>
<div class="form-group">
<label for="recipient-name2" class="col-form-label">Description:</label>
<input type="text" class="form-control" id="recipient-name2" name="description">
</div>
<div class="form-group">
<label for="recipient-name3" class="col-form-label">Nationality:</label>
<input type="text" class="form-control" id="recipient-name3" name="nationality">
</div>
<div class="form-group">
<label for="recipient-name4" class="col-form-label">Continent:</label>
<input type="text" class="form-control" id="recipient-name4" name="continent">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" data-dismiss="modal">Add</button>
</div>
</form>
</div>
If I add data manually to the DB everything works fine, but when using this form nothing happens. At the same time I didn't get to errors or whatever. Server runs OK. Instead of JPARepository I tried using CRUDRepository. Also doblechecked the names of the form so they have the same values as Country fields. Realy lost here...

How to assign entity to another entity in a form using ThymeLeaf?

I am working on MVC Java project and am using Spring Boot with ThymeLeaf. The issue I have is, that when creating a Task, I want to select and save a User, that will be assign to the task. I managed to do the selection correctly, but am unable to save the selected user. It always saves without the User assigned.
Here is my Task entity class:
#Entity
public class Task extends BaseEntity {
private String name;
private String description;
private Date dateOfCreation;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dueDate;
#ManyToOne
private User assignee;
public Task() {
this.dateOfCreation = new Date(System.currentTimeMillis());
}
}
My User entity is as follows:
#Entity
public class User extends BaseEntity {
private String username;
private String password;
#OneToMany(mappedBy = "assignee")
private List<Task> assignedTasks;
}
Where BaseEntity contains
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
My controller function, that is responsible for my taskform.html is:
#RequestMapping("/new")
public String newTask(Model model){
model.addAttribute("task", new Task());
model.addAttribute("users", userService.getAllUsers());
return "task/taskform";
}
And my taskform.html looks like this:
<form class="form-horizontal" th:object="${task}" th:action="#{/task}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{version}"/>
<div class="form-group">
<label class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{name}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{description}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="date" th:value="*{dueDate}" th:field="*{dueDate}" id="dueDate" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Select user:</label>
<div class="col-sm-10">
<select class="form-control">
<option th:field="*{assignee}" th:each="assignee : ${users}" th:value="${assignee}" th:text="${assignee.username}">
</option>
</select>
</div>
</div>
<div class="row">
<button type="submit" class="btn btn-default">Submit</button>
</div>
I am trying to pass the object from users list as the value, but it does not work Any idea, how to do it?
Showing the users works as expected:
Working frontend
Null is being assigned to assignee column, where the user should be assigned.
Null in H2 Database
EDIT
Here is my POST method from Task Controller:
#RequestMapping(method = RequestMethod.POST)
public String saveOrUpdate(Task task){
taskService.persistTask(task);
return "redirect:/task/list";
}

I can not update my entity using Hibernate, Spring MVC, Thymleaf

Hello I want to update User entity, so in the form edit.html i'm using thymeleaf:
<form action="#" th:action="#{/{id}/edit(id=${user.id})}"
th:object="${user}" method="post">
<div class="md-form">
<input type="text" th:field="*{firstName}"
th:value="${user.firstName}" name="firstName" id="firstName"
class="form-control" /> <label class="active" for="firstName">Prénom</label>
</div>
<div class="md-form">
<input type="text" th:field="*{lastName}"
th:value="${user.lastName}" name="lastName" id="lastName"
class="form-control" /> <label class="active" for="lastName">Nom</label>
</div>
<div class="md-form">
<input type="text" th:field="*{email}" th:value="${user.email}"
name="email" id="email" class="form-control" /> <label
class="active" for="email">email</label>
</div>
<div class="md-form">
<input type="text" th:field="*{password}"
th:value="${user.password}" name="password" id="password"
class="form-control" /> <label class="active" for="password">mot
de passe</label>
</div>
<div class="md-form">
<input type="text" th:field="*{occupation}"
th:value="${user.occupation}" name="occupation" id="occupation"
class="form-control" /> <label class="active" for="occupation">profession</label>
</div>
<div class="md-form">
<input type="text" th:field="*{ville}" th:value="${user.ville}"
name="ville" id="ville" class="form-control" /> <label
class="active" for="ville">ville</label>
</div>
<div>
<input class="btn btn-sm btn-primary waves-effect btn-rounded"
type="submit" value="modifier" />
</div>
</form>
User.java:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String userName;
private int age;
private String ville;
private String email;
private String password;
private String phone;
private String company;
private String occupation;
private String img_profil;
#ManyToMany(mappedBy = "users", cascade = { CascadeType.ALL })
private Set<Discussion> discussion;
UserController.java
#GetMapping("/{userName}/edit")
public String editUser(#PathVariable String userName, Model model) {
User user = ur.findByUserName(userName).get(0);
model.addAttribute(user);
return "edit";
}
#PostMapping("/{id}/edit")
public String updateUser(#ModelAttribute("user") User user, #PathVariable("id") Long id) {
user = ur.findOne(id);
ur.save(user);
return "redirect:/find/" + user.getUserName();
}
UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUserName(String userName);
}
PROBLEM is in the console I do not see update request (generated by Hibernate), nothing is changed on the database.
Make the following change in UserController.java:
#PostMapping("/{id}/edit")
public String updateUser(
#ModelAttribute("user") User user,
#PathVariable("id") Long id)
{
//user = ur.findOne(id);
user.setId(id);
ur.save(user);
return "redirect:/find/" + user.getUserName();
}

Thymeleaf registration page - Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor'

I'm making a registration page for a website. I understand that in order for a new User to be created, an id is required, so we have the field:
<input type="hidden" th:field="{*id} />
However, when I go to the page, I get the error I mentioned in this post's title.
Here is the form in question:
<form th:action="#{/users/register}" th:object="${user}" class="form-signin" method="POST">
<h2 class="form-signin-heading">Register</h2>
<input type="hidden" th:field="*{id}" />
<label for="inputUsername" class="sr-only">Username*</label>
<input type="text" th:field="*{username}" name="username" id="inputUsername" class="form-control" placeholder="Username" required="required" autofocus="autofocus" />
<label for="inputEmail" class="sr-only">Email Address*</label>
<input type="text" th:field="*{email}" name="email" id="inputEmail" class="form-control" placeholder="Email address" required="required" autofocus="autofocus" />
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" th:field="*{password}" name="password" id="inputPassword" class="form-control" placeholder="Password" required="required" />
<label for="inputConfirmPassword" class="sr-only">Confirm Password</label>
<input type="password" th:field="${confirmPassword}" name="confirmPassword" id="inputConfirmPassword" class="form-control" placeholder="Confirm password" required="required" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
</form>
Here is my UserController:
#RequestMapping("/register")
public String registerAction(Model model) {
model.addAttribute("user", new User());
model.addAttribute("confirmPassword", "");
return "views/users/register";
}
#RequestMapping(value="/register", method = RequestMethod.POST)
public String doRegister(User user) {
User savedUser = userService.save(user);
return "redirect:/"; //redirect to homepage
}
And the first part of the User entity:
#Entity
#Table(name = "users")
public class User {
// Default constructor require by JPA
public User() {}
#Column(name = "id")
#Id #GeneratedValue
private Long id;
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
From what I can see, there's nothing wrong here so I'm stuck.
I'm following this example: https://github.com/cfaddict/spring-boot-intro
Any ideas?
The problem is the way you have declared your id property. The field uses a reference type Long which is null. The getter uses a primitive long. When Spring accesses the id field it tries to unbox a null value causing an error. Change your domain class to be
#Entity
#Table(name = "users")
public class User {
// Default constructor required by JPA
public User() {}
#Id
#Column(name = "id")
#GeneratedValue
private Long id;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}
I don't know if you have a class like this
#Controller
#RequestMapping("/users")
public class MyController{
#RequestMapping("/register")
public String registerAction(Model model) {
model.addAttribute("user", new User());
model.addAttribute("confirmPassword", "");
return "views/users/register";
}
#RequestMapping(value="/register", method = RequestMethod.POST)
public String doRegister(User user) {
User savedUser = userService.save(user);
return "redirect:/"; //redirect to homepage
}
}
becouse if you don't have the #RequestMapping("/users") this is a problem becous if you dont have this annotation in you class the correct actione in the thymeleaf templace should be "#{/register}" other wise yon don't have the endpoint pubblished in other words with the methods that you posted you should have a template like this:
<form th:action="#{/register}" th:object="${user}" class="form-signin" method="POST">
<h2 class="form-signin-heading">Register</h2>
<input type="hidden" th:field="*{id}" />
.... should be as you written
<input type="password" th:field="*{confirmPassword}" id="inputConfirmPassword" class="form-control" placeholder="Confirm password" required="required" />
<button class="btn btn-lg btn-primary btn-block" type="submit">Register</button>
</form>
reading beter the your html you probably should have th:field="*{confirmPassword}" and not th:field="${confirmPassword}".
another think that in my opinion don't works is that you repeate name attribute. The my advice is don't repeate and let to thymeleaf the work of build the correct attribute for databinding.

Resources