java Springboot +JPA+thymeleaf+MySQL小项目


前言

用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>  &nbsp; &nbsp;
					</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>

三、最终效果

在这里插入图片描述

总结

运用了框架做了一个小项目,收货还是挺大的,一步一个脚印,见证自己学习的过程,慢慢进步,最终才能达到自己想要的高度,刚入门的萌新!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值