这是我见过最全的支付系统!一套适合互联网企业使用的开源支付系统 - Java陈序员 - 博客园

mikel阅读(60)

来源: 这是我见过最全的支付系统!一套适合互联网企业使用的开源支付系统 – Java陈序员 – 博客园

项目介绍

Jeepay —— 计全支付,一套适合互联网企业使用的开源支付系统,支持多渠道服务商和普通商户模式。

已对接微信支付,支付宝,云闪付官方接口,支持聚合码支付

系统架构:

Jeepay 使用 Spring Boot 和 Ant Design Vue 开发,集成 Spring Security 实现权限管理功能,是一套非常实用的 web 开发框架!

系统截图

运营平台

主页

商户管理

服务商管理

订单管理

支付配置

系统管理

商户系统

主页

商户中心

订单中心

分账管理

快速上手

环境准备:

  • Java 8
  • Redis
  • MySQL
  • MQ:ActiveMQ 或 RabbitMQ 或 RocketMQ
  • Node.js

后端服务

1、拉取代码

git clone https://github.com/jeequan/jeepay.git

代码目录结构:

jeepay
├── conf -- 存放系统部署使用的.yml文件
├── docker -- 存放docker相关文件
└── docs -- 存放项目相关文档说明
     ├── intsll -- 项目部署shell脚本
     ├── script -- 项目启动shell脚本
     └── sql -- 初始化sql文件
└── jeepay-components -- 公共组件目录
     ├── jeepay-components-mq -- mq组件
     └── jeepay-components-oss -- oss组件
├── jeepay-core -- 核心依赖包
├── jeepay-manager -- 运营平台服务端[9217]
├── jeepay-merchant -- 商户系统服务端[9218]
├── jeepay-payment -- 支付网关[9216]
├── jeepay-service -- 业务层代码
└── jeepay-z-codegen -- mybatis代码生成

2、初始化数据库

在 MySQL 5.7 下创建数据库 jeepaydb 并执行项目下 docs/SQL/init.sql,确保所有语句执行成功。

3、将代码以 Maven 的形式导入到 IDEA

4、修改配置文件中的 MySQL、Redis、MQ 等中间件的连接地址、用户名、密码等配置

5、进入到不同的业务模块代码中,执行主启动类,启动后端服务

前端服务

1、拉取代码

git clone https://github.com/jeequan/jeepay-ui.git

代码目录结构:

jeepay-ui
├── jeepay-ui-cashier -- 聚合收银台项目
├── jeepay-ui-manager -- 运营平台web管理端
└── jeepay-ui-merchant -- 商户系统web管理端

2、以 jeepay-ui-manager 为例,进入到目录 jeepay-ui-manager 下,安装依赖

npm install

3、将文件 .env 中的 VUE_APP_API_BASE_URL 配置改为后端服务地址

4、启动项目

npm run serve

5、浏览器访问

http://localhost:8000

jeepay-ui-cashier、jeepay-ui-merchant 重复执行上述操作即可,只是启动后的访问端口不一样。

最后

推荐的开源项目已经收录到 GitHub 项目,欢迎 Star

https://github.com/chenyl8848/great-open-source-project

或者访问网站,进行在线浏览:

https://chencoding.top:8090/#/

大家的点赞、收藏和评论都是对作者的支持,如文章对你有帮助还请点赞转发支持下,谢谢!

Java对接JeePay支付、转账实现以及回调函数-CSDN博客

mikel阅读(60)

来源: Java对接JeePay支付、转账实现以及回调函数-CSDN博客

最近公司对接了第三方支付平台JeePay,看到网上文章比较少,给大家发一篇对接微信支付的吧,支付宝也一样,更换里面的参数即可,官方文档地址:系统介绍 – 计全文档,具体的服务需要大家去搭建,并创建里面的应用,我这里只给大家展示出了代码,具体的服务搭建和创建应用大家去看下官网,下面开始实现我们的代码。

首先我们引入两个pom依赖。

<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>

<dependency>
<groupId>com.jeequan</groupId>
<artifactId>jeepay-sdk-java</artifactId>
<version>1.5.0</version>
</dependency>
下面我们需要在配置文件里面加上相关配置,我们可以新建一个 application-jee-pay.properties。

#这个是回调的地址,一定要能访问到我们回调的IP上面,自定义
domain-name=http://120.29.172.100:8500
#这个固定写死
api-base=https://pay.vichel.com.cn/
#商户私钥
api-key=商户的私钥,如何获取看下面截图
#商户号,看下面截图
mch-no=M1670111111
#应用ID
app-id=1111b3f0e4b05e7111111111
#转账回调地址
wx-withdrawal=${domain-name}/wxPay/result/withdrawalCallback
#支付回调地址
wx-recharge=${domain-name}/wxPay/result/wxRechargeCallback
打开jeePay运营平台,点击我们要对接的应用,点击修改,里面有应用ID和商户号,我们直接复制就可以了。随机生成出一个私钥,点击保存就可以了

 

 

基础配置类

package com.mart.web.pay;

import com.jeequan.jeepay.Jeepay;
import com.jeequan.jeepay.JeepayClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

/**
* JeePay配置相关
*/
@Configuration
//这里指定我们要读取的配置文件
@PropertySource(“classpath:application-jee-pay.properties”)
public class JeePayClientConfig {

@Autowired
private Environment config;

@Bean
public JeepayClient jeePayConfig(){
//地址
Jeepay.setApiBase(config.getProperty(“api-base”));
//私钥
Jeepay.apiKey = config.getProperty(“api-key”);
//商户号
Jeepay.mchNo = config.getProperty(“mch-no”);
//应用ID
Jeepay.appId = config.getProperty(“app-id”);
JeepayClient jeepayClient = JeepayClient.getInstance(Jeepay.appId, Jeepay.apiKey, Jeepay.getApiBase());
return jeepayClient;
}
}
下面是一些支付转账操作的模块,我给大家出了一个示例,里面的参数需要结合业务需求做相应的调整,我下面只要使用的是微信小程序支付和微信零钱的转账功能。商户可以转账到用户微信的零钱。

package com.mart.web.pay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jeequan.jeepay.Jeepay;
import com.jeequan.jeepay.JeepayClient;
import com.jeequan.jeepay.exception.JeepayException;
import com.jeequan.jeepay.model.PayOrderCreateReqModel;
import com.jeequan.jeepay.model.TransferOrderCreateReqModel;
import com.jeequan.jeepay.model.TransferOrderCreateResModel;
import com.jeequan.jeepay.request.PayOrderCreateRequest;
import com.jeequan.jeepay.request.TransferOrderCreateRequest;
import com.jeequan.jeepay.response.PayOrderCreateResponse;
import com.jeequan.jeepay.response.TransferOrderCreateResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
*
* 支付转账核心操作功能模块
*/
@Slf4j
@Service
public class JeePayService {

@Autowired
private JeepayClient jeepayClient;

@Autowired
private Environment config;

/**
* 转账操作,转账到微信零钱(特别注意,下面转账的时候Jeepay一定要使用微信的主商户进行转账,如果使用的是子商户就会出现 {“code”:9999,”msg”:”微信子商户暂不支持转账业务”})
* @param openId 用户的openId
* @param amount 转账金额
* @param numberOn 转账订单号
* @return
*/
public Boolean withdrawal(String openId, BigDecimal amount,String numberOn) {
// 构建请求数据
TransferOrderCreateRequest request = new TransferOrderCreateRequest();
TransferOrderCreateReqModel model = new TransferOrderCreateReqModel();
// 商户号
model.setMchNo(Jeepay.mchNo);
// 应用ID
model.setAppId(Jeepay.appId);
// 商户订单号
model.setMchOrderNo(numberOn);
// 支付方式
model.setIfCode(“wxpay”);
// 入账方式
model.setEntryType(“WX_CASH”);
// 我们传入的是元,这里需要吧金额转成单位分
amount = amount.multiply(new BigDecimal(“100”));
model.setAmount(amount.longValue());
// 币种,目前只支持cny
model.setCurrency(“CNY”);
model.setAccountNo(openId);
// 转账备注
model.setTransferDesc(“测试转账操作”);
// 异步通知地址
model.setNotifyUrl(config.getProperty(“wx-withdrawal”));
// 商户扩展参数,回调时原样返回
model.setExtParam(numberOn);
request.setBizModel(model);
log.info(“jeepay下单参数处理完毕,参数:[{}]”, JSON.toJSONString(request));
try {
TransferOrderCreateResponse response = jeepayClient.execute(request);
// 下单成功
if (response.isSuccess(Jeepay.apiKey)) {
//转账成功
log.warn(“转账成功:{}”);
return true;
}
} catch (JeepayException e) {
log.error(e.getMessage());
}
log.warn(“转账失败:{}”);
return false;
}

/**
* 支付操作,我下面使用的是微信支付的
* @param Subject 商品标题
* @param body 描述
* @param openId 微信的OpenId或者是支付宝的用户ID
* @param amount 支付的金额 CNY
* @param numberOn 平台自己生成的随机订单号
* @return
*/
public String scanPay(String Subject,String body,String openId, BigDecimal amount,String numberOn) {
// 构建请求数据
PayOrderCreateRequest request = new PayOrderCreateRequest();
PayOrderCreateReqModel model = new PayOrderCreateReqModel();
// 商户号
model.setMchNo(Jeepay.mchNo);
// 应用ID
model.setAppId(Jeepay.appId);
// 商户订单号
model.setMchOrderNo(numberOn);
// 支付方式
model.setWayCode(“WX_JSAPI”);
amount = amount.multiply(new BigDecimal(“100”));
// 金额,单位分
model.setAmount(amount.longValue());
// 币种,目前只支持cny
model.setCurrency(“CNY”);
// 发起支付请求客户端的IP地址
model.setClientIp(config.getProperty(“ip-address”));
// 商品标题
model.setSubject(Subject);
// 商品描述
model.setBody(body);
// 异步通知地址
model.setNotifyUrl(config.getProperty(“wx-recharge”));
// 渠道扩展参数 传OpenId
model.setChannelExtra(“{\”openid\”: \””+openId+”\”}”);
// 商户扩展参数,回调时原样返回
model.setExtParam(numberOn);
request.setBizModel(model);
log.info(“jeepay下单参数处理完毕,参数:[{}]”, JSON.toJSONString(request));
try {
PayOrderCreateResponse response = jeepayClient.execute(request);
// 下单成功
if (response.isSuccess(Jeepay.apiKey)) {
String result = response.getData().getString(“payData”);
return result;
}
} catch (JeepayException e) {
log.error(e.getMessage());
}
return null;
}

}
回调函数

package com.mart.web.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.jeequan.jeepay.util.JeepayKit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
* 回调接收
* @author HayDen
* @date 2022-11-15
*/
@RestController
@RequestMapping(“/wxPay/result”)
@SentinelResource(value = “CallbackController”)
public class CallbackController
{

@Autowired
private Environment config;

/**
* 转账回调
* @return
*/
@PostMapping(“/withdrawalCallback”)
public String withdrawalCallback(HttpServletRequest req) throws Exception
{
String result = “failure”;
try {
Map<String, Object> map = getParamsMap(req);
//获取私钥
String apikey = config.getProperty(“api-key”);
//验签
if (chackSgin(map, apikey)) {
return result;
}
//提现成功
//获取订单号
String orderNumber = map.get(“mchOrderNo”).toString();
//提现金额
BigDecimal amount = new BigDecimal(map.get(“amount”).toString()).divide(new BigDecimal(“100”),4,BigDecimal.ROUND_HALF_UP);

}
result = “success”;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

/**
* 微信支付回调
* @return
*/
@PostMapping(“/wxRechargeCallback”)
public String wxRechargeCallback(HttpServletRequest req) throws Exception
{
String result = “failure”;
try {
Map<String, Object> map = getParamsMap(req);
//获取私钥
String apikey = config.getProperty(“api-key”);
//验签
if (chackSgin(map, apikey)) {
return result;
}
//订单号
String orderNumber = map.get(“mchOrderNo”).toString();
//支付金额
BigDecimal amount = new BigDecimal(map.get(“amount”).toString()).divide(new BigDecimal(“100”),4,BigDecimal.ROUND_HALF_UP);
//返回成功
result = “success”;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

/**
* 回调验签
* @param map
* @param apikey
* @return
*/
private Boolean chackSgin(Map<String, Object> map, String apikey) {
Object sign = map.remove(“sign”);
String reSign = JeepayKit.getSign(map, apikey);

if (!Objects.equals(reSign, sign)) {
return true;
}
return false;
}

private Map<String, Object> getParamsMap(HttpServletRequest req) {
Map<String, String[]> requestMap = req.getParameterMap();
Map<String, Object> paramsMap = new HashMap<>();
requestMap.forEach((key, values) -> {
String strs = “”;
for (String value : values) {
strs = strs + value;
}
paramsMap.put(key, strs);
});
return paramsMap;
}

}
好了,到这里基本就结束了,如果大家有什么疑问可以给我留言,看到后一定会第一时间回复的,有建议那是最好的,欢迎大家提出来,如果合理我一定第一时间优化代码。

如果这篇文章在你一筹莫展的时候帮助到了你,可以请作者吃个棒棒糖🙂,如果有啥疑问或者需要完善的地方欢迎大家在下面留言或者私信作者优化改进。

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_38935605/article/details/128639513

【Docker 模块】使用手册 - Linux面板 - 宝塔面板论坛

mikel阅读(62)

来源: 【Docker 模块】使用手册 – Linux面板 – 宝塔面板论坛

什么是 Docker?
Docker 是一个用于开发、发布和运行应用程序的开放平台。Docker 使您能够将应用程序与基础架构分离,以便您可以快速交付软件。使用 Docker,您可以像管理应用程序一样管理基础设施。通过利用 Docker 快速交付、测试和部署代码的方法,您可以显着减少编写代码和在生产环境中运行之间的延迟。

什么是 Dockerfile?
Docker 可以通过读取 Dockerfile 中的指令自动构建镜像,Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

什么是Docker Compose?
Docker Compose 是一种用于帮助定义和共享多容器应用程序的工具。使用 Compose,我们可以创建一个 YAML 文件来定义服务,并且使用一个命令或操作,可以启动所有内容或将其全部关闭。

安装:
测试版本的面板:在左侧菜单 “Docker” 界面安装
正式版本的面板:需要先在”面板设置”中的 面板菜单栏隐藏 将 “Docker” 打开,按F5刷新界面,在左侧菜单 “Docker” 界面安装
安装后界面如下:点击图片可看大图

产品功能列表与详解:
一、镜像
Docker 镜像是容器的基础。镜像没有状态,它永远不会改变。
二、容器
容器是Docker 镜像的运行实例。
三、Compose
Compose是一个使用 Docker 定义和运行复杂应用程序的工具。
四、Compose模板
Compose模板 定义构成Compose 项目的yaml文件。
五、网络
容器网络是由 Docker 为容器创造的虚拟环境的一部分,能让容器从宿主机的网络环境中独立出来。
六、存储卷
存储卷是一个或多个容器中的一个特别指定的目录,存储卷旨在数据持久化,独立于容器的生命周期。因此删除容器时,Docker 永远不会自动删除卷。
七、仓库
仓库是用来存放Docker镜像。
八、设置
Docker 服务的状态。

一、镜像
镜像界面预览:点击图片可看大图

  • 从仓库拉取:从Docker官方库、第三方库拉取镜像
    例:
    从docker官方仓库拉取镜像:mySQL:5.7
    mySQL:5.7 解释; mySQL是镜像的名称,5.7是标签,采用英文“:”分隔
    从第三方仓库拉取镜像:registry.cn-shenzhen.aliyuncs.com/star7th/showdoc
    解释:第三方仓库/用户/镜像的名称,没有标签默认为:latest
  • 导入镜像:从本服务器导入镜像
  • 构建镜像:通过Dockerfile文件构建镜像
    查看构建镜像例子:点我直达 Dockerfile 构建镜像例子
  • 推送:将镜像推送到指定的仓库
    注意:需要先设置你自己仓库,才能进行推送
    标签填写格式:镜像名:标签,镜像名要与仓库名相同才能正常推送。如图:
  • 导出:导出镜像到本服务器
  • 删除:删除镜像,删除镜像后无法恢复请注意相关的备份
  • ID:镜像的sha256指纹信息,也是镜像的ID
  • 镜像名:镜像的名称和标签,Docker镜像唯一的标识,如果”构建/导入镜像”有相同”镜像名称:标签”将会覆盖旧的镜像
  • 大小:镜像的大小
  • 创建时间:镜像创建的时间

二、容器
容器界面预览:点击图片可看大图

  • 添加容器:通过镜像创建容器、通过Compose模板创建容器编排
    例:我们以“mysql:5.7”镜像为例创建容器
    在命令行中一般这样创建容器:

    1. docker run -d –name mysql_test -p 3361:3306 -v /docker/mysql_data/:/var/lib/mysql/ -e MYSQL_ROOT_PASSWORD=my-passwd mysql:5.7

    复制代码

    命令解释:

    run:使用mysql:5.7镜像创建容器
    -d:容器后台运行
    –name:设置容器名为:mysql_test
    -p 3361:3306:映射宿主机3361端口到容器3306端口
    -v /docker/mysql_data/:/var/lib/mysql/:映射宿主机/docker/mysql_data/ 目录到容器/var/lib/mysql/ 目录,用于数据的持久化(宿主机目录如果不存在会自动创建)
    -e:MYSQL_ROOT_PASSWORD=my-passwd:指定环境变量,并设置MySQL root用户密码为 my-passwd,在mysql镜像中如果不指定这条环境变量将无法运行容器

    在面板中可以这样创建容器:

    界面解释:

    容器:对应 –name,填写容器名称
    镜像:选择mysql:5.7 创建容器
    暴露端口:对应 -p 3361:3306 ,注意:填写完成后要点+号图标,才会生效
    启动命令:可留空
    容器停止后自动删除容器:勾上后容器停止将自动删除这个容器,请注意数据的备份删除后无法恢复
    限制CPU、内存:限制容器使用的资源
    挂载卷:对应 -v /docker/mysql_data/:/var/lib/mysql/ ,也可以在 “存储卷界面” 添加并且选择存储卷名做数据的持久化,注意:填写完成后要点+号图标,才会生效
    标签:用于标识容器的用处,可留空
    环境变量:对应 -e MYSQL_ROOT_PASSWORD=my-passwd
    重启规则:
            不重启:重启服务器/重启Docker服务不会启动容器
            关闭时重启:重启服务器/重启Docker服务自动启动容器
            错误时重启(默认5次):容器出错时将重启,超过5次后不再重启,请查看容器日志进行排查错误
    面板默认已经使用 run -d 后台运行
    公共镜像的容器如何使用,请查看其官方的资料
  • 实时监控:实时监控容器的 CPU、内存、硬盘IO、网络IO 资源的使用
  • 终端:终端模式进入容器
    注意:需要容器是启动状态才能进入容器,否则将退出到宿主机
  • 目录:通过文件管理器进入容器目录
  • 日志:查看容器的运行日志
  • 删除:删除容器,删除容器后数据无法恢复请注意数据的备份,如果容器有做数据持久化,存储卷是不会被删除
  • 容器名:可以点击进去使用“容器配置”,“生成镜像”功能
    (1) 容器配置:点击“容器名”查看容器配置,可点击“…”可以查看更多配置

    (2) 生成镜像:将当前容器生成镜像、生成镜像后导出压缩包
  • 状态:可以选择 启动、停止、暂停、取消暂停、重启、重载容器
  • 镜像:容器使用的镜像
  • IP:容器的IP地址
  • CPU使用率:容器的CPU使用率
  • 端口 (主机–>容器):宿主机映射到容器的端口,左边为宿主机
  • 启动时间:第一次启动容器的时间
  • 批量操作:选择1个及以上对容器进行批量操作:启动、停止、暂停、取消暂停、重启、重载、删除容器

三、Compose
Compose界面预览:点击图片可看大图

  • 添加Compose项目:从Compose模板中建立容器
    查看Docker Compose例子:点我直达 Docker Compose例子
  • 容器列表:
    (1) Compose操作:可选择 启动、停止、暂停、取消暂停、重启整个Compose项目
    (2) 状态:可以选择 启动、停止、暂停、取消暂停、重启、重载容器
    (3) 终端:终端模式进入容器
    (4) 目录:通过文件管理器进入容器目录
    (5) 日志:查看容器的运行日志
    (6) 删除:删除单个容器,删除后数据无法恢复请注意数据的备份,如果容器有做数据持久化,存储卷是不会被删除
  • 删除:删除整个Compose项目的容器,将删除项目内所有的容器,删除后数据无法恢复请注意数据的备份,如果容器有做数据持久化,存储卷是不会被删除
  • Compose项目名称:项目名称
  • 容器数量:项目内的容器数量
  • 启动时间:第一次启动容器的时间
  • 描述:用于描述此项目的用处
  • 批量操作:选择1个及以上对项目进行批量操作:删除Comose项目

四、Compose模板
Compose模板界面预览:点击图片可看大图

  • 添加:添加Compose模板、搜索本地模板
  • 编辑:编辑Compose模板
  • 拉取镜像:根据Compose模板的配置拉取镜像
  • 删除:删除Compose模板,删除后无法恢复请注意模板内容的备份
  • 模板名:模板的名称
  • 路径:模板的存储路径
  • 描述:用于描述此模板的用处
  • 批量操作:选择1个及以上对模板进行批量操作:删除Compose模板

五、网络
网络界面预览:点击图片可看大图

  • 添加网络:添加新的网络到Docker
  • 删除:删除容器网络
  • 网络名:网络的名称
  • 显示:网络驱动类型
    (1) none:none模式不使用网络
    (2) host:host模式直接使用宿主机的网络
    (3) bridge:bridge模式与宿主机桥接,容器默认使用的网络
  • 网络号:容器网络的IP范围
  • 网关:容器网络子网的网关IP地址
  • 标签:用于标识容器网络的用处
  • 创建时间:创建容器网络的时间
  • 批量操作:选择1个及以上对网络进行批量操作:删除网络

六、存储卷
存储卷界面预览:点击图片可看大图

  • 添加存储卷:添加新的存储卷
    可先添加存储卷,再到 添加容器界面 选择存储卷
  • 删除:删除存储卷,删除存储卷后数据无法恢复请注意数据的备份
  • 存储卷:容器数据持久化的存储卷名称
  • 挂载点:存储在宿主机的路径
  • 所属容器:目前那个容器在使用这个存储卷
  • 设备:存储卷所存储的设备
  • 创建时间:创建存储卷的时间
  • 标签:用于标识存储卷的用处
  • 批量操作:选择1个及以上对存储卷进行批量操作:删除存储卷,删除存储卷后数据无法恢复请注意数据的备份

七、仓库
仓库界面预览:点击图片可看大图

  • 添加仓库:添加docker官方库、第三方仓库
    docker官方库添加如下:

    添加仓库可参考:https://www.bt.cn/bbs/thread-80965-1-1.html
  • 编辑:编辑仓库
  • 删除:删除仓库
  • URL:镜像仓库链接
  • 用户:登录仓库用户
  • 仓库名:仓库名称/镜像名称
  • 描述:用于标识仓库的用处
  • 批量操作:选择1个及以上对仓库进行批量操作:删除仓库

八、设置
设置界面预览:点击图片可看大图

  • Docker服务:当前Docker服务状态,可开启、重启、停止。启动Docker服务后,容器是否启动根据重启规则来启动
  • 容器监控:开启、关闭。关闭后CPU使用率将不再监控
  • 监控天数:设置容器页面监控保存天数。默认为30天
  • 加速URL:设置加速URL,设置加速后需要手动重启Docker。Docker默认仓库在国内下载较慢,建议使用加速URL
    常用的国内镜像仓库:
    科大:

    1. https://docker.mirrors.ustc.edu.cn/

    复制代码

    网易:

    1. https://hub-mirror.c.163.com/

    复制代码

    阿里云: (需要注册登录获取专属镜像加速器地址) https://cr.console.aliyun.com/

【Docker 模块】使用手册—2022/7/5 第一版
本使用手册编写时使用的环境:
操作系统:CentOS7.9.2009 x86_64,内核3.10.0
面板版本:7.9.2(当前最新正式版)
面板Python环境:3.7.9

如何优雅的一键升级宝塔面板多个Docker容器。 | 老张博客

mikel阅读(57)

来源: 如何优雅的一键升级宝塔面板多个Docker容器。 | 老张博客

目前老张在自己的宝塔面板Docker里部署了好几个项目,Alist、ChatGPT-web、Trilium、思源笔记这四个常用的项目。对于这几个项目里,更新频率最高的就是思源笔记了。我在《宝塔面板下利用Docker部署思源笔记!》等几篇关于宝塔面板Docker的文章里也有说法,如果官方项目版本更新之后,需要将本地的容器和镜像删除之后,重新拉取最新的镜像,然后再新建容器进行重新配置,这样真的很麻烦。

后来经过向度娘请教之后,发现很多人在群晖里升级Docker容器用了watchtower这个项目来自动升级Docker里的项目容器,我便把他搬到了宝塔里来了。

watchtower本身也是Docker里一个项目,但是我们这次使用他是在宝塔面板的”计划任务”里。打开宝塔的“计划任务”新建一个“shell脚本”,执行周期可以设置成每周执行一次。而脚本内容可以按需复制以下代码:

1.运行一次,更新所有的容器,并清除旧的容器 。

docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --cleanup --run-once

2.运行一次,更新所有的容器,并清除旧的容器,并删除watchtower容器。

docker run --rm --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --cleanup --run-once

3.指定容器更新,如无需自动更新所有稳定运行的容器,可以配置仅更新指定容器,只需要在命令后加上容器名.例如只更新nginx和redis。

docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --cleanup --run-once nginx redis

有了这个神项目,就不再需要手动更新docker容器了。

修改『Visual Studio Code(VS Code)』插件默认安装路径的方法_vscode修改插件安装路径-CSDN博客

mikel阅读(87)

来源: 修改『Visual Studio Code(VS Code)』插件默认安装路径的方法_vscode修改插件安装路径-CSDN博客

修改『Visual Studio Code(VS Code)』插件默认安装路径的方法
前言
方法一:修改快捷方式目标路径(★★☆)
1. 确保『code』快捷命令的可用
2. 移动插件文件到自定义目录
3. 将自定义文件夹加入VS Code扩展目录
4. 修改快捷方式目标路径
方法二:默认路径下插件文件变为快捷方式(★☆☆)
总结
前言
作者希望将『Visual Studio Code(以下简称为“VS Code”)』的插件安装在数据盘(D盘),用于统一管理,因此需要修改VS Code插件安装路径。
VS Code插件默认的安装位置为:C:\Users\{个人用户名}\.vscode\extensions。
本文通过2种方式解决问题,作者用(★/☆)标注操作的难易程度,具体如下。

方法一:修改快捷方式目标路径(★★☆)
1. 确保『code』快捷命令的可用
按键 Win + R 进入运行。

输入『cmd』后,按确定进入命令提示符(CMD)。
在命令提示符中输入『code -v』确定『code』快捷命令的可用性。

『code』快捷命令的如不可用,可选择如下操作:
a. 重新安装,并在安装时勾选『添加到PATH(重启后生效)』。
b. VS Code中执行 『Ctrl + Shift + P』,打开命令面板,键入『shell』,选择『Shell命令: 在PATH中安装”code”命令』。
c. 若不想安装,则可选方法二。
2. 移动插件文件到自定义目录
插件默认安装路径在C:\Users\{个人用户名}\.vscode\extensions目录下,找到『extensions』文件夹,右键→剪切。

作者自定义的路径是D:\Buffer\VSCode\extensions,找到D:\Buffer\VSCode,右键→粘贴,将插件文件夹『extensions』移动到此处。

3. 将自定义文件夹加入VS Code扩展目录
按照第1步方式,打开命令提示符(CMD)。
输入『code –extensions-dir “{自定义路径}”』→回车。
注:英文双引号里面是你自己定义的文件夹路径,根据自身情况修改。
code –extensions-dir “D:\Buffer\VSCode\extensions”
1
确认是否修改成功,打开VS Code,点击左侧边栏→扩展,会显示出已安装插件;若未出现已安装插件,则重新执行第2步。
4. 修改快捷方式目标路径
找到VS Code桌面快捷方式,右键→属性→快捷方式→目标,在目标的原目录后面添加『 –extensions-dir “D:\Buffer\VSCode\extensions”』。
注:英文双引号里面是你自己定义的文件夹路径,根据自身情况修改;可以直接复制『』中的内容,(空格)–extensions-dir(空格)”{自定义路径}”。

继按确定,完成修改。点击VS Code桌面快捷方式,点击左侧边栏→扩展,会显示出已安装插件;若未出现已安装插件,则重新执行第2步。
方法二:默认路径下插件文件变为快捷方式(★☆☆)
本方法将C盘插件默认安装路径下的extensions文件夹移动(剪切)到自定义路径,然后将C盘下的extensions文件变为快捷方式。

移动(剪切)插件文件到自定义目录。插件默认安装路径在C:\Users\{个人用户名}\.vscode\extensions目录下,找到『extensions』文件夹,右键→剪切。
注:对文件处理时,必须是剪切。

作者自定义的路径是D:\Buffer\VSCode\extensions,找到D:\Buffer\VSCode,右键→粘贴,将插件文件夹『extensions』移动到此处。

在管理员权限下的命令提示符(CMD)输入以下命令:mklink /D “C:\Users\{个人用户名}\.vscode\extensions” “{自定义路径}”;运行成功后,会提示创建的符号链接。
注:必须在管理员权限下进行;必须使用命令提示符(CMD),不能使用Powershell。
mklink /D “C:\Users\zhang3\.vscode\extensions” “D:\Buffer\VSCode\extensions”
1

3. 打开C:\Users\{个人用户名}\.vscode,extensions变成快捷方式,则修改成功。

 

总结
本文所采用的2种方法,任意选一种都可以解决修改『Visual Studio Code(VS Code)』插件默认安装路径的方法。
请读者根据自身需求,选择所需方式。作者推荐方法二。
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_41679061/article/details/132448137

Visual Studio 修改NuGet 包缓存路径 - Earen - 博客园

mikel阅读(64)

来源: Visual Studio 修改NuGet 包缓存路径 – Earen – 博客园

Visual Studio 下载的NuGet包默认会缓存到 C:\Users{Windows用户名}.nuget\packages 下,时间一长就会导致 C盘空间严重不足。

那么怎样去设置,让包缓存文件保存到其他盘呢?

首先我们要找到 Microsoft.VisualStudio.Offline.config 这个文件,它在哪呢? 在 C:\Program Files (x86)\NuGet\Config。

再到文件并用记事本打开 如下:

我们在中间增加如下配置内容:

  <config>
      <add key="globalPackagesFolder" value="D:\Nuget\.nuget\packages" />
  </config>

最终效果如下图:

这样就配置好了,重新打开 Visual Studio 下载 NuGet 包文件后,查看包的引用地址就会发现地址为修改后的地址。

温馨提示:在配置好地址后,可将原来已经缓存的包文件全部拷贝到新的目录中。

Spring AI与DeepSeek实战四:系统API调用 - zlt2000 - 博客园

mikel阅读(71)

来源: Spring AI与DeepSeek实战四:系统API调用 – zlt2000 – 博客园

一、概述

在 AI 应用开发中,工具调用 Tool Calling 是增强大模型能力的核心技术。通过让模型与外部 API 或工具交互,可实现 实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能。

Spring AI 作为企业级 AI 开发框架,在 1.0.0.M6 版本中进行了重要升级:废弃 Function Calling 引入 Tool Calling 以更贴合行业术语;本文结合 Spring AI 与大模型,演示如何通过 Tool Calling 实现系统 API 调用,同时处理多轮对话中的会话记忆。

关于 Spring AI 与 DeepSeek 的集成,以及 API-KEY 的申请等内容,可参考文章《Spring AI与DeepSeek实战一:快速打造智能对话应用

 

二、函数调用原理

大模型仅负责 决定是否调用工具 和 提供参数,实际执行逻辑由客户端(Spring 应用)实现,确保工具调用的可控性与安全性。

2.1. 工具元数据注入

在发起Chat Request时,将工具描述(name/description)、参数结构(input schema)等元数据封装至请求体,建立大模型的工具调用能力基线。

2.2. 模型决策响应

大模型根据上下文推理生成工具调用指令(tool_calls字段),返回包含选定工具名称及结构化参数的中间响应。

2.3. 服务端路由执行

Spring AI模块解析工具调用指令,通过服务发现机制定位目标工具实例,注入参数并触发同步/异步执行。

2.4. 执行结果标准化

工具返回原始执行结果后,系统进行数据类型校验、异常捕获和JSON序列化处理,生成模型可解析的标准化数据结构。

2.5. 上下文增强推理

将标准化结果作为新增上下文(tool_outputs)回传大模型,触发基于增强上下文的二次推理流程。

2.6. 终端响应生成

模型综合初始请求与工具执行结果,生成最终自然语言响应,完成工具增强的对话闭环。

 

三、核心代码

3.1. 定义工具

创建类 TestTools 并用 @Tool 注解定义 tool 的描述

public static class TestTools {
    @Tool(description = "获取今天日期")
    String getCurrentDateTime() {
        System.out.println("======getCurrentDateTime");
        return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
    }

    @Tool(description = "获取当前温度")
    String getCurrentTemperature(MyToolReques  toolReques) {
        System.out.println("======getCurrentTemperature: " + toolReques.localName + "__" + toolReques.date);
        return toolReques.date + toolReques.localName + "温度为20摄氏度";
    }

    public record MyToolReques(String localName, String date) {}
}

这里定义了两个方法,并通过注解的 description 参数告诉大模型方法的用途。

record 类型是 Java17 的新特性,可用于替代传统的 POJO 类。

3.2. 创建对话接口

private ChatMemory chatMemory = new InMemoryChatMemory();
private MessageChatMemoryAdvisor messageChatMemoryAdvisor = new MessageChatMemoryAdvisor(chatMemory);

@GetMapping(value = "/chat")
public String chat(@RequestParam String input, String sessionId, HttpServletResponse response) {
    response.setCharacterEncoding("UTF-8");

    return chatClient.prompt().user(input)
            .tools(new TestTools())
            .advisors(messageChatMemoryAdvisor)
            .advisors(spec -> spec
                    .param(MessageChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
            .call()
            .content();
}
  • tools 给大模型注册可以调用的方法。
  • MessageChatMemoryAdvisor 实现聊天记忆,InMemoryChatMemory 为 SpringAI 自带的实现(基于内存)。
  • 可以使用 CHAT_MEMORY_CONVERSATION_ID_KEY 参数指定对话ID,不同的会话ID用于隔离记忆。

3.3. 测试

通过后台打印信息可以看到大模型会自动识别,先调用 getCurrentDate 方法获取今天日期,再调用 getCurrentTemperature 方法获取天气。

======getCurrentDate

======getCurrentTemperature: 广州__2025年04月13日

 

加一个聊天框,测试多轮对话效果:

第二次会话直接输入 广州 大模型就知道我要问什么了,说明聊天记忆功能已生效。

 

四、总结

本文以问天气为场景,通过 Tool Calling 实现系统 API 调用,同时实现多轮对话中的会话记忆。需要注意的是 InMemoryChatMemory 只能作为测试使用,在企业应用中需要使用其他实现方式,把聊天记录存储在 Redis 或者 数据库中,并且需要考虑消息的保存时间、容量、如何清除等问题。

 

五、完整代码

  • Gitee地址:

https://gitee.com/zlt2000/zlt-spring-ai-app

  • Github地址:

https://github.com/zlt2000/zlt-spring-ai-app

Spring AI与DeepSeek实战三:打造企业知识库 - zlt2000 - 博客园

mikel阅读(70)

来源: Spring AI与DeepSeek实战三:打造企业知识库 – zlt2000 – 博客园

一、概述

企业应用集成大语言模型(LLM)落地的两大痛点:

  • 知识局限性:LLM依赖静态训练数据,无法覆盖实时更新或垂直领域的知识;
  • 幻觉:当LLM遇到训练数据外的提问时,可能生成看似合理但错误的内容。

用最低的成本解决以上问题,需要使用 RAG 技术,它是一种结合信息检索技术与 LLM 的框架,通过从外部 知识库 动态检索相关上下文信息,并将其作为 Prompt 融入生成过程,从而提升模型回答的准确性;

本文将以AI智能搜索为场景,基于 Spring AI 与 RAG 技术结合,通过构建实时知识库增强大语言模型能力,实现企业级智能搜索场景与个性化推荐,攻克 LLM 知识滞后与生成幻觉两大核心痛点。

关于 Spring AI 与 DeepSeek 的集成,以及 API-KEY 的申请等内容,可参考文章《Spring AI与DeepSeek实战一:快速打造智能对话应用

 

二、RAG数据库选择

构建知识库的数据库一般有以下有两种选择:

维度 向量数据库 知识图谱
数据结构 非结构化数据(文本/图像向量) 结构化关系网络(实体-关系-实体)
查询类型 语义相似度检索 多跳关系推理
典型场景 文档模糊匹配、图像检索 供应链追溯、金融风控
性能指标 QPS>5000 复杂查询响应时间>2s
开发成本 低(API即用) 高(需构建本体模型)

搜索推荐场景更适合选择 向量数据库

 

三、向量模型

向量模型是实现 RAG 的核心组件之一,用于将非结构化数据(如文本、图像、音频)转换为 高维向量(Embedding)的机器学习模型。这些向量能够捕捉数据的语义或结构信息,使计算机能通过数学运算处理复杂关系。

向量数据库是专门存储、索引和检索高维向量的数据库系统

spring-ai-alibaba-starter 默认的向量模型为 text-embedding-v1

可以通过 spring.ai.dashscope.embedding.options.model 进行修改。

 

四、核心代码

4.1. 构建向量数据

创建 resources/rag/data-resources.txt 文件,内容如下:

1. {"type":"api","name":"测试api服务01","topic":"综合政务","industry":"采矿业","remark":"获取采矿明细的API服务"}
2. {"type":"api","name":"新能源车类型","topic":"能源","industry":"制造业","remark":"获取新能源车类型的服务"}
3. {"type":"api","name":"罚款报告","topic":"交通","industry":"制造业","remark":"获取罚款报告的接口"}
4. {"type":"api","name":"光伏发电","topic":"能源","industry":"电力、热力、燃气及水生产和供应业","remark":"获取光伏发电的年度报告"}
5. {"type":"api","name":"收益明细2025","topic":"综合政务","industry":"信息传输、软件和信息技术服务业","remark":"2025年的收益明细信息表"}

创建向量数据库的 Bean

@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel
        , @Value("classpath:rag/data-resources.txt") Resource docs) {
    VectorStore vectorStore = SimpleVectorStore.builder(embeddingModel).build();
    vectorStore.write(new TokenTextSplitter().transform(new TextReader(docs).read()));
    return vectorStore;
}
  • SimpleVectorStore 是 Spring AI 提供的一个基于内存的向量数据库;
  • 使用 TokenTextSplitter 来切分文档。

4.2. 创建ChatClient

private final ChatClient chatClient;

public RagController(ChatClient.Builder builder, VectorStore vectorStore) {
    String sysPrompt = """
            您是一个数据产品的智能搜索引擎,负责根据用户输入的内容进行精准匹配、模糊匹配和近义词匹配,以搜索相关的数据记录。
            您只能搜索指定的内容,不能回复其他内容或添加解释。
            您可以通过[search_content]标识符来表示需要搜索的具体内容。要求您返回匹配内容的完整记录,以JSON数组格式呈现。
            如果搜索不到内容,请返回[no_data]。
            """;
    this.chatClient = builder
            .defaultSystem(sysPrompt)
            .defaultAdvisors(
                    new QuestionAnswerAdvisor(vectorStore, new SearchRequest())
            )
            .defaultOptions(
                    DashScopeChatOptions.builder()
                            .withModel("deepseek-r1")
                            .build()
            )
            .build();
}
  • 通过系统 Prompt 来指定智能体的能力;
  • 通过 QuestionAnswerAdvisor 绑定向量数据库。

4.3. 搜索接口

@GetMapping(value = "/search")
public List<SearchVo> search(@RequestParam String search, HttpServletResponse response) {
    response.setCharacterEncoding("UTF-8");
    PromptTemplate promptTemplate = new PromptTemplate("[search_content]: {search}");
    Prompt prompt = promptTemplate.create(Map.of("search", search));

    return chatClient.prompt(prompt)
            .call()
            .entity(new ParameterizedTypeReference<List<SearchVo>>() {});
}

这里通过 entity 方法来实现搜索结果以结构化的方式返回。

4.4. 测试接口

4.4.1. 搜索新能源

除了模糊匹配了新能源车之外,还匹配了和新能源相关的光伏数据。

4.4.21. 搜索收入

匹配同义词的收益数据。

 

五、总结

本文以智能搜索引擎场景,通过 RAG 技术,实现了全文搜索、模糊搜索、同义词推荐等功能,并以结构化的方式返回搜索结果。需要注意的是,在企业应用中,要把 SimpleVectorStore 改为成熟的第三方向量数据库,例如 milvuselasticsearchredis 等。

 

六、完整代码

  • Gitee地址:

https://gitee.com/zlt2000/zlt-spring-ai-app

  • Github地址:

https://github.com/zlt2000/zlt-spring-ai-app

Spring AI与DeepSeek实战二:打造企业级智能体 - zlt2000 - 博客园

mikel阅读(46)

来源: Spring AI与DeepSeek实战二:打造企业级智能体 – zlt2000 – 博客园

一、概述

智能体 Agent 能自主执行任务实现特定目标的 AI 程序。传统 AI(如ChatGPT)主要依靠用户输入指令,而智能体 Agent 可以自主思考、决策,并执行复杂任务,就像一个AI助手,能够独立完成多步操作。本文将以多语言翻译助手为场景,演示如何基于Spring AI与DeepSeek模型构建一个支持多种语言的企业级翻译智能体,实现精准可控的跨语言交互。

关于 Spring AI 与 DeepSeek 的集成,以及 API-KEY 的申请等内容,可参考文章《Spring AI与DeepSeek实战一:快速打造智能对话应用

 

二、系统Prompt

智能体的核心在于通过 Prompt 工程明确其能力边界。以下为翻译智能体的系统级 Prompt 设计:

您是一名专业的多语言翻译助手,需严格遵守以下规则:
1. **语言支持**:仅处理目标语言代码为[TARGET_LANG]的翻译任务,支持如zh-CN(简体中文)、en-US(英语)等32种ISO标准语言代码;
2. **输入格式**:用户使用---translate_content---作为分隔符,仅翻译分隔符内的文本,其余内容视为无效指令;
3. **行为限制**:禁止回答与翻译无关的问题,若输入不包含合法分隔符或目标语言,回复:"请提供有效的翻译指令"。
4. **支持多语言**:需要翻译的内容如果包含多种语言,都需要同时翻译为TARGET_LANG指定的语言。

关键设计解析:

  • 需要给大模型明确 角色 和 行为边界
  • 通过 TARGET_LANG 参数化语言配置,便于动态扩展;
  • 使用 ---translate_content--- 强制结构化输入,避免模型处理无关信息;
  • 明确拒绝策略,保障服务安全性。

 

三、Prompt模板

结合Spring AI的prompt模板,实现动态Prompt生成:

TARGET_LANG: {target}
---translate_content---
"{content}"

关键设计解析:

  • 使用占位符 {TARGET_LANG} 和 {content} 实现多语言动态适配;
  • 无论用户输入任何内容,只会出现在 translate_content 分隔符下。

 

四、核心代码

@GetMapping(value = "/translate")
public String translate(@RequestParam String input, @RequestParam(required = false) String target, HttpServletResponse response) {
    String systemPrompt = """
               您是一名专业的多语言翻译助手,需严格遵守以下规则:
               1. **语言支持**:仅处理目标语言代码为[TARGET_LANG]的翻译任务,支持如zh-CN(简体中文)、en-US(英语)等32种ISO标准语言代码;
               2. **输入格式**:用户使用---translate_content---作为分隔符,仅翻译分隔符内的文本,其余内容视为无效指令;
               3. **行为限制**:禁止回答与翻译无关的问题,若输入不包含合法分隔符或目标语言,回复:"请提供有效的翻译指令"。
               4. **支持多语言**:需要翻译的内容如果包含多种语言,都需要同时翻译为TARGET_LANG指定的语言。
               """;

    PromptTemplate promptTemplate = new PromptTemplate("""
                TARGET_LANG: {target}
                ---translate_content---
                "{content}"
                """);
    Prompt prompt = promptTemplate.create(Map.of("target", target, "content", input));

    String result = chatClient.prompt(prompt)
            .system(systemPrompt)
            .call()
            .content();
    if (result != null && result.length() >= 2) {
        result = result.substring(1, result.length() - 1);
    }
    return result;
}

通过 target 来指定目标语言,input 参数为需要翻译的内容。

 

五、测试

  • 直接调用接口测试:

尝试输入提问方式的内容,大模型也仅翻译内容

  • 配套一个前端页面测试:

  • 多语言同时翻译:
    翻译包含八种语言的内容

 

六、总结

本文通过翻译场景, 封印 了大模型的对话能力,演示了企业级智能体的三大核心能力:指令结构化行为边界控制 与 动态模板适配。然而,现实中的复杂任务(如合同审核、数据分析)往往需要更高级能力:

  1. 任务拆解:将复杂问题拆解为子任务链(如”翻译→摘要生成→格式校验”);
  2. 工作流引擎:通过状态机管理任务执行顺序与异常重试;
  3. 记忆与上下文:实现多轮对话的长期记忆管理。

 

七、完整代码

  • Gitee地址:

https://gitee.com/zlt2000/zlt-spring-ai-app

  • Github地址:

https://github.com/zlt2000/zlt-spring-ai-app

Spring Cloud Alibaba AI 入门与实践 - zlt2000 - 博客园

mikel阅读(61)

来源: Spring Cloud Alibaba AI 入门与实践 – zlt2000 – 博客园

一、概述

Spring AI 是 Spring 官方社区项目,旨在简化 Java AI 应用程序开发,让 Java 开发者像使用 Spring 开发普通应用一样开发 AI 应用。

Spring Cloud Alibaba AI 是一个将 Spring Cloud 微服务生态与阿里巴巴 AI 能力无缝集成的框架,帮助开发者快速构建具备 AI 功能的现代化应用。本文将介绍 Spring Cloud Alibaba AI 的基本概念、主要特性和功能,并演示如何完成一个 在线聊天 和 在线画图 的 AI 应用。

 

二、主要特性和功能

Spring Cloud Alibaba AI 目前基于 Spring AI 0.8.1 版本 API 完成通义系列大模型的接入。通义接入是基于阿里云 阿里云百炼 服务;而 阿里云百炼 建立在 模型即服务(MaaS) 的理念基础之上,围绕 AI 各领域模型,通过标准化的 API 提供包括模型推理、模型微调训练在内的多种模型服务。

主要提供以下核心功能:

2.1. 简单易用的集成

通过 Spring Boot 风格的自动配置机制,开发者只需少量代码配置,即可快速接入阿里云的 AI 服务。

2.2. 丰富的 AI 服务支持

支持以下核心能力:

  • 自然语言处理(NLP):文本分析、智能问答、翻译。
  • 计算机视觉(CV):图像生成、图像识别、目标检测。
  • 语音处理:语音识别、语音合成。
  • 数据分析与预测:数据建模、趋势分析。

2.3. 高度扩展性

通过配置中心和注册中心(如 Nacos)实现动态扩展,支持微服务架构的扩展需求。
提供接口定义,方便接入第三方 AI 平台。

 

三、构建 AI 应用

Spring Cloud Alibaba AI 对 Java 版本有要求,所以需要提前预装好 Java 17 环境。

3.1. 申请 API-KEY

登录阿里云,进入 阿里云百炼 的页面:

https://bailian.console.aliyun.com/?apiKey=1#/api-key

创建自己的 API-KEY

3.2. 添加依赖

在 Spring Boot 项目的 pom.xml 中添加 alibaba-ai 依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-ai</artifactId>
</dependency>

<repositories>
    <repository>
        <id>alimaven</id>
        <url>https://maven.aliyun.com/repository/public</url>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-snapshots</id>
        <url>https://repo.spring.io/snapshot</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

 

3.3. 配置 API-KEY

在 application.yml 中配置 Kafka 的相关属性,包括服务器地址、认证信息等。

spring:
  cloud:
    ai:
      tongyi:
        connection:
          api-key: sk-xxxxxx
  • api-key 配置在阿里云百炼里申请的api-key

3.4. 创建模型调用服务

@Service
@Slf4j
public class TongYiSimpleService {
    @Resource
    private TongYiChatModel chatClient;
    @Resource
    private TongYiImagesModel imageClient;

    public String chat(String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return chatClient.call(prompt).getResult().getOutput().getContent();
    }

    public String image(String message) {
        ImagePrompt prompt = new ImagePrompt(message);
        Image image = imageClient.call(prompt).getResult().getOutput();
        return image.getB64Json();
    }
}

聊天和图片的服务,分别通过注入 TongYiChatModel 和 TongYiImagesModel 对象来实现,屏蔽底层通义大模型交互细节。

3.5. 创建controller

@RestController
@RequestMapping("/ai")
public class TongYiController {
    @Resource
    private TongYiSimpleService tongYiSimpleService;

    @GetMapping("/chat")
    public String chat(@RequestParam(value = "message") String message) {
        return tongYiSimpleService.chat(message);
    }

    @GetMapping("/image")
    public ResponseEntity<byte[]> image(@RequestParam(value = "message") String message) {
        String b64Str = tongYiSimpleService.image(message);
        byte[] imageBytes = Base64.getDecoder().decode(b64Str);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);
        return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
    }
}

3.6. 测试效果

3.6.1. 聊天接口

在浏览器输入:http://localhost:8009/ai/chat?message=你是谁

3.6.2. 图片接口

在浏览器输入:http://localhost:8009/ai/image?message=意大利面拌42号混凝土

3.6.3. 搭配聊天页面

四、总结

当前版本的 Spring Cloud Alibaba AI 主要完成了几种常见生成式模型的适配,涵盖对话、文生图、文生语音等。在未来的版本中将继续推进 VectorStoreEmbeddingETL PipelineRAG 等更多 AI 应用开发场景的建设。

完整的样例代码下载:
https://gitee.com/zlt2000/spring-cloud-ai-sample