文章目录
前言
用java Springboot +JPA+thymeleaf+MySQL做一个小项目
一、springboot
SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率
二、项目
1、控制器
MVC的核心就是Controller(控制器),它负责处理客户端(常常是浏览器)发送来的所有请求,并决定将什么内容响应给客户端,通过这种方式,Controller负责响应用户的输入,并且在响应时修改Model,把数据输出到相关的View。MVC架构中的Controller主要关注应用程序流入、输入数据的处理,以及提供向View输出的数据。
控制器(Controller)本身是一个派生于Controller的类,这个类包含有多个方法,这些方法中声明为public的即被当作动作(Action),可以通过这些Action接收网页请求并决定应用的视图(View)。
import com.example.productmanagement.module.Product;
import com.example.productmanagement.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/")
public String viewHomePage(Model model) {
return findPaginated(1, "name", "asc", model);
}
@GetMapping("/showNewProductForm")
public String showNewProductForm(Model model) {
// create model attribute to bind form data
Product product = new Product();
model.addAttribute("product", product);
return "new_product";
}
@PostMapping("/saveProduct")
public String saveProduct(@ModelAttribute("product") Product product) {
// save book to database
productService.saveProduct(product);
return "redirect:/";
}
@GetMapping("/showFormForUpdate/{id}")
public String showFormForUpdate(@PathVariable(value = "id") long id, Model model) {
// get employee from the service;
Product product = productService.getProductById(id);
// set book as a model attribute to pre-populate the form
model.addAttribute("product", product);
return "update_product";
}
@GetMapping("/queryProduct{name}")
public String find(@PathVariable(value = "name") String name,Model model){
List<Product> listProduct = productService.findByProductName(name);
model.addAttribute("listProducts",listProduct);
return "index";
}
@GetMapping("/deleteProduct/{id}")
public String deleteProduct(@PathVariable(value = "id") long id) {
// call delete employee method
this.productService.deleteProductById(id);
return "redirect:/";
}
//获取分页数据
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 5;
Page<Product> page = productService.findPaginated(pageNo, pageSize, sortField, sortDir);
List<Product> listProducts = page.getContent();
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("listProducts", listProducts);
return "index";
}
}
2.模型类
模型:主要包含业务数据和业务逻辑。在模型层,还会涉及到用户发布的服务,在服务中会根据不同的业务需求,更新业务模型中的数据。
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "name")
private String name;
@Column(name = "type")
private String type;
@Column(name = "status")
private String status;
}
3.repository接口
JpaRepository:是PagingAndSortingRepository的子接口,将上面三个接口的返回值做了优化,方便调用时返回结果集。
import com.example.productmanagement.module.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ProductRepository extends JpaRepository<Product,Long> {
@Query("select p from Product p where p.name like %:name%")
List<Product> findAllByProductName(@Param("name") String name) ;
}
4.service层
service层里主要是业务实现类
import com.example.productmanagement.module.Product;
import org.springframework.data.domain.Page;
import java.util.List;
public interface ProductService {
List<Product> getAllProducts();
//新增/更新
void saveProduct(Product product);
//查找指定ID
Product getProductById(long id);
//删除指定书籍
void deleteProductById(long id);
//查找书籍
List<Product> findByProductName(String name);
//分页
Page<Product> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
import com.example.productmanagement.module.Product;
import com.example.productmanagement.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class ProductServicelmpl implements ProductService{
@Autowired
private ProductRepository productRepository;
@Override
public List<Product> getAllProducts() {
return productRepository.findAll();
}
@Override
public void saveProduct(Product product) {
this.productRepository.save(product);
}
@Override
public Product getProductById(long id) {
Optional<Product> optional = productRepository.findById(id);
Product product = null;
if (optional.isPresent()){
product = optional.get();
}else {
throw new RuntimeException(" 找不到商品id::" + id);
}
return product;
}
@Override
public void deleteProductById(long id) {
this.productRepository.deleteById(id);
}
@Override
public List<Product> findByProductName(String name) {
List<Product> optional1 = productRepository.findAllByProductName(name);
return optional1;
}
@Override
public Page<Product> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
//设置排序参数,升序ASC/降序DESC?
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortField).ascending()
: Sort.by(sortField).descending();
//根据页号/每页记录数/排序依据返回某指定页面数据。
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
return this.productRepository.findAll(pageable);
}
}
5.index.html
视图:呈现给用户的部分,是用户和程序交互的接口,用户会根据具体的业务需求,在View视图层输入自己特定的业务数据,并通过界面的事件交互,将对应的输入参数提交给后台控制器进行处理。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>商品管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container my-2">
<h1 class="text-center">商品列表</h1>
<div class="container my-2">
<a th:href = "@{/showNewProductForm}" class="btn btn-primary btn-sm mb-3"> 添加商品 </a>
<form id="query-from" action="/queryProduct" method="get">
<input type="text" id="name-input" name="" placeholder="product name">
<button type="button" onclick="quer()">查找</button>
</form>
<script>
function quer(){
var name = document.getElementById("name-input").value;
var url = "/queryProduct"+ encodeURIComponent(name);
window.location.href = url;
}
</script>
</div>
<table border="1" class = "table table-striped table-responsive-md">
<thead >
<tr>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=name&sortDir=' + ${reverseSortDir}}">
name</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=type&sortDir=' + ${reverseSortDir}}">
type</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=status&sortDir=' + ${reverseSortDir}}">
status</a>
</th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${listProducts}">
<td th:text="${product.name}"></td>
<td th:text="${product.type}"></td>
<td th:text="${product.status}"></td>
<td> <a th:href="@{/showFormForUpdate/{id}(id=${product.id})}" type="button" class="btn btn-success">Update</a>
<a th:href="@{/deleteProduct/{id}(id=${product.id})}" type="button" class="btn btn-warning">Delete</a>
</td>
</tr>
</tbody>
</table>
<div th:if = "${totalPages > 1}">
<div class = "row col-sm-10">
<div class = "col-sm-3">
Total Rows: [[${totalItems}]]
</div>
<div class = "col-sm-5">
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
<a th:if="${currentPage != i}" th:href="@{'/page/' + ${i}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">[[${i}]]</a>
<span th:unless="${currentPage != i}">[[${i}]]</span>
</span>
</div>
<div class = "col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${currentPage + 1}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Next</a>
<span th:unless="${currentPage < totalPages}">Next</span>
</div>
<div class="col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Last</a>
<span th:unless="${currentPage < totalPages}">Last</span>
</div>
</div>
</div>
</div>
</body>
</html>
6.new_product.html
这是点击添加按钮跳转到的html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>商品管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>商品管理系统</h1>
<hr>
<h2>保存商品</h2>
<form action="#" th:action="@{/saveProduct}" th:object="${product}" method="POST">
<input type="text" th:field="*{name}" placeholder="Product title" class="form-control mb-4 col-4">
<input type="text" th:field="*{type}" placeholder="Product author" class="form-control mb-4 col-4">
<input type="text" th:field="*{status}" placeholder="Product price" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> 保存商品</button>
</form>
<hr>
<a th:href="@{/}"> 返回商品列表 </a>
</div>
</body>
</html>
7.update_product.html
这是点击更新按钮要跳转到的html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>商品管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>商品管理系统</h1>
<hr>
<h2>更新商品</h2>
<form action="#" th:action="@{/saveProduct}" th:object="${product}" method="POST">
<input type="hidden" th:field="*{id}"/>
<input type="text" th:field="*{name}" class="form-control mb-4 col-4">
<input type="text" th:field="*{type}" class="form-control mb-4 col-4">
<input type="text" th:field="*{status}" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> 更新商品</button>
</form>
<hr>
<a th:href="@{/}"> 返回商品列表</a>
</div>
</body>
</html>
三、最终效果
总结
运用了框架做了一个小项目,收货还是挺大的,一步一个脚印,见证自己学习的过程,慢慢进步,最终才能达到自己想要的高度,刚入门的萌新!!!