wap开发

wap开发2001 年 7 月 12 日 如果您的企业已经依赖于使用多层的企业 Java 应用 那么您也许比想象中更接近无线科技的未来 通过描述一个样本应用 Aashish Patil 向您展示了如何用最少的

2001 年 7 月 12 日

如果您的企业已经依赖于使用多层的企业 Java 应用,那么您也许比想象中更接近无线科技的未来。通过描述一个样本应用,Aashish Patil 向您展示了如何用最少的人力物力把您现有的企业 Java 基础构件连接到无线网络中去。使用现有的 EJB、修改过的 Servlet 以及新的 WML 和 WMLScript 页面会使这个过程产生一个飞跃。如果您的企业已经依赖于使用多层的企业 Java 应用,那么您也许比想象中更接近无线科技的未来。通过描述一个样本应用,Aashish Patil 向您展示了如何用最少的人力物力把您现有的企业 Java 基础构件连接到无线网络中去。使用现有的 EJB、修改过的 Servlet 以及新的 WML 和 WMLScript 页面会使这个过程产生一个飞跃。

无线应用协议(Wireless Application Protocol,WAP)可以提高一个企业现有 Web 体系结构的含金量。如果您已经使用了企业 Java 应用,您可以容易地将它们与 WAP 服务集成,这样可以为移动工作群体带来有用的数据和功能。在这篇文章里,我会涉及到使用与 WAP 相关的 J2EE 的基本要素,然后创建一个 WAP/企业 Java 样本应用,以展示您如何把自己的 EJB 连接到无线网络中去。

背景:J2EE 和 WAP

在阅读本文前,您应该对 Java 2 平台,Enterprise Edition(J2EE)体系结构有个基本的了解。您可以通过下面的 参考资料章节找到关于 J2EE 的更多信息的链接。作为一个回顾,下面是一张为台式客户机设计的典型 J2EE 应用的示意图。

在图 1 中,包含 JavaServer Page(JSP)和 Servlet 的那一层负责生成动态 HTML 页面。而在 WAP 应用中,这一层将生成动态的无线标记语言(Wireless Markup Language,简称 WML)页面。因此,为了转换一个标准的 J2EE 应用使之为移动设备所使用,您将不得不编写新的 JSP,并且在某些情况下,还要编写新的 Servlet。企业 JavaBean(EJB)保持不变,因 为它们与数据表现无关。

wap开发
什么是 WML?

正如 Web 浏览器显示 HTML 编码的数据一样,支持无线标记语言(WAP)的设备显示 WML 编码的数据;另外,正如 Web 开发人员使用 JavaScript 把脚本功能嵌入到 Web 页面一样,设备开发人员使用 WMLScript 把同样的功能嵌入到 WML 页面中。WML 是 XML 的一个子集,而对于精通 HTML 或其它标记语言的人来说它看起来很眼熟。WML 有一个独一无二的特征需要牢记:它像 一盒卡片;一个单一的 HTML 文档显示成一个单一的 Web 文档,而一个单一的 WML 文档可以包含很多卡片。WAP 设备的屏幕一次只能显示一张卡片。关于一些 WML 和 WMLScript 的链接可以参阅下面的 参考资料章节。


有些人认为 Servlet 无需更改,或者说:只要把 Servlet 的输出简单地重定向到生成动态 WML 页面的 JSP 上就已经足够了。然而,Servlet 不能区别从台式机和从 WAP 设备发来的请求;既然 WAP 应用可能无法实现基于 Web 的体系结构的所有功能,所以在这方面并没有混淆的地方,这一点很重要。也正由于此,开发人员通常为 WAP 应用设计新的 Servlet。然而在大多数情况下,这些 Servlet 与那些在基于 Web 的体系结构上提供类似功能的 Servlet 非常相似。

在图 1 中没有出现但对 WAP 应用又很重要的另一个组件是 WAP 网关。这个组件负责 WAP 栈和 Internet 栈之间的相互转换。

图 2 是图 1 的改进版,显示了使用 WAP 设备作为客户端的 J2EE 应用的结构:

按照图示,所有自 WAP 客户端到 Web 服务器的请求必须通过 WAP 网关发送。尽管 WAP 网关也可以作为放置 WML/WMLScript 页面的 WAP 服务器,但使用 Web 服务器来放置这些页面更为方便。

有很多 WAP 网关的部署方法。对于多数 WAP 应用来说,网关或由 ISP 部署,或由提供这个应用的公司来部署。后者更为安全,我们以后会解释;然而,如果用户要求在他们的 WAP 设备上进行多用途的网络访问,一个内部的 WAP 网关会很不方便。大多数非 ISP 不希望他们的网关被用来访问他们自己站点以外的其他站点;因此,为了访问其他站点,用户将不得不使用 ISP 网关。但对于被 WAP 客户端使用的每一个网关来说,用户都必须定义一个不同的连接,正如 Windows 98 的拨号网络一样 ― 而且在每个设备上,这样连接的数目通常是有限的。这就增加了用户的不便性,并且在访问一个站点时造成 WAP 设备中的连接阻塞。

wap开发
wap开发
wap开发

wap开发
 
回页首


 

WAP 应用设计的考虑事项

当使用 WAP 时,一个习惯为台式客户机编写 J2EE 应用的开发人员会遇到一些新的挑战。以下是在构建 WAP 应用时您也许会碰到的一些问题。

我可以在屏幕上显示几行信息?
事实上,对显示多少行没有特别限制,只要不超过面板的最大尺寸就行(随设备的不同而不同)。然而,为了避免太多滚屏,每屏(即卡片)5 至 7 行最佳。

我应该考虑哪些安全问题?
一些电话不支持使用 POST 方法发送表单数据。因此,用户名和密码必须通过 GET 方法发送。在 WAP 网关上,如果日志功能被激活并且请求已被记录,管理员就有能看到用户名和密码。如果网关是由 ISP 或其它第三方提供的,这个问题就会特别突出。

即使一个安全的连接也不能完全消除安全隐患。那些发送到 WAP 网关的数据使用 WTLS(Wireless Transport Layer Security)加密,它使用与标准 TLS 相同的算法。然而,发送到 WAP 网关的数据是二进制的编码格式(对 WAP),所以这些加密后的数据必须用 TLS 解密和再加密以适用于因特网。经过一段时间以后,敏感数据在 WAP 网关上以明文的形式出现。黑客则会在适当的时刻,将内存中的信息转储出来,进而成功地访问这些敏感数据。

按照注释,解决该问题的一种办法是在自己公司(而不是在 ISP)设一个 WAP 网关。在这种情况下,一个可信的人可以操作网关,并且可以关闭日志功能。

您也可以用 WMLScript 来编写自定义的加密算法,以对客户端的用户名和密码进行加密。这只有在使用简单的算法时才有可能实现;在支持 DES 类的算法上,WMLScript 不够强大。

我怎样保持 Session?
WAP 客户端不支持 Cookie。这样,当用户在您的站点的不同页面之间穿梭时,为了在服务器端保留关于客户端的信息,在向服务器发送每个请求的同时,一个 Session ID 必须被当作参数传递。Session ID 的参数名根据 Servlet 引擎的不同而不同。

有时,缺省的 Session ID 长度很大幅度地增加了每个请求的长度。结果导致客户端或 WAP 网关可能将此请求看作一个无效的 URL 而拒绝。这样有必要缩短 Session ID 的长度。请查看一下您正在使用的 Servlet 引擎的说明文档中关于 Session ID 参数名的部分。如果您碰到过无效 URL 的错误,这个说明文档也应提供有关缩短 Session ID 值长度的指南。

wap开发
wap开发
wap开发

wap开发
 
回页首


 

构造样本应用

XYZ Ltd. 是一家生产 PDA,可佩戴的计算机,及其它普及计算设备的公司。公司的销售人员拜访客户,提供 XYZ 产品的现场演示;某些演示要求销售人员必须跑很远的路去客户那里。那么在路上,他们是怎么收到客户列表和其它重要数据的呢?

为此使用电子邮件会需要体积较大且昂贵的便携式电脑或无休止的 Internet caf?s 的搜索;在客户端使用传真机则更不切实际。取而代之的是 XYZ 的销售人员会通过支持 WAP 功能的设备接收数据,例如手机或 PDA。使用移动设备,销售人员能在拜访客户时向公司提供及时的反馈。公司就能马上安排给客户及时发货并维护目前的销售统计信息。

我们的应用有两个主要目标。首先,我们流动的销售人员应该能使用它在 WAP 设备上查看客户列表。第二,如果一个客户希望买货,那么销售人员应能使用设备来下订单。此外,任何 WAP 应用的一个重要目标应该是减少用户必要的按键数目。由于受手持设备的用户界面限制,用户需要输入的数据量应控制在最少。

这是一张显示我们系统的体系结构的流程示意图

用户首先必须登录以访问系统;然后他们能浏览客户列表和每个客户的详细信息。如果他们希望为某一特定的客户下订单,那么系统会提供他们一个产品列表,他们可以从中为该客户选择一个特定的产品。

在本文余下的大多数内容中,我们会讨论实现该应用的 Servlet 和 JSP 代码,并会考察 JSP 和 Servlet 一起工作的方式。关于每个 JavaServer Page 的讨论还配有图解,显示了 JSP 在设备屏幕上的输出。

清单 1, Login.jsp 接受用户名和密码,并把它们作为参数来调用 LoginServlet 。对这个和其它所有的 JSP 来说,MIME 类型都应被设置成 text/vnd.wap.wml 类型。在传递请求的同时,上面的 Login.jsp 还传递了一个叫 SessionID 的参数。它必须与每个传送到服务器的请求一起传递。参数名 SessionID 是一个占位符;请参考应用服务器的说明文档,找到适用于您特定的应用服务器的正确的参数名。Java 方法 HttpServletResponse.encodeURL(String URL) 自动添加 Session ID;在我们的应用里,这已经被广泛地使用在 Servelet 中。

验证空白的输入域时会出现问题。在 input 标记里有一个属性,它让您使输入域不为空:

emptyok=”false”/>

 

一个手机用户必须访问各个独立的对话框屏幕去输入数据。问题出现了,因为用户宁愿选择直接访问下一盒或下一张卡片而不愿通过对话框屏幕去输入数据。一个用户面对如图 4 所示的屏幕时也许会遗漏密码并揿下 NEXT。

一个开发人员可以通过使用 WMLScript 的验证来避免这个问题的发生(通过使用 onclick 事件)。然而,直到输入一个值到输入框以后,您传递到 WMLScript 函数的代表输入域值的那个变量才开始被初始化。因此,若无密码键入,传递到该函数的是未初始化的变量和脚本错误结果。这个问题的解决方法是在服务器端验证所有的输入域。

清单 2, LoginServlet 是我们问题的解决方案:它可以认证销售人员,并把他记录在系统中。它也可以在服务器端为销售人员创建一个 Session。代码块上的注释指明了在哪里这些操作会被执行。一旦成功登录,设备显示如清单 3 所示的主菜单( MainMenu.jsp )。

如图 5 所示,该文件将两个链接显示在设备屏幕上。其中第二个终止了当前的 Session;第一个指向当前的客户列表。在当前版本的程序流程中,销售人员必须在开始任何销售交易之前先从列表中选择一个客户;有关销售产品的列表只能在后继的屏幕上显示(后面将会讨论到细节)。也有其它可能的程序流:举例来说,用来直接将用户送到产品列表的链接可以被加到主菜单中。但是,您不应该在任一菜单中提供太多链接,否则支持 WAP 的设备的小屏幕会因此而变得混乱不堪。

在图 5 的主菜单中揿下 View Clients 将调用清单 4 中的 ClientViewServlet ,它抽取销售人员将要拜访的客户列表。代码上的注释说明了 Servlet 怎样从客户端上找到该信息。接着 Servlet 将列表放到 Session 对象中并调用 ClientList.jsp 。(这里和下一段中提到的 Session 对象是来自于 Java servlet 包中的 HttpSession 类。)

清单 5, ClientList.jsp 抽取由 ClientViewServlet 放置在 Session 中的客户列表;它显示了客户的姓名,但不是完整的详细信息(请参见图 6)。当选择一个用户时,销售人员则被定向到 ClientDetails.jsp 。

注意:显示客户列表的任务由三个独立的部分完成 ― ClientViewServlet 、 ClientList.jsp 和 ClientDetails.jsp 。这样设计的原因是什么呢?

  1. 大多数 J2EE 架构的权威人士建议 JSP 不应该直接访问 EJB;而应使用诸如 Servlet 的中间件来进行与 EJB 的交互。 ClientViewServlet 访问 EJB 并获得客户列表。
  2. 这个应用本可以如此设计,这样所有的用户信息都会包含在一个单一的 WML 文档中。在这个体系结构中,客户列表包含在 WML 盒中的一张卡片上,而单个客户的详细信息会包含在同一盒中的不同卡片上。不过该单一文档可能包含太多数据,以至于对一个低带宽的 WAP 设备来说不能立刻下载。如果客户数目过于庞大,所生成的数据总量很容易超过 WML 卡片盒所允许的最大容量。(最大容量随设备不同而有所区别;如 Nokia 7110 的最大编译卡片盒容量为 1.3 KB)。因此我们使用两个 JSP: ClientList.jsp ― 显示客户列表,还有 ClientDetails.jsp ― 显示单个客户的详细信息。

清单 6, ClientDetails.jsp 接受客户数组的索引号作为参数,其中索引号在 Session 中出现。接下来它抽取所选客户的详细信息并显示。如果销售人员希望为该客户下订单,他只要揿下 Items 按钮。这会调用清单 7, ItemListServlet ,并且显示该订单的可选产品。

清单 7, ItemListServlet 抽取销售人员可以销售的产品列表,并将列表置于 Session 中。然后它调用清单 8, ItemList.jsp

清单 8, ItemList.jsp 从 session 中抽取产品列表并显示产品名称。销售人员可选择一个产品去订货并揿下 Order 按钮去调用 PlaceOrder.jsp 。数组中所选产品的索引被作为参数送到清单 9, PlaceOrder.jsp

PlaceOrderServlet 从 Session 中获得销售人员、客户及产品的 ID。接着通过创建新的 Order Entity EJB 可以产生一个新的订单。成功的下单显示了订单的 ID 和下订单的时间。

在这一版本的应用中,销售人员在完成交易后的唯一选择便是返回主菜单(请参见图 9)。您也可修改代码以便使用户返回到客户或产品列表。

如果注意观察,您会发觉销售人员只输入两次数据:登录时和为客户输入购买产品数量时。

wap开发
wap开发
wap开发

wap开发
 
回页首


 

关于代码

附带文件包含本文所有的 JSP 和 Servlet 代码,也包含必需的 EJB 代码。EJB 的 jar 文件和部署描述符也一起包含在内。所有屏幕截图均来自 Nokia WAP 模拟器 2.0 版。

wap开发
wap开发
wap开发

wap开发
 
回页首


 

结论

就像前面提到的那样,WAP 应用提供了非常好的增值服务。一个孤立的 WAP 应用是不可取的。然而,这样一个应用无需花费很多财力人力就可以方便地集成到一个现有的 Web 应用体系结构中去。您所需要的唯一新硬件是一台机器,以及用于 WAP 网关的软件;如果您使用的是自己 ISP 的网关,那么这项开销也可省去了。

现有的 HTML 页面需要被转换成 WML。然而,WML 不像 HTML 那么复杂,因为它不支持 HTML 的许多功能。因此,这并不是一件费时的工作。

WAP 也支持无线 BitMap(WBMP)格式的图片。然而,使用 WAP 设备的用户在连接时间上花费了不少钱,他们更感兴趣的是直接有效的信息而非奢华的界面。除非图片本身能传递信息,否则提供快速的信息比占用带宽和时间来传输图片会更好。

最后注意事项:尽管模拟器可以提供测试 WAP 应用的良好环境,但只有当它配合已部署好的 WAP 网关,运行在所有可能的目标 WAP 设备上时,WAP 应用才算作真正意义上的被完全测试过了。所有动态生成的页面在网关上被编译。因此,有必要知道您的网关支持哪些版本的 WAP。如果网关编译器只使用 WML 1.1,那么用 WML 1.2 编写的页面是毫无用处的。

参考资料

关于作者

wap开发

 

wap开发

Aashish Patil 不久前刚获得印度 Mumbai 的 Thadomal Shahani 工程技术学院的计算机工程系学士学位。在 Tata Consultancy Services,他作为实习生完成了一个关于支持 WAP 的股票交易的项目;本文是该项目的一个直接部分。今年秋季,他将赴 Southern California 大学攻读计算机科学系的硕士学位。可通过 ash01@vsnl.net 联系 Aashish。

 

WAP经验总结

包括WAP1.2和WAP2.0,包括移动和联通,对各款手机对WML和XHTML支持的一个总结

移动全网:

2006-02-06

只有订购过的用户,移动才会引导到MISC平台里来,否则直接导向SP的链接;

移动上线测试:



采用refresh重定向如果程序里设置了背景,那么将会出现一个带背景的空白屏幕一小会,可在跳转的时候将背景去掉;采取timer跳转看起来比较正常;

移动MISC返回错误:

 

一下方法是经过验证的。

例如  URL:wap.gd.monternet.com/?userType=B&serviceID=04020028 提示信息:神秘激情地带,江湖儿女情长神秘激情地带,江湖儿女情长神秘激情地带,江湖儿女情长
第一包:
0B05040B8423F00000403AE81EA02056A0045C60C0E67642E6D6F6E74657
26E65742E636F6D2F3FD3D0
070103E7A59EE7A798E6BF80E68385E59CB0E5B8A62CE6B19FE6B996E584BFE5A5B3E68385E995BF
E7A59EE7A798E6BF80E68385E59CB0E5B8A62C 
第二包:
0B05040B8423F0000E6B19FE6B996E584BFE5A5B3E68385E995BFE7A59EE7A798E6BF80E6
8385E59CB0E5B8A62CE6B19FE6B996E584BFE5A5B3E68385E995BF000101 ,解释可参考WDP WSP,我就不具体说了







如果长度超常(短信一个包的Content不要超过140)

就要分解成

 

 

如果所有这些加起来大于140个字节,那么就需要修改UDH头,分成两条短消息串联。但是没有尝试成功。

同样的技术可以用来发送mms通知、fundown的铃声图片。

需要解决的问题:长于127字节/两条短信的时候该怎么办。

 

另转载 Wap push over sms 实践  

浏览器不支持默认的meta标签,例如:


 

最常使用的META是:


 

这个告诉浏览器重新装入指定的WML页面。WML中已经包含了一个


39. 为什么服务器接收不到用户发送的参数?

用户输入的参数或者其他参数可以像在HTML中一样通过提交方式发送到服务器。在HTML中这个是

,POST或者GET。

首先知道要知道POST和GET的区别。对于POST浏览器将生成一个数据包将变量名和它们的内容捆绑在一起,并发送到服务器。对于GET,它其实是一个URL请求,变量名和内容都包含在URL中。
对于WAP环境,要求是非常严格的,必须要根据协议来操作。虽然以下的URL

“/cgi-bin/somescript?username=john&telephone=123-123-1234&occupation=banana+bender”

“/cgi-bin/somescript?username=john&telephone=123-123-1234&occupation=banana+bender”

在这里 & 被名字实体所替换。为了解释更清楚些,请看下面的代码:



 

 

注意这不是真正的WAP协议,专门的字符应该转义,否则将得到不可预料的结果。

40. 为什么在HTTP中的Referer看不见?

 

这样就会把参考的URL发送到服务器。

41. 如果没有找到URL,有可能重新将用户引导到另外一个WML卡片或者页面吗?

是的。但这是服务器端的特点,与客户端没有关系。

42. 为什么普通的HTTP 302重新导向不好使?

这的确是一个事实。核心的问题是在服务端的脚本语言,而不是在服务端语言和服务器之间。
所谓的302 Found HTTP反应是指服务器告诉用户代理,它所需要的资源在另外的地方可以找到。302反应可能包括一个人们可理解的信息,如果在这种情况下“ Content-type: ”就被设置了
。笔者所测试过的服务器,即使没有内容也都加了“Content-type:”。默认的 “Content-type:” 是text/html。当然有些网关不喜欢这个类型。
以下的例子已经经过测试,在Apache和Microsoft Internet Information Server都可以工作。如果使用其他的Web Server,或者其他的脚本语言,需要能转换这些简
单的脚本。关键的工作是十分简单的,除非需要,不用告诉服务器整个HTTP头。大多数Web Server将自动完成这个HTTP头,使得用户代理可以理解。
所有的代码例子可以在线测试。如果它们能够工作,用户将被重新引导到




http://wap.colorline.no/clientinfo.html ,在那儿将产生一个WML页面来显示所有的HTTP头。
PHP 代码测试可以在 http://wap.colorline.no/wap-faq/apps/302test.php3中找到。

    header(“Location: http://wap.colorline.no/clientinfo.html“);
    header(“Content-type: text/vnd.wap.wml”;
?> 

Perl测试代码可以在http://wap.colorline.no/cgi-bin/302test.pl中找到。 

print “Location: http://wap.colorline.no/clientinfo.html/n“;
print “Content-type: text/vnd.wap.wml/n”; 

ASP测试代码可以在 http://www.colorline.no/302test.asp中找到。 (注意不同的URL): 

43. 可能在WML中实现ASP Session吗?

44. WAP支持Session吗?

http://wap.colorline.no/wap-faq/archive/phplib_wml.zip
45. 可以在WAP中使用Cookies吗?

在理论上是可以的,但不是所有的WAP设备都支持。另一个方法来管理会话是使用隐藏的fields(包含会话标识,无论是POST或者GET方式)。

46. WAP支持Cookies吗?

 



Increase value

     

To:

     

Subject:

     

Message body:

     
  
 

在代码中的http://some.host/mailhandler是一个CGI程序,它是服务端的脚本程序,将提交的表单转换成E-Mail格式并发送出去。
如果想使用一个类似于发信的过程,就需要编辑变量名。另外发送的数据是有限的,长信息可能需要打断。
为了演示它是如何工作的,下面的 PHP 脚本可以用来处理Mail。它将格式化WML页面,告诉用户是否发出信件。在真实的应用中,应该加入检测,例如:E-Mail的合法格式。

Mail was sent successfully

/n”);
      echo(“/n”);
    }
    else {
// The mail could not be sent
      echo(”

/n”); 

      echo(”

Unable to send mail

/n”);
      echo(“/n”);
    }
    echo(“/n”);
?>

因为安全性的原因,以上的代码没有演示程序。

48. 可以在模拟器上操作本地的页面,却没有办法访问Internet上的,有什么问题吗?

49. 什么是PUSHing,它是如何工作的?

50. WAP模拟器说text/html不支持,但是用户的MIME设置是正确的,为什么?

51. 在哪儿有Visio移动电话的模板库?

目前唯一知道的就是它包含在 Nokia 7110 中。

52. 有没有其他有用的WML内容服务列表?

53. XML到XSL的转换可以应用到WML和WAP吗?

54. 想让用户只要简单地按下一个按钮就能够转跳到其他卡片而不是通过选择URL,这个可能吗?

不,不可能。

55. 如何避免一个行的中断以便可以在一行中输入多个链接?

在Nokia 7110中,不可能做到这一点,每个链接都占据自己的一行。

下面是使用WebClasses(VB)的例子。使用”Response.Expires=-1″,防止Cache。

这里有一个ASP的例子,同样使用“Response.Expires=-1”防止Cache。

最后是使用META的例子:

This deck will never be stored in the cache

   
 

下面的页面是在经过86400秒(24 hours)后过期。

This card will live in the cache for a day

   
 

有些浏览器例如:UP.Simulator如果可以通过“返回”达到另外一个卡片,那么它将不会重新装载卡片。为了强制这个更新动作,用户必须在META标签中使用must-revalidate 参数。

28. 如何防止变量被保存在Cache中?




但是,不是每个时候都有效果。在某些情况下必须使用一个难以想象的方法来清空变量。就是使用 onenterforward 事件。



  


    

    

  








29. 怎么能够知道请求是从WML浏览器来的还是HTML浏览器来的?


 
 
  <%Response.Flush:Response.End%>

30. 如何判断访问者是来自哪个浏览器或者移动电话?

31. 可以得到用户代理的电话号码吗?

不可以,除非网关支持这个特点,WAP没有办法知道用户的电话号码。

32. 可以通过WML使得可以用WAP设备进行拨号吗?

WAP的电话功能可以使用Wireless Telephony Application Interface(WTAI)。

例如:

WMLScript: WTAPublic.MakeCall(“9287787”); 

但是第一代的WAP设备不支持这个功能。

33. 能够从WAP设备中读取数据吗,例如:电话号码?




这里有一些通过HTTP的信息,但是十分有限。既然只有网关发送过来少量的信息,像WAP设备的号码可能无法读取。同时,在某些国家这还涉及到个人隐私的问题。
基本上丢弃的内容就是WAP网关传送给HTTP服务器的内容。这不同于WAP网关到网关。Phone.com的UP.Link网关是一个最好的例子。因为它在HTTP头中返回一个字符串叫做 UP_X_SUBN
O,里面包含了电话号码。Ericsson网关将传送一个辨别设备用的字符串,但是在明文中没有电话号码。
每次WAP设备向HTTP服务器请求一个URL,WAP网关就会将信息传送给HTTP服务器。
以下的PHP脚本显示了从网关过来的所有HTTP头的信息。可以使用WML浏览器进行测试。(



http://wap.colorline.no/clientinfo.html)。其他的例子也可以在下面的UT
L中找到:http://wap.colorline.no/demos.html
第一个部分是取得所有的标准HTTP头信息。第二个部分是提取一个内容。

 
 
Henrik Gemal ( gemal@dk.net)也有一个在线的基于WML的工具BrowserSpy,来显示更多关于HTTP头的信息、服务器环境和用户的浏览器等等。有关这个工具的详细情况可以浏览h
ttp://wap.gemal.dk/
Werner Forkel 提交了一个Perl的脚本,可以显示电话号码(如果有)。可以在以下位置测试: http://wap.colorline.no/wap-faq/apps/subnotest.w
ml,同样也收集在: http://wap.colorline.no/demos.html.
这些程序只适合某个网关。如果要测试其他的网关,可能就显示不出电话号码。因此电话号码不能作为ID号来处理。至少因为不是一个全球的标准。 34. 有没有办法连接到电话号码?

 

Make a call to +47-
 

Nokia 7110 已经有个功能叫做“Use Number”。它可以通过WML卡片查找一个类似于电话号码的列表,然后用户可以选择进行呼叫。注意用户必须分离这些数字以便它能正常工作。

35. 使用GET或者POST方式能传送多少字符?


  

下面仍然是一个使用GET的请求,但是使用了 来传送参数。这个代码就漂亮多了。既然可以定义为GET,同样也很容易转成POST。


  

直接改为POST:


  

最好是做测试找到到底能传输多少数据。这里有个测试程序: http://wap.colorline.no/wap-faq/apps/putsize.php3

这个程序也可以在下面的URL中找到:http://wap.colorline.no/demos.html
该程序将产生一个卡片包含一个变量,里面包含了一定数量的字符X。用户可以选择传输是使用GET还是POST。在传输之后,脚本将要显示接收到的字符个数。
脚本生成一个页面来测试使用GET或者POST方式到底能发送多少个字符:

 

36. 如何同HTML站点一样POST/CGI,返回表单数据到服务器?

如果使用:


 

并且使用:

 

就可以POST数据给CGI程序了。

37. POST无法工作是怎么回事?

全部的代码,就应该像下面的代码:

” & vbCrLf & vbTab
  sWMLDeck = sWMLDeck & “” & vbCrLf & “>/wml>”

35. 使用GET或者POST方式能传送多少字符?


  

下面仍然是一个使用GET的请求,但是使用了 来传送参数。这个代码就漂亮多了。既然可以定义为GET,同样也很容易转成POST。


  

直接改为POST:


  

最好是做测试找到到底能传输多少数据。这里有个测试程序: http://wap.colorline.no/wap-faq/apps/putsize.php3

这个程序也可以在下面的URL中找到:http://wap.colorline.no/demos.html
该程序将产生一个卡片包含一个变量,里面包含了一定数量的字符X。用户可以选择传输是使用GET还是POST。在传输之后,脚本将要显示接收到的字符个数。
脚本生成一个页面来测试使用GET或者POST方式到底能发送多少个字符:

 

36. 如何同HTML站点一样POST/CGI,返回表单数据到服务器?

如果使用:


 

并且使用:

 

就可以POST数据给CGI程序了。

37. POST无法工作是怎么回事?

全部的代码,就应该像下面的代码:

” & vbCrLf & vbTab
  sWMLDeck = sWMLDeck & “” & vbCrLf & “>/wml>”

2. 有哪些公司现在提供这样的开发环境?

3. 开发WAP应用一定要有WAP手机吗?

4. 开发者需要一个WAP网关吗?

5. 可以看到WML的源代码么?

如果开发者使用SDK浏览的时候将能够看到WML的代码。如果只有一个HTML浏览器,可以访问“Fetch Page”服务(http://www.webcab.de)来取得代码。这个可以显示在Inter
net上的任何WML页面中。

6. 可能在WML中加入applets吗?

8. 可以通过WML页面来操作数据库吗?

可以,与创建HTML页面相同。任何相关的服务器端的技术都可以用来生成WML页面。

9. 可以使用CGI生成WML页面吗?

当然。可以用创建HTML同样的方法来创建WML。如果想书写一个CGI来创建WML,只要记住在页面的开头正确设置MIME类型。具体的形式根据所使用的语言不同而不同。例如在Perl中:

print (“Content-type:application/vnd.wap.wml /n/n/n”); 

注意至少要使用2个换行。

10. 如何使用Cold Fusion来生成页面?

使用Cold Fusion只需要加上:

11. 如何使用PHP来书写动态的WML页面?

基于PC的浏览器将忽略这些无法理解的WML标记。但是如果想在WAP设备或者模拟器上测试的时候,只需要将”//”去掉,页面自动变成WML页面。

12. 使用PHP动态输出WML

13. 可以使用Java Servlet来生成WML页面吗?

14. 可以使用ASP、Perl等生成动态的应用吗?

如果在ASP脚本中有一个错误,那么诊断程序会发还一个HTML页面,请检查脚本。

17. 在使用ASP生成WML页面的时候出现了错误:

,会是什么问题?

这个问题是Web浏览器不知道WML的正确类型,修改ASP的第一行,加入:


 

后就可以工作了。

18. 下面的代码有什么问题吗?

去掉
之前的空格。XML解释器希望在这行中没有其他字符,甚至是空行。

19. ASP代码可以在模拟器上工作,在真正的浏览器上怎么不行?

<%Response.ContentType = "text/vnd.wap.wml"%>

在XML定义正确的格式化以后,后面的部分WML对空格就没有那么严格的要求。

21. 应当如何下手书写WAP应用程序?

http://www.motorola.com/MIMS/MSPG/cgi-bin/spn_madk.cgi. 

22. 如何编写和测试WML页面?

24. 如何操作WML页面?

25. 有没有一个友好的方式来管理WML内容?

还没有。虽然Oracale正在开发数据库驱动的文档服务,被称为Panama,可以支持WAP分发。

26. 如何防止用户代理cache页面?

如果用户使用ASP,应该加入一行<%Response.expires=-1%> ,这个将阻止Cache。

  1.1 什么是WAP推送

  WAP推送(PUSH)技术是一种建立在客户服务器上的机制,就是由服务器主动将信息发往客户端的技术。同传统的拉(PULL)技术相比,最主要的区别在于推送(PUSH)技术是由服务器主动向客户机发送信息,而拉(PULL)技术则是由客户机主动请求信息。PUSH技术的优势在于信息的主动性和及时性。

  PUSH技术在Internet中没能取得大的成功,原因是多方面的。主要原因在于固定网中计算机等固定设备为用户提供了足够的资源和能力去查找信息所以用户通常将它作为一个浏览信息的窗口,而不是被动的信息接收者。同时固定网用户对于信息准确性的要求远甚于对其及时性的要求,因此PUSH技术未能得到广泛的应用。

  而在移动网中,由于存在着网络带宽、移动终端能力以及自费标准高昂等诸多限制,使得用户查找信息受到了一定的限制,如果将重要的信息主动及时地推送到用户的移动设备上无疑会大大方便用户。移动通信的优点是移动设备能够随时随地接收信息因此PUSH技术在移动网中可以大展拳脚,WAP PUSH正是PUSH技术和移动通信两者扬长避短相结合的产物。WAP PUSH是在移动网络中应用的PUSH技术,它结合了一般PUSH技术和移动网络的特点。它的系统框架、使用协议和服务方式与固定网上的PUSH技术有很大不同。

  1.2 WAP PUSH系统框架

  WAP PUSH框架主要包括推送发起者(PI:PUSH Initiator)、推送代理网关(PPG:PUSH ProxyGateway)和推送客户(PC:PUSH Client)三个功能部分。PI位于Internet中,而PC在WAP领域,PI和WAP客户端所使用的协议是不同的,需要在中间建立一个协议转换网关即PPG。PPG通过推送访问协议(PAP:PUSH AccessProtocol)与PI通信,通过推送空间传输协议(PUSH OTA:PUSH over-the-Air)完成向客户推送信息的数据传输任务。

  PPG完成推送体系结构中的大部分工作,包括从Internet到移动网的访问接入,以及与其有关的认证、安全、客户端控制等所有工作。PPG所提供的主要服务包括:1)PI的标识、鉴权和访问控制;2)对推送内容进行语法分析,并依据数据类型定义(DTD)检错纠错;3)客户寻址与信息传输;4)PAP与PUSH OTA间的协议转换;5)为提高无线信道中的传输效率,对信息进行压缩、编译等处理。

  另外,PPG还可以通过别名机制实现组播和广播,即将某些特定的地址别名映射到组播或广播的操作中,具体方案可以由系统实现者决定。不同的客户端,其能力是不同的,PPG还要负责响应PI的客户能力查询请求,以便于PI针对不同的客户端构造合适的内容格式。

  1.3 推送协议

  PAP是PI与PPG间的通信协议,它使用可扩展标记语言(XML)作为消息的描述语言,通过简单的请求响应机制完成数据的传输。PAP可以在多种通信协议(包括超文本传输协议(HTTP)、简单邮件传输协议(SMTP)等)之上实现。

  而PUSH OTA是运行于无线会话协议(WSP)之上的一个较为简单的协议层,负责从PPG到客户代理的数据传输。PUSH OTA可使用面向连接的会话和无连接会话两种WSP层服务,对于使用连接会话的推送,需要在PPG和客户端间预先有一个激活的会话上下文;对于无连接的推送,则通过预留的端口来完成通信。

  1.4 推送服务方式

  2 短消息网关简介

  短消息网关(ISMG)是处于短消息中心(SMSC)和业务提供商(SP)之间的设备,它为这两个实体的数据交换提供安全、快捷的通道。网关与短消息中心之间使用SMPP协议(Short Message Peer to Peer,短消息点对点协议), 与SP之间使用CMPP协议(China Mobile Peer to Peer,中国移动点对点协议),因此短消息网关需要完成协议的转换、计费、路由、安全和网络管理等功能。具体说来, SMPP通信代理系统主要实现网关和GSM网中短消息中心(SMSC)的连接,确保准确接收和发送数据,实现高效、可靠的数据传输。为了达到规范要求的不超过0.001%的数据丢包率,SMPP通信代理需要支持流量控制。CMPP通信代理系统主要是实现和SP服务提供商的连接,与SMPP通信代理系统不同的是,由于协议的影响,CMPP通信代理是服务器端,需等待SP的连接,而SMPP通信代理是客户端,需要主动连接SMSC。短消息网关处理系统是网关中最复杂的处理进程,它完成的任务包括:向GNS(汇接网关) 查询路由,维护路由表,进行协议转换和数据分发。防火墙系统主要为网关系统提供安全保障,它包括IP包过滤和身份验证。短信网关计费系统主要形成各种计费话单,为计费提供依据。业务管理系统主要完成对业务进行统计报告,生成报表,为运营者对用户数据的添加、修改、删除以及对网关系统的监控、查询、操作和维护提供接口和界面。

  3 基于短信网关发送WAP PUSH

  WAP PUSH的发送有两种途径,一个是通过PPG网关,另外一个是通过SMPP协议。其中SMPP是一个基本协议,在中国主要有三个由其派生的协议:中国移动的CMPP协议,中国联通的SGIP(在CDMA上是ETIP),以及小灵通的SMGP。通过中国移动的PPG网关发送WAP PUSH有着开发周期长,调测流程较复杂等不足,而使用CMPP协议即基于短信网关来进行WAP PUSH发送灵活性比较高,相对比较简单。

  3.1 WAP PUSH发送的实现模式

  可通过计算机串口上连接GSM MODEM,用它向手机发送WAP PUSH。这种方法发WAP PUSH又分三种模式:BLOCK 模式、TEXT 模式和PDU 模式。BLOCK 模式现在用的很少了, TEXT 模式则只能发送ASCII 码,它不能发送中文的UNICODE码,而PDU 模式开发起来则较为复杂,它需要编写专门的函数来将文本转换为PDU 格式,但PDU 模式被所有手机支持,可以使用任何字符集,它也是手机默认的编码方式,所以选用PDU模式发送WAP PUSH.

  例如

  为一串可以成功发送的WAP PUSH,其中包括了汉字描述和WAP页面地址。具体分析如下

  00 SMSC 地址信息的长度 00表示用手机上设置短信中心号码,PDU 串的“SMSC 址格式”段和“SMSC 地址”段将省去

  51 基本参数(TP-MTI/VFP) 不要求发送回复

  00 消息基准值(TP-MR)

  0B 对方电话的长度

  A1 目标地址格式 A1表示为国内格式

  F6 目标地址,补‘F’凑成偶数位后奇偶位互换

  00 协议标识(TP-PID) 是普通GSM 类型,点到点方式

  F5 用户信息编码方式 (TP-DCS)

  A7 有效期(TP-VP)

  85 用户信息长度(TP-UDL)

  0B WAP PUSH头部的总长度

  05040B8423F0表示接下来是一个WAP PUSH

  00 表示是Concatenated Short Messages

  03 长度

  03 reference number

  01 表示分成1个短信发送

  01 当前包的序号

  AE81EA8DCA WSP

  02 标记位

  05 -//WAPFORUM//DTD SI 1.0//EN

  6A UTF-8

  00 标记开始

  45

  C6

  08

  0C href=”http://

  03 字符串开始

  00 URL 字符串结束

  01 >

  03 内容描述字符串开始

  00 内容描述字符串结束

  01

  01

  4 结束语

  WAP PUSH技术结合了PUSH技术的优势和移动通信服务的特性,具有良好的应用前景。但是WAP PUSH技术仍然存在着一些亟待解决的问题,如信息的鉴权与认证、信息的准确性、如何避免垃圾信息等。如何解决好这些问题将是WAP PUSH技术成功的关键。另外,随着GPRS技术和3G无线通信技术的发展,无线信道的带宽将逐步增大,WAP PUSH也将能进一步推送多媒体信息,有着更宽广的应用前景

    PUSH技术在Internet中没能取得大的成功,原因是多方面的。在固定网中计算机等固定设备为用户提供了足够的资源和能力去查找信息所以用户通常将它作为一个浏览信息的窗口,而不是被动的信息接收者。固定网用户对于信息准确性的要求远甚于对其及时性的要求。 

    而在移动网中,由于存在着网络带宽、移动设备能力以及高昂的资费标准等诸多限制,用户无法像在固定网中一样方便地查找信息,如果将重要的信息主动及时地推送到用户的移动设备上无疑会大大方便用户。移动通信的优点是移动设备能够随时随地接收信息因此PUSH技术可以在移动网中大显身手,WAP  PUSH正是PUSH技术和移动通信两者扬长避短相结合的产物。 

    WAP  PUSH是在移动网络中应用的PUSH技术它既具有一般PUSH技术的特点又拥有移动网络的特点。它的系统框架、使用协议和服务方式与固定网上的PUSH技术有很大不同。 

 

http://wap.fractalist.cn/” action=”signal-high”>

    挑战脉动,挑战你我

 

这个XML的DTD定义在http://www.openmobilealliance.org/tech/dtd/si.dtd

WMXML定义在http://www.w3.org/1999/06/NOTE-wbxml-19990624/

编码后作为二进制短消息发送给用户,记得讲tp_udhi设为1就可以了

WBXML编码的代码如下:

#include

#include


#include
#include


#pragma warning(disable : 4267)
#include


#pragma warning(default : 4267)
#include










#include


#include

///

/// Series of well known constants and static uint8_t values used when encoding
/// a document to WBXML
///


class WBXML
{

public:
 static const uint8_t CHAR_NULL = 0x00;

 static const uint8_t CHARSET_UTF_8 = 0x6A;

///

/// Encapsulates the Service Indication WAP Push instruction.
/// Full documentation can be found at http://www.openmobilealliance.org/tech/affiliates/wap/wap-167-serviceind-20010731-a.pdf?doc=wap-167-serviceind-20010731-a.pdf
///


class ServiceIndication
{

public:
 // Allowed values of the action attribute of the indication tag
 enum Action {NotSet = -1, signal_none = 0, signal_low, signal_medium, signal_high, Delete};
 // Well known DTD token
 static const uint8_t DOCUMENT_DTD_ServiceIndication = 0x05;   // ServiceIndication 1.0 Public Identifier

 ///

 /// Generates a uint8_t array comprising the encoded Service Indication
 ///

 ///

The encoded body

 //01 05 6a 00 45 c6 0c 03 77 61 702e16ce636e0008 0820
 //746f6c

 std::vector

getWBXMLBytes() const

 {

  std::vector

vec;

  vec.push_back(WBXML::VERSION_1_1);
  vec.push_back(DOCUMENT_DTD_ServiceIndication);
  vec.push_back(WBXML::CHARSET_UTF_8);
  vec.push_back(WBXML::CHAR_NULL);







 /// Gets the token for the action attribute
 ///

 /// Interruption level instruction to the handset
 ///

well known uint8_t value for the action attribute

 uint8_t getActionToken(Action action) const
 {

  return ATTRIBUTESTARTTOKEN_action[(int)action];
 }

 ///

 /// Encodes an inline string into the stream using UTF8 encoding
 ///

 /// The target stream
 /// The text to write
 void writeInlineString(std::vector

& vec, const std::string & text) const

 {

  // indicate that the follow bytes comprise a string
  vec.push_back(WBXML::TOKEN_INLINE_STRING_FOLLOWS);

 /// Encodes the DateTime to the stream.
 /// DateTimes are encoded as Opaque Data with each number in the string represented
 /// by its 4-bit binary value
 /// eg: 1999-04-30 06:40:00
 /// is encoded as 0.
 /// Trailing zero values are not included.
 ///






 /// Target stream
 /// DateTime to encode
 void writeDate(std::vector

& vec, time_t date) const

 {

  struct tm * gm = gmtime(&date);
  uint8_t buffer[7];

  uint8_t dateLength = 4;

///

/// Well known values used when generating WSP (Wireless Session Protocol) headers
///

class WSP
{

public:
 static const uint8_t TRANSACTIONID_CONNECTIONLESSWSP = 0x25;

 static const uint8_t PDUTYPE_PUSH = 0x06;

 static const uint8_t HEADER_CONTENTLENGTH = 0x8D;

 static const uint8_t HEADER_CONTENTTYPE_application_vnd_wap_sic_utf_8[4];

 static const uint8_t HEADER_PUSHFLAG[2];

};

///

/// Well known values used when generating a WDP (Wireless Datagram Protocol) header
///

class WDP
{

public:
 static const uint8_t INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT = 0x05;
};

///

/// Encapsulates an SMS WAP Push message
///

class PushMessage
{

private:
 // Ports for the WDP information element, instructing the handset which
 // application to load on receving the message
 static const uint8_t WDP_DESTINATIONPORT[2];
 static const uint8_t WDP_SOURCEPORT[2];

 ServiceIndication serviceIndication;

 ///

 /// Generates the body of the SMS message
 ///

 ///

uint8_t array

 std::vector

getSMSBytes() const

 {

  std::vector

vec;

 ///

 /// Generates the PDU (Protocol Data Unit) comprising the encoded Service Indication
 /// and the WSP (Wireless Session Protocol) headers
 ///


 ///

uint8_t array comprising the PDU

 void getPDUBytes(std::vector

& vec) const

 {

  std::vector

body = serviceIndication.getWBXMLBytes();

  std::vector

header = getWSPHeaderBytes((uint8_t)body.size());

#ifdef _DEBUG
  cout << "getWSPHeaderBytes/n";
  for(size_t i = 0; i < header.size(); ++i)
  {

   cout << hex << setw(2) << setfill("0") << ((int)header[i]);
  }
  cout << "/n" << endl;







 ///

 /// Generates the WSP (Wireless Session Protocol) headers with the well known
 /// uint8_t values specfic to a Service Indication
 ///


 /// the length of the encoded Service Indication
 ///

uint8_t array comprising the headers

 //25060a03ae81eaaf828dc1b484
 //25060a03ae81eaaf828dc8b484

 std::vector

getWSPHeaderBytes(uint8_t contentLength) const

 {

  std::vector

vec;



 ///

 /// Generates the WDP (Wireless Datagram Protocol) or UDH (User Data Header) for the
 /// SMS message. In the case comprising the Application Port information element
 /// indicating to the handset which application to start on receipt of the message
 ///



 ///

uint8_t array comprising the header

 void getWDPHeaderBytes(std::vector

& vec) const

 {

  uint8_t headerLength = sizeof(WDP::INFORMATIONELEMENT_IDENTIFIER_APPLICATIONPORT)
   + 1
   + sizeof(WDP_DESTINATIONPORT) / sizeof(WDP_DESTINATIONPORT[0])
   + sizeof(WDP_SOURCEPORT) / sizeof(WDP_SOURCEPORT[0]);
  vec.push_back(headerLength);

  首先你的 Web服务器要安装好PHP,即能处理PHP脚本程序。其次,为使Web服务器能同时识别和处理PHP、WML、WBMP等文件,Web 服务器的MIME表需添加以下的几种文件类型。

  二、用PHP输出简单动态WAP页面 

  下面有一个最简单的PHP生成WAP页面的例子。注意由于需要PHP解释器来解释该程序,并输出WAP页面,因此所有类似程序应以.php为扩展名。

″);
  ?> 

  该例子在WAP手机模拟器中可以浏览,输出当前日期时间,而在普通的浏览器中无法识别,甚至会被认为是错误下载。这是因为在程序开头就声明了该输出文档为WML类型,该类型只有WAP设备能够识别并解释。值得注意的是,我们常见的HTML语言对规范性要求不严,大多数浏览器能“容忍”其中相当多的编写错误,而WML规范相当严格,一点失误都可能导致无法输出所需页面。

  一旦我们知道了用PHP脚本输出WAP页面的标准过程,我们就能够使用PHP强大的功能配合以WML语言的交互处理以及WML Script的简单脚本,开发出适合我们需要的应用系统了。

   三、用PHP动态生成图像 

  WAP应用使用一种特殊黑白的图像格式WBMP。我们可以用一些工具来将已有图像转换成WBMP格式,然后在WML文档中使用。但是在WAP站点上如果能动态地生成所需图像如K线图等,将会有广阔的应用前景。幸运的是,PHP的GD库(版本1.8以上)已经提供了相应函数。

  该文件将在WAP模拟器中显示一个黑色矩形框。注意要使用GD的图像函数库,必须在PHP配置中加载PHP_GD.DLL库文件。

  四、在PHP中处理汉字

  WAP作为一种全球应用,选择了UNICODE 2.0作为其标准字符集编码,以便能同时处理包括英文、中文、日文、法文等多种文字。而我们平常处理汉字使用的是GB2312编码,不同的内码标准势必不能通用,因此如果不在两种编码之间通过码表进行转换,就会出现汉字乱码现象。现在已经有较成熟的GB-2312与UNICODE编码转换的程序和函数,并在ASP、PHP、JSP等系统中使用,我们可以在一些技术站点上找到它们。

  目前的大多数WAP手机(Nokia7110、爱立信R320S等等)都是使用UTF-8编码的,也就是采用UNICODE来编码。这样,如果我们直接在WML使用中文字符(GB2312编码),将会产生乱码,手机用户无法识别,所以我们在输出中文之前,要使用程序或函数对中文进行UNICODE的编码。而在少数支持GB2312编码的手机或WAP终端设备中,我们可以在程序中定义好文档的内码类型后即可直接正确显示汉字,例如:

″);
 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=

0
0
 

(请您对文章做出评价)

 
« 上一篇:
史玉柱:社会对我的要求比对陈天桥丁磊高

» 下一篇: Struts例子的设计分析
 

try { GS_googleAddAdSenseService(“ca-pub-04288”); GS_googleEnableAllServices(); } catch (e) { } try { GA_googleAddSlot(“ca-pub-04288”, “cnblogs_blogpost_body”); GA_googleAddSlot(“ca-pub-04288”, “cnblogs_commentbox_up”); GA_googleAddSlot(“ca-pub-04288”, “cnblogs_blogpost_bottom”); } catch (e) { } try { GA_googleFetchAds(); } catch (e) { } var blog_ad_has_shown = false;

posted on 2008-01-29 13:51 exce4 阅读(2584) 评论(2)  编辑 收藏 网摘

wap开发
#1楼[楼主] 2008-01-29 14:44 exce4      

评论
 

关于基于jsp+resin的移动wap的中文参数传递问题?

out.print(outWML.outHref(DefaultURL+”free.jsp?name=假使我漂亮-jade关心妍”, “假使我漂亮(jade关心妍)”));
这句,我将一个中文参数传递到free.jsp页面

free.jsp
//

“>

String para = new String(request.getParameter(“name“).getBytes(“iso8859_1“));
out.print(“




















“+para+“

“);//输出获得的参数,都为乱码

out.print(outWML.outHref(DefaultURL+“mring.jsp“, “劲歌金曲爬行榜首页“));
out.print(monternet);
–>

//
出来的结果怎么都是乱码

是关于java的,java的默认参数传递方式是utf8码,今天终于解决了
不是楼上说的问题
在发送url请求的页面和接收url请求的页面做如下设置
//utf8
//参数处理方式utf8
//页面字符处理方式 iso-8859-1

2004-07-06 11:33 | khan

o?按照ISO-8859-1传递就行了?我怎么记得也会出问题呢?过网关的时候也会出点莫名其妙的事情。

我是都urlencode了,然后替换一下%,然后程序再解码。

2004-07-08 09:05 | virushuo

呵呵,普通的传递用urlencode.class,解码用urldecode.class
表单的传递用iso-8859-1就可以了,呵呵

以上是指移动的wap业务,所有汉字编码必须是utf8的情况下
   回复   引用   查看    

#2楼 [ 楼主] 2008-01-29 14:51 exce4       

昨天和一个老程序员吃饭聊起codelphi,说很久以前,经常能从这里搜索到一些好的技术文章。
最近的工作也蛮辛苦。开始接触以前从来没有接触过的GNU/linux下的基于gcc的开发。两样东西都是现学的。工作了3个星期,只写了一个 电信smgp3协议的tlv参数解析包。所谓的tlv参数就是(tag ,length,value),tag表示一个指令标志,length,表示这个指令所携带数据的长度,value表示指令所携带的数据,用这种方式传递 参数可以很大程度的在不影响效率的情况下减少空参数所占的空间,节省网络带宽。贴部分代码给大家指正

#ifndef _PTLV_HPP
#define _PTLV_HPP

#include
#include
#include
#include
/*sowpdu*/
typedef unsigned short WORD;
typedef unsigned char BYTE;

typedef int BOOL;
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

/*
Name: PTlv
Copyright:
Author:
Date: 14-12-05 15:05
Description:
*/
class PTlv{
private:
WORD tag;//tlv 标识
WORD len; //value 长度
BYTE *value; //参数数据体
int byteOffset;

public:
PTlv(WORD new_tag, WORD new_len, BYTE *new_value);
PTlv(WORD new_tag, BYTE new_value);

PTlv();

void Clone(PTlv &src_tlv);

~PTlv();

enum VALUE_TYPE{ //
INTEGER_1 = 0×0001, //byte
INTEGER_2 = 0×0002, //word
OCTET_STRING = 0×0003 //string
};

enum TLV_Tag{
TLV_TP_PID = 0×0001, //GSM协议类型。详细解释请参考GSM03.40中的9.2.3.9
TLV_TP_UDHI = 0×0002, //GSM协议类型。详细解释请参考GSM03.40中的9.2.3.23,仅使用1位,右对齐。
TLV_LINK_ID = 0×0003, //交易标识,用于唯一标识一次交易
TLV_CHARGE_USER_TYPE = 0×0004, //计费用户类型。
// 0=对短消息接收方计费;
// 1=对短消息发送方计费;
// 2=对SP计费;
// 3=表示本字段无效,对谁计费参见ChargeTermID或ChargeTermPseudo 字段。
TLV_CHARGE_TERM_TYPE = 0×0005, //计费用户的号码类型。
// 0=真实号码;
// 1=伪码;其它保留。
TLV_CHARGE_TERM_PSEUDO = 0×0006, //计费用户的伪码
TLV_DEST_TERM_TYPE = 0×0007, //短消息接收方的号码类型。
// 0=真实号码;
// 1=伪码;其它保留
TLV_DEST_TERM_PSEUDO = 0×0008, //短消息接收方的伪码,当有多个接收方伪码时,要求每个接收方伪码的长度一样。
TLV_PK_TOTAL = 0×0009, //相同Msg_Id的消息总条数。
TLV_PK_NUMBER = 0×000A, //相同Msg_Id的消息序号,从1开始。
TLV_SUBMIT_MSG_TYPE = 0×000B, //SP发送的消息类型。
// 0=普通短消息;
// 1=WEB方式定制结果消息;
// 2=WEB方式取消定制结果消息;
// 3=终端方式定制结果消息;
// 4=终端方式取消定制结果消息;
// 5=包月扣费通知消息;
// 6=WEB方式定制二次确认消息;
// 7=WEB方式取消定制二次确认消息;
// 8=终端方式定制二次确认消息;
// 9=终端方式取消定制二次确认消息;
// 10=WEB方式点播二次确认消息;
// 11=终端方式点播二次确认消息(暂保留);
// 12=群发请求;
// 13:同步订购(包括点播和定制)关系;
// 14:群发结果通知消息。
// 无该字段时,默认为”普通短消息”
// 15:同步订购(包括点播和定制)关系回复;其它保留;
TLV_SP_DEAL_RESLT = 0×000C, //SP对消息的处理结果
// 0=成功;
// 1=失败;其它保留。
// 该字段在SubmitMsgType为0、5、6、7、8、9、10、11、14时无效。

TLV_SRC_TERM_TYPE = 0×000D, //短消息发送方的号码类型。
// 0=真实号码;
// 1=伪码;其它保留。

TLV_SRC_TERM_PSEUDO = 0×000E, //短消息发送方的伪码
TLV_NODES_COUNT = 0×000F, //经过的网关数量。该字段的初始值为1。

TLV_MSG_SRC = 0×0010, //信息内容的来源。
// 在固定网短消息业务中,MsgSrc填写SP的服务代码。
// 在移动网短消息业务中,MsgSrc填写SP的企业代码。
TLV_SRC_TYPE = 0×0011, //传递给SP 的源号码的类型。
// 0=真实号码;
// 1=伪码;其它保留。
TLV_M_SERVICE_ID = 0×0012 //业务代码。用于移动网业务
};

WORD getTag() const { return tag;}
void setTag(WORD new_tag){ tag = new_tag; }

WORD getTLVLen() const { return 2+2+len; }
WORD getValueLen() const { return len;}
int getOffset() const{ return byteOffset;}

BOOL getValue(BYTE *pstr, int value_len);

static BOOL IsValidTag(WORD the_tag);
static std::string AliasByTag(WORD the_tag);

BOOL Decode(BYTE *pstr, int tlv_len);
BOOL Encode(WORD the_tag, WORD the_len, BYTE *the_value);
BOOL Encode(WORD new_tag, BYTE new_value);

void PrintOn(std::ostream & strm) const;
void ToString(std::ostream & strm) const;

WORD getValueType(WORD the_tag) const;
protected:

};

#endif //_TLV_HPP

//tlv.cpp///
#include “TLV.hpp”

// PTLV

/构造器
*@param */
PTlv::PTlv(WORD new_tag, WORD new_len, BYTE *new_value){
Encode(new_tag, new_len, new_value);
}

PTlv::PTlv(WORD new_tag, BYTE new_value){
Encode(new_tag, new_value);
}

PTlv::PTlv(){
tag=0×0000;
len=0×0000;
value=0;
byteOffset=0;
}

//
void PTlv::Clone(PTlv &src_tlv){
tag = src_tlv.getTag();
len = src_tlv.getValueLen();
byteOffset= src_tlv.getOffset();
if(value != NULL) {
delete []value;
value = NULL;
}
value = new BYTE[len];
memset(value, 0, len);
src_tlv.getValue(value,len);
}

/*析构器*/
PTlv::~PTlv(){
if (value != NULL)
delete []value;
value = NULL;
byteOffset = 0;
len = 0;
}

BOOL PTlv::IsValidTag(WORD the_tag){
switch(the_tag){
case TLV_TP_PID:// = 0×00000001,
case TLV_TP_UDHI:// = 0×00000002,
case TLV_LINK_ID:// = 0×00000003,
case TLV_CHARGE_USER_TYPE:// = 0×00000004,
case TLV_CHARGE_TERM_TYPE:// = 0×00000005,
case TLV_CHARGE_TERM_PSEUDO:// = 0×00000006,
case TLV_DEST_TERM_TYPE:// = 0×00000007,
case TLV_DEST_TERM_PSEUDO:// = 0×00000008,
case TLV_PK_TOTAL:// = 0×00000009,
case TLV_PK_NUMBER:// = 0×0000000A,
case TLV_SUBMIT_MSG_TYPE:// = 0×0000000B,
case TLV_SP_DEAL_RESLT:// = 0×0000000C,
case TLV_SRC_TERM_TYPE:// = 0×0000000D,
case TLV_SRC_TERM_PSEUDO:// = 0×0000000E,
case TLV_NODES_COUNT:// = 0×0000000F,
case TLV_MSG_SRC:// = 0×00000010,
case TLV_SRC_TYPE:// = 0×00000011,
case TLV_M_SERVICE_ID:// = 0×00000012,
return TRUE;
default :
return FALSE;
}
}

/
* 取得tag的别名
* @param the_tag tag标识
* @return string 别名
*/
std::string PTlv::AliasByTag(WORD the_tag){
switch(the_tag){
case TLV_TP_PID:
return “TLV_TP_PID”;
case TLV_TP_UDHI:
return “TLV_TP_UDHI”;
case TLV_LINK_ID:
return “TLV_LINK_ID”;
case TLV_CHARGE_USER_TYPE:
return “TLV_CHARGE_USER_TYPE”;
case TLV_CHARGE_TERM_TYPE:
return “TLV_CHARGE_TERM_TYPE”;
case TLV_CHARGE_TERM_PSEUDO:
return “TLV_CHARGE_TERM_PSEUDO”;
case TLV_DEST_TERM_TYPE:
return “TLV_DEST_TERM_TYPE”;
case TLV_DEST_TERM_PSEUDO:
return “TLV_DEST_TERM_PSEUDO”;
case TLV_PK_TOTAL:
return “TLV_PK_TOTAL”;
case TLV_PK_NUMBER:
return “TLV_PK_NUMBER”;
case TLV_SUBMIT_MSG_TYPE:
return “TLV_SUBMIT_MSG_TYPE”;
case TLV_SP_DEAL_RESLT:
return “TLV_SP_DEAL_RESLT”;
case TLV_SRC_TERM_TYPE:
return “TLV_SRC_TERM_TYPE”;
case TLV_SRC_TERM_PSEUDO:
return “TLV_SRC_TERM_PSEUDO”;
case TLV_NODES_COUNT:
return “TLV_NODES_COUNT”;
case TLV_MSG_SRC:
return “TLV_MSG_SRC”;
case TLV_SRC_TYPE:
return “TLV_SRC_TYPE”;
case TLV_M_SERVICE_ID:
return “TLV_M_SERVICE_ID”;
default :
return “TLV_UNKNOWN_TAG_ID”;
}
}

void PTlv::PrintOn(std::ostream &strm) const{
strm << “SMGP3_TLV:{/n”;
strm << std::setw(15) << “tag:” << AliasByTag(tag) << ” 0x” << std::hex << std::setw(sizeof(tag))<< std::setfill(’0′) << tag << ‘/n’;
strm << std::setfill(’ ‘) << std::setw(15) << “len:” << len << std::endl;
strm << std::setfill(’ ‘) << std::setw(17) << “value:” << value <





































































































































































































































































































































































































































版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215206.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午2:26
下一篇 2026年3月18日 下午2:27


相关推荐

  • executorservice和executor_source counter

    executorservice和executor_source counter1、创建一个WorkerThread类,表示执行任务publicclassWorkerThreadimplementsRunnable{ @Override publicvoidrun(){ System.out.println("当前时间:"+System.currentTimeMillis()+"线程名称:" +Thread.currentT…

    2025年10月21日
    4
  • 用几何光学方法如何分析反射调制方式光纤位移_相位单点激光测距

    用几何光学方法如何分析反射调制方式光纤位移_相位单点激光测距本文介绍了移相干涉技术中最基础却也非常重要的一步——相位提取,主要阐述了移相干涉测量原理、四步移相法提取相位、多步平均法推导过程、多步解包裹后平均法这四个部分,希望能给同样从事该领域研究的你带来一点帮助。

    2026年4月17日
    4
  • 安全-流量劫持形成的原因

    流量劫持,这种古老的攻击沉寂了一段时间后,最近又开始闹的沸沸扬扬。众多知名品牌的路由器相继爆出存在安全漏洞,引来国内媒体纷纷报道。只要用户没改默认密码,打开一个网页甚至帖子,路由器配置就会被暗中修改。互联网一夜间变得岌岌可危。详解流量劫持的形成原因攻击还是那几种攻击,报道仍是那千篇一律的砖家提醒,以至于大家都麻木了。早已见惯运营商的各种劫持,频繁的广告弹窗,大家也无可奈何。这么多年也没出现…

    2022年4月9日
    43
  • oracle忘记sys密码处理

    oracle忘记sys密码处理

    2021年8月23日
    58
  • unittest测试框架组成_unittest接口自动化

    unittest测试框架组成_unittest接口自动化一、unittest简介unittest是python的单元测试框架。unittest单元测试提供了创建测试用例,测试套件以及批量执行的方案,unittest在安装pyhton以后就直接自带了,直接importunittest就可以使用。作为单元测试的框架,unittest也是可以对程序最小模块的一种敏捷化的测试。在自动化测试中,我们虽然不需要做白盒测试,但是必须需要知道所使用语言的单元测试框架。利用单元测试框架,创建一个类,该类继承unittest的TestCase,这样可以把每

    2022年10月14日
    4
  • 吐槽一下Activiti用户手册和一本书

    吐槽一下Activiti用户手册和一本书

    2022年1月6日
    52

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号