策略模式深度实践——通用的HTTP接口调用

news2024/12/23 0:53:29

个人主页:金鳞踏雨

个人简介:大家好,我是金鳞,一个初出茅庐的Java小白

目前状况:22届普通本科毕业生,几经波折了,现在任职于一家国内大型知名日化公司,从事Java开发工作

我的博客:这里是CSDN,是我学习技术,总结知识的地方。希望和各位大佬交流,共同进步 ~

前言

前一段时间,跟着视频学习了策略模式,总结如下:

【23种设计模式】策略模式(State Pattern)_金鳞踏雨的博客-CSDN博客https://harmony.blog.csdn.net/article/details/131078118这几天公司的项目中正好使用到了策略模式!由于项目中经常需要调HTTP请求,所以使用策略模式来处理不同的HTTP请求。

策略模式

简单来说,就是为了解决多重 if 的问题,优化代码结构

环境(Context)/ 上下文:环境是策略模式的核心,它持有一个策略对象的引用,并在需要执行特定算法时,调用策略对象的方法。环境类负责将客户端的请求委派给具体的策略对象。

抽象策略(Strategy):抽象策略定义了策略类的公共接口,它可以是一个接口或抽象类。它声明了策略类应该实现的方法,以便环境类能够通过统一的接口调用不同的策略。

具体策略(Concrete Strategy):具体策略是抽象策略的具体实现,它实现了策略接口定义的方法,并封装了具体的算法逻辑。在不同的具体策略中,算法的实现可以有所不同。

策略模式实现通用的HTTP接口

1. 抽象策略(Strategy)

public abstract class AbstractXXXInterface {
	
	private static final Logger logger = Logger .getLogger("XXX");

	protected Context ctx;

	protected String otherJsonParam;

	protected int type;
	
	/** 查询接口配置信息的sql */
	private static final String querySql = "SELECT interfaceUrl, isOpen, typeLabel from T_RH_InterfaceConfig where interfaceType = %s";

	/** 单据编号 */
	protected String billNumber;

	/** 接口配置信息 */
	private InterfaceConfigEntity info;

	private String result;

	/** 请求方式:get、post */
	protected String httpMethodType;
	
	private JSONObject jsonObject;

	protected JSONObject otherParam;

	private boolean isCheckOpen = true;

	public AbstractXXXInterface setIsCheckOpen(boolean isCheckOpen) {
		this.isCheckOpen = isCheckOpen;
		return this;
	}

	protected abstract void initData();

	public AbstractXXXInterface call() throws Exception {
		if (StringUtils.isNotBlank(otherJsonParam)) {
			otherParam = JSONObject.parseObject(otherJsonParam);
		}
		// 校验
		validator();

		if (!isCall()) {
			return this;
		}
		initData();
		// 获取接口信息
		info = getInterfaceInfo();
		if (info == null) {
			throw new BOSException("接口信息为空");
		}
		if (isCheckOpen && !isOpen(info.getIsOpen())) {
			logger.error("接口:【" + info.getInterfaceLabel() + "】未开启");
			setResult("接口:【" + info.getInterfaceLabel() + "】未开启");
			return this;
		}
		// 设置接口参数
		info.setParamJson(createParamJson());
	
		// 调用接口
		jsonObject = HttpClientNewUtil.doHttp(ctx, info, httpMethodType);
		// 处理响应结果
		callBack();

		return this;
	}

	protected boolean isCall() throws Exception {
		return true;
	}

	/**
	 * 通用校验,可以重写该方法实现自己的校验
	 */
	protected void validator() throws Exception {
		if (StringUtils.isBlank(billNumber)) {
			logger.error("接口:【" + info.getInterfaceLabel() + "】单据编号为空");
			throw new BOSException("单据编号不能为空");
		}
	}

	/**
	 * 执行sql获取接口信息
	 */
	private InterfaceConfigEntity getInterfaceInfo() throws Exception {
		try {
			IRowSet rowSet = DbUtil.executeQuery(ctx, String.format(querySql, type));
			while (rowSet.next()) {
				InterfaceConfigEntity info = new InterfaceConfigEntity();
				info.setInterfaceUrl(rowSet.getString("interfaceUrl"));
				info.setIsOpen(rowSet.getInt("isOpen"));
				info.setInterfaceLabel(rowSet.getString("typeLabel"));
				return info;
			}
		} catch (Exception e) {
			logger.error("sql: " + type + "执行异常.", e);
			throw new Exception(e.getMessage());
		}
		return null;
	}

	/**
	 * 处理响应结果
	 */
	protected void callBack() throws Exception {
		JSONObject result = getJsonObject();
		if (result == null) {
			logger.error("单据【" + billNumber + "】响应结果为空");
			return;
		}
		if (isSuccess(result.getString("code"))) {
			successAfter(result);
		} else {
			failAfter(result);
		}
	}

	/**
	 * 成功后调用
	 */
	protected abstract void successAfter(JSONObject result) throws Exception;

	/**
	 * 失败后调用
	 */
	protected abstract void failAfter(JSONObject result) throws Exception;

	/**
	 * 根据具体单据创建请求参数
	 */
	protected abstract String createParamJson() throws Exception;
	
	/**
	 * 判断是否开启:1-开启,返回true
	 */
	private boolean isOpen(int isOpen) {
		return CommonUtils.convertBoolean(isOpen);
	}
  
	protected boolean isSuccess(String code) {
		return XXXConstant.InterfaceReturnCode.SUCCESSE.equals(code) || 
              XXXConstant.InterfaceReturnCode.SUCCESSE1.equals(code) ||        
              XXXConstant.InterfaceReturnCode.SUCCESSE2.equals(code);
	}

    /**
     * getter、setter方法
     */
	protected void setXXX(String XXX) {
		this.XXX= XXX;
	}
	public String getXXX() {
		return XXX;
	}
}

 2. 抽象工厂

public class XXXFactory {
	
	private XXXFactory() {
	}
	
	public static AbstractXXXInterface getStrategy(int type) {
		if (XXXConstant.InterfaceType.TYPE1 == type) {
			return new DEMO1();
		} else if (XXXConstant.InterfaceType.TYPE2 == type) {
			return new DEMO2();
        } else if (...) {
            return ...;
		} else {
			return null;
		}
	}
}

3. 具体策略(Concrete Strategy)

public class DEMO1 extends AbstractXXXInterface {
	
	private static Logger logger = Logger.getLogger("XXX");

	@Override
	protected String createParamJson() throws BOSException, SQLException {
		
        // 拼接请求报文(body)        

        return null;
	}

	@Override
	protected void failAfter(JSONObject result) throws BOSException,
			SQLException {
        
        // 调用接口失败的处理逻辑,处理响应

		setResult("同步失败");		
	}

	@Override
	protected void initData() {
		this.httpMethodType = CommonConstant.HttpType.POST;
        this.type = XXXConstant.InterfaceType.TYPE1; 
	}

	@Override
	protected void successAfter(JSONObject result) throws BOSException,
			SQLException {
        
        // 调用接口成功的处理逻辑,处理响应

		setResult("同步成功");
	}
}

4. HTTP工具类

/**
 * HTTP工具类
 */
public class HttpClientNewUtil {

    private static final Logger logger = Logger.getLogger("XXX");
    
    public static JSONObject doHttp(Context ctx, InterfaceConfigEntity info, String type) {
        String url = info.getInterfaceUrl();
        
        String token = "";

        try {
            if (isUrlEmpty(url)) {
                logger.error("接口地址为空");
                return null;
            }
            logger.error("start call interface: " + info.getInterfaceLabel());
            logger.error("The paramJson is: " + info.getParamJson());

            CloseableHttpClient httpClient = createClient(url);

            if (CommonConstant.HttpType.POST.equals(type)) {
                return doPost(ctx, httpClient, url, info, token);
            } else if (CommonConstant.HttpType.GET.equals(type)) {
                return doGet(ctx, httpClient, url, info, token);
            }
           
        } catch (Exception e) {
            logger.error("访问接口失败,接口地址为:" + url, e);
        }
        return null;
    }

	private static JSONObject doPost(Context ctx, CloseableHttpClient httpClient, String url,
                                      InterfaceConfigEntity info, String token) throws IOException {
        HttpPost httpPost = new HttpPost(url);
        
        
        httpPost.setHeader("source", "99");
        httpPost.setHeader("site", "1");
        
        // 设置Token头部
        httpPost.setHeader("token", getToken(ctx));
        
        if(info.getParamJson() != null) {
            StringEntity entity = new StringEntity(info.getParamJson(), "UTF-8");
            entity.setContentType("application/json");
            httpPost.setEntity(entity);
        }
        

        return parseResult(httpClient.execute(httpPost), info);
    }

    private static JSONObject doGet(Context ctx, CloseableHttpClient httpClient, String url,
                                    InterfaceConfigEntity info, String token) throws IOException {

        Map<String, String> params = JSONObject.parseObject(info.getParamJson(), Map.class);
        List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String value = entry.getValue();
            if (value != null) {
                pairs.add(new BasicNameValuePair(entry.getKey(), value));
            }
        }
        url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, "UTF-8"));
        HttpGet httpGet = new HttpGet(url);
        
        
      httpGet.setHeader("source", "99");
      httpGet.setHeader("site", "1");
      // 设置Token头部
      httpGet.setHeader("token", getToken(ctx));
        
        return parseResult(httpClient.execute(httpGet), info);
    }

    private static JSONObject parseResult(CloseableHttpResponse response, InterfaceConfigEntity info) throws IOException {
        logger.error("response:" + response);
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String resultJson = EntityUtils.toString(response.getEntity(), "utf-8");
            logger.error(info.getInterfaceLabel() + " response: " + resultJson);
            response.close();
            return JSONObject.parseObject(resultJson);
        }
        return null;
    }

    /**
     * 创建HttpClient客户端
     */
    @SuppressWarnings("deprecation")
    private static CloseableHttpClient createClient(String url) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        if (url.startsWith("https")) {
            try {
                SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                    // 信任所有
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return true;
                    }
                }).build();
                SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
                        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                httpClientBuilder.setSSLSocketFactory(sslsf);
            } catch (Exception e) {
                logger.error("创建HTTPS客户端异常", e);
            }
        }
        return httpClientBuilder.build();
    }

    /**
     * 判断url是否为空:为空返回true
     */
    private static boolean isUrlEmpty(String url) {
        return StringUtils.isBlank(url);
    }
    
    /**
     * 获取token
     */
    private static String getToken(Context ctx) {

        String token = null;
        
        try {
        	
        	String sql = "select interfaceUrl from T_RH_InterfaceConfig where interfaceType = 14;";
        	IRowSet rs = DbUtil.executeQuery(ctx, sql);
        	rs.next();
        		
            // 构造获取Token的请求
            HttpPost tokenRequest = new HttpPost(rs.getString("interfaceUrl"));
            tokenRequest.setHeader("Content-Type", "application/json");

            // 设置请求参数,如用户名和密码
            JSONObject requestBody = new JSONObject();
            requestBody.put("account", "eas");
            requestBody.put("password", "o6H95Utzv9GKzvx9+P45Zw==");
            StringEntity entity = new StringEntity(requestBody.toJSONString());
            entity.setContentType("application/json");
            tokenRequest.setEntity(entity);
            
            // 发送请求并解析响应
            CloseableHttpClient httpClient = HttpClients.createDefault();
            CloseableHttpResponse response = httpClient.execute(tokenRequest);
            
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            	
                String responseBody = EntityUtils.toString(response.getEntity());
                JSONObject responseJson = JSONObject.parseObject(responseBody);
                
                // 提取Token字段
                int code = responseJson.getIntValue("code");
                if (code == 1000) {
                    JSONObject data = responseJson.getJSONObject("data");
                    token = data.getString("token");
                }
            }
            
            // 关闭资源
            response.close();
            httpClient.close();
        } catch (Exception e) {
            logger.error("获取Token失败", e);
        }
        
        return token;
    }
}

文章到这里就结束了,如果有什么疑问的地方,可以在评论区指出~

希望能和大佬们一起努力,诸君顶峰相见

再次感谢各位小伙伴儿们的支持!!!

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

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

相关文章

【CSS卡片翻转特效】CSS3实现3D旋转动画卡片翻转效果(附源码)

文章目录 写在前面涉及知识点效果展示1、web页面的搭建1&#xff09;创建dom节点2&#xff09;DOM元素添加图片3&#xff09;添加翻转后的文字 2、CSS效果的实现1&#xff09;div本身翻转效果2&#xff09;3D翻转效果完整CSS3实现翻转效果demo代码可以留言邮箱或者自己去百度网…

扒开 TCP 的外衣,看清 TCP 的本质

TCP 非常重要&#xff0c;它的内容很多&#xff0c;今天只能讲解其中的一部分&#xff0c;但足以让你超越 80 % 的编程开发人员对于 TCP 的认知。 本篇内容非常多&#xff0c;非常干&#xff0c;希望你花点时间仔细研究&#xff0c;我相信会对你有所帮助。 1. TCP 协议是什么…

【tomcat】应用服务

准备环境 三台虚拟机 192.168.1.120 192.168.1.122 192.168.1.131 三台虚拟机关闭防火墙 、查看光盘 、检测yun创库 查看JDK是否安装 [rootlocalhost ~]# java -version openjdk version "1.8.0_161" //这是系统自带的rpm方式安装 OpenJDK Runtime Environment…

云端刺点难?这次看看云端地球怎么做

了解像控点与刺点 像控点是直接为摄影测量的控制点加密或测图需要而在实地布设并进行测定的控制点。 刺像控点是把外业采集的像控点的地理坐标与看到这个点的照片相关联的过程。在倾斜摄影建模中&#xff0c;使用像控点进行刺点可以大大提高建模精度。 为什么云端地球可以做…

青岛大学_王卓老师【数据结构与算法】Week04_02_带尾结点的循环链表合并_学习笔记

本文是个人学习笔记&#xff0c;素材来自青岛大学王卓老师的教学视频。 一方面用于学习记录与分享&#xff0c;另一方面是想让更多的人看到这么好的《数据结构与算法》的学习视频。 如有侵权&#xff0c;请留言作删文处理。 课程视频链接&#xff1a; 数据结构与算法基础–…

LLM搭建金融系统

背景&#xff1a; 这篇文章主要给大家介绍如何基于LLM模型配合各种pluging工具&#xff08;这边主要是跟数据连接、检索的工具相关&#xff1a;知识图谱、向量库...)。在开始文章前先讲讲我的观点&#xff1a;大模型的颠覆性应用应该不在于AIGC&#xff0c;而在于数据驱动技术…

python验证公网ip与内网ip

公网IP和内网IP都是用于标识网络设备的地址&#xff0c;但它们有着不同的作用和特点。 公网IP是由互联网服务提供商&#xff08;ISP&#xff09;分配给用户设备的唯一标识符。它是全球范围内唯一的&#xff0c;并且可以被其他网络设备使用来寻找和连接特定的设备。公网IP通常用…

Linux操作系统中命令提示符最后的符号为“#”或“$”

07-Linux操作系统中命令提示符最后的符号为“#”或“$” 1、最后提示符“#”2、最后提示符“$”3、[lwhlocalhost~]中 “ ~” 1、最后提示符“#” 表示管理员身份2、最后提示符“$” 表示不同用户3、[lwhlocalhost~]中 “ ~” 表示当前用户的家目录

安装umi

安装umi 一、安装Node.js&#xff0c;通过node -v查看版本号 二、安装yarn&#xff0c;其中tyarn使用的是npm.taobao.org的源&#xff0c;速度要快一些&#xff08;可以把yarn看做优化了的npm&#xff09; 1. 安装tyarn npm i yarn tyarn -g1 -g&#xff1a;全局安装 2. …

【C++】用Ceres从三维点中拟合三维空间中的圆

任务描述 在三维空间中有N个点&#xff0c;需要得到过这N个点的最优圆&#xff0c;需要估计圆的圆心、半径和法向量&#xff0c;本文提供了一种方法和代码示例&#xff0c;利用Ceres进行非线性拟合&#xff0c;在cpp上开发。 圆心为三维&#xff0c;半径一维&#xff0c;法向…

深入刨析容器(四):深入理解容器镜像

容器通过Namespace和Cgroups将自己与宿主机隔离&#xff0c;那么容器里的进程看到文件系统又是什么样子的呢&#xff1f;容器里的程序应该看到完全独立的文件系统&#xff0c;这样它就可以在自己的容器目录&#xff08;比如 /tmp&#xff09;下进行操作&#xff0c;而完全不会受…

贝莱德CEO力挺比特币!币圈嘲讽:传统金融从嘲笑到开始入场了!

资产管理巨头贝莱德&#xff08;BlackRock&#xff09;首席执行官Larry Fink公开喊话&#xff0c;希望监管者以民主化方式&#xff0c;来看待现货ETF申请。将与监管积极配合&#xff0c;解除他们对现货比特币ETF的疑虑。 六月中旬&#xff0c;贝莱德向美国证券交易委员会&#…

vue3中Cron表达式的使用

效果&#xff1a; <a-form-item label"Cron表达式" name"cron" required><a-input v-show"false" v-model:value"setForm.cron"></a-input><a-button type"primary" size"small" click"…

使用NVCleanstall导致显卡功率被锁至115W问题解决

以拯救者Y9000K为例&#xff0c;显卡功耗最大可以达到165W&#xff0c;但最近更新至最新的显卡驱动后&#xff0c;发现显卡功率被限制到了115W。一度怀疑是老黄做了手脚。 经过一系列测试后发现&#xff0c;是自己操作姿势不对。 NVIDIA Platform Controllers and Framework这…

leetcode极速复习版-第四章字符串

目录 344. 反转字符串 541. 反转字符串II 剑指Offer 05.替换空格 151.翻转字符串里的单词 剑指Offer58-II.左旋转字符串 28.实现 strStr() 459.重复的子字符串 字符串总结 344. 反转字符串 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 char…

JAVA jfreechart生成柱状图

JAVA jfreechart生成柱状图 在项目资源评估中&#xff0c;也就是生成word文档里需要根据数据生成柱状图&#xff0c;在网上找到了jfreechart工具包&#xff0c;来生成柱状图&#xff0c;当然他不仅仅只能生成柱状图&#xff0c;还支持折线图、饼状图等等… 过程 导入依赖 &l…

快速创建剪映草稿

实现原理 : JianYingPro 项目文件是 json 的形式存储的,只需要创建draft_content.json,draft_mate_info.json 打开软件后会自动补全。添加一个媒体到轨道顺序 草稿媒体库 -> 内容媒体库-> 轨道片段add_media_to_track 会识别媒体类型,加入到对应轨道。当没有视频轨道时…

哈希表 基础理论

什么是哈希表&#xff1f; 哈希表英文名hash table&#xff0c;国内有一些书籍也翻译为散列表。哈希表是根据关键码的值而直接进行访问的数据结构。 直白来讲&#xff0c;其实数组就是一张哈希表&#xff0c;哈希表中关键码就是数组的索引下标&#xff0c;然后通过下标直接访…

华为云编译构建CodeArts Build新手操作指南

华为云编译构建&#xff08;CodeArts Build&#xff09;基于云端大规模并发加速&#xff0c;为客户提供高速、低成本、配置简单的混合语言构建能力&#xff0c;帮助客户缩短构建时间&#xff0c;提升构建效率。 本文将给各位开发者带来华为云CodeArts Pipeline的手把手初级教学…

亚马逊买家账号被封的原因

亚马逊封号原因有很多种情况&#xff0c;以下是一些可能导致账号被封的常见原因&#xff1a; 1、违反亚马逊的服务条款&#xff1a;亚马逊有一系列的服务条款和规定&#xff0c;如果您违反了这些规定&#xff0c;比如多次提交虚假评价、涉及欺诈行为、滥用退货政策等&#xff…