您的位置:首页 > 移动开发 > 微信开发

微信公众账号开发简单实例【java】

2017-10-25 22:58 746 查看
进入公众账号的后台https://mp.weixin.qq.com/

微信公众平台的通讯机制



开发流程



从上图中可以看到,高级功能包含两种模式:编辑模式和开发模式,并且这两种模式是互斥关系,即两种模式不能同时开启。那两种模式有什么区别呢?作为开发人员到底要开启哪一种呢?

编辑模式:主要针对非编程人员及信息发布类公众帐号使用。开启该模式后,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。

开发模式:主要针对具备开发能力的人使用。开启该模式后,能够使用微信公众平台开放的接口,通过编程方式实现自定义菜单的创建、用户消息的接收/处理/响应。这种模式更加灵活,建议有开发能力的公司或个人都采用该模式。

在这里就只介绍开发模式了, 编辑没有就不用讲了,都是动手操作的事情太简单了。 嘿嘿。



开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,否则接入失败。

signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
加密/校验流程:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信


备注 :URL必须是公网地址

后台代码

[java] view
plain copy

/**

* User: zhanglin

* Date: 13-10-23

* Time: 下午5:31

* Desc: 微信控制电器

*/

@Controller

@RequestMapping("/")

public class WeiXinControllerTest {

private static Logger log = LogManager.getLogger(WeiXinControllerTest.class);

@Resource

private ServiceConfig serviceConfig;

@Resource

private IWeiXinTextService weiXinTextService;

//get请求方式,可以做测试用。

@ResponseBody

@RequestMapping(method = RequestMethod.GET)

public String get(ModelMap model, String signature, String timestamp, String nonce, String echostr) {

boolean bChecked = check(signature, timestamp, nonce);

if (bChecked) {

return echostr;

}

return "hello";

} //微信进来的请求就通过POST方式进来

@RequestMapping(method = RequestMethod.POST)

public void post(String signature, String timestamp, String nonce, HttpServletRequest request, HttpServletResponse response) {

boolean bChecked = check(signature, timestamp, nonce);

if (bChecked) {

response.setCharacterEncoding("UTF-8");

PrintWriter out = null;

Document doc;

SAXReader reader = new SAXReader();

InputStream in = null;

try {

out = response.getWriter();

in = request.getInputStream();

doc = reader.read(in);

Element root = doc.getRootElement();

//根据消息类型执行不同的方法

checkMsgType(out, root,response);

} catch (Exception e) {

log.debug(e.getMessage());

} finally {

if (in != null) {

try {

in.close();

} catch (IOException e) {

log.debug(e.getMessage());

}

}

if (out != null) {

out.flush();

out.close();

}

}

}

}

/**

* 检测是否为微信发送的请求

*

* @param signature

* @param timestamp

* @param nonce

* @return

*/

private boolean check(String signature, String timestamp, String nonce) {

List<String> strList = new ArrayList<String>(); //这里的token 就是网站填的值, 建议用配置文件读取,根据环境不同读取不同的数据。

strList.add(serviceConfig.getToken());

strList.add(timestamp);

strList.add(nonce);

Collections.sort(strList);

String str = "";

for (String s : strList) {

str += s;

}

String strSha = DigestUtils.shaHex(str);

return strSha.equals(signature);

}

}

微信向公众号发送一个地理位置,然后公众号读取坐标 ,查询这个坐标附近的数据。

当用户向公众号发送请求, 微信服务器再向公众号发送的是XML的数据, 所以不了解解析XML,封装XML的童鞋可以先去补一下这方面的知识。



后台代码

//把抽象的东西抽取成java对象

[java] view
plain copy

/**

* User: zhanglin

* Date: 13-10-23

* Time: 下午4:26

*/

public enum MsgType {

text("文本"),image("图片"),location("地理位置"),link("连接"),event("事件"),news("图文信息") ;

private String value;

public String getValue() {

return value;

}

private MsgType(String value) {

this.value = value;

}

}

封装图文消息类,在这里笔者是用xml提供的标签来创建xml

[java] view
plain copy

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

/**

* User: zhanglin

* Date: 13-10-24

* Time: 下午1:37

* desc: 图片文消息

*/

@XmlRootElement(name="item")

public class Item {

private String title;

private String description;

private String picUrl;

private String url;

public Item() {

}

public Item(String title, String description, String picUrl, String url) {

this.title = title;

this.description = description;

this.picUrl = picUrl;

this.url = url;

}

@XmlElement(name = "Title")

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

@XmlElement(name = "Description")

public String getDescription() {

return description;

}

public void setDescription(String description) {

this.description = description;

}

@XmlElement(name = "PicUrl")

public String getPicUrl() {

return picUrl;

}

public void setPicUrl(String picUrl) {

this.picUrl = picUrl;

}

@XmlElement(name = "Url")

public String getUrl() {

return url;

}

public void setUrl(String url) {

this.url = url;

}

}

//查询坐标附近的数据

[java] view
plain copy

/**

* 根据不同的类型执行不同的方法

*

* @param out 输出流

* @param root 从请求中获得的有关xml对象

*/

private void checkMsgType(PrintWriter out, Element root) {

try {

String value = root.element("MsgType").getTextTrim();

//<span style="font-family: Arial; font-size: 14px; line-height: 26px;">查询坐标附近的数据</span>

if (MsgType.location.toString().equals(value)) {

findNearCommunity(out, root);

}

//做其他的逻辑

} catch (Exception e) {

log.debug(e.getMessage());

}

}

[java] view
plain copy

/**

*

* @param out

* @param root

*/

private void findNearCommunity(PrintWriter out, Element root) throws Exception {

NearCoordinate nearCoordinate = param(root);

Integer count ="..." ;//调用接口查询条数

List<Object> list = "...";//调用接口查询数据

out.println(WeiXinXmlFactory.getImgNewsXml(list, root, count));

}

[java] view
plain copy

<span style="font-size: 14px;"> /**

* 图文信息xml

* @param list 结果集

* @param root

* @param count 总条数

* @return

*/

public static String getImgNewsXml(List<CommunityDto> list,Element root,Integer count) {

try { //接收方帐号(收到的OpenID)

String toUserName = root.element("ToUserName").getTextTrim(); // 开发者微信号

String fromUserName = root.element("FromUserName").getTextTrim();

Marshaller m = getMarshaller(new WeiXinImg());

ArrayList<Item> items = new ArrayList<Item>();

Articles articles = new Articles();

Item item ;

int next=0;

for (CommunityDto communityDto:list){

//封装 Item对象

items.add(item);

next++;

}

//总条数大于列表条数

if(WeiXinConfig.COMMUNITY_LIST_SIZE<count){

//封装一个“更多” Item对象

items.add(item);

}

articles.setArrayList(items);

WeiXinImg weiXinImg = new WeiXinImg(fromUserName,toUserName,System.currentTimeMillis(), MsgType.news,<span style="font-family: Arial, Helvetica, sans-serif;">count</span><span style="font-family: Arial, Helvetica, sans-serif;">,articles);</span>

StringWriter fw = new StringWriter();

m.marshal(weiXinImg, fw);

return fw.toString();

}catch (Exception e){

log.debug(e.getMessage());

}

return null;

}

//创建一个< tt >Marshaller< / tt >对象,可以用来转换成一个Java内容树转换成XML数据。

[java] view
plain copy

private static Marshaller getMarshaller(Object o)throws Exception{

JAXBContext context = JAXBContext.newInstance(o.getClass());

// 下面代码演示将对象转变为xml

Marshaller m = context.createMarshaller();

//是否格式化生成的xml串

m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);

//是否省略xml头信息

m.setProperty(Marshaller.JAXB_FRAGMENT, true);

return m;

}

[java] view
plain copy

/**

* 图文信息xml

* @param list 结果集

* @param root

* @param count 总条数

* @return

*/

public static String getImgNewsXml(List<CommunityDto> list,Element root,Integer count) {

try {

String toUserName = root.element("ToUserName").getTextTrim();

String fromUserName = root.element("FromUserName").getTextTrim();

Marshaller m = getMarshaller(new WeiXinImg());

ArrayList<Item> items = new ArrayList<Item>();

Articles articles = new Articles();

Item item ;

int next=0;

for (CommunityDto communityDto:list){

//组装Item对象

items.add(item);

next++;

}

//总条数大于列表条数

if(WeiXinConfig.COMMUNITY_LIST_SIZE<count){

item = new Item("更多","",WeiXinConfig.FUNI_LOGO,UrlGenerator.getWapCommunityList(WeiXinConfig.CITY));

items.add(item);

}

articles.setArrayList(items);

int articleCount = itemCount(list.size(),WeiXinConfig.COMMUNITY_LIST_SIZE<count);

WeiXinImg weiXinImg = new WeiXinImg(fromUserName,toUserName,System.currentTimeMillis(), MsgType.news,articleCount,articles);

StringWriter fw = new StringWriter();

m.marshal(weiXinImg, fw);

return fw.toString();

}catch (Exception e){

log.debug(e.getMessage());

}

return null;

}

//运行的结果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息