1.实现功能
使用AI实现自动在数据库里建表,实现增删改查操作
使用@Tool配置工具类实现
2.主要步骤
2.1配置xml文件
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
2.2配置application.yml文件
java
server:
port: 8008
spring:
application:
name: ai-siliconflow-mcp-glm
ai:
openai:
base-url: https://api.siliconflow.cn
api-key: 你的硅基流动key
chat:
options:
model: "zai-org/GLM-4.6"
temperature: 0.7
datasource:
password: 123456
username: root
url: jdbc:mysql://localhost:3306/jiazhong_2025_2
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: status
logic-delete-value: 0
logic-not-delete-value: 1
2.3书写bean包
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.bean;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.JdbcType;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("student")
public class Student implements Serializable {
@TableId("id")
private Long id;
private String name;
private String password;
private Character gender;
@TableField(jdbcType = JdbcType.DATE)
private String birthday;
private String phone;
private String address;
private Integer status;
}
2.4书写mapper包
因为没有建表的方法
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.bean.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface StudentMapper extends BaseMapper<Student> {
@Insert("${sql}")
boolean createTable(String sql);
}
2.5service包以及serviceimpl包
2.5.1获取时间
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service;
import org.springframework.stereotype.Service;
@Service
public interface NowDateService {
String getNowDate();
}
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.impl;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.NowDateService;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
@Service
public class NowDateServiceImpl implements NowDateService {
@Tool(description = "获取当前时间")
public String getNowDate() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(new Date());
}
}
2.5.2雪花算法(实现随机生成id)
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service;
import org.springframework.stereotype.Service;
@Service
public interface SnowFlakeGenerateIdWorkerService{
/**
* 生成默认机器ID的雪花ID(AI 工具方法)
*/
long generateId();
}
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.impl;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.SnowFlakeGenerateIdWorkerService;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.util.SnowflakeUtil;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SnowFlakeGenerateIdWorkerServiceImpl implements SnowFlakeGenerateIdWorkerService {
@Autowired
private SnowflakeUtil snowflakeUtil;
/**
* AI 工具方法:生成默认机器ID的雪花ID
* @return 雪花ID(Long类型)
*/
@Tool(description = "生成分布式唯一雪花ID(使用默认机器ID),返回Long类型的唯一ID")
@Override
public long generateId() {
return snowflakeUtil.nextId();
}
}
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.util;
import org.springframework.stereotype.Component;
/**
* 雪花算法工具类(线程安全,单例)
*/
@Component
public class SnowflakeUtil {
// 起始时间戳(2026-01-01 00:00:00)
private static final long START_TIMESTAMP = 1777555200000L;
private static final long WORKER_ID_BITS = 10L;
private static final long SEQUENCE_BITS = 12L;
private static final long MAX_WORKER_ID = (1 << WORKER_ID_BITS) - 1;
private static final long MAX_SEQUENCE = (1 << SEQUENCE_BITS) - 1;
private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;
private static final long TIMESTAMP_SHIFT = WORKER_ID_BITS + SEQUENCE_BITS;
private final long workerId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeUtil() {
this(0L);
}
public SnowflakeUtil(long workerId) {
if (workerId < 0 || workerId > MAX_WORKER_ID) {
throw new IllegalArgumentException("Worker ID 超出范围(0-" + MAX_WORKER_ID + ")");
}
this.workerId = workerId;
}
public synchronized long nextId() {
long currentTimestamp = System.currentTimeMillis();
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("时钟回拨,拒绝生成ID!当前时间:" + currentTimestamp + ",上一次时间:" + lastTimestamp);
}
if (currentTimestamp == lastTimestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
currentTimestamp = waitNextTimestamp(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = currentTimestamp;
return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
| (workerId << WORKER_ID_SHIFT)
| sequence;
}
private long waitNextTimestamp(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
public String parseId(long id) {
long timestamp = (id >> TIMESTAMP_SHIFT) + START_TIMESTAMP;
long workerId = (id >> WORKER_ID_SHIFT) & MAX_WORKER_ID;
long sequence = id & MAX_SEQUENCE;
return String.format("ID:%d -> 时间戳:%d(%tF %<tT),机器ID:%d,序列号:%d",
id, timestamp, timestamp, workerId, sequence);
}
}
2.5.3实现数据库建表、增删查改
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.bean.Student;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface StudentService extends IService<Student> {
boolean createTable(String sql);
boolean saveStudent(Student student);
boolean saveBatchStudent(List<Student> list);
boolean updateStudent(Student student);
boolean deleteStudent(Student student);
List<Student> findAll();
}
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.bean.Student;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.mapper.StudentMapper;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.StudentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper,Student> implements StudentService {
//创建表的工具
@Tool(description = "根据方法的参数创建一张表")
public boolean createTable(@ToolParam(description = "建表语句") String sql) {
log.info("调用了创建表的工具:{}",sql);
return getBaseMapper().createTable(sql);
}
//新增数据工具
@Tool(description = "向表中录入数据")
public boolean saveStudent(@ToolParam(description = "录入的对象") Student student) {
return save(student);
}
@Tool(description = "批量录入数据")
public boolean saveBatchStudent(@ToolParam(description = "录入的多个对象") List<Student> list) {
return saveBatch(list);
}
@Tool(description = "修改某个同学的信息")
public boolean updateStudent(@ToolParam(description = "修改的对象") Student student) {
return updateById(student);
}
@Tool(description = "逻辑删除某个学生")
public boolean deleteStudent(@ToolParam(description = "要删除的对象")Student student) {
return removeById(student);
}
@Tool(description = "获取所有的学生信息")
public List<Student> findAll() {
return list();
}
}
2.6写config包
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.config;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.NowDateService;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.SnowFlakeGenerateIdWorkerService;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.StudentService;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ChatClientConfig {
@Resource
private OpenAiChatModel openAiChatModel;
@Resource
private StudentService studentService;
@Resource
private NowDateService nowDateService;
@Resource
private SnowFlakeGenerateIdWorkerService snowFlakeGenerateIdWorkerService;
@Bean("openAiChatClient")
public ChatClient openAiChatClient(){
return ChatClient.builder(openAiChatModel)
.defaultTools(studentService,nowDateService,snowFlakeGenerateIdWorkerService)
.build();
}
}
2.7书写controller包
java
package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.controller;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.bean.Student;
import com.jiazhong.mingxing.ai.siliconflow.mcp.glm.mysql.service.StudentService;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
@RestController
@RequestMapping("/sql")
public class SqlController {
@Resource
private ChatClient openAiChatClient;
@Autowired
private StudentService studentService;
@GetMapping(value = "/create",produces = "text/html;charset=utf-8")
public Flux<String> create(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据以下上下文操作
1. 创建表语句根据Student类为模版生成
2. 如果这张表存在,则不新建并返回内容
3. 如果创建表时出错,返回错误信息
##Student类的源码如下:
```java
@TableName("student")
public class Student implements Serializable {
@TableId("id")
private Long id;
private String name;
private String password;
private Character gender;
@TableField(jdbcType = JdbcType.DATE)
private String birthday;
private String phone;
private String address;
private Integer status;
}
"""
)
.user(question)
.stream().content();
}
@GetMapping(value = "/insert",produces = "text/html;charset=utf-8")
public Flux<String> insert(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据如下上下文执行添加
1. 主键id通过雪花算法生成
2. 密码需要通过md5进行加密操作
3. 如果密码未赋值,默认密码是123456
4. 默认性别是男
5. 手机号唯一,不能重复
6. 如果没有给手机号设置为null
6. 如果录入失败,请返回失败原因
"""
)
.user(question)
.stream().content();
}
@GetMapping(value = "/batch_insert", produces = "text/html;charset=utf-8")
public Flux<String> batchInsert(@RequestParam("question") String question) {
return openAiChatClient.prompt("""
##请根据如下上下文执行添加
1. 主键id通过雪花算法生成
2. 密码需要通过md5进行加密操作
3. 如果密码未赋值,默认密码是123456
4. 手机号唯一,不能重复
5. 如果录入失败,请返回失败原因
""")
.user(question)
.stream().content();
}
@GetMapping(value = "/find_all_1",produces = "text/html;charset=utf-8")
public Flux<String> findAll1(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据如下上下文执行查询
1. 返回的结果是一个HTML页面
2. 内容以表格的形式体现
3. 数据仅从数据库的表格中获取
"""
)
.user(question)
.stream().content();
}
@GetMapping(value = "/find_all_2",produces = "application/json;chaset=utf-8")
public List<Student> findAll2(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据如下上下文执行查询
1. 返回的结果是一个HTML页面
2. 内容以表格的形式体现
3. 数据仅从数据库的表格中获取
"""
)
.user(question)
.call().entity(new ParameterizedTypeReference<List<Student>>() {});
}
@GetMapping(value = "/find_all_3",produces = "application/json;charset=utf-8")
public List<Student> findAll3(){
return studentService.findAll();
}
@GetMapping(value = "/update",produces = "application/json;chaset=utf-8")
public Flux<String> update(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据如下上下文执行查询
1. 输出是否已经修改好
2.给出修改好后的数据
3. 数据仅从数据库的表格中获取
"""
)
.user(question)
.stream().content();
}
@GetMapping(value = "/delete",produces = "application/json;chaset=utf-8")
public Flux<String> delete(@RequestParam("question") String question){
return openAiChatClient.prompt(
"""
##请根据如下上下文执行查询
1.逻辑删除是将statue由0变为1
2.输出是否已经删除好
2. 给出逻辑删除好后的数据
3. 数据仅从数据库的表格中获取
"""
)
.user(question)
.stream().content();
}
}