前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >springboot第52集:微服务分布式架构,统一验证,oauth,订单,地区管理周刊

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

作者头像
达达前端
发布2024-01-27 12:43:02
1180
发布2024-01-27 12:43:02
举报
文章被收录于专栏:达达前端

在计算机领域中,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 正则表达式
代码语言:javascript
复制
public class SysUser implements Serializable {
 private static final long serialVersionUID = 1L;
 
 /**
  * 用户ID
  *
  */
 @TableId
 private Long userId;

 /**
  * 用户名
  */
 @NotBlank(message="用户名不能为空")
 @Size(min = 2,max = 20,message = "用户名长度要在2-20之间")
 private String username;

 /**
  * 密码
  */
 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
 private String password;

 /**
  * 邮箱
  */
 @NotBlank(message="邮箱不能为空")
 @Email(message="邮箱格式不正确")
 private String email;

 /**
  * 手机号
  */
 @Pattern(regexp="0?1[0-9]{10}",message = "请输入正确的手机号")
 private String mobile;

 /**
  * 状态  0:禁用   1:正常
  */
 private Integer status;
 
 /**
  * 用户所在店铺id
  */
 private Long shopId;
 
 /**
  * 角色ID列表
  */
 @TableField(exist=false)
 private List<Long> roleIdList;
 
 /**
  * 创建时间
  */
 private Date createTime;

}
代码语言:javascript
复制
@RestController
@RequestMapping("/sys/user")
public class SysUserController {
 /**
  * 保存用户
  */
 @SysLog("保存用户")
 @PostMapping
 @PreAuthorize("@pms.hasPermission('sys:user:save')")
 public ResponseEntity<String> save(@Valid @RequestBody SysUser user){
  String username = user.getUsername();
  SysUser dbUser = sysUserService.getOne(new LambdaQueryWrapper<SysUser>()
    .eq(SysUser::getUsername, username));
  if (dbUser!=null) {
   return ResponseEntity.badRequest().body("该用户已存在");
  }
  user.setShopId(SecurityUtils.getSysUser().getShopId());
  user.setPassword(passwordEncoder.encode(user.getPassword()));
  sysUserService.saveUserAndUserRole(user);
  return ResponseEntity.ok().build();
 }
}

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

代码语言:javascript
复制
+--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

订单

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

代码语言:javascript
复制
/**
     * 订单ID
     */
    @TableId
    private Long orderId;

    /**
     * 店铺id
     */
    private Long shopId;
    
    /**
     * 订购流水号
     */
    private String orderNumber;

    /**
     * 订单状态 1:待付款 2:待发货 3:待收货 4:待评价 5:成功 6 交易失败
     */
    private Integer status;
    
    /**
     * 订购时间
     */
    private Date createTime;

    /**
     * 订单更新时间
     */
    private Date updateTime;

    /**
     * 付款时间
     */
    private Date payTime;

    /**
     * 发货时间
     */
    private Date dvyTime;

    /**
     * 完成时间
     */
    private Date finallyTime;

    /**
     * 取消时间
     */
    private Date cancelTime;
商品信息
代码语言:javascript
复制
/**
     * 产品名称,多个产品将会以逗号隔开
     */
    private String prodName;
    
    /**
     * 总值
     */
    private Double total;

    /**
     * 实际总值
     */
    private Double actualTotal;
    
    /**
     * 订单商品总数
     */
    private Integer productNums;
    
    /**
     * 优惠总额
     */
    private Double reduceAmount;
买家信息
代码语言:javascript
复制
/**
     * 订购用户ID
     */
    private String userId;

    /**
     * 订单备注
     */
    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
物流
代码语言:javascript
复制
/**
     * 配送类型
     */
    private String dvyType;

    /**
     * 配送方式ID
     */
    private Long dvyId;

    /**
     * 物流单号
     */
    private String dvyFlowId;

收货人信息UserAddrOrder

代码语言:javascript
复制
public class UserAddrOrder implements Serializable {
    /**
     * ID
     */
    @TableId
    private Long addrOrderId;

    /**
     * 地址ID
     */
    private Long addrId;

    /**
     * 用户ID
     */
    private String userId;

    /**
     * 收货人
     */
    private String receiver;

    /**
     * 省
     */
    private String province;
    
    /**
     * 城市
     */
    private String city;
    
    /**
     * 区
     */
    private String area;

    /**
     * 地址
     */
    private String addr;

    /**
     * 邮编
     */
    private String postCode;

    /**
     * 省ID
     */
    private Long provinceId;
    
    /**
     * 城市ID
     */
    private Long cityId;
    
    /**
     * 区域ID
     */
    private Long areaId;

    /**
     * 手机
     */
    private String mobile;

    /**
     * 建立时间
     */
    private Date createTime;

    /**
     * 版本号
     */
    private Integer version;

}

结算信息OrderSettlement

代码语言:javascript
复制
public class OrderSettlement implements Serializable {
    /**
     * 支付结算单据ID
     */
    @TableId

    private Long settlementId;

    /**
     * 用户系统内部的订单号
     */
    private String payNo;

    /**
     * 外部订单流水号
     */
    private String bizPayNo;
    
    /**
     * 订单号
     */
    private String orderNumber;
    
    /**
     * 支付方式 0 手动代付 1 微信支付 2 支付宝
     */

    private Integer payType;

    /**
     * 支付金额
     */
    private Double payAmount;

    /**
     * 用户ID
     */

    private String userId;

    /**
     * 是否清算 0:否 1:是
     */

    private Integer isClearing;

    /**
     * 创建时间
     */

    private Date createTime;

    /**
     * 清算时间
     */

    private Date clearingTime;

    /**
     * 支付状态
     */
    private Integer payStatus;
    
    /**
     * 版本号
     */
    private Integer version;

    /**
     * 支付方式名称
     */
    private String payTypeName;

}
  • orderNumber :关联订单的订单号
  • payNo: 支付时的支付订单号,根据雪花算法生成
  • payAmount:实付金额。
  • bizPayNo:外部交易编号。比如,如果支付方式是微信支付,就是财付通的交易单号。

订单项 OrderItem

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

代码语言:javascript
复制
/**
     * 订单项ID
     */
    @TableId(type = IdType.AUTO)
    private Long orderItemId;


    private Long shopId;

    /**
     * 订单orderNumber
     */
    private String orderNumber;

    /**
     * 产品ID
     */

    private Long prodId;

    /**
     * 产品SkuID
     */
    private Long skuId;

    /**
     * 购物车产品个数
     */
    private Integer prodCount;

    /**
     * 产品名称
     */
    private String prodName;

    /**
     * sku名称
     */
    private String skuName;

    /**
     * 产品主图片路径
     */
    private String pic;

    /**
     * 产品价格
     */
    private Double price;

    /**
     * 用户Id
     */

    private String userId;

    /**
     * 商品总金额
     */
    private Double productTotalAmount;

    /**
     * 购物时间
     */

    private Date recTime;

    /**
     * 评论状态: 0 未评价  1 已评价
     */
    private Integer commSts;

    /**
     * 推广员使用的推销卡号
     */
    private String distributionCardNo;

    /**
     * 加入购物车的时间
     */
    private Date basketDate;
  • orderNumber :订单编号,指向 Order.orderNumber 。
  • prodId:商品id
  • 冗余商品字段:
    • prodName ,商品标题。
    • pic ,商品主图片地址。
  • skuId ,商品 SKU 编号,指向 ItemSku.id 。
  • 冗余商品 SKU 字段:
    • skuName ,SKU的值,即:商品的规格。如:机身颜色:黑色;手机套餐:官方标配。
  • num ,购买数量。

地区管理

model实体类:
代码语言:javascript
复制
@Data
@TableName("tz_area")
public class Area implements Serializable {
    private static final long serialVersionUID = -6013320537436191451L;
    @TableId
    @ApiModelProperty(value = "地区id",required=true)
    private Long areaId;

    @ApiModelProperty(value = "地区名称",required=true)
    private String areaName;

    @ApiModelProperty(value = "地区上级id",required=true)
    private Long parentId;

    @ApiModelProperty(value = "地区层级",required=true)
    private Integer level;

    @TableField(exist=false)
    private List<Area> areas;
}
  • areaId ,地区id
  • areaName,地区名称
  • level,级别,根据上面所说的地区枚举
  • parentId ,地区上级id
model实体类:
运费模板类(tz_transport)
代码语言:javascript
复制
@Data
@TableName("tz_transport")
public class Transport{
    /**
     * 运费模板id
     */
    @TableId
    @ApiModelProperty(value = "运费模板id",required=true)
    private Long transportId;

    /**
     * 运费模板名称
     */
    @ApiModelProperty(value = "运费模板名称",required=true)
    private String transName;

    /**
     * 店铺id
     */
    @ApiModelProperty(value = "店铺id",required=true)
    private Long shopId;

    /**
     * 参考 TransportChargeType
     * 收费方式(0 按件数,1 按重量 2 按体积)
     */
    @ApiModelProperty(value = "收费方式(0 按件数,1 按重量 2 按体积)",required=true)
    private Integer chargeType;


   /**
    * 是否包邮 0:不包邮 1:包邮
    */
    @ApiModelProperty(value = "是否包邮 0:不包邮 1:包邮",required=true)
    private Integer isFreeFee;

    /**
     * 是否含有包邮条件
     */
    @ApiModelProperty(value = "是否含有包邮条件",required=true)
    private Integer hasFreeCondition;
    
    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间",required=true)
    private Date createTime;
}
  • transportId ,运费模板id
  • transName,运费模板名称,存在多个运费模板时,方便商家选择更好的运费模板
  • shopId,店铺id,可扩展为B2B2C模式
  • isFreeFee,是否包邮,如果商家选择了包邮,则不需要后面的其他操作
  • chargeType,收费方式可分为按件数、按重量 、按体积,影响运费项表中firstPiececontinuousFee的单位
  • hasFreeCondition,是否包含包邮条件,勾选后,商家可以设定指定包邮的地区与条件
运费项(tz_transfee)
代码语言:javascript
复制
@Data
@TableName("tz_transfee")
public class Transfee {
    /**
     * 运费项id
     */
    @TableId
    @ApiModelProperty(value = "运费项id",required=true)
    private Long transfeeId;

    /**
     * 运费模板id
     */
    @ApiModelProperty(value = "运费模板id",required=true)
    private Long transportId;

    /**
     * 续件数量
     */
    @ApiModelProperty(value = "续件数量",required=true)
    private Double continuousPiece;

    /**
     * 首件数量
     */
    @ApiModelProperty(value = "首件数量",required=true)
    private Double firstPiece;

    /**
     * 续件费用
     */
    @ApiModelProperty(value = "续件费用",required=true)
    private Double continuousFee;

    /**
     * 首件费用
     */
    @ApiModelProperty(value = "首件费用",required=true)
    private Double firstFee;

}
运费项关联城市表(tz_transcity)
代码语言:javascript
复制
@Data
@TableName("tz_transcity")
public class Transcity implements Serializable {
    @TableId
    private Long transcityId;

    /**
     * 运费项id
     */
    private Long transfeeId;

    /**
     * 城市id
     */
    private Long cityId;
}

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

  • transcityId , 模板项关联城市ID
  • transfeeId ,关联的模板项目ID
  • cityId , 关联亚米商城系统中的区域管理模块
指定条件包邮项表(tz_transfee_free)
代码语言:javascript
复制
@Data
@TableName("tz_transfee_free")
public class TransfeeFree {
    /**
     * 指定条件包邮项id
     */
    @TableId
    @ApiModelProperty(value = "指定条件包邮项id",required=true)
    private Long transfeeFreeId;

    /**
     * 运费模板id
     */
    @ApiModelProperty(value = "运费模板id",required=true)
    private Long transportId;

    /**
     * 包邮方式 (0 满x件/重量/体积包邮 1满金额包邮 2满x件/重量/体积且满金额包邮)
     */
    @ApiModelProperty(value = "包邮方式 (0 满x件/重量/体积包邮 1满金额包邮 2满x件/重量/体积且满金额包邮)",required=true)
    private Integer freeType;

    /**
     * 需满金额
     */
    @ApiModelProperty(value = "需满金额",required=true)
    private Double amount;

    /**
     * 包邮x件/重量/体积
     */
    @ApiModelProperty(value = "包邮x件/重量/体积",required=true)
    private Double piece;
}
代码语言:javascript
复制
@Data
public class ShopCartOrderMergerDto implements Serializable{

    @ApiModelProperty(value = "实际总值", required = true)
    private Double actualTotal;

    @ApiModelProperty(value = "商品总值", required = true)
    private Double total;

    @ApiModelProperty(value = "商品总数", required = true)
    private Integer totalCount;

    @ApiModelProperty(value = "订单优惠金额(所有店铺优惠金额相加)", required = true)
    private Double orderReduce;

    @ApiModelProperty(value = "地址Dto", required = true)
    private UserAddrDto userAddr;

    @ApiModelProperty(value = "每个店铺的购物车信息", required = true)
    private List<ShopCartOrderDto> shopCartOrders;

    @ApiModelProperty(value = "整个订单可以使用的优惠券列表", required = true)
    private List<CouponOrderDto> coupons;
}
代码语言:javascript
复制
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 命令。这个命令会加载之前保存的事务信息,从而可以回滚到之前的状态。

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 统一验证
  • 订单
    • 商品信息
      • 买家信息
        • 物流
          • 收货人信息UserAddrOrder
            • 结算信息OrderSettlement
              • 订单项 OrderItem
              • 地区管理
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档