图书管理系统Spring Boot + Jpa + Thymeleaf +MySQL

目录

一、简介

什么是三层架构?

二、配置文件

三、代码的实现过程

1.启动类

2.数据库层代码

3.继承 JpaRepository 类

4.业务层处理

4.1 BookService接口

5.Controller层中添加接受请求的方法

四、网页搭建

1.主页面搭建

2.查询书籍的跳转页面

3.添加图书的页面

4.修改图书页面

五、总结


一、简介

本文介绍了如何使用JpaThymelaf创建一个增删改查的示例。

让我首先和你们谈谈为什么我喜欢写这种类型的脚手架项目。当我学习一项新技术时,我总是想快速构建一个演示来尝试它的效果。演示越简单,就越容易上手,而且效果最好。在网上搜索相关信息时,总是很麻烦。有些文章写得很好,但没有源代码,而另一些文章有源代码,但文章介绍不太清楚,这使得查找信息有点困难。因此,当我学习Spring Boot时,我会写一些最简单和基本的示例项目。一方面,方便其他朋友以最快的方式了解它。另一方面,如果我的项目需要使用相关技术,我可以在这个示例版本中直接修改或集成它。

现在有很多类型的技术博客,有些喜欢分析源代码,而另一些则倾向于关注基本原理。我最喜欢的是写一些小而漂亮的例子,方便自己和他人。

什么是三层架构?

三层架构是指:视图层View、业务逻辑层Service、数据访问层DAO。
他们分别完成不同的功能。
View层:用于接收用户提交请求的代码
Service层:系统的业务逻辑主要在这里完成
DAO层:直接操作数据库的代码
为了更好的降低各层之间的耦合度,系统的复杂度,在三层架构程序设计中,采用面向抽象编程。即上层对下层的调用,是通过接口实现的。而下层对上层的真正服务提供者,是下层接口的实现类。服务标准(接口)是相同的,服务提供者(实现类)可以更换。 这就实现了层间解耦合。 发生在哪一层的变化,只需更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高。
Controller只负责管理,而Service负责实施。
Controller是管理业务调度和管理跳转的。
Service是管理具体的功能的。
DAO只完成增删改查,虽然可以1-n,n-n,1-1关联,模糊、动态、子查询都可以。但是无论多么复杂的查询,dao只是封装增删改查。至于增删查改如何去实现一个功能,dao是不管的。

dao层:数据访问层
dao层属于一种比较底层,比较基础的操作,具体到对于某个表的增删改查,也就是说某个DAO一定是和数据库的某一张表一一对应的,其中封装了增删改查基本操作,建议DAO只做原子操作,增删改查。
负责与数据库进行联络的一些任务都封装在此,dao层的设计首先是设计dao层的接口,然后在Spring的配置文件中定义此接口的实现类,然后就可以再模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,dao层的数据源配置,以及有关数据库连接参数都在Spring配置文件中进行配置。

service层:服务层
粗略的理解就是对一个或多个DAO进行的再次封装,封装成一个服务,所以这里也就不会是一个原子操作了,需要事物控制。
service层主要负责业务模块的应用逻辑应用设计。同样是首先设计接口,再设计其实现类,接着再Spring的配置文件中配置其实现的关联。这样我们就可以在应用中调用service接口来进行业务处理。service层的业务实,具体要调用已经定义的dao层接口,封装service层业务逻辑有利于通用的业务逻辑的独立性和重复利用性。程序显得非常简洁。

controller层
Controler负责请求转发,接受页面过来的参数,传给Service处理,接到返回值,再传给页面。
controller层负责具体的业务模块流程的控制,在此层要调用service层的接口来控制业务流程,控制的配置也同样是在Spring的配置文件里进行,针对具体的业务流程,会有不同的控制器。我们具体的设计过程可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块。这样不仅使程序结构变得清晰,也大大减少了代码量。
 

二、配置文件

pom.xml 包里面添加 Jpa 和 Thymeleaf 还有SpringBoot的相关包引用

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.1</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>s05-mvc-employee</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>demo</description>
    <properties>
        <java.version>20</java.version>
    </properties>

    <dependencies>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>true</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

在application.properties中添加配置

注意数据库和用户名密码需要更改

spring.datasource.url=jdbc:mysql://localhost:3306/gdka?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username= root
spring.datasource.password= 123456

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect

spring.jpa.hibernate.ddl-auto= update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE

三、代码的实现过程

1.启动类

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

2.数据库层代码

在model层下创建一个图书对象实体类映射数据库表

package com.example.demo.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;


//图书对象实体
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
@Table(name = "books")//数据库表
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "Name")
    private String name;  //图书名
    @Column(name = "Author")
    private String author;  //作者
    @Column(name = "Publisher")
    private String publisher;  //出版社
    @Column(name = "BookType")
    private String bookType;   //图书类型
    @Column(name = "Price")
    private float price;    //价格

}

3.继承 JpaRepository 类

repository层下创建一个继承 JpaRepository 类的BookRepository接口内置的方法可以在里面实现,包括增删改查。

package com.example.demo.repository;
import com.example.demo.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
    List<Book> findByAuthor(String author);
}

4.业务层处理

service层下创建图书业务类和图书接口,在实体类中添加方法实现,服务调用Jpa来实现相关的添加、删除、修改和查询。在实际项目中,服务层处理特定的业务代码。封装service层业务逻辑有利于通用的业务逻辑的独立性和重复利用性,程序显得非常简洁。

package com.example.demo.service.impl;

import com.example.demo.model.Book;
import com.example.demo.repository.BookRepository;
import com.example.demo.service.BookService;
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 BookServiceImpl implements BookService {
    @Autowired
    private BookRepository bookRepository;

    //获取所有图书
    @Override
    public List<Book> getAllBook() {
        return bookRepository.findAll();
    }

    //新增图书
    @Override
    public void addBook(Book book) {
        this.bookRepository.save(book);
    }

    //更新图书
    @Override
    public void updateBook(Book book) {
        bookRepository.saveAndFlush(book);

    }

    //获取指定id的图书
    @Override
    public Book getBookById(long id) {
        //调用数据访问层查找指定id的图书,返回Optional对象
        Optional<Book> optional = bookRepository.findById(id);
        Book book = null;
        if (optional.isPresent()){  //如果指定的id存在
            book = optional.get();  //从Optional对象中获取图书
        }else {   //否则提示找不到图书
            throw new RuntimeException("找不到图书id :" + id);
        }
        return book;
    }

    //删除指定id的图书
    @Override
    public void deleteBookById(long id) {
        this.bookRepository.deleteById(id);

    }

    //分页
    @Override
    public Page<Book> 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.bookRepository.findAll(pageable);
    }

    //获取指定的作者
    @Override
    public Book findByAuthor(String author) {
        return (Book) bookRepository.findByAuthor(author);

    }

}

4.1 BookService接口

service层下的BookService接口对象的方法定义

package com.example.demo.service;

import com.example.demo.model.Book;
import com.example.demo.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;

import java.util.List;
import java.util.Optional;

public interface BookService {

    //获取所有图书
    List<Book> getAllBook();

    //新增图书
    void addBook(Book book);

    //更新图书
    void updateBook(Book book);

    //获取指定id的图书
    Book getBookById(long id);

    //删除指定id的图书
    void deleteBookById(long id);

    //分页
    Page<Book> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);


    //获取指定的作者的图书
    Book findByAuthor(String author);


}

5.Controller层中添加接受请求的方法

Controller 负责接收请求,处理完后将页面内容返回给前端。

package com.example.demo.controller;

import com.example.demo.model.Book;
import com.example.demo.repository.BookRepository;
import com.example.demo.service.BookService;
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 BookController {

    @Autowired
    private BookService bookService;

    //首页
    @GetMapping("/")
    public String index(Model model){
        return findPaginated(1,"name","asc", model);

    }
    //新增图书页
    @GetMapping("/showNewBookForm")
    public String showNewBookForm(Model model){
        //创建模型属性来绑定表单数据
        Book book = new Book();
        model.addAttribute("book",book);
        return "increase_book";
    }

    //新增图书页
    @PostMapping("/addBook")
    public String addBook(@ModelAttribute("book") Book book){
        //将图书保存到数据库
        bookService.addBook(book);
        return "redirect:/";
    }

    //更新图书信息页
    @GetMapping("/updateBook/{id}")
    public String updateBook(@PathVariable(value = "id") long id, Model model){
        //从BookService中获取员工
        Book book = bookService.getBookById(id);

        //将book设置为模型属性预填充表单
        model.addAttribute("book", book);
        return "update_book";
    }

    //删除指定id的图书
    @GetMapping("/deleteBook/{id}")
    public String deleteBook(@PathVariable(value = "id") long id){
        this.bookService.deleteBookById(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 = 7;  //每页7条数据
        Page<Book> page = bookService.findPaginated(pageNo, pageSize, sortField, sortDir);
        List<Book> listBook = 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("listBook",listBook);
        return "index";
    }
    
    @Autowired
    private BookRepository bookRepository;

    //获取所有书
    @GetMapping("/books")
    public String getBooks(Model model){
        List<Book> books = bookRepository.findAll();
        model.addAttribute("books",books);
        return "search";
    }

//    //查询指定的作者
    @PostMapping("/books/search")
    public String searchBook(@RequestParam("author") String author, Model model) {
        List<Book> books = bookRepository.findByAuthor(author);
        model.addAttribute("books",books);

        return "search";
    }


}

四、网页搭建

1.主页面搭建

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="ISO-8859-1">
    <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 text-success">图书管理系统</h1>

    <form class="form-inline" th:action="@{/books/search}" method="post">
        <div class="form-group mb-2">
            <a th:href="@{/showNewBookForm}" class="btn btn-primary mb-2">添加图书信息</a>
        </div>
        <div class="form-group mx-sm-3 mb-2">
            <input type="text" class="form-control" name="author" placeholder="作者">
        </div>
        <button type="submit" class="btn btn-info mb-2" style="width:100px">查询</button>
    </form>

    <table border="1" class="table table-striped table-responsive-md table-active">
        <thead class="thead-light">
            <tr>
                <th><a th:href="@{'/page/' + ${currentPage} + '?sortField=id&sortDir=' + ${reverseSortDir}}">id</a></th>
                <th width="150"><a th:href="@{'/page/' + ${currentPage} + '?sortField=name&sortDir=' + ${reverseSortDir}}">书名</a></th>
                <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=author&sortDir=' + ${reverseSortDir}}">作者</a></th>
                <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=publisher&sortDir=' + ${reverseSortDir}}">出版社</a></th>
                <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=bookType&sortDir=' + ${reverseSortDir}}">图书类型</a></th>
                <th><a th:href="@{'/page/' + ${currentPage} + '?sortField=price&sortDir=' + ${reverseSortDir}}">价格</a></th>
                <th>操作</th>
            </tr>
        </thead>

        <tbody>
        <tr th:each="book : ${listBook}">
            <td th:text="${book.id}"></td>
            <td th:text="${book.name}"></td>
            <td th:text="${book.author}"></td>
            <td th:text="${book.publisher}"></td>
            <td th:text="${book.bookType}"></td>
            <td th:text="${book.price}"></td>
            <td>
                <a th:href="@{/updateBook/{id}(id=${book.id})}" class="btn btn-warning btn-xs">修改</a>
                <a th:href="@{/deleteBook/{id}(id=${book.id})}" class="btn btn-success btn-xs">删除</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="pagination justify-content-end" >
					<span th:each="i: ${#numbers.sequence(1, totalPages)}" class="page-item">
						<a th:if="${currentPage != i}" th:href="@{'/page/' + ${i}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}" class="page-link">[[${i}]]</a>
						<span th:unless="${currentPage != i}" class="page-link">[[${i}]]</span>  &nbsp; &nbsp;
					</span>
            </div>

            <div >
                <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${currentPage + 1}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}" class="page-link">下一页</a>
                <span th:unless="${currentPage < totalPages}" class="page-link">下一页</span>
            </div>

            <div >
                <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}" class="page-link">最后一页</a>
                <span th:unless="${currentPage < totalPages}" class="page-link">最后一页</span>
            </div>
        </div>
    </div>

</div>
</body>
</html>

2.查询书籍的跳转页面

<!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 text-success">图书管理系统</h1>

    <form class="form-inline" th:action="@{/books/search}" method="post">
        <div class="form-group mb-2">
            <a th:href="@{/showNewBookForm}" class="btn btn-primary mb-2">添加图书信息</a>
        </div>
        <div class="form-group mx-sm-3 mb-2">
            <input type="text" class="form-control" name="author" placeholder="作者">
        </div>
        <button type="submit" class="btn btn-info mb-2" style="width:100px">查询</button>
        <a type="submit" class="btn btn-primary mb-2" th:href="@{/}">重置</a>
    </form>

    <table border="1" class="table table-striped table-responsive-md table-active">
        <thead class="thead-light">
        <tr>
            <th><a th:href="@{'/page/' + ${currentPage} + '?sortField=id&sortDir=' + ${reverseSortDir}}">id</a></th>
            <th width="150"><a th:href="@{'/page/' + ${currentPage} + '?sortField=name&sortDir=' + ${reverseSortDir}}">书名</a></th>
            <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=author&sortDir=' + ${reverseSortDir}}">作者</a></th>
            <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=publisher&sortDir=' + ${reverseSortDir}}">出版社</a></th>
            <th width="200"><a th:href="@{'/page/' + ${currentPage} + '?sortField=bookType&sortDir=' + ${reverseSortDir}}">图书类型</a></th>
            <th><a th:href="@{'/page/' + ${currentPage} + '?sortField=price&sortDir=' + ${reverseSortDir}}">价格</a></th>
            <th>操作</th>
        </tr>

        </thead>
        <tbody>
        <tr th:each="book : ${books}">
            <td th:text="${book.id}"></td>
            <td th:text="${book.name}"></td>
            <td th:text="${book.author}"></td>
            <td th:text="${book.publisher}"></td>
            <td th:text="${book.bookType}"></td>
            <td th:text="${book.price}"></td>
            <td>
                <a th:href="@{/updateBook/{id}(id=${book.id})}" class="btn btn-warning btn-xs">修改</a>
                <a th:href="@{/deleteBook/{id}(id=${book.id})}" class="btn btn-success btn-xs">删除</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}}">下一页</a>
                <span th:unless="${currentPage < totalPages}">下一页</span>
            </div>

            <div class="col-sm-1">
                <a th:if="${currentPage < totalPages}" th:href="@{'/page/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">最后一页</a>
                <span th:unless="${currentPage < totalPages}">最后一页</span>
            </div>
        </div>
    </div>
</div>
</body>
</html>

3.添加图书的页面

<!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">
  <h1>添加图书页面</h1>
  <hr>
  <h2>添加图书</h2>
  <form action="#" th:action="@{/addBook}" th:object="${book}" method="POST">
    <input type="text" th:field="*{name}" placeholder="书名" class="form-control mb-4 col-4">
    <input type="text" th:field="*{author}" placeholder="作者" class="form-control mb-4 col-4">
    <input type="text" th:field="*{publisher}" placeholder="出版社" class="form-control mb-4 col-4">
    <input type="text" th:field="*{bookType}" placeholder="图书类型" class="form-control mb-4 col-4">
    <input type="text" th:field="*{price}" placeholder="价格" 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>

4.修改图书页面

<!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">
    <h1>修改图书信息页面</h1>
    <hr>
    <h2>修改信息</h2>
    <form action="#" th:action="@{/addBook}" th:object="${book}" method="POST">
        <input type="hidden" th:field="*{id}" />
        <input type="text" th:field="*{name}" placeholder="书名" class="form-control mb-4 col-4">
        <input type="text" th:field="*{author}" placeholder="作者" class="form-control mb-4 col-4">
        <input type="text" th:field="*{publisher}" placeholder="出版社" class="form-control mb-4 col-4">
        <input type="text" th:field="*{bookType}" placeholder="图书类型" class="form-control mb-4 col-4">
        <input type="text" th:field="*{price}" placeholder="价格" class="form-control mb-4 col-4">

        <button type="submit" class="btn btn-info col-2">修改图书信息</button>
    </form>
    <a th:href="@{/}">返回首页</a>
</div>
</body>
</html>

五、总结

以上就是我用java+Springboot +JPA+thymeleaf+MySQL技术框架来创建图书管理系统的全部过程。虽然这些技术比较过时,语法很冗余,Thymeleaf其实就是一个模块引擎 直接套就好了 Jpa 是spring家族自己的持久层框架,可以理解为类似于mybatis,但是本人的学识比较浅还掌握不了这门技术,如果能实现Springboot+vue+mybatis+mysql技术来创建我的图书管理系统就很好。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的 Spring Boot + Vue 图书管理示例。 首先,我们需要创建一个 Spring Boot 项目并添加必要的依赖项: 1. 在 https://start.spring.io/ 上创建一个新的 Spring Boot 项目,选择 Web, JPA, MySQLThymeleaf 依赖。 2. 在 pom.xml 文件中添加以下依赖项: ```xml <!-- MySQL 驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> </dependency> <!-- Thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> ``` 接下来,我们需要创建一个 Book 实体类和一个 BookRepository 接口来与数据库交互,以及一个 BookController 类来处理 HTTP 请求。 1. 创建 Book 实体类: ```java @Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private String author; // getters and setters } ``` 2. 创建 BookRepository 接口: ```java @Repository public interface BookRepository extends JpaRepository<Book, Long> { } ``` 3. 创建 BookController 类: ```java @Controller public class BookController { @Autowired private BookRepository bookRepository; @GetMapping("/") public String index(Model model) { List<Book> books = bookRepository.findAll(); model.addAttribute("books", books); return "index"; } @GetMapping("/add") public String addForm(Model model) { model.addAttribute("book", new Book()); return "add"; } @PostMapping("/add") public String addSubmit(@ModelAttribute Book book) { bookRepository.save(book); return "redirect:/"; } } ``` 现在我们已经完成了后端部分,接下来我们需要创建一个 Vue 前端界面来显示和添加图书。 1. 创建一个 `src/main/resources/static` 目录,并在其中创建一个 `index.html` 文件,用于渲染 Vue 应用。 ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Book Management</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <h1>Book Management</h1> <div v-if="books.length === 0"> <p>No books found.</p> </div> <table v-else> <thead> <tr> <th>Title</th> <th>Author</th> </tr> </thead> <tbody> <tr v-for="book in books"> <td>{{book.title}}</td> <td>{{book.author}}</td> </tr> </tbody> </table> <button @click="addForm">Add Book</button> <div v-if="showAddForm"> <form @submit.prevent="addBook"> <div> <label>Title:</label> <input v-model="newBook.title" required> </div> <div> <label>Author:</label> <input v-model="newBook.author" required> </div> <div> <button type="submit">Add</button> <button type="button" @click="cancelAdd">Cancel</button> </div> </form> </div> </div> <script src="/js/app.js"></script> </body> </html> ``` 2. 在 `src/main/resources/static` 目录中创建一个 `js` 目录,并在其中创建一个 `app.js` 文件。这个文件将包含我们的 Vue 应用程序。 ```js new Vue({ el: '#app', data: { books: [], showAddForm: false, newBook: { title: '', author: '' } }, mounted() { this.fetchBooks(); }, methods: { fetchBooks() { fetch('/api/books') .then(response => response.json()) .then(data => { this.books = data; }); }, addForm() { this.showAddForm = true; }, cancelAdd() { this.showAddForm = false; this.newBook.title = ''; this.newBook.author = ''; }, addBook() { const data = { title: this.newBook.title, author: this.newBook.author }; fetch('/api/books', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => { if (response.ok) { this.fetchBooks(); this.showAddForm = false; this.newBook.title = ''; this.newBook.author = ''; } }); } } }); ``` 现在,我们已经完成了整个项目。启动 Spring Boot 应用程序,然后在浏览器中访问 http://localhost:8080 即可看到图书列表和添加图书的表单。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值