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

news2024/11/20 9:43:37

前提条件:

具备基础的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.coloradmin.cn/o/1887408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搜索型数据库的技术发展历程与趋势前瞻

概述 随着数字科技的飞速发展和信息量的爆炸性增长&#xff0c;搜索引擎已成为我们获取信息的首选途径之一&#xff0c;典型的代表厂商如 Google。然而&#xff0c;随着用户需求的不断演变&#xff0c;传统的搜索技术已经无法满足人们对信息的实时性、个性化和多样性的需求。 …

C++基础知识-编译相关

记录C语言相关的基础知识 1 C源码到可执行文件的四个阶段 预处理(.i)、编译(.s)、汇编(.obj)、链接。 1.1 预处理 预处理阶段&#xff0c;主要完成宏替换、文件展开、注释删除、条件编译展开、添加行号和文件名标识&#xff0c;输出.i/.ii预处理文件。 宏替换&#xff0c;…

AI的价值——不再那么“废”人,保险行业用AI人员流失减少20%

最近有个热点挺让人唏嘘的&#xff0c;某咖啡店员工对顾客泼咖啡粉&#xff0c;我们对于这个事件不予评价。但是对员工这种情绪崩溃&#xff0c;我们所接触的行业中也有不少例子&#xff0c;比如保险行业&#xff0c;相信大家经常会被打保险电话&#xff0c;这类电话很容易就被…

K8s 的最后一片拼图:dbPaaS

K8s 的发展使得私有云跟公共云之间的技术差不断的缩小&#xff0c;不管是在私有云还是公共云&#xff0c;大家今天都在基于 K8s 去开发 PaaS 系统。而 K8s 作为构建 PaaS 的基础&#xff0c;其全景图里还缺最后一块“拼图”——dbPaaS。作为一个云数据库行业干了十几年的资深从…

Swin Transformer:最佳论文,准确率和性能双佳的视觉Transformer | ICCV 2021

论文提出了经典的Vision Transormer模型Swin Transformer&#xff0c;能够构建层级特征提高任务准确率&#xff0c;而且其计算复杂度经过各种加速设计&#xff0c;能够与输入图片大小成线性关系。从实验结果来看&#xff0c;Swin Transormer在各视觉任务上都有很不错的准确率&a…

哈尔滨如何选择合适的等保测评机构?

选择合适的等保测评机构确实需要细致考虑&#xff0c;您提到的八个方面已经非常全面&#xff0c;涵盖了资质、专业能力、服务质量和合规性等多个关键点。为了进一步确保所选机构的可靠性&#xff0c;还可以考虑以下几点&#xff1a; 1.技术创新与工具&#xff1a;了解测评机构是…

UE5的安装与基本操作(一)

文章目录 前言安装UE5新建第一个游戏项目基本游览方式对目标进行变换各种变换对齐 快速定位目标 总结 前言 Unreal Engine 5 (UE5) 是一款由 Epic Games 开发的实时 3D 创作平台&#xff0c;用于制作游戏、电影、动画、建筑可视化和其他类型的交互式体验。UE5 提供了一系列强大…

解锁IDEA中Git/SVN Issue Navigation功能:80%程序员都不懂的秘密武器~

文章目录 前言什么是 Git Issue Navigation&#xff1f;配置 Git Issue Navigation1. 打开设置2. 导航到 Issue Navigation 设置3. 添加新的 Issue Navigation 规则具体示例配置 使用 Git Issue Navigation在提交信息中使用 Issue ID实际导航到连接 优点1. 快速定位问题2. 提高…

可重入锁思想,设计MQ迁移方案

如果你的MQ消息要从Kafka切换到RocketMQ且不停机&#xff0c;怎么做&#xff1f;在让这个MQ消息调用第三方发奖接口&#xff0c;但无幂等字段又怎么处理&#xff1f;今天小傅哥就给大家分享一个关于MQ消息在这样的场景中的处理手段。 这是一种比较特例的场景&#xff0c;需要保…

6月28日华为云数据库斯享会上海站,NineData技术总监薛晓乐受邀并带来主题分享

6月28日&#xff08;周五&#xff09;&#xff0c;华为云数据库斯享会即将在上海举办&#xff0c;将与的开发者朋友们一起进行数据库技术交流&#xff01;NineData 技术总监薛晓乐受邀参会&#xff0c;并将带来《企业级数据库 DevOps 最佳实践》的主题分享。 本次活动议程&…

ROS2 分布式 及 ssh远程控制 和 上传文件夹

问题1. 多台计算机连接同一wifi后 &#xff0c;运行ROS2的小乌龟案例&#xff0c;自己的计算机&#xff0c;无法控制其他电脑的小乌龟 按照正常的情况来说&#xff0c;ROS2是DDS的自发现通信机制&#xff0c;只要处在同一wifi网络中&#xff0c; A计算机执行启动小乌龟的命…

Qt 配置ASan

Qt 配置ASan 文章目录 Qt 配置ASan摘要关于ASan&#xff08;AddressSanitizer&#xff09;在Qt中配置 ASan1. 安装必要的工具2. 修改项目的 .pro 文件3. 重新构建项目4. 运行应用程序5. 分析错误报告示例注意事项 关键字&#xff1a; Qt、 ASan、 AddressSanitizer 、 GCC …

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

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

【bug报错已解决】ERROR: Could not find a version that satisfies the requirement

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言一、问题描述1.1 报错示例1.2 报错分析 二、解决方法2.1 方法一2.2 方法二 三、总结 引言 有没有遇到过那种让人…

吴晓波:企业出海的最佳时间窗口只有5-10年,中国企业如何把握出海机遇?

鼓励企业参与绿色“一带一路”建设&#xff0c;带动先进的环保技术、装备、产能走出去。 出海计划&#xff01;马来西亚水环境项目国际考察暨2024中马水务合作论坛

探囊取物之多形式登录页面(基于BootStrap4)

基于BootStrap4的登录页面&#xff0c;支持手机验证码登录、账号密码登录、二维码登录、其它统一登录 低配置云服务器&#xff0c;首次加载速度较慢&#xff0c;请耐心等候&#xff1b;演练页面可点击查看源码 预览页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/pr…

记录部署项目《庆自提》完整流程

项目选型&#xff1a;后端网页小程序 前言&#xff1a;在部署这个项目我采用的是宝塔去直接部署&#xff0c;没有使用docker去部署 部署后端部分可参考&#xff1a;记录部署项目到云服务器_项目部署到云服务器-CSDN博客 一、部署后端 &#xff08;1&#xff09;修改yml配置文件…

大模型技术:能否引领十年的行业变革与职业发展黄金期?......

身边做程序的朋友、前同事&#xff0c;包括亲人&#xff0c;很多都在今年失业了&#xff0c;每年都说难&#xff0c;而今年&#xff0c;无疑是进入21世纪后最难的一年。 套用一下大话西游里的台词&#xff1a;上班的时候&#xff0c;不知道工作的珍贵&#xff0c;待到失去后才…

【日常记录】【JS】动态执行JS脚本

文章目录 1、第一种方式&#xff1a;eval2、第二种方式&#xff1a;setTimeout3、第三种方式&#xff1a;创建script 标签插入body4、第四种方式&#xff1a;创建 Function5、对比6、 参考链接 1、第一种方式&#xff1a;eval 语法 eval(string)参数 string&#xff1a;一个…

Linux基础篇——学习Linux基本工具安装教程视频链接

本篇文章就是记录一下学习Linux需要用到的基本工具的视频教程链接&#xff0c;方便以后查看 VMware15.5安装 安装视频教程&#xff1a;VMware15.5安装教程 centos7.6安装&#xff08;这个视频教程真的很nice&#xff09; 视频教程&#xff1a;centos7.6 虚拟机克隆、快照、…