为什么sae上传了代码而java微信上传图片代码没有更新

053 微信公众平台开发教程第23篇SAE不支持XStream框架的解决方案
问题描述 最近几天(日之后),突然有不少网友反应,柳峰博客中的微信公众平台开发代码在SAE上运行会报错,或者是能正常部署,但向公众号发消息没反应。以前也有一些初学者质疑过我博客中的代码是否能正常运行,最后都被我一一证明是由于他们的不理解和粗心导致,但这一次短短几天就有很多人反应同样的问题,这就引起了我的足够重视。对于这种“同样的代码以前可以正常运行,现在却不能运行”的问题,我猜测可能是程序运行环境发生了某种变化,应该是SAE近期做了什么更新导致的。问题分析 如果Java Web项目中使用了日志工具log4j或者slf4j,并且设置了将日志输出到控制台(console),那么在项目部署到SAE之后,可以在SAE网站的“日志中心”看到应用的相关日志。查看HTTP服务error级别的日志,能够看到如下图所示的错误日志:
为了方便查看和讲解,我对上述错误日志进行了格式化处理,结果如下:101.226.62.83 [27/Aug/:10 +0800] JAVA_SAE_Fatal_error:
Error for /coreServletjava.lang.NoClassDefFoundError: Could not initialize class org.liufeng.weixin.util.MessageUtil
at org.liufeng.gywodejia.service.CoreService.processRequest(CoreService.java:40)
at org.liufeng.gywodejia.servlet.CoreServlet.doPost(CoreServlet.java:54)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:538)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:478)
at com.sina.sae.servlet.SaeServletHandler.doHandle(SaeServletHandler.java:49)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:517)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:225)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:937)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:406)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:871)
at com.sina.sae.webapp.SaeWebAppContext.doScope(SaeWebAppContext.java:166)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:259)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
at com.sina.sae.handler.SaeUserInfoHandler.handle(SaeUserInfoHandler.java:105)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:305)
at org.eclipse.jetty.server.handler.HandlerW yq36.javaruntime
从日志中的第二行可以看出,在访问/coreServlet时报了一个错误NoClassDefFoundError(类找不到),并且提示org.liufeng.weixin.util.MessageUtil类不能被实例化。在部署的WAR中,MessageUtil.class明明存在,为什么会找不到类呢?我们来看看,MessageUtil.java中到底都写了些什么,源代码如下:package org.liufeng.course.
import java.io.InputS
import java.io.W
import java.util.HashM
import java.util.L
import java.util.M
import javax.servlet.http.HttpServletR
import org.dom4j.D
import org.dom4j.E
import org.dom4j.io.SAXR
import org.liufeng.course.message.resp.A
import org.liufeng.course.message.resp.MusicM
import org.liufeng.course.message.resp.NewsM
import org.liufeng.course.message.resp.TextM
import com.thoughtworks.xstream.XS
import com.thoughtworks.xstream.core.util.QuickW
import com.thoughtworks.xstream.io.HierarchicalStreamW
import com.thoughtworks.xstream.io.xml.PrettyPrintW
import com.thoughtworks.xstream.io.xml.XppD
* 消息工具类
* @author liufeng
public class MessageUtil {
* 返回消息类型:文本
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&;
* 解析微信发来的请求(XML)
* @param request
* @throws Exception
@SuppressWarnings(&unchecked&)
public static Map&String, String& parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map&String, String& map = new HashMap&String, String&();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List&Element& elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream =
* 文本消息对象转换成xml
* @param textMessage 文本消息对象
* @return xml
public static String textMessageToXml(TextMessage textMessage) {
xstream.alias(&xml&, textMessage.getClass());
return xstream.toXML(textMessage);
* 音乐消息对象转换成xml
* @param musicMessage 音乐消息对象
* @return xml
public static String musicMessageToXml(MusicMessage musicMessage) {
xstream.alias(&xml&, musicMessage.getClass());
return xstream.toXML(musicMessage);
* 图文消息对象转换成xml
* @param newsMessage 图文消息对象
* @return xml
public static String newsMessageToXml(NewsMessage newsMessage) {
xstream.alias(&xml&, newsMessage.getClass());
xstream.alias(&item&, new Article().getClass());
return xstream.toXML(newsMessage);
* 扩展xstream,使其支持CDATA块
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata =
@SuppressWarnings(&unchecked&)
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write(&&![CDATA[&);
writer.write(text);
writer.write(&]]&&);
writer.write(text);
} MessageUtil是消息处理工具类,该类的代码大致可以分为以下3部分: 1)第33~91行:定义了若干常量,用于表示请求消息类型、事件类型和响应消息类型。 2)第93-124行:定义了一个parseXml()方法,通过dom4j工具解析微信服务器发来的xml格式的消息。 3)第126~187行:通过XStream工具将Java消息对象转换成xml。 很明显,问题应该不会出现在第1部分代码中,因为这段代码太平常不过了。我猜想,问题可能与第2、3部分代码中引用的第三方工具dom4j或XStream有关,会不会是SAE做了什么更新不支持dom4j或XStream了呢?要想证明也不难,写一个最简单的Java web工程,其中只用到dom4j或者只用到XStream工具,就能知道是哪里出了问题。好在我认识一个SAE官方的运营人员,就偷了个懒,直接咨询他,他帮忙问过SAE研发人员之后给出的答复是:XStream源码中通过反射机制使用到了sun.misc.Unsafe类,而该类因为安全原因被SAE禁用掉了,这就是为什么用到XStream的项目部署到SAE会报NoClassDefFoundError的原因。噢,原来是这么回事,知道原因了就总能找到解决方案。问题解决 XStream框架的作用是实现Java对象与XML的互相转换,SAE研发人员建议用其他有类似功能的框架替代,如Xerces、jdom或者dom4j,当然,这是一个很不错的建议,如果是在新的项目中,我肯定会这样做。但现在的问题是,如果真的用其他框架来替换XStream,可能要修改的不仅仅是MessageUtil一个类,这样的改动太大了,我也很难向这么多读者交待。正是出于这种考虑,让我想到了有没有可能通过修改XStream框架的源码来解决问题。 我在XStream官方网站上找到了xstream-1.3.1.jar对应的源码,导入到Eclipse,然后借助Eclipse强大的搜索功能,很快找到了使用sun.misc.Unsafe的类,我尝试将这些类删除或者修改它们的实现,避免使用sun.misc.Unsafe类,最终得到了一个新的jar包,我将其命名为xstream-1.3.1-sae-liufeng.jar,用它替换以前项目中使用的xstream-1.3.1.jar,最终项目再次顺利地运行在SAE上。 可能很多看到标题进来的读者,就是想知道这个问题是如何解决的,并不想听我哆嗦半天。授人鱼不如授人以渔,我之所以将问题的发现、分析和解决整个过程写出来,也是希望能够帮助更多初学者逐渐掌握自行解决问题的方法。 xstream-1.3.1-sae-liufeng.jar的下载地址:http://download.csdn.net/download/lyq。声明我提供的解决方案有些暴力,旨在帮助大家能够在SAE上继续测试学习微信公众平台开发,可能会影响到XStream的性能。如果是作为正式项目使用,在非SAE平台上运行公众平台程序,还是建议用XStream官方原本的jar。如果觉得博客的文章对你有所帮助,请通过留言或关注下方的微信公众账号来支持柳峰!
&转帖请注明本文出自柳峰的博客(http://blog.csdn.net/lyq8479),请尊重他人的辛勤劳动成果,谢谢!
> 本站内容系网友提交或本网编辑转载,其目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请及时与本网联系,我们将在第一时间删除内容!
问题描述 最近几天(日之后),突然有不少网友反应,柳峰博客中的微信公众平台开发代码在SAE上运行会报错,或者是能正常部署,但向公众号发消息没反应.以前也有一些初学者质疑过我博客中的代码是否能正常运行,最后都被我一一证明是由于他们的不理解和粗心导致,但这一次短短几天就有很多人反应同样的问题,这就引起了我的足够重视.对于这种&同样的代 ...
笔者在CSDN博客频道推出微信公众平台开发教程之后,接触了许多公众平台开发爱好者,也帮助他们解决了许多实际的问题,当然这其中有很多问题都是重复的,因此,笔者将这些问题及解答整理出来,以帮助更多初学者少走弯路.1.订阅号与服务号的主要区别是什么?订阅号每天能群发一条消息,没有自定义菜单及高级接口权限:服务号有自定义菜单及高级接口权限,但每月只能 ...
最近接触微信公众号后台的开发,看了一些资料基本可以满足简单的需求开发.笔者将这些问题及解答整理出来,以帮助更多初学者少走弯路. 欢迎加入群: 进行讨论相互交流
我的微信公众账号
图床:没有服务器 拖拽图片 外网即可访问http://2./home 1 ...
最近接触微信公众号后台的开发,看了一些资料基本可以满足简单的需求开发.笔者将这些问题及解答整理出来,以帮助更多初学者少走弯路. 欢迎加入群: 进行讨论相互交流
我的微信公众账号
图床:没有服务器 拖拽图片 外网即可访问http://2./home 1.订 ...
1.订阅号与服务号的主要区别是什么?订阅号每天能群发一条消息,没有自定义菜单及高级接口权限:服务号有自定义菜单及高级接口权限,但每月只能群发一条消息.2.到底该申请订阅号还是服务号?申请哪种类型的公众账号,主要取决于账号的用途.服务号主要面向企业和组织,旨在为用户提供服务:订阅号主要面向媒体和个人,旨在为用户提供信息和资讯.3.订阅号是否支持编程开发?不管是 ...
为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等,开发者在调用这些接口时,都需要传入一个相同的参数access_token,它是公众账号的全局唯一票据,它是接口访问凭证. access_token的有效期是7200秒(两小时),在有效 ...
为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等,开发者在调用这些接口时,都需要传入一个相同的参数access_token,它是公众账号的全局唯一票据,它是接口访问凭证. access_token的有效期是7200秒(两小时),在有效期内,可以一直使 ...
为了使第三方开发者能够为用户提供更多更有价值的个性化服务,微信公众平台开放了许多接口,包括自定义菜单接口.客服接口.获取用户信息接口.用户分组接口.群发接口等,开发者在调用这些接口时,都需要传入一个相同的参数access_token,它是公众账号的全局唯一票据,它是接口访问凭证. access_token的有效期是7200秒(两小时),在有效期内,可以一直使 ...SAE下CURL上传微信永久素材的问题,请大家帮帮忙! - ThinkPHP框架
sae下使用curl上传图片到微信永久素材,代码如下:&&&&$token&=&get_access_token();&&//&获取AccessToken
&&&&$url&=&&https://api./cgi-bin/material/add_material?access_token=&.$&//&微信上传API
&&&&$varname&=&'media';&&&&&//上传到$_FILES数组中的&key&&
&&&&$name&=&'abc.jpg';&&&&&//文件名&&
&&&&$type&=&'image/jpeg';&//文件类型
&&&&$key&=&&$varname\&;&filename=\&$name\r\nContent-Type:&$type\r\n&;&&
&&&&$re=new&SaeStorage();&//&关于SAE
&&&&$ss=$re-&read(&your_SaeStorage_domain&,&$name);&//&读取文件
&&&&$fields[$key]&=&$
&&&&$ch&=&curl_init($url);&&//&准备POST
&&&&curl_setopt($ch,&CURLOPT_POST,1);
&&&&curl_setopt($ch,&CURLOPT_POSTFIELDS,&$fields);
&&&&curl_setopt($ch,&CURLOPT_VERBOSE,1);
&&&&curl_setopt($ch,&CURLOPT_RETURNTRANSFER,1);
&&&&$responce&=&curl_exec($ch);&//&执行POST
&&&&dump($responce);微信返回结果为:{&errcode&:40113,&errmsg&:&unsupported&file&type&}请大家帮帮忙 看看是哪里的问题!
ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。开发微信公众平台-新建新浪云sae部署服务器 - 移动开发当前位置:& &&&开发微信公众平台-新建新浪云sae部署服务器开发微信公众平台-新建新浪云sae部署服务器&&网友分享于:&&浏览:238次开发微信公众平台--新建新浪云sae部署服务器创建新浪云计算应用
我们使用SAE新浪云计算平台作为服务器资源,并且申请PHP环境+MySQL数据库作为程序运行环境。
申请地址:百度搜sae&,使用新浪微博账号可以直接登录SAE,登录后SAE将赠送500个免费云豆。认证开发者送2000豆
够用很久的了
创建新应用&/txw1958/p/wechat-tutorial.html&
登录后点击顶部【我的首页】
点击下侧的创建新应用,这时会弹出提示, 禁止放置违法违规内容,点击继续创建,弹出如下窗口。
选择一个未使用的appid,如果老是已经被使用不知道该什么好,就填写你的QQ号或者手机号吧。
填写二级域名AppID、应用名称、验证码,开发语言选择PHP,应用类型选择web应用。然后点击创建应用
应用创建成功。并自动跳转到应用列表中,可以看到已经有刚才创建的应用,点击管理应用
创建版本&/txw1958/p/wechat-tutorial.html&
选择侧的应用管理下面的代码管理,
跳转到代码管理
点击右侧的
版本号默认为1,点击创建,成功后到这里,就成功创建了一个域名URL为&/&的应用了。
&原文:/txw1958/p/wechat-tutorial.html&
上传代码&/txw1958/p/wechat-tutorial.html&
将以下代码复制下来,选编辑代码,新建index.php。
请看另一篇文章:点击进入:
微信公众平台开发入门--PHP,实现自动回复文本,图文,点击事件
然后把代码复制进index.php ,就大功告成了。
记得进入微信后台:
登录微信公众平台后台,选择高级功能,进入后就看到两种模式,关闭编辑模式,开启开发模式
弹出URL和Token填写框:
url: /index.php&&
token:& mzh
然后就OK了。记得token改成自己的
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有关键字:Memcache&access_token 更新 存储 7200
本文介绍如何存储及更新 access token的方法。
access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。
公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在开发模式中获得(需要已经成为开发者,且帐号没有异常状态)。注意调用所有微信接口时均需使用https协议。
接口调用请求说明
http请求方式: GET
https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数是否必须说明
grant_type
获取access_token填写client_credential
第三方用户唯一凭证
第三方用户唯一凭证密钥,既appsecret
正常情况下,微信会返回下述JSON数据包给公众号:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
class class_weixin
var $appid = APPID;
var $appsecret = APPSECRET;
//构造函数,获取Access Token
public function __construct($appid = NULL, $appsecret = NULL)
if($appid && $appsecret){
$this-&appid = $appid;
$this-&appsecret = $appsecret;
//1. 数据库形式
DROP TABLE IF EXISTS `wx_token`;
CREATE TABLE IF NOT EXISTS `wx_token` (
`id` int(1) NOT NULL,
`type` varchar(20) NOT NULL,
`expire` varchar(16) NOT NULL,
`value` varchar(600) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `wx_token` (`id`, `type`, `expire`, `value`) VALUES
(1, 'access_token', '', 't3oyW9fRnOWKQHQhZXoEH-pgThhjmnCqTVpaLyUD'),
(2, 'jsapi_ticket', '', '');
$con = mysql_connect(MYSQLHOST.':'.MYSQLPORT, MYSQLUSER, MYSQLPASSWORD);
mysql_select_db(MYSQLDATABASE, $con);
$result = mysql_query("SELECT * FROM `wx_token` WHERE `type` = 'access_token'");
while($row = mysql_fetch_array($result))
$this-&access_token = $row['value'];
$this-&expires_time = $row['expire'];
if (time() & ($this-&expires_time + 3600)){
$url = "https://api./cgi-bin/token?grant_type=client_credential&appid=".$this-&appid."&secret=".$this-&
$res = $this-&http_request($url);
$result = json_decode($res, true);
$this-&access_token = $result["access_token"];
$this-&expires_time = time();
mysql_query("UPDATE `wx_token` SET `expire` = '$this-&expires_time', `value` = '$this-&access_token' WHERE `type` = 'access_token';");
//2. 缓存形式
if (isset($_SERVER['HTTP_APPNAME'])){
//SAE环境,需要开通memcache
$mem = memcache_init();
//本地环境,需已安装memcache
$mem = new M
$mem-&connect('localhost', 11211) or die ("Could not connect");
$this-&access_token = $mem-&get($this-&appid);
if (!isset($this-&access_token) || empty($this-&access_token)){
$url = "https://api./cgi-bin/token?grant_type=client_credential&appid=".$this-&appid."&secret=".$this-&
$res = $this-&http_request($url);
$result = json_decode($res, true);
$this-&access_token = $result["access_token"];
$mem-&set($this-&appid, $this-&access_token, 0, 3600);
//3. 本地写入
$res = file_get_contents('access_token.json');
$result = json_decode($res, true);
$this-&expires_time = $result["expires_time"];
$this-&access_token = $result["access_token"];
if (time() & ($this-&expires_time + 3600)){
$url = "https://api./cgi-bin/token?grant_type=client_credential&appid=".$this-&appid."&secret=".$this-&
$res = $this-&http_request($url);
$result = json_decode($res, true);
$this-&access_token = $result["access_token"];
$this-&expires_time = time();
file_put_contents('access_token.json', '{"access_token": "'.$this-&access_token.'", "expires_time": '.$this-&expires_time.'}');
//4. 实时拉取
$url = "https://api./cgi-bin/token?grant_type=client_credential&appid=".$this-&appid."&secret=".$this-&
$res = $this-&http_request($url);
$result = json_decode($res, true);
$this-&access_token = $result["access_token"];
$this-&expires_time = time();
阅读(...) 评论()

我要回帖

更多关于 新浪sae上传代码 的文章

 

随机推荐