我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java 提供给第三方使用接口方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java 提供给第三方使用接口方法

Java提供接口给第三方使用,校验保证接口的安全性

前言

相信有很多小伙伴,在日常的开发中都有遇到过需要调用第三方接口的需求吧,但是自己有没有写过接口提供给第三方使用呢,常规的都是我们调用别人的接口,但是自己需要开发接口提供给第三方使用的场景应该不是很多,很多小伙伴可能会想不就开发一个接口对外开放嘛岂不是很简单,但是在开发接口对外开放,我们需要考虑一个问题,没有限制条件,那岂不是太不安全了,谁都可以调我这个接口了啊。
所以接下来的就是我们需要考虑的问题了,在开发接口的时候就要考虑到安全性的问题,那么应该如何去解决这个问题呢?提供接口给第三方使用的时候需要加上校验保证接口的安全性。
下面是我写的一个例子希望对大家有帮助。

接口Controller

在写接口前一定要签名做签名校验,我的签名方式做了特殊处理,因为接口是对外开放的,这个是为了避免恶意调用接口做的处理,叫做签名的混淆值,这个签名混淆值的作用是就算别人知道了接口,并且知道签名方式也不能被攻击,是为了避免被恶意篡改数据,签名混淆值就是一组特定加密后的数据。

@PostMapping("refundDeductionPoints")public Result<SysIntegralStatement> refundDeductionPoints (@RequestParam Map<String,String> params){Result<SysIntegralStatement> result = new Result<SysIntegralStatement>();try {//签名校验String msgDigest = params.get("msgDigest");//签名String msgData = params.get("msgData");String timeStamp = params.get("timeStamp");String secret = params.get("secret");//秘钥String sign = SignUtil.sign(msgData+"wf8la1tw7p9o2xz",timeStamp);//wf8la1tw7p9o2xz为签名混淆值if (!msgDigest.equals(sign)) {return result.setCode(1006).setReason("数字签名无效");}if (Common.isEmpty(secret)) {//先签名后幂等校验return result.setCode(1001).setReason("密钥不能为空");}String value = redistempalte.opsForValue().get(secret);if (Common.isNotEmpty(value)) {logger.error("重复请求 secret={}",value);return result.setCode(1007).setReason("重复请求");}redistempalte.opsForValue().set(secret, "1",60,TimeUnit.SECONDS);//设置缓存一分钟return service.refundDeductionPoints(params);} catch (Exception e) {logger.error("添加积分流水异常", e);return result.setCode(ErrorCodes.BUSINESS_ERROR).setReason("生成积分流水失败");}}

接口幂等性校验

此接口做幂等性校验,幂等性校验常见解决方案有很多,可以自行根据实际情况选择,
说到幂等首先要先了解什么是幂等
概念:
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。

在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数.

幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次,比如:

订单接口, 不能多次创建订单
支付接口, 重复支付同一笔订单只能扣一次钱
支付宝回调接口, 可能会多次回调, 必须处理重复回调
普通表单提交接口, 因为网络超时等原因多次点击提交, 只能成功一次
等等
解决方案常见的几种方式
唯一索引 – 防止新增脏数据

token机制 – 防止页面重复提交

悲观锁 – 获取数据的时候加锁(锁表或锁行)

乐观锁 – 基于版本号version实现, 在更新数据那一刻校验数据

分布式锁 – redis(jedis、redisson)或zookeeper实现

状态机 – 状态变更, 更新数据时判断状态

如果有小伙伴不理解什么是幂等可以看看官方是解释

实现类ServiceImpl

@Transactional@Overridepublic Result<SysIntegralStatement> refundDeductionPoints(Map<String, String> params) {String msgData = params.get("msgData");ParamIntegral entity = new Gson().fromJson(msgData, ParamIntegral.class);if (Common.isNull(entity)) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("请求参数不能为空");}if (Common.isEmpty(entity.getBitems())) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("请求参数不能为空");}int row = 0;for (ParamIntegral bitem : entity.getBitems()) {if (Common.isEmpty(bitem.getDdh())) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("订单号为必传参数");}if (null == bitem.getJfz()) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("扣减积分不能为空");}List<MallOrderInfo> orderInfo = mallOrderInfoMapper.selectByDdh(bitem.getDdh());if (orderInfo == null) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("订单号为" + bitem.getDdh() + "没有此订单请联系客服核对信息。");}if (orderInfo != null && orderInfo.size() > 1) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("订单号为" + bitem.getDdh() + "有多个相同订单请联系客服核对信息。");}if (!"E".equals(orderInfo.get(0).getDdzt())) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("订单号为" + bitem.getDdh() + "未确认收货还没产生积分不允许退货。");}SysIntegral integral = Common.first(integralMapper.selectByMdbm(orderInfo.get(0).getMdbm()));if (integral == null) {return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("门店编码为" + orderInfo.get(0).getMdbm() + "积分汇总没有找到此门店,请联系客服核实");}BigDecimal kyjf = BigDecimal.ZERO;if (entity.getReturnGoods() == true) {// 可用积分小于扣减积分不够扣ERP使用前抵扣if (bitem.getJfz().compareTo(integral.getKyjf()) == 1) {kyjf = BigDecimal.ZERO;} else {// 可用积分 = 当前可用积分-扣减积分kyjf = Common.nvl(integral.getKyjf(), BigDecimal.ZERO).subtract(bitem.getJfz());}} else {// 可用积分 = 当前可用积分+退还积分kyjf = Common.nvl(integral.getKyjf(), BigDecimal.ZERO).add(bitem.getJfz());}// 更新积分汇总SysIntegral dataMap = new SysIntegral();dataMap.setIntegralId(integral.getIntegralId());dataMap.setMdbm(integral.getMdbm());dataMap.setKyjf(kyjf);dataMap.setUpdateTime(new Date());dataMap.setUpdateUser(entity.getUserName());dataMap.setUpdateUserid(entity.getUserId().intValue());row = integralMapper.updateByPrimaryKeySelective(dataMap);if (row == 0) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("更新积分失败");}//推送到ERP门店信息 BdMdxxH mdxx =new BdMdxxH(); mdxx.setMdbm(integral.getMdbm()); mdxx.setMdjf(kyjf);com.lkfs.cw.common.Result<BdMdxxH> bdMdxxh = dataBaseServiceApi.updateStorePoints(mdxx);if (!bdMdxxh.isComplete()) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return new Result<SysIntegralStatement>().setCode(bdMdxxh.getCode()).setReason(bdMdxxh.getReason());}SysIntegralStatement statement = new SysIntegralStatement();if (entity.getReturnGoods() == true) {statement.setJfz(bitem.getJfz().negate());// 消费的积分值if (bitem.getJfz().compareTo(integral.getKyjf()) == 1) {// 可用积分小于扣减积分不够扣ERP使用前抵扣statement.setTzhjfz(BigDecimal.ZERO);// 调整后积分值} else {statement.setTzhjfz(Common.nvl(integral.getKyjf(), BigDecimal.ZERO).subtract(bitem.getJfz()));// 调整后积分值}statement.setJfxflx("E");// 积分支出statement.setXxsm("退货扣减积分(订单号为:" + bitem.getDdh() + "," + "退货单号为:" + entity.getDjh() + ")" + "已扣除:"+ bitem.getJfz().negate() + ":积分");} else {// 取消退货statement.setJfxflx("I");// 积分收入statement.setJfz(bitem.getJfz());// 取消退货把积分赠送回来statement.setTzhjfz(Common.nvl(integral.getKyjf(), BigDecimal.ZERO).add(bitem.getJfz()));// 调整后积分值statement.setXxsm("取消退货(订单号为:" + bitem.getDdh() + "," + "退货单号为:" + entity.getDjh() + ")" + "已退还:"+ bitem.getJfz() + ":积分");}statement.setIntegralId(integral.getIntegralId());// 该门店积分编码statement.setTzqjfz(integral.getKyjf());// 调整前积分值statement.setDdh(entity.getDdh());statement.setCreateTime(new Date());// 流水生成时间statement.setCreateUser(entity.getUserName());statement.setCreateUserid(entity.getUserId().intValue());statement.setJftz("T");// 积分扣减为Tstatement.setZt("Y");// 状态 Y:有效row = mapper.insert(statement);if (row == 0) {TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return new Result<SysIntegralStatement>().setCode(ErrorCodes.INNER_ERROR).setReason("插入积分流水失败");}}return new Result<SysIntegralStatement>().setCode(ErrorCodes.SUCCESS).setReason("操作成功");}

第三方调用接口Api实现类

模拟第三方合作方调用接口

//此方式以上已写了封装信息就不一一展示了,可以根据实际情况自行操作private void pushIntegral(Long djlsh) {FiSjysjsH fiSjysjsh = mapper.selectByPrimaryKey(djlsh);//订单退货调用某某退货扣减积分接口List<FiSjysjsB> sjysjsbList = bmapper.selectByKhddh(djlsh);if (sjysjsbList != null && sjysjsbList.size() > 0) {List<ParamIntegral> list = new ArrayList<ParamIntegral>();for (FiSjysjsB bitem : sjysjsbList) {ParamIntegral temp = new ParamIntegral();temp.setDdh(bitem.getKhddh());temp.setJfz(bitem.getJfz());list.add(temp);}ParamIntegral param = new ParamIntegral();param.setBitems(list);param.setDjh(fiSjysjsh.getDjh());param.setUserId(AppRealm.getCurrentUser().getUserId());param.setUserName(AppRealm.getCurrentUser().getUserName());if (new Short("1").equals(fiSjysjsh.getLocked())) {param.setReturnGoods(true);}else {param.setReturnGoods(false);}String msgData = new Gson().toJson(param).toString();Map<String, String> params = new HashMap<String, String>();String timeStamp = String.valueOf(System.currentTimeMillis());//时间戳params.put("timeStamp", timeStamp);params.put("msgData", msgData);params.put("msgDigest", SignUtil.sign(msgData+"wf8la1tw7p9o2xz", timeStamp));//生成签名第二个值暂定(wf8la1tw7p9o2xz签名混淆值)params.put("secret",IDEMPOTENT_SECRET_PREFIX + fiSjysjsh.getDjh() + AppRealm.getCurrentUser().getUserId()+param.getReturnGoods() );//自定义密钥 做幂等校验String result = HttpCilent.post(B2B_URL, params); //发送http post请求B2bIntegralResponse res = new Gson().fromJson(result, B2bIntegralResponse.class);if (null == res) {throw new RuntimeException("调用积分接口系统异常");}if (res.getCode() != 0) {//接口返回失败异常代码提示throw new RuntimeException("调用积分接口发生异常,异常代码为:"+res.getCode()+"异常信息为:"+res.getReason());}}}

生成签名工具类

package com.cy.xgsm.util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.google.gson.JsonElement;import com.google.gson.JsonObject;import com.google.gson.JsonParser;public class SignUtil {private static final Logger log = LoggerFactory.getLogger(SignUtil.class);public static String sign(String str, String secret) {StringBuilder enValue = new StringBuilder();enValue.append(secret);enValue.append(str);enValue.append(secret);return encryptByMD5(enValue.toString());}private static String encryptByMD5(String data) {String re_md5 = new String();try {MessageDigest md = MessageDigest.getInstance("MD5");md.update(data.getBytes());byte b[] = md.digest();int i;StringBuffer buf = new StringBuffer();for (int offset = 0; offset < b.length; offset++) {i = b[offset];if (i < 0)i += 256;if (i < 16)buf.append("0");buf.append(Integer.toHexString(i));}re_md5 = buf.toString();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return re_md5.toUpperCase();}public static String compare(String jsonStr,String secret ){JsonParser jsonParser = new JsonParser();JsonObject jsonObject = jsonParser.parse(jsonStr).getAsJsonObject();String sign1 = "null";JsonElement signElement = jsonObject.remove("sign");if( signElement != null ){sign1 = signElement.getAsString();}log.info("sign1: " + sign1);StringBuilder enValue = new StringBuilder();enValue.append(secret);enValue.append(jsonObject.toString());enValue.append(secret);String sign2 = encryptByMD5(enValue.toString());jsonObject.addProperty("sign", sign2);return jsonObject.toString();}}

HttpCilent工具类

这个工具类在我之前的文章也有但是没有把这个方式的放上去,如果有需要用到可直接把一下代码复制到这个Http工具类 最后即可直接使用。

       public static String post(String url, Map<String, String> parameters) {    String result = "";// 返回的结果    BufferedReader in = null;// 读取响应输入流    PrintWriter out = null;    StringBuffer sb = new StringBuffer();// 处理请求参数    String params = "";// 编码之后的参数    try {    // 编码请求参数    if (parameters.size() == 1) {    for (String name : parameters.keySet()) {    sb.append(name)    .append("=")    .append(java.net.URLEncoder.encode(    parameters.get(name), "UTF-8"));    }    params = sb.toString();    } else {    for (String name : parameters.keySet()) {    sb.append(name)    .append("=")    .append(java.net.URLEncoder.encode(    parameters.get(name), "UTF-8")).append("&");    }    String temp_params = sb.toString();    params = temp_params.substring(0, temp_params.length() - 1);    }    // 创建URL对象    java.net.URL connURL = new java.net.URL(url);    // 打开URL连接    java.net.HttpURLConnection httpConn = (java.net.HttpURLConnection) connURL    .openConnection();    // 设置通用属性    httpConn.setRequestProperty("Accept", "*/*");    httpConn.setRequestProperty("Connection", "Keep-Alive");    httpConn.setRequestProperty("content-type", "application/x-www-form-urlencoded");    httpConn.setRequestProperty("User-Agent",    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)");    // 设置POST方式    httpConn.setDoInput(true);    httpConn.setDoOutput(true);    // 获取HttpURLConnection对象对应的输出流    out = new PrintWriter(httpConn.getOutputStream());    // 发送请求参数    out.write(params);    // flush输出流的缓冲    out.flush();    // 定义BufferedReader输入流来读取URL的响应,设置编码方式    in = new BufferedReader(new InputStreamReader(    httpConn.getInputStream(), "UTF-8"));    String line;    // 读取返回的内容    while ((line = in.readLine()) != null) {    result += line;    }    } catch (Exception e) {    e.printStackTrace();    } finally {    try {    if (out != null) {    out.close();    }    if (in != null) {    in.close();    }    } catch (IOException ex) {    ex.printStackTrace();    }    }    return result;    }

此文章仅供参考,如果能帮助到大家,可以给博主支持一下。

来源地址:https://blog.csdn.net/weixin_45731661/article/details/126341900

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java 提供给第三方使用接口方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java如何调用第三方接口

这篇“Java如何调用第三方接口”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java如何调用第三方接口”文章吧。一、 通过
2023-07-02

java怎么调用第三方接口

在Java中调用第三方接口通常可以通过使用网络请求的方式来实现。以下是一种基本的方法:使用Java的内置网络请求类,比如HttpURLConnection或者HttpClient来发送HTTP请求到第三方接口的URL。根据第三方接口的要求
java怎么调用第三方接口
2024-03-05

Java怎么调用第三方http接口

Java可以通过以下几种方式调用第三方HTTP接口:1. 使用Java内置的HttpURLConnection类:```javaimport java.io.BufferedReader;import java.io.InputStream
2023-08-17

Java调用第三方接口封装实现

本文主要介绍了Java调用第三方接口封装实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-02-16

如何使用Feign调用第三方http接口

本篇内容介绍了“如何使用Feign调用第三方http接口”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Feign调用第三方http接口我们平
2023-06-29

Android 应用提供SDK Jar包给第三方使用 (设计思路 以及实现步骤)

最近想总结一下关于应用如何封装自己的SDK给第三方应用使用,提供jar包给第三方使用是现在比较常见的方式,方式有很多种,但是具体的大体思路都是一样的,今天写了一个SDK封装的大体框架Demo,方便后期查查阅: 工具基于AndroidStud
2022-06-06

Java调用第三方http接口的方式总结(四种)

在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接口(短信、天气等) ①通过JDK网络类Java.net.HttpURLConn
2023-08-16

javaweb怎么调用第三方接口

调用第三方接口的方法在JavaWeb中与其他Java应用程序相同,可以使用Java的网络编程库来发送HTTP请求并处理响应。以下是一个简单的示例代码,演示如何使用JavaWeb调用第三方接口:```javaimport java.io.Bu
2023-08-23

java异步调用第三方接口怎么实现

在Java中,可以使用多线程或使用异步框架来实现异步调用第三方接口。1. 使用多线程:可以创建一个新的线程来执行第三方接口的调用操作,这样可以让主线程继续执行其他任务而不需要等待第三方接口的返回结果。可以使用Java的Thread类或者Ex
2023-10-09

php如何调用第三方api接口

要调用第三方API接口,可以使用PHP中的curl函数,示例如下:```php// 第三方API的URL$url = 'http://example.com/api';// 请求参数$data = ['param1' => 'value1'
2023-08-30

Springboot使用RestTemplate调用第三方接口的操作代码

这篇文章主要介绍了Springboot使用RestTemplate调用第三方接口,我只演示了最常使用的请求方式get、post的简单使用方法,当然RestTemplate的功能还有很多,感兴趣的朋友可以参考RestTemplate源码
2022-12-08

在Windows8的邮件应用中使用第三方提供商邮箱如qq/163

我们可以利用Windows 8 系统中自带的邮件功能,来让我们平时使用的(QQ、126、163)等第三方邮箱也能在不通过网页的情况下收发邮件。是不是很方便?首先在开始屏幕中打开“邮件”程序;如果我们需要使用非微软的邮
2023-06-03

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录