当前位置:   article > 正文

springboot第52集:微服务分布式架构,统一验证,oauth,订单,地区管理周刊

springboot第52集:微服务分布式架构,统一验证,oauth,订单,地区管理周刊

在计算机领域中,FGC 通常代表 Full Garbage Collection,即全垃圾收集。垃圾收集是一种自动管理内存的机制,它负责回收不再被程序使用的内存,以便释放资源和提高程序性能。

当系统执行 Full Garbage Collection 时,它会检查整个堆内存,并尝试回收所有不再使用的对象。这个过程可能会导致一些系统暂时停止执行,特别是在大型内存堆上。因此,频繁的 Full Garbage Collection 可能会对系统性能产生影响。

"FGC增加 44次" 可能表示在一个时间段内进行了 44 次 Full Garbage Collection 操作。这可能表明系统在处理大量内存回收,可能是因为程序生成了大量的垃圾对象,需要频繁进行全堆垃圾收集。

考虑优化程序的内存使用,减少产生垃圾对象的频率,以降低 Full Garbage Collection 的次数,从而提高系统性能。

在 Java 虚拟机中,YGC 通常表示 Young Generation Garbage Collection,即年轻代垃圾收集。Java 堆被分为年轻代、老年代和持久代(在一些较新的 JVM 中可能不存在),而年轻代是 Java 对象的初始分配和短期存活的地方。

年轻代通常被划分为三个部分:

  1. Eden 区(伊甸园区): 这是对象的初始分配区域,大多数对象最初都在这里分配。

  2. Survivor 区(幸存者区): Survivor 区有两个,通常称为 S0 和 S1。它们用于存放在 Eden 区中经过一次垃圾收集后仍然存活的对象。

  3. 老年代(Old Generation): 如果对象在年轻代经历了一定次数的垃圾收集仍然存活,它将被晋升到老年代。

Young Generation Garbage Collection 就是指针对年轻代的垃圾收集操作。在年轻代,主要的垃圾收集算法是通过复制(Copying)和标记-清除(Mark-Sweep)结合的方式进行的。垃圾收集的目标是尽可能快速地清理掉那些很快就不再使用的对象,以提高程序的性能。

因此,YGC 的发生频率相对较高,通常不会影响整个系统的性能。相比之下,FGC(Full Garbage Collection)涉及到整个堆的垃圾收集,会导致更大的停顿时间,因此通常希望 YGC 的次数较多,FGC 的次数较少。

  • 配置中心&服务注册&发现:Nacos

  • API网关:Spring Cloud Gateway

  • 认证授权:Spring Security OAuth2 Authorization Server

  • 远程调用:Dubbo & Spring Cloud OpenFeign & OkHttp & HttpClient & WebClient

  • 负载均衡:Spring Cloud Loadbalancer & OpenResty

  • 服务熔断&降级&限流:Sentinel

  • 分库分表&读写分离:Mybatis Plus & ShardingSphere

  • 分布式事务:Seata & RocketMQ

  • 消息队列:RocketMQ & Kafka & MQTT

  • 服务监控:Spring Boot Admin & Prometheus

  • 链路跟踪:SkyWalking

  • 任务调度:XXL Job

  • 日志分析:EFK

  • 缓存&分布式锁:Redis & Redisson

  • 统计报表:MongoDB

  • 对象存储:Amazon S3

  • 自动化部署:Docker

  • 网络通讯:Netty

  • 持续集成&交付:Jenkins

  • 持久层框架:Mybatis Plus

  • JSON序列化:Jackson

  • 对象转换:MapStruct

  • 数据库:Mysql & Postgresql

  • 工作流:Flowable

  • 数据库迁移:Flyway

  • 微服务框架

    • [界面一览]

    • [产品简介]

    • [Docker启动基础服务]

    • [Nacos安装]

    • [Sentinel安装]

    • [导入Nacos配置]

    • [数据库导入]

    • [运行Cloud版本]

    • [告警部署]

    • [监控部署]

    • [前端部署]

    • [后端部署]

    • [对接准备]

    • [Jar模式对接]

<el-table-column> 中的 type="selection" 用于显示表格的选择列,允许用户选择表格中的行。在这个列上,你可以使用一些属性来定制选择的行为。在你提供的代码中,有两个属性被使用到:

  1. :selectable: 该属性接受一个函数,用于判断某一行是否可以被选择。这个函数将会接收表格当前行的数据作为参数,你可以在这个函数中编写逻辑来决定该行是否可以被选择。如果返回 true,则表示该行可以被选择,否则不可以。在你的代码中,这个属性被绑定到 selectable 变量,但你没有提供这个变量的定义。这个函数可以不传,默认为返回 true

  2. :reserve-selection: 该属性接受一个布尔值,表示是否保留用户之前所选的内容。如果设置为 true,则在切换分页时保留之前所选的项。在你的代码中,这个属性被设置为 true

这两个属性的使用可以帮助你在表格中实现选择行的功能。在用户选择行时,可以通过监听 selection-change 事件,获取用户选择的数据,并进行相关的处理。

统一验证

  • @NotNull 不能为null

  • @NotEmpty 不能为null、空字符串、空集合

  • @NotBlank 不能为null、空字符串、纯空格的字符串

  • @Min 数字最小值不能小于x

  • @Max 数字最大值不能大于x

  • @Email 字符串为邮件格式

  • @Max 数字最大值不能大于x

  • @Size 字符串长度最小为x、集合长度最小为x

  • @Pattern 正则表达式

  1. public class SysUser implements Serializable {
  2.  private static final long serialVersionUID = 1L;
  3.  
  4.  /**
  5.   * 用户ID
  6.   *
  7.   */
  8.  @TableId
  9.  private Long userId;
  10.  /**
  11.   * 用户名
  12.   */
  13.  @NotBlank(message="用户名不能为空")
  14.  @Size(min = 2,max = 20,message = "用户名长度要在2-20之间")
  15.  private String username;
  16.  /**
  17.   * 密码
  18.   */
  19.  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
  20.  private String password;
  21.  /**
  22.   * 邮箱
  23.   */
  24.  @NotBlank(message="邮箱不能为空")
  25.  @Email(message="邮箱格式不正确")
  26.  private String email;
  27.  /**
  28.   * 手机号
  29.   */
  30.  @Pattern(regexp="0?1[0-9]{10}",message = "请输入正确的手机号")
  31.  private String mobile;
  32.  /**
  33.   * 状态  0:禁用   1:正常
  34.   */
  35.  private Integer status;
  36.  
  37.  /**
  38.   * 用户所在店铺id
  39.   */
  40.  private Long shopId;
  41.  
  42.  /**
  43.   * 角色ID列表
  44.   */
  45.  @TableField(exist=false)
  46.  private List<Long> roleIdList;
  47.  
  48.  /**
  49.   * 创建时间
  50.   */
  51.  private Date createTime;
  52. }
  1. @RestController
  2. @RequestMapping("/sys/user")
  3. public class SysUserController {
  4.  /**
  5.   * 保存用户
  6.   */
  7.  @SysLog("保存用户")
  8.  @PostMapping
  9.  @PreAuthorize("@pms.hasPermission('sys:user:save')")
  10.  public ResponseEntity<String> save(@Valid @RequestBody SysUser user){
  11.   String username = user.getUsername();
  12.   SysUser dbUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>()
  13.     .eq(SysUser::getUsername, username));
  14.   if (dbUser!=null) {
  15.    return ResponseEntity.badRequest().body("该用户已存在");
  16.   }
  17.   user.setShopId(SecurityUtils.getSysUser().getShopId());
  18.   user.setPassword(passwordEncoder.encode(user.getPassword()));
  19.   sysUserService.saveUserAndUserRole(user);
  20.   return ResponseEntity.ok().build();
  21.  }
  22. }

当然,我们也要简单介绍下oauth的运行流程:

  1. +--------+                               +---------------+
  2.      |        |--(A)- Authorization Request ->|   Resource    |
  3.      |        |                               |     Owner     |
  4.      |        |<-(B)-- Authorization Grant ---|               |
  5.      |        |                               +---------------+
  6.      |        |
  7.      |        |                               +---------------+
  8.      |        |--(C)-- Authorization Grant -->| Authorization |
  9.      | Client |                               |     Server    |
  10.      |        |<-(D)----- Access Token -------|               |
  11.      |        |                               +---------------+
  12.      |        |
  13.      |        |                               +---------------+
  14.      |        |--(E)----- Access Token ------>|    Resource   |
  15.      |        |                               |     Server    |
  16.      |        |<-(F)--- Protected Resource ---|               |
  17.      +--------+                               +---------------+

订单

Order,订单。一次下单,生成一条订单记录,即使多种商品。

  1. /**
  2.      * 订单ID
  3.      */
  4.     @TableId
  5.     private Long orderId;
  6.     /**
  7.      * 店铺id
  8.      */
  9.     private Long shopId;
  10.     
  11.     /**
  12.      * 订购流水号
  13.      */
  14.     private String orderNumber;
  15.     /**
  16.      * 订单状态 1:待付款 2:待发货 3:待收货 4:待评价 5:成功 6 交易失败
  17.      */
  18.     private Integer status;
  19.     
  20.     /**
  21.      * 订购时间
  22.      */
  23.     private Date createTime;
  24.     /**
  25.      * 订单更新时间
  26.      */
  27.     private Date updateTime;
  28.     /**
  29.      * 付款时间
  30.      */
  31.     private Date payTime;
  32.     /**
  33.      * 发货时间
  34.      */
  35.     private Date dvyTime;
  36.     /**
  37.      * 完成时间
  38.      */
  39.     private Date finallyTime;
  40.     /**
  41.      * 取消时间
  42.      */
  43.     private Date cancelTime;
b52a77352c9f4cc92833eddd45f0dd8d.png
image.png

商品信息

  1. /**
  2.      * 产品名称,多个产品将会以逗号隔开
  3.      */
  4.     private String prodName;
  5.     
  6.     /**
  7.      * 总值
  8.      */
  9.     private Double total;
  10.     /**
  11.      * 实际总值
  12.      */
  13.     private Double actualTotal;
  14.     
  15.     /**
  16.      * 订单商品总数
  17.      */
  18.     private Integer productNums;
  19.     
  20.     /**
  21.      * 优惠总额
  22.      */
  23.     private Double reduceAmount;

买家信息

  1. /**
  2.      * 订购用户ID
  3.      */
  4.     private String userId;
  5.     /**
  6.      * 订单备注
  7.      */
  8.     private String remarks;
  • userId ,买家用户编号。

  • remarks ,买家购买备注。

image.png
  • total :商品总价。该字段通过 OrderItem的 price 求和计算。

  • freightAmount :运费总价。该字段通过 OrderItem的商品的运费价格求和计算。

  • reduceAmount:交易优惠金额。注意,TradeOrder 的

    • total = 100 ,reduceAmount = 72 ,actualTotal = 18 。

    • total = 100 ,reduceAmount = 10 ,actualTotal = 90 。

    • 购买的商品参加 折扣活动,原价 100 元,折扣价 10 元。那么数据如下(我们会看到折扣活动跟着 商品走):

    • 购买的商品使用优惠劵,在上面例子的基础上,优惠劵打 2 折。那么数据如下(我们会看到优惠劵跟着 Trade 走):

  • actualTotalactualTotal = total + freightAmount - reduceAmount

物流

  1. /**
  2.      * 配送类型
  3.      */
  4.     private String dvyType;
  5.     /**
  6.      * 配送方式ID
  7.      */
  8.     private Long dvyId;
  9.     /**
  10.      * 物流单号
  11.      */
  12.     private String dvyFlowId;

收货人信息UserAddrOrder

  1. public class UserAddrOrder implements Serializable {
  2.     /**
  3.      * ID
  4.      */
  5.     @TableId
  6.     private Long addrOrderId;
  7.     /**
  8.      * 地址ID
  9.      */
  10.     private Long addrId;
  11.     /**
  12.      * 用户ID
  13.      */
  14.     private String userId;
  15.     /**
  16.      * 收货人
  17.      */
  18.     private String receiver;
  19.     /**
  20.      * 省
  21.      */
  22.     private String province;
  23.     
  24.     /**
  25.      * 城市
  26.      */
  27.     private String city;
  28.     
  29.     /**
  30.      * 区
  31.      */
  32.     private String area;
  33.     /**
  34.      * 地址
  35.      */
  36.     private String addr;
  37.     /**
  38.      * 邮编
  39.      */
  40.     private String postCode;
  41.     /**
  42.      * 省ID
  43.      */
  44.     private Long provinceId;
  45.     
  46.     /**
  47.      * 城市ID
  48.      */
  49.     private Long cityId;
  50.     
  51.     /**
  52.      * 区域ID
  53.      */
  54.     private Long areaId;
  55.     /**
  56.      * 手机
  57.      */
  58.     private String mobile;
  59.     /**
  60.      * 建立时间
  61.      */
  62.     private Date createTime;
  63.     /**
  64.      * 版本号
  65.      */
  66.     private Integer version;
  67. }

结算信息OrderSettlement

  1. public class OrderSettlement implements Serializable {
  2.     /**
  3.      * 支付结算单据ID
  4.      */
  5.     @TableId
  6.     private Long settlementId;
  7.     /**
  8.      * 用户系统内部的订单号
  9.      */
  10.     private String payNo;
  11.     /**
  12.      * 外部订单流水号
  13.      */
  14.     private String bizPayNo;
  15.     
  16.     /**
  17.      * 订单号
  18.      */
  19.     private String orderNumber;
  20.     
  21.     /**
  22.      * 支付方式 0 手动代付 1 微信支付 2 支付宝
  23.      */
  24.     private Integer payType;
  25.     /**
  26.      * 支付金额
  27.      */
  28.     private Double payAmount;
  29.     /**
  30.      * 用户ID
  31.      */
  32.     private String userId;
  33.     /**
  34.      * 是否清算 0:否 1:是
  35.      */
  36.     private Integer isClearing;
  37.     /**
  38.      * 创建时间
  39.      */
  40.     private Date createTime;
  41.     /**
  42.      * 清算时间
  43.      */
  44.     private Date clearingTime;
  45.     /**
  46.      * 支付状态
  47.      */
  48.     private Integer payStatus;
  49.     
  50.     /**
  51.      * 版本号
  52.      */
  53.     private Integer version;
  54.     /**
  55.      * 支付方式名称
  56.      */
  57.     private String payTypeName;
  58. }
  • orderNumber :关联订单的订单号

  • payNo: 支付时的支付订单号,根据雪花算法生成

  • payAmount:实付金额。

  • bizPayNo:外部交易编号。比如,如果支付方式是微信支付,就是财付通的交易单号。

订单项 OrderItem

每个订单都会有多个商品,每个商品就是一个订单项。

  1. /**
  2.      * 订单项ID
  3.      */
  4.     @TableId(type = IdType.AUTO)
  5.     private Long orderItemId;
  6.     private Long shopId;
  7.     /**
  8.      * 订单orderNumber
  9.      */
  10.     private String orderNumber;
  11.     /**
  12.      * 产品ID
  13.      */
  14.     private Long prodId;
  15.     /**
  16.      * 产品SkuID
  17.      */
  18.     private Long skuId;
  19.     /**
  20.      * 购物车产品个数
  21.      */
  22.     private Integer prodCount;
  23.     /**
  24.      * 产品名称
  25.      */
  26.     private String prodName;
  27.     /**
  28.      * sku名称
  29.      */
  30.     private String skuName;
  31.     /**
  32.      * 产品主图片路径
  33.      */
  34.     private String pic;
  35.     /**
  36.      * 产品价格
  37.      */
  38.     private Double price;
  39.     /**
  40.      * 用户Id
  41.      */
  42.     private String userId;
  43.     /**
  44.      * 商品总金额
  45.      */
  46.     private Double productTotalAmount;
  47.     /**
  48.      * 购物时间
  49.      */
  50.     private Date recTime;
  51.     /**
  52.      * 评论状态: 0 未评价  1 已评价
  53.      */
  54.     private Integer commSts;
  55.     /**
  56.      * 推广员使用的推销卡号
  57.      */
  58.     private String distributionCardNo;
  59.     /**
  60.      * 加入购物车的时间
  61.      */
  62.     private Date basketDate;
  • orderNumber :订单编号,指向 Order.orderNumber 。

  • prodId:商品id

  • 冗余商品字段:

    • prodName ,商品标题。

    • pic ,商品主图片地址。

  • skuId ,商品 SKU 编号,指向 ItemSku.id 。

  • 冗余商品 SKU 字段:

    • skuName ,SKU的值,即:商品的规格。如:机身颜色:黑色;手机套餐:官方标配。

  • num ,购买数量。

地区管理

96bbd81eef4a75fe519d3f4a94a2d54f.png
image.png
model实体类:
  1. @Data
  2. @TableName("tz_area")
  3. public class Area implements Serializable {
  4.     private static final long serialVersionUID = -6013320537436191451L;
  5.     @TableId
  6.     @ApiModelProperty(value = "地区id",required=true)
  7.     private Long areaId;
  8.     @ApiModelProperty(value = "地区名称",required=true)
  9.     private String areaName;
  10.     @ApiModelProperty(value = "地区上级id",required=true)
  11.     private Long parentId;
  12.     @ApiModelProperty(value = "地区层级",required=true)
  13.     private Integer level;
  14.     @TableField(exist=false)
  15.     private List<Area> areas;
  16. }
  • areaId ,地区id

  • areaName,地区名称

  • level,级别,根据上面所说的地区枚举

  • parentId ,地区上级id

model实体类:
运费模板类(tz_transport)
  1. @Data
  2. @TableName("tz_transport")
  3. public class Transport{
  4.     /**
  5.      * 运费模板id
  6.      */
  7.     @TableId
  8.     @ApiModelProperty(value = "运费模板id",required=true)
  9.     private Long transportId;
  10.     /**
  11.      * 运费模板名称
  12.      */
  13.     @ApiModelProperty(value = "运费模板名称",required=true)
  14.     private String transName;
  15.     /**
  16.      * 店铺id
  17.      */
  18.     @ApiModelProperty(value = "店铺id",required=true)
  19.     private Long shopId;
  20.     /**
  21.      * 参考 TransportChargeType
  22.      * 收费方式(0 按件数,1 按重量 2 按体积)
  23.      */
  24.     @ApiModelProperty(value = "收费方式(0 按件数,1 按重量 2 按体积)",required=true)
  25.     private Integer chargeType;
  26.    /**
  27.     * 是否包邮 0:不包邮 1:包邮
  28.     */
  29.     @ApiModelProperty(value = "是否包邮 0:不包邮 1:包邮",required=true)
  30.     private Integer isFreeFee;
  31.     /**
  32.      * 是否含有包邮条件
  33.      */
  34.     @ApiModelProperty(value = "是否含有包邮条件",required=true)
  35.     private Integer hasFreeCondition;
  36.     
  37.     /**
  38.      * 创建时间
  39.      */
  40.     @ApiModelProperty(value = "创建时间",required=true)
  41.     private Date createTime;
  42. }
  • transportId ,运费模板id

  • transName,运费模板名称,存在多个运费模板时,方便商家选择更好的运费模板

  • shopId,店铺id,可扩展为B2B2C模式

  • isFreeFee,是否包邮,如果商家选择了包邮,则不需要后面的其他操作

  • chargeType,收费方式可分为按件数、按重量 、按体积,影响运费项表中firstPiececontinuousFee的单位

  • hasFreeCondition,是否包含包邮条件,勾选后,商家可以设定指定包邮的地区与条件

运费项(tz_transfee)
  1. @Data
  2. @TableName("tz_transfee")
  3. public class Transfee {
  4.     /**
  5.      * 运费项id
  6.      */
  7.     @TableId
  8.     @ApiModelProperty(value = "运费项id",required=true)
  9.     private Long transfeeId;
  10.     /**
  11.      * 运费模板id
  12.      */
  13.     @ApiModelProperty(value = "运费模板id",required=true)
  14.     private Long transportId;
  15.     /**
  16.      * 续件数量
  17.      */
  18.     @ApiModelProperty(value = "续件数量",required=true)
  19.     private Double continuousPiece;
  20.     /**
  21.      * 首件数量
  22.      */
  23.     @ApiModelProperty(value = "首件数量",required=true)
  24.     private Double firstPiece;
  25.     /**
  26.      * 续件费用
  27.      */
  28.     @ApiModelProperty(value = "续件费用",required=true)
  29.     private Double continuousFee;
  30.     /**
  31.      * 首件费用
  32.      */
  33.     @ApiModelProperty(value = "首件费用",required=true)
  34.     private Double firstFee;
  35. }
运费项关联城市表(tz_transcity)
  1. @Data
  2. @TableName("tz_transcity")
  3. public class Transcity implements Serializable {
  4.     @TableId
  5.     private Long transcityId;
  6.     /**
  7.      * 运费项id
  8.      */
  9.     private Long transfeeId;
  10.     /**
  11.      * 城市id
  12.      */
  13.     private Long cityId;
  14. }

运费项可以根据需求指定特定区域的进行设置,运费项表与运费项关联城市表之间为一对多的关系,设定的区域优先于所有地区。

  • transcityId , 模板项关联城市ID

  • transfeeId ,关联的模板项目ID

  • cityId , 关联亚米商城系统中的区域管理模块

指定条件包邮项表(tz_transfee_free)
  1. @Data
  2. @TableName("tz_transfee_free")
  3. public class TransfeeFree {
  4.     /**
  5.      * 指定条件包邮项id
  6.      */
  7.     @TableId
  8.     @ApiModelProperty(value = "指定条件包邮项id",required=true)
  9.     private Long transfeeFreeId;
  10.     /**
  11.      * 运费模板id
  12.      */
  13.     @ApiModelProperty(value = "运费模板id",required=true)
  14.     private Long transportId;
  15.     /**
  16.      * 包邮方式 (0 满x件/重量/体积包邮 1满金额包邮 2满x件/重量/体积且满金额包邮)
  17.      */
  18.     @ApiModelProperty(value = "包邮方式 (0 满x件/重量/体积包邮 1满金额包邮 2满x件/重量/体积且满金额包邮)",required=true)
  19.     private Integer freeType;
  20.     /**
  21.      * 需满金额
  22.      */
  23.     @ApiModelProperty(value = "需满金额",required=true)
  24.     private Double amount;
  25.     /**
  26.      * 包邮x件/重量/体积
  27.      */
  28.     @ApiModelProperty(value = "包邮x件/重量/体积",required=true)
  29.     private Double piece;
  30. }
  1. @Data
  2. public class ShopCartOrderMergerDto implements Serializable{
  3.     @ApiModelProperty(value = "实际总值", required = true)
  4.     private Double actualTotal;
  5.     @ApiModelProperty(value = "商品总值", required = true)
  6.     private Double total;
  7.     @ApiModelProperty(value = "商品总数", required = true)
  8.     private Integer totalCount;
  9.     @ApiModelProperty(value = "订单优惠金额(所有店铺优惠金额相加)", required = true)
  10.     private Double orderReduce;
  11.     @ApiModelProperty(value = "地址Dto", required = true)
  12.     private UserAddrDto userAddr;
  13.     @ApiModelProperty(value = "每个店铺的购物车信息", required = true)
  14.     private List<ShopCartOrderDto> shopCartOrders;
  15.     @ApiModelProperty(value = "整个订单可以使用的优惠券列表", required = true)
  16.     private List<CouponOrderDto> coupons;
  17. }
yum remove docker \ > docker-client \ > docker-client-latest \ > docker-common \ > docker-latest \ > docker-latest-logrotate \ > docker-logrotate \ > docker-selinux \ > docker-engine-selinux \ > docker-engine

这段命令是在卸载 Docker 相关的软件包。它先使用 yum remove 命令移除了以下 Docker 相关的软件包:

  • container-selinux

  • docker

  • docker-client

  • docker-common

然后,它输出了一些关于仓库的信息,包括签名和主要数据库的下载进度。在这之后,它列出了所有将要被移除的软件包及其版本和大小,然后询问用户是否继续。用户选择了 y 表示同意进行卸载操作。

最后,它给出了一个提示,如果用户希望回滚上述操作,可以使用 yum load-transaction 命令。这个命令会加载之前保存的事务信息,从而可以回滚到之前的状态。

5fbd2ea167d304a314ca46960d36dcc0.png
image.png
88acdfdaaf057e1b9cd312d8dbd8e3fa.png
image.png
48b1cbae54edb88b21ab3a8b8845dd9c.png
image.png
c43d3a5f9c3d3626a55bba36eb7a050d.png
image.png
7fdff3ad872ba82732bb27fe6719c8d9.png
image.png

dump下来的文件大约1.8g,用jvisualvm查看,发现用char[]类型的数据占用了41%内存,同时另外一个com.alibaba.druid.stat.JdbcSqlStat类型的数据占用了35%的内存,也就是说整个堆中几乎全是这两类数据。

加群联系作者vx:xiaoda0423

仓库地址:https://github.com/webVueBlog/JavaGuideInterview

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号