SpringBoot案例 调用第三方接口传输数据

一、前言

最近再写调用三方接口传输数据的项目,这篇博客记录项目完成的过程,方便后续再碰到类似的项目可以快速上手
项目结构:
在这里插入图片描述

二、编码

这里主要介绍HttpClient发送POST请求工具类和定时器的使用,mvc三层架构编码不做探究

pom.xml

<dependencies>
   <!--web启动依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- httpclient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    <!--fastjson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.79</version>
    </dependency>
    <!--swagger2-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.1</version>
    </dependency>
    <!--mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!--druid-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.14</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!--测试单元-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

application-dev.yml

#####端口配置#####
server:
  port: 9991

#####数据源配置#####
spring:
  datasource:
    username: dev
    password: dev1234
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

#####mybatis配置#####
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.jzj.pojo
  configuration:
    map-underscore-to-camel-case: true

#####配置日志文件#####
logging:
  config: classpath:logback.xml
  #设置日志级别的节点
  level:
    com:
      jzj: debug

Constast

package com.jzj.common;

public class Constast {
    /**
     * 请求头信息
     */
    public static final String CONTENT_TYPE = "application/json;charset=UTF-8";

    /**
     * 返回状态值
     */
    public static final Integer OK = 200;

    public static  final String YK_URL = "三方接口地址";
}

utils

package com.jzj.utils;

import com.jzj.common.Constast;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * Apache HttpClient发送POST请求工具类
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/14 14:18
 */
public class HttpUtils {

    /**
     * 发送post请求
     *
     * @param url       请求url
     * @param jsonParam 请求参数
     * @return 响应数据
     */
    public static String doPostJson(String url, String jsonParam) {
        // 创建一个HttpPost对象,并指定URL
        HttpPost httpPost = new HttpPost(url);
        // 声明一个CloseableHttpResponse对象来接收请求的响应
        CloseableHttpResponse response = null;
        // 创建一个CloseableHttpClient对象。wrapClient方法是自定义的方法,用于构建和配置HttpClient对象
        CloseableHttpClient httpClient = wrapClient(url);
        try {
            // 通过重新赋值的方式为HttpPost对象设置URL
            httpPost = new HttpPost(url);
            // 设置请求头的内容类型。Constast.CONTENT_TYPE表示请求的数据类型
            httpPost.setHeader("Content-type", Constast.CONTENT_TYPE);
            // 创建一个StringEntity对象,用于封装JSON参数。
            StringEntity entity = new StringEntity(jsonParam, "UTF-8");
            // 将实体的内容编码设置为与请求头的内容类型相同
            entity.setContentEncoding(new BasicHeader("Content-type", Constast.CONTENT_TYPE));
            // 将StringEntity对象设置为HttpPost请求的实体
            httpPost.setEntity(entity);
            // 执行HttpPost请求,并将响应赋值给response对象
            response = httpClient.execute(httpPost);
            // 判断响应的状态码是否等于200
            if (response.getStatusLine().getStatusCode() == Constast.OK) {
                // 将响应实体转换为字符串并返回。EntityUtils.toString方法用于读取响应实体的内容。
                return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            throw new RuntimeException("[发送POST请求错误:]" + e.getMessage());
        } finally {
            // 释放连接、关闭响应和关闭HttpClient对象
            try {
                httpPost.releaseConnection();
                response.close();
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 根据URL的协议来配置HttpClient对象
     * @param url url地址
     * @return CloseableHttpClient
     */
    private static CloseableHttpClient wrapClient(String url) {
        // 使用HttpClientBuilder类创建一个默认的HttpClient对象
        CloseableHttpClient client = HttpClientBuilder.create().build();
        if (url.startsWith("https")) { // 检查URL是否以"https"开头,以确定是否需要使用HTTPS协议
            // 如果URL以"https"开头,调用方法获取配置了HTTPS支持的CloseableHttpClient对象
            client = getCloseableHttpsClients();
        }
        return client;
    }

    /**
     * 创建一个支持HTTPS的CloseableHttpClient对象
     * @return CloseableHttpClient
     */
    private static CloseableHttpClient getCloseableHttpsClients() {
        // 采用绕过验证的方式处理https请求
        SSLClient ssl = new SSLClient();
        SSLContext sslcontext = ssl.createIgnoreVerifySSL();
        // 设置协议http和https对应的处理socket链接工厂的对象
        org.apache.http.config.Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
                .<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext)).build();
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        HttpClients.custom().setConnectionManager(connManager);
        // 创建自定义的httpsclient对象
        CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
        return client;
    }
}
package com.jzj.utils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;

/**
 * 用于创建一个支持绕过HTTPS验证的SSLContext对象
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/14 14:35
 */
public class SSLClient {

    // 使用@SuppressWarnings注解来抑制未使用的警告
    @SuppressWarnings("unused")
    public SSLContext createIgnoreVerifySSL() {
        // 创建套接字对象
        SSLContext sslContext = null;
        try {
            // 指定TLS版本
            sslContext = SSLContext.getInstance("TLSv1.2");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("[创建套接字失败:] " + e.getMessage());
        }
        // 实现X509TrustManager接口,用于绕过验证
        X509TrustManager trustManager = new X509TrustManager() {
            // 该方法用于验证客户端证书
            @Override
            public void checkClientTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            // 该方法用于验证服务器证书
            @Override
            public void checkServerTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate,
                                           String paramString) throws CertificateException {
            }

            // 该方法返回受信任的颁发机构(证书颁发机构)数组。在这里,返回null表示不对颁发机构进行限制
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        try {
            // 初始化sslContext对象
            sslContext.init(null, new TrustManager[]{trustManager}, null);
        } catch (KeyManagementException e) {
            throw new RuntimeException("[初始化套接字失败:] " + e.getMessage());
        }
        return sslContext;
    }
}

scheduled

package com.jzj.scheduled;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jzj.common.Constast;
import com.jzj.pojo.TrsfToYk;
import com.jzj.pojo.TrsfToYkLog;
import com.jzj.service.SfSfmxService;
import com.jzj.service.TrsfToYkLogService;
import com.jzj.service.TrsfToYkService;
import com.jzj.utils.HttpUtils;
import com.jzj.vo.YkResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 定时器任务
 *
 * @author 黎明
 * @version 1.0
 * @date 2023/8/15 15:03
 */
@Component
@Slf4j
public class TrsfToYkScheduled {
    // 注入trsfToYkService
    @Autowired
    private TrsfToYkService trsfToYkService;
    // 注入trsfToYkLogService
    @Autowired
    private TrsfToYkLogService trsfToYkLogService;
    // 注入SfSfmxService
    @Autowired
    private SfSfmxService sfSfmxService;

    /**
     * 审方信息下传英克
     */
    @Scheduled(cron = "*/10 * * * * *")
    public void toYk() {
        // 根据视图查询所有bs=0审方信息
        List<TrsfToYk> sfAllInfo = trsfToYkService.findAll();
        if (sfAllInfo.size() != 0) { // 判断是否有数据
            ObjectMapper mapper = new ObjectMapper();
            String requestData = null;
            try {
                requestData = mapper.writeValueAsString(sfAllInfo);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            log.info("发送的数据是:{}", requestData);
            String responseData = HttpUtils.doPostJson(Constast.YK_URL, requestData);
            log.info("响应的数据是:{}", responseData);
            JSONObject responseJson = JSONObject.parseObject(responseData);
            YkResultVo ykResultVo = responseJson.toJavaObject(YkResultVo.class);
            // 判断响应状态是否为200
            if (ykResultVo.getStatus().equals("200") && ykResultVo.getStatus() != null) {
                // 记录日志
                ykResultVo.getData().stream().forEach(v -> {
                    TrsfToYkLog trsfToYkLog = new TrsfToYkLog();
                    trsfToYkLog.setAuditId(v.getAuditId());
                    trsfToYkLog.setStatus(v.getStatus());
                    trsfToYkLogService.insertLog(trsfToYkLog);
                });

                // 更新审方明细表bs字段
                ykResultVo.getData().stream().filter(v -> v.getStatus().equals("200")).forEach(v -> {
                    long aid = Long.parseLong(v.getAuditId());
                    sfSfmxService.renewalBs(aid);
                });
            }
        }
    }
}

三、总结

该定时任务每10秒执行一次,将满足条件的审方信息发送到三方系统,并根据返回的结果进行相应的日志记录和数据更新操作。再调用三方接口时,使用的是封装好了的工具类将post请求发送给三方接口,并对https安全传输协议做了跳过操作。

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

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

相关文章

dom靶场

靶场下载地址&#xff1a; https://www.vulnhub.com/entry/domdom-1,328/ 一、信息收集 获取主机ip nmap -sP 192.168.16.0/24netdiscover -r 192.168.16.0/24端口版本获取 nmap -sV -sC -A -p 1-65535 192.168.16.209开放端口只有80 目录扫描 这里扫描php后缀的文件 g…

设计模式之责任链模式【Java实现】

责任链&#xff08;Chain of Resposibility&#xff09; 模式 概念 责任链&#xff08;chain of Resposibility&#xff09; 模式&#xff1a;为了避免请求发送者与多个请求处理者耦合在一起&#xff0c;于是将所有请求的处理者 通过前一对象记住其下一个对象的引用而连成一条…

Oracle 使用 CONNECT_BY_ROOT 解锁层次结构洞察:在 SQL 中导航数据关系

CONNECT_BY_ROOT 是一个在 Oracle 数据库中使用的特殊函数&#xff0c;它通常用于在层次查询中获取根节点的值。在使用 CONNECT BY 子句进行层次查询时&#xff0c;通过 CONNECT_BY_ROOT 函数&#xff0c;你可以在每一行中获取根节点的值&#xff0c;而不仅仅是当前行的值。 假…

打印出二进制的奇数位和偶数位

void print(int a) {int i0;printf("奇数位&#xff1a;");for(i30;i>0;i-2){printf("%d ",(a>>i)&1);}printf("\n");printf("偶数位&#xff1a;");for(i31;i>1;i-2){printf("%d ",(a>>i)&1);} …

Kotlin runBlocking launch多个协程读写mutableListOf时序

Kotlin runBlocking launch多个协程读写mutableListOf时序 import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlockingfun main(args: Array<String>) {var lists mutableListOf<String>()runBlocking {launch {r…

【boost网络库从青铜到王者】第五篇:asio网络编程中的同步读写的客户端和服务器示例

文章目录 1、简介2、客户端设计3、服务器设计3.1、session函数3.2、StartListen函数3、总体设计 4、效果测试5、遇到的问题5.1、服务器遇到的问题5.1.1、不用显示调用bind绑定和listen监听函数5.1.2、出现 Error occured!Error code : 10009 .Message: 提供的文件句柄无效。 [s…

09- DMA(DirectMemoryAccess直接存储器访问)

DMA 09 、DMA(DirectMemoryAccess直接存储器访问)DMA配置流程 09 、DMA(DirectMemoryAccess直接存储器访问) DMA配置流程 dma.c文件 main.c文件 详见《stm32中文参考手册》表57。

基于php驾校驾驶理论考试模拟系统

驾校驾驶理论考试模拟系统&#xff0c;是基于php编程语言&#xff0c;mysql数据库进行开发&#xff0c;本系统分为用户和管理员两个角色&#xff0c;其中用户可以注册登陆系统&#xff0c;查看考试规则&#xff0c;进行驾照考试&#xff0c;查看考试得分&#xff0c;考试错题&a…

hdu8-Congruences(中国剩余定理)

Problem - 7363 (hdu.edu.cn) 参考&#xff1a;2023杭电暑假多校8 题解 3 5 7 10 | JorbanS_JorbanS的博客-CSDN博客 题解&#xff1a;&#xff08;中国剩余定理 增量法&#xff09; 注意验证和特判&#xff0c;此题中 pi 两两互质&#xff0c;可用CRT和增量法&#xff0c;当…

设计模式之门面模式(Facade)的C++实现

1、门面模式提出 在组件的开发过程中&#xff0c;某些接口之间的依赖是比较紧密的&#xff0c;如果某个接口发生变化&#xff0c;其他的接口也会跟着发生变化&#xff0c;这样的代码违背了代码的设计原则。门面设计模式是在外部客户程序和系统程序之间添加了一层中间接口&…

Android上架商城 隐私政策需要网页 没有怎么办

Android开发的项目上架商城的时候会需要你填写url&#xff0c;但其实并不需要真的去发布一个网站 使用腾讯文档新建文档 填写隐私政策 点击生成网页 再将网址填写即可 下面我找到的一个隐私政策文档供大家参考 将XXXX应用一键替换为自己的应用 将XXXXXX公司一键替换为公司 …

Docker容器与虚拟化技术:Docker镜像创建、Dockerfile实例

目录 一、理论 1.Docker镜像的创建方法 2.Docker镜像结构的分层 3.Dockerfile 案例 4.构建Systemctl镜像&#xff08;基于SSH镜像&#xff09; 5.构建Tomcat 镜像 6.构建Mysql镜像 二、实验 1.Docker镜像的创建 2. Dockerfile 案例 3.构建Systemctl镜像&#xff08;…

web后端解决跨域问题

目录 什么是跨域问题 为什么限制访问 解决 什么是跨域问题 域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。但是一般情况下不能这么做&#xff0c;它是由浏览器的同源策略造成的&#xff0c;是浏览器对js施加的安全…

[oneAPI] 手写数字识别-卷积

[oneAPI] 手写数字识别 手写数字识别参数与包加载数据模型训练过程结果 oneAPI 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI&#xff1a;https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolkitSam…

Vector

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析2 目录 &#x1f449;&#x1f3fb;vector概念&#x1f449;&#x1f3fb;vector constr…

Python爬虫——scrapy_工作原理

引擎向spiders要url引擎把将要爬取的url给调度器调度器会将url生成的请求对象放入到指定的队列中从队列中出队一个请求引擎将请求交给下载器进行处理下载器发送请求获取互联网数据下载器将数据返回给引擎引擎将数据再次给到spidersspiders通过xpath解析该数据&#xff0c;得到数…

召集令:CloudQuery 社区有奖征文活动来啦!

CloudQuery 社区第一期征文活动来袭&#xff01;&#xff01;&#xff01;只要你对 CloudQuery 产品感兴趣&#xff0c;或者是希望了解 CQ &#xff0c;都可以来参加&#xff0c;在本期活动中&#xff0c;我们也为大家准备了多种主题供你选择&#xff0c;CQ 使用案例、版本对比…

字符设备驱动分布注册

驱动文件&#xff1a; 脑图&#xff1a; 现象&#xff1a;

Open3D 进阶(5)变分贝叶斯高斯混合点云聚类

目录 一、算法原理二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 系列文章(连载中。。。爬虫,你倒是爬个完整的呀?): Open3D 进阶(1) MeanShift点云聚类Open3D 进阶(2)DB…

Windows11 Docker Desktop 启动 -wsl kernel version too low

系统环境&#xff1a;windows11 1&#xff1a;docker下载 Docker: Accelerated Container Application Development 下载后双击安装即可 安装后启动Docker提示&#xff1a;Docker Desktop -wsl kernel version too low 处理起来也是非常方便 1:管理员身份启动&#xff1a;…