SpringBoot集成支付宝,看这一篇就够了。
前 言
在开始集成支付宝支付之前,我们需要准备一个支付宝商家账户,如果是个人开发者,可以通过注册公司或者让有公司资质的单位进行授权,后续在集成相关API的时候需要提供这些信息。
下面我以电脑网页端在线支付为例,介绍整个从集成、测试到上线的具体流程。
1. 预期效果展示
在开始之前我们先看下我们要达到的最后效果,具体如下:
- 前端点击支付跳转到支付宝界面
- 支付宝界面展示付款二维码
- 用户手机端支付
- 完成支付,支付宝回调开发者指定的url
2. 开发流程
2.1 沙盒调试
支付宝为我们准备了完善的沙盒开发环境,我们可以先在沙盒环境调试好程序,后续新建好应用并成功上线后,把程序中对应的参数替换为线上参数即可。
1. 创建沙盒应用
直接进入 https://open.alipay.com/develop/sandbox/app 创建沙盒应用即可,
这里因为是测试环境,我们就选择系统默认密钥就行了,下面选择公钥模式,另外应用网关地址就是用户完成支付之后,支付宝会回调的url。在开发环境中,我们可以采用内网穿透的方式,将我们本机的端口暴露在某个公网地址上,这里推荐 https://natapp.cn/ ,可以免费注册使用。
2. SpringBoot代码实现
在创建好沙盒应用,获取到密钥,APPID,商家账户PID等信息之后,就可以在测试环境开发集成对应的API了。这里我以电脑端支付API为例,介绍如何进行集成。
关于电脑网站支付的详细产品介绍和API接入文档可以参考:https://opendocs.alipay.com/open/repo-0038oa?ref=api 和 https://opendocs.alipay.com/open
- 步骤1, 添加alipay sdk对应的Maven依赖。
<!-- alipay -->
<dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.35.132.ALL</version>
</dependency>
- 步骤2,添加支付宝下单、支付成功后同步调用和异步调用的接口。
这里需要注意,同步接口是用户完成支付后会自动跳转的地址,因此需要是Get请求。异步接口,是用户完成支付之后,支付宝会回调来通知支付结果的地址,所以是POST请求。
@RestController
@RequestMapping("/alipay")
public class AliPayController { @Autowired AliPayService aliPayService; @PostMapping("/order") public GenericResponse<Object> placeOrderForPCWeb(@RequestBody AliPayRequest aliPayRequest) { try { return aliPayService.placeOrderForPCWeb(aliPayRequest); } catch (IOException e) { throw new RuntimeException(e); } } @PostMapping("/callback/async") public String asyncCallback(HttpServletRequest request) { return aliPayService.orderCallbackInAsync(request); } @GetMapping("/callback/sync") public void syncCallback(HttpServletRequest request, HttpServletResponse response) { aliPayService.orderCallbackInSync(request, response); } }
- 步骤3,实现Service层代码
这里针对上面controller中的三个接口,分别完成service层对应的方法。下面是整个支付的核心流程,其中有些地方需要根据你自己的实际情况进行保存订单到DB或者检查订单状态的操作,这个可以根据实际业务需求进行设计。
public class AliPayService { @Autowired AliPayHelper aliPayHelper; @Resource AlipayConfig alipayConfig; @Transactional(rollbackFor = Exception.class) public GenericResponse<Object> placeOrderForPCWeb(AliPayRequest aliPayRequest) throws IOException { log.info("【请求开始-在线购买-交易创建】*********统一下单开始*********"); String tradeNo = aliPayHelper.generateTradeNumber(); String subject = "购买套餐1"; Map<String, Object> map = aliPayHelper.placeOrderAndPayForPCWeb(tradeNo, 100, subject); if (Boolean.parseBoolean(String.valueOf(map.get("isSuccess")))) { log.info("【请求开始-在线购买-交易创建】统一下单成功,开始保存订单数据"); //保存订单信息 // 添加你自己的业务逻辑,主要是保存订单数据log.info("【请求成功-在线购买-交易创建】*********统一下单结束*********"); return new GenericResponse<>(ResponseCode.SUCCESS, map.get("body")); }else{ log.info("【失败:请求失败-在线购买-交易创建】*********统一下单结束*********"); return new GenericResponse<>(ResponseCode.INTERNAL_ERROR, String.valueOf(map.get("subMsg"))); } } // sync return page public void orderCallbackInSync(HttpServletRequest request, HttpServletResponse response) { try { OutputStream outputStream = response.getOutputStream(); //通过设置响应头控制浏览器以UTF-8的编码显示数据,如果不加这句话,那么浏览器显示的将是乱码 response.setHeader("content-type", "text/html;charset=UTF-8"); String outputData = "支付成功,请返回网站并刷新页面。"; /** * data.getBytes()是一个将字符转换成字节数组的过程,这个过程中一定会去查码表, * 如果是中文的操作系统环境,默认就是查找查GB2312的码表, */ byte[] dataByteArr = outputData.getBytes("UTF-8");//将字符转换成字节数组,指定以UTF-8编码进行转换 outputStream.write(dataByteArr);//使用OutputStream流向客户端输出字节数组 } catch (IOException e) { throw new RuntimeException(e); } } public String orderCallbackInAsync(HttpServletRequest request) { try { Map<String, String> map = aliPayHelper.paramstoMap(request); String tradeNo = map.get("out_trade_no"); String sign = map.get("sign"); String content = AlipaySignature.getSignCheckContentV1(map); boolean signVerified = aliPayHelper.CheckSignIn(sign, content); // check order status // 这里在DB中检查order的状态,如果已经支付成功,无需再次验证。if(从DB中拿到order,并且判断order是否支付成功过){ log.info("订单:" + tradeNo + " 已经支付成功,无需再次验证。"); return "success"; } //验证业务数据是否一致 if(!checkData(map, order)){ log.error("返回业务数据验证失败,订单:" + tradeNo ); return "返回业务数据验证失败"; } //签名验证成功 if(signVerified){ log.info("支付宝签名验证成功,订单:" + tradeNo); // 验证支付状态 String tradeStatus = request.getParameter("trade_status"); if(tradeStatus.equals("TRADE_SUCCESS")){ log.info("支付成功,订单:"+tradeNo); // 更新订单状态,执行一些业务逻辑return "success"; }else{ System.out.println("支付失败,订单:" + tradeNo ); return "支付失败"; } }else{ log.error("签名验证失败,订单:" + tradeNo ); return "签名验证失败."; } } catch (IOException e) { log.error("IO exception happened ", e); throw new RuntimeException(ResponseCode.INTERNAL_ERROR, e.getMessage()); } } public boolean checkData(Map<String, String> map, OrderInfo order) { log.info("【请求开始-交易回调-订单确认】*********校验订单确认开始*********"); //验证订单号是否准确,并且订单状态为待支付 if(验证订单号是否准确,并且订单状态为待支付){ float amount1 = Float.parseFloat(map.get("total_amount")); float amount2 = (float) order.getOrderAmount(); //判断金额是否相等 if(amount1 == amount2){ //验证收款商户id是否一致 if(map.get("seller_id").equals(alipayConfig.getPid())){ //判断appid是否一致 if(map.get("app_id").equals(alipayConfig.getAppid())){ log.info("【成功:请求开始-交易回调-订单确认】*********校验订单确认成功*********"); return true; } } } } log.info("【失败:请求开始-交易回调-订单确认】*********校验订单确认失败*********"); return false; }
}
- 步骤4,实现alipayHelper类。这个类里面对支付宝的接口进行封装。
public class AliPayHelper { @Resource private AlipayConfig alipayConfig; //返回数据格式 private static final String FORMAT = "json"; //编码类型 private static final String CHART_TYPE = "utf-8"; //签名类型 private static final String SIGN_TYPE = "RSA2"; /*支付销售产品码,目前支付宝只支持FAST_INSTANT_TRADE_PAY*/ public static final String PRODUCT_CODE = "FAST_INSTANT_TRADE_PAY"; private static AlipayClient alipayClient = null; private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); private static final Random random = new Random(); @PostConstruct public void init(){ alipayClient = new DefaultAlipayClient( alipayConfig.getGateway(), alipayConfig.getAppid(), alipayConfig.getPrivateKey(), FORMAT, CHART_TYPE, alipayConfig.getPublicKey(), SIGN_TYPE); }; /*================PC网页支付====================*/ /** * 统一下单并调用支付页面接口 * @param outTradeNo * @param totalAmount * @param subject * @return */ public Map<String, Object> placeOrderAndPayForPCWeb(String outTradeNo, float totalAmount, String subject){ AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); request.setNotifyUrl(alipayConfig.getNotifyUrl()); request.setReturnUrl(alipayConfig.getReturnUrl()); JSONObject bizContent = new JSONObject(); bizContent.put("out_trade_no", outTradeNo); bizContent.put("total_amount", totalAmount); bizContent.put("subject", subject); bizContent.put("product_code", PRODUCT_CODE); request.setBizContent(bizContent.toString()); AlipayTradePagePayResponse response = null; try { response = alipayClient.pageExecute(request); } catch (AlipayApiException e) { e.printStackTrace(); } Map<String, Object> resultMap = new HashMap<>(); resultMap.put("isSuccess", response.isSuccess()); if(response.isSuccess()){ log.info("调用成功"); log.info(JSON.toJSONString(response)); resultMap.put("body", response.getBody()); } else { log.error("调用失败"); log.error(response.getSubMsg()); resultMap.put("subMsg", response.getSubMsg()); } return resultMap; } /** * 交易订单查询 * @param out_trade_no * @return */ public Map<String, Object> tradeQueryForPCWeb(String out_trade_no){ AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); JSONObject bizContent = new JSONObject(); bizContent.put("trade_no", out_trade_no); request.setBizContent(bizContent.toString()); AlipayTradeQueryResponse response = null; try { response = alipayClient.execute(request); } catch (AlipayApiException e) { e.printStackTrace(); } Map<String, Object> resultMap = new HashMap<>(); resultMap.put("isSuccess", response.isSuccess()); if(response.isSuccess()){ System.out.println("调用成功"); System.out.println(JSON.toJSONString(response)); resultMap.put("status", response.getTradeStatus()); } else { System.out.println("调用失败"); System.out.println(response.getSubMsg()); resultMap.put("subMsg", response.getSubMsg()); } return resultMap; } /** * 验证签名是否正确 * @param sign * @param content * @return */ public boolean CheckSignIn(String sign, String content){ try { return AlipaySignature.rsaCheck(content, sign, alipayConfig.getPublicKey(), CHART_TYPE, SIGN_TYPE); } catch (AlipayApiException e) { e.printStackTrace(); } return false; } /** * 将异步通知的参数转化为Map * @return */ public Map<String, String> paramstoMap(HttpServletRequest request) throws UnsupportedEncodingException { Map<String, String> params = new HashMap<String, String>(); Map<String, String[]> requestParams = request.getParameterMap(); for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } // 乱码解决,这段代码在出现乱码时使用。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } return params; } }
- 步骤5,封装config类,用于存放所有的配置属性。
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig { private String gateway; private String appid; private String pid; private String privateKey; private String publicKey; private String returnUrl; private String notifyUrl; }
另外需要在application.properties中,准备好上述对应的属性。
# alipay config
alipay.gateway=https://openapi.alipaydev.com/gateway.do
alipay.appid=your_appid
alipay.pid=your_pid
alipay.privatekey=your_private_key
alipay.publickey=your_public_key
alipay.returnurl=完成支付后的同步跳转地址
alipay.notifyurl=完成支付后,支付宝会异步回调的地址
3. 前端代码实现
前端代码只需要完成两个功能, 1. 根据用户的请求向后端发起支付请求。 2. 直接提交返回数据完成跳转。
下面的例子中,我用typescript实现了用户点击支付之后的功能,
async function onPositiveClick() { paymentLoading.value = true const { data } = await placeAlipayOrder<string>({ //你的一些请求参数,例如金额等等}) const div = document.createElement('divform') div.innerHTML = data document.body.appendChild(div) document.forms[0].setAttribute('target', '_blank') document.forms[0].submit() showModal.value = false paymentLoading.value = false
}
2.2 创建并上线APP
完成沙盒调试没问题之后,我们需要创建对应的支付宝网页应用并上线。
登录 https://open.alipay.com/develop/manage 并选择创建网页应用。
填写应用相关信息:
创建好应用之后,首先在开发设置中,设置好接口加签方式以及应用网关。
注意密钥选择RSA2,其他按照上面的操作指南一步步走即可,注意保管好自己的私钥和公钥。
之后在产品绑定页,绑定对应的API,比如我们这里是PC网页端支付,找到对应的API绑定就可以了。如果第一次绑定,可能需要填写相关的信息进行审核,按需填写即可,一般审核一天就通过了。
最后如果一切就绪,我们就可以把APP提交上线了,上线成功之后,我们需要把下面SpringBoot中的properties替换为线上APP的信息,然后就可以在生产环境调用支付宝的接口进行支付了。
# alipay config
alipay.gateway=https://openapi.alipaydev.com/gateway.do
alipay.appid=your_appid
alipay.pid=your_pid
alipay.privatekey=your_private_key
alipay.publickey=your_public_key
alipay.returnurl=完成支付后的同步跳转地址
alipay.notifyurl=完成支付后,支付宝会异步回调的地址
相关文章:
SpringBoot集成支付宝,看这一篇就够了。
前 言 在开始集成支付宝支付之前,我们需要准备一个支付宝商家账户,如果是个人开发者,可以通过注册公司或者让有公司资质的单位进行授权,后续在集成相关API的时候需要提供这些信息。 下面我以电脑网页端在线支付为例,介…...
数据结构程序设计——哈希表的应用(2)->哈希表解决冲突的方法
目录 实验须知 代码实现 实验报告 一:问题分析 二、数据结构 1.逻辑结构 2.物理结构 三、算法 (一)主要算法描述 1.用除留余数法构造哈希函数 2.线性探测再散列法 (一)主要算法实现代码 四、上机调试 实…...
微信小程序开发系列-07组件
微信小程序开发系列目录 《微信小程序开发系列-01创建一个最小的小程序项目》《微信小程序开发系列-02注册小程序》《微信小程序开发系列-03全局配置中的“window”和“tabBar”》《微信小程序开发系列-04获取用户图像和昵称》《微信小程序开发系列-05登录小程序》《微信小程序…...
JavaScript 中 Set 和 Map 的区别
JavaScript 中的 Set 和 Map 都是用来存储数据的数据结构,它们之间的区别如下: Set 是一组唯一值的集合,而 Map 是一组键值对的集合。Set 中的值是唯一的,不允许重复;Map 中的键是唯一的,值可以重复。Set …...
web前端之JavaScript
MENU JavaScript之设计模式、单例、代理、装饰者、中介者、观察者、发布订阅、策略JavaScript之数组静态方法的实现、reduce、forEach、map、push、every JavaScript之设计模式、单例、代理、装饰者、中介者、观察者、发布订阅、策略 单例模式 概念 保证一个类仅有一个实例&am…...
C# 图标标注小工具-查看重复文件
目录 效果 项目 代码 下载 效果 项目 代码 using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Windows.Forms;namespace ImageDuplicate {public partial clas…...
浅谈冯诺依曼体系和操作系统
🌎冯诺依曼体系结构 文章目录 冯诺依曼体系结构 认识冯诺依曼体系结构 硬件分类 各个硬件的简单认识 输入输出设备 中央处理器 存储器 关于内存 对冯诺依曼体系的理解 操作系统 操作系统…...
Good Bye 2023
Good Bye 2023 Good Bye 2023 A. 2023 题意:序列a中所有数的乘积应为2023,现在给出序列中的n个数,找到剩下的k个数并输出,报告不可能。 思路:把所有已知的数字乘起来,判断是否整除2023,不够…...
多开工具对手机应用响应速度的优化与改进
多开工具对手机应用响应速度的优化与改进 摘要: 如今,手机应用的多样化和个性化需求不断增长,用户对应用的响应速度要求也越来越高。为了满足用户的需求,开发者们使用了多种技术手段进行应用的优化和改进。其中,多开工…...
文件批量整理,文件归类整理,文件批量归类
我们每天都要面对无数的文件,从工作报告、个人照片到电影和音乐。如何有效地管理和归类这些文件,成为了我们日常生活和工作中所要处理的。今天,小编就给大家介绍一款简单易用的工具——文件批量改名高手,助你轻松实现文件批量归类…...
Python+Django+Mysql+SimpleUI搭建后端用户管理系统(非常详细,每一步都清晰,列举了里面所有使用的方法属性)
一、在Anaconda环境下创建虚拟环境 (1)打开Anaconda Prompt(install),创建虚拟环境,如下图所示: 方法一:默认情况下虚拟环境创建在Anaconda安装目录下的envs文件夹中 conda create --name usermanage …...
【Qt-QWidget-QLabel-QFrame-QSlider-View-Bar】
Qt编程指南 ■ Label■ QLabel■ QMovie 显示动画■ Widget■ QWidget■ QTabWidget■ QTableWidget■ QListWidget■ QStackedWidget■ QCalendarWidget■ QFrame■ QFrame■ View■ QT...
11|代理(上):ReAct框架,推理与行动的协同
11|代理(上):ReAct框架,推理与行动的协同 在之前介绍的思维链(CoT)中,我向你展示了 LLMs 执行推理轨迹的能力。在给出答案之前,大模型通过中间推理步骤(尤其…...
毫秒格式化
## 计算当前毫秒数: const [start,setStart] useState(new Date().getTime())useEffect(()>{setInterval(()>{setCurrMill(new Date().getTime()-start)},1)},[]) ## 格式化毫秒 function formatMilliseconds(milliseconds) {const totalSeconds Math.flo…...
pytorch与cuda版本对应关系汇总
pytorch与cuda版本关系 cuda版本支持pytorch版本cuda10.21.5 ~ 1.12cuda11.01.7 ~ 1.7.1cuda11.11.8 ~ 1.10.1cuda11.31.8.1 ~ 1.12.1cuda11.61.12.0 ~ 1.13.1cuda11.71.13.0 ~ 2.0.1cuda11.82.0.0 ~ 2.1.1cuda12.12.1.0 ~ 2.1.1 cuda 与 cudnn关系 cuda版本支持cudnn版本cu…...
Linux系统下隧道代理HTTP
在Linux系统下配置隧道代理HTTP是一个涉及网络技术的话题,主要目的是在客户端和服务器之间建立一个安全的通信通道。下面将详细解释如何进行配置。 一、了解基本概念 在开始之前,需要了解几个关键概念:代理服务器、隧道代理和HTTP协议。代理…...
unity学习笔记----游戏练习03
一、修复植物种植的问题 1.当手上存在植物时,再次点击卡片上的植物就会在手上添加新的植物,需要修改成只有手上没有植物时才能再次获取到植物。需要修改AddPlant方法。 public bool AddPlant(PlantType plantType) { //防止手上出现多个植…...
VistualStudio查看类图UML
点击菜单栏中的工具–》获取工具和功能。 然后在资源管理器中对应的代码中鼠标右键选择查看类图 生成一个ClassDiagram.cd文件就是类图的文件了。 根据需要拖拽就可以生成类图了。...
elasticsearch系列九:异地容灾-CCR跨集群复制
概述 起初只在部分业务中采用es存储数据,在主中心搭建了个集群,随着es在我们系统中的地位越来越重要,数据也越来越多,针对它的安全性问题也越发重要,那如何对es做异地容灾呢? 今天咱们就一起看下官方提供的…...
基于Java网上点餐系统设计与实现
博主介绍: ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精彩专栏 推荐订阅 👇🏻 不然下次找不到 Java项目精品实…...
公司电脑文件加密系统——防止内部核心文件数据 | 资料外泄,自动智能透明加密保护
一套从源头上保障企业电脑数据安全和电脑使用安全的加密软件。天锐绿盾加密软件包含了表格数据加密、图纸加密、文档文件加密、内网文件加密流转、密级管控、电脑离线管理、文件外发管理、灵活的审批流程、工作模式切换、服务器白名单等功能。天锐绿盾加密系统全面覆盖Mac、Win…...
计算机毕业设计------ssm茶叶溯源系统
项目介绍 茶叶溯源系统,分为前台与后台。普通用户可在前台通过18位的编码查询茶叶的出售历史。 后台分为两种角色,管理员与经销商; 管理员主要功能包括: 主界面; 管理员管理:管理员列表、添加管理员&am…...
【网络安全 | Misc】miss_01 太湖杯
解压时提示输入密码: 如果 frFlags 或 deFlags 不为0会导致zip的伪加密 将deFlags的值修改为0 将9改为0,另存为123.zip: 即可绕过加密: 得到一个zip一个docx,但zip需要密码: 因此看docx有无敏感信息&#x…...
【深度学习目标检测】十一、基于深度学习的电网绝缘子缺陷识别(python,目标检测,yolov8)
YOLOv8是一种物体检测算法,是YOLO系列算法的最新版本。 YOLO(You Only Look Once)是一种实时物体检测算法,其优势在于快速且准确的检测结果。YOLOv8在之前的版本基础上进行了一系列改进和优化,提高了检测速度和准确性。…...
《深入理解C++11:C++11新特性解析与应用》笔记六
第六章 提高性能及操作硬件的能力 6.1 常量表达式 6.1.1 运行时常量性与编译时常量性 大多数情况下,const描述的是运行时常量性,也即是运行时数据的不可更改性。但有时候我们需要的却是编译时的常量性,这是const关键字无法保证的。例如&am…...
C# 基于事件的观察者模式
观察者模式是一种软件设计模式,用于定义对象之间的一对多依赖关系,当一个对象的状态发生变化时,它的所有依赖者(观察者)都将得到通知并自动更新。这种模式通过解耦合主题和观察者来提高对象的灵活性。 定义 观察者模式…...
ARM CCA机密计算软件架构之软件堆栈概述
Arm CCA平台通过硬件添加和固件组件的混合方式实现,例如在处理元素(PEs)中的RME以及特定的固件组件,特别是监视器和领域管理监视器。本节介绍Arm CCA平台的软件堆栈。 软件堆栈概述 领域VM的执行旨在与Normal world(正常世界)隔离,领域VM由Normal world Host(正常世界…...
《Python机器学习原理与算法实现》学习笔记
以下为《Python机器学习原理与算法实现》(杨维忠 张甜 著 2023年2月新书 清华大学出版社)的学习笔记。 根据输入数据是否具有“响应变量”信息,机器学习被分为“监督式学习”和“非监督式学习”。 “监督式学习”即输入数据中即有X变量&…...
k8s集群通过helm部署skywalking
1、安装helm 下载脚本安装 ~# curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 ~# chmod 700 get_helm.sh ~# ./get_helm.sh或者下载包进行安装 ~# wget https://get.helm.sh/helm-canary-linux-amd64.tar.gz ~# mv helm …...
介绍一款PDF在线工具
PDF是我们日常工作中的一种常见格式,其处理也是我们工作的重要基础性环节,一款可靠的处理工具显得十分重要。 完全免费、易于使用、丰富的PDF处理工具,包括:合并、拆分、压缩、转换、旋转和解锁PDF文件,以及给PDF文件…...
wordpress 更新url/网站快速排名
1、PNP逻辑数据库。 LOOP获取信息类型数据。 TABLES: PERNR . INFOTYPES: 0000, 0001 .START-OF-SELECTION.GET PERNR .LOOP AT P0000 WHERE ......ENDLOOP.LOOP AT P0001 WHERE ......ENDLOOP. 宏获取信息类型数据。 TABLES: PERNR, T001P. INFOTYPES: 0000, 0001 .GET PERNR …...
大型网站建设公司 北京/广告接单网站
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼n2;//换方下子}else{chess[i][j]2;setfillcolor(BLACK); setfillstyle(BLACK);fillellipse(m.x-7,m.y-7,m.x7,m.y7);if(Game_Over1(chess,2)1||Game_Over2(chess,2)1||Game_Over3(chess,2)1) {setcolor(BLACK);outtextxy(200,200,&…...
bilibili推广网站/诊断网站seo现状的方法
文章目录一、使用idea构建项目二、项目结构三、编写第一个程序Hello World四、配置项目的热部署五、单元测试一、使用idea构建项目 1、选择 File -> New —> Project… 弹出新建项目的框 2、选择 Spring Initializr,Next 也会出现上述类似的配置界面…...
基于aws ec2免费实例进行网站建设/营销策划书范文案例
介绍: 一个富有动感的Sheet(选择器), 支持背景虚化,背景暗化,支持快速拓展.支持从 Menu 中填充数据。运行效果: 使用说明: 上面是设计图,demo运行效果图: MainActivity.class 1234567891011121314151617181…...
设计的很好的网站/临沂网站建设
最近有空研究了一下基于Opencv的视频人数统计。总结了一下,视频人数统计系统的工作流程主要包括以下几个部分: 1.视频捕获 从视频源(摄像头或视频文件)获取到视频图像数据。 2.目标提取(背景建模、前景分析ÿ…...
pc开奖网站开发/网址缩短在线生成器
来源是:Text at LEFT如何更改CSS以使两个DIV看起来像?----------------------|Text at LEFT | ####|| | ####|| | ####|| | || | |----------------------即。文本在左侧DIV左上角,图像在右侧DIV右上方对齐。更新:我使用的是&…...