环境搭建

1.Java与微信公众号交互原理

微信公众号可以进行简易开发通过可视化界面交由普通用户即可完成,但想要实现跟高级的功能,那么我们就需要自己去实现接口来实现逻辑,即使用程序员的方式创建公众号。

用户在向公众号发送信息以及公众号返回数据给用户的过程,实际上要经过一下过程。

2.内网穿透

想要完成与微信服务器的交互,必须有一个可以与外网交互,能够让微信服务器访问到的url,而我们通常在本地做测试开发,那么就需要使用一个能够实现内网穿透的一个小工具来获取一个外网可访问的url,它能够将本地的地址指定端口映射到他们的服务器上,使外网可以访问像这类工具还是挺多的,在这里我用的是natapp,使用了收费版本(免费版映射的url会随机改变),当然也可以选择其他版本的工具,但大部分也是收费或者不稳定的。使用过程可以参考以下文档,还是比较简单的:

NATAPP1分钟快速新手图文教程 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具

3.注册微信订阅号

官方网址:

微信公众平台

注册

注册订阅号(服务号和订阅号开发类似,但需要填写企业各种信息,个人开发练习订阅号即可)

填写信息注册成功之后,在【设置与开发】—>【开发者工具】中可以看到自己的测试号信息

这里我的接口配置信息已经写过了,正常刚注册是没有的。

连接微信接口+基本护回复功能实现

接下来就是配置接口信息了,也就是要使得微信服务器与“我们的服务器建立起联系”

​​​​URL:内网穿透映射的URL+项目路径(项目会在后面讲怎么搭建)

Token:随便写,只是为了做验证

1.新建项目

项目创建此处不做赘述。

项目依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 日志打印 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.1</version></dependency><!-- xml格式转换工具 --><dependency><groupId>com.thoughtworks.xstream</groupId><artifactId>xstream</artifactId><version>1.4.11.1</version></dependency><!-- 获取xml文档用 --><dependency><groupId>org.dom4j</groupId><artifactId>dom4j</artifactId><version>2.1.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

2.测试连接

写一下测试代码测试连接(因为微信发送的连接数据请求是get请求,所以这里使用doGet接收参数,若收到get请求,此方法自动执行)

@Controller
@RequestMapping ( "/wechat" )
public  class  WechatSecurity {private  static Logger logger = Logger.getLogger(String.valueOf(WechatSecurity.class));@RequestMapping (value =  "security" , method = RequestMethod.GET)public  void  doGet(HttpServletRequest request,HttpServletResponse response,) {System.out.println("succee!");}
}

注意:此方法的路径需要正好对应我们上面接口配置信息中所填URL

运行项目,在接口配置信息界面点击提交,如果控制台打印“succee”,则证明项目与微信接口之间是连接畅通的。

但是提交之后网页仍然会提示连接失败,这是因为微信需要验证接口的有效性,发过来的请求带有很多参数,我们需要验证之后返回给微信数据才能够验证成功

3.服务器验证代码:

@Controller
@RequestMapping ( "/wechat" )
public  class  WechatSecurity {private  static Logger logger = Logger.getLogger(String.valueOf(WechatSecurity.class));/**** @Description: 用于接收get参数,返回验证参数* @param @param request* @param @param response* @param @param signature* @param @param timestamp* @param @param nonce* @param @param echostr* @author dapengniao* @date 2016年3月4日 下午6:20:00*/@RequestMapping (value =  "security" , method = RequestMethod.GET)public  void  doGet(HttpServletRequest request,HttpServletResponse response,@RequestParam(value =  "signature" , required =  true ) String signature,@RequestParam (value =  "timestamp" , required =  true ) String timestamp,@RequestParam (value =  "nonce" , required =  true ) String nonce,@RequestParam (value =  "echostr" , required =  true ) String echostr) {try  {if  (SignUtil.checkSignature(signature, timestamp, nonce)) {PrintWriter out = response.getWriter();out.print(echostr);out.close();}  else  {logger.info( "这里存在非法请求!" );}}  catch  (Exception e) {e.printStackTrace();}}
}

需要的工具类:(注意修改token)

/*** ClassName: SignUtil* @Description: 请求校验工具类* @author dapengniao* @date 2016年3月4日 下午6:25:41*/
public  class  SignUtil {// 与接口配置信息中的Token要一致private  static  String token =        ;/*** 验证签名* @param signature* @param timestamp* @param nonce* @return*/public  static  boolean  checkSignature(String signature, String timestamp, String nonce) {String[] arr =  new  String[] { token, timestamp, nonce };// 将token、timestamp、nonce三个参数进行字典序排序Arrays.sort(arr);StringBuilder content =  new  StringBuilder();for  ( int  i =  0 ; i < arr.length; i++) {content.append(arr[i]);}MessageDigest md =  null ;String tmpStr =  null ;try  {md = MessageDigest.getInstance( "SHA-1" );// 将三个参数字符串拼接成一个字符串进行sha1加密byte [] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);}  catch  (NoSuchAlgorithmException e) {e.printStackTrace();}content =  null ;// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信return  tmpStr !=  null  ? tmpStr.equals(signature.toUpperCase()) :  false ;}/*** 将字节数组转换为十六进制字符串* @param byteArray* @return*/private  static  String byteToStr( byte [] byteArray) {String strDigest =  "" ;for  ( int  i =  0 ; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return  strDigest;}/*** 将字节转换为十六进制字符串* @param mByte* @return*/private  static  String byteToHexStr( byte  mByte) {char [] Digit = {  '0' ,  '1' ,  '2' ,  '3' ,  '4' ,  '5' ,  '6' ,  '7' ,  '8' ,  '9' ,  'A' ,  'B' ,  'C' ,  'D' ,  'E' ,  'F'  };char [] tempArr =  new  char [ 2 ];tempArr[ 0 ] = Digit[(mByte >>>  4 ) &  0X0F ];tempArr[ 1 ] = Digit[mByte &  0X0F ];String s =  new  String(tempArr);return  s;}
}

通过以上代码可成功验证。

至此环境搭建完毕并且连接成功

4.实现通信

测试号管理界面往下翻能够找到自己订阅号的二维码,扫码关注即可

当我们向该公众号发送信息微信会通过post请求向我们发送xml格式的数据,这时候我们就需要接收post请求,解析该请求并且同样的返回xml格式文件

@RequestMapping(value =  "security" , method = RequestMethod.POST)// post方法用于接收微信服务端消息public  void  DoPost(HttpServletRequest req,HttpServletResponse resp) throws IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");//将请求中的xml参数转成mapMap<String,String> map = WxService.parseRequest(req.getInputStream());System.out.println(map);//转换为xml格式回复消息String textMsg = WxService.getRespose(map);resp.getWriter().print(textMsg);}

数据转换

@Service
public class WxService {public static  Map<String, String> parseRequest(InputStream is) {Map<String,String> map = new HashMap<String,String>();//1.通过io流得到文档对象SAXReader saxReader = new SAXReader();Document document = null;try {document = saxReader.read(is);} catch (DocumentException e) {e.printStackTrace();}//2.通过文档对象得到根节点对象Element root = document.getRootElement();//3.通过根节点对象获取所有子节点对象List<Element> elements = root.elements();//4.将所有节点放入mapfor (Element element : elements) {map.put(element.getName(), element.getStringValue());}return map;}/*** 事件消息回复*/public static String getRespose(Map<String, String> requestMap) {BaseMsg msg = null;// 根据用户发送消息的类型,做不同的处理String msgType = requestMap.get("MsgType");switch (msgType) {case "text":msg = dealTextMsg(requestMap);break;case "news":break;default:break;}// System.out.println(msg);// 将处理结果转化成xml的字符串返回if (null != msg) {return beanToXml(msg);}return null;}/*** 将回复的消息类转成xml字符串** @param msg* @return*/public static String beanToXml(BaseMsg msg) {XStream stream = new XStream();stream.processAnnotations(TextMsg.class);stream.processAnnotations(NewsMsg.class);String xml = stream.toXML(msg);return xml;}/*** 当用户发送是文本消息的处理逻辑** @param map* @return*/private static BaseMsg dealTextMsg(Map<String, String> requestMap) {// 获取用户发送的消息内容String msg = requestMap.get("Content");// 如果是图文回复一个图文消息if (msg.equals("图文")) {List<Article> articles = new ArrayList<Article>();articles.add(new Article(“自定义”));return new NewsMsg(requestMap, articles);}//否则回复一个文本消息,文本内容为'当前时间+你好'//当然这个内容可以自定义,在这里也可以接入自动回复机器人TextMsg textMsg = new TextMsg(requestMap, new Date(System.currentTimeMillis()).toLocaleString() + "你好");return textMsg;}}

通过实体类来将xml属性封装成为对象格式

/*** 消息类型实体类父类*/
public class BaseMsg {/*@XStreamAlias使用了xstream的依赖,用来生成xml格式*/@XStreamAlias("ToUserName")private String toUserName;//接收方的账号(收到的openid)@XStreamAlias("FromUserName")private String fromUserName;//开发者的微信号@XStreamAlias("CreateTime")private String createTime;//消息创建时间@XStreamAlias("MsgType")private String msgType;//消息类型//可直接设置所有消息的发送、接收账号以及创建时间(这些属性所有类型消息都一样,不一样的属性会单独设置)public BaseMsg(Map<String,String> requestMap) {this.toUserName = requestMap.get("FromUserName");this.fromUserName = requestMap.get("ToUserName");this.createTime = requestMap.get("CreateTime");}get() and set()......}
/*
图文消息实体类*/
@XStreamAlias("xml")
public class NewsMsg extends BaseMsg {@XStreamAlias("ArticleCount")private String articleCount;//图文消息个数@XStreamAlias("Articles")private List<Article> articles;public NewsMsg(Map<String, String> requestMap, List<Article> articles) {super(requestMap);this.setMsgType("news");this.articles = articles;this.setArticleCount(this.articles.size()+"");}get() and set()......}
/*
图文类消息子节点,对应item节点*/
@XStreamAlias("item")//映射到xml中的item这个节点
public class Article {@XStreamAlias("Title")private String title;//图文消息标题@XStreamAlias("Description")private String description;//图文消息描述@XStreamAlias("PicUrl")private String picUrl;//图片链接@XStreamAlias("Url")private String url;//点击图文消息跳转链接public Article() {}public Article(String title, String description, String picUrl, String url) {this.title = title;this.description = description;this.picUrl = picUrl;this.url = url;}get() and set()......}
/*
文本消息实体类*/
@XStreamAlias("xml") //xml指的就是xml这个根节点名称
public class TextMsg extends BaseMsg {@XStreamAlias("Content")private String content;//回复的文本内容public TextMsg(Map<String,String> requestMap, String content) {super(requestMap);this.setMsgType("text");this.content = content;}get() and set()......}

这里只写了文本和图文消息两种格式,其他类型数据处理方式大同小异

到这里基本完成了和微信公众号的基本交互。

本文代码实现部分借鉴了一下两篇文献:

Java微信公众平台开发(一)——接入微信公众平台_North-java的博客-CSDN博客_微信公众平台如何开发微信公众号开发-Java版学习笔记 | 贺刘芳的搬砖日记Java微信公众平台开发(一)——接入微信公众平台_North-java的博客-CSDN博客_微信公众平台如何开发

贺刘芳的细节写的比较到位,如有不懂可以参考一下

官方文档地址:

接入概述 | 微信开放文档

Java-微信公众号-上(环境搭建+基础回复功能)相关推荐

  1. 微信公众号本地环境搭建(解决微信接口需要公网地址,但是只有本地环境的问题)

    微信公众号本地环境搭建(解决微信接口需要公网地址,但是只有本地环境的问题) 置顶2018年01月08日 17:22:13 阅读数:342 目前移动开发处于比较火的的趋势,很多的开发者都跃跃欲试,目前移 ...

  2. Java 微信公众号上传永久素材的方法

    用 Java 实现微信公众号上传永久素材,代码如下: /*** 上传其他永久素材(图片素材的上限为5000,其他类型为1000)* @param appid* @param secret* @retu ...

  3. 微信公众号开发环境搭建

    第一章 申请服务器资源 创建新浪云计算应用 申请账号 我们使用SAE新浪云计算平台作为服务器资源,并且申请PHP环境+MySQL数据库作为程序运行环境. 申请地址为:http://www.sinacl ...

  4. 微信公众号开发环境搭建(一)

    公网映射配置 需要将本地地址映射到公网,这里我们使用natapp 注意:本地端口必须是要填8080的(这个购买后也是可以再修改的),因为微信公众平台接口的调用仅支持80 客户端下载 1.配置confi ...

  5. 慕课网_《Java微信公众号开发进阶》学习总结

    时间:2017年08月12日星期六 说明:本文部分内容均来自慕课网.@慕课网:http://www.imooc.com 教学源码:http://img.mukewang.com/down/... 学习 ...

  6. 微信公众号上云 后台管理更轻松

    微信公众号上云 后台管理更轻松 作为时下热门的通讯工具和社交平台,微信已成为我们使用率最高的App之一.适应碎片化学习.娱乐的需要,大家会关注一些自己喜欢的企业微信公众号,看资讯.学技能.观美图,并在 ...

  7. JAVA微信公众号开发第8篇JSSDK图片上传预览

    简介 博主微信JSSDK&图片上传预览基于微信分享做拓展,所以一些配置操作请点击查阅JAVA微信公众号开发第7篇JSSDK&微信分享博文 页面 <html><head ...

  8. 工具类产品适合在微信公众号上运营吗?

    1. 工具类产品适合在微信公众号上运营吗? 问题描述:如果工具类的产品,主要的核心服务功能搬到微信公众号上运营会有些什么优势和劣势,以及如何在公众号上实现流量变现? 答:微信公众号之前有三种分类:服务 ...

  9. Java微信公众号开发微信网页授权之前端传递code方式获取用户信息

    本片博客讲解的网页授权分为两步,前端先传递backUrl(回调地址)到后台网页授权接口,该接口拿到回调地址后组装授权连接,重定向到前端页面,前端页面截取Code,传入后端获取用户信息方法,获取用户信息 ...

  10. java微信公众号JSAPI支付以及所遇到的坑

    java微信公众号JSAPI支付以及所遇到的坑 上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http:/ ...

最新文章

  1. python使用imbalanced-learn的KMeansSMOTE方法进行上采样处理数据不平衡问题
  2. Error(s) in loading state_dict for ModelMain
  3. [LeetCode][Java] 3Sum Closest
  4. girton college things locations
  5. Windows系统下黑客(极客)学习发展流程图
  6. 一个命名管道可以被多个客户端访问吗_Redis 的事务机制和管道技术Pipelining
  7. VLAN与子网划分区别
  8. 面试题,你觉得XX和XX产品有何区别?
  9. Java中各种对象的各种实例化方式
  10. Java开发笔记(六十九)泛型类的定义及其运用
  11. C 语言中的指针和内存泄漏
  12. linux 下 dhcp failover相关
  13. Centos7 安装独立显卡驱动
  14. 汽车照明全国产化电子元件推荐方案
  15. 【调剂】上海科技大学信息学院2023年硕士招生调剂公告
  16. 密码学应用的四个进化阶段 | 博文精选
  17. 电话销售潜在客户从哪里找 电销行业还值得深入研究吗?
  18. JS基础--强制类型转换(易错点,自用)
  19. 对话姜老师,DBA的职场之路
  20. 虚幻代码底层——虚幻属性系统(虚幻C++的反射机制)

热门文章

  1. json模块的转义dump 和反转义 loap
  2. 用JSON-server模拟REST API
  3. CheckException和UnCheckException的区别
  4. scala怎么取绝对值
  5. 2.Zigbee串口发送
  6. 大数据与云计算的理解与基本认识
  7. 从单片机初学者迈向单片机工程师(对初学者非常有用)
  8. 计算机设置了分组用户怎么切换,怎么弄微信小号-不单止换小号,另外这些微信小技巧也一定让你“相见恨晚”...
  9. 利用Python scapy爬取起点小说网小说
  10. 微信H5开发,怎样禁止手机横屏