day18_支付宝支付项目部署(保存支付信息,支付接口,支付宝异步回调)

文章目录

  • 1 支付
    • 1.1 需求说明
    • 1.2 支付宝支付
      • 1.2.1 产品介绍
        • 产品特色
        • 使用示例
        • 申请条件
        • 费率
      • 1.2.2 接入准备
      • 1.2.3 手机网站支付快速接入
      • 1.2.4 官方demo研究
    • 1.3 环境搭建(service-pay)
    • 1.4 后端接口
      • 1.4.1 保存支付信息
        • 实现流程说明
        • 查询订单接口开发
        • openFeign接口定义
        • 代码实现
          • 添加依赖
          • 修改启动类
          • PaymentInfo
          • PaymentInfoService
          • PaymentInfoMapper
          • PaymentInfoMapper.xml
      • 1.4.2 支付接口
        • pom.xml
        • application-alipay.yml
        • AlipayProperties
        • 修改启动类(PayApplication)
        • AlipayConfiguration
        • AlipayController
        • AlipayService
        • 服务网关
      • 1.4.3 支付宝异步回调
        • 异步通知说明
        • 通知流程说明
        • 内网穿透介绍
        • 验证签名
        • 更新支付信息
          • PaymentInfoService
          • PaymentInfoMapper
          • PaymentInfoMapper.xml
        • 更新订单支付状态
        • 更新商品销量
          • SkuSaleDto
          • ProductController
          • ProductService
          • ProductSkuMapper
          • ProductSkuMapper.xml
          • ProductFeignClient
          • ProductFeignClientFallback
          • PaymentInfoService
  • 2 项目部署
    • 2.1 将配置文件导入Nacos
      • 2.1.1 引入依赖
      • 2.1.2 添加nacos配置文件
      • 2.1.3 修改application.yml
      • 2.1.4 启动项目测试
    • 2.2 docker部署
      • 2.2.0 Harbor准备
        • 2.2.0.1 修改harbor配置
        • 2.2.0.2 修改harbor-nginx容器端口号
        • 2.2.0.3 修改docker-registry通信安全地址
        • 2.2.0.4 docker服务端开启远程访问
        • 2.2.0.5 启动harbor所有容器
        • 2.2.0.6 在harbor控制台中创建spzx项目目录
      • 2.2.1 修改maven配置-settings.xml
      • 2.2.2 引入依赖插件
      • 2.2.4 编写dockerfile文件
      • 2.2.5 执行maven的打包命令
      • 2.2.6 拉取镜像部署
        • 部署
        • 启动

1 支付

1.1 需求说明

订单支付如图所示:

在这里插入图片描述

在支付页面点击确认支付按钮此时就需要对接第三方支付系统,给用户展示出第三方支付系统的收银台。

查看接口文档:

支付接口地址及返回结果:

get /api/order/alipay/submitAlipay/{orderNo}
返回结果:
支付宝支付H5表单

1.2 支付宝支付

官网地址:https://open.alipay.com/

支付宝(中国)网络技术有限公司 [1] 是国内的第三方支付平台,致力于提供“简单、安全、快速”的支付解决方案 [2] 。支付宝公司从2004年建立开始,始终以“信任”作为产品和服务的核心。旗下有“支付宝”与“支付宝钱包”两个独立品牌。自2014年第二季度开始成为当前全球最大的移动支付厂商。

1.2.1 产品介绍

产品特色

选择手机网站支付:https://open.alipay.com/api/detail?code=I1080300001000041949

在这里插入图片描述

手机网站支付是指商家在移动端网页展示商品或服务,用户在商家页面确认使用支付宝支付后,浏览器自动跳转支付宝 App 或支付宝网页完成付款的支付产品。该产品在签约完成后,需要技术集成方可使用。

使用示例

image

申请条件

支持的账号类型:支付宝企业账号、支付宝个人账号。

签约申请提交材料要求:

  • 提供网站地址,网站能正常访问且页面显示完整,网站需要明确经营内容且有完整的商品信息。
  • 网站必须通过 ICP 备案,且备案主体需与支付宝账号主体一致。若网站备案主体与当前账号主体不同时需上传授权函。
  • 个人账号申请,需提供营业执照,且支付宝账号名称需与营业执照主体一致。

注意:需按照要求提交材料,若部分材料不合格,收款额度将受到限制(单笔收款 ≤ 2000 元,单日收款 ≤ 20000 元)。若签约时未能提供相关材料(如营业执照),请在合约生效后的 30 天内补全,否则会影响正常收款。

费率
收费模式费率
单笔收费0.6%-1.0%

特殊行业费率为 1.0%,非特殊行业费率为 0.6%。特殊行业包含:休闲游戏、网络游戏点卡、游戏渠道代理、游戏系统商、网游周边服务、交易平台、网游运营商(含网页游戏)等。

1.2.2 接入准备

官方文档:https://opendocs.alipay.com/open/203/107084?pathHash=a33de091

整体流程:

在这里插入图片描述

为了提供数据传输的安全性,在进行传输的时候需要对数据进行加密:

常见的加密方式:

1、不可逆加密:只能会数据进行加密不能解密

2、可逆加密:可以对数据加密也可以解密

可逆加密可以再细分为:

1、对称加密: 加密和解密使用同一个秘钥

在这里插入图片描述

2、非对称加密:加密和解密使用的是不同的秘钥

在这里插入图片描述

支付宝为了提供数据传输的安全性使用了两个秘钥对:

在这里插入图片描述

沙箱环境使用步骤:

1、注册登录支付宝开放平台

2、进入支付宝开放平台控制台,选择沙箱环境

在这里插入图片描述

在这里插入图片描述

3、沙箱环境提供的应用已经绑定了相关产品

4、配置应用公钥:

在这里插入图片描述

需要下载支付宝秘钥生成器【https://opendocs.alipay.com/common/02khjo】,然后生成秘钥。

注意:使用沙箱买家账号进行测试,提前充值。

1.2.3 手机网站支付快速接入

官方文档:https://opendocs.alipay.com/open/203/105285?pathHash=ada1de5b

系统交互流程图:

在这里插入图片描述

作为我们的项目来讲只需要将支付宝的收银台展示给用户即可,后续支付的动作和我们的系统就没有关系了。支付成功以后,支付宝开放平台会请求我

们系统的接口通知支付结果,我们的系统也可以调用支付宝交易查询接口获取支付结果。

展示收银台流程图如下所示:

在这里插入图片描述

1.2.4 官方demo研究

步骤:

1、官方demo下载地址:https://opendocs.alipay.com/open/203/105910?pathHash=1a2e3a94

2、将访问demo的eclipse项目更改为idea的maven项目(jdk8)

3、在AlipayConfig类中填写参数信息

4、启动项目进行测试

1.3 环境搭建(service-pay)

步骤:

1、在spzx-service模块下创建一个service-pay微服务,并加入如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、准备application.yml、application-dev.yml、logback-spring.xml、mybatis-config.xml文件。文件内容如下所示:

server:
  port: 8514

spring:
  application:
    name: service-pay
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.136.142:8848
    sentinel:
      transport:
        dashboard: localhost:8080
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.136.142:3306/db_spzx?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true
    username: root
    password: 1234
  data:
    redis:
      host: 192.168.136.142
      port: 6379
      password: 1234

mybatis:
  config-location: classpath:mybatis-config.xml
  mapper-locations: classpath:mapper/*/*.xml
feign:
  sentinel:
    enabled: true

logback-spring.xml修改输出路径:

<property name="log.path" value="D://work//service-pay//logs" />

mybatis-config.xml:从之前的模块中进行复制

3、创建启动类

// com.atguigu.spzx.pay;
@SpringBootApplication
@EnableUserWebMvcConfiguration
public class PayApplication {

    public static void main(String[] args) {
        SpringApplication.run(PayApplication.class , args) ;
    }

}

1.4 后端接口

1.4.1 保存支付信息

实现流程说明

在支付之前需要保存支付信息到payment_info表中:

在这里插入图片描述

查询订单接口开发

在service-order微服务中需要提供一个根据orderNo查询订单信息的接口,步骤如下:

1、OrderMapper添加接口方法

OrderInfo getByOrderNo(String orderNo) ;

2、OrderMapper.xml映射文件添加如下sql语句

<select id="getByOrderNo" resultMap="orderInfoMap">
    select <include refid="columns" />
    from order_info
    where
    order_no = #{orderNo}
</select>

3、OrderService业务层代码实现

// 业务接口
OrderInfo getByOrderNo(String orderNo) ;

// 业务接口实现类
@Override
public OrderInfo getByOrderNo(String orderNo) {
    return orderInfoMapper.getByOrderNo(orderNo) ;
}

4、OrderController表现层代码实现

@Operation(summary = "获取订单信息")
@GetMapping("auth/getOrderInfoByOrderNo/{orderNo}")
public Result<OrderInfo> getOrderInfoByOrderNo(@Parameter(name = "orderId", description = "订单id", required = true) @PathVariable String orderNo) {
    OrderInfo orderInfo = orderInfoService.getByOrderNo(orderNo) ;
    return Result.build(orderInfo, ResultCodeEnum.SUCCESS);
}
openFeign接口定义

步骤:

1、在spzx-service-client模块下创建一个service-order-client的子模块

2、在service-order-client模块下定义远程openFeign接口

// com.atguigu.spzx.feign.order;
@FeignClient(value = "service-order" , fallback = OrderFeignClientFallback.class)
public interface OrderFeignClient {

    @GetMapping("/api/order/orderInfo/auth/getOrderInfoByOrderNo/{orderNo}")
    public Result<OrderInfo> getOrderInfoByOrderNo(@PathVariable String orderNo) ;

}


// com.atguigu.spzx.feign.order.fallback;
@Slf4j
public class OrderFeignClientFallback implements OrderFeignClient {

    @Override
    public Result<OrderInfo> getOrderInfoByOrderNo(String orderNo) {
        log.info("OrderFeignClientFallback...getOrderInfoByOrderNo方法执行了");
        return Result.build(null , ResultCodeEnum.SUCCESS) ;
    }

}

3、降级类自动化配置

在resources目录下创建一个MATE-INF/spring文件夹,在该文件夹下创建一个

org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,文件的中的内容如下所示:

com.atguigu.spzx.feign.order.fallback.OrderFeignClientFallback
代码实现
添加依赖

在service-pay微服务的pom.xml中添加service-order-client的依赖:

<dependency>
    <groupId>com.atguigu.spzx</groupId>
    <artifactId>service-order-client</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
修改启动类

在PayApplication启动类上添加如下代码:

@EnableFeignClients(basePackages = {
        "com.atguigu.spzx.feign.order"
})
PaymentInfo

针对当前要操作的数据定义一个与之对应的实体类:

// com.atguigu.spzx.model.entity.pay;
@Data
@Schema(description = "支付信息实体类")
public class PaymentInfo extends BaseEntity {

   private static final long serialVersionUID = 1L;

   @Schema(description = "用户id")
   private Long userId;

   @Schema(description = "订单号")
   private String orderNo;

   @Schema(description = "付款方式:1-微信 2-支付宝")
   private Integer payType;

   @Schema(description = "交易编号(微信或支付)")
   private String outTradeNo;

   @Schema(description = "支付金额")
   private BigDecimal amount;

   @Schema(description = "交易内容")
   private String content;

   @Schema(description = "支付状态:0-未支付 1-已支付")
   private Integer paymentStatus;

   @Schema(description = "回调时间")
   private Date callbackTime;

   @Schema(description = "回调信息")
   private String callbackContent;

}
PaymentInfoService
//业务接口
public interface PaymentInfoService {
    PaymentInfo savePaymentInfo(String orderNo);
}

//业务接口实现
// com.atguigu.spzx.pay.service.impl;
@Service
public class PaymentInfoServiceImpl implements PaymentInfoService {

    @Autowired
    private PaymentInfoMapper paymentInfoMapper ;

    @Autowired
    private OrderFeignClient orderFeignClient ;

    @Override
    public PaymentInfo savePaymentInfo(String orderNo) {

        // 查询支付信息数据,如果已经已经存在了就不用进行保存(一个订单支付失败以后可以继续支付)
        PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(orderNo);
        if(null == paymentInfo) {
            OrderInfo orderInfo = orderFeignClient.getOrderInfo(Long.parseLong(orderNo)).getData();
            paymentInfo = new PaymentInfo();
            paymentInfo.setUserId(orderInfo.getUserId());
            paymentInfo.setPayType(orderInfo.getPayType());
            String content = "";
            for(OrderItem item : orderInfo.getOrderItemList()) {
                content += item.getSkuName() + " ";
            }
            paymentInfo.setContent(content);
            paymentInfo.setAmount(orderInfo.getTotalAmount());
            paymentInfo.setOrderNo(orderNo);
            paymentInfo.setPaymentStatus(0);
            paymentInfoMapper.save(paymentInfo);
        }
        return paymentInfo;
    }
}
PaymentInfoMapper

持久层代码实现:

@Mapper
public interface PaymentInfoMapper {
    void save(PaymentInfo paymentInfo);
    PaymentInfo getByOrderNo(String orderNo);
}
PaymentInfoMapper.xml

在映射文件中定义对应的sql语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.atguigu.spzx.order.mapper.PaymentInfoMapper">

   <resultMap id="paymentInfoMap" type="com.atguigu.spzx.model.entity.order.PaymentInfo" autoMapping="true">
   </resultMap>
   
   <!-- 用于select查询公用抽取的列 -->
   <sql id="columns">
    id,user_id,order_no,pay_type,out_trade_no,amount,content,payment_status,callback_time,callback_content,create_time,update_time,is_deleted
   </sql>

   <insert id="save" useGeneratedKeys="true" keyProperty="id">
      insert into payment_info (
         id,
         user_id,
         order_no,
         pay_type,
         out_trade_no,
         amount,
         content,
         payment_status,
         callback_time,
         callback_content
      ) values (
         #{id},
         #{userId},
         #{orderNo},
         #{payType},
         #{outTradeNo},
         #{amount},
         #{content},
         #{paymentStatus},
         #{callbackTime},
         #{callbackContent}
      )
   </insert>

   <select id="getByOrderNo" resultMap="paymentInfoMap">
      select <include refid="columns" />
      from payment_info
      where
      order_no = #{orderNo}
   </select>
   
</mapper>

1.4.2 支付接口

pom.xml

在service-pay微服务中添加alipay的依赖:

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
</dependency>
application-alipay.yml

支付宝示例demo:https://opendocs.alipay.com/open/203/105285?pathHash=ada1de5b

将支付宝所需要的参数定义配置文件中,以提高代码的维护性:

spzx:
  alipay:
    alipay_url: https://openapi.alipaydev.com/gateway.do
    app_id: 2021000122609658
    app_private_key: MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXHXwKl51d5htttzJDQg1Oq+w/RAdjdGlTgGlodWxM5Vszd9IgnEffB2HlsGcpgHDteppONr8rWsEy/LmwaMR9C83YfgFPRbSIYATrQw1VynuwEFwvlW5FBT00QUqmL1AXaFGWLAao8xjRjQiArhnQA+o88DXEVnUwHTWFd8aOymesOUjJGWOId6x1MnK8om66Zxc/QFR/vZoQaE8YrATNGMMd1O1CGsnwgJ1bBOcG1Cv1dF903gllGwkLhSE3LK1/SbUg0fUi8mHU0EUyasbknlFqBdvFvJZZJ0NC+Z2sZqXV57DLa8M7bp6+YsDuc0o0EAVnLx7beYlDjwGDMgqxAgMBAAECggEAJo9UfpNviW1VJGrxvW3WXXPLRd2DESK8WZ1TyF7mMrz3x6tUiBO41zVYCrc3q8RljIOTak/X+iUfVXZdn6EsOkhPz2Vfyi2cQoxV1P54IaMYarXSACZeS+hpVLMwbDV4d3CcGPjE/kmB1L7rI4LJfWXyWHhnD+GL56ocZSFKHlcsY2bx99T+HHKTretBRnLQ8q8/iZLkTbxReaMd3o9dGTqS75d3O1nT4u0A8Pupo2dPrlE7NvtOLJMEKixToJPAfJ0b2/H1nxV19/ZW3xvRPJjSIdx32ULuUIyzkAMlH5jwO3D9NMR8fbLcsewgDAif0sPB3USpUT/4AfmJAdcVrQKBgQDf1DnUXQ/JPH/SS78W1EdUzvhGjead1NCG70gZH9YKWS3+l4wkl7l1bqrXGe17jVnPD0vHQZT7V9MjQpa0n9mGU6jKt7ym27BQwF6CLqLE82ITKKqRhUAY7D/TpXPD+DI4STmRqEWDzCgAeX2B9Y7MtOndlExPh8ZxPKtPxDPsNwKBgQCs1cH8h/nGXMv2I0hLPdIKVAQRPDCVBpzuycxn2ezHDcz5rBrYsjOpdNr3SWzcavduGI4A673uWa5znO2KE4e8Y8Uoi75wI7nx4/VapsnS8IuqpIOpkLR2ovEjxGz1BI6QyIg1Xl3QFF65BBVEucgYeLXvt/dMdUA7Z7id/h9cVwKBgDZkZmE69Dkc4JsEGT28/FCZsy/CEAbOzpXb1BN27xa4sTqrLT0/OaxV5mI7RMC/itGMkAet4jxqDT8GUYU3Sy8faWdJ2yhZPrGA7faIyrk9w9mQClMupHLqBmCyVj2LNPkEol7JG4t5s0baPyuztq38UNCt1xWEky61ZZQOw+dlAoGAQdEhD0bEwlpCPZhQBn8jRlWaOun94jJjfreQRJgDiAXkYcu9aXnrHIPogrUOZJ3DXcSyBv2/FU5HlbVT6/nl/cLMqNUWj2O7grb5jyzmvJJnzXLaxK7bWjZQt/ssNt4mYFJNNG2cMgofzDsW0lYhMdh+CCy5Wv9nl3e3IUtNq/8CgYASPcPdaCBLzCSGlTV9HMhQwRhOpWLOzQNKprebQf0fubNFGd6+yfM6DdejHXf6KH4IgV9l8OPe5ro85tmrBkvMlbh7KHbpYJ/V9cdMKd+kbxoJTkRKCnoZhY5QSuEMoC8OB1qhzJeuoqUvmpi0q569IBXrxZguD29ZqwGxoa1KNg==
    alipay_public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk41ooyX7utKM9B7jNcc4EzmyVU0Qfs18KFVFwyhl7YQMw/PB2YVQreVSvvb1rS/2YVxcjLK/9ehD//79b8aoxhFlEGqA7fGu0C2UR6pl+PhmRLcHeyN+DOG87Fhqb1t4JXmXQc1LXUfelJoh+r5XnMPWDAlY5JJtH3GZIU+AoBt9PuEtfhh03LL6WtnJMwOnqH94T8qHymLDftEGOWme1iAlenB692cUId20BmLJal621EAN+xpmkeJZEpx1wQ2fGhyTo7pm4v8LVLuqzOXkraffITvfbPl5IU0kjjs/QECwItAI0IBbNsDutezw/a0JobijjoF28uo4gtwmncBoQwIDAQAB
    return_payment_url: http://192.168.136.142/#/pages/money/paySuccess
    notify_payment_url: http://127.0.0.1:8500/api/order/alipay/callback/notify

在application-dev.yml文件中导入该配置:

spring:
  config:
    import: application-alipay.yml
AlipayProperties

定义一个实体类读取配置文件内

// com.atguigu.spzx.pay.properties;
@Data
@ConfigurationProperties(prefix = "spzx.alipay")
public class AlipayProperties {

    private String alipayUrl;
    private String appPrivateKey;
    public  String alipayPublicKey;
    private String appId;
    public  String returnPaymentUrl;
    public  String notifyPaymentUrl;

    public final static String format="json";
    public final static String charset="utf-8";
    public final static String sign_type="RSA2";

}
修改启动类(PayApplication)

在启动类上添加**@EnableConfigurationProperties**注解,开启通过实体类读取配置文件内容封装数据功能:

@EnableConfigurationProperties(value = { AlipayProperties.class })
AlipayConfiguration

定义一个AlipayConfiguration的配置类,配置发送请求的核心对象:AlipayClient

//  com.atguigu.spzx.pay.configuration;
@Configuration
public class AlipayConfiguration {

    @Autowired
    private AlipayProperties alipayProperties ;

    @Bean
    public AlipayClient alipayClient(){
        AlipayClient alipayClient = new DefaultAlipayClient(alipayProperties.getAlipayUrl() ,
                alipayProperties.getAppId() ,
                alipayProperties.getAppPrivateKey() ,
                AlipayProperties.format ,
                AlipayProperties.charset ,
                alipayProperties.getAlipayPublicKey() ,
                AlipayProperties.sign_type );
        return alipayClient;
    }

}
AlipayController
// com.atguigu.spzx.pay.controller
@Controller
@RequestMapping("/api/order/alipay")
public class AlipayController {

    @Autowired
    private AlipayService alipayService;

    @Operation(summary="支付宝下单")
    @GetMapping("submitAlipay/{orderNo}")
    @ResponseBody
    public Result<String> submitAlipay(@Parameter(name = "orderNo", description = "订单号", required = true) @PathVariable(value = "orderNo") String orderNo) {
        String form = alipayService.submitAlipay(orderNo);
        return Result.build(form, ResultCodeEnum.SUCCESS);
    }
}
AlipayService
//业务接口
public interface AlipayService {
    String submitAlipay(String orderNo);
}

//业务接口实现
// com.atguigu.spzx.pay.service.impl;
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private AlipayProperties alipayProperties ;

    @SneakyThrows  // lombok的注解,对外声明异常
    @Override
    public String submitAlipay(String orderNo) {

        //保存支付记录
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(orderNo);

        //创建API对应的request
        AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();

        // 同步回调
        alipayRequest.setReturnUrl(alipayProperties.getReturnPaymentUrl());

        // 异步回调
        alipayRequest.setNotifyUrl(alipayProperties.getNotifyPaymentUrl());

        // 准备请求参数 ,声明一个map 集合
        HashMap<String, Object> map = new HashMap<>();
        map.put("out_trade_no",paymentInfo.getOrderNo());
        map.put("product_code","QUICK_WAP_WAY");
        map.put("total_amount",paymentInfo.getAmount());
        map.put("subject",paymentInfo.getContent());
        alipayRequest.setBizContent(JSON.toJSONString(map));

        // 发送请求
        AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest);
        if(response.isSuccess()){
            log.info("调用成功");
            return response.getBody();
        } else {
            log.info("调用失败");
            throw new GuiguException(ResultCodeEnum.DATA_ERROR);
        }
    }

}
服务网关

在spzx-server-gateway网关中配置service-pay微服务的路由规则:

spring:
  cloud:
    gateway:
      routes:
        - id: service-pay
          uri: lb://service-pay
          predicates:
            - Path=/api/order/alipay/**

1.4.3 支付宝异步回调

异步通知说明

官网地址:https://opendocs.alipay.com/open/203/105286?pathHash=022a439c&ref=api

在这里插入图片描述

通知流程说明

当用户支付成功以后,支付宝系统会调用我们系统的接口通知支付结果,整体流程如下所示:

在这里插入图片描述

内网穿透介绍

在service-pay微服务中开发一个接口供支付宝进行调用:

// com.atguigu.spzx.pay.controller.AlipayController
@RequestMapping("callback/notify")
@ResponseBody
public String alipayNotify(@RequestParam Map<String, String> paramMap, HttpServletRequest request) {
    log.info("AlipayController...alipayNotify方法执行了...");
    return "success" ;
}

当支付成功以后支付宝无法调用本地接口,因为本地接口是位于一个私有IP地址范围内,并且被路由器或防火墙等设备保护起来。这个私有的网络设备无法直接从公共网络访问,该问题的解决可以使用内网穿透技术。

内网穿透:内网穿透(Intranet Port Forwarding)是一种将本地网络中的服务暴露给公共网络访问的技术。

内网穿透通过在公共网络上建立一个中转服务器,使得公共网络上的设备可以通过该中转服务器访问内网中的设备和服务。具体而言,内网穿透技术允

许您在公共网络上使用一个公网IP地址和端口号来映射到内网中的某个设备或服务的私有IP地址和端口号。

在这里插入图片描述

常见的内网穿透工具包括natapp、Ngrok、frp、花生壳等。

官网地址:https://natapp.cn/

试用步骤:

1、注册用户

2、购买隧道

在这里插入图片描述

3、购买二级域名,绑定隧道

在这里插入图片描述

4、下载客户端

在这里插入图片描述

5、客户端使用教程:https://natapp.cn/article/nohup

natapp.exe -authtoken=xxxxx

authtoken信息获取:

在这里插入图片描述

验证签名

支付宝回传过来的数据需要进行合法性的校验,校验通过以后才可以走后续的流程,具体代码如下所示:

// com.atguigu.spzx.pay.controller.AlipayController
@Operation(summary="支付宝异步回调")
@RequestMapping("callback/notify")
@ResponseBody
public String alipayNotify(@RequestParam Map<String, String> paramMap, HttpServletRequest request) {
    log.info("AlipayController...alipayNotify方法执行了...");
    boolean signVerified = false; //调用SDK验证签名
    try {
        signVerified = AlipaySignature.rsaCheckV1(paramMap, alipayProperties.getAlipayPublicKey(), AlipayProperties.charset, AlipayProperties.sign_type);
    } catch (AlipayApiException e) {
        e.printStackTrace();
    }

    // 交易状态
    String trade_status = paramMap.get("trade_status");

    // true
    if (signVerified) {

        // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
        if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
            // 正常的支付成功,我们应该更新交易记录状态
            paymentInfoService.updatePaymentStatus(paramMap, 2);
            return "success";
        }

    } else {
        // TODO 验签失败则记录异常日志,并在response中返回failure.
        return "failure";
    }

    return "failure";
}
更新支付信息
PaymentInfoService
//业务接口
void updatePaymentStatus(Map<String, String> map, Integer payType);


@Transactional
@Override
public void updatePaymentStatus(Map<String, String> map, Integer payType) {
    
    // 查询PaymentInfo
    PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(map.get("out_trade_no"));
    if (paymentInfo.getPaymentStatus() == 1) {
        return;
    }

    //更新支付信息
    paymentInfo.setPaymentStatus(1);
    paymentInfo.setOutTradeNo(map.get("trade_no"));
    paymentInfo.setCallbackTime(new Date());
    paymentInfo.setCallbackContent(JSON.toJSONString(map));
    paymentInfoMapper.updateById(paymentInfo);

}
PaymentInfoMapper
void updateById(PaymentInfo paymentInfo);
PaymentInfoMapper.xml
<update id="updateById" >
   update payment_info set
   <if test="userId != null and userId != ''">
      user_id = #{userId},
   </if>
   <if test="orderNo != null and orderNo != ''">
      order_no = #{orderNo},
   </if>
   <if test="payType != null">
      pay_type = #{payType},
   </if>
   <if test="outTradeNo != null and outTradeNo != ''">
      out_trade_no = #{outTradeNo},
   </if>
   <if test="amount != null and amount != ''">
      amount = #{amount},
   </if>
   <if test="content != null and content != ''">
      content = #{content},
   </if>
   <if test="paymentStatus != null">
      payment_status = #{paymentStatus},
   </if>
   <if test="callbackTime != null">
      callback_time = #{callbackTime},
   </if>
   <if test="callbackContent != null and callbackContent != ''">
      callback_content = #{callbackContent},
   </if>
   update_time =  now()
   where
   id = #{id}
</update>
更新订单支付状态

具体步骤:

1、在service-order微服务中开发一个更新订单支付状态的接口供service-pay微服务进行调用

// com.atguigu.spzx.order.controller.OrderInfoController
@Operation(summary = "获取订单分页列表")
@GetMapping("auth/updateOrderStatusPayed/{orderNo}/{orderStatus}")
public Result updateOrderStatus(@PathVariable(value = "orderNo") String orderNo , @PathVariable(value = "orderStatus") Integer orderStatus) {
    orderInfoService.updateOrderStatus(orderNo , orderStatus);
    return Result.build(null , ResultCodeEnum.SUCCESS) ;
}

// com.atguigu.spzx.order.service.impl.OrderInfoServiceImpl
@Transactional
@Override
public void updateOrderStatus(String orderNo, Integer orderStatus) {

    // 更新订单状态
    OrderInfo orderInfo = orderInfoMapper.getByOrderNo(orderNo);
    orderInfo.setOrderStatus(1);
    orderInfo.setPayType(orderStatus);
    orderInfo.setPaymentTime(new Date());
    orderInfoMapper.updateById(orderInfo);

    // 记录日志
    OrderLog orderLog = new OrderLog();
    orderLog.setOrderId(orderInfo.getId());
    orderLog.setProcessStatus(1);
    orderLog.setNote("支付宝支付成功");
    orderLogMapper.save(orderLog);
}

// com.atguigu.spzx.order.mapper.OrderInfoMapper
void updateById(OrderInfo orderInfo);

OrderInfoMapper.xml映射文件中添加sql语句:

<update id="updateById" >
    update order_info set
    <if test="userId != null and userId != ''">
        user_id = #{userId},
    </if>
    <if test="nickName != null and nickName != ''">
        nick_name = #{nickName},
    </if>
    <if test="orderNo != null and orderNo != ''">
        order_no = #{orderNo},
    </if>
    <if test="couponId != null and couponId != ''">
        coupon_id = #{couponId},
    </if>
    <if test="totalAmount != null and totalAmount != ''">
        total_amount = #{totalAmount},
    </if>
    <if test="couponAmount != null and couponAmount != ''">
        coupon_amount = #{couponAmount},
    </if>
    <if test="originalTotalAmount != null and originalTotalAmount != ''">
        original_total_amount = #{originalTotalAmount},
    </if>
    <if test="feightFee != null and feightFee != ''">
        feight_fee = #{feightFee},
    </if>
    <if test="payType != null">
        pay_type = #{payType},
    </if>
    <if test="orderStatus != null">
        order_status = #{orderStatus},
    </if>
    <if test="receiverName != null and receiverName != ''">
        receiver_name = #{receiverName},
    </if>
    <if test="receiverPhone != null and receiverPhone != ''">
        receiver_phone = #{receiverPhone},
    </if>
    <if test="receiverTagName != null and receiverTagName != ''">
        receiver_tag_name = #{receiverTagName},
    </if>
    <if test="receiverProvince != null and receiverProvince != ''">
        receiver_province = #{receiverProvince},
    </if>
    <if test="receiverCity != null and receiverCity != ''">
        receiver_city = #{receiverCity},
    </if>
    <if test="receiverDistrict != null and receiverDistrict != ''">
        receiver_district = #{receiverDistrict},
    </if>
    <if test="receiverAddress != null and receiverAddress != ''">
        receiver_address = #{receiverAddress},
    </if>
    <if test="paymentTime != null">
        payment_time = #{paymentTime},
    </if>
    <if test="deliveryTime != null">
        delivery_time = #{deliveryTime},
    </if>
    <if test="receiveTime != null">
        receive_time = #{receiveTime},
    </if>
    <if test="remark != null and remark != ''">
        remark = #{remark},
    </if>
    <if test="cancelTime != null and cancelTime != ''">
        cancel_time = #{cancelTime},
    </if>
    <if test="cancelReason != null and cancelReason != ''">
        cancel_reason = #{cancelReason},
    </if>
    update_time =  now()
    where
    id = #{id}
</update>

2、openFeign远程调用接口定义

// com.atguigu.spzx.feign.order.OrderFeignClient
@FeignClient(value = "service-order" , fallback = OrderFeignClientFallback.class)
public interface OrderFeignClient {

    @GetMapping("/api/order/orderInfo/auth/updateOrderStatusPayed/{orderNo}/{orderStatus}")
    public abstract Result updateOrderStatus(@PathVariable(value = "orderNo") String orderNo , @PathVariable(value = "orderStatus") Integer orderStatus) ;
}

3、PaymentInfoService业务代码修改

// com.atguigu.spzx.pay.service.impl.PaymentInfoServiceImpl
@Transactional
@Override
public void updatePaymentStatus(Map<String, String> map, Integer payType) {

    // 1、查询PaymentInfo
    // 2、更新支付信息
    // 3、更新订单的支付状态
    orderFeignClient.updateOrderStatus(paymentInfo.getOrderNo() , payType) ;

}
更新商品销量

操作模块:service-product

SkuSaleDto

定义远程调用传输的数据的实体类:

@Data
public class SkuSaleDto {

   private Long skuId;
   private Integer num;

}
ProductController

表现层代码:

@Operation(summary = "更新商品sku销量")
@PostMapping("updateSkuSaleNum")
public Boolean updateSkuSaleNum(@RequestBody List<SkuSaleDto> skuSaleDtoList) {
   return productService.updateSkuSaleNum(skuSaleDtoList);
}
ProductService

业务层代码实现:

//业务接口
Boolean updateSkuSaleNum(List<SkuSaleDto> skuSaleDtoList);

//业务接口实现
@Transactional
@Override
public Boolean updateSkuSaleNum(List<SkuSaleDto> skuSaleDtoList) {
    if(!CollectionUtils.isEmpty(skuSaleDtoList)) {
        for(SkuSaleDto skuSaleDto : skuSaleDtoList) {
            productSkuMapper.updateSale(skuSaleDto.getSkuId(), skuSaleDto.getNum());
        }
    }
    return true;
}
ProductSkuMapper
void updateSale(@Param("skuId") Long skuId, @Param("num") Integer num);
ProductSkuMapper.xml
<update id="updateSale" >
   update product_sku set sale_num = sale_num + #{num}, stock_num = stock_num - #{num}, update_time =  now() where id = #{skuId}
</update>
ProductFeignClient

操作模块:service-product-client

远程调用Feign接口

/**
 * 更新商品sku销量
 * @param skuSaleDtoList
 * @return
 */
@PostMapping("/api/product/updateSkuSaleNum")
Boolean updateSkuSaleNum(@RequestBody List<SkuSaleDto> skuSaleDtoList);
ProductFeignClientFallback

操作模块:service-product-client

远程调用服务降级容错类

@Override
public Boolean updateSkuSaleNum(List<SkuSaleDto> skuSaleDtoList) {
    log.info("ProductFeignClientFallback...updateSkuSaleNum的方法执行了");
    return false ;
}
PaymentInfoService

修改PaymentInfoService业务代码修改

@Transactional
@Override
public void updatePaymentStatus(Map<String, String> map, Integer payType) {

    // 1、查询PaymentInfo
    // 2、更新支付信息
    // 3、更新订单的支付状态
    // 4、更新商品销量
    OrderInfo orderInfo = orderFeignClient.getOrderInfoByOrderNo(paymentInfo.getOrderNo()).getData();
    List<SkuSaleDto> skuSaleDtoList = orderInfo.getOrderItemList().stream().map(item -> {
        SkuSaleDto skuSaleDto = new SkuSaleDto();
        skuSaleDto.setSkuId(item.getSkuId());
        skuSaleDto.setNum(item.getSkuNum());
        return skuSaleDto;
    }).collect(Collectors.toList());
    productFeignClient.updateSkuSaleNum(skuSaleDtoList) ;

}

2 项目部署

2.1 将配置文件导入Nacos

以service-user为例,其他模块类似

2.1.1 引入依赖

spzx-service模块引入依赖

<!-- 服务配置 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

2.1.2 添加nacos配置文件

在nacos服务器添加配置文件

在这里插入图片描述

将application-dev.yml文件中的内容复制到nacos的service-user-dev.yml配置中:

server:
  port: 8512

spring:
  application:
    name: service-user
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.136.142:8848
    sentinel:
      transport:
        dashboard: localhost:8080
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.136.142:3306/db_spzx?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=true
    username: root
    password: 1234
  data:
    redis:
      host: 192.168.136.142
      port: 6379
      password: 1234

mybatis:
  config-location: classpath:mybatis-config.xml
  mapper-locations: classpath:mapper/*/*.xml

2.1.3 修改application.yml

修改application.yml文件的内容如下所示:

spring:
  cloud:
    nacos:
      config:
        server-addr: 192.168.1.170:8848
  config:
    import:
      - nacos:service-user-dev.yml

2.1.4 启动项目测试

正常运行,接口正常访问

说明:

1、service-cart、service-pay、service-product、service-order按以上步骤调整(不需再次引入依赖)

2、spzx-server-gateway服务网关也是类似,注意单独引入依赖

2.2 docker部署

基于第一天docker环境及Harbor部署

2.2.0 Harbor准备

因为服务端80端口号被占用,所以修改harbor端口号为82

2.2.0.1 修改harbor配置
# 编辑配置 修改端口号为82
vim /opt/harbor/harbor.yml

在这里插入图片描述

2.2.0.2 修改harbor-nginx容器端口号
vim /opt/harbor/docker-compose.yml

在这里插入图片描述

2.2.0.3 修改docker-registry通信安全地址
vim /etc/docker/daemon.json

在这里插入图片描述

2.2.0.4 docker服务端开启远程访问
#修改该文件
vim /lib/systemd/system/docker.service

#找到ExecStart行,修改成如下内容
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H fd:// --containerd=/run/containerd/containerd.sock

systemctl daemon-reload				#重启守护进程
systemctl restart docker			#重启docker

注意:关闭防火墙[systemctl stop firewalld.service]

必须重启docker

2.2.0.5 启动harbor所有容器

执行harbor的安装启动脚本:

/opt/harbor/install.sh

浏览器访问harbor测试:

http://虚拟机ip:82
账号密码:
	admin/Harbor12345
2.2.0.6 在harbor控制台中创建spzx项目目录

在这里插入图片描述

2.2.1 修改maven配置-settings.xml

在maven的settings.xml文件中配置harbor服务的账号信息:

<server>
    <id>harbor</id>
    <username>admin</username>
    <password>Harbor12345</password>
    <configuration>
        <email>123456@aliyun.com</email>
    </configuration>
</server>

2.2.2 引入依赖插件

spzx-user为例,其他模块类似

pom.xml文件添加docker插件

<properties>
    <!--        harbor地址 -->
    <docker.repostory>192.168.1.170:82</docker.repostory>
    <!--        连接harbor的项目名称:和上面创建的项目名称一样 -->
    <docker.registry.name>spzx</docker.registry.name>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>1.2.2</version>

            <!--将插件绑定在某个phase执行-->
            <executions>
                <execution>
                    <id>build-image</id>
                    <!--将插件绑定在package这个phase(阶段)上。也就是说,用户只需执行mvn package,就会自动执行mvn docker:build-->
                    <phase>package</phase>
                    <goals>
                        <goal>build</goal>
                        <goal>push</goal>
                    </goals>
                </execution>
            </executions>

            <configuration>

                <serverId>harbor</serverId>
                <registryUrl>http://${docker.repostory}</registryUrl>
                <dockerHost>http://192.168.1.170:2375</dockerHost>  <!-- 配置docker主机地址 -->

                <!--指定生成的镜像名-->
                <imageName>${docker.repostory}/${docker.registry.name}/${project.artifactId}:${project.version}</imageName>
                <!-- 指定 dockerfile 路径-->
                <dockerDirectory>${project.basedir}</dockerDirectory>
                <!-- 是否跳过docker构建 -->
                <skipDockerBuild>false</skipDockerBuild>
            </configuration>
        </plugin>
    </plugins>
</build>

插件原理:就是在docker主机上构建docker对应的镜像,然后将构建的镜像推送到harbor远程仓库中。

2.2.4 编写dockerfile文件

该文件的位置必须是和pom.xml处于同一个目录

FROM centos7-jdk17
MAINTAINER atguigu
EXPOSE 8512
ADD target/service-user-1.0-SNAPSHOT.jar /service-user-1.0-SNAPSHOT.jar

WORKDIR /
ENTRYPOINT ["java" , "-jar" , "service-user-1.0-SNAPSHOT.jar"]

2.2.5 执行maven的打包命令

mvn clean package -DskipTests								# 打包跳过测试
mvn clean package -DskipTests -DskipdockerBuild				# 打包跳过测试的同时提高构建

控制台打印如图:

在这里插入图片描述

Harbor查看镜像:

在这里插入图片描述

注意:需要先在Harbor上将spzx项目创建出来

2.2.6 拉取镜像部署

部署

使用docker compose部署

service-user.yml文件的内容如下所示:

services:
  service-user:
    container_name: service-user
    image: 192.168.1.170/spzx/service-user:1.0-SNAPSHOT
    ports:
      - "8512:8512"

**注意:**拉取失败,请在docker中添加安全访问权限

# 编辑/etc/docker/daemon.json文件
vim /etc/docker/daemon.json

# 添加安全访问权限
{
  "insecure-registries":["http://192.168.1.170:82"]
}

# 重启Docker
systemctl restart docker

docker compose相关命令复习

# 启动容器(如果不存在容器就创建、存在则修改)
docker compose -f docker-compose.yml up -d

# 删除所有容器
docker compose -f docker-compose.yml down

# 停止所有容器
docker compose -f docker-compose.yml stop

# 启动所有容器
docker compose -f docker-compose.yml start

# 重启所有容器
docker compose -f docker-compose.yml restart
启动

docker compose相关命令:

# 启动容器(如果不存在容器就创建、存在则修改)
docker compose -f service-user.yml up -d

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【重温设计模式】备忘录模式及其Java示例

备忘录模式的概述 在软件设计的世界中&#xff0c;备忘录模式是一种行为设计模式&#xff0c;它的主要作用是保存对象的当前状态&#xff0c;以便在将来的某个时间点&#xff0c;可以将对象恢复到这个保存的状态。这种模式的命名源于生活中的备忘录&#xff0c;我们常常用它来…

P1914 小书童——凯撒密码

题目描述&#xff1a; AC代码&#xff1a; #include<iostream> #include<cstring>using namespace std;int main() {int n;scanf("%d",&n);string str;cin >> str;//字符串密码输入 for(int i0;i<str.size();i) //遍历字符串中的字符使其…

Unity的PICO项目基础环境搭建笔记(调试与构建应用篇)

文章目录 前言一、为设备开启开发者模式1、开启PICO VR一体机。前往设置>通用>关于本机>软件版本号2、一直点击 软件版本号 &#xff0c;直到出现 开发者 选项3、进入 开发者模式&#xff0c;打开 USB调试&#xff0c;选择 文件传输 二、实时预览应用场景1、下载PC端的…

Apache的运用与实战

WEB服务器 1、WEB服务简介 # 目前最主流的三个Web服务器是Apache、Nginx、 IIS。 - WEB服务器一般指网站服务器&#xff0c;可以向浏览器等Web客户端提供网站的访问&#xff0c;让全世界浏览。 - WEB服务器也称为WWW(WORLD WIDE WEB)服务器&#xff0c;主要功能是提供网上信息…

【Java - 框架 - Mybatis】(01) 普通Java项目使用Mybatis操作Mysql - 快速上手

普通Java项目使用Mybatis操作Mysql - 快速上手 说明 通过软件"IntelliJ IDEA"创建"Maven"项目完成&#xff1b;通过"Mybatis"框架操纵"MySQL"数据库完成操作&#xff1b; 环境 Java版本"1.8.0_202"&#xff1b;Windows …

python 的zip函数的用法

目录 简介 示例 例子1 例子2 例子3 简介 zip在英语里的意思是拉链。想象两个列表&#xff08;或任何可迭代的容器&#xff09;&#xff0c;a和b。两者各自有若干元素。zip的输入变量就是两个可迭代的容器&#xff0c;zip的返回值也是一个容器&#xff0c;容器的每个元素都…

《JAVA与模式》之不变模式

系列文章目录 文章目录 系列文章目录前言一、不变模式的结构二、不变模式在JAVA中的应用三、不变模式的优点和缺点前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 …

OpenSearch 与 Elasticsearch:哪个开源搜索引擎适合您?

当谈论到搜索引擎产品时&#xff0c;Elasticsearch 和 OpenSearch 是两个备受关注的选择。它们都以其出色的功能和灵活性而闻名&#xff0c;但在一些方面存在一些差异。在本文中&#xff0c;我们将从功能和延展性、工具与资源、价格和许可这三个角度对这两个产品进行论述。通过…

OSPF直连路由引入实验简述

OSPF直连路由引入 实验拓扑图 实验命令 r2: sys sysname r2 undo info enable int loopb 0 ip add 2.2.2.2 32 quit int e0/0/0 ip add 23.1.1.2 24 quit ospf 1 area 0 network 23.1.1.0 0.0.0.255 network 2.2.2.2 0.0.0.0 ret sys int loopb 200 ip add 200.200.200.200 3…

KH-MCX-KWE-W

KH-MCX-KWE-W品牌: kinghelm(金航标)封装: 插件 描述: 镀金

【数据分享】2013-2022年全国范围逐日SO2栅格数据

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2013-2022年全国范围逐月SO2栅格数据和逐年SO2栅格数据&#xff08;均可查看之前的文章获悉详情&#xff09;。 本次我们给大家带来的是2013-2022年全国范围的逐日的SO2栅格数据&#xff0c;原始…

CSS中元素的层叠顺序

层叠顺序&#xff0c;英文称作 stacking order&#xff0c;表示元素发生层叠时有着特定的垂直显示顺序。下面是盒模型的层叠规则&#xff1a; 对于上图&#xff0c;由上到下分别是&#xff1a; &#xff08;1&#xff09;背景和边框&#xff1a;建立当前层叠上下文元素的背景…

飞驰云联CEO朱旭光荣获“科技领军人才”称号

2024年2月29日&#xff0c;苏州工业园区“优化营商环境暨作风效能建设大会”成功举办&#xff0c;会上公布了2023年度苏州工业园区第十七届第一批金鸡湖科技领军人才名单&#xff0c;Ftrans飞驰云联创始人兼CEO朱旭光先生凭借在数据安全以及文件交换领域取得的突出成果&#xf…

容器(0)-DOCKERFILE-安装-常用命令-部署-迁移备份-仓库

1.安装 启动 systemclt start docker //启动 systemctl status docker //状态 docker info systemclt stop docker systemctl status docker systemctl enable docker //开机启动 2.常用命令 镜像查看 docker images 镜像查看 docker status 镜像拉取 docker pull centos:…

红队专题-渗透工具-瑞士军刀Netcat

瑞士军刀Netcat NC: netcatNC反弹shell命令centos 安装反弹shell时如果用Linux的netcat监听可能 会出现中文字符、↑↓←→等特殊按键乱码问题,我们可以尝试使用rlwrap工具来解决这个问题。 NC: netcat 一个简单、可靠的网络工具 nc的作用(1)实现任意TCP/UDP端口的侦听 …

下载一些ROS的包的方式

ROS Index 我们可以去ROS Index网站下载一些我们需要的包。打开浏览器在网址框输入index.ros.org。或者点击此处链接ROS Index 在这个网站中我们可以浏览并找到我们需要的包&#xff0c;也可以下载它的源代码或者仅安装到我们的系统中来使用。&#xff08;安装过程在终端中进行…

【Redis知识点总结】(三)——Redis持久化机制、内存淘汰策略、惰性删除机制

Redis知识点总结&#xff08;三&#xff09;——Redis持久化机制、内存淘汰策略、惰性删除机制 Redis持久化RDBAOFAOF与RDB的对比混合持久化 内存淘汰策略惰性删除机制 Redis持久化 Redis有两种数据持久化的方式&#xff0c;一种是RDB、一种是AOF。 RDB RDB是内存快照&#…

市场情绪主升周期的分歧产生核心节点剖析

昨天下午我在群里分享了核心一些观点&#xff1a; 理解市场&#xff0c;划分情绪周期阶段&#xff0c;本质还是理解&#xff0c;观察驱动市场先手资金的动向。 亏钱可以说是因为我们带有个人偏见导致的&#xff0c;进一步说是因为我们偏离了市场资金共识导致的&#xff0c;可能…

HuggingFace团队亲授:如何使用HuggingFace上的开源模型

Open Source Models with Hugging Face 本文是 https://www.deeplearning.ai/short-courses/open-source-models-hugging-face/ 这门课程的学习笔记。 文章目录 Open Source Models with Hugging FaceWhat you’ll learn in this course Lesson 1: Selecting ModelsLesson 2: …

openJDK17官方镜像报Error loading shared library libfreetype.so

新项目使用openJDK17做的&#xff0c;做完后打包成docker镜像到服务器上运行 docker镜像基础镜像用的是openjdk:17-jdk-alpine 运行后加载验证码的时候报&#xff1a;Error loading shared library libfreetype.so 搜了一圈没找到哪里有共用的带字体库的jdk17镜像&#xff0…