`

在无线J2ME设备上实现超文本传输协议【转】

阅读更多

随着越来越多手提电话和个人数字助理开始融入到信息高速公路之上,从移动设备上访问Web站点变得越来越重要。Java开创了消费设备中小型的储存容量的先河,它是用于开发手机、传呼机及其他微型设备应用程序的理想语言。

  在本文中,我们将学习如何从一个J2ME客户机上向服务器发送一条HTTP GET请求和一条HTTP POST请求。虽然这只是一篇探讨性质的文章,但是我还是假定读者已经熟悉Java,J2ME,以及Java Midlets(MIDP应用程序)的运作机制。我们将使用J2ME的MIDP简表,并利用SUN的J2ME的无线应用程序开发工具包编译、配置和测试我们的应用程序。对于HTTP服务器,任何WWW地址都可以被访问,但是默认时我们将使用一个简单的Java Servlet来返回我们的HTTP请求的细节。

  如何使用J2ME客户机向Web服务器和类似的支持HTTP的服务器发送HTTP请求呢?答案就是使用可在javax.microedition.io程序包中可找到的J2ME的网络类。本文就想具体阐述这个问题。

  本文概述∶

  使用J2ME设计无线网络应用程序

  .发送一条超文本GET请求

  .发送一条超文本POST请求

  .使用J2ME进行无线网络编程

  Java的网络编程能力是相当健壮的。Java 2标准版( J2SE)在java.io和java.net程序包中定义了100多个接口程序,类和异常。通过这些库实现的功能是很强大的,但是这只适用于传统的计算机系统,这些计算机系统有强大的CPU处理能力,快速的内存和持久的数据储存,但是这些在大多数的无线设备上是不现实的。因此,J2ME定义了这些函数的子集,并提供了一套用于网络和文件访问的固定的程序包--- javax.microedition.io程序包。由于可移动设备种类繁多,这个程序包仅仅定义了一套接口,而为每个可移动设备供应厂商留下了实际的应用程序接口实现。这就在可移植性和设备特定特征的应用中找到了一个最佳的平衡点。

  定义在javax.microedition.io类中的抽象网络和文件输入输出框架称为通用连接框架(Generic Connection Framework,简称GCF)。GCF定义了一套有关抽象化的内容来描述不同的通信方法。最高级的抽象被称作连接(Connection),还声明了六个接口(四个是直接的,两个是间接的)。这七个接口就构成了J2ME的CLDC的一部分,CLDC是大多数的能使用Java的无线设备使用的配置。设计这个配置的目的就是为所有的CLDC设备(手提电话,双向传呼机,低档的PDA等等)提供公用的网络和文件输入输出能力。虽然GCF的目的是公用网络和文件输入输出框架,但是生产商并不要求实现GCF中声明的所有的接口。有的厂家可以决定只支持socket连接,而其它的厂家可以选择只支持基于数据报的通信。为了促进跨越类似装置的可移植性,MIDP规范要求所有的MIDP设备实现HttpConnection接口。HttpConnection不是GCF的一部分,但是它是从GCF的一个接口ContentConnection衍生出来的。我们将使用HttpConnection接口构造我们样本应用程序。

  发送一个HTTP GET请求

  这一节将重点解释程序代码,在下一节中我们将只讲述被用来发送HTTP请求并检索由服务器返回的响应通用连接框架接口和HttpConnection接口。创建MIDP用户界面的程序代码见附录。

  我们先要定义一个方法来放用于发送HTTP GET请求的代码。因为这个方法中的有些操作有潜在的抛出IOException的可能,所以我们将把这样的意外(exception)抛给调用方法。
  public String sendHttpGet( String url ) throws IOException {
  HttpConnection hcon = null;
  DataInputStream dis = null;
  StringBuffer message = "";
  try {

  第一步是使用Connector类打开一个到服务器的连接,这是GCF的关键。我们将把这个连接强制转换为需要的类型,在本例中为HttpConnection类型。
  hcon = ( HttpConnection ) Connector.open( url );

  接下来,我们得到HttpConnection上的一个DataInputStream,允许我们一个字符一个字符的读取服务器的响应数据。
  dis = new DataInputStream( hcon.openInputStream() );

  使用DataInputStream的read ()方法,服务器响应的每个字符都被集中起来放入StringBuffer对象。
  int ch;
  while ( ( ch = dis.read() ) != -1 ) {
  message = message.append( ( char ) ch );
  }


  最后,连接对象被净空以保存资源,而信息从这个方法中返回。
  } finally {
  if ( hcon != null ) hcon.close();
  if ( dis != null ) dis.close();
  }//结束try/finally代码段
  return message.toString();
  }//结束 sendGetRequest( String )

 如何发送一个HTTP POST请求

  你可以想象,发送一个HTTP POST请求的处理过程其实与发送一个GET请求非常地类似。我们将修改一个现有命令,添加少量的新的命令,并添加一个来自通用连接框架的附加的对象和一个附加的StringBuffer对象把POST请求体重的内容发送到服务器中。剩下的命令将保持不变。

  复制我们刚才创建的sendHttpGet()方法,把它粘贴进同一个类文件,改名为sendHttpPost()。 现在,我们将修改这个新方法来发送一个HTTP POST请求到服务器。 在方法的顶部添加两个新的变量说明。 声明一个类型为DataOutputStream的变量和另一个String类型的变量。 我们将使用DataOutputStream对象把存在于字符串变量中的POST请求体发送到服务器中。
  DataOutputStream dos = null;
  String requestBody = null;

  修改connector.open()命令包含另一个参数,指出连接将允许客户端可以通过连接在服务器上读和写。
  hcon = ( HttpConnection ) Connector.open( url, Connector.READ_WRITE );

  设置HttpConnection对象使用的请求方法为POST(默认的方法是GET)。
  hcon.setRequestMethod( HttpConnection.POST );

  得到一个用于现有的HTTP连接的DataOutputStream对象。
  dos = hc.openDataOutputStream();

  声明一个字节数组并通过检索一个来自requestBody字符串的字节数组初始化。 然后把DataOutputStream的缓冲写入字节数组内。
  byte[] byteRequest = requestBody.getBytes();
  for( int i = 0; i < byteRequest.length; i++ ) {
  dos.writeByte(byteRequest[i]);
  }//结束for( int i = 0; i < byteRequest.length; i++ )

  dos.flush(); //包含本句,在某些设被上将可能会产生不可预期的结果

  调用flush ()方法的意图是发送已经写入的数据到DataOutputStream的服务器的缓冲区中。 在某些电话上,这个操作工作正常,在其他的电话上,它导致HTTP请求的Transfer - Encoding被设置为" chunked ",有一些随机字符被放到请求本身的前面和后面。那又怎样处理这个问题呢?这个方法调用实际上是根本不需要的。在接下来的一行中,服务器连接打开(通过openInputStream ()),将自动输入缓冲区。因此,你最好不要调用缓冲区的flush()方法。这个方法其余的部分保持不变,除了DataOutputStream对象必须在finally{}语句块中关闭。
  } finally {
  if ( hc != null ) hc.close();

  if ( dis != null ) dis.close();

  if ( dos != null ) dis.close();
  }//结束 try/finally

  这就是所有的程序代码!并请参见本文后附带的程序代码。

  随着可以使用国际互联网络和支持网络的无线设备日益的增多普及,Java和J2ME的重要性也在不断的变大。因为HTTP协议是当前仅有的,被所有的遵从MIDP规范的设备支持的网络协议,它也是用于开发无线网络应用程序的最好的候选者。

  在本文中,我们探究了无线网络编程的基本结构和几个核心问题,我们看了如何调用两个最常用的HTTP请求方法:GET和POST。J2ME仍然在它的发展初期,并且无线设备也即将得到大面积的普及。所以,所有有志投身于无线网络编程中的开发者们将得到大展拳脚的好机会。

  附录:
  /*
  * HttpMidlet.java
  */
  import javax.microedition.midlet.*;
  import javax.microedition.lcdui.*;
  import javax.microedition.io.*;
  import java.io.*;


  public class HttpMidlet extends MIDlet implements CommandListener {
  //使用默认的URL。用户可以从图形用户接口改变这个值
  private static String defaultURL = "http://localhost:8080/test/servlet/EchoServlet";

  // 主MIDP 显示
  private Display myDisplay = null;

  // 输入URL的图形用户接口组件
  private Form requestScreen;
  private TextField requestField;

// 用于提交请求的图形用户接口组件
  private List list;
  private String[] menuItems;

  // 用于显示服务器响应的图形用户接口组件
  private Form resultScreen;
  private StringItem resultField;

  //用于requestScreen的"send"按钮
  Command sendCommand;
  // 用于requestScreen的"exit"按钮
  Command exitCommand;
  // 用于requestScreen的"back"按钮
  Command backCommand;

  public HttpMidlet(){
  // 初始化图形用户接口组件
  myDisplay = Display.getDisplay( this );
  sendCommand = new Command( "SEND", Command.OK, 1 );
  exitCommand = new Command( "EXIT", Command.OK, 1 );
  backCommand = new Command( "BACK", Command.OK, 1 );

  //显示请求的URL
  requestScreen = new Form( "Type in a URL:" );
  requestField = new TextField( null, defaultURL, 100, TextField.URL );
  requestScreen.append( requestField );
  requestScreen.addCommand( sendCommand );
  requestScreen.addCommand( exitCommand );
  requestScreen.setCommandListener( this );

  // 选择想要的HTTP请求方法
  menuItems = new String[] {"GET Request", "POST Request"};
  list = new List( "Select an HTTP method:", List.IMPLICIT, menuItems, null );
  list.setCommandListener( this );

  // 先是从服务器上收到的信息
  resultScreen = new Form( "Server Response:" );
  resultScreen.addCommand( backCommand );
  resultScreen.setCommandListener( this );

  }//结束HttpMidlet()

  public void startApp() {
  myDisplay.setCurrent( requestScreen );
  }//结束 startApp()

  public void commandAction( Command com, Displayable disp ) {
  // 当用户点击"send"按钮
  if ( com == sendCommand ) {
  myDisplay.setCurrent( list );
  } else if ( com == backCommand ) {
  requestField.setString( defaultURL );
  myDisplay.setCurrent( requestScreen );
  } else if ( com == exitCommand ) {
  destroyApp( true );
  notifyDestroyed();
  }//结束 if ( com == sendCommand )

  if ( disp == list && com == List.SELECT_COMMAND ) {

  String result;

  if ( list.getSelectedIndex() == 0 ) // 发送一个 GET 请求到服务器
  result = sendHttpGet( requestField.getString() );
  else // 发送一个 POST 请求到服务器
  result = sendHttpPost( requestField.getString() );

  resultField = new StringItem( null, result );
  resultScreen.append( resultField );
  myDisplay.setCurrent( resultScreen );
  }//结束if ( dis == list && com == List.SELECT_COMMAND )
  }//结束 commandAction( Command, Displayable )

  private String sendHttpGet( String url )
  {
  HttpConnection hcon = null;
  DataInputStream dis = null;
  StringBuffer responseMessage = new StringBuffer();

  try {
  //使用READ权限的标准的 HttpConnection
  hcon = ( HttpConnection )Connector.open( url );

  //从HttpConnection取得一个 DataInputStream
  dis = new DataInputStream( hcon.openInputStream() );

// 从服务器上取回响应
  int ch;
  while ( ( ch = dis.read() ) != -1 ) {
  responseMessage.append( (char) ch );
  }//结束while ( ( ch = dis.read() ) != -1 )
  }
  catch( Exception e )
  {
  e.printStackTrace();
  responseMessage.append( "ERROR" );
  } finally {
  try {
  if ( hcon != null ) hcon.close();
  if ( dis != null ) dis.close();
  } catch ( IOException ioe ) {
  ioe.printStackTrace();
  }//结束try/catch
  }//结束try/catch/finally
  return responseMessage.toString();
  }//结束sendHttpGet( String )

  private String sendHttpPost( String url )
  {
  HttpConnection hcon = null;
  DataInputStream dis = null;
  DataOutputStream dos = null;
  StringBuffer responseMessage = new StringBuffer();
  // 请求体
  String requeststring = "This is a POST.";

  try {
  // 使用读写权限的 HttpConnection
  hcon = ( HttpConnection )Connector.open( url, Connector.READ_WRITE );

  //设置请求方法为POST
  hcon.setRequestMethod( HttpConnection.POST );

  // 取得发送请求字符串的DataOutputStream
  dos = hcon.openDataOutputStream();
  byte[] request_body = requeststring.getBytes();

  // 发送请求字符串到服务器
  for( int i = 0; i < request_body.length; i++ ) {
  dos.writeByte( request_body[i] );
  }//结束 for( int i = 0; i < request_body.length; i++ )

  // 取得做为接收服务器响应的DataInputStream
  dis = new DataInputStream( hcon.openInputStream() );

  // 从服务器上取回响应
  int ch;
  while( ( ch = dis.read() ) != -1 ) {
  responseMessage.append( (char)ch );
  }//结束while( ( ch = dis.read() ) != -1 ) {
  }
  catch( Exception e )
  {
  e.printStackTrace();
  responseMessage.append( "ERROR" );
  }
  finally {
  // 释放输入输出流和HTTP连接
  try {
  if( hcon != null ) hcon.close();
  if( dis != null ) dis.close();
  if( dos != null ) dos.close();
  } catch ( IOException ioe ) {
  ioe.printStackTrace();
  }//结束try/catch
  }//结束try/catch/finally
  return responseMessage.toString();
  }//结束sendHttpPost( String )

  public void pauseApp() {
  }//结束pauseApp()

  public void destroyApp( boolean unconditional ) {
  myDisplay = null;
  requestScreen = null;
  requestField = null;
  resultScreen = null;
  resultField = null;
  }//结束 destroyApp( boolean )
  }//结束HttpMidlet

 

分享到:
评论

相关推荐

    在无线J2ME设备上实现超文本传输协议

    在无线J2ME设备上实现超文本传输协议主要涉及到的是如何使用Java Micro Edition (J2ME)技术在有限资源的移动设备上与Web服务器进行通信。J2ME是一种轻量级的Java平台,专为嵌入式设备如手机、PDA等设计,它包括了...

    j2me网络类http协议传输

    j2me网络类,http协议传输j2me网络类,http协议传输j2me网络类,http协议传输

    J2ME无线设备编程

    **J2ME无线设备编程** 是Java Micro Edition(Java ME)在无线设备上进行应用程序开发的重要领域。这一技术主要用于移动电话、智能手表、PDA等嵌入式设备,为这些设备提供丰富的应用程序和服务。 J2ME的核心是Java...

    J2ME 无线设备编程

    **J2ME 无线设备编程**是Java技术在移动设备和嵌入式系统中的应用,主要针对资源有限的设备如手机、智能手表等。J2ME全称为Java Micro Edition,它是Java平台的一个子集,旨在为小型设备提供可移植性和性能优化的...

    j2me无线设备编程.rar

    《J2ME无线设备编程》是一本专注于Java Micro Edition(J2ME)在无线设备上应用开发的专业书籍。J2ME作为Java平台的一个子集,主要用于嵌入式系统,特别是移动设备,如早期的智能手机、PDA以及各种物联网设备。本书...

    精通J2ME无线编程.pdf

    读者将学习到如何编写、编译和测试J2ME应用程序,以及如何在模拟器和真实设备上运行这些程序。 在核心概念部分,作者会介绍CLDC和MIDP的关键组件,如Class Library、User Interface (UI) 构建、以及如何使用Java ...

    J2ME无线设备编程指南

    在“J2ME无线设备编程指南”中,我们将深入探讨如何利用J2ME技术开发无线应用,为这些设备提供丰富的功能。 1. **J2ME架构** J2ME由配置(Configurations)和框架(Profiles)组成。配置定义了最小的Java运行环境...

    J2ME无线设备程序设计-.rar

    WAT,全称为Wireless Application Toolkit,是Sun Microsystems(现已被Oracle收购)推出的一款模拟器,用于测试J2ME应用在不同无线设备上的行为。它可以帮助开发者在没有物理设备的情况下进行开发和调试,模拟各种...

    J2ME无线设备编程.rar

    这个压缩包"J2ME无线设备编程.rar"显然包含了一组资源,可能包括教程、示例代码或文档,用于教授如何在无线设备上使用J2ME进行编程。J2ME广泛应用于手机、智能手表、数字电视等设备,其核心在于提供一套可以在这些...

    在J2ME中开发蓝牙无线软件

    2. **javax.obex** - 用于实现对象交换协议 (OBEX, Object Exchange),这是蓝牙设备间数据传输的一种常见方式。 #### 三、蓝牙Java API的核心组成部分 蓝牙Java API的核心组成部分包括: 1. **蓝牙控制中心 (BCC, ...

    j2me midp无线设备编程指南

    《J2ME MIDP无线设备编程指南》是针对在移动设备上进行软件开发的专业书籍,主要聚焦于Java Micro Edition(J2ME)平台中的Mobile Information Device Profile(MIDP),这是Java为移动和嵌入式设备设计的一个子集。...

    用J2ME在移动设备上实现动画

    使用MIDP(Mobile Information Device Profile)的开发人员经常会抱怨用些什么办法才可以在一个MIDlet上显示动画。MIDP 1.0 没有直接提供对动画的支持(正在开发中的MIDP 2.0支持),但真要是自己去实现,其实也并非是一...

    J2ME实现超级玛丽源码

    7. **优化与性能**:由于J2ME运行在资源有限的设备上,性能优化至关重要。这包括减少不必要的计算、优化图像资源、合理安排内存使用等。 通过对上述知识点的掌握和运用,开发者能够在J2ME环境中构建出一个基本的...

Global site tag (gtag.js) - Google Analytics