Lab#SB00-2: CRUD User
Spring Boot controllerView CRUD User (and Librarian)
📘 Spring Boot Lab#SB00-2: CRUD User (and Librarian)
CRUD
stands for Create
, Read
, Update
, and Delete
- the four basic operations for persistent storage of data.
In the context of a LibraryMangement
, CRUD
operations would allow us to create new users, retrieve information about existing users, update user information, and delete users from the system.
- First, we’ll create our User class and annotate it with @Data, @NoArgsConstructor, and @AllArgsConstructor.
- Next, we’ll create our
UserService
class and annotate it with@Service
. This class will use aHashMap
to store user data, and will expose methods to create, read, update, and delete users. - Next, we’ll create our
UserController
class and annotate it with@Controller
. This class will handle requests to view, create, update, and delete users. We’ll inject theUserService
into the controller using@Autowired
. - Finally, we’ll create our
Thymeleaf
HTML
templates. We’ll create anindex.html
orhome.html
template to display a list of users, acreateUser.html
template to allow users to create new users, and aneditUser.html
template to allow users to edit existing users.
1 Overview
We’ll be using a Java class called User
to represent user data.
The @Data
annotation is used to generate getters, setters, equals, hashCode, and toString methods for the class. The @NoArgsConstructor
and @AllArgsConstructor
annotations are used to generate constructors with no arguments and all arguments, respectively.
We’ll also be using a HashMap
to store user data, with userId
as the key. This will allow us to quickly retrieve user data using the user ID as a lookup key.
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
// generates getters, setters, equals,
// hashCode, and toString methods
@Data
@NoArgsConstructor // generates a no-args constructor
@AllArgsConstructor // generates a constructor with all arguments
public class User {
private String userId;
private String name;
private String address;
private int age;
}
We might implement the CRUD
operations for our LibraryMangement
system:
Create
: To create a new user, we’ll need to generate a unique user ID and create a new User object with the provided user data. We can then add the new User object to our HashMap using the generated user ID as the key.Read
: To retrieve information about an existing user, we’ll need to look up the User object in our HashMap using the user ID as the key.Update
: To update user information, we’ll need to retrieve the User object from our HashMap using the user ID as the key, and then update the relevant properties of the User object.Delete
: To delete a user from the system, we’ll need to remove the User object from our HashMap using the user ID as the key.
2 References
2.1 Library5
2.1.1 Repos
2.1.2 Java Classes
2.1.3 Templates Thynmeleaf
2.2 LibraryManagement: controllerView
3 controllerView
3.1 folder-tree project & domains
3.2 Home
This cycle defines a @Controller
class that handles requests to the URL
"/home"
. When a request
is made, it adds the current date and time to the model
object, and then returns
the name of the view to be rendered.
The view will have access to the “todayDate” attribute and can use it to display the current date and time.
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
@Controller
public class HomeController {
@RequestMapping("/home")
public String gethome(Model model){
model.addAttribute("todayDate", new Date().toString());
return "home";
}
}
4 CRUD: read
4.1 Users
The cycle request-response relies in the @Controller
class called UserController
, which maps
requests
to the "/user/users" URL
.
It uses an @Autowired
UserService
to fetch
a list of users and adds them to the model
, before returning a view called "user/users".
package com.example.myFirstSpring.controller;
import com.example.myFirstSpring.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
@RequestMapping("/users")
public String getAllUsers(Model model){
// fetch all users, add to model
model.addAttribute("users", userService.getAllUsers());
return "user/users";
}
}
Here we will define the @Service class, called UserService
with a method called getAllUsers
, which returns a HashMap
of user
objects.
The HashMap
is populated with 20 fake user objects using a utility method called populateFakeUsers
.
package com.example.myFirstSpring.service;
import com.example.myFirstSpring.model.User;
import com.example.myFirstSpring.utils.Utils;
import org.springframework.stereotype.Service;
import java.util.HashMap;
@Service
public class UserService {
public static HashMap<String, User> users = new HashMap<>();
static {
Utils.populateFakeUsers(20, users);
}
public HashMap<String, User> getAllUsers (){
return users;
}
}
4.1.1 Code source
4.2 Librarians
Like User request-response cyle read
feature (user-case and user-story) we will code the Librarian
.
The Librarian cycle request-response
would function similarly to the User cycle request-response, but with different URLs, controller methods, and service methods tailored to the Librarian entity.
The
LibrarianController
wouldmap
requests to the appropriate URLs, such as"/librarian/librarians"
.These
requests
would be handled by methods in theLibrarianController
, which would call methods from theLibrarianService
to fetch or manipulate data.
The LibrarianService
would contain methods for fetching and manipulating data from the Librarian entity, similar to the UserService for the User entity.
- Templates would also be created for rendering views related to the Librarian entity, using
Thymeleaf
or a similar templating engine.
4.2.1 Code source
5 CRUD: create
5.1 Create book (reference)
In HTML
forms, the name
and id
attributes serve different purposes for form elements:
name
attribute: This attribute defines thename
of the input element, which is used to identify the form data in the request that is sent to the server when the form is submitted. The name attribute is required for all form controls and must be unique within the form.id
attribute: This attribute is used to uniquely identify an HTML element. It can be used to target the element withCSS
orJavaScript
, and can also be used to associate a label with an input element using the for attribute.
The action
attribute is used to specify the URL of the server-side script or class/method that will process the form data when the form is submitted.
This attribute is required for all forms and specifies the location where the form data will be sent.
The method attribute is also used to specify the HTTP
method that will be used to submit the form data, such as GET
or POST
.
The for
attribute is used to associate a label with an input element.
The for
attribute specifies which input element the label belongs to by referring to the id
attribute of the input element.
5.2 Create user
- The client sends a
request
to server-controller by anendpoint
to get the create-user form: Users template
- The server-controller method handles the
request
and sends aresponse
with the create-user form: UserController
- The client renders the create-user form received from server-controller: userForm
<form action="/user/createUser" >
<p>
<label for="name">Name</label>
<input type="text" name="name" id="name"></p>
<p>
<label for="address">address</label>
<input type="text" name="address" id="address"></p>
<p>
<label for="age">age</label>
<input type="number" name="age" id="age" ></p>
<p>
<input type="submit" value="Add new user" />
</form>
- The client sends a
request
to add this newuser
toHashMap
: userForm
- The sever-controller method handles the
request
, saves theuser
object in aHashMap
and redirects the reponse: UserController
6 CRUD: update
6.1 Update book (reference)
6.2 Update user
- The client sends a
request
to server-controller by anendpoint
to get the update-user form: Update user template
- The server-controller method handles the
request
and sends a response with the update-user form: UserController
@RequestMapping("/packedUserForm")
public String packedUserForm(@RequestParam("idFromView") String id ,
Model model){
User userFound = userService.findUserById(id);
if (userFound != null){
model.addAttribute("userFromController", userFound);
model.addAttribute("message", "User found");}
else
model.addAttribute("message", "User not found");
return "user/userToUpdateForm";
}
- The client renders the update-user form received from server-controller: userForm
<form th:action=
"@{updateUser/{idFromView}
(idFromView=${userFromController.idUser})}"
th:object=
"${userFromController}"
method=
"post">
<p>
<label for="userId">User Id</label>
<input type="number" name="userId" id="userId"
th:field="*{userId}" readonly></p>
<p>
<p>
<label for="name">Name</label>
<input type="text" name="name" id="name"
th:field="*{name}"></p>
<p>
<label for="address">Address</label>
<input type="text" name="address" id="address"
th:field="*{address}"></p>
<p>
<label for="Age">Age</label>
<input type="number" name="age" id="age"
th:field="*{age}" ></p>
<input type="submit" value="Update user"/>
</div>
</form>
- The client sends a request to update this
user
toHashMap
: userForm
<form th:action=
"@{updateUser/{idFromView}
(idFromView=${userFromController.idUser})}"
th:object=
"${userFromController}"
method=
"post">
</form>
- The sever-controller method handles the request, updates the
user
object in aHashMap
and redirects the reponse: UserController and UserService
@PostMapping("/updateUser/{idFromView}")
public String updateUser(@PathVariable("idFromView") String id,
User updatedUser) {
User userFound = userService.findUserById(id);
if (userFound != null) {
userService.updateUserByUser(updatedUser);
return "redirect:/user/users";
} else return "user/userNotFound";
}
7 CRUD: delete
- The client sends a
request
to server-controller by anendpoint
to delete a user: Users template
- The server-controller method handles the
request
and sends a response with the result. It could be success (user deleted) or fail (the deletion operation could not be done): UserController
@RequestMapping("/deleteUser")
public String deleteUser(@RequestParam("idFromView") String id) {
User userFound = userService.findUserById(id);
if (userFound != null) {
userService.deleteUserById(id);
return "redirect:/user/users";
} else return "user/userNotFound";
}
The @Controller
uses userService to call @Service
: deleteUserById
:
- The server-controller method after handled the request sends the response: redirects the reponse to users: UserController redirect