zoukankan      html  css  js  c++  java
  • 是时候给你的微信公众号请一位专属客服了

    1.为什么要写这篇文章?

    一是因为经常逛知乎,发现好些知乎大神的签名上都放的自己的微信公众号,但是关注之后就回一句简单的谢谢关注之类的话,缺乏互动性。二来是之前网盘共享了一堆本科生的毕设,为了防止别有用心的人拿去卖,加了密码,想要获取密码的话得加我微信验证。最近好多人都来加微信求密码,实在忙不过来,于是就想到了搞一个微信公众号的聊天机器人。于是乎借着周末的时间搞了一个能自动回复密码的机器人儿,但是后来发现这个机器人还可以做得更好,比如有粉丝不问密码的时候还可以聊点别的。网上搜了一下,看到一款机器人叫“图灵机器人”,首先图灵这个名字就很喜欢啊,其次它还提供API,正是我想要的。

    2.怎么搞?

    这里分两种情况,因为世界上有两种人啊,一种程序猿,一种普通人(简称麻瓜)。
    2.1 for麻瓜
    打开http://www.tuling123.com/ 注册->登录->个人中心->我的机器人-创建机器人,然后下拉看到微信接入,点击“+微信公众号”,然后根据提示一步步操作,最后就好了。是不是很简单?效果如下图
    效果

    2.2 for程序猿
    对于傲娇的程序猿来说,我们才不屑于这种傻瓜式的接入方式,还好图灵机器人提供了API接口可以拯救一下程序猿们。看下图是不是很亲切?
    apikey
    下面就来详细说一下如何接入。
    (1)你得有一台主机,一个域名。没有的话蹭一下你身边的基友的吧!
    (2)微信开发者配置。
    weixin
    微信会首先验证你的服务器和域名,所以这里需要填上你的接口地址(注意:不是域名,是接口地址)
    这个接口应该由一个web服务提供,下面给出我用java实现的版本:

    java    73行

    @Controller
    @RequestMapping("/msg")
    public class WxMessageController extends WxBaseController{
    	
    	private static String TOKEN = "token123";
    	@Autowired
    	private WxPaperPwdService wxPaperPwdService;
    	
    	@Autowired
    	private WxTuringService wxTuringService;
    
    	@RequestMapping(value="home",method={RequestMethod.GET,RequestMethod.POST})
    	@ResponseBody
    	public void home(HttpServletRequest req,HttpServletResponse res){
    		//get为请求验证,post为消息
    		boolean isGet = req.getMethod().toLowerCase().equals("get");
    		if(isGet){
    			log.info("info:check url");
    			checkUrl(req,res);
    		}else {
    			log.info("info:received message");
    			try {
    				chat(req,res);
    			} catch (IOException e) {
    				log.error("error:"+e.getMessage());
    			}
    		}
    	}
    	
    	private void checkUrl(HttpServletRequest req,HttpServletResponse res){
    		String signature = req.getParameter("signature");
    		String timestamp = req.getParameter("timestamp");// 时间戳  
    	    String nonce = req.getParameter("nonce");// 随机数  
    	    String echostr = req.getParameter("echostr");// 随机字符串  
    	    
    	    List<String> params = new ArrayList<String>();  
            params.add(TOKEN);  
            params.add(timestamp);  
            params.add(nonce);  
            Collections.sort(params, new Comparator<String>() {  
                public int compare(String o1, String o2) {  
                    return o1.compareTo(o2);  
                }  
            });  
            
            String temp = SecurityUtils.SHA1Encode(params.get(0) + params.get(1) + params.get(2));  
            if (temp.equals(signature)) {  
                try {  
                    res.getWriter().write(echostr);  
                    log.info("info:pass,hashcode is "+temp); 
                } catch (Exception e) {  
                    log.error("error:check error" + e.getMessage());
                }  
            }  
    	}
    	
    	private void chat(HttpServletRequest req,HttpServletResponse res) throws IOException{
    		WxMessage message = new WxMessage();
    		Map<String,String> msgMap =message.xmlToMap(req);
    		if("text".equals(msgMap.get("MsgType"))){
    			String content = msgMap.get("Content");
    			//获取密码服务
    			if(WxConstant.SERVNAME_PAPERPWD.equals(WxRules.getRule(content))){
    				log.info("paper password service");
    				wxPaperPwdService.getPwd(msgMap, res);
    			}else{
    				log.info("turing machine service");
    				wxTuringService.turingChat(msgMap, res);
    			}
    		}
    	}
    }
    

    微信做接口验证的时候走的是get方式,接收微信消息的时候走的是post方式,所以会根据不同的请求方式判断是验证还是聊天。同时附上一个加密用的工具类。

    java    66行

    public class SecurityUtils {
    
    	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };  
    	 
    	/**
    	 * sha1加密
    	 * @param str
    	 * @return
    	 */
    	public static String SHA1Encode(String str){
    		 if (str == null) {  
    	            return null;  
    	        }  
    	        try {  
    	            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");  
    	            messageDigest.update(str.getBytes());  
    	            return getFormattedText(messageDigest.digest());  
    	        } catch (Exception e) {  
    	            throw new RuntimeException(e);  
    	        }  
    	}
    	
    	private static String getFormattedText(byte[] bytes) {  
            int len = bytes.length;  
            StringBuilder buf = new StringBuilder(len * 2);  
            // 把密文转换成十六进制的字符串形式  
            for (int j = 0; j < len; j++) {  
                buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);  
                buf.append(HEX_DIGITS[bytes[j] & 0x0f]);  
            }  
            return buf.toString();  
        }  
    	
    	/**
    	 * Md5加密
    	 * @param s
    	 * @return
    	 */
    	public static String MD5(String s) {
    		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    				'a', 'b', 'c', 'd', 'e', 'f' };
    		try {
    			byte[] btInput = s.getBytes("utf-8");
    			// 获得MD5摘要算法的 MessageDigest 对象
    			MessageDigest mdInst = MessageDigest.getInstance("MD5");
    			// 使用指定的字节更新摘要
    			mdInst.update(btInput);
    			// 获得密文
    			byte[] md = mdInst.digest();
    			// 把密文转换成十六进制的字符串形式
    			int j = md.length;
    			char str[] = new char[j * 2];
    			int k = 0;
    			for (int i = 0; i < j; i++) {
    				byte byte0 = md[i];
    				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
    				str[k++] = hexDigits[byte0 & 0xf];
    			}
    			return new String(str);
    		} catch (Exception e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    }
    

    有了上面两端咒文,接口验证应该是没有问题了。当然这个代码你直接粘贴过去肯定是跑不起来,别担心我的整个工程一直在完善中,文末放我的联系方式,你可以通过我的联系方式获取完整的工程代码。
    (3)接入图灵机器人API
    加入你上面的配置没问题了,可以看下面如何接入图灵机器人的API。有点开发经验的都知道如何调用API吧,下面我就简单贴一下代码。还是那句话这些代码直接粘贴过去跑不起来,完整代码请看文末联系方式,找我。代码免费赠送。

    java    31行

    public class TuringApiUtils {
    
    	private static final String API_URL = "http://www.tuling123.com/openapi/api";
    	private static final String API_KEY = "";
    	private static final String SECRET = "";
    	
    	public static JSONObject post(Map<String,String> msgMap) throws ClientProtocolException, IOException{
    		String content = msgMap.get("Content");
    		String wxid = msgMap.get("FromUserName");
    		JSONObject data = new JSONObject();
    		data.put("key", API_KEY);
    		data.put("info", content);
    		data.put("userid", wxid);
    		
    		String timestamp = String.valueOf(System.currentTimeMillis());
    		String keyParam = SECRET+timestamp+API_KEY;
    		String key = SecurityUtils.MD5(keyParam);
    		Aes mc = new Aes(key);
    		String datas = mc.encrypt(data.toJSONString());
    		
    		JSONObject json = new JSONObject();
    		json.put("key", API_KEY);
    		json.put("timestamp", timestamp);
    		json.put("data", datas);
    		JSONObject res = (JSONObject) JSONObject.parse(PostServer.SendPost(json.toJSONString(), API_URL));
    		
    		return res;
    		
    	}
    }
    

    java    59行

    public class PostServer {
    	
    	/**
    	 * 向后台发送post请求
    	 * @param param
    	 * @param url
    	 * @return
    	 */
    	public static String SendPost(String param, String url) {
    		OutputStreamWriter out = null;
    		BufferedReader in = null;
    		String result = "";
    		try {
    			URL realUrl = new URL(url);
    			HttpURLConnection conn = (HttpURLConnection) realUrl
    					.openConnection();
    			conn.setDoOutput(true);
    			conn.setDoInput(true);
    			conn.setUseCaches(false);
    			conn.setRequestMethod("POST");
    			conn.setConnectTimeout(50000);
    			conn.setReadTimeout(50000);
    			conn.setRequestProperty("Content-Type", "application/json");
    			conn.setRequestProperty("Accept", "application/json");
    			conn.setRequestProperty("Authorization", "token");
    			conn.setRequestProperty("tag", "htc_new");
    
    			conn.connect();
    
    			out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
    			out.write(param);
    
    			out.flush();
    			out.close();
    			//
    			in = new BufferedReader(new InputStreamReader(
    					conn.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;
    	}
    }
    

    java    66行

    public class Aes {
    	
    	private Key key;
    	/**
    	 * AES CBC模式使用的Initialization Vector
    	 */
    	private IvParameterSpec iv;
    	/**
    	 * Cipher 物件
    	 */
    	private Cipher cipher;
    
    	/**
    	 * 构造方法
    	 * @param strKet 
    	 * 		密钥
    	 */
    	public Aes(String strKey) {
    		try {
    			this.key = new SecretKeySpec(getHash("MD5", strKey), "AES");
    			this.iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0,
    					0, 0, 0, 0, 0, 0, 0, 0 });
    			this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    		} catch (final Exception ex) {
    			throw new RuntimeException(ex.getMessage());
    		}
    	}
    	
    	/**
    	 * 加密方法
    	 * 
    	 * 说明:采用128位
    	 * 
    	 * @return 加密结果
    	 */
    	public String encrypt(String strContent) {
    		try {
    			byte[] data = strContent.getBytes("UTF-8");
    			cipher.init(Cipher.ENCRYPT_MODE, key, iv);
    			byte[] encryptData = cipher.doFinal(data);
    			String encryptResult = new String(Base64.encodeBase64(
    					encryptData), "UTF-8");
    			return encryptResult;
    		} catch (Exception ex) {
    			throw new RuntimeException(ex.getMessage());
    		}
    	}
    
    	/**
    	 * 
    	 * @param algorithm
    	 * @param text
    	 * @return
    	 */
    	private static byte[] getHash(String algorithm, String text) {
    		try {
    			byte[] bytes = text.getBytes("UTF-8");
    			final MessageDigest digest = MessageDigest.getInstance(algorithm);
    			digest.update(bytes);
    			return digest.digest();
    		} catch (final Exception ex) {
    			throw new RuntimeException(ex.getMessage());
    		}
    	}
    }
    

    上面的代码做的事情很简单,就是请求接口获取返回值。目前我的代码只是完成了获取返回的文本类和链接类数据,而且代码写的比较乱,没脸贴完整的[捂脸],下面是部分效果截图:
    效果
    如果你感兴趣,请把玩我的公众号,或者像我索取完整代码。附公众号二维码一枚:
    wx

  • 相关阅读:
    Win10 Tensorflow 配置Mask_RCNN
    Tensorflow学习(练习)—使用inception做图像识别
    Tensorflow学习(练习)—下载骨骼图像识别网络inception数据集
    Tensorflow递归神经网络学习练习
    Tensorflow学习练习-卷积神经网络应用于手写数字数据集训练
    Tensorflow 优化学习
    Tensorflow学习—— AdamOptimizer
    Tensorflow练习
    Tensorflow手写数字识别(交叉熵)练习
    Tensorflow手写数字识别训练(梯度下降法)
  • 原文地址:https://www.cnblogs.com/bigdataer/p/6511990.html
Copyright © 2011-2022 走看看