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

进入公众账号的后台https://mp.weixin.qq.com/, 

微信公众平台的通讯机制


开发流程


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

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

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

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


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

signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。

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

备注 :URL必须是公网地址


后台代码

/**
 * 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对象

/**
 * 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

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;
    }
}

//查询坐标附近的数据

   /**
     * 根据不同的类型执行不同的方法
     *
     * @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());
        }
    }

    /**
     
     *
     * @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));
    }
<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数据

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;
    }



 /**
     * 图文信息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;

    }


//运行的结果



在微信号上创建菜单、发送连接、文本都有很明确的API, 希望要了解的童鞋多看文档: http://mp.weixin.qq.com/wiki/index.php?title=%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97










  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值