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

news2025/2/7 8:53:56

信息系统开发实践 | 系列文章传送门
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 {
    @Override
    public 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 {
    @Autowired
    private IProductService productService;

    @Autowired
    private ISaleService saleService;

    @Autowired
    private SaleFactory saleFactory;

    @Autowired
    private 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获取Sale
        Payment 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 {
    @Autowired
    private 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.coloradmin.cn/o/2267376.html

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

相关文章

Linux -- 从抢票逻辑理解线程互斥

目录 抢票逻辑代码&#xff1a; thread.hpp thread.cc 运行结果&#xff1a; 为什么票会抢为负数&#xff1f; 概念前言 临界资源 临界区 原子性 数据不一致 为什么数据不一致&#xff1f; 互斥 概念 pthread_mutex_init&#xff08;初始化互斥锁&#xff09; p…

1.微服务灰度发布落地实践(方案设计)

前言 微服务架构中的灰度发布&#xff08;也称为金丝雀发布或渐进式发布&#xff09;是一种在不影响现有用户的情况下&#xff0c;逐步将新版本的服务部署到生产环境的策略。通过灰度发布&#xff0c;你可以先将新版本的服务暴露给一小部分用户或特定的流量&#xff0c;观察其…

从 Coding (Jenkinsfile) 到 Docker:全流程自动化部署 Spring Boot 实战指南(简化篇)

前言 本文记录使用 Coding (以 Jenkinsfile 为核心) 和 Docker 部署 Springboot 项目的过程&#xff0c;分享设置细节和一些注意问题。 1. 配置服务器环境 在实施此过程前&#xff0c;确保服务器已配置好 Docker、MySQL 和 Redis&#xff0c;可参考下列链接进行操作&#xff1…

丢失的MD5

丢失的MD5 源代码&#xff1a; import hashlib for i in range(32,127):for j in range(32,127):for k in range(32,127):mhashlib.md5()m.update(TASCchr(i)O3RJMVchr(j)WDJKXchr(k)ZM)desm.hexdigest()if e9032 in des and da in des and 911513 in des:print des 发现给…

基于51单片机的交通灯外部中断proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1WSlta_7pz5HdWsyIGoviHg 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…

JavaWeb(一) | 基本概念(web服务器、Tomcat、HTTP、Maven)、Servlet 简介

1. 基本概念 1.1、前言 web开发&#xff1a; web&#xff0c;网页的意思&#xff0c;www.baidu.com静态 web html,css提供给所有人看的数据始终不会发生变化&#xff01; 动态 web 淘宝&#xff0c;几乎是所有的网站&#xff1b;提供给所有人看的数据始终会发生变化&#xf…

C语言性能优化:从基础到高级的全面指南

引言 C 语言以其高效、灵活和功能强大而著称&#xff0c;被广泛应用于系统编程、嵌入式开发、游戏开发等领域。然而&#xff0c;要写出高性能的 C 语言代码&#xff0c;需要对 C 语言的特性和底层硬件有深入的了解。本文将详细介绍 C 语言性能优化的背后技术&#xff0c;并通过…

C语言-数据结构-查找

目录 一,查找的概念 二,线性查找 1,顺序查找 2,折半查找 3,分块查找 三,树表的查找 1,二叉排序树 (1)查找方式: (2)、二叉排序树的插入和生成 (3)、二叉排序树的删除 2,平衡二叉树 (1)、什么是平衡二叉树 (2)、平衡二叉树的插入调整 &#xff08;1&#xff09;L…

[江科大编程技巧] 第1期 定时器实现非阻塞式程序 按键控制LED闪烁模式——笔记

提前声明——我只是写的详细其实非常简单&#xff0c;不要看着多就放弃学习&#xff01; 阻塞&#xff1a;执行某段程序时&#xff0c;CPU因为需要等待延时或者等待某个信号而被迫处于暂停状态一段时间&#xff0c;程序执行时间较长或者时间不定 非阻塞&#xff1a;执行某段程…

如何理解:产品线经营管理的战略、组织、业务、项目、流程、绩效之间的逻辑关系?-中小企实战运营和营销工作室博客

如何理解&#xff1a;产品线经营管理的战略、组织、业务、项目、流程、绩效之间的逻辑关系&#xff1f;-中小企实战运营和营销工作室博客 产品线经营管理中&#xff0c;战略、组织、业务、项目、流程、绩效之间存在着紧密的逻辑关系&#xff0c;它们相互影响、相互作用&#xf…

【CSS in Depth 2 精译_096】16.4:CSS 中的三维变换 + 16.5:本章小结

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第五部分 添加动效 ✔️【第 16 章 变换】 ✔️ 16.1 旋转、平移、缩放与倾斜 16.1.1 变换原点的更改16.1.2 多重变换的设置16.1.3 单个变换属性的设置 16.2 变换在动效中的应用 16.2.1 放大图标&am…

Oracle 11G还有新BUG?ORACLE 表空间迷案!

前段时间遇到一个奇葩的问题&#xff0c;在开了SR和oracle support追踪两周以后才算是有了不算完美的结果&#xff0c;在这里整理出来给大家分享。 1.问题描述 12/13我司某基地MES全厂停线&#xff0c;系统卡死不可用&#xff0c;通知到我排查&#xff0c;查看alert log看到是…

三只脚的电感是什么东西?

最近在做加湿器&#xff0c;把水雾化的陶瓷片需要有专门的驱动电路。 我参考了某宝卖家的驱动板以及网上的开源项目&#xff0c;发现了驱动电路的核心就是一个三脚电感。 在此之前我都没注意过这玩意&#xff0c;三脚电感不也还是电感嘛&#xff1f; 今天我们就来看看三脚电…

pyQT + OpenCV相关练习

一、设计思路 1、思路分析与设计 本段代码是一个使用 PyQt6 和 OpenCV 创建的图像处理应用程序。其主要功能是通过一个图形界面让用户对图片进行基本的图像处理操作&#xff0c;如灰度化、翻转、旋转、亮度与对比度调整&#xff0c;以及一些滤镜效果&#xff08;模糊、锐化、边…

【Git_bugs】remote error GH013 Repository rule violations found for.md

背景 1 在一个分支上的提交顺序如下&#xff1a;-> 代表新的提交 在提交 E 中&#xff0c;文件包含了 GitHub 生成的 token提交 F 是一次普通的提交&#xff0c;不包含 token A -> ... -> E -> F (敏感信息在 E 中)附&#xff1a;给提交起名是为了方便说明问题。…

Day1 微服务 单体架构、微服务架构、微服务拆分、服务远程调用、服务注册和发现Nacos、OpenFeign

目录 1.导入单体架构项目 1.1 安装mysql 1.2 后端 1.3 前端 2.微服务 2.1 单体架构 2.2 微服务 2.3 SpringCloud 3.微服务拆分 3.1 服务拆分原则 3.1.1 什么时候拆 3.1.2 怎么拆 3.2 拆分购物车、商品服务 3.2.1 商品服务 3.2.2 购物车服务 3.3 服务调用 3.3.1 RestTemplate 3.…

安卓执法仪Android接入国标GB28181平台实现实时监控、对讲、报警、定位等管理方案

最近协助不少企业完成了4G无线设备国标接入的需求&#xff0c;尤其是国产芯片的接入&#xff0c;国标发展了十年的时间&#xff0c;目前协议从完成度、性能、AI等各个方面&#xff0c;都已经非常完美地满足各种各样的场景需求&#xff0c;尤其是GB28181-2022的推出&#xff0c;…

SpringMVC学习(二)——RESTful API、拦截器、异常处理、数据类型转换

一、RESTful (一)RESTful概述 RESTful是一种软件架构风格&#xff0c;用于设计网络应用程序。REST是“Representational State Transfer”的缩写&#xff0c;中文意思是“表现层状态转移”。它基于客户端-服务器模型和无状态操作&#xff0c;以及使用HTTP请求来处理数据。RES…

国内独立开发者案例及免费送独立开发蓝图书

独立开发者在国内越来越受到关注&#xff0c;他们追求的是一种自由且自给自足的工作状态。 送这个&#xff1a; 少楠light&#xff08;Flomo、小报童、如果相机&#xff09;&#xff1a;他们是独立开发者的典范&#xff0c;不仅开发了多款产品&#xff0c;还坚信“剩者为王”…

【JavaEE进阶】@RequestMapping注解

目录 &#x1f4d5;前言 &#x1f334;项目准备 &#x1f332;建立连接 &#x1f6a9;RequestMapping注解 &#x1f6a9;RequestMapping 注解介绍 &#x1f384;RequestMapping是GET还是POST请求&#xff1f; &#x1f6a9;通过Fiddler查看 &#x1f6a9;Postman查看 …