总想自己动动手系列·1·本地和外网(Liunx服务器上部署的web项目)按照自定义的报文格式进行交互(准备篇)
一、准备工作
(1)有一台属于自己的云服务器,并成功部署和发布一个web项目(当然,本质上来说Java-Project也没问题),通过外网IP可以正常访问该web项目。
需要说明的是:任何web项目,只要成功部署后在外网上能访问到即可。本案例注重修改web对请求的监听和过滤的处理(下个版本在弄这个啦!)。
(2)本地新建Java-project,需要准备一些jar包,比如:AES加密相关的包,BASE64加相关的包,解析XML的包,至于通信相关的类,JDK的java.io和java.net自带。
二、Code部分
(1)第一步:首先创建一个接口,先定义好规则(比如:需要用到哪些方法等)
1 package com.xfwl.message.serverMsg; 2 3 import java.net.URL; 4 import java.net.URLConnection; 5 import java.util.Map; 6 7 /** 8 * 通讯类接口 9 * @function 10 * @author 小风微凉 11 * @time 2018-11-8 下午2:03:39 12 */ 13 public interface IHttpClient { 14 /** 15 * 默认编码格式 16 */ 17 static final String CHARTER_ENCODE="UTF-8"; 18 //创建报文发送对象 19 public URLConnection getClient(String url); 20 //创建发送报文方法 21 public boolean sendDataMsg(URLConnection url,String encygen); 22 //创建接收报文方法 23 public StringBuffer receiveDataMsg(URLConnection url,String encygen); 24 //创建报文加密方法 25 public StringBuffer encryptMsg(String data,String encygen); 26 //创建报文解密方法 27 public StringBuffer deCioherMsg(String data,String encygen); 28 }
(2)第二步:准备要用到的工具类,比如报文的加密、解密等,下面用到的时AES加密(加解密时都需要加密因子,中间使用了Base64改变编码格式)
1 package com.xfwl.message.serverMsg; 2 3 import java.security.NoSuchAlgorithmException; 4 import java.security.SecureRandom; 5 import java.util.logging.Level; 6 import java.util.logging.Logger; 7 8 import javax.crypto.Cipher; 9 import javax.crypto.KeyGenerator; 10 import javax.crypto.SecretKey; 11 import javax.crypto.spec.SecretKeySpec; 12 import org.apache.commons.codec.binary.Base64; 13 /** 14 * AES加密、解密处理工具(加密因子+base64的加解密) 15 * @function 16 * @author 小风微凉 17 * @time 2018-11-8 下午2:35:15 18 */ 19 public class AESUtil { 20 //默认加密秘钥 21 private static final String KEY_ALGORITHM = "AES"; 22 //默认的加密算法 23 private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; 24 /** 25 * AES 加密操作 26 * 27 * @param content 待加密内容 28 * @param password 加密密码 29 * @return 返回Base64转码后的加密数据 30 */ 31 public static String encrypt(String content, String password) { 32 try { 33 Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器 34 35 byte[] byteContent = content.getBytes("utf-8"); 36 37 cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器 38 39 byte[] result = cipher.doFinal(byteContent);// 加密 40 41 return Base64.encodeBase64String(result);//通过Base64转码返回 42 } catch (Exception ex) { 43 Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 44 } 45 46 return null; 47 } 48 49 /** 50 * AES 解密操作 51 * 52 * @param content 数据 53 * @param password 加密因子 54 * @return 55 */ 56 public static String decrypt(String content, String password) { 57 try { 58 //实例化 59 Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); 60 61 //使用密钥初始化,设置为解密模式 62 cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password)); 63 64 //执行操作 65 byte[] result = cipher.doFinal(Base64.decodeBase64(content)); 66 67 return new String(result, "utf-8"); 68 } catch (Exception ex) { 69 Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 70 } 71 72 return null; 73 } 74 75 /** 76 * 生成加密秘钥 77 * @param password 加密因子 78 * @return 79 */ 80 private static SecretKeySpec getSecretKey(final String password) { 81 //返回生成指定算法密钥生成器的 KeyGenerator 对象 82 KeyGenerator kg = null; 83 try { 84 kg = KeyGenerator.getInstance(KEY_ALGORITHM); 85 //AES 要求密钥长度为 128 86 kg.init(128, new SecureRandom(password.getBytes())); 87 //生成一个密钥 88 SecretKey secretKey = kg.generateKey(); 89 90 return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为AES专用密钥 91 } catch (NoSuchAlgorithmException ex) { 92 Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex); 93 } 94 return null; 95 } 96 /** 97 * 测试 98 * @param args 99 */ 100 public static void main(String[] args) { 101 String s = "hello,xfwl"; 102 System.out.println("明文(加密前):" + s); 103 //加密 104 String s1 = AESUtil.encrypt(s, "xfwl"); 105 System.out.println("加密后:" + s1); 106 //解密 107 System.out.println("解密后:"+AESUtil.decrypt(s1, "xfwl")); 108 } 109 }
(3)第三步:开始实现步骤一中定义的规则
1 package com.xfwl.message.serverMsg; 2 3 import java.io.BufferedOutputStream; 4 import java.io.BufferedReader; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.io.InputStreamReader; 8 import java.io.OutputStream; 9 import java.io.OutputStreamWriter; 10 import java.net.MalformedURLException; 11 import java.net.URL; 12 import java.net.URLConnection; 13 import java.util.HashMap; 14 import java.util.Iterator; 15 import java.util.List; 16 import java.util.Map; 17 import java.util.Set; 18 import java.util.Map.Entry; 19 20 import org.dom4j.Attribute; 21 import org.dom4j.Document; 22 import org.dom4j.DocumentException; 23 import org.dom4j.DocumentHelper; 24 import org.dom4j.Element; 25 26 public class HTTPServerClient implements IHttpClient { 27 /** 28 * 报文上送数据集合 29 */ 30 private Map<String,Object> sendMap=null; 31 /** 32 * 构造器 33 */ 34 public HTTPServerClient(Map<String,Object> sendMap){ 35 this.sendMap=sendMap; 36 } 37 /** 38 * 获取连接对象 39 */ 40 public URLConnection getClient(String url) { 41 URL u=null; 42 try { 43 u= new URL(url); 44 } catch (MalformedURLException e) { 45 e.printStackTrace(); 46 } 47 System.out.println("建立["+url+"]链接...."); 48 //获取连接对象 49 URLConnection uc=null; 50 try { 51 uc = u.openConnection(); 52 } catch (IOException e) { 53 e.printStackTrace(); 54 } 55 return uc; 56 } 57 /** 58 * 发送报文 59 */ 60 public boolean sendDataMsg(URLConnection uc,String encygen) { 61 //打开输出流 62 uc.setDoOutput(true); 63 //获取输出流对象 64 OutputStream raw=null; 65 OutputStream buffered = null; 66 OutputStreamWriter out=null; 67 try { 68 raw = uc.getOutputStream(); 69 buffered = new BufferedOutputStream(raw); 70 out = new OutputStreamWriter(buffered, CHARTER_ENCODE); 71 StringBuffer data=createMsgFormat(sendMap); 72 System.out.println("发送报文[明文]:"+data); 73 out.write(encryptMsg(data.toString(),encygen).toString()); 74 System.out.println("发送报文[密文]:"+encryptMsg(data.toString(),encygen).toString()); 75 out.flush(); 76 System.out.println("关闭连接"); 77 out.close(); 78 } catch (IOException e) { 79 e.printStackTrace(); 80 return false; 81 } 82 return true; 83 } 84 /** 85 * 接收报文 86 */ 87 public StringBuffer receiveDataMsg(URLConnection uc,String deciogen) { 88 //获取到返回数据的输入流 89 InputStream is=null; 90 BufferedReader br=null; 91 StringBuffer blzRspXml = new StringBuffer(); 92 try { 93 is = uc.getInputStream(); 94 br = new BufferedReader(new InputStreamReader(is,CHARTER_ENCODE)); 95 String line = ""; 96 System.out.println("获取返回数据:"); 97 while((line = br.readLine()) != null){ 98 //读取返回数据,分行读取 99 //System.out.println(deCioherMsg(line.trim(),deciogen));//解密 100 System.out.println(line.trim()); 101 blzRspXml.append(line.trim()); 102 } 103 } catch (IOException e) { 104 e.printStackTrace(); 105 } 106 return blzRspXml; 107 } 108 /** 109 * 加密数据 110 */ 111 public StringBuffer encryptMsg(String data,String encygen) { 112 return new StringBuffer(AESUtil.encrypt(data, encygen)); 113 } 114 /** 115 * 解析数据 116 */ 117 public StringBuffer deCioherMsg(String data,String deciogen) { 118 return new StringBuffer(AESUtil.decrypt(data, deciogen)); 119 } 120 121 /** 122 * 生成送报文: 123 * 上送报文和响应报文都需要约定一种报文格式 124 */ 125 private StringBuffer createMsgFormat(Map<String,Object> dataMap){ 126 StringBuffer msg=new StringBuffer(); 127 msg.append("<service>"); 128 /*msg.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");*/ 129 msg.append("<SYS_HEAD>"); 130 //存放:业务类型码 131 msg.append("<HEAD_BSNCODE>100001</HEAD_BSNCODE>"); 132 msg.append("</SYS_HEAD>"); 133 msg.append("<BODY>"); 134 //存放:业务数据 135 Set<Entry<String, Object>> set = dataMap.entrySet(); 136 Iterator<Entry<String, Object>> it = set.iterator(); 137 while (it.hasNext()) { 138 Entry<String, Object> ey = it.next(); 139 String key = ey.getKey(); 140 String value = (String) ey.getValue(); 141 msg.append("<"+key+">"+value+"</"+key+">"); 142 } 143 msg.append("</BODY>"); 144 msg.append("</service>"); 145 return msg; 146 } 147 /** 148 * 解析响应报文:通过dom4j解析xml字符串 149 * @param args 150 */ 151 public Map<String,Object> parseRecMsgFormat(String xml){ 152 Map<String,Object> recMap =new HashMap<String, Object>(); 153 Document doc=null; 154 Element root=null; 155 List<Element> elems=null; 156 List<Element> elems_head=null; 157 List<Element> elems_body=null; 158 try { 159 doc=DocumentHelper.parseText(xml); 160 root=doc.getRootElement(); 161 elems=root.elements(); 162 for(Element elem:elems){ 163 //开始解析结点 164 if("SYS_HEAD".equals(elem.getName())){ 165 //检查报文头 166 elems_head=elem.elements(); 167 for(Element head:elems_head){ 168 if("HEAD_BSNCODE".equals(head.getName())){ 169 recMap.put("HEAD_BSNCODE", head.getText()); 170 } 171 } 172 }else if("BODY".equals(elem.getName())){ 173 //检查报文体 174 elems_body=elem.elements(); 175 for(Element body:elems_body){ 176 recMap.put(body.getName(), body.getText()); 177 } 178 } 179 /*List<Attribute> attrs=elem.attributes(); 180 for(Attribute attr:attrs){ 181 //开始解析结点的属性 182 if("HEAD_BSNCODE".equals(attr.getText())){ 183 System.out.println(elem.getName()+":"+elem.getText()); 184 } 185 }*/ 186 } 187 } catch (DocumentException e) { 188 e.printStackTrace(); 189 } 190 return recMap; 191 } 192 public static void main(String[] args) { 193 Map<String,Object> sendMap =new HashMap<String, Object>(); 194 sendMap.put("ADMIN", "小风微灵"); 195 sendMap.put("PWD", "xfwl123"); 196 //System.out.println(createMsgFormat(sendMap)); 197 } 198 }
(4)第四步:开始测试一下
1 package com.xfwl.message.test; 2 3 import java.net.URLConnection; 4 import java.util.HashMap; 5 import java.util.Map; 6 7 import com.xfwl.message.serverMsg.HTTPServerClient; 8 9 public class TestAction3 { 10 public static void main(String[] args) { 11 Map<String,Object> sendMap =new HashMap<String, Object>(); 12 sendMap.put("ADMIN", "小风微灵"); 13 sendMap.put("PWD", "xfwl123"); 14 15 HTTPServerClient client=new HTTPServerClient(sendMap); 16 URLConnection uc=client.getClient("http://47.105.58.153:3000"); 17 client.sendDataMsg(uc,"lvjun"); 18 client.receiveDataMsg(uc,"lvjun"); 19 } 20 }
看一下测试结果:
1 建立[http://47.105.58.153:3000]链接.... 2 发送报文[明文]:<service><?xml version="1.0" encoding="UTF-8"?><SYS_HEAD><HEAD_BSNCODE>100001</HEAD_BSNCODE></SYS_HEAD><BODY><ADMIN>小风微灵</ADMIN><PWD>xfwl123</PWD></BODY></service> 3 发送报文[密文]:UCr7pP6rDXPVlZzhcTRD20JHzoQSI7/Tb82YL6m6O25tD37RE6lW062yoRvdAv4eWxKWT2shrt97 4 t2ZN+kjNVqkhLRaEw96yr1arAWtxri0pX0W3LYXw0Gw4LoTWsPb09a0JRv5p35Dt0QICN/Ve0+mP 5 ayN+jCSFE3DKk5xusgSzua3adfnEdELhxbR33+CL09yI+Rc8In2NjYrsg24kkM29dJaWSRGm+ahn 6 26OUQnI= 7 8 关闭连接 9 获取返回数据: 10 {"status":"1","msg":"未登录!","result":""}
三、接下来准备要做的事情
从上面的测试结果来看,已经成功完成了第一步,即将本地的请求(用自定义的报文格式处理请求数据)发送到云服务器上部署的web工程服务上,接下来要做的就是在web工程上动手,监听这类请求,根据约定的加密因子和
报文规则,解密和解析析xml报文,获取其中的请求数据,经行业务逻辑处理后按照约定的加密方式和报文规则,生成对应的响应报文,返回给本地的Java-Project,本地Java-Project再解密解析响应报文,获取响应数据,从而经行本
地的业务逻辑处理。
一步步来吧,只要脚步不停下,就是在进步......
研究技术需要静下心来,一点一点地深究.......