JAVA极简图书管理系统,初识springboot后端项目

前提条件:

具备基础的springboot 知识

Java基础

废话不多说!

创建项目

配置所需环境

将application.properties==>application.yml   配置以下环境

数据库连接MySQL

自己创建的数据库名称为book_test


server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/book_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  mvc:
    hiddenmethod:
      filter:
        enabled: true

mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

#一直出现的问题:引入依赖包的问题

 追加两个依赖使得可以使用mapper-locations

数据库准备

图书以及简单的用户信息

CREATE TABLE `book_info` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`book_name` VARCHAR(127) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
	`author` VARCHAR(127) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
	`count` INT(10) NULL DEFAULT NULL,
	`price` DECIMAL(7,2) NOT NULL,
	`publish` VARCHAR(256) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
	`status` TINYINT(3) NULL DEFAULT '1' COMMENT '0-⽆效, 1-正常, 2-不允许借阅',
	`create_time` DATETIME NULL DEFAULT 'CURRENT_TIMESTAMP',
	`update_time` DATETIME NULL DEFAULT 'CURRENT_TIMESTAMP' ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=25
;

CREATE TABLE `user_info` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`user_name` VARCHAR(128) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
	`password` VARCHAR(128) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
	`delete_flag` TINYINT(3) NULL DEFAULT '0',
	`create_time` DATETIME NULL DEFAULT 'CURRENT_TIMESTAMP',
	`update_time` DATETIME NULL DEFAULT 'CURRENT_TIMESTAMP' ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`) USING BTREE,
	UNIQUE INDEX `user_name_UNIQUE` (`user_name`) USING BTREE
)
COMMENT='用户表'
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=3
;

 

spring MVC 运行逻辑

Mapper ==> Service ==> Controller

mapper接口层代码:


    @Insert("INSERT INTO book_info (book_name, author, count, price, publish, status, create_time, update_time) VALUES " +
            "(#{bookName}, #{author}, #{count}, #{price}, #{publish}, #{status}, #{createTime}, #{updateTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insertBook(BookInfo book);

    @Select("SELECT id, book_name AS bookName, author, count, price, publish, status, " +
            "CASE status WHEN 0 THEN '无效' WHEN 1 THEN '允许借阅' ELSE '不允许借阅' END AS statusCN, " +
            "create_time, update_time FROM book_info WHERE id = #{id}")
    @Results(id = "bookResultMap", value = {
            @Result(property = "id", column = "id"),
            @Result(property = "bookName", column = "bookName"),
            @Result(property = "author", column = "author"),
            @Result(property = "count", column = "count"),
            @Result(property = "price", column = "price"),
            @Result(property = "publish", column = "publish"),
            @Result(property = "status", column = "status"),
            @Result(property = "statusCN", column = "statusCN"),
            @Result(property = "createTime", column = "create_time"),
            @Result(property = "updateTime", column = "update_time")
    })
    BookInfo selectBookById(Integer id);

    @Update("UPDATE book_info SET book_name = #{bookName}, author = #{author}, count = #{count}, price = #{price}, " +
            "publish = #{publish}, status = #{status}, update_time = #{updateTime} WHERE id = #{id}")
    int updateBook(BookInfo book);

    @Delete("DELETE FROM book_info WHERE id = #{id}")
    int deleteBook(Integer id);

    @Select("SELECT * FROM book_info")
    List<BookInfo> selectAllBooks();

    List<BookInfo> mockData();

创建用户bookinfo


@RequestMapping("/user")
@RestController
public class UserController {
    @RequestMapping("/login")
    public boolean login(String name, String password, HttpSession session){
        //账号或密码为空
        if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
            return false;
        }
        //模拟验证数据, 账号密码正确
        if("admin".equals(name) && "admin".equals(password)){
            session.setAttribute("userName",name);
            return true;
        }
        //账号密码错误
        return false;
    }

@Data
public class BookInfo {
    //图书ID
    private Integer id;
    //书名
    private String bookName;
    //作者
    private String author;
    //数量
    private Integer count;
    //定价
    private BigDecimal price;
    //出版社
    private String publish;
    //状态 0-⽆效 1-允许借阅 2-不允许借阅
    private Integer status;
    private String statusCN;
    //创建时间
    private Date createTime;
    //更新时间
    private Date updateTime;
}

service层面:

  /**
     * 添加图书
     * @param book 图书信息
     * @return 操作结果,成功返回true,失败返回false
     */
    boolean addBook(BookInfo book);

    /**
     * 根据ID查询图书
     * @param id 图书ID
     * @return 图书信息
     */
    BookInfo getBookById(Integer id);

    /**
     * 更新图书信息
     * @param book 图书信息
     * @return 操作结果,成功返回true,失败返回false
     */
    boolean updateBook(BookInfo book);

    /**
     * 删除图书
     * @param id 图书ID
     * @return 操作结果,成功返回true,失败返回false
     */
    boolean deleteBook(Integer id);

    /**
     * 获取所有图书列表
     * @return 图书列表
     */
    List<BookInfo> getAllBooks();

接口层的实现

 private BookInfoMapper bookMapper;

    @Override
    public boolean addBook(BookInfo book) {
        // 可以在这里添加业务逻辑校验,例如检查图书信息是否完整
        int rowsAffected = bookMapper.insertBook(book);
        return rowsAffected > 0;
    }

    @Override
    public BookInfo getBookById(Integer id) {
        return bookMapper.selectBookById(id);
    }

    @Override
    public boolean updateBook(BookInfo book) {
        // 业务逻辑校验,例如确保ID不为空且存在对应的图书记录
        int rowsAffected = bookMapper.updateBook(book);
        return rowsAffected > 0;
    }

    @Override
    public boolean deleteBook(Integer id) {
        // 可以添加逻辑判断,比如检查图书是否已被借阅不能删除
        int rowsAffected = bookMapper.deleteBook(id);
        return rowsAffected > 0;
    }

    @Override
    public List<BookInfo> getAllBooks() {
        return bookMapper.selectAllBooks();
    }

控制层面:

@Autowired
    private BookService bookService;

    // 添加图书
    @PostMapping("/add")
    public ResponseEntity<ResponseMessage> addBook(@RequestBody BookInfo book) {
//        boolean isAdded = bookService.addBook(book);
//        if (isAdded) {
//            return ResponseEntity.status(200).body(book);
//        } else {
//            return ResponseEntity.badRequest().build();
//        }
        try {
            boolean isAdded = bookService.addBook(book);
            if (isAdded) {
                // 创建ResponseMessage实例,表示成功
                ResponseMessage response = new ResponseMessage(200, "图书添加成功", book);
                return ResponseEntity.ok(response); // 注意这里返回的是ResponseEntity<ResponseMessage>
            } else {
                // 创建ResponseMessage实例,表示失败
                ResponseMessage response = new ResponseMessage(400, "图书添加失败,请检查输入信息", null);
                return ResponseEntity.badRequest().body(response); // 同样返回ResponseEntity<ResponseMessage>
            }
        } catch (Exception e) {
            // 异常处理,返回错误信息
            ResponseMessage response = new ResponseMessage(500, "添加图书时发生系统错误: " + e.getMessage(), null);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
        }
    }

    // 根据ID获取图书信息
    @GetMapping("/{id}")
    public ResponseEntity<BookInfo> getBookById(@PathVariable Integer id) {
        BookInfo book = bookService.getBookById(id);
        if (book != null) {
            return ResponseEntity.ok(book);
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    // 更新图书信息
    @PutMapping("/{id}")
    public ResponseEntity<Void> updateBook(@PathVariable Integer id, @RequestBody BookInfo book) {
        book.setId(id); // 确保请求体中的ID与路径变量ID一致
        boolean isUpdated = bookService.updateBook(book);
        if (isUpdated) {
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    // 删除图书
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteBook(@PathVariable Integer id) {
        boolean isDeleted = bookService.deleteBook(id);
        if (isDeleted) {
            return ResponseEntity.noContent().build();
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    // 获取所有图书列表
    @GetMapping
    public ResponseEntity<List<BookInfo>> getAllBooks() {
        List<BookInfo> books = bookService.getAllBooks();
        return ResponseEntity.ok(books);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public ResponseMessage(int code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    private int code; // 状态码,200表示成功,非200表示各种错误
    private String message; // 描述信息
    private Object data; // 可选,成功时返回的数据或错误时的额外信息

后端结束

前台交互

增加图书:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>添加图书</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/add.css">

</head>

<body>

    <div class="container">

        <div class="form-inline">
            <h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"
                    fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16">
                    <path
                        d="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" />
                </svg>
                <span>添加图书</span>
            </h2>
        </div>

        <form id="addBook">
            <div class="form-group">
                <label for="bookName">图书名称:</label>
                <input type="text" class="form-control" placeholder="请输入图书名称" id="bookName" name="bookName">
            </div>
            <div class="form-group">
                <label for="bookAuthor">图书作者</label>
                <input type="text" class="form-control" placeholder="请输入图书作者" id="bookAuthor" name="author" />
            </div>
            <div class="form-group">
                <label for="bookStock">图书库存</label>
                <input type="text" class="form-control" placeholder="请输入图书库存" id="bookStock" name="count"/>
            </div>

            <div class="form-group">
                <label for="bookPrice">图书定价:</label>
                <input type="number" class="form-control" placeholder="请输入价格" id="bookPrice" name="price">
            </div>

            <div class="form-group">
                <label for="bookPublisher">出版社</label>
                <input type="text" id="bookPublisher" class="form-control" placeholder="请输入图书出版社" name="publish" />
            </div>
            <div class="form-group">
                <label for="bookStatus">图书状态</label>
                <select class="custom-select" id="bookStatus" name="status">
                    <option value="1" selected>可借阅</option>
                    <option value="2">不可借阅</option>
                </select>
            </div>

            <div class="form-group" style="text-align: right">
                <button type="button" class="btn btn-info btn-lg" onclick="add()">确定</button>
                <button type="button" class="btn btn-secondary btn-lg" onclick="history.back()">返回</button>
            </div>
        </form>
    </div>
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script>
        function add() {
            // 收集表单数据
            const formData = {
                bookName: $("#bookName").val(),
                author: $("#bookAuthor").val(),
                count: $("#bookStock").val(),
                price: $("#bookPrice").val(),
                publish: $("#bookPublisher").val(),
                status: $("#bookStatus").val()
            };

            // 使用Ajax发送数据到后端
            $.ajax({
                type: "POST",
                url: "/book/add", //请替换为您的后端接口地址
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify(formData),
                success: function(response) {
                    if(response.code === 200 || response.code === 201) { // 假设200或201都表示成功
                        // alert(response.code);
                        alert("添加成功");

                        location.href = "book_list.html"; // 添加成功后跳转到列表页
                    } else {
                        alert("添加失败:" + response.message);
                    }
                },
                error: function(xhr, status, error) {
                    alert("添加图书时发生错误: " + error);
                }
            });
        }
    </script>
</body>

</html>

图书列表:展示所有图书

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书列表展示</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/list.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/bootstrap.min.js"></script>
    <script src="js/jq-paginator.js"></script>
</head>

<body>
<div class="bookContainer">
    <h2>图书列表展示</h2>
    <div class="navbar-justify-between">
        <div>
            <button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
            <button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
        </div>
    </div>

    <table class="table">
        <thead>
        <tr>
            <th><label for="selectAllBooks"></label><input type="checkbox" id="selectAllBooks"></th>
            <th>ID</th>
            <th>书名</th>
            <th>作者</th>
            <th>数量</th>
            <th>定价</th>
            <th>出版社</th>
            <th>状态</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        </tbody>
    </table>

    <div class="demo">
        <ul id="pageContainer" class="pagination justify-content-center"></ul>
    </div>

    <script>
        $(document).ready(function() {
            getBookList();
            $("#selectAllBooks").click(function() {
                $("input[name='selectBook']").prop('checked', this.checked);
            });
        });

        function getBookList() {
            $.ajax({
                type: "get",
                url: "/book"+location.search,
                success: function (result) {
                    console.log(result);
                    if (result != null) {
                        let finalHtml = "";
                        for (const book of result) {
                            finalHtml += '<tr>';
                            finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '"></td>'; // 修正了value属性的遗漏
                            finalHtml += '<td>' + book.id + '</td>';
                            finalHtml += '<td>' + book.bookName + '</td>';
                            finalHtml += '<td>' + book.author + '</td>';
                            finalHtml += '<td>' + book.count + '</td>';
                            finalHtml += '<td>' + book.price + '</td>';
                            finalHtml += '<td>' + book.publish + '</td>';
                            finalHtml += '<td>' + book.statusCN + '</td>';
                            finalHtml += '<td><div class="op">';
                            finalHtml += '<a href="book_update.html?bookId=' + book.id + '" class="btn btn-sm btn-primary">编辑</a>'; // 修正了链接的闭合
                            finalHtml += '<button class="btn btn-sm btn-danger" onclick="deleteBook(' + book.id + ')">删除</button>';
                            finalHtml += '</div></td>';
                            finalHtml += '</tr>';
                        }
                        $("tbody").html(finalHtml);
                    }
                }
            });
        }


        function deleteBook(id) {
            const isDelete = confirm("确认删除?");
            if (isDelete) {
                $.ajax({
                    type: "DELETE",
                    url: "/book/" + id,
                    success: function() {
                        alert("删除成功");
                        // 刷新页面以反映删除后的数据变化
                        getBookList();
                        location.reload();
                    },
                    error: function(xhr, status, error) {
                        if (xhr.status === 404) {
                            alert("图书不存在");
                        } else {
                            alert("删除失败: " + error);
                        }
                    }
                });
            }
        }



        function batchDelete() {
            const isDelete = confirm("确认批量删除?");
            if (isDelete) {
                //获取复选框的id
                const ids = [];
                $("input:checkbox[name='selectBook']:checked").each(function () {
                    ids.push($(this).val());
                });
                console.log(ids);
                alert("批量删除成功");
            }
        }
    </script>
</div>
</body>

</html>

修改图书

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>修改图书</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/add.css">
</head>

<body>

    <div class="container">
        <div class="form-inline">
            <h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"
                    fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16">
                    <path
                        d="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" />
                </svg>
                <span>修改图书</span>
            </h2>
        </div>

        <form id="updateBook">
            <input type="hidden" class="form-control" id="bookId" name="id">
            <div class="form-group">
                <label for="bookName">图书名称:</label>
                <input type="text" class="form-control" id="bookName" name="bookName">
            </div>
            <div class="form-group">
                <label for="bookAuthor">图书作者</label>
                <input type="text" class="form-control" id="bookAuthor" name="author"/>
            </div>
            <div class="form-group">
                <label for="bookStock">图书库存</label>
                <input type="text" class="form-control" id="bookStock" name="count"/>
            </div>
            <div class="form-group">
                <label for="bookPrice">图书定价:</label>
                <input type="number" class="form-control" id="bookPrice" name="price">
            </div>
            <div class="form-group">
                <label for="bookPublisher">出版社</label>
                <input type="text" id="bookPublisher" class="form-control" name="publish"/>
            </div>
            <div class="form-group">
                <label for="bookStatus">图书状态</label>
                <select class="custom-select" id="bookStatus" name="status">
                    <option value="1" selected>可借阅</option>
                    <option value="2">不可借阅</option>
                </select>
            </div>
            <div class="form-group" style="text-align: right">
                <button type="button" class="btn btn-info btn-lg" onclick="update()">确定</button>
                <button type="button" class="btn btn-secondary btn-lg" onclick="history.back()">返回</button>
            </div>
        </form>
    </div>
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <!-- HTML 表单保持不变 -->


    <script>


        function update() {
            // 收集表单数据
            const formData = {
                id: location.search.split("=")[1], // 确保隐藏字段包含图书ID
                bookName: $("#bookName").val(),
                author: $("#bookAuthor").val(),
                count: $("#bookStock").val(),
                price: $("#bookPrice").val(),
                publish: $("#bookPublisher").val(),
                status: $("#bookStatus").val()
            };
            // 对id进行Base64编码
            // 使用Ajax发送PUT请求到Spring Boot后端更新图书,URL中包含Base64编码的id
            // 构建正确的URL,使用模板字符串动态插入ID
            console.log("--------------"+formData)
            const urls = `/book/${formData.id}`;

            // 使用Ajax发送PUT请求到Spring Boot后端更新图书
            $.ajax({
                type: "PUT",
                url: urls, // 使用上面构建的正确URL
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify(formData),
                success: function(response, textStatus, jqXHR) {
                    if(jqXHR.status === 204) {
                        alert("更新成功");
                        location.href = "book_list.html";
                    } else if(response.status === 'SUCCESS') {
                        alert("更新成功");
                        location.href = "book_list.html";
                    } else {
                        alert("更新失败:" + response.message);
                    }
                },
                error: function(xhr, status, error) {
                    alert("更新图书时发生错误: " + xhr.responseText || error);
                }
            });

        }
    </script>
</body>

</html>

用户登录页面:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/login.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
</head>

<body>
    <div class="container-login">
        <div class="container-pic">
            <img src="pic/computer.png" width="713" alt="">
        </div>
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <label for="userName"></label><input type="text" name="userName" id="userName" class="form-control">
            </div>
            <div class="row">
                <span>密码</span>
                <label for="password"></label><input type="password" name="password" id="password" class="form-control">
            </div>
            <div class="row">
                <button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
            </div>
        </div>
    </div>
    <script src="js/jquery.min.js"></script>
    <script>
        function login() {
            $.ajax({
                type: "post",
                url: "/user/login",
                data: {
                    name: $("#userName").val(),
                    password: $("#password").val()
                },
                success: function (result) {
                    if (result) {
                        location.href = "book_list.html";
                    } else {
                        alert("账号或密码不正确!");
                    }
                }
            });
        }
    </script>
</body>

</html>

总结:

  1. src/main/java/bao/book_again 目录下的 BookAgainApplication.java 是项目的启动类,它继承了Spring Boot的SpringBootApplication,并使用@SpringBootApplication注解开启自动配置和扫描。

  2. Controller 目录下有多个控制器类,如 BasicController.javaPathVariableController.java,它们使用Spring MVC的@RestController@Controller注解,处理来自客户端的HTTP请求,并返回相应的响应。

  3. Domain 目录下有领域模型类,如 User.javaBookInfo.java,它们代表了应用中的实体对象。

  4. Exception 目录下有异常处理类,如 ResponseMessage.java,可能是用于封装错误信息和响应状态的类。

  5. Mapper 目录下有MyBatis的相关接口,如 BookService.java,它们定义了数据库操作的接口。

  6. Service 目录下有服务层实现,如 BookServiceImpl.java,实现了业务逻辑。

  7. resources/static 目录下有静态资源,如HTML文件和图片。

  8. application.yml 是项目的配置文件,用于配置Spring Boot应用的各种属性。

  9. test 目录下可能有单元测试或集成测试代码。

这个项目使用了Spring Boot和Spring MVC,结合MyBatis作为持久层框架,实现了基本的CRUD操作。用户界面使用HTML模板,通过RESTful API与后端交互。整体来看,这是一个典型的MVC架构的Web应用,其中Controller负责处理HTTP请求,Service层处理业务逻辑,Mapper层处理数据库操作,Domain层定义了领域模型,Exception层处理异常,static目录下存放了前端资源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/765404.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

存储故障导致Oracle 19c 数据文件处于recover状态的恢复案例

1.背景 某次平台分布式存储故障&#xff0c;导致数据库出现ORA-00376、ORA-01110数据文件不可读报错&#xff0c;本文将整个恢复过程进行整理记录。 2.报错信息 在进行租户数据库打开操作时&#xff0c;出现了如下报错&#xff1a; ORA-00376: file 17 cannot be read at t…

DICOM灰度图像、彩色图像的窗宽、窗位与像素的最大最小值的换算关系?

图像可以调整窗宽、窗位 dicom图像中灰度图像可以调整窗宽、窗位&#xff0c;RGB图像调整亮度或对比度&#xff1f;_灰度 图 调节窗宽-CSDN博客 窗宽、窗位与像素的最大最小值的换算关系? 换算公式 max-minWindowWidth; (maxmin)/2WindowCenter; 详细解释 窗宽&#xff0…

谷歌重磅:告别RAG,长上下文的大语言模型无需检索增强

当今人工智能领域正在经历一场静默的革命。随着大语言模型(LLM)的快速发展&#xff0c;它们不仅能够处理更长的上下文&#xff0c;还展现出惊人的推理和检索能力。 难道我们要告别基于LLM的检索增强生成(RAG)了吗&#xff1f; 结果还真是这样&#xff0c;最近谷歌发布专门用于…

贪心算法算法,完全零基础小白教程,不是计算机的都能学会!超详解

目录 一、基本概念 二、举几个例子&#xff0c;便于理解 1、找零问题 2、最小路径和 3、背包问题 1&#xff09;只考虑体积的贪心策略&#xff1a; 2&#xff09; 只考虑价值的贪心策略&#xff1a; 三、贪心策略的特点 四、贪心策略证明 四、如何学习贪心 五、例题…

eNSP中WLAN的配置和使用

一、基础配置 1.拓扑图 2.VLAN和IP配置 a.R1 <Huawei>system-view [Huawei]sysname R1 GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ip address 200.200.200.200 24 b.S1 <Huawei>system-view [Huawei]sysname S1 [S1]vlan 100 [S1-vlan100]vlan 1…

IAR工程目录移动报错(改变文件目录结构)

刚开始用IAR&#xff0c;记录一下。 工作中使用华大单片机&#xff0c;例程的文件目录结构太复杂了想精简一点。 1.如果原本的C文件相对工程文件&#xff08;.eww文件&#xff09;路径变化了&#xff0c;需要先打开工程&#xff0c;再将所有的.c文件右键Add添加进工程&#xf…

PHP7源码结构

PHP7程序的执行过程 1.PHP代码经过词法分析转换为有意义的Token&#xff1b; 2.Token经过语法分析生成AST&#xff08;Abstract Synstract Syntax Tree&#xff0c;抽象语法树&#xff09;&#xff1b; 3.AST生成对应的opcode&#xff0c;被虚拟机执行。 源码结构&#xff1…

昇思25天学习打卡营第14天|CycleGAN图像风格迁移互换

模型介绍 模型简介 CycleGAN(Cycle Generative Adversarial Network) 即循环对抗生成网络&#xff0c;该模型实现了一种在没有配对示例的情况下学习将图像从源域 X 转换到目标域 Y 的方法。 该模型一个重要应用领域是域迁移&#xff0c;它只需要两种域的数据&#xff0c;而不…

2023-2024华为ICT大赛中国区 实践赛网络赛道 全国总决赛 理论部分真题

Part1 数通模块(10题)&#xff1a; 1、如图所示&#xff0c;某园区部署了IPv6进行业务测试&#xff0c;该网络中有4台路由器&#xff0c;运行OSPFv3实现网络的互联互通&#xff0c;以下关于该OSPFv3网络产生的LSA的描述&#xff0c;错误的是哪一项?(单选题) A.R1的LSDB中将存在…

Java高级重点知识点-13-数据结构、List集合、List集合的子类

文章目录 数据结构List集合List的子类&#xff08;ArrayList集、LinkedList集&#xff09; 数据结构 栈 stack,又称堆栈&#xff0c;它是运算受限的线性表&#xff0c;其限制是仅允许在标的一端进行插入和删除操作&#xff0c;不允许在其他任何位置进行添加、查找、删除等操作…

如何下载huggingface仓库里某一个文件

如何下载huggingface仓库里某一个文件&#xff1a; https://huggingface.co/PixArt-alpha/PixArt-Sigma/tree/main 直接用命令&#xff1a; wget https://huggingface.co/PixArt-alpha/PixArt-Sigma/resolve/main/PixArt-Sigma-XL-2-2K-MS.pth

30个!2024重大科学问题、工程技术难题和产业技术问题发布

【SciencePub学术】中国科协自2018年开始&#xff0c;组织开展重大科技问题难题征集发布活动&#xff0c;引导广大科技工作者紧跟世界科技发展大势&#xff0c;聚焦国家重大需求&#xff0c;开展原创性、引领性研究&#xff0c;不断夯实高质量发展的科技支撑。 自2024年征集活动…

南京林业大学点云相关团队论文

【1】Chen Dong, Wan Lincheng, Hu Fan, Li Jing, Chen Yanming, Shen Yueqian*, Peethambaran Jiju, 2024. Semantic-aware room-level indoor modeling from point clouds, International Journal of Applied Earth Observation and Geoinformation, 2024, 127, 103685. 语义…

QT5 static_cast实现显示类型转换

QT5 static_cast实现显示类型转换&#xff0c;解决信号重载情况

一款十六进制编辑器,你的瑞士军刀!!【送源码】

软件介绍 ImHex是一款功能强大的十六进制编辑器&#xff0c;专为逆向工程师、程序员以及夜间工作的用户设计。它不仅提供了基础的二进制数据编辑功能&#xff0c;还集成了一系列高级特性&#xff0c;使其成为分析和修改二进制文件的理想工具。 功能特点 专为逆向工程、编程和夜…

【AI】Image Inpainting

学习参考摘抄来自&#xff1a;大模型修复徐克经典武侠片&#xff0c;「全损画质」变4K&#xff0c;还原林青霞40年前绝世美貌 火山引擎多媒体实验室 &#xff08;1&#xff09;清晰度 去噪、去压缩、去模糊、超分辨率、人像增强 &#xff08;2&#xff09;流畅度 智能插帧算…

3.js - 纹理的重复、偏移、修改中心点、旋转

你瞅啥 上字母 // ts-nocheck // 引入three.js import * as THREE from three // 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls // 导入lil.gui import { GUI } from three/examples/jsm/libs/lil-gui.module.min.js // 导入twee…

补浏览器环境

一&#xff0c;导言 // global是node中的关键字&#xff08;全局变量&#xff09;&#xff0c;在node中调用其中的元素时&#xff0c;可以直接引用&#xff0c;不用加global前缀&#xff0c;和浏览器中的window类似&#xff1b;在浏览器中可能会使用window前缀&#xff1a;win…

Latex写作工具整理(Overleaf)

一、公式&#xff08;MathType&#xff09; 先用MathType编辑好公式&#xff0c;再粘贴到Overleaf 预置-剪切和复制预置-选择“MathML或Tex"-确定 1.行内公式 粘贴到overleaf里面把两侧的" \["替换成"$" $ A $ 2.单行公式 \begin{equation}\labe…

Mysql并发控制和日志

文章目录 一、并发控制锁机制事务&#xff08;transactions&#xff09;事务隔离级别 二、日志事务日志错误日志通用日志慢查询日志二进制日志 备份在线查看二进制离线查看二进制日志 一、并发控制 锁机制 锁类型&#xff1a; 读锁&#xff1a;共享锁&#xff0c;也称为 S 锁…