20.<Spring图书管理系统①(登录+添加图书)>

PS:关于接口定义

接口定义,通常由服务器提供方来定义。

1.路径:自己定义

2.参数:根据需求考虑,我们这个接口功能完成需要哪些信息。

3.返回结果:考虑我们能为对方提供什么。站在对方角度考虑。

我们使用到的技术:

前端:"是自己在网上找的代码

后端

  • IDEA
  • Maven
  • MySQL+Mybatis
  • SSM

实现的功能:

  1. 用户登录
  2. 添加图书
  3. 显示图书列表
  4. 更新图书
  5. 删除图书
  6. 批量删除图书
  7. 强制登录
  8. 引入统一功能

做这个管理系统,首先我们需要考虑到什么呢?

第一步建立数据库

比如登录、用户要输入 用户名 和 密码。

因此对于数据库。我们需要一张用户表。用来存储用户名和密码。

还需要配置数据库 & 日志文件

搞完数据库相关的。就要写代码了。

第二步创建实体类

我们需要根据数据库字段创建一些实体类。

第三步实现用户登录功能

第四步实现添加图书功能

第五步实现显示图书列表功能

第六步实现更新图书功能

第七步实现删除图书功能

第八步实现批量删除图书

第九步实现强制登录

第十步加上统一功能

预览整体项目

首页

登录进去

可以进行翻页

添加图书

批量删除

修改图书

删除图书

一、建立数据库

1.1配置数据库 & 日志

复制代码
server:  #端口号配置
  port: 1208
spring:
  datasource: # 数据库连接配置
    url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 12345678
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印 MyBatis?志
    map-underscore-to-camel-case: true #配置驼峰?动转换
  mapper-locations: classpath:mapper/**Mapper.xml # 配置mybatis xml的?件路径,在resources/mapper创建所有表的xml?件
  # classpath对应resources这个目录,接下来说明在mapper这个文件夹下面,以Mapper.xml结束的都可以被加载

# 设置?志?件的?件名
logging:
  file:
    name: spring-book.log

我们新建一个book_test数据库。

复制代码
DROP DATABASE IF EXISTS book_test;
CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;

①新建一个用户表

复制代码
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
    `id` INT NOT NULL AUTO_INCREMENT,
    `user_name` VARCHAR ( 128 ) NOT NULL,
    `password` VARCHAR ( 128 ) NOT NULL,
    `delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY ( `id` ), --将 id 列设置为主键,保证每条记录唯一
    UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC )
--指定了索引的列以及排序方式。在此例中,user_name 列按照升序(ASC)排序。
--默认是升序,因此这里 ASC 是可选的。
) 
    ENGINE = INNODB --设置存储引擎为 InnoDB,支持事务和外键
    DEFAULT CHARACTER SET = utf8mb4 COMMENT = '??表';

②新建图书表

复制代码
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (
    `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
    `book_name` VARCHAR ( 127 ) NOT NULL,
    `author` VARCHAR ( 127 ) NOT NULL,
    `count` INT ( 11 ) NOT NULL,
    `price` DECIMAL (7,2 ) NOT NULL,
    `publish` VARCHAR ( 256 ) NOT NULL,
    `status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-?效, 1-正常, 2-不允许借阅',
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now() ON UPDATE now(),
    PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

初始化数据

复制代码
-- 初始化数据 
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "admin", "admin" );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "zhangsan", "123456" );
-- 初始化图书数据 
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES
 ('活着', '余华', 29, 22.00, '北京?艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES
 ('平凡的世界', '路遥', 5, 98.56, '北京???艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES
 ('三体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES
 ('?字塔原理', '?肯锡', 16, 178.00, '?主与建设出版社');

下面是我们建好后的用户表

图书表

二、创建实体类

2.1 用户实体类UserInfo实体类

复制代码
package com.qiyangyang.springbook.demos.model;

import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
    private Integer id;
    private String userName;
    private String password;
    private Integer delete_flag;
    private Date createTime;
    private Date updateTime;
}

2.2 图书实体类 BookInfo实体类

复制代码
package com.qiyangyang.springbook.demos.model;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class BookInfo {
    private Integer id;
    private String bookName;
    private String author;
    private Integer count;
    private BigDecimal price;
    private String publish;
    private Integer status;//1-可借阅   2-不可借阅  0-已删除
    private String stateCN;//根据book状态设置描述
    private Date createTime;
    private Date updateTime;
}

三、实现用户登录接口

3.1约定前后端交互接口

复制代码
[请求]
/user/login
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

[参数]
name=zhangsan&password=123456

[响应]
true //账号密码验证正确, 否则返回false

浏览器给服务器发送 /user/login 这样的 HTTP 请求, 服务器给浏览器返回了一个Boolean类型 的数据.返回true,表示账号密码验证正确

3.2实现(后端)服务器代码

3.2.1控制层

从数据库查询用户名和密码,如果可以查到并且密码一致,就认为登录成功。

创建UserController

复制代码
package com.qiyangyang.springbook.demos.controller;

import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/login")
    public boolean login(String userName, String password, HttpSession session){
        /**
         * 校验参数
         */
        if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
            return false;
        }
        //判断用户输入的密码和用户输入的密码是否一致
        //我们需要查询数据库,得到数据库的密码
        UserInfo userInfo = userService.queryByName(userName);
        if(userInfo == null){
            //用户不存在
            return false;
        }
        if(password.equals(userInfo.getPassword())){
            //将密码置为空,不置为空也可以,因为Session是在服务器上的数据,客户端也看不到
            //session也是占内存的因此,不需要的不存。
            /**
             * 如果密码正确
             * 存Session
             */
            //由于密码信息是没用的,用不到。我们设置成空。不设置成空也行,因为存在服务器。客户端是看不到的
            userInfo.setPassword("");
            session.setAttribute("user_session",userInfo);
            return true;
        }
        return false;
    }
}
/**
package com.qiyangyang.springbook.demos.controller;

import com.qiyangyang.springbook.demos.model.UserInfo;
import com.qiyangyang.springbook.demos.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;

@Slf4j
@RequestMapping("/user")
@RestController
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/login")
    public boolean login(String userName, String password, HttpSession session){
        /**
         * 校验参数
         */
        if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)){
            return false;
        }
        //判断用户输入的密码和用户输入的密码是否一致
        //我们需要查询数据库,得到数据库的密码
        UserInfo userInfo = userService.queryByName(userName);
        if(userInfo == null){
            //用户不存在
            return false;
        }
        if(password.equals(userInfo.getPassword())){
            //将密码置为空,不置为空也可以,因为Session是在服务器上的数据,客户端也看不到
            //session也是占内存的因此,不需要的不存。
            /**
             * 如果密码正确
             * 存Session
             */
            //由于密码信息是没用的,用不到。我们设置成空。不设置成空也行,因为存在服务器。客户端是看不到的
            userInfo.setPassword("");
            session.setAttribute("user_session",userInfo);
            return true;
        }
        return false;
    }
}
/**
 * HttpSession session
 * 存的是根据SessionId获取的Session对象,每一个sessionId对应一个session对象。
 * 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。
 * SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。
 *
 */
 *
 */

问题1:每次我们存的Session都一样。后面用户。存的Session会覆盖前面用户的Session吗?

答:同一个用户会覆盖,不同用户,不同客户端不会覆盖。

Session表示的是会话,对话。是有来有回的,而且是多个回合。

* HttpSession session

* 存的是根据SessionId获取的Session对象,每一个sessionId对应一个session对象。

* 会根据客户端等等判断是新用户还是老用户。服务器里面存了很多session。

* SessionId在后端通过服务器生成并通过 Cookie 发送给客户端。

问题2:如果多个客户端同时访问,需不需要加多线程?

答:不需要,因为我们没有使用多线程。

请求的隔离框架已经帮我们做了。因此不考虑多线程。

什么时候才去做多线程呢,比如程序里面用到了线程池。才考虑多线程。每个用户进来login函数。信息存放在栈里面,栈是线程私有的。堆是线程公有的。这些成员变量存储在栈里面,因此每个用户的信息之间没有关系。分别对应不同的对象。

在我们需要进行优化的时候考虑多线程。比如要查询两次数据。第一次得到了密码,可以因为业务需要还要查询一次。这时候串行查询觉得太慢了。这时候考虑多线程。就可以进行并行查询。加了多线程我们就要考虑线程安全的情况。代码里用到多线程,才考虑多线程。

校验密码我们推荐在业务逻辑层来写,由于这里比较简单。我们就写在Controller中

3.2.2 业务层

创建UserService

复制代码
package com.qiyangyang.springbook.demos.service;

import com.qiyangyang.springbook.demos.mapper.UserInfoMapper;
import com.qiyangyang.springbook.demos.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    /**
     * 从数据库中查询用户信息
     * @param userName
     * @return
     */
    public UserInfo queryByName(String userName){
        return userInfoMapper.queryByName(userName);
    }
}
3.2.3数据层

创建UserInfoMapper

复制代码
package com.qiyangyang.springbook.demos.mapper;

import com.qiyangyang.springbook.demos.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserInfoMapper {
    @Select("select * from user_info where delete_flag = 0 and user_name=#{userName}")
    UserInfo queryByName(String userName);


}

3.3后端校验

使用Postman校验。多次实验发现,校验成功。然后我们再去写前端的代码。

3.4实现前端代码

3.4.1 ajax 部分
复制代码
    <script src="js/jquery.min.js"></script>
    <script>
        function login() {
            $.ajax({
               type:"post",
                url:"/user/login",
                data:{
                   userName:$("#userName").val(),
                    password:$("#password").val()
                },
                success:function (result) {
                    if(result===true){
                        //验证成功
                        location.href = "book_list.html";
                    }else {
                        alert("登录失败,用户名不存在或密码错误!");
                    }
                }
            });
        }
    </script>
3.4.2完整前端登录代码
复制代码
<!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="350px">
        </div>
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <input type="text" name="userName" id="userName" class="form-control">
            </div>
            <div class="row">
                <span>密码</span>
                <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:{
                   userName:$("#userName").val(),
                    password:$("#password").val()
                },
                success:function (result) {
                    if(result===true){
                        //验证成功
                        location.href = "book_list.html";
                    }else {
                        alert("登录失败,用户名不存在或密码错误!");
                    }
                }
            });
        }
    </script>
</body>

</html>

3.5完整校验前后端交互

输入正确用户名和密码

成功登录,并且跳转到图书目录页面。

输入错误用户名和密码。登录失败。弹框显示用户名不存在或密码错误。

四、实现添加图书接口

4.1约定前后端交互

请求

/book/addBook

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

参数

bookName=图书1&author=作者1&count=23&price=36&publish=出版社1&status=1

响应

"成功添加图书" //失败信息, 成功时返回空字符串
我们约定浏览器给服务器发送/book/addBook 这样的HTTP请求。

form表单的形式来提交数据。服务器返回处理结果。返回""表示图书添加成功。否则,返回失败信息。

4.2实现(后端)服务器代码

4.2.1控制层

创建BookController类

复制代码
@Slf4j
@RestController
@RequestMapping("book")
public class BookController {

    @Autowired
    private BookService bookService;
    @RequestMapping("/addBook")
    public String addBook(BookInfo bookInfo){
        log.info("添加图书,bookInfo:{}",bookInfo);
        /**
         * 参数校验
         */
        if(!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || !StringUtils.hasLength(bookInfo.getPublish())
                || bookInfo.getCount() <=0
                || bookInfo.getPrice()==null){
            return "参数错误";
        }
        /**
         * 添加图书
         */
        /**
         * 出现错误比如参数错误。添加过程出现异常,因为MySQL会出现一些异常
         * 我们使用try/catch来捕获。
         */
        try {
            bookService.insertBook(bookInfo);
        }catch (Exception a){
            return "内部发生错误,请联系管理员";
        }
        /**
         * 返回成功添加吐过表示图书插入成功。
         */
        return "成功添加图书";
    }
}
4.2.2 业务层

创建BookService类

复制代码
@Service
public class BookService {
    @Autowired
    private BookInfoMapper bookInfoMapper;

    public Integer insertBook(BookInfo bookInfo){
        return bookInfoMapper.insertBook(bookInfo);
    }
}
4.2.3 数据层

创建BookInfoMapper

复制代码
@Mapper
public interface BookInfoMapper {
    @Insert("insert into book_info(book_name,author,count,price,publish) " +
            "values (#{bookName},#{author},#{count},#{price},#{publish})")
    Integer insertBook(BookInfo bookInfo);
}

4.3后端测试

填写正确数据,返回成功添加图书

填写错误数据,返回参数错误

小bug(后端服务器问题)

count 和 price为字符串时,会报400错误。请求参数类型不匹配。

日志显示在绑定 bookInfo 对象时出现了类型转换错误:

  • count 字段 :后端定义 count 应为 Integer,但接收到的值是 "五大"(字符串)。
  • price 字段 :后端定义 price 应为 BigDecimal,但接收到的值是 "带娃"(字符串)。

因为这些值无法转换成期望的数值类型,所以 Spring 在尝试绑定请求参数时抛出了 BindException,并返回 HTTP 400 错误,表示请求的格式或内容无效。

4...4实现前端代码

4.4.1 form表单 和 ajax 部分

form表单
我们可以把提交的数据写成一个form表单。

form表单 Id 在前端显示页面并没有什么作用。主要是搭配后端来进行前后端交互。

整个表单内容需要提交的话,我们可以借助form标签来提交整个表单

复制代码
data: $("#addBook").serialize(), //序列化

//这个函数会把整个表单的所有的input框...等等输入的项目都会提交

提交的结构是以key : value 键值对的形式提交

key就是name

value就是输入的值。

复制代码
      <form id="addBook">
        <div class="form-group">
          <label for="bookName">图书名称:</label>
          <input
            type="text"
            class="form-control"
            placeholder="请输入图书名称"
            id="bookName"
            name="bookName"
          />
        </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="javascript:history.back()">返回</button>
            </div>
        </form>

ajax部分

复制代码
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script>
        function add() {
            $.ajax({
                type:"post",
                url:"/book/addBook",
//整个表单内容需要提交的话,我们可以借助form标签来提交整个表单,搭配后端做一些交互来使用的。
                data: $("#addBook").serialize(),//序列化
//这个函数会把整个表单的所有的input框..等等输入的项目都会提交
                success:function (result) {
                    if(result === "成功添加图书"){
                        alert("添加成功");
                        location.href = "book_list.html";
                    }else {
                        alert(result);
                    }
                }
            });

        }
    </script>
4.4.2完整前端添加图书代码
复制代码
<!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="javascript:history.back()"
          >
            返回
          </button>
        </div>
      </form>
    </div>
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script>
      function add() {
        $.ajax({
          type: "post",
          url: "/book/addBook",
          //整个表单内容需要提交的话,我们可以借助form标签来提交整个表单,搭配后端做一些交互来使用的。
          data: $("#addBook").serialize(), //序列化
          //这个函数会把整个表单的所有的input框..等等输入的项目都会提交
          success: function (result) {
            if (result === "成功添加图书") {
              alert("添加成功");
              location.href = "book_list.html";
            } else {
              alert(result);
            }
          },
        });
      }
    </script>
  </body>
</html>

4.5完整校验前后端交互

输入正确数据

成功添加到我们的数据库中。
输入错误数据。

弹框提示输入参数错误!

本篇内容已经很多。

后续内容在下一篇文章中!

相关推荐
吴声子夜歌2 分钟前
Java面试——基础
java·开发语言·面试
newerp2 分钟前
Redis 操作与缓存策略
后端·程序员·go
newerp6 分钟前
GORM ORM 基础
后端·程序员·go
小岛前端12 分钟前
AI Skills 已经封神,但新的问题却越来越严重!
前端·后端·github
拖孩15 分钟前
一个人 + AI 做的小程序,上线 15 天赚了 10 块 5
前端·后端·微信小程序
newerp17 分钟前
CRUD 操作与预处理语句
后端·程序员·go
智码看视界22 分钟前
Day 56:AI辅助开发全面提效:Copilot + Cursor的Java开发
java·单元测试·copilot·cursor·后端开发·代码审查·ai辅助开发
wei_shuo24 分钟前
KES 数据同步与ETL实战:数据集成、转换与实时同步方案
后端
乒乓狂魔147867399700030 分钟前
LangGraph:用一张图,编排一群 AI 助手
后端
Gopher_HBo31 分钟前
请求绑定 binding(binding/ 包)
后端