• java微信二次第三方开发,token认证,消息事件接收,图文素材库,自定义菜单等功能


    基于之前的文章SSM配置的项目:http://www.cnblogs.com/mangyang/p/5168291.html

    来进行微信第三方开发,

    微信二次开发,官方还是网上有很多介绍了,这里就不在进行讲述了 直接上干货。

    首先 与微信对接,服务器配置,需要80端口和443端口开放的服务器,这里推荐 使用 python 的pagekite,一款反向代理的工具,具体安装百度搜,提供下配置放方法:http://jingyan.baidu.com/article/0eb457e52ca0af03f0a90568.html

    配置好了之后,使用maven 或者 tomcat 等中间件 启动咱们的项目,访问之前注册的 pagekite地址,试一下,正常访问就进行下一步,

    一、服务器配置认证

    首先根据官方文档得知,

    1)将token、timestamp、nonce三个参数进行字典序排序

    2)将三个参数字符串拼接成一个字符串进行sha1加密

    3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

    SHA1.java

    package com.wx.util;
    
    /*
     * 微信公众平台(JAVA) SDK
     *
     * Copyright (c) 2014, Ansitech Network Technology Co.,Ltd All rights reserved.
     * http://www.ansitech.com/weixin/sdk/
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    import java.security.MessageDigest;
    
    /**
     * <p>
     * Title: SHA1算法
     * </p>
     * 
     */
    public final class SHA1 {
    
    	private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
    
    	/**
    	 * Takes the raw bytes from the digest and formats them correct.
    	 * 
    	 * @param bytes
    	 *            the raw bytes from the digest.
    	 * @return the formatted bytes.
    	 */
    	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();
    	}
    
    	public static String encode(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);
    		}
    	}
    }
    

    然后编写controller 来接收 微信的 认证请求

    WxManagerController.java

    package com.controller;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.wx.util.SHA1;
    
    
    @Controller 
    @RequestMapping( "/wx" )
    public class WxManagerController {
    	
    	private String Token = "testfortoken";
    	
    	@RequestMapping(value = "", method = { RequestMethod.GET, RequestMethod.POST })
    	@ResponseBody
    	public void load(Model model, HttpServletRequest request, HttpServletResponse response) {
    		//判断访问方式
    		boolean isGet = request.getMethod().toLowerCase().equals("get");
    		if (isGet) {
    			//进行认证
    			access(request, response);
    		} else {
    			//处理微信post请求
    		}
    	}
    	
    	/**
    	 * 验证URL真实性
    	 * 
    	 * @param request
    	 * @param response
    	 * @return String
    	 */
    	private String access(HttpServletRequest request, HttpServletResponse response) {
    		// 验证URL真实性
    		String signature = request.getParameter("signature");// 微信加密签名
    		String timestamp = request.getParameter("timestamp");// 时间戳
    		String nonce = request.getParameter("nonce");// 随机数
    		String echostr = request.getParameter("echostr");// 随机字符串
    		List<String> params = new ArrayList<String>();
    		params.add(Token);
    		params.add(timestamp);
    		params.add(nonce);
    		// 1. 将token、timestamp、nonce三个参数进行字典序排序
    		Collections.sort(params, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return o1.compareTo(o2);
    			}
    		});
    		// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
    		String temp = SHA1.encode(params.get(0) + params.get(1) + params.get(2));
    		if (temp.equals(signature)) {
    			try {
    				response.getWriter().write(echostr);
    				return echostr;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return null;
    	}
    
    }
    

    OK,到微信公众号后台,开发-基本配置-修改配置

    token是项目里自己填写的参数,一致即可,

    EncodingAESKey 随机生成即可,

    点击提交。、

    成功!

    下面做一些功能,用户消息处理以及事件处理,

    二、消息,事件处理

    根据官方文档得知,处理微信的post请求,微信是以xml格式发送的,所以要解析xml并做处理,这里使用XStream

    maven 使用的 oschina库 搜不到 xstream-1.4.8 版本 手动下载了一个 下载链接:http://pan.baidu.com/s/1dEAdDVb

    其他的maven 可直接pom里配置。

    pom.xml

    <dependency>
    		<groupId>xstream</groupId>
    		<artifactId>xstream</artifactId>
    		<version>1.4.8</version>
    		<scope>system</scope>
    		<systemPath>${project.basedir}/WebContent/WEB-INF/lib/xstream-1.4.8.jar</systemPath>
    	</dependency>
    	<dependency>
    		<groupId>xmlpull</groupId>
    		<artifactId>xmlpull</artifactId>
    		<version>1.1.3.1</version>
    	</dependency>
    	<dependency>
    		<groupId>xpp3</groupId>
    		<artifactId>xpp3</artifactId>
    		<version>1.1.4c</version>
    	</dependency>
    

    xstream 下的 systemPath 填写项目里对应的jar位置。

    开始编写代码

    加入 CDATA 验证创建的@interface类

    XStreamCDATA.java

    package com.penuel.mythopoet.wx.manager;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.FIELD })
    public @interface XStreamCDATA {
    
    }
    

    XStream工具类

    SerializeXmlUtil.java
    package com.wx.util;
    
    import java.io.Writer;
    import java.lang.reflect.Field;
    
    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    import com.thoughtworks.xstream.core.util.QuickWriter;
    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
    import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
    import com.thoughtworks.xstream.io.xml.XppDriver;
    
    /**
     * xml 转换工具类
     */
    public class SerializeXmlUtil {
    
    	public static XStream createXstream() {
    		return new XStream(new XppDriver() {
    			@Override
    			public HierarchicalStreamWriter createWriter(Writer out) {
    				return new PrettyPrintWriter(out) {
    					boolean cdata = false;
    					Class<?> targetClass = null;
    
    					@Override
    					public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
    						super.startNode(name, clazz);
    						// 业务处理,对于用XStreamCDATA标记的Field,需要加上CDATA标签
    						if (!name.equals("xml")) {
    							cdata = needCDATA(targetClass, name);
    						} else {
    							targetClass = clazz;
    						}
    					}
    
    					@Override
    					protected void writeText(QuickWriter writer, String text) {
    						if (cdata) {
    							writer.write("<![CDATA[");
    							writer.write(text);
    							writer.write("]]>");
    						} else {
    							writer.write(text);
    						}
    					}
    				};
    			}
    		});
    	}
    
    	private static boolean needCDATA(Class<?> targetClass, String fieldAlias) {
    		boolean cdata = false;
    		// first, scan self
    		cdata = existsCDATA(targetClass, fieldAlias);
    		if (cdata)
    			return cdata;
    		// if cdata is false, scan supperClass until java.lang.Object
    		Class<?> superClass = targetClass.getSuperclass();
    		while (!superClass.equals(Object.class)) {
    			cdata = existsCDATA(superClass, fieldAlias);
    			if (cdata)
    				return cdata;
    			superClass = superClass.getClass().getSuperclass();
    		}
    		return false;
    	}
    
    	private static boolean existsCDATA(Class<?> clazz, String fieldAlias) {
    		if ("MediaId".equals(fieldAlias)) {
    			return true; // 特例添加 morning99
    		}
    		// scan fields
    		Field[] fields = clazz.getDeclaredFields();
    		for (Field field : fields) {
    			// 1. exists XStreamCDATA
    			if (field.getAnnotation(XStreamCDATA.class) != null) {
    				XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
    				// 2. exists XStreamAlias
    				if (null != xStreamAlias) {
    					if (fieldAlias.equals(xStreamAlias.value()))// matched
    						return true;
    				} else {// not exists XStreamAlias
    					if (fieldAlias.equals(field.getName()))
    						return true;
    				}
    			}
    		}
    		return false;
    	}
    
    }
    

    微信误参数字典

     WxErrorCode.java

    package com.wx.util;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @SuppressWarnings("unchecked")
    public class WxErrorCode {
    
    	@SuppressWarnings("rawtypes")
    	public static final Map ERRORCODE=new HashMap<Integer,String>();
    	
    	static{
    		ERRORCODE.put(-1,"系统繁忙");
    		ERRORCODE.put(0,"请求成功");
    		ERRORCODE.put(40001,"获取access_token时AppSecret错误,或者access_token无效");
    		ERRORCODE.put(40002,"不合法的凭证类型");
    		ERRORCODE.put(40003,"不合法的OpenID");
    		ERRORCODE.put(40004,"不合法的媒体文件类型");
    		ERRORCODE.put(40005,"不合法的文件类型");
    		ERRORCODE.put(40006,"不合法的文件大小");
    		ERRORCODE.put(40007,"不合法的媒体文件id");
    		ERRORCODE.put(40008,"不合法的消息类型");
    		ERRORCODE.put(40009,"不合法的图片文件大小");
    		ERRORCODE.put(40010,"不合法的语音文件大小");
    		ERRORCODE.put(40011,"不合法的视频文件大小");
    		ERRORCODE.put(40012,"不合法的缩略图文件大小");
    		ERRORCODE.put(40013,"不合法的APPID");
    		ERRORCODE.put(40014,"不合法的access_token");
    		ERRORCODE.put(40015,"不合法的菜单类型");
    		ERRORCODE.put(40016,"不合法的按钮个数");
    		ERRORCODE.put(40017,"不合法的按钮个数");
    		ERRORCODE.put(40018,"不合法的按钮名字长度");
    		ERRORCODE.put(40019,"不合法的按钮KEY长度");
    		ERRORCODE.put(40020,"不合法的按钮URL长度");
    		ERRORCODE.put(40021,"不合法的菜单版本号");
    		ERRORCODE.put(40022,"不合法的子菜单级数");
    		ERRORCODE.put(40023,"不合法的子菜单按钮个数");
    		ERRORCODE.put(40024,"不合法的子菜单按钮类型");
    		ERRORCODE.put(40025,"不合法的子菜单按钮名字长度");
    		ERRORCODE.put(40026,"不合法的子菜单按钮KEY长度");
    		ERRORCODE.put(40027,"不合法的子菜单按钮URL长度");
    		ERRORCODE.put(40028,"不合法的自定义菜单使用用户");
    		ERRORCODE.put(40029,"不合法的oauth_code");
    		ERRORCODE.put(40030,"不合法的refresh_token");
    		ERRORCODE.put(40031,"不合法的openid列表");
    		ERRORCODE.put(40032,"不合法的openid列表长度");
    		ERRORCODE.put(40033,"不合法的请求字符,不能包含\uxxxx格式的字符");
    		ERRORCODE.put(40035,"不合法的参数");
    		ERRORCODE.put(40038,"不合法的请求格式");
    		ERRORCODE.put(40039,"不合法的URL长度");
    		ERRORCODE.put(40050,"不合法的分组id");
    		ERRORCODE.put(40051,"分组名字不合法");
    		ERRORCODE.put(41001,"缺少access_token参数");
    		ERRORCODE.put(41002,"缺少appid参数");
    		ERRORCODE.put(41003,"缺少refresh_token参数");
    		ERRORCODE.put(41004,"缺少secret参数");
    		ERRORCODE.put(41005,"缺少多媒体文件数据");
    		ERRORCODE.put(41006,"缺少media_id参数");
    		ERRORCODE.put(41007,"缺少子菜单数据");
    		ERRORCODE.put(41008,"缺少oauth code");
    		ERRORCODE.put(41009,"缺少openid");
    		ERRORCODE.put(42001,"access_token超时");
    		ERRORCODE.put(42002,"refresh_token超时");
    		ERRORCODE.put(42003,"oauth_code超时");
    		ERRORCODE.put(43001,"需要GET请求");
    		ERRORCODE.put(43002,"需要POST请求");
    		ERRORCODE.put(43003,"需要HTTPS请求");
    		ERRORCODE.put(43004,"需要接收者关注");
    		ERRORCODE.put(43005,"需要好友关系");
    		ERRORCODE.put(44001,"多媒体文件为空");
    		ERRORCODE.put(44002,"POST的数据包为空");
    		ERRORCODE.put(44003,"图文消息内容为空");
    		ERRORCODE.put(44004,"文本消息内容为空");
    		ERRORCODE.put(45001,"多媒体文件大小超过限制");
    		ERRORCODE.put(45002,"消息内容超过限制");
    		ERRORCODE.put(45003,"标题字段超过限制");
    		ERRORCODE.put(45004,"描述字段超过限制");
    		ERRORCODE.put(45005,"链接字段超过限制");
    		ERRORCODE.put(45006,"图片链接字段超过限制");
    		ERRORCODE.put(45007,"语音播放时间超过限制");
    		ERRORCODE.put(45008,"图文消息超过限制");
    		ERRORCODE.put(45009,"接口调用超过限制");
    		ERRORCODE.put(45010,"创建菜单个数超过限制");
    		ERRORCODE.put(45015,"回复时间超过限制");
    		ERRORCODE.put(45016,"系统分组,不允许修改");
    		ERRORCODE.put(45017,"分组名字过长");
    		ERRORCODE.put(45018,"分组数量超过上限");
    		ERRORCODE.put(46001,"不存在媒体数据");
    		ERRORCODE.put(46002,"不存在的菜单版本");
    		ERRORCODE.put(46003,"不存在的菜单数据");
    		ERRORCODE.put(46004,"不存在的用户");
    		ERRORCODE.put(47001,"解析JSON/XML内容错误");
    		ERRORCODE.put(48001,"api功能未授权");
    		ERRORCODE.put(50001,"用户未授权该api");
    	}
    
    }
    

    消息工具类

    WxMessageUtil.java

    package com.wx.util;
    
    
    /**
     * 消息工具类
     *
     */
    public class WxMessageUtil {
    	/**
    	 * 返回消息类型:文本
    	 */
    	public static final String RESP_MESSAGE_TYPE_TEXT = "text";
    
    	/**
    	 * 返回消息类型:音乐
    	 */
    	public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
    
    	/**
    	 * 返回消息类型:图文
    	 */
    	public static final String RESP_MESSAGE_TYPE_NEWS = "news";
    
    	/**
    	 * 请求消息类型:文本
    	 */
    	public static final String REQ_MESSAGE_TYPE_TEXT = "text";
    
    	/**
    	 * 请求消息类型:图片
    	 */
    	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
    
    	/**
    	 * 请求消息类型:链接
    	 */
    	public static final String REQ_MESSAGE_TYPE_LINK = "link";
    
    	/**
    	 * 请求消息类型:地理位置
    	 */
    	public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
    
    	/**
    	 * 请求消息类型:音频
    	 */
    	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
    
    	/**
    	 * 请求消息类型:推送
    	 */
    	public static final String REQ_MESSAGE_TYPE_EVENT = "event";
    
    	/**
    	 * 事件类型:subscribe(订阅)
    	 */
    	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
    
    	/**
    	 * 事件类型:unsubscribe(取消订阅)
    	 */
    	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
    
    	/**
    	 * 事件类型:CLICK(自定义菜单点击事件)
    	 */
    	public static final String EVENT_TYPE_CLICK = "CLICK";
    
    }
    

    微信POST的XML数据包转换为消息接受对象

    InputMessage.java

    package com.penuel.mythopoet.wx.manager;
    
    /*
     * 微信公众平台(JAVA) SDK
     *
     * Copyright (c) 2014, Ansitech Network Technology Co.,Ltd All rights reserved.
     * http://www.ansitech.com/weixin/sdk/
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    import java.io.Serializable;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    /**
     * POST的XML数据包转换为消息接受对象
     * 
     * <p>
     * 由于POST的是XML数据包,所以不确定为哪种接受消息,<br/>
     * 所以直接将所有字段都进行转换,最后根据<tt>MsgType</tt>字段来判断取何种数据
     * </p>
     * 
     */
    @XStreamAlias("xml")
    public class InputMessage implements Serializable {
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	@XStreamAlias("ToUserName")
    	private String ToUserName;
    	@XStreamAlias("FromUserName")
    	private String FromUserName;
    	@XStreamAlias("CreateTime")
    	private Long CreateTime;
    	@XStreamAlias("MsgType")
    	private String MsgType = "text";
    	@XStreamAlias("MsgId")
    	private Long MsgId;
    	// 文本消息
    	@XStreamAlias("Content")
    	private String Content;
    	// 图片消息
    	@XStreamAlias("PicUrl")
    	private String PicUrl;
    	// 位置消息
    	@XStreamAlias("LocationX")
    	private String LocationX;
    	@XStreamAlias("LocationY")
    	private String LocationY;
    	@XStreamAlias("Scale")
    	private Long Scale;
    	@XStreamAlias("Label")
    	private String Label;
    	// 链接消息
    	@XStreamAlias("Title")
    	private String Title;
    	@XStreamAlias("Description")
    	private String Description;
    	@XStreamAlias("Url")
    	private String URL;
    	// 语音信息
    	@XStreamAlias("MediaId")
    	private String MediaId;
    	@XStreamAlias("Format")
    	private String Format;
    	@XStreamAlias("Recognition")
    	private String Recognition;
    	// 事件
    	@XStreamAlias("Event")
    	private String Event;
    	@XStreamAlias("EventKey")
    	private String EventKey;
    	@XStreamAlias("Ticket")
    	private String Ticket;
    
    	public String getToUserName() {
    		return ToUserName;
    	}
    
    	public void setToUserName(String toUserName) {
    		ToUserName = toUserName;
    	}
    
    	public String getFromUserName() {
    		return FromUserName;
    	}
    
    	public void setFromUserName(String fromUserName) {
    		FromUserName = fromUserName;
    	}
    
    	public Long getCreateTime() {
    		return CreateTime;
    	}
    
    	public void setCreateTime(Long createTime) {
    		CreateTime = createTime;
    	}
    
    	public String getMsgType() {
    		return MsgType;
    	}
    
    	public void setMsgType(String msgType) {
    		MsgType = msgType;
    	}
    
    	public Long getMsgId() {
    		return MsgId;
    	}
    
    	public void setMsgId(Long msgId) {
    		MsgId = msgId;
    	}
    
    	public String getContent() {
    		return Content;
    	}
    
    	public void setContent(String content) {
    		Content = content;
    	}
    
    	public String getPicUrl() {
    		return PicUrl;
    	}
    
    	public void setPicUrl(String picUrl) {
    		PicUrl = picUrl;
    	}
    
    	public String getLocationX() {
    		return LocationX;
    	}
    
    	public void setLocationX(String locationX) {
    		LocationX = locationX;
    	}
    
    	public String getLocationY() {
    		return LocationY;
    	}
    
    	public void setLocationY(String locationY) {
    		LocationY = locationY;
    	}
    
    	public Long getScale() {
    		return Scale;
    	}
    
    	public void setScale(Long scale) {
    		Scale = scale;
    	}
    
    	public String getLabel() {
    		return Label;
    	}
    
    	public void setLabel(String label) {
    		Label = label;
    	}
    
    	public String getTitle() {
    		return Title;
    	}
    
    	public void setTitle(String title) {
    		Title = title;
    	}
    
    	public String getDescription() {
    		return Description;
    	}
    
    	public void setDescription(String description) {
    		Description = description;
    	}
    
    	public String getURL() {
    		return URL;
    	}
    
    	public void setURL(String uRL) {
    		URL = uRL;
    	}
    
    	public String getEvent() {
    		return Event;
    	}
    
    	public void setEvent(String event) {
    		Event = event;
    	}
    
    	public String getEventKey() {
    		return EventKey;
    	}
    
    	public void setEventKey(String eventKey) {
    		EventKey = eventKey;
    	}
    
    	public String getMediaId() {
    		return MediaId;
    	}
    
    	public void setMediaId(String mediaId) {
    		MediaId = mediaId;
    	}
    
    	public String getFormat() {
    		return Format;
    	}
    
    	public void setFormat(String format) {
    		Format = format;
    	}
    
    	public String getRecognition() {
    		return Recognition;
    	}
    
    	public void setRecognition(String recognition) {
    		Recognition = recognition;
    	}
    
    	public String getTicket() {
    		return Ticket;
    	}
    
    	public void setTicket(String ticket) {
    		Ticket = ticket;
    	}
    }
    

    xml输出配置

    OutputMessage.java

    package com.wx.util;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    @XStreamAlias("xml")
    public class OutputMessage {
    
    	@XStreamAlias("ToUserName")
    	@XStreamCDATA
    	private String ToUserName;
    
    	@XStreamAlias("FromUserName")
    	@XStreamCDATA
    	private String FromUserName;
    
    	@XStreamAlias("CreateTime")
    	private Long CreateTime;
    
    	@XStreamAlias("MsgType")
    	@XStreamCDATA
    	private String MsgType = "text";
    
    	private ImageMessage Image;
    
    	public String getToUserName() {
    		return ToUserName;
    	}
    
    	public void setToUserName(String toUserName) {
    		ToUserName = toUserName;
    	}
    
    	public String getFromUserName() {
    		return FromUserName;
    	}
    
    	public void setFromUserName(String fromUserName) {
    		FromUserName = fromUserName;
    	}
    
    	public Long getCreateTime() {
    		return CreateTime;
    	}
    
    	public void setCreateTime(Long createTime) {
    		CreateTime = createTime;
    	}
    
    	public String getMsgType() {
    		return MsgType;
    	}
    
    	public void setMsgType(String msgType) {
    		MsgType = msgType;
    	}
    
    	public ImageMessage getImage() {
    		return Image;
    	}
    
    	public void setImage(ImageMessage image) {
    		Image = image;
    	}
    
    }
    

    图片消息支持

    MediaIdMessage.java

    package com.wx.util;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    public class MediaIdMessage {
    	@XStreamAlias("MediaId")
    	@XStreamCDATA
    	private String MediaId;
    
    	public String getMediaId() {
    		return MediaId;
    	}
    
    	public void setMediaId(String mediaId) {
    		MediaId = mediaId;
    	}
    
    }
    

    ImageMessage.java

    package com.wx.util;
    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    
    @XStreamAlias("Image")
    public class ImageMessage extends MediaIdMessage {
    }
    

    ok 以上配置完成后即可 编写post处理controller

    WxManagerController.java 

    修改后最终

    package com.controller;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.thoughtworks.xstream.XStream;
    import com.wx.util.ImageMessage;
    import com.wx.util.InputMessage;
    import com.wx.util.OutputMessage;
    import com.wx.util.SHA1;
    import com.wx.util.SerializeXmlUtil;
    import com.wx.util.WxMessageUtil;
    
    
    @Controller 
    @RequestMapping( "/wx" )
    public class WxManagerController {
    	
    	private String Token = "testfortoken";
    	
    	@RequestMapping(value = "", method = { RequestMethod.GET, RequestMethod.POST })
    	@ResponseBody
    	public void load(Model model, HttpServletRequest request, HttpServletResponse response) {
    		//判断访问方式
    		boolean isGet = request.getMethod().toLowerCase().equals("get");
    		if (isGet) {
    			//进行认证
    			access(request, response);
    		} else {
    			try {
    				//转码UTF-8,防止乱码
    				request.setCharacterEncoding("utf-8");
    				response.setCharacterEncoding( "utf-8" );
    				//处理微信post请求
    				acceptMessage(request,response);
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	/**
    	 * 验证URL真实性
    	 * 
    	 * @param request
    	 * @param response
    	 * @return String
    	 */
    	private String access(HttpServletRequest request, HttpServletResponse response) {
    		// 验证URL真实性
    		String signature = request.getParameter("signature");// 微信加密签名
    		String timestamp = request.getParameter("timestamp");// 时间戳
    		String nonce = request.getParameter("nonce");// 随机数
    		String echostr = request.getParameter("echostr");// 随机字符串
    		List<String> params = new ArrayList<String>();
    		params.add(Token);
    		params.add(timestamp);
    		params.add(nonce);
    		// 1. 将token、timestamp、nonce三个参数进行字典序排序
    		Collections.sort(params, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return o1.compareTo(o2);
    			}
    		});
    		// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
    		String temp = SHA1.encode(params.get(0) + params.get(1) + params.get(2));
    		if (temp.equals(signature)) {
    			try {
    				response.getWriter().write(echostr);
    				return echostr;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return null;
    	}
    	
    	private void acceptMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
    		// 处理接收消息
    		ServletInputStream in = request.getInputStream();
    		// 将POST流转换为XStream对象
    		XStream xs = SerializeXmlUtil.createXstream();
    		xs.processAnnotations(InputMessage.class);
    		xs.processAnnotations(OutputMessage.class);
    		// 将指定节点下的xml节点数据映射为对象
    		xs.alias("xml", InputMessage.class);
    		// 将流转换为字符串
    		StringBuilder xmlMsg = new StringBuilder();
    		byte[] b = new byte[4096];
    		for (int n; (n = in.read(b)) != -1;) {
    			xmlMsg.append(new String(b, 0, n, "UTF-8"));
    		}
    		// 将xml内容转换为InputMessage对象
    		InputMessage inputMsg = (InputMessage) xs.fromXML(xmlMsg.toString());
    
    		String servername = inputMsg.getToUserName();// 服务端
    		String custermname = inputMsg.getFromUserName();// 客户端
    		long createTime = inputMsg.getCreateTime();// 接收时间
    		Long returnTime = Calendar.getInstance().getTimeInMillis() / 1000;// 返回时间
    
    		// 取得消息类型
    		String msgType = inputMsg.getMsgType();
    		// 根据消息类型获取对应的消息内容
    		if (msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
    			// 文本消息
    			StringBuffer str = new StringBuffer();
    			str.append("<xml>");
    			str.append("<ToUserName><![CDATA[" + custermname + "]]></ToUserName>");
    			str.append("<FromUserName><![CDATA[" + servername + "]]></FromUserName>");
    			str.append("<CreateTime>" + returnTime + "</CreateTime>");
    			str.append("<MsgType><![CDATA[" + msgType + "]]></MsgType>");
    			str.append("<Content><![CDATA[您发送的是:" + inputMsg.getContent() + "?]]></Content>");
    			str.append("</xml>");
    			response.getWriter().write(str.toString());
    		}
    		// 获取并返回多图片消息
    		else if(msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
    			System.out.println("获取多媒体信息");
    			String mediaId = inputMsg.getMediaId();//多媒体文件id
    			String picUrl = inputMsg.getPicUrl();//图片链接
    			long msgId = inputMsg.getMsgId();//消息id,64位整型
    
    			OutputMessage outputMsg = new OutputMessage();
    			outputMsg.setFromUserName(servername);
    			outputMsg.setToUserName(custermname);
    			outputMsg.setCreateTime(returnTime);
    			outputMsg.setMsgType(msgType);
    			ImageMessage images = new ImageMessage();
    			images.setMediaId(mediaId);
    			outputMsg.setImage(images);
    			response.getWriter().write(xs.toXML(outputMsg));
    		}
    		//事件
    		else if (msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
    			// 事件类型
    			String eventType = inputMsg.getEvent();
    			if (eventType.equals(WxMessageUtil.EVENT_TYPE_SUBSCRIBE)) {
    				// 关注
    			}else if (eventType.equals(WxMessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
    				//取消关注
    			}else if(eventType.equals(WxMessageUtil.EVENT_TYPE_CLICK)){
    				//点击
    			}
    		}
    	}
    
    }
    

    启动测试,重新提交一下服务器认证。

    效果:

    完成,进行下一个功能 素材库管理

    三、素材库

    操作素材库需要 access_token 接口调用凭据,

    下面编写 access_token 方法。

    创建 AccessToken model

    AccessToken.java

    package com.wx.model;
    
    public class AccessToken {
    	// 获取到的凭证
    	private String token;
    	// 凭证有效时间,单位:秒
    	private int expiresIn;
    
    	public String getToken() {
    		return token;
    	}
    
    	public void setToken(String token) {
    		this.token = token;
    	}
    
    	public int getExpiresIn() {
    		return expiresIn;
    	}
    
    	public void setExpiresIn(int expiresIn) {
    		this.expiresIn = expiresIn;
    	}
    }
    

    想微信发起post请求必须使用https方式,所以需要编写配置https请求方式,证书配置如下,

    MyX509TrustManager.java

    package com.wx.util;
    
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.X509TrustManager;
    
    public class MyX509TrustManager implements X509TrustManager {
    	public void checkClientTrusted(X509Certificate[] chain, String authType) {  
    
        }  
    
    	public void checkServerTrusted(X509Certificate[] chain, String authType) {  
    
        }  
    
    	public X509Certificate[] getAcceptedIssuers() {  
    
    		return null;  
    
        }  
    }
    

    配置后编写处理https发起以及处理,和获取accesstoken方法

    WxManagerUtil.java

    package com.wx.util;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ConnectException;
    import java.net.URL;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    
    import com.alibaba.fastjson.JSONException;
    import com.alibaba.fastjson.JSONObject;
    import com.wx.model.AccessToken; public class WxManagerUtil { // 获取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 发起https请求并获取结果 * * @param requestUrl 请求地址 * @param requestMethod 请求方式(GET、POST) * @param outputStr 提交的数据 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) */ public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) { JSONObject jsonObject = null; StringBuffer buffer = new StringBuffer(); try { // 创建SSLContext对象,并使用我们指定的信任管理器初始化 TrustManager[] tm = { new MyX509TrustManager() }; SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); sslContext.init(null, tm, new java.security.SecureRandom()); // 从上述SSLContext对象中得到SSLSocketFactory对象 SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(requestUrl); HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection(); httpUrlConn.setSSLSocketFactory(ssf); httpUrlConn.setDoOutput(true); httpUrlConn.setDoInput(true); httpUrlConn.setUseCaches(false); // 设置请求方式(GET/POST) httpUrlConn.setRequestMethod(requestMethod); if ("GET".equalsIgnoreCase(requestMethod)) httpUrlConn.connect(); // 当有数据需要提交时 if (null != outputStr) { OutputStream outputStream = httpUrlConn.getOutputStream(); // 注意编码格式,防止中文乱码 outputStream.write(outputStr.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 InputStream inputStream = httpUrlConn.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader); String str = null; while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } bufferedReader.close(); inputStreamReader.close(); // 释放资源 inputStream.close(); inputStream = null; httpUrlConn.disconnect(); jsonObject = JSONObject.parseObject(buffer.toString()); } catch (ConnectException ce) { System.out.println("微信服务器连接超时!"); } catch (Exception e) { System.out.println("HTTPS请求错误,错误信息: " + e.getMessage()); } return jsonObject; } /** * 生成AccessToken * @param appid * @param appsecret * @return */ public static AccessToken getAccessToken(String appid, String appsecret) { AccessToken accessToken = null; String requestUrl = access_token_url.replace("APPID", appid).replace( "APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果请求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getIntValue("expires_in")); } catch (JSONException e) { accessToken = null; // 获取token失败 System.out.println("获取TOKEN失败("+jsonObject.getString("errcode")+")"); } } return accessToken; } }

    创建素材库model

    WxArticles.java

    package com.wx.model;
    
    public class WxArticles {
    	private String title; //标题
    	private String thumb_media_id;//图文消息的封面图片素材id
    	private String author;//作者
    	private String digest;//图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空
    	private String show_cover_pic;//是否显示封面,0为false,即不显示,1为true,即显示
    	private String content;//	图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS
    	private String content_source_url;//图文消息的原文地址,即点击“阅读原文”后的URL
    	public String getTitle() {
    		return title;
    	}
    	public void setTitle(String title) {
    		this.title = title;
    	}
    	public String getThumb_media_id() {
    		return thumb_media_id;
    	}
    	public void setThumb_media_id(String thumb_media_id) {
    		this.thumb_media_id = thumb_media_id;
    	}
    	public String getAuthor() {
    		return author;
    	}
    	public void setAuthor(String author) {
    		this.author = author;
    	}
    	public String getDigest() {
    		return digest;
    	}
    	public void setDigest(String digest) {
    		this.digest = digest;
    	}
    	public String getShow_cover_pic() {
    		return show_cover_pic;
    	}
    	public void setShow_cover_pic(String show_cover_pic) {
    		this.show_cover_pic = show_cover_pic;
    	}
    	public String getContent() {
    		return content;
    	}
    	public void setContent(String content) {
    		this.content = content;
    	}
    	public String getContent_source_url() {
    		return content_source_url;
    	}
    	public void setContent_source_url(String content_source_url) {
    		this.content_source_url = content_source_url;
    	}
    }
    

    完成以上基本OK。

    先写一个测试方法,提交图文素材 需要thumb_media_id 这个参数,即:图文消息的封面图片素材id(必须是永久mediaID)

    我们现在公众号里上传一个图片素材,然后去获取他的thumb_media_id后再 提交新的图文素材,这里使用用户发送消息来触发测试

     最终代码:

    WxManagerController.java

    package com.controller;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.eclipse.jdt.internal.compiler.batch.Main;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.alibaba.fastjson.JSONObject;
    import com.thoughtworks.xstream.XStream;
    import com.wx.model.AccessToken;
    import com.wx.model.WxArticles;
    import com.wx.util.ImageMessage;
    import com.wx.util.InputMessage;
    import com.wx.util.OutputMessage;
    import com.wx.util.SHA1;
    import com.wx.util.SerializeXmlUtil;
    import com.wx.util.WxManagerUtil;
    import com.wx.util.WxMessageUtil;
    
    
    @Controller 
    @RequestMapping( "/wx" )
    public class WxManagerController {
    	
    	private String Token = "CL0WQY79GJ12XV643BEZKMF5PHTAN";
    	
    	@RequestMapping(value = "", method = { RequestMethod.GET, RequestMethod.POST })
    	@ResponseBody
    	public void load(Model model, HttpServletRequest request, HttpServletResponse response) {
    		//判断访问方式
    		boolean isGet = request.getMethod().toLowerCase().equals("get");
    		if (isGet) {
    			//进行认证
    			access(request, response);
    		} else {
    			try {
    				//转码UTF-8,防止乱码
    				request.setCharacterEncoding("utf-8");
    				response.setCharacterEncoding( "utf-8" );
    				//处理微信post请求
    				acceptMessage(request,response);
    			} catch (IOException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	/**
    	 * 验证URL真实性
    	 * 
    	 * @param request
    	 * @param response
    	 * @return String
    	 */
    	private String access(HttpServletRequest request, HttpServletResponse response) {
    		// 验证URL真实性
    		String signature = request.getParameter("signature");// 微信加密签名
    		String timestamp = request.getParameter("timestamp");// 时间戳
    		String nonce = request.getParameter("nonce");// 随机数
    		String echostr = request.getParameter("echostr");// 随机字符串
    		List<String> params = new ArrayList<String>();
    		params.add(Token);
    		params.add(timestamp);
    		params.add(nonce);
    		// 1. 将token、timestamp、nonce三个参数进行字典序排序
    		Collections.sort(params, new Comparator<String>() {
    			@Override
    			public int compare(String o1, String o2) {
    				return o1.compareTo(o2);
    			}
    		});
    		// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
    		String temp = SHA1.encode(params.get(0) + params.get(1) + params.get(2));
    		if (temp.equals(signature)) {
    			try {
    				response.getWriter().write(echostr);
    				return echostr;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		return null;
    	}
    	
    	private void acceptMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
    		// 处理接收消息
    		ServletInputStream in = request.getInputStream();
    		// 将POST流转换为XStream对象
    		XStream xs = SerializeXmlUtil.createXstream();
    		xs.processAnnotations(InputMessage.class);
    		xs.processAnnotations(OutputMessage.class);
    		// 将指定节点下的xml节点数据映射为对象
    		xs.alias("xml", InputMessage.class);
    		// 将流转换为字符串
    		StringBuilder xmlMsg = new StringBuilder();
    		byte[] b = new byte[4096];
    		for (int n; (n = in.read(b)) != -1;) {
    			xmlMsg.append(new String(b, 0, n, "UTF-8"));
    		}
    		// 将xml内容转换为InputMessage对象
    		InputMessage inputMsg = (InputMessage) xs.fromXML(xmlMsg.toString());
    
    		String servername = inputMsg.getToUserName();// 服务端
    		String custermname = inputMsg.getFromUserName();// 客户端
    		long createTime = inputMsg.getCreateTime();// 接收时间
    		Long returnTime = Calendar.getInstance().getTimeInMillis() / 1000;// 返回时间
    
    		// 取得消息类型
    		String msgType = inputMsg.getMsgType();
    		// 根据消息类型获取对应的消息内容
    		if (msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
    			// 文本消息
    //			StringBuffer str = new StringBuffer();
    //			str.append("<xml>");
    //			str.append("<ToUserName><![CDATA[" + custermname + "]]></ToUserName>");
    //			str.append("<FromUserName><![CDATA[" + servername + "]]></FromUserName>");
    //			str.append("<CreateTime>" + returnTime + "</CreateTime>");
    //			str.append("<MsgType><![CDATA[" + msgType + "]]></MsgType>");
    //			str.append("<Content><![CDATA[您发送的是:" + inputMsg.getContent() + "?]]></Content>");
    //			str.append("</xml>");
    //			response.getWriter().write(str.toString());
    			AccessToken at = WxManagerUtil.getAccessToken("你的AppID", "你的AppSecret");	
    			String mediaId = getImgsFor(at.getToken());
    			addImgTest(at.getToken(),mediaId);
    		}
    		// 获取并返回多图片消息
    		else if(msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
    			System.out.println("获取多媒体信息");
    			String mediaId = inputMsg.getMediaId();//多媒体文件id
    			String picUrl = inputMsg.getPicUrl();//图片链接
    			long msgId = inputMsg.getMsgId();//消息id,64位整型
    
    			OutputMessage outputMsg = new OutputMessage();
    			outputMsg.setFromUserName(servername);
    			outputMsg.setToUserName(custermname);
    			outputMsg.setCreateTime(returnTime);
    			outputMsg.setMsgType(msgType);
    			ImageMessage images = new ImageMessage();
    			images.setMediaId(mediaId);
    			outputMsg.setImage(images);
    			response.getWriter().write(xs.toXML(outputMsg));
    		}
    		//事件
    		else if (msgType.equals(WxMessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
    			// 事件类型
    			String eventType = inputMsg.getEvent();
    			if (eventType.equals(WxMessageUtil.EVENT_TYPE_SUBSCRIBE)) {
    				// 关注
    			}else if (eventType.equals(WxMessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
    				//取消关注
    			}else if(eventType.equals(WxMessageUtil.EVENT_TYPE_CLICK)){
    				//点击
    			}
    		}
    	}
    	
    	public String getImgsFor(String token){
    		
    		//取第一个图片素材
    		String geturls = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token="+token;
    		String jsonval="{"type":"image","offset":"0","count":"1"}";
    		
    		JSONObject jsonObject = WxManagerUtil.httpRequest(geturls, "POST", jsonval);
    		
    		String result=null;
    		if (null != jsonObject) {
    			JSONObject josns =(JSONObject) jsonObject.getJSONArray("item").get(0);
    			result = josns.getString("media_id");
    		}
    		return result;
    	}
    	public void addImgTest(String token,String mediaId){
    		List<WxArticles> list = new ArrayList<WxArticles>();
    		WxArticles wxArticles = new WxArticles();
    		wxArticles.setTitle("a title");
    		wxArticles.setAuthor("a author");
    		wxArticles.setContent("a content");
    		wxArticles.setContent_source_url("a content_source_url");
    		wxArticles.setDigest("a digest");
    		wxArticles.setShow_cover_pic("a show_cover_pic");
    		wxArticles.setThumb_media_id(mediaId);
    		
    		list.add(wxArticles);
    		Map<String,List<WxArticles>> maplist = new HashMap<String,List<WxArticles>>();
    		maplist.put("articles", list);
    		
    		String urls= "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token="+token;
    		String jsons = JSONObject.toJSONString(maplist);
    		
    		JSONObject jsonObject = WxManagerUtil.httpRequest(urls, "POST", jsons);
    		String result=null;
    		if (null != jsonObject) {
    			result = jsonObject.getString("media_id");
    			System.out.println("返回("+result+")");
    		}
    		
    	}
    }
    

    上传永久素材成功!

    别忘了 填写自己的 appID 和appSecret;

    AccessToken at = WxManagerUtil.getAccessToken("你的AppID", "你的AppSecret");

    补充: 自定义菜单 功能;

    WxManagerController.java 下添加此方法

    private void accessMenu(String token){
    		
    		String menu = "{"button":[{"type":"click","name":"项目管理","key":"20_PROMANAGE"},{"type":"click","name":"机构运作","key":"30_ORGANIZATION"},{"name":"日常工作","sub_button":[{"type":"click","name":"待办工单","key":"01_WAITING"},{"type":"click","name":"已办工单","key":"02_FINISH"},{"type":"click","name":"我的工单","key":"03_MYJOB"},{"type":"click","name":"公告消息箱","key":"04_MESSAGEBOX"},{"type":"click","name":"签到","key":"05_SIGN"}]}]}";
    		String requestUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+token;
    		int result = 0 ;
    		JSONObject jsonObject = WxManagerUtil.httpRequest(requestUrl, "POST", menu);
    
    		if (null != jsonObject) {
    			if (0 != jsonObject.getIntValue("errcode")) {
    				result = jsonObject.getIntValue("errcode");
    				System.out.println("创建菜单失败("+result+")");
    			}
    			System.out.println("创建成功("+result+")");
    		}
    	}
    

      

    完成!

  • 相关阅读:
    java—连连看-实现封装
    java—连连看GUI
    连连看--产生随机数
    勇者斗恶龙
    在ctex环境下利用Metapost作图
    [leetcode] Binary Tree Postorder Traversal
    [leetcode] Binary Tree Maximum Path Sum
    [leetcode] Binary Tree Level Order Traversal II
    [leetcode] Binary Tree Level Order Traversal
    [leetcode] Binary Tree Inorder Traversal
  • 原文地址:https://www.cnblogs.com/mangyang/p/5396084.html
Copyright © 2020-2023  润新知