对接第三方平台JAVA接口问题推送和解决
前言
本节所讲为实际项目中与第三方对接出现的问题最后还是靠老大解决了问题以此作为备忘录,本篇分为三小节,一小节解析Java加密接口数据,二小节解析XML文件需注意问题,最后一节则是请求Java Soap协议接口。因为第三方平台都是采用JAVA语言,所以这种情况应该对大家有所帮助。
DES加密/解密Java接口
关于Java中序列化为XML文件就不搞了,我们首先需要讲解的是关于加密问题,由于是第三方是采用的DES加密,所以我们只讲解DES,有很多人可能有疑问了,这不过时了么且不安全,不必纠结,这个也不是你我能决定的问题,不在讨论范畴内。刚开始以为只是加密和解密而已,很简单嘛,况且网上的例子多如牛毛,慢慢发现是我太自信了,过后开始研究Java中加密的实现,网上文档如此说:Java中默认DES加密方式为ECB(电子密码本模式),而C#中默认DES加密方式为CBC(加密分组链接模式)这二者是最常见的DES加密方式,且加密key都为8位,其他的我们就不看了。而后看过各种Java和C#中DES加密文档,看到此链接文章时心里开始激动了:http://luanxiyuan.iteye.com/blog/1938348,结果一扫,文中所给的Java加密为CBC模式,而刚好对应C#中默认加密模式,,没毛病不是我想要的,再看看园中其他文章,恩,也挺好,作者给出了Java中的实现,C#中的实现也给出了,但是下面评论一看,加密或者解密出错,作者回复:在C#上未实践。我是没招了,搞了好久也没弄出来,最后还是没弄出来,老大搞定,我就等着吃现成的吧,事后我看了看代码,然后再次查了查资料发现其中区别,所以在这里作此备忘录。对此还特意下了个IDEA,玩玩Java,对比下java中C#中的实现,首先我们来看看Java中实现。原谅我没接触过Java,搞了两个小时才研究明白下载IDEA,破解IDEA,下载JDK,使用IDEA,导入包,调试java,本篇博客名称可以起名为:从Java到.NET,还是.NET好 ,结果很显然会喷,因为作为初学者没深入了解Java,所以还是老老实实起个正经博文名称。一边打开IDEA,一边打开VS,那叫一个卡啊。先看看安装最新IDEA 2017.2.1版本界面。
首先我们来看看在.NET中DES加密中ECB模式的实现。
public static string Encrypt(string originalString, string key)
{
if (String.IsNullOrEmpty(originalString))
{
throw new ArgumentNullException
("The string which needs to be encrypted can not be null.");
}
var bytes = Encoding.UTF8.GetBytes(key);
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()
{
Mode = CipherMode.ECB,
Padding = PaddingMode.None
}; MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
cryptoProvider.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);
StreamWriter writer = new StreamWriter(cryptoStream);
writer.Write(originalString);
writer.Flush();
cryptoStream.FlushFinalBlock();
writer.Flush();
return Convert.ToBase64String(memoryStream.GetBuffer(), , (int)memoryStream.Length);
}
public static string Decrypt(string cryptedString, string key)
{
if (String.IsNullOrEmpty(cryptedString))
{
throw new ArgumentNullException
("The string which needs to be decrypted can not be null.");
}
var bytes = Encoding.UTF8.GetBytes(key);
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()
{
Mode = CipherMode.ECB,
Padding = PaddingMode.None
};
MemoryStream memoryStream = new MemoryStream
(Convert.FromBase64String(cryptedString));
CryptoStream cryptoStream = new CryptoStream(memoryStream,
cryptoProvider.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
StreamReader reader = new StreamReader(cryptoStream);
return reader.ReadToEnd();
}
调用如下:
var encryptStr = Encrypt("Jeffcky from cnblogs", "");
神马啊,加密的数据长度无效,对数据长度还有要求啊,啥破玩意啊。然后需要删除填充模式:
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()
{
Mode = CipherMode.ECB,
Padding = PaddingMode.None
};
好了,没毛病了,在.NET中DES的ECB模式加密和解密就实现了,到了刚才才发现这么篇文章:http://www.cnblogs.com/Lawson/archive/2012/05/20/2510781.html,文中关键点在这里:ECB模式:电子密本方式,这是JAVA封装的DES算法的默认模式,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,则补足8个字节(注意:这里就涉及到数据补位了)进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。然后我们再来看看Java中的实现。
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64; public class DesAlgorithm {
private static final String CIPHER_ALGORITHM = "DES/ECB/NoPadding"; private static SecretKey keyGenerator(String keyStr) throws Exception {
DESKeySpec desKey = new DESKeySpec(keyStr.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secureKey = keyFactory.generateSecret(desKey);
return secureKey;
} private static String paddingChar(String date) {
if (date.getBytes().length % > ) {
for (int i = ; i < date.getBytes().length % ; i++) {
date = " " + date;
}
}
return date;
} public static String encrypt(String data, String key) throws Exception {
SecretKey desKey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecureRandom random = new SecureRandom();
cipher.init(Cipher.ENCRYPT_MODE, desKey, random);
byte[] results = cipher.doFinal(paddingChar(data).getBytes());
return Base64.encodeBase64String(results);
} public static String decrypt(String data, String key) throws Exception {
SecretKey desKey = keyGenerator(key);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, desKey);
return new String(cipher.doFinal(Base64.decodeBase64(data))).trim();
}
}
调用如下:
public class Main { public static void main(String[] args) {
try {
String source =
"<?xml version=\"1.0\" encoding=\"GBK\"?>\n" +
"<REQUEST>\n" +
" <workyear>4</workyear>\n" +
" <sex>0</sex>\n" +
" <name>汪鹏</name>\n" +
" <idtype>1</idtype>\n" +
" <idno>421081199109284899</idno>\n" +
" <brithday>1991-09-28</brithday>\n" +
" <school>北华大学</school>\n" +
" <email>2752154844@qq.com</email>\n" +
"</REQUEST>";
String key = "";
String encryptData = DesAlgorithm.encrypt(source,key);
System.out.println("加密后: " + encryptData);
String decryptData = DesAlgorithm.decrypt("hYbvHlD/ZpOBLyjofjVJmE4oAqitG9BAhhhuykmI0sc7C3TCLtuxCmjxp5WB+OXdEuwt1CqQxtLBCxpvsGbQUHw37J2LSABl+Zx4cM6Z8o5X4VdhTibUjryYkVPwYrzHgaiHA4VVDQ7P7RpMTsnFk372ZP1W+fr2UhpHC8hkohyBaOZ1NWOieQQvPvOLErhzcGWcmjUsnjp0vNEfM7y/FRsQhhvTKtRiPWPdRpWZGH+TofsSuhNtmcE61u0tgEhLcOpDvifLS9zGj2F7Jn8nR05Au7/uz5gl8jB6FCHc97YKAPR0jx69egA+MKfv6IYTmpSZSnWJGgFnnP4SpLGnH3+7Mm6uX8ni2sBaM0/9H9YpVgqpXJ2fCw==", key);
System.out.println("解密后: " + decryptData);
}
catch (Exception ex)
{ }
}
}
此时我们将加密后的数据利用.NET来进行解密,这里就有两个问题需要解决,一个是Java中ECB模式为不填充,第二个上述讲到Java中ECB加密时会对数据进行补位,且上述演示例子也是对数据进行了补位且用空字符串,所以在.NET中我们仍然需要加上ECB不填充且数据要补位和Java中一致,所以加密需要高修改为如下:
public static string Encrypt(string originalString, string key)
{
if (String.IsNullOrEmpty(originalString))
{
throw new ArgumentNullException
("The string which needs to be encrypted can not be null.");
}
byte[] textBytes = Encoding.UTF8.GetBytes(originalString);
int mod = (8 - (textBytes.Length % 8));
for (int i = 0; i < mod; i++)
{
originalString = " " + originalString;
}
var bytes = Encoding.UTF8.GetBytes(key);
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()
{
Mode = CipherMode.ECB,
Padding = PaddingMode.None
}; MemoryStream memoryStream = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(memoryStream,
cryptoProvider.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);
StreamWriter writer = new StreamWriter(cryptoStream);
writer.Write(originalString);
writer.Flush();
cryptoStream.FlushFinalBlock();
writer.Flush();
return Convert.ToBase64String(memoryStream.GetBuffer(), , (int)memoryStream.Length);
}
因为加密时对数据进行了补位,所以在加密时将补位的空字符串去除,所以上述解密出错我们只需要利用 Trim() 方法去除空字符串即可,我们看看
public static string Decrypt(string cryptedString, string key)
{
if (String.IsNullOrEmpty(cryptedString))
{
throw new ArgumentNullException
("The string which needs to be decrypted can not be null.");
} var bytes = Encoding.UTF8.GetBytes(key);
DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider()
{
Mode = CipherMode.ECB,
Padding = PaddingMode.None
};
MemoryStream memoryStream = new MemoryStream
(Convert.FromBase64String(cryptedString));
CryptoStream cryptoStream = new CryptoStream(memoryStream,
cryptoProvider.CreateDecryptor(bytes, bytes), CryptoStreamMode.Read);
StreamReader reader = new StreamReader(cryptoStream);
return reader.ReadToEnd().Trim();
}
大功告成,Over,就是这么简单,解密时通过Tirm()方法去除空字符串即可。
解析XML文件
解析XML文件本没有任何问题,这是老生常谈的问题了,但是还是会遇到没碰到的问题,作此记录,请往下看,先声明一个类:
public class Blog
{
public string Name { get; set; }
}
序列化和反序列化诺:
public static string Serializer(Type type, object obj)
{
MemoryStream Stream = new MemoryStream();
XmlSerializer xml = new XmlSerializer(type);
xml.Serialize(Stream, obj);
Stream.Position = ;
StreamReader sr = new StreamReader(Stream);
string str = sr.ReadToEnd(); sr.Dispose();
Stream.Dispose(); return str;
}
public static object Deserialize(Type type, string xml)
{
using (StringReader sr = new StringReader(xml))
{
XmlSerializer xmldes = new XmlSerializer(type);
return xmldes.Deserialize(sr);
}
}
没毛病,再看,上述Blog再添加一个属性并实例化Url:
public string Url { get; set; }
var blog = new Blog()
{
Name = "Jeffcky",
Url = "https://i.cnblogs.com/EditPosts.aspx?postid=7295879&update=1"
};
想说明的是Url序列化成了如下情况:
<?xml version="1.0"?>
<Blog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Jeffcky</Name>
<Url>https://i.cnblogs.com/EditPosts.aspx?postid=7295879&update=1</Url>
</Blog>
&变成了&,想必这是XML序列化的规则对有些特殊字符进行了处理。但是在调用Java接口反序列化时对于上述&却没进行翻译,报错如下,纳闷:
The reference to entity "characterEncoding" must end with the ';' delimiter
此时需要将&替换为&同样对于>或者<亦是如此。
var data = data.Replace("&", "&");
请求Java中SOAP接口
由于未接触过WebService和Soap,在请求Java上的Soap接口时需要在请求头中添加 SOAPAction ,当然在C#中的Soap请求也可能要加上如下请求头。如下:
using (var httpClient = new HttpClient(handler))
{
var httpContent = new StringContent(“xml”, Encoding.UTF8, "text/xml");
httpContent.Headers.Add("SOAPAction", “action”);
response = await httpClient.PostAsync("url", httpContent);
}
总结
对于上述遇到的问题想必有些读者门已经遇见过了,不喜勿喷。对于解析Java中的加密数据过程可见,何必有语言之争,多懂一门语言终归是好的,都是为了更好的发展不是,相煎何太急了,以上所有以此作为备忘录,现在想来对接真不是想象的那么简单啊,程序员都认为自己写的代码没有任何问题,有时候还是好生交流才是上策啊,首先怀疑是不是自身这边是不是出了问题再言其他,而非一棒子直接打死是对方的问题。see u。
对接第三方平台JAVA接口问题推送和解决的更多相关文章
- 关于调用三方平台接口与推送接口的总结<二>(2020.7.27)
前言:本篇博客是接着上篇总结写的,想了解怎么对接第三方平台接口的同学可以看我上一篇博客,地址是 https://www.cnblogs.com/alanturingson/p/13377500.ht ...
- Java使用HTTPClient3.0.1开发的公众平台消息模板的推送功能
package com.company.product.manager.busniess.impl; import java.io.IOException;import java.nio.charse ...
- 在Unity3D中实现安卓平台的本地通知推送
[前言] 对于手游来说,什么时候需要推送呢?玩过一些带体力限制的游戏就会发现,我的体力在恢复满后,手机会收到一个通知告诉我体力已完全恢复了.这类通知通常是由本地的客户端发起的,没有经过服务端. 在安卓 ...
- Java整合极光推送 ( 简单 )
Java 整合极光推送官方文档:https://github.com/jpush/jpush-api-java-client 这里记录一下简单的使用步骤:创建一个普通的 Maven 工程然后添加依赖 ...
- C#微信接口之推送模板消息功能示例
本文实例讲述了C#微信接口之推送模板消息功能.分享给大家供大家参考,具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2 ...
- ZH奶酪:基于ionic.io平台的ionic消息推送功能实现
Hybrid App越来越火,Ionic的框架也逐渐被更多的人熟知. 在mobile app中,消息推送是很必要的一个功能. 国内很多ionic应用的推送都是用的极光推送,最近研究了一下Ionic自己 ...
- .atitit.web 推送实现解决方式集合(3)----dwr3 Reverse Ajax
.atitit.web 推送实现解决方式集合(3)----dwr3 Reverse Ajax 1. 原理实现 1 2. Page 添加配置.添加回调函数dwr.engine.setActiveRev ...
- 微信公众平台设置URL和Token接收接口事件推送
最近做对接微信闪开发票-微信发票名片,里面有个接收用户提交抬头接口是微信推送事件到公众号后台,该事件将发送至开发者填写的URL(登录公众平台进入[开发者中心设置]). 开发者可通过事件推送完成数据统计 ...
- Java对接微信公众号模板消息推送
内容有点多,请耐心! 最近公司的有这个业务需求,又很凑巧让我来完成: 首先想要对接,先要一个公众号,再就是开发文档了:https://developers.weixin.qq.com/doc/offi ...
随机推荐
- CSS学习笔记10 相对定位,绝对定位与固定定位
文档流中的元素的位置由元素在 (X)HTML 中的位置决定,这就是最原始的普通流,前面讲到的浮动CSS学习笔记08 浮动可以改变元素在文档流中的位置,除了这个我们还可以通过使用CSS的position ...
- 如何让局域网内的其他电脑访问本机的mysql
测试电脑:本机ip是125.216.250.67 其他电脑 125.216.250.68 第一步:先用其他电脑ping本机,看能否ping通 如上图即为成功ping通了 第二步:开放mysql的全向 ...
- Backbone中父子view之间的值传递
backbone中,使用最多的莫过于在view中进行操作,如模板的渲染以及事件函数的定义.为了提高代码的可维护性,一般地我们会写多个视图即view,将界面按照功能的不同进行模块化划分,模块与view一 ...
- axis1.4开发webservice客户端(快速入门)-基于jdk1.4
写在前面: 对于客户端,服务端开发好了以后,客户端只需要调用就可以了.这里我们讲的是,根据服务的访问地址,来生成客户端所需要用到的代码(听说有几种调用方式,但是用到最常见的就是stub方式,貌似我说的 ...
- ASP.NET MVC Autofac依赖注入的一点小心得(包含特性注入)
前言 IOC的重要性 大家都清楚..便利也都知道..新的ASP.NET Core也大量使用了这种手法.. 一直憋着没写ASP.NET Core的文章..还是怕误导大家.. 今天这篇也不是讲Core的 ...
- acm->stl
容器 queue 队列 定义 queue的定义需要两个参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque类型 基本方法 push(x) 入队,将x接到队列的末端 ...
- JavaScript 的 作用域
在看了几本书之后的一些理解和自己的想法. 作用域,变量的作用范围 在ES6之前 变量的声明 只有var可以声明变量属于某个作用域,并且,也只有全局作用域和函数作用域. (没有var声明的变 ...
- 【PHP】PHP面向对象编程--phpOOP入门
PHP从入门到精通 之PHP的面相对象编程 面向对象编程(Object Oriented Programming, OOP, 面向对象程序设计)是一种计算机编程架构,OOP的一条基本原则是计算机程序 ...
- Hadoop的介绍、搭建、环境
HADOOP背景介绍 1.1Hadoop产生背景 HADOOP最早起源于Nutch.Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取.索引.查询等功能,但随着抓取网页数量的增加,遇到了严 ...
- zookeeper的集群介绍、搭建、环境、安装
zookeeper是本身是一种分布式协调服务(英文意思动物园园长因为Hadoop就是一个动物园,storm.hadoop.kafkaka.hbaser都是基于zookeeper开发的) 原理:Zook ...