2. Create Maven Project in Eclipse
3. Configure Data Source Properties
7. Code Spring MVC Controller Class
8. Code Spring Boot Application Class
9. Implement List Products Feature
10. Implement Create Product Feature
11. Implement Edit Product Feature
12. Implement Delete Product Feature
13. Test and package the Spring Boot CRUD Web Application
CREATE TABLE `product` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `brand` varchar(45) NOT NULL, `madein` varchar(45) NOT NULL, `price` float NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;The name of the database schema is sales.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.codejava</groupId> <artifactId>ProductManager</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>As you can see, with Spring Boot we have to specify only few dependencies: Spring Boot Starter Web, Spring Boot Data JPA, Spring Boot ThymeLeaf and MySQL JDBC driver.TIP: Use Spring Boot DevTools for automatic restart so you don't have to manually restart the application during development.And create the main Java package net.codejava.
spring.jpa.hibernate.ddl-auto=none spring.datasource.url=jdbc:mysql://localhost:3306/sales spring.datasource.username=root spring.datasource.password=password logging.level.root=WARNThe first line tells Hibernate to make no changes to the database. And we specify the database connection properties in the next 3 lines (change the values according to your settings). And the last line we set the logging level to WARN to avoid too verbose output in the console.
// copyright www.codejava.net package net.codejava; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class Product { private Long id; private String name; private String brand; private String madein; private float price; protected Product() { } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long getId() { return id; } // other getters and setters are hidden for brevity }This is simple JPA entity class with the class name and field names are identical to column names of the table product in the database, to minimize the annotations used.
package net.codejava; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository<Product, Long> { }As you can see, this interface extends the JpaRepository interface from Spring Data JPA. JpaRepository defines standard CRUD methods, plus JPA-specific operations. We don’t have to write implementation code because Spring Data JPA will generate necessary code at runtime, in form of proxy instances.So the purpose of writing the repository interface is to tell Spring Data JPA about the domain type (Product) and ID type (Long) to work with.
// copyright www.codejava.net package net.codejava; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class ProductService { @Autowired private ProductRepository repo; public List<Product> listAll() { return repo.findAll(); } public void save(Product product) { repo.save(product); } public Product get(long id) { return repo.findById(id).get(); } public void delete(long id) { repo.deleteById(id); } }In this class, we inject an instance of ProductRepository via private field using @Autowired annotation. At runtime, Spring Data JPA will generate a proxy instance of ProductRepository and inject it to the instance of ProductService class.You might see this service class is redundant as it delegates all the calls to ProductRepository. In fact, the business logic would be more complex over time, e.g. calling two or more repository instances.So we create this class for the purpose of extensibility in future.
package net.codejava; import org.springframework.stereotype.Controller; @Controller public class AppController { @Autowired private ProductService service; // handler methods... }As you can see, we inject an instance of the ProductService class to this controller – Spring will automatically create one at runtime. We will write code for the handler methods when implementing each CRUD operation.
Spring Boot E-Commerce Ultimate Course
Learn to Build a complete shopping website using Java, Spring Boot, Thymeleaf, Bootstrap, jQuery and MySQL database
package net.codejava; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class AppMain { public static void main(String[] args) { SpringApplication.run(AppMain.class, args); } }Here, the @SpringBootApplication annotation does all the magic stuffs such as create the web server instance and Spring MVC dispatcher servlet.
@RequestMapping("/") public String viewHomePage(Model model) { List<Product> listProducts = service.listAll(); model.addAttribute("listProducts", listProducts); return "index"; }We use ThymeLeaf instead of JSP, so create the templates directory under src/main/resources to store template files (HTML).Create the index.html file under src/main/resources/templates with the following code:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"/> <title>Product Manager</title> </head> <body> <div align="center"> <h1>Product List</h1> <a href="/new">Create New Product</a> <br/><br/> <table border="1" cellpadding="10"> <thead> <tr> <th>Product ID</th> <th>Name</th> <th>Brand</th> <th>Made In</th> <th>Price</th> <th>Actions</th> </tr> </thead> <tbody> <tr th:each="product : ${listProducts}"> <td th:text="${product.id}">Product ID</td> <td th:text="${product.name}">Name</td> <td th:text="${product.brand}">Brand</td> <td th:text="${product.madein}">Made in</td> <td th:text="${product.price}">Price</td> <td> <a th:href="/@{'/edit/' + ${product.id}}">Edit</a> <a th:href="/@{'/delete/' + ${product.id}}">Delete</a> </td> </tr> </tbody> </table> </div> </body> </html>Now we can run the AppMain class to test our Spring Boot web application. You should see the Spring Boot logo appears in the Console view of Eclipse:Open your web browser and type the URL http://localhost:8080 to see the website’s homepage:You see, the list of products gets displayed nicely – Suppose that you inserted some rows in the product table before.
<a href="/new">Create New Product</a>The relative URL new is handled by the following method in the AppController class:
@RequestMapping("/new") public String showNewProductPage(Model model) { Product product = new Product(); model.addAttribute("product", product); return "new_product"; }For the view, create the new_product.html file with the following code:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8" /> <title>Create New Product</title> </head> <body> <div align="center"> <h1>Create New Product</h1> <br /> <form action="#" th:action="@{/save}" th:object="${product}" method="post"> <table border="0" cellpadding="10"> <tr> <td>Product Name:</td> <td><input type="text" th:field="*{name}" /></td> </tr> <tr> <td>Brand:</td> <td><input type="text" th:field="*{brand}" /></td> </tr> <tr> <td>Made In:</td> <td><input type="text" th:field="*{madein}" /></td> </tr> <tr> <td>Price:</td> <td><input type="text" th:field="*{price}" /></td> </tr> <tr> <td colspan="2"><button type="submit">Save</button> </td> </tr> </table> </form> </div> </body> </html>As you can see, here we use ThymeLeaf syntax for the form instead of Spring form tags. The Create New Product page looks like this:And we need to code another handler method to save the product information into the database:
@RequestMapping(value = "/save", method = RequestMethod.POST) public String saveProduct(@ModelAttribute("product") Product product) { service.save(product); return "redirect:/"; }After the product is inserted into the database, it redirects to the homepage to refresh the product list.
<a th:href="/@{'/edit/' + ${product.id}}">Edit</a>Code the handler method in the controller class as follows:
@RequestMapping("/edit/{id}") public ModelAndView showEditProductPage(@PathVariable(name = "id") int id) { ModelAndView mav = new ModelAndView("edit_product"); Product product = service.get(id); mav.addObject("product", product); return mav; }And code the view page edit_product.html with the following code:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8" /> <title>Edit Product</title> </head> <body> <div align="center"> <h1>Edit Product</h1> <br /> <form action="#" th:action="@{/save}" th:object="${product}" method="post"> <table border="0" cellpadding="10"> <tr> <td>Product ID:</td> <td> <input type="text" th:field="*{id}" readonly="readonly" /> </td> </tr> <tr> <td>Product Name:</td> <td> <input type="text" th:field="*{name}" /> </td> </tr> <tr> <td>Brand:</td> <td><input type="text" th:field="*{brand}" /></td> </tr> <tr> <td>Made In:</td> <td><input type="text" th:field="*{madein}" /></td> </tr> <tr> <td>Price:</td> <td><input type="text" th:field="*{price}" /></td> </tr> <tr> <td colspan="2"><button type="submit">Save</button> </td> </tr> </table> </form> </div> </body> </html>The edit product page should look like this:Click the Save button will update the product information into the database. The handler method saveProduct() is reused in this case.
<a th:href="/@{'/delete/' + ${product.id}}">Delete</a>So code the handler method in the controller class as follows:
@RequestMapping("/delete/{id}") public String deleteProduct(@PathVariable(name = "id") int id) { service.delete(id); return "redirect:/"; }When the user clicks the Delete hyperlink, the corresponding product information is removed from the database, and the home page gets refreshed.
java -jar ProductManager-0.0.1-SNAPSHOT.jarFor your reference, here’s the screenshot of the project structure:That’s how to develop a Spring Boot CRUD application with Spring MVC, Spring Data JPA, ThymeLeaf, Hibernate and MySQL. You can download the sample project in the attachment section below.