zoukankan      html  css  js  c++  java
  • 微信公众号02 接收文本消息、回复文本消息、接入百度翻译功能

    1 说明

      本篇博文承接上一篇博文:https://www.cnblogs.com/NeverCtrl-C/p/10241763.html

    2 接收文本消息

      微信公众号官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453

      说明:接收文本消息属于接收普通消息的范围,当公众号粉丝向公众号发送消息时,微信服务器会向开发者服务器发送一个POST请求,这个POST请求携带XML格式的数据包到开发者填写的URL上

    2.1 文本消息XML格式

    <xml>
        <ToUserName>< ![CDATA[toUser] ]></ToUserName>
        <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
        <CreateTime>1348831860</CreateTime>
        <MsgType>< ![CDATA[text] ]></MsgType>
        <Content>< ![CDATA[this is a test] ]></Content>
        <MsgId>1234567890123456</MsgId>
    </xml>

    2.2 文本消息参数说明

    参数描述
    ToUserName 开发者微信号
    FromUserName 发送方帐号(一个OpenID)
    CreateTime 消息创建时间 (整型)
    MsgType text
    Content 文本消息内容
    MsgId 消息id,64位整型


    step01 创建一个com.xunyji.xunyjitest.comm.TransformUtils类用来存放一下数据类型转换相关的工具方法
    2.3 Java代码实现

    step02 引入XML和对象相互转换相关的jar包

            <!--xml2对象 start-->
            <!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
            <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
            </dependency>
            <!--xml2对象 end-->
    
            <!--对象2XML start-->
            <!-- https://mvnrepository.com/artifact/com.thoughtworks.xstream/xstream -->
            <dependency>
                <groupId>com.thoughtworks.xstream</groupId>
                <artifactId>xstream</artifactId>
                <version>1.3.1</version>
            </dependency>
            <!--对象2XML end-->

    step03 创建com.xunyji.xunyjitest.comm.TransformUtils#xml2Map方法用于将XML转化成Map类型

        /**
         * xml转换成map【微信平台请求开发者平台时的数据格式都是XML格式的】
         * @param request
         * @return
         * @throws IOException
         * @throws DocumentException
         */
        public static Map<String, String> xml2Map(HttpServletRequest request) throws IOException, DocumentException {
    //        01 定义Map对象用来存放数据
            Map<String, String> map = new HashMap<>();
    
    //        02 创建SAXReader用于读取xml文件
            SAXReader reader = new SAXReader();
    
    //        03 读取Request中的信息
            InputStream ins = request.getInputStream();
            Document doc = reader.read(ins);
    
    //        04 获取xml的根元素
            Element root = doc.getRootElement();
    
    //        05 获取根元素中的所有子元素
            List<Element> list = root.elements();
    
    //        06 遍历所有子元素并将数据存放到定义好的集合中
            for (Element e : list) {
                map.put(e.getName(), e.getText());
            }
    
    //        07 关闭输入流
            ins.close();
    
    //        08 返回存放xml内容的Map对象
            return map;
        }

    step04 创建一个com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法用于接收微信平台发送的POST请求

      step0401 该方法接收POST请求

      step0402 通过 HttpServletRequest 对象获取微信平台传过来的XML数据包

      step0403 将XML数据转化成Map数据并打印输出

        @PostMapping
        public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {
    //        01 请求、响应编码格式设定
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
    
    //        02 获取输出对象
            PrintWriter out = response.getWriter();
    //        03 获取微信平台传过来的请求参数【PS:默认是XML格式的,这里转化成了Mapl类型】
            Map<String, String> receiveMap = TransformUtils.xml2Map(request);
            log.info("接收微信消息时获取到的信息为:" + receiveMap);
    
    //        04 从Map对象中获取单个数据
            String fromUserName = receiveMap.get("FromUserName");
            String toUserName = receiveMap.get("ToUserName");
            String msgType = receiveMap.get("MsgType");
            String content = receiveMap.get("Content");
    
        }

      step0404 启动项目并通过粉丝账户向公众号发送文本消息,效果如图所示

    3 回复文本消息

      回复文本消息属于被动回复消息的范围,微信官网提供的被动回复消息文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140543

      技巧01:粉丝向公众号发送消息时微信服务器会向开发者服务器发送一个POST请求,开发者可以从这个POST请求中获取到一些信息,也可以像发送者返回一些信息

    3.1 回复文本消息XML格式

    <xml>
        <ToUserName>< ![CDATA[toUser] ]></ToUserName>
        <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
        <CreateTime>12345678</CreateTime>
        <MsgType>< ![CDATA[text] ]></MsgType>
        <Content>< ![CDATA[你好] ]></Content>
    </xml>

    3.2 回复文本消息参数说明

    参数是否必须说明
    ToUserName 接收方帐号(收到的OpenID)
    FromUserName 开发者微信号
    CreateTime 消息创建时间 (整型)
    MsgType image
    MediaId 通过素材管理中的接口上传多媒体文件,得到的id。

    3.3 Java代码实现

    step01 创建一个com.xunyji.xunyjitest.model.weixin.send.SendBaseMessage类作为所有被动回复消息的基类

    step02 创建一个com.xunyji.xunyjitest.model.weixin.send.ReplyTextMessage类作为回复文本消息的实体类

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class ReplyTextMessage extends ReplyBaseMessage {
        /** 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示) */
        private String Content;
    }

    step03 创建一个com.xunyji.xunyjitest.comm.enums.weixin.MessageTypeEnum枚举类来存放各种消息类型

    @Getter
    public enum MessageTypeEnum {
        //    接收普通消息类型【0开头表示接收的消息类型】 start
        /** 被动回复文本消息 */
        RECEIVE_MESSAGE_TEXT(001, "text"),
        RECEIVE_MESSAGE_IMAGE(002, "image"),
        RECEIVE_MESSAGE_VOICE(003, "voice"),
        RECEIVE_MESSAGE_LOCATION(004, "location"),
        RECEIVE_MESSAGE_LINK(005, "link"),
        RECEIVE_MESSAGE_SHORTVIDEO(06, "shortvideo"),
        RECEIVE_MESSAGE_VIDEO(007, "video"),
    //    接收普通消息类型【0开头表示接收的消息类型】 end
        ;
        /** 消息类型编号 */
        private Integer code;
        /** 消息类型(和微信文档中保持一致) */
        private String type;
    
        MessageTypeEnum(Integer code, String type) {
            this.code = code;
            this.type = type;
        }
    }

    step04 创建一个com.xunyji.xunyjitest.comm.util.weixin.MessageUtils类作为各种消息封装类

      step0401 创建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#replyTextMessageToXml方法实现将ReplyTextMessage 转化成 XML

        /**
         * ReplyTextMessage 转化成 XML
         * @param replyTextMessage
         * @return
         */
        private String replyTextMessageToXml(ReplyTextMessage replyTextMessage) {
            XStream xStream = new XStream();
            xStream.alias("xml", replyTextMessage.getClass());
            return xStream.toXML(replyTextMessage);
        }

      step0402 创建com.xunyji.xunyjitest.comm.util.weixin.MessageUtils#initReplyTextMessage方法实现封装回复文本消息时所需的XML格式字符串

        /**
         * 封装XML格式的"发送文本消息"
         * @param fromUserName 粉丝appId
         * @param toUserName 公众号appId
         * @param content XML格式的字符串
         * @return
         */
        public String initReplyTextMessage(String fromUserName, String toUserName, String content) {
            ReplyTextMessage text = new ReplyTextMessage();
            text.setToUserName(fromUserName);
            text.setFromUserName(toUserName);
            text.setMsgType(MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType());
            long time = System.currentTimeMillis();
            text.setCreateTime(String.valueOf(time));
            text.setContent("逆向公众号发送了:" + content);
            return replyTextMessageToXml(text);
        }

    step05 重构com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法实现接收文本消息时回复文本消息,其他消息不做任何处理

      step0501 从封装了请求数据的map集合中获取公众号appid(toUserName)、粉丝appid(fromUserName)、接收消息类型(msgType)

      step0502 判断接收消息类型并做相应处理,此处以接收到的消息类型为文本消息为例

        如果是文本消息就获取文本内容,然后封装响应数据即可

      step0503 必须对响应数据进行非空处理,因为如果响应数据为null就会出现一个错误,很影响用户体验

        @PostMapping
        public void receiveMessage(HttpServletRequest request, HttpServletResponse response) throws IOException, DocumentException {
    //        01 请求、响应编码格式设定
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");
    
    //        02 获取输出对象
            PrintWriter out = response.getWriter();
    //        03 获取微信平台传过来的请求参数【PS:默认是XML格式的,这里转化成了Mapl类型】
            Map<String, String> receiveMap = TransformUtils.xml2Map(request);
            log.info("接收微信消息时获取到的信息为:" + receiveMap);
    
    //        04 从Map对象中获取单个数据
            String fromUserName = receiveMap.get("FromUserName");
            String toUserName = receiveMap.get("ToUserName");
            String msgType = receiveMap.get("MsgType");
    
    //        05 用于存放String类型的XML格式响应数据
            String message = null;
    //        06 如果接收的消息类型是text类型的处理逻辑
            if (MessageTypeEnum.RECEIVE_MESSAGE_TEXT.getType().equals(msgType)) {
                String content = receiveMap.get("Content");
                message = new MessageUtils().initReplyTextMessage(fromUserName, toUserName, content);
            }
    //        07 响应对象非空处理,如果返回null会报异常(影响用户体验)
            if (message == null) {
                message = "";
            }
    //        08 打印XML格式的响应消息
            log.info("被动回复消息的XML格式为:" + message);
    //        09 响应XML格式数据给微信服务器
            out.print(message);
    
        }
    View Code

     step06 启动项目并向公众号发送文本消息,效果如图所示

     

    3.4 代码重构

      应该根据不同的消息类型调用不同的服务层方法来实现业务逻辑,不应该将所有业务逻辑都放到controller层中

    step01 引入fastjson依赖,因为需要将Map转化成Bean

            <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.54</version>
            </dependency>

    step02 创建com.xunyji.xunyjitest.service.ReceiveMessageService接口用于定义处理各种接收到的消息

    step03 创建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl实现了实现处理各种接收到的消息

    step04 创建com.xunyji.xunyjitest.comm.TransformUtils#parseMap2Object方法用于将Map转化成Bean

        /**
         * Map类型转化成指定类型
         * @param paramMap 待转化的Map对象
         * @param clazz 目标类型的类类型
         * @param <T> 目标类型
         * @return
         */
        public static <T> T parseMap2Object(Map<String, String> paramMap, Class<T> clazz) {
            return JSONObject.parseObject(JSONObject.toJSONString(paramMap), clazz);
        }

    step05 创建com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl#textMessageHandler方法用于处理文本类型消息

        @Override
        public String textMessageHandler(Map<String, String> receiveParam) {
    //        01 用于存放封装好的回复文本消息的XML数据
            String message = null;
    //        02 将Map类型参数转化成ReceiveTextMessage类型
            ReceiveTextMessage receiveTextMessage = TransformUtils.parseMap2Object(receiveParam, ReceiveTextMessage.class);
            log.info("接收到的text消息请求参数为:" + receiveTextMessage);
    
    //        03 获取文本内容和双方信息
    //        0301 粉丝appId
            String fromUserName = receiveTextMessage.getFromUserName();
    //        0302 公众号appId
            String toUserName = receiveTextMessage.getToUserName();
    //        0303 接收到的文本内容
            String content = receiveTextMessage.getContent();
            content = content.trim();
    
    //        04 根据文本内容响应不同的数据 TODO: 应该将接收到的消息信息存储到数据库或者缓存中
            if ("1".equals(content)) {
                message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.firstMenu());
            } else if ("2".equals(content)) {
                message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.secondMenu());
            } else if ("?".equals(content) || "?".equals(content)) {
                message = messageUtils.initReplyTextMessage(fromUserName, toUserName, messageUtils.menuText());
            } else {
                message = messageUtils.initReplyTextMessage(fromUserName, toUserName, content);
            }
    
            return message;
        }
    View Code

    step06 在com.xunyji.xunyjitest.web.weixin.WeixinController#receiveMessage方法中,如果是文本消息类型就调用com.xunyji.xunyjitest.service.ReceiveMessageService#textMessageHandler实现业务处理

    step07 启动应用并以此发送 1、2、?、?,效果图如下:

     

    4 接入百度翻译功能

    4.1 百度翻译开放平台

      官网地址:http://api.fanyi.baidu.com/api/trans/product/index

      说明:进入到百度翻译平台官网过后需要注册一个开发者账号,注册的时候填入相关信息即可

    4.2 通用翻译API技术文档

      官网文档地址:http://api.fanyi.baidu.com/api/trans/product/apidoc

      技巧01:百度通用翻译API提供了URL,开发者只需要根据文档说明访问这个URL即可

    step01 通用翻译API的地址:http://api.fanyi.baidu.com/api/trans/vip/translate  或者  https://fanyi-api.baidu.com/api/trans/vip/translate

    step02 可以向两个url地址发送GET请求或者POST请求,但是必须携带如下参数(PS:是指请求参数,即url后面跟的那种参数)

      技巧01:为保证翻译质量,请将单次请求长度控制在 6000 bytes以内。(汉字约为2000个)

    字段名类型必填参数描述备注
    q TEXT Y 请求翻译query UTF-8编码
    from TEXT Y 翻译源语言 语言列表(可设置为auto)
    to TEXT Y 译文语言 语言列表(不可设置为auto)
    appid INT Y APP ID 可在管理控制台查看
    salt INT Y 随机数  
    sign TEXT Y 签名 appid+q+salt+密钥 的MD5值

    step03 签名生成规则

      step0301 将请求参数中的 APPID(appid), 翻译query(q, 注意为UTF-8编码), 随机数(salt), 以及平台分配的密钥(可在管理控制台查看)

    按照 appid+q+salt+密钥 的顺序拼接得到字符串1。

      step0302 对字符串1做md5,得到32位小写的sign(PS:签名是为了保证调用安全,使用MD5算法生成的一段字符串,生成的签名长度为 32位,签名中的英文字符均为小写格式)

    step04 注意事项

      step0401 请先将需要翻译的文本转换为UTF-8编码

      step0402 在发送HTTP请求之前需要对各字段做URL encode

      step0403 在生成签名拼接 appid+q+salt+密钥 字符串时,q不需要做URL encode,在生成签名之后,发送HTTP请求之前才需要对要发送的待翻译文本字段q做URL encode。

    step05 响应的JSON格式说明

    字段名类型描述
    from TEXT 翻译源语言
    to TEXT 译文语言
    trans_result MIXED LIST 翻译结果
    src TEXT 原文
    dst TEXT 译文

    4.3 官方Demo实现

    step01 官方demo下载地址:https://fanyiapp.cdn.bcebos.com/api/demo/java.zip ,官方demo文件说明如下图所示

    step02 将这个三个文件拷贝到项目中

    step03 测试官方提供的demo

    4.4 自定义翻译demo

      说明:百度翻译官方提供的demo中使用的是java提供的HttpURLConnection进行远程调用的,而我比较喜欢用RestTemplate实现第三方的服务调用;该系列文章之后的文章中调用你微信公众号平台的相关url时也是使用RestTemplate进行调用,所以这里创建一个由RestTemplate实现的HTTP工具类

    step01 创建一个com.xunyji.xunyjitest.config.CreatBeanConfig类来创建项目所需的Bean

      技巧01:需要在类级别添加 @Configuration 来指明该类是一个配置类,@Configuration 标注的类相当于一个XML配置类

    step02 创建com.xunyji.testdemo.comm.config.CreatBeanConfig#restTemplate方法来创建RestTemplate对应的Bean

      技巧01:注意乱码问题,参考博文 -> https://blog.csdn.net/papamilk/article/details/80000683

      坑01:解决乱码问题时需要使用到HttpClient相关的jar包

            <!--httpclient start-->
            <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.2</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpcore</artifactId>
                <version>4.4.6</version>
            </dependency>
            <!--httpclient end-->

     

    step03 在application-dev.yml文件中配置百度翻译所需的账号和url信息

    step04 创建相关实体类来读取step03里面配置的信息,这里的配置有三层,所以需要两个百度翻译相关的配置实体类

     

    step05 创建MD5加密工具类com.xunyji.xunyjitest.comm.util.Md5Utils

    package com.xunyji.testdemo.util;
    
    import java.io.*;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    
    /**
     * @author AltEnter
     * @create 2019-01-09 10:13
     * @desc MD5编码工具类
     **/
    public class Md5Utils {
    
        // 首先初始化一个字符数组,用来存放每个16进制字符
        private static final char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
                'e', 'f' };
    
        /**
         * 获得一个字符串的MD5值
         * @param input 输入的字符串
         * @return 输入字符串的MD5值
         *
         */
        public static String md5(String input) {
            if (input == null) {
                return null;
            }
    
            try {
                // 拿到一个MD5转换器(如果想要SHA1参数换成”SHA1”)
                MessageDigest messageDigest = MessageDigest.getInstance("MD5");
                // 输入的字符串转换成字节数组
                byte[] inputByteArray = input.getBytes("utf-8");
                // inputByteArray是输入字符串转换得到的字节数组
                messageDigest.update(inputByteArray);
                // 转换并返回结果,也是字节数组,包含16个元素
                byte[] resultByteArray = messageDigest.digest();
                // 字符数组转换成字符串返回
                return byteArrayToHex(resultByteArray);
            } catch (NoSuchAlgorithmException e) {
                return null;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * 获取文件的MD5值
         *
         * @param file
         * @return
         */
        public static String md5(File file) {
            try {
                if (!file.isFile()) {
                    System.err.println("文件" + file.getAbsolutePath() + "不存在或者不是文件");
                    return null;
                }
    
                FileInputStream in = new FileInputStream(file);
    
                String result = md5(in);
    
                in.close();
    
                return result;
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 获取一个输入流的MD5值
         * @param in
         * @return
         */
        public static String md5(InputStream in) {
    
            try {
                MessageDigest messagedigest = MessageDigest.getInstance("MD5");
    
                byte[] buffer = new byte[1024];
                int read = 0;
                while ((read = in.read(buffer)) != -1) {
                    messagedigest.update(buffer, 0, read);
                }
    
                in.close();
    
                String result = byteArrayToHex(messagedigest.digest());
    
                return result;
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        /**
         * 获取一个字节数组的MD5值
         * @param byteArray
         * @return
         */
        private static String byteArrayToHex(byte[] byteArray) {
            // new一个字符数组,这个就是用来组成结果字符串的(解释一下:一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方))
            char[] resultCharArray = new char[byteArray.length * 2];
            // 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去
            int index = 0;
            for (byte b : byteArray) {
                resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
                resultCharArray[index++] = hexDigits[b & 0xf];
            }
    
            // 字符数组组合成字符串返回
            return new String(resultCharArray);
    
        }
    
    }
    Md5Utils.java

    step06 创建HTTP请求方法工具类com.xunyji.xunyjitest.comm.util.HttpMethodUtils

    package com.xunyji.xunyjitest.comm.util;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.Map;
    
    /**
     * @author AltEnter
     * @create 2019-01-10 21:20
     * @desc HTTP请求方法工具类
     **/
    @Component
    @Slf4j
    public class HttpMethodUtils {
        @Autowired
        private RestTemplate restTemplate;
    
        /**
         * get请求方法封装【利用RestTemplate实现】
         * @param url
         * @return
         */
        public String doGetStrByRestTemplate(String url) {
            String result = null;
            result = restTemplate.getForObject(url, String.class);
            return result;
        }
    
        /**
         * get请求方法封装【利用RestTemplate实现】
         * @param url
         * @return
         */
        public Map doGetMapByRestTemplate(String url) {
            Map result = null;
    //        RestTemplate restTemplate = new RestTemplate();
            result = restTemplate.getForObject(url, Map.class);
            return result;
        }
    
    
        /**
         * get请求方法封装【利用RestTemplate实现】
         * @param url 请求路径【不带参数的和带参数的url都可以】
         * @param params 请求路径参数
         * @return
         */
        public String doGetStrWithMapParamByRestTemplate(String url, Map<String, String> params) throws UnsupportedEncodingException {
            String result = null;
    
            String query = URLEncoder.encode(params.get("q"), "UTF-8");
    
            log.info("加密前请求参数为:" + params);
    
    //        封装get请求的完整url
            String sendUrl = getUrlWithQueryString(url, params);
            log.info("参数加密后的请求URL为:" + sendUrl);
            result = restTemplate.getForObject(sendUrl, String.class);
    
            return result;
        }
    
        /**
         * get请求方法封装【利用RestTemplate实现】
         * @param url
         * @return
         */
        public Map doGetMapWithMapByRestTemplate(String url, Map<String, String> params) throws UnsupportedEncodingException {
    
            Map result = null;
    
            String query = URLEncoder.encode(params.get("q"), "UTF-8");
    
            log.info("加密前请求参数为:" + params);
    
    //        封装get请求的完整url
            String sendUrl = getUrlWithQueryString(url, params);
            log.info("加密后请求参数为:" + sendUrl);
            result = restTemplate.getForObject(sendUrl, Map.class);
            return result;
        }
    
        /**
         * 将不带参数的url和Map类型的参数封装成一个带参数的url
         * @param url
         * @param params
         * @return
         */
        private static String getUrlWithQueryString(String url, Map<String, String> params) {
            if (params == null) {
                return url;
            }
    
            StringBuilder builder = new StringBuilder(url);
            if (url.contains("?")) {
                builder.append("&");
            } else {
                builder.append("?");
            }
    
            int i = 0;
            for (String key : params.keySet()) {
                String value = params.get(key);
                // 过滤空的key
                if (value == null) {
                    continue;
                }
    
                if (i != 0) {
                    builder.append('&');
                }
    
                builder.append(key);
                builder.append('=');
    //            builder.append(encode(value)); // 如果使用RestTemplate请求时就不需要进行UrlEncode进行加密了,加密了反而会报错
                builder.append(value);
    
                i++;
            }
    
            return builder.toString();
        }
    
        /**
         * 对输入的字符串进行URL编码, 即转换为%20这种形式
         *
         * @param input 原文
         * @return URL编码. 如果编码失败, 则返回原文
         */
        public static String encode(String input) {
            if (input == null) {
                return "";
            }
    
            try {
                return URLEncoder.encode(input, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    
            return input;
        }
    }
    HttpMethodUtils.java

    step07 创建对象互转工具类 com.xunyji.xunyjitest.comm.util.TransformUtils

    package com.xunyji.xunyjitest.comm.util;
    
    import com.alibaba.fastjson.JSONObject;
    
    import java.util.Map;
    
    /**
     * @author AltEnter
     * @create 2019-01-07 8:37
     * @desc 各种类型转化工具类
     **/
    public class TransformUtils {
        /**
         * Map类型转化成指定类型
         * @param paramMap 待转化的Map对象
         * @param clazz 目标类型的类类型
         * @param <T> 目标类型
         * @return
         */
        public static <T> T parseMap2Object(Map<String, String> paramMap, Class<T> clazz) {
            return JSONObject.parseObject(JSONObject.toJSONString(paramMap), clazz);
        }
    
        /**
         * String类型转化成指定类型
         * @param str 带转化的String对象
         * @param clazz 目标类型的类类型
         * @param <T> 目标类型
         * @return
         */
        public static <T> T parseStr2Object(String str, Class<T> clazz) {
            return JSONObject.parseObject(str, clazz);
        }
    
        /**
         * unicode 2 utf
         * @param theString
         * @return String
         */
        public static String unicodeToUtf8(String theString) {
            char aChar;
            int len = theString.length();
            StringBuffer outBuffer = new StringBuffer(len);
            for (int x = 0; x < len;) {
                aChar = theString.charAt(x++);
                if (aChar == '\') {
                    aChar = theString.charAt(x++);
                    if (aChar == 'u') {
                        // Read the xxxx
                        int value = 0;
                        for (int i = 0; i < 4; i++) {
                            aChar = theString.charAt(x++);
                            switch (aChar) {
                                case '0':
                                case '1':
                                case '2':
                                case '3':
                                case '4':
                                case '5':
                                case '6':
                                case '7':
                                case '8':
                                case '9':
                                    value = (value << 4) + aChar - '0';
                                    break;
                                case 'a':
                                case 'b':
                                case 'c':
                                case 'd':
                                case 'e':
                                case 'f':
                                    value = (value << 4) + 10 + aChar - 'a';
                                    break;
                                case 'A':
                                case 'B':
                                case 'C':
                                case 'D':
                                case 'E':
                                case 'F':
                                    value = (value << 4) + 10 + aChar - 'A';
                                    break;
                                default:
                                    throw new IllegalArgumentException(
                                            "Malformed   \uxxxx   encoding.");
                            }
                        }
                        outBuffer.append((char) value);
                    } else {
                        if (aChar == 't')
                            aChar = '	';
                        else if (aChar == 'r')
                            aChar = '
    ';
                        else if (aChar == 'n')
                            aChar = '
    ';
                        else if (aChar == 'f')
                            aChar = 'f';
                        outBuffer.append(aChar);
                    }
                } else
                    outBuffer.append(aChar);
            }
            return outBuffer.toString();
        }
    
    
    }
    TransformUtils.java

    step08 创建百度翻译响应实体类com.xunyji.xunyjitest.model.baidu.TranslationResponse  com.xunyji.xunyjitest.model.baidu.TransResult

    package com.xunyji.xunyjitest.model.baidu;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author AltEnter
     * @create 2019-01-09 16:07
     * @desc 翻译请求响应数据封装实体类
     **/
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class TranslationResponse {
        /** 翻译源语言 */
        private String from;
        /** 译文语言 */
        private String to;
        /** 翻译结果 */
        private TransResult[] trans_result;
    }
    TranslationResponse.java
    package com.xunyji.xunyjitest.model.baidu;
    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    /**
     * @author AltEnter
     * @create 2019-01-09 16:09
     * @desc 翻译结果
     **/
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class TransResult {
        /** 翻译源文本 */
        private String src;
        /** 译文文本 */
        private String dst;
    }
    TransResult.java

    step09 创建百度翻译API封装类com.xunyji.xunyjitest.comm.util.BaiduTransApi

    package com.xunyji.xunyjitest.comm.util;
    
    import com.xunyji.xunyjitest.config.baidu.BaiduBaseConfig;
    import com.xunyji.xunyjitest.model.baidu.TransResult;
    import com.xunyji.xunyjitest.model.baidu.TranslationResponse;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.UnsupportedEncodingException;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author AltEnter
     * @create 2019-01-09 10:28
     * @desc 百度翻译API封装
     **/
    @Component
    @Slf4j
    public class BaiduTransApi {
    
        @Autowired
        private HttpMethodUtils httpMethodUtils;
    
        @Autowired
        private BaiduBaseConfig baiduBaseConfig;
    
        /**
         * 发送get请求进行翻译
         * @param query
         * @param from
         * @param to
         * @return
         */
        public String getTransStrResult(String query, String from, String to) throws UnsupportedEncodingException {
            Map<String, String> params = buildParams(query, from, to);
            // 调用自定义的get方法
            String restStr = httpMethodUtils.doGetStrWithMapParamByRestTemplate(baiduBaseConfig.getTranslation().getTransApiHost(), params);
            String result = TransformUtils.unicodeToUtf8(restStr);
            TranslationResponse translationResponse = TransformUtils.parseStr2Object(result, TranslationResponse.class);
            log.info("翻译请求结果为:" + translationResponse.toString());
            TransResult transResult = translationResponse.getTrans_result()[0];
            return String.format("%s -> %s", transResult.getSrc(), transResult.getDst());
            // 调用官方提供的get方法
    //        return HttpGet.get(baiduBaseConfig.getTranslation().getTransApiHost(), params);
        }
    
        public Map<String, String> getTransMapResult(String query, String from, String to) throws UnsupportedEncodingException {
            Map<String, String> params = buildParams(query, from, to);
            // 调用自定义的get方法
            Map<String, String> restMap = httpMethodUtils.doGetMapWithMapByRestTemplate(baiduBaseConfig.getTranslation().getTransApiHost(), params);
            String trans_result = restMap.get("trans_result");
            return restMap;
            // 调用官方提供的get方法
    //        return HttpGet.get(baiduBaseConfig.getTranslation().getTransApiHost(), params);
        }
    
    
    
        /**
         * 构建请求参数
         * @param query
         * @param from
         * @param to
         * @return
         */
        private Map<String, String> buildParams(String query, String from, String to) {
    
            String appid = baiduBaseConfig.getTranslation().getAppId();
            String securityKey = baiduBaseConfig.getTranslation().getSecurityKey();
    
    //        String appid = "20190109000255665";
    //        String securityKey = "iNPVhM9qtM3Kb0ZTesI9";
    
            Map<String, String> params = new HashMap<String, String>();
            params.put("q", query);
            params.put("from", from);
            params.put("to", to);
            params.put("appid", appid);
    
            // 随机数
            String salt = String.valueOf(System.currentTimeMillis());
            params.put("salt", salt);
    
            // 签名
            String src = appid + query + salt + securityKey; // 加密前的原文
            log.info("加密前的签名:" + src);
            String sign = Md5Utils.md5(src);
            params.put("sign", sign);
            log.info("加密后的签名:" + sign);
    
            return params;
        }
    
    
    
    }
    BaiduTransApi.java

    step10  调用com.xunyji.xunyjitest.comm.util.BaiduTransApi#getTransStrResult进行测试即可

      坑01:利用restTemplate调用百度翻译平台的url是不需要对参数进行urlEncoder加密,否则会报错:sign错误

     4.5 接入百度翻译

    step01 翻译文本格式说明 ->需要翻译的内容也是text类型额数据,翻译文本内容的格式如下

        en翻译足球 -> 表示将'足球'翻译成英文

        zh翻译football -> 表示将'football'翻译成中文

        zh翻译 -> 调出此菜单

        en翻译 -> 调出此菜单

    step02 创建com.xunyji.testdemo.util.weixin.MessageUtil#threeMenu方法作为翻译格式的提示信息封装方法

    step03 创建com.xunyji.testdemo.util.weixin.BaiduTransApi#getTransStrResult方法来对百度翻译api进行再一次封装

    step04 重构com.xunyji.xunyjitest.service.ReceiveMessageServiceImpl#textMessageHandler中的逻辑来实现翻译功能

    step05 启动应用,测试效果如下

    扫码获取源代码

     

     

  • 相关阅读:
    155. 最小栈
    160. 相交链表
    PAT 1057 Stack
    PAT 1026 Table Tennis
    PAT 1017 Queueing at Bank
    PAT 1014 Waiting in Line
    PAT 1029 Median
    PAT 1016 Phone Bills
    PAT 1010 Radix
    PAT 1122 Hamiltonian Cycle
  • 原文地址:https://www.cnblogs.com/NeverCtrl-C/p/10247498.html
Copyright © 2011-2022 走看看