java,异常Exception in thread "AWT-awt eventqueue 0-0" java.lang.NullPointerException

Java 命令行报错E xception in thread &main& java.lang.Unsupp_小组_ThinkSAAS
Java 命令行报错E xception in thread &main& java.lang.Unsupp
Java 命令行报错E xception in thread &main& java.lang.Unsupp
好久没有命令行了,今天用下
命令行出错Exception in thread"main"java.lang.UnsupportedClassVersionError: Filter(Unsupp
orted major.minor version 50.0).
一运行就报main 函数出错了,意思是没有找到main 函数的入口。可是代码正确啊。到Eclipse 下试试,一切正常,看来不是它的问题。
命令行下输入:javac -version 显示:javac 1.4.2...
-version 显示:java
编译和运行环境的版本怎么不一样,JDK 不是明明1.6 吗?装的是jdk 1.6 的怎么就变成1.4 了?
报错原来是用低版本的JDK编译高版本的.class就会报这个错
到环境变量查看了半天也没发现问题,忽然发现PATH中oracle中怎么是1.4.2 了,
C:Program FilesMySQLMySQL Server 5.0D:oracleproduct10.1.0Db_4D:oracleproduct10.1.0Db_4jre1.4.2D:oracleproduct10.1.0Db_4jre1.4.2%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32WC:Program FilesMicrosoft SQL Server90TC:Program FilesMicrosoft SQL Server80ToolsBC:Program FilesTortoiseSVN%JAVA_HOME%%Path%
改为:在PATH 最前面加上 %JAVA_HOME%
%JAVA_HOME%:Program FilesMySQLMySQL Server 5.0D:oracleproduct10.1.0Db_4D:oracleproduct10.1.0Db_4jre1.4.2D:oracleproduct10.1.0Db_4jre1.4.2%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32WC:Program FilesMicrosoft SQL Server90TC:Program FilesMicrosoft SQL Server80ToolsBC:Program FilesTortoiseSVN%JAVA_HOME%%Path%
再到DOS 下试试 ,OK !运行通过。
C:Documents and Settingsjoan&javac -version
javac 1.6.0_02
C:Documents and Settingsjoan&java -version
java version"1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing)
C:Documents and Settingsjoan&javac test.java
C:Documents and Settingsjoan&java test
C:Documents and Settingsjoan&
用户评论(0)
开发技术学习小组列表
PHP开发框架
缓存Memcache
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
手机客户端
ThinkSAAS接收任何功能的Iphone(IOS)和Android手机的客户端定制开发服务
让ThinkSAAS更好,把建议拿来。
iphone扫码下载客户端Exception in thread &main& java.lang.NullPointerException有关问题求教
&来源:读书人网&【读书人网():综合教育门户网站】
Exception in thread main java.lang.NullPointerException问题求教!下面是源代码出现的异常是Exception
Exception in thread &main& java.lang.NullPointerException问题求教!下面是源代码出现的异常是Exception in thread &main& java.lang.NullPointerExceptionat com.qq.server.db.Text10.&init&(Text10.java:58)at com.qq.server.db.Text10.main(Text10.java:39)58行是 jp2.add(jb2);,39行是Text10 text= new
Text10();求教这问题怎么解决??package com.qq.server.import javax.swing.*;import javax.xml.soap.Timport java.awt.*;import java.awt.event.*;import java.util.*;import java.sql.*;//完成一个迷你版的用户信息管理系统public class Text10
extends JFrame implements ActionListener{JPanel jp1,jp2;JLabel jl1; &
JButton jb1,jb2,jb3,jb4; &
JTJScrollPJTextFVector rowData, columnN//rowData用户来存放行数据//后者用来存放列明//操作需要定义的变量PreparedStatement ps=Connection ct =ResultSet rs=String url=&jdbc:sqlserver://127.0.0.1:1433;databaseName=QQ&;String user=&sa&;String passwd=&322008&;/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubText10 text= new
Text10();} public Text10(){&
jp1=new JPanel(); jtf=new JTextField(10); jb1 = new JButton(&查询&); jb1.addActionListener(this); jl1 = new JLabel(&请输入名字:&);&
jp1.add(jl1); jp1.add(jtf); jp1.add(jb1);&
jb2= new JButton(&添加&); jb3= new JButton(&修改&); jb4= new JButton(&注销&);& &
jp2.add(jb2); jp2.add(jb3); jp2.add(jb4);&
//中间//设置列名
columnNames=
new Vector();
columnNames.add(&号码&);
columnNames.add(&昵称&);
columnNames.add(&性别&);
columnNames.add(&密码&);
columnNames.add(&状态&);
rowData= new Vector();
//从读取数据
//1.加载驱动Class.forName(&com.microsoft.sqlserver.jdbc.SQLServerDriver&);ct=DriverManager.getConnection(url,user,passwd);ps=ct.prepareStatement(&select * from personalinfo &);rs=ps.executeQuery();while(rs.next()){Vector hang = new Vector();hang.add(rs.getString(1));hang.add(rs.getString(2));hang.add(rs.getString(3));hang.add(rs.getString(4));hang.add(rs.getString(5));rowData.add(hang);}
}catch(Exception e){
e.printStackTrace();
if(rs!=null)
rs.close();
if(ps!=null)
ps.close();
if(ct!=null)
ct.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
JTable( rowData,columnNames);
jsp= new JScrollPane(jt);
this.add(jsp);
this.add(jp1,&North&);
this.add(jp2,&South&);
this.setVisible(true);
this.setSize(500, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}[解决办法]jp2 没有new 所以是nulljp2.add(jb2);jp2.add(jb3);jp2.add(jb4);Chapter 18. Application servers and environments supported by Weld and
more info).The downside of javax.servlet.ServletContainerInitializer approach is
that the Weld listener will be added to the end of the ordered list of
discovered listeners. In practice the request and session context will
not be active during ServletRequestListener and HttpSessionListener
notifications. Fortunately, it’s possible to combine the
EnhancedListener and the old Listener to fix this problem - simply
add the old Listener to the web.xml as mentioned above. Note that it
must be defined before the listeners using request and session context.NoteThere is quite a special use-case where one more special component must
be involved. If you want the session context to be active during
HttpSessionListener.sessionDestroyed() invocation when the session
times out or when all the sessions are destroyed because the deployment
is being removed then org.jboss.weld.servlet.WeldTerminalListener must
be specified as the last one in your web.xml. This listener activates
the session context before other listeners are invoked (note that the
listeners are notified in reverse order when a session is being
destroyed)..Weld also supports Servlet and Filter injection in Jetty containers.
Listener injection should also work on Jetty 9.1.1 and newer versions.).
This mode may bring additional overhead during container bootstrap. Therefore, Weld Servlet supports the use of
bytecode scanning library to speed up the scanning process. Simply put the
on the classpath.
If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback.In general, an implicit bean archive does not have to contain a beans.xml descriptor. However, such a bean archive is not supported by Weld Servlet, i.e. it’s excluded from discovery.NoteThe bean discovery mode of annotated is supported from version 2.2.5.Final. Previous versions processed implicit bean archives in the same way as explicit bean archives.). This mode may bring additional overhead during container bootstrap.
Therefore, Weld Servlet supports the use of
bytecode scanning library to speed up the scanning process. Simply put the
on the classpath.
If Jandex is not found on the classpath Weld will use the Java Reflection as a fallback.In general, an implicit bean archive does not have to contain a beans.xml descriptor. However, such a bean archive is not supported by Weld SE, i.e. it’s excluded from discovery.NoteThe bean discovery mode of annotated is supported from version 2.2.0.Final. Previous versions processed implicit bean archives in the same way as explicit bean archives. . In addition, Weld comes with a sample application
called Paint which demonstrates how to use CDI with OSGi. Check
examples/osgi/README.md for more information.128133人阅读
微信5.0发布
日,伴随着微信5.0 iPhone版的发布,公众平台也进行了重要的更新,主要包括:
1)运营主体为组织,可选择成为服务号或者订阅号;
2)服务号可以申请自定义菜单;
3)使用QQ登录的公众号,可以升级为邮箱登录;
4)使用邮箱登录的公众号,可以修改登录邮箱;
5)编辑图文消息可选填作者;
6)群发消息可以同步到腾讯微博。
其中,大家议论最多的当属前两条,就是关于帐号类型和自定义菜单的更新,我这里做几点补充说明:
1)目前公众号类型分为两种:服务号和订阅号,8月5日平台更新后所有的帐号默认为订阅号,有一次转换成服务号的机会;
2)服务号主要面向企业、政府和其他组织,而订阅号主要面向媒体和个人;
3)只有服务号可以申请自定义菜单,订阅号不能申请;
4)服务号每月只能群发一条消息,而订阅号每天能群发一条消息。
平台更新后,让很多人纠结的是自定义菜单和每天群发一条消息不可兼得,对此,我不想过多评论。
引言及内容概要
在微信5.0以前,自定义菜单是作为一种内测资格使用的,只有少数公众帐号拥有菜单,因此出现很多企业为了弄到菜单不惜重金求购。现如今,一大批帐号从订阅号转为服务号,很多都是奔着自定义菜单去的。而且,经测试发现,微信最近的审核放松很多,只要申请服务号、自定义菜单的基本都成功了,根本不管填写的资料真伪。不知道以后微信会不会翻脸,要求补全企业资料,那将会是一种给小孩一颗糖吃再把他打哭的感觉。。。
自定义菜单是申请到了,到底该怎么创建、怎么使用呢?最近几天不管是微信官方交流群,还是在我博客留言里,都能够看到不少开发者都在为这个发愁。本篇文章就为大家解决这个难题。
自定义菜单的创建步骤
1、找到AppId和AppSecret。自定义菜单申请成功后,在“高级功能”-“开发模式”-“接口配置信息”的最后两项就是;
2、根据AppId和AppSecret,以https get方式获取访问特殊接口所必须的凭证access_token;
3、根据access_token,将json格式的菜单数据通过https post方式提交。
分析创建菜单的难点
原来创建菜单这么简单,三步就能搞定?跟把大象放冰箱差不多。呵呵,当然没有这么简单,那我们一步步来看,到底难在哪里?
首先,第1步肯定都没有问题,只要成功申请了自定义菜单,一定能拿到AppId和AppSecret这两个值。
再来看第2步,由于是get方式获取access_token,很多人直接把拼好的url放在浏览器里执行,access_token就拿到了。抛开是不是用编程方式实现的来说,这真是个好办法,显然大家在第二步上也没有问题。
最后再看第3步,拼装json格式的菜单数据,虽然繁锁一点,但基本上也都没有什么问题的,因为官方给了个例子,照猫画虎就行了。那问题一定就出现在https post提交上了。
结论:不知道如何创建自定义菜单的朋友,大都可以归为以下三种情况:
1)根本不看或者没看懂中关于“”、“”和“”部分的说明;
2)不知道如何发起HTTPS请求(平时的http请求,直接使用HttpUrlConnection就可以轻松搞定,但https请求要复杂一点);
3)不知道如何通过POST方式提交json格式的菜单数据。
正在看文章的你,不知道是属于哪一种,或者几种情况都有,不妨留言说出来,也可以做个调查。不管属于哪一种情况,既然看到了这篇文章,相信一定会让你弄明白的。
解读通用接口文档---凭证的获取
我们先来看的简介部分,如下图所示。
通俗点讲,这段简介可以这么理解:公众平台还有很多特殊的接口,像自定义菜单的创建、语音文件的获取、主动发送消息等,如果开发者想通过HTTP请求访问这些特殊接口,就必须要有访问凭证,也就是access_token。
那么,又该如何获取接口访问凭证access_token呢?让我们继续往下看。
图中已经表达的很清楚了,获取access_token是通过GET方式访问如下链接:
https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
链接中有三个参数,分别是grant_type、appid和secret。根据图中的参数说明,grant_type传固定值client_credential,而appid和secret就是申请完自定义菜单后微信分配给我们的。
请求发送成功后,微信服务器会返回一个json串,包含access_token和expires_in两个元素。其中,access_token就是我们最终需要的凭证,而expires_in是凭证的有效期,单位是秒,7200秒也就是2个小时。这就意味着,不是每次访问特殊接口,都需要重新获取一次access_token,只要access_token还在有效期内,就一直可以使用。
解读自定义菜单接口文档
还是一样,先来看看的简介部分,如下图所示。
从图中我们能够获取到以下信息:
1)拿到凭证access_token后,我们能对菜单执行三种操作:创建、查询和删除;
2)自定义菜单目前只支持click一种事件,即用户点击后回复某种类型的消息;不能够实现点击菜单项直接打开页面(type=view未开放,目前只是微生活有);
3)由于微信客户端缓存的原因,菜单创建后并不会立即在微信上显示出来,需要过24小时。在测试菜单创建时,可以通过取消关注后,再关注的方式达到立即看菜单的目的。
继续往下看,就是关于菜单怎么创建的介绍了,如下图所示。
其实就是向地址以POST方式提交一个JSON格式的菜单字符串。
后面,关于参数说明的部分我就不一一贴图说明了,把重点说一下:
1)自定义菜单是一个3x5结构的,即菜单最多只能有二级,一级菜单最多只能有3个,每个一级菜单下最多可以有5个二级菜单项;
2)菜单项都有一个key值。当用户点击某个菜单项时,微信会将该菜单项的key值以事件推送的方式发送给我们的后台处理程序。
关于菜单的查询、创建我就不提了,这两个接口使用的频率非常小,一般都用不上。如果需要,再按照我上面提供的思路也不难理解。
解读API文档之使用限制
很多小伙伴看到这张图就开始疑惑了:怎么菜单还限制使用次数,用户量越来越大的时候,根本不够用啊。看清楚,这个限制是针对接口调用的,也就是针对开发者的,和用户数、使用次数半点关系也没有。
就先拿获取凭证接口来说吧,限制一天只能调用200次。还记得前面提到过access_token是有有效期的,并且有效期为两小时,也就是获取一次access_token后的两小时内,都可以继续使用,那么理想情况一天24小时内,是不是只需要获取12次就够了?难道200次还不够用?
再来看下菜单创建接口限制一天只能调用100次。我就这么解释吧,菜单创建一次后,只要你不切换模式(指的是在编辑模式和开发模式间切换)、不调用删除接口,这个菜单会永远存在的。谁没事干,一天要创建100次菜单,就算是测试,测个10次8次足够了吧?
菜单的查询和删除接口的限制我就不解释了,至今为止这二个接口我都没使用过一次。就算有这样的使用需求,一天这么多次的调用,完全足够了。
封装通用的请求方法
读到这里,就默认大家已经掌握了上面讲到的所有关于自定义菜单的理论知识,下面就进入代码实战讲解的部分。
先前我们了解到,创建菜单需要调用二个接口,并且都是https请求,而非http。如果要封装一个通用的请求方法,该方法至少需要具备以下能力:
<span style="color:#)支持HTTPS请求;
<span style="color:#)支持GET、POST两种方式;
<span style="color:#)支持参数提交,也支持无参数的情况;
对于https请求,我们需要一个证书信任管理器,这个管理器类需要自己定义,但需要实现X509TrustManager接口,代码如下:
package org.liufeng.weixin.
import java.security.cert.CertificateE
import java.security.cert.X509C
import javax.net.ssl.X509TrustM
* 证书信任管理器(用于https请求)
* @author liufeng
public class MyX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
public X509Certificate[] getAcceptedIssuers() {
这个证书管理器的作用就是让它信任我们指定的证书,上面的代码意味着信任所有证书,不管是否权威机构颁发。
证书有了,通用的https请求方法就不难实现了,实现代码如下:
package org.liufeng.weixin.
import java.io.BufferedR
import java.io.InputS
import java.io.InputStreamR
import java.io.OutputS
import java.net.ConnectE
import java.net.URL;
import javax.net.ssl.HttpsURLC
import javax.net.ssl.SSLC
import javax.net.ssl.SSLSocketF
import javax.net.ssl.TrustM
import net.sf.json.JSONO
import org.slf4j.L
import org.slf4j.LoggerF
* 公众平台通用接口工具类
* @author liuyq
public class WeixinUtil {
private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
* 发起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 =
StringBuffer buffer = new StringBuffer();
// 创建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 =
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream =
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error(&Weixin server connection timed out.&);
} catch (Exception e) {
log.error(&https request error:{}&, e);
return jsonO
&代码说明:
1)41~50行:解决https请求的问题,很多人问题就出在这里;
2)55~59行:兼容GET、POST两种方式;
3)61~67行:兼容有数据提交、无数据提交两种情况,也有相当一部分人不知道如何POST提交数据;
Pojo类的封装
在获取凭证创建菜单前,我们还需要封装一些pojo,这会让我们的代码更美观,有条理。
首先是调用获取凭证接口后,微信服务器会返回json&#26684;式的数据:{&access_token&:&ACCESS_TOKEN&,&expires_in&:7200},我们将其封装为一个AccessToken对象,对象有二个属性:token和expiresIn,代码如下:
package org.liufeng.weixin.
* 微信通用接口凭证
* @author liufeng
public class AccessToken {
// 获取到的凭证
// 凭证有效时间,单位:秒
private int expiresIn;
public String getToken() {
public void setToken(String token) {
this.token =
public int getExpiresIn() {
return expiresIn;
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
接下来是对菜单结构的封装。因为我们是采用面向对象的编程方式,最终提交的json&#26684;式菜单数据就应该是由对象直接转换得到,而不是在程序代码中拼一大堆json数据。菜单结构封装的依据是公众平台API文档中给出的那一段json&#26684;式的菜单结构,如下所示:
&button&:[
&type&:&click&,
&name&:&今日歌曲&,
&key&:&V1001_TODAY_MUSIC&
&type&:&click&,
&name&:&歌手简介&,
&key&:&V1001_TODAY_SINGER&
&name&:&菜单&,
&sub_button&:[
&type&:&click&,
&name&:&hello word&,
&key&:&V1001_HELLO_WORLD&
&type&:&click&,
&name&:&赞一下我们&,
&key&:&V1001_GOOD&
首先是菜单项的基类,所有一级菜单、二级菜单都共有一个相同的属性,那就是name。菜单项基类的封装代码如下:
package org.liufeng.weixin.
* 按钮的基类
* @author liufeng
public class Button {
public String getName() {
public void setName(String name) {
this.name =
接着是子菜单项的封装。这里对子菜单是这样定义的:没有子菜单的菜单项,有可能是二级菜单项,也有可能是不含二级菜单的一级菜单。这类子菜单项一定会包含三个属性:type、name和key,封装的代码如下:
package org.liufeng.weixin.
* 普通按钮(子按钮)
* @author liufeng
public class CommonButton extends Button {
public String getType() {
public void setType(String type) {
this.type =
public String getKey() {
public void setKey(String key) {
this.key =
再往下是父菜单项的封装。对父菜单项的定义:包含有二级菜单项的一级菜单。这类菜单项包含有二个属性:name和sub_button,而sub_button以是一个子菜单项数组。父菜单项的封装代码如下:
package org.liufeng.weixin.
* 复杂按钮(父按钮)
* @author liufeng
public class ComplexButton extends Button {
private Button[] sub_
public Button[] getSub_button() {
return sub_
public void setSub_button(Button[] sub_button) {
this.sub_button = sub_
最后是整个菜单对象的封装,菜单对象包含多个菜单项(最多只能有3个),这些菜单项即可以是子菜单项(不含二级菜单的一级菜单),也可以是父菜单项(包含二级菜单的菜单项),如果能明白上面所讲的,再来看封装后的代码就很容易理解了:
package org.liufeng.weixin.
* @author liufeng
public class Menu {
private Button[]
public Button[] getButton() {
public void setButton(Button[] button) {
this.button =
关于POJO类的封装就介绍完了。
凭证access_token的获取方法
继续在先前通用请求方法的类WeixinUtil.java中加入以下代码,用于获取接口访问凭证:
// 获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = &https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET&;
* 获取access_token
* @param appid 凭证
* @param appsecret 密钥
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken =
String requestUrl = access_token_url.replace(&APPID&, appid).replace(&APPSECRET&, appsecret);
JSONObject jsonObject = httpRequest(requestUrl, &GET&, null);
// 如果请求成功
if (null != jsonObject) {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString(&access_token&));
accessToken.setExpiresIn(jsonObject.getInt(&expires_in&));
} catch (JSONException e) {
accessToken =
// 获取token失败
log.error(&获取token失败 errcode:{} errmsg:{}&, jsonObject.getInt(&errcode&), jsonObject.getString(&errmsg&));
return accessT
自定义菜单的创建方法
继续在先前通用请求方法的类WeixinUtil.java中加入以下代码,用于创建自定义菜单:
// 菜单创建(POST) 限100(次/天)
public static String menu_create_url = &https://api./cgi-bin/menu/create?access_token=ACCESS_TOKEN&;
* 创建菜单
* @param menu 菜单实例
* @param accessToken 有效的access_token
* @return 0表示成功,其他值表示失败
public static int createMenu(Menu menu, String accessToken) {
int result = 0;
// 拼装创建菜单的url
String url = menu_create_url.replace(&ACCESS_TOKEN&, accessToken);
// 将菜单对象转换成json字符串
String jsonMenu = JSONObject.fromObject(menu).toString();
// 调用接口创建菜单
JSONObject jsonObject = httpRequest(url, &POST&, jsonMenu);
if (null != jsonObject) {
if (0 != jsonObject.getInt(&errcode&)) {
result = jsonObject.getInt(&errcode&);
log.error(&创建菜单失败 errcode:{} errmsg:{}&, jsonObject.getInt(&errcode&), jsonObject.getString(&errmsg&));
调用封装的方法创建自定义菜单
package org.liufeng.weixin.
import org.liufeng.weixin.pojo.AccessT
import org.liufeng.weixin.pojo.B
import org.liufeng.monB
import org.liufeng.plexB
import org.liufeng.weixin.pojo.M
import org.liufeng.weixin.util.WeixinU
import org.slf4j.L
import org.slf4j.LoggerF
* 菜单管理器类
* @author liufeng
public class MenuManager {
private static Logger log = LoggerFactory.getLogger(MenuManager.class);
public static void main(String[] args) {
// 第三方用户唯一凭证
String appId = &000000&;
// 第三方用户唯一凭证密钥
String appSecret = &&;
// 调用接口获取access_token
AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);
if (null != at) {
// 调用接口创建菜单
int result = WeixinUtil.createMenu(getMenu(), at.getToken());
// 判断菜单创建结果
if (0 == result)
(&菜单创建成功!&);
(&菜单创建失败,错误码:& + result);
* 组装菜单数据
private static Menu getMenu() {
CommonButton btn11 = new CommonButton();
btn11.setName(&天气预报&);
btn11.setType(&click&);
btn11.setKey(&11&);
CommonButton btn12 = new CommonButton();
btn12.setName(&公交查询&);
btn12.setType(&click&);
btn12.setKey(&12&);
CommonButton btn13 = new CommonButton();
btn13.setName(&周边搜索&);
btn13.setType(&click&);
btn13.setKey(&13&);
CommonButton btn14 = new CommonButton();
btn14.setName(&历史上的今天&);
btn14.setType(&click&);
btn14.setKey(&14&);
CommonButton btn21 = new CommonButton();
btn21.setName(&歌曲点播&);
btn21.setType(&click&);
btn21.setKey(&21&);
CommonButton btn22 = new CommonButton();
btn22.setName(&经典游戏&);
btn22.setType(&click&);
btn22.setKey(&22&);
CommonButton btn23 = new CommonButton();
btn23.setName(&美女电台&);
btn23.setType(&click&);
btn23.setKey(&23&);
CommonButton btn24 = new CommonButton();
btn24.setName(&人脸识别&);
btn24.setType(&click&);
btn24.setKey(&24&);
CommonButton btn25 = new CommonButton();
btn25.setName(&聊天唠嗑&);
btn25.setType(&click&);
btn25.setKey(&25&);
CommonButton btn31 = new CommonButton();
btn31.setName(&Q友圈&);
btn31.setType(&click&);
btn31.setKey(&31&);
CommonButton btn32 = new CommonButton();
btn32.setName(&电影排行榜&);
btn32.setType(&click&);
btn32.setKey(&32&);
CommonButton btn33 = new CommonButton();
btn33.setName(&幽默笑话&);
btn33.setType(&click&);
btn33.setKey(&33&);
ComplexButton mainBtn1 = new ComplexButton();
mainBtn1.setName(&生活助手&);
mainBtn1.setSub_button(new CommonButton[] { btn11, btn12, btn13, btn14 });
ComplexButton mainBtn2 = new ComplexButton();
mainBtn2.setName(&休闲驿站&);
mainBtn2.setSub_button(new CommonButton[] { btn21, btn22, btn23, btn24, btn25 });
ComplexButton mainBtn3 = new ComplexButton();
mainBtn3.setName(&更多体验&);
mainBtn3.setSub_button(new CommonButton[] { btn31, btn32, btn33 });
* 这是公众号xiaoqrobot目前的菜单结构,每个一级菜单都有二级菜单项&br&
* 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?&br&
* 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:&br&
* menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 });
Menu menu = new Menu();
menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });
注意:在运行以上代码时,需要将appId和appSecret换成你自己公众号的。
整个工程的结构
为了保证文章的完整独立性和可读性,我是新建了一个Java Project(Java web工程也可以,没有太大关系),没有在前几篇文章所讲到的weixinCourse工程中添加代码。如果需要,读者可以自己实现将菜单创建的代码移到自己已有的工程中去。
图中所有Java文件的源代码都在文章中贴出并进行了说明,图中使用到的jar也是Java开发中通用的jar包,很容易在网上下载到。
工程中引入的jar包主要分为两类:
<span style="color:#)第一类是json开发工具包,用于Java对象和Json字符串之间的转换;json开发工具包一共有3个jar:ezmorph-1.0.6.jar,json-lib-2.2.3-jdk13.jar和morph-1.1.1.jar。
<span style="color:#)第二类是slf4j日志工具包,用于记录系统运行所产生的日志,日志可以输出到控制台或文件中。
整个工程中,唯一没有讲到的是src下的log4j.properties的配置,也把它贴出来,方便大家参考,这样才是一个完整的工程源码。log4j.properties文件的内容如下:
log4j.rootLogger=info,console,file
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-5p] %m%n
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern='-'yyyy-MM-dd
log4j.appender.file.File=./logs/weixinmpmenu.log
log4j.appender.file.Append=true
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%-5p] %d %37c %3x - %m%n
如何响应菜单点击事件
自定义菜单的创建工作已经完成,那么该如何接收和响应菜单的点击事件呢,也就是说在公众帐号后台处理程序中,如何识别用户点击的是哪个菜单,以及做出响应。这部分内容其实在教程的第5篇中已经讲解清楚了。
来看一下第一篇教程weixinCourse项目中的CoreService类要怎么改写,才能接收响应菜单点击事件,该类修改后的完整代码如下:
package org.liufeng.course.
import java.util.D
import java.util.M
import javax.servlet.http.HttpServletR
import org.liufeng.course.message.resp.TextM
import org.liufeng.course.util.MessageU
* 核心服务类
* @author liufeng
public class CoreService {
* 处理微信发来的请求
* @param request
public static String processRequest(HttpServletRequest request) {
String respMessage =
// 默认返回的文本消息内容
String respContent = &请求处理异常,请稍候尝试!&;
// xml请求解析
Map&String, String& requestMap = MessageUtil.parseXml(request);
// 发送方帐号(open_id)
String fromUserName = requestMap.get(&FromUserName&);
// 公众帐号
String toUserName = requestMap.get(&ToUserName&);
// 消息类型
String msgType = requestMap.get(&MsgType&);
// 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
// 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
respContent = &您发送的是文本消息!&;
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = &您发送的是图片消息!&;
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = &您发送的是地理位置消息!&;
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = &您发送的是链接消息!&;
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
respContent = &您发送的是音频消息!&;
// 事件推送
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get(&Event&);
if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {
respContent = &谢谢您的关注!&;
// 取消订阅
else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
// TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息
// 自定义菜单点击事件
else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {
// 事件KEY值,与创建自定义菜单时指定的KEY值对应
String eventKey = requestMap.get(&EventKey&);
if (eventKey.equals(&11&)) {
respContent = &天气预报菜单项被点击!&;
} else if (eventKey.equals(&12&)) {
respContent = &公交查询菜单项被点击!&;
} else if (eventKey.equals(&13&)) {
respContent = &周边搜索菜单项被点击!&;
} else if (eventKey.equals(&14&)) {
respContent = &历史上的今天菜单项被点击!&;
} else if (eventKey.equals(&21&)) {
respContent = &歌曲点播菜单项被点击!&;
} else if (eventKey.equals(&22&)) {
respContent = &经典游戏菜单项被点击!&;
} else if (eventKey.equals(&23&)) {
respContent = &美女电台菜单项被点击!&;
} else if (eventKey.equals(&24&)) {
respContent = &人脸识别菜单项被点击!&;
} else if (eventKey.equals(&25&)) {
respContent = &聊天唠嗑菜单项被点击!&;
} else if (eventKey.equals(&31&)) {
respContent = &Q友圈菜单项被点击!&;
} else if (eventKey.equals(&32&)) {
respContent = &电影排行榜菜单项被点击!&;
} else if (eventKey.equals(&33&)) {
respContent = &幽默笑话菜单项被点击!&;
textMessage.setContent(respContent);
respMessage = MessageUtil.textMessageToXml(textMessage);
} catch (Exception e) {
e.printStackTrace();
return respM
代码说明:
1)第69行、第81行这两行代码说明了如何判断菜单的点击事件。当消息类型MsgType=event,并且Event=CLICK时,就表示是自定义菜单点击事件;
2)第83行是判断具体点击的是哪个菜单项,根据菜单的key&#20540;来判断;
3)第85~109行表示当用户点击某个菜单项后,具体返回什么消息,我只是做个简单示例,统一返回文本消息,读者可以根据实际需要来灵活处理。
到这里关于自定义菜单的创建、菜单事件的判断和处理响应就全部介绍完了。我只希望看过文章的人不要只是拷贝代码,如果是这样,我完全不用花这么多的时间来写这篇文章,直接把工程放在下载区多简单。另外,网上是有很多工具,让你填入appid,appsecret和菜单结构,提交就能创建菜单,请慎用!因为appid和appsecret一旦告诉别人,你的公众号的菜单控制权就在别人手上了,总会有别有用心的人出来搞点事的。
如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号xiaoqrobot来支持柳峰!
转帖请注明本文出自柳峰的博客(),请尊重他人的辛勤劳动成果,谢谢!
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2524923次
积分:12549
积分:12549
排名:第385名
原创:55篇
评论:3697条
难度:高级
类型:技术教程
难度:高级
类型:实战教学
文章:22篇
阅读:1686198
(1)(2)(1)(2)(4)(1)(4)(3)(1)(5)(2)(6)(1)(1)(1)(1)(1)(15)(4)

我要回帖

更多关于 我的世界java.lang 的文章

 

随机推荐