ISDP010_基于DDD架构实现收银用例主成功场景

信息系统开发实践 | 系列文章传送门
ISDP001_课程概述
ISDP002_Maven上_创建Maven项目
ISDP003_Maven下_Maven项目依赖配置
ISDP004_创建SpringBoot3项目
ISDP005_Spring组件与自动装配
ISDP006_逻辑架构设计
ISDP007_Springboot日志配置与单元测试
ISDP008_SpringBoot Controller接口文档与测试
ISDP009_基于DDD架构设计ISDP的处理销售用例
ISDP010_基于DDD架构实现收银用例主成功场景

1 面向DDD重构mis-pos模块

重要说明:由于代码量增加,且经常需要重构。笔记将难以展示项目完整代码。本章笔记开始只展示部分代码。完整代码详见笔记最后项目仓库分支代码。

参考上篇分析与设计制品,参考DDD架构,重构的mis-pos模块的架构分层。

根据DDD架构分为application、domain、infrastructure三个包。
在这里插入图片描述

2 基础设施层

基础设施层暂时还没有写太多的类。只是添加了SaleFactory用于实例化Sale。

引入Hutool工具类,用于生成订单的雪花ID。

        <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.20</version></dependency>

编写SaleFactory,实例化Sale并设置初始化值。

package edu.scau.mis.pos.infrastructure.factory;import cn.hutool.core.util.IdUtil;
import edu.scau.mis.pos.domain.entity.Sale;
import edu.scau.mis.pos.domain.enums.SaleStatusEnum;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.Date;/*** Sale工厂类*/
@Component
public class SaleFactory {public Sale initSale(){Sale sale = new Sale();sale.setSaleNo("so-" + IdUtil.getSnowflakeNextId());sale.setSaleStatus(SaleStatusEnum.CREATED);sale.setTotalAmount(BigDecimal.ZERO);sale.setTotalQuantity(0);sale.setSaleTime(new Date());return sale;}}

3 领域层

在DDD架构中,领域层是重点关注层。

为了简化Setter和getter编写,引入了Lombok。

        <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency>

3.1 SaleProduct实体类

SaleProduct实体类包含了业务逻辑方法getSubTotal,计算每个订单明细的小计。

package edu.scau.mis.pos.domain.entity;import edu.scau.mis.pos.domain.enums.SaleProductStatusEnum;
import lombok.Data;import java.math.BigDecimal;/*** 订单-产品明细实体类*/
@Data
public class SaleProduct {private Long saleProductId;private Long saleId;private Long productId;private Product product;private Integer saleQuantity;private BigDecimal salePrice;private SaleProductStatusEnum saleProductStatus;/*** 计算小计* @return*/public BigDecimal getSubTotal() {return salePrice.multiply(new BigDecimal(saleQuantity));}
}

3.2 支付实体类

支付类暂时还没有写业务逻辑方法。后期考虑通过适配器,连接第三方支付。

package edu.scau.mis.pos.domain.entity;import com.fasterxml.jackson.annotation.JsonFormat;
import edu.scau.mis.pos.domain.enums.PaymentStatusEnum;
import edu.scau.mis.pos.domain.enums.PaymentStrategyEnum;
import lombok.Data;import java.math.BigDecimal;
import java.util.Date;/*** 支付实体类*/
@Data
public class Payment {private Long paymentId;private Long paymentSaleId;private PaymentStrategyEnum paymentStrategy;private String paymentNo;private BigDecimal paymentAmount;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date paymentTime;private PaymentStatusEnum paymentStatus;}

3.3 Sale聚合根

Sale类是收银领域层的聚合根。

该类内聚了两个业务逻辑方法,分别为添加订单明细和计算总金额。

package edu.scau.mis.pos.domain.entity;import com.fasterxml.jackson.annotation.JsonFormat;
import edu.scau.mis.pos.domain.enums.SaleStatusEnum;
import lombok.Data;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** 销售实体类* 聚合根*/
@Data
public class Sale {private Long saleId;private String saleNo;private BigDecimal totalAmount;private Integer totalQuantity;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date saleTime;private Payment payment;private List<SaleProduct> saleProducts = new ArrayList<>();private SaleStatusEnum saleStatus;/*** 计算总金额* @return*/public BigDecimal getTotal(){totalAmount = BigDecimal.ZERO;totalQuantity = 0;for(SaleProduct saleProduct: saleProducts){totalAmount = totalAmount.add(saleProduct.getSubTotal());totalQuantity = totalQuantity + saleProduct.getSaleQuantity();}return totalAmount;}/*** 添加订单明细* @param product* @param saleQuantity* @return*/public List<SaleProduct> makeLineItem(Product product, Integer saleQuantity) {// 判断商品是否已录入,未录入则新增。已录入则修改数量。if(!isEntered(product.getProductSn(),saleQuantity)){SaleProduct saleProduct = new SaleProduct();saleProduct.setProduct(product);saleProduct.setSaleQuantity(saleQuantity);saleProduct.setSalePrice(product.getProductPrice());saleProducts.add(saleProduct);}return saleProducts;}/*** 判断商品是否已录入* 业务逻辑:如果已录入,则修改数量,否则添加saleLineItem* @param productSn* @param saleQuantity* @return*/private boolean isEntered(String productSn, Integer saleQuantity){boolean flag = false;for(SaleProduct sp : saleProducts){if(productSn.equals(sp.getProduct().getProductSn())) {flag = true;Integer quantityOriginal = sp.getSaleQuantity();sp.setSaleQuantity(quantityOriginal + saleQuantity);}}return flag;}
}

3.4 领域服务类SaleService

主要用于生成支付功能。ISDP项目POS系统设计支持挂单功能。

package edu.scau.mis.pos.domain.service.impl;import cn.hutool.core.util.IdUtil;
import edu.scau.mis.pos.domain.entity.Payment;
import edu.scau.mis.pos.domain.entity.Sale;
import edu.scau.mis.pos.domain.enums.PaymentStatusEnum;
import edu.scau.mis.pos.domain.enums.PaymentStrategyEnum;
import edu.scau.mis.pos.domain.service.ISaleService;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.util.Date;/*** 领域服务*/
@Service
public class SaleServiceImpl implements ISaleService {@Overridepublic Payment makePayment(Sale sale, String paymentStrategy, BigDecimal paymentAmount) {Payment payment = new Payment();payment.setPaymentStrategy(PaymentStrategyEnum.valueOf(paymentStrategy));payment.setPaymentNo(paymentStrategy + "-" + IdUtil.getSnowflakeNextId());payment.setPaymentAmount(paymentAmount);payment.setPaymentTime(new Date());payment.setPaymentStatus(PaymentStatusEnum.PAID);// TODO: 根据不同支付策略调用不同外部接口return payment;}
}

3.5 其他

Domain层还有仓库、枚举等包。由于暂时还没有使用数据库和Redis,仓库代码暂时没写。

写了一些枚举类。由于只是教学项目,没有设计过多状态。

package edu.scau.mis.pos.domain.enums;/*** 订单状态枚举*/
public enum SaleStatusEnum {CREATED("0","已预订"),SUBMITTED("1","已提交"),PAID("2","已支付");private String value;private String label;SaleStatusEnum(String value, String label) {this.value = value;this.label = label;}public String getLabel() {return label;}public String getValue() {return value;}/*** 根据匹配value的值获取Label** @param value* @return*/public static String getLabelByValue(String value){for (SaleStatusEnum s : SaleStatusEnum.values()) {if(value.equals(s.getValue())){return s.getLabel();}}return "";}/*** 获取StatusEnum** @param value* @return*/public static SaleStatusEnum getStatusEnum(String value){for (SaleStatusEnum s : SaleStatusEnum.values()) {if(value.equals(s.getValue())){return s;}}return null;}
}

支付策略枚举类

package edu.scau.mis.pos.domain.enums;/*** 支付策略枚举*/
public enum PaymentStrategyEnum {WECHAT("wechat","微信支付"),ALIPAY("alipay","支付宝"),CASH("cash","现金");private String value;private String label;PaymentStrategyEnum(String value, String label) {this.value = value;this.label = label;}public String getLabel() {return label;}public String getValue() {return value;}/*** 根据匹配value的值获取Label** @param value* @return*/public static String getLabelByValue(String value){for (PaymentStrategyEnum s : PaymentStrategyEnum.values()) {if(value.equals(s.getValue())){return s.getLabel();}}return "";}/*** 获取StatusEnum** @param value* @return*/public static PaymentStrategyEnum getStrategyEnum(String value){for (PaymentStrategyEnum s : PaymentStrategyEnum.values()) {if(value.equals(s.getValue())){return s;}}return null;}
}

4 应用层

4.1 应用服务类SaleApplicationService

编写SaleApplicationService类。该类主要负责跨领域协作。

目前主要就两个领域Sale(SaleProduct、Payment)和Product(Category)。

如果使用微服务,可以分别针对这两个领域创建两个微服务模块。

package edu.scau.mis.pos.application.service;import edu.scau.mis.pos.application.assembler.SaleAssembler;
import edu.scau.mis.pos.application.dto.command.EnterItemCommand;
import edu.scau.mis.pos.application.dto.command.MakePaymentCommand;
import edu.scau.mis.pos.application.dto.vo.*;
import edu.scau.mis.pos.domain.entity.Payment;
import edu.scau.mis.pos.domain.entity.Product;
import edu.scau.mis.pos.domain.entity.Sale;
import edu.scau.mis.pos.domain.entity.SaleProduct;
import edu.scau.mis.pos.domain.enums.SaleStatusEnum;
import edu.scau.mis.pos.domain.service.IProductService;
import edu.scau.mis.pos.infrastructure.factory.SaleFactory;
import edu.scau.mis.pos.domain.service.ISaleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class SaleApplicationService {@Autowiredprivate IProductService productService;@Autowiredprivate ISaleService saleService;@Autowiredprivate SaleFactory saleFactory;@Autowiredprivate SaleAssembler saleAssembler;private Sale currentSale; // 后期改成Redis缓存CurrentSale/*** 开始一次新销售* @return*/public SaleVo makeNewSale(){SaleVo saleVo = new SaleVo();currentSale = saleFactory.initSale();// TODO:引入Redis缓存return saleAssembler.toSaleVo(currentSale);}/*** 录入商品* @param command* @return*/public SaleAndProductListVo enterItem(EnterItemCommand command){SaleAndProductListVo saleAndProductListVo = new SaleAndProductListVo();Product product = productService.selectProductBySn(command.getProductSn());List<SaleProduct> saleProducts = currentSale.makeLineItem(product, command.getSaleQuantity());currentSale.getTotal();List<SaleProductVo> saleProductVoList = saleProducts.stream().map(saleProduct -> new SaleProductVo(saleProduct.getProduct().getProductSn(), saleProduct.getProduct().getProductName(), saleProduct.getSalePrice(), saleProduct.getSaleQuantity())).toList();saleAndProductListVo.setSaleVo(saleAssembler.toSaleVo(currentSale));saleAndProductListVo.setSaleProductVoList(saleProductVoList);return saleAndProductListVo;}/*** 结束销售* 计算优惠、持久化订单等* @return*/public SaleVo endSale(){currentSale.setSaleStatus(SaleStatusEnum.SUBMITTED);// TODO: 持久化Sale和SaleProduct,添加事务注解return saleAssembler.toSaleVo(currentSale);}/*** 完成支付* @param command* @return*/public SaleAndPaymentVo makePayment(MakePaymentCommand command){SaleAndPaymentVo saleAndPaymentVo = new SaleAndPaymentVo();// TODO: 挂单--根据saleNo获取SalePayment payment = saleService.makePayment(currentSale,command.getPaymentStrategy(), command.getPaymentAmount());currentSale.setPayment(payment);currentSale.setSaleStatus(SaleStatusEnum.PAID);// TODO: 持久化Sale和Payment,添加事务注解// payment.setPaymentSaleId(sale.getSaleId());saleAndPaymentVo.setSaleVo(saleAssembler.toSaleVo(currentSale));saleAndPaymentVo.setPaymentVo(saleAssembler.toPaymentVo(payment));return saleAndPaymentVo;}
}

4.2 数据传输对象DTO

ISDP项目采用CQRS思想,该层编写大量的数据传输对象DTO。笔记只展示部分代码。详细参加项目仓库。

EnterItemCommand参考代码如下。

后期将使用Redis缓存currentSale,设计saleNo作为key。保留saleNo备用。

package edu.scau.mis.pos.application.dto.command;import lombok.Data;import java.io.Serializable;/*** 输入订单明细命令*/
@Data
public class EnterItemCommand implements Serializable {private String saleNo;private String productSn;private Integer saleQuantity;
}

MakePaymentCommand代码参考如下:

同上,saleNo暂时不需要。

package edu.scau.mis.pos.application.dto.command;import lombok.Data;import java.io.Serializable;
import java.math.BigDecimal;/*** 创建支付命令*/
@Data
public class MakePaymentCommand implements Serializable {private String saleNo;private BigDecimal paymentAmount;private String paymentStrategy;
}

SaleVo类

package edu.scau.mis.pos.application.dto.vo;import lombok.Data;import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class SaleVo implements Serializable {private String saleNo;private BigDecimal totalAmount;private Integer totalQuantity;private Date saleTime;private String saleStatus;
}

SaleAndPaymentVo

package edu.scau.mis.pos.application.dto.vo;import lombok.Data;import java.io.Serializable;
@Data
public class SaleAndPaymentVo implements Serializable {private SaleVo saleVo;private PaymentVo paymentVo;
}

4.3 对象转换器SaleAssembler

面向接口层主要使用DTO对象,因此不可避免涉及到DTO与领域对象的转换。

package edu.scau.mis.pos.application.assembler;import edu.scau.mis.pos.application.dto.vo.PaymentVo;
import edu.scau.mis.pos.application.dto.vo.SaleVo;
import edu.scau.mis.pos.domain.entity.Payment;
import edu.scau.mis.pos.domain.entity.Sale;
import org.springframework.stereotype.Component;/*** 订单转换器* 实现DTO与Entity的转换*/@Component
public class SaleAssembler {public SaleVo toSaleVo(Sale sale){SaleVo saleVo = new SaleVo();saleVo.setSaleNo(sale.getSaleNo());saleVo.setTotalAmount(sale.getTotalAmount());saleVo.setTotalQuantity(sale.getTotalQuantity());saleVo.setSaleTime(sale.getSaleTime());saleVo.setSaleStatus(sale.getSaleStatus().getLabel());return saleVo;}public PaymentVo toPaymentVo(Payment payment){PaymentVo paymentVo = new PaymentVo();paymentVo.setPaymentId(payment.getPaymentId());paymentVo.setPaymentSaleId(payment.getPaymentSaleId());paymentVo.setPaymentNo(payment.getPaymentNo());paymentVo.setPaymentAmount(payment.getPaymentAmount());paymentVo.setPaymentTime(payment.getPaymentTime());paymentVo.setPaymentStrategy(payment.getPaymentStrategy().getLabel());paymentVo.setPaymentStatus(payment.getPaymentStatus().getLabel());return paymentVo;}
}

5 接口层

5.1 Controller接口

SaleController参考如下:

package edu.scau.mis.web.controller;import edu.scau.mis.pos.application.dto.command.EnterItemCommand;
import edu.scau.mis.pos.application.dto.command.MakePaymentCommand;
import edu.scau.mis.pos.application.dto.vo.SaleAndPaymentVo;
import edu.scau.mis.pos.application.dto.vo.SaleAndProductListVo;
import edu.scau.mis.pos.application.dto.vo.SaleVo;
import edu.scau.mis.pos.application.service.SaleApplicationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/sale")
public class SaleController {@Autowiredprivate SaleApplicationService saleApplicationService;@GetMapping("/makeNewSale")public ResponseEntity<SaleVo> makeNewSale(){return ResponseEntity.ok(saleApplicationService.makeNewSale());}@PostMapping("/enterItem")public ResponseEntity<SaleAndProductListVo> enterItem(@RequestBody  EnterItemCommand enterItemCommand){return ResponseEntity.ok(saleApplicationService.enterItem(enterItemCommand));}@GetMapping("/endSale")public ResponseEntity<SaleVo> endSale(){return ResponseEntity.ok(saleApplicationService.endSale());}@PostMapping("/makePayment")public ResponseEntity<SaleAndPaymentVo> makePayment(@RequestBody MakePaymentCommand makePaymentCommand){return ResponseEntity.ok(saleApplicationService.makePayment(makePaymentCommand));}
}

5.2 接口测试

使用Knife4j对SaleController接口进行测试,简单验证后端业务逻辑。

5.2.1 makeNewSale接口

该接口目前只是初始化currentSale数据。
在这里插入图片描述

5.2.2 enterItem接口

接口接收产品编号和订购数量。

接口返回订单和订购商品集合的json数据。

在这里插入图片描述

5.2.3 endSale接口

该接口暂时未写太多业务逻辑,只是提交订单,更新订单状。

后期将会从redis中清除缓存currentSale,然后持久化currentSale数据。
在这里插入图片描述

5.2.4 makePayment接口

接口接收支付金额和支付方式两个参数。

接口返回订单和支付json数据。
在这里插入图片描述
本章笔记基于上篇的分析与设计模型,编写DDD架构基础设施层、领域层、应用层和接口层的代码。实现了收银用例的4个主要步骤makeNewSale、enterItem、endSale和makePayment。

下一篇笔记将应用适配器模式调用支付宝沙箱支付接口。

本笔记项目仓库地址:
https://gitcode.com/tiger2704/isdp-boot3/tree/isdp010

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/890915.shtml

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

相关文章

中学数学:一个函数值计算题

在数学的领域中&#xff0c;函数是一种描述变量之间关系的桥梁&#xff0c;它能够揭示出看似复杂现象背后的简洁规律。通过函数&#xff0c;我们可以预测、分析并解决实际问题。在这张图片中&#xff0c;我们看到了一位数学爱好者手写的解题过程&#xff0c;它展示了如何巧妙地…

#渗透测试#漏洞挖掘#红蓝攻防#常见未授权访问漏洞汇总

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

基于Oauth2的SSO单点登录---前端

Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架&#xff0c;提供了丰富的组件和功能&#xff0c;可以帮助开发者快速搭建现代化的后台管理系统。 一、基本知识 &#xff08;一&#xff09;Vue-element-admin 的主要文件和目录 vue-element-admin/ |--…

linux内核如何实现TCP的?

TCP(传输控制协议)是网络通信中的核心协议之一,实现了可靠的、面向连接的、基于字节流的通信。在Linux内核中,TCP的实现相对复杂,涉及多个模块和层次。以下是一些关键概念和机制: 1. 协议栈 Linux 内核中的网络协议栈(Network Stack)是分层设计的,包括链路层、网络层…

ElasticSearch 分布式部署

一、引言 在当今大数据时代&#xff0c;数据呈爆炸式增长&#xff0c;如何高效地存储、检索数据成为了众多企业面临的关键挑战。ElasticSearch 作为一款强大的分布式搜索引擎&#xff0c;凭借其卓越的性能、灵活的扩展性以及强大的全文检索能力&#xff0c;在日志分析、数据分…

依图科技简介

依图科技&#xff08;YITU Technology&#xff09;是中国一家全球领先的人工智能&#xff08;AI&#xff09;公司&#xff0c;成立于2012年&#xff0c;总部位于上海。公司专注于计算机视觉、语音识别和自然语言处理等核心AI技术&#xff0c;致力于推动AI技术在医疗、安防、金融…

[创业之路-206]:《华为战略管理法-DSTE实战体系》- 6-关键成功因素法CSF

目录 一、概述 1、定义与起源 2、关键成功因素的定义 3、关键成功因素的来源 4、关键成功因素的确认方法 5、关键成功因素法的步骤 6、关键成功因素法的应用 7、关键成功因素法的优势与局限性 二、 关键成功因素法CSF的应用 1、企业战略管理 2、项目管理 3、绩效管…

Express.js 有哪些常用的中间件?

在使用 Express.js 开发应用程序时&#xff0c;中间件&#xff08;Middleware&#xff09;是处理请求和响应的关键组件。它们可以执行各种任务&#xff0c;如解析请求体、添加HTTP头部、记录日志等。以下是一些常用的中间件&#xff1a; body-parser 用于解析传入的请求体。它…

华为 AI Agent:企业内部管理的智能变革引擎(11/30)

一、华为 AI Agent 引领企业管理新潮流 在当今数字化飞速发展的时代&#xff0c;企业内部管理的高效性与智能化成为了决定企业竞争力的关键因素。华为&#xff0c;作为全球领先的科技巨头&#xff0c;其 AI Agent 技术在企业内部管理中的应用正掀起一场全新的变革浪潮。 AI Ag…

RustDesk内置ID服务器,Key教程

RustDesk内置ID服务器&#xff0c;Key教程 首先需要准备一个域名&#xff0c;并将其指定到你的 rustdesk 服务器 ip 地址上&#xff0c;这里编译采用的是Github Actions &#xff0c;说白了是就workflows&#xff0c;可以创建一些自动化的工作流程&#xff0c;例如代码的检查&a…

虚幻引擎结构之UObject

一. UObject 的介绍 UObject 是虚幻引擎中的核心基础类,所有其他游戏对象和资源类都直接或间接地继承自它。作为虚幻引擎的基石,UObject 提供了多项关键功能,包括内存管理、序列化、反射(introspection)、垃圾回收以及元数据支持。在虚幻引擎中,UObject 类的实例通常被称…

Python异常处理在“简易记事本”项目中的应用

Python异常处理在“简易记事本”项目中的应用 在“简易记事本”项目中&#xff0c;异常处理的使用尤为重要&#xff0c;因为文件操作过程中可能会遇到各种问题&#xff0c;例如文件不存在、权限不足或文件占用等。如果这些问题未被妥善处理&#xff0c;程序可能会崩溃&#xf…

Wend看源码-Java-集合学习(List)

摘要 本篇文章深入探讨了基于JDK 21版本的Java.util包中提供的多样化集合类型。在Java中集合共分类为三种数据结构&#xff1a;List、Set和Queue。本文将详细阐述这些数据类型的各自实现&#xff0c;并按照线程安全性进行分类&#xff0c;分别介绍非线程安全与线程安全的实现方…

阿里云新用户服务器配置

创建和链接实例 创建实例&#xff0c;点击左侧标签栏总的实例&#xff0c; 找到链接帮助 根据帮助中的ip信息&#xff0c;然后启用vscode的ssh链接 ctrlp选择配置&#xff0c;输入公网的ip即可 passwd修改root密码 安装conda 参考 https://blog.csdn.net/adreammaker/arti…

向量索引和文本嵌入有什么区别

向量索引和文本嵌入的区别 文本嵌入&#xff08;Text Embeddings&#xff09;&#xff1a;是将文本&#xff08;如一句话、段落、文章&#xff09;转换成 数字向量 的过程。每个文本都对应一个向量&#xff0c;向量的数值可以用来表达该文本的语义信息。常用的嵌入模型如 OpenA…

五金产品视觉检测

五金产品种类繁多&#xff0c;且与我们的日常生活紧密有关&#xff0c;依照加工工艺的不同&#xff0c;五金产品有压铸件&#xff0c;五金冲压件&#xff0c;铸件等&#xff0c;无论是哪种加工方式&#xff0c;产品总会存在各式各样的问题&#xff0c;今天我们就五金产品的缺陷…

Kotlin语言的软件工程

Kotlin语言的软件工程 引言 在现代软件开发中&#xff0c;选择合适的编程语言是项目成功的关键之一。随着移动互联网的迅猛发展&#xff0c;以及大数据和人工智能等新兴技术的崛起&#xff0c;Kotlin语言凭借其简洁、高效和安全等特性&#xff0c;迅速崛起为备受欢迎的编程语…

ip怎么查域名?IP和域名分别是什么?

为什么我们可以通过简单的域名访问网站&#xff0c;而不是记住一串复杂的数字&#xff1f;IP地址和域名之间到底是什么关系&#xff1f;在互联网的世界里&#xff0c;IP地址和域名是两种重要的概念&#xff0c;它们共同构成了我们日常上网的基础。 IP地址是互联网协议地址的缩…

拼多多纠偏,能否实现买卖平权?

科技新知 原创作者丨江蓠 编辑丨蕨影 当曾将仅退款、运费险作为标配的电商平台们开始听到商家诉求&#xff0c;有意优化营商环境&#xff0c;作为“仅退款”服务发起者的拼多多也坐不住了。 在推出一揽子减免计划讨好中小商家之后&#xff0c;拼多多近期被传正在内测精选用户…

XGPT用户帮助手册

文章目录 20242024.12.27 摘要 本文介绍如何使用XGPT软件, XGPT融合了当前最先进的人工智能技术&#xff0c;并专为国内用户优化。 2024 2024.12.27 XGPT v1正式发布, 特色功能: 具备图像文本多模态处理功能包含GPT等最先进模型国内可访问 B站视频介绍 图1 XGPT v1 快照