⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jan02_ericg.txt

📁 TechTips j2me的常用技巧. 网络功能
💻 TXT
📖 第 1 页 / 共 2 页
字号:

 J 2 M E    T  E  C  H    T  I  P  S

                      TIPS, TECHNIQUES, AND SAMPLE CODE


WELCOME to the Java Developer Connection(sm) (JDC)
Java(tm) 2 Platform, Micro Edition (J2ME(tm)) 
Tech Tips, for January 31, 2002. This issue covers:

     * Maintaining Client State Across HTTP Requests
     * Using Fixed Point Arithmetic in the Connected Limited
       Device Configuration
         
The J2ME Tech Tips are written by Eric Giguere
(http://www.ericgiguere.com), an engineer at iAnywhere 
Solutions, inc. Eric is the author of the book "Java 2 Micro
Edition: Professional Developer's Guide" and co-author of the 
book "Mobile Information Device Profile for Java 2 Micro 
Edition," both books in John Wiley & Sons' Professional 
Developer's Guide series.

You can view this issue of the J2ME Tech Tips on the Web at
http://java.sun.com/jdc/J2METechTips/2002/tt0131.html

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
MAINTAINING CLIENT STATE ACROSS HTTP REQUESTS

Due to the constraints of the J2ME platform, many J2ME 
applications offload some of their work to a server. A natural 
way for the client to communicate with the server is to follow
the HTTP protocol. There are two good reasons for this. First, 
HTTP is a widely recognized and supported protocol. The Mobile 
Information Device Profile (MIDP), for example, includes HTTP 
support through the HttpConnection interface. Second, HTTP lets 
you do more than just fetch web pages. You can also invoke 
server-side code written as servlets or JavaServer Pages(tm)
(JSP(tm)). This makes HTTP a natural and familiar way to 
communicate with Java(tm) 2 Platform, Enterprise Edition 
(J2EE(tm)) servers.

One problem with HTTP is that it was designed specifically as 
a stateless protocol. In other words, each HTTP request-response 
cycle is independent and isolated. The server potentially keeps 
client connections open only as long as necessary to service 
a single request. This allows a Web server to service many more 
clients than would be possible if each client kept an open 
connection to the server. But it also means that the server 
cannot identify which requests come from which clients based 
solely on the connection. Instead, the clients send some form of 
identification to the server with each request. The server can 
then track which request comes from which client, and create 
a session for each client. Tracking clients this way is referred 
to as session tracking.

The simplest kind of session tracking occurs when the client 
sends a unique identifier along with each request. For example:

String URL = "http://www.mysite.com/servlet/MyApp";
int    id = ...; // get the ID somewhere

HttpConnection conn = (HttpConnection)
             Connector.open( URL + "&id=" + id );

The identifier can be sent as a request parameter or as an HTTP 
header. The servlet or JSP extracts the value from the request to 
identify the client. But where does the unique identifier come 
from? It can't be a randomly-generated value, since there's no 
guarantee it won't conflict with a number generated by another 
client. The name (or userid) of the user is a possibility, but 
only if combined with other information. This additional 
identification is needed in case the user runs the same 
application on two or more devices in overlapping time periods.


A better solution is to let the server generate a unique 
identifier for each session. The server passes this identifier 
back to the client as part of the response to the client's first
request. The client is then responsible for passing it back to 
the server on each subsequent request. This is in fact how Web 
browsers and Web servers do session tracking. It's usually 
referred to as cookie-based session tracking because it involves
the exchange of a "cookie" between the two sides. A cookie is
a short string of encoded data. It's easy to use cookie-based 
session tracking in J2ME applications.

When a Web server replies to a request, it usually includes 
additional information in the headers of the HTTP response. If 
cookies are enabled, the response includes one or more Set-Cookie 
headers. For example, if you connect to a Web application on 
a Tomcat server and the response that comes back
includes a cookie definition, the Set-Cookie header looks 
something like this:

Set-Cookie: JSESSIONID=12ae8%33dk22KKLdk39jKK9;path=/

A Set-Cookie header consists of several parts, each separated by 
a semicolon. Most of these parts are optional. You can find the 
full specification on Netscape's site at
http://home.netscape.com/newsref/std/cookie_spec.html.
For J2EE servers, the cookie is always named "JSESSIONID",
but for other servers it varies -- see the specification for
the exact details. The client extracts the cookie and stores it.
Subsequent requests by the client back to server should
include a Cookie header, like this:

Cookie: JSESSIONID=12ae8%33dk22KKLdk39jKK9

The server then knows which session to associate with the 
request. (As an aside, a useful tool to see raw HTTP responses 
returned by Web servers is found at 
http://www.rexswain.com/httpview.html.)

Here's an example of a simple servlet that counts the number of 
times it has been accessed by a particular client:

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

/**
 * A simple servlet that increments a counter each
 * time a request is made. The counter is stored
 * as a session attribute.
 */

public class Counter extends HttpServlet {

    public static final String BINARY =
                        "application/octet-stream";

    public static final String HTML =
                        "text/html";

    public void doGet( HttpServletRequest request,
                       HttpServletResponse response )
            throws IOException, ServletException {

        // Get the client session. If none exists,
        // this creates one. The server will
        // automatically add a Set-Cookie header to
        // the servlet output.

        HttpSession session = 
                           request.getSession( true );

        // Get the old counter value, if it exists.
        // Otherwise create a new one initialized to 0.

        Integer counter = (Integer)
                      session.getValue( "counter" );

        if( counter == null ){
            counter = new Integer( 0 );
        } 

        // Increment the counter and store the new
        // value back in the session.

        counter = new Integer( 
                              counter.intValue() + 1 );
        session.putValue( "counter", counter );

        // If client is a J2ME device, send counter
        // back as a simple integer, otherwise wrap
        // it in an HTML page for viewing with a
        // conventional web browser.

        String ua = request.getHeader( "User-Agent" );

        if( ua.indexOf( "CLDC" ) != -1 ){
            ByteArrayOutputStream bout =
                          new ByteArrayOutputStream();
            DataOutputStream dout =
                         new DataOutputStream( bout );

            dout.writeInt( counter.intValue() );
            dout.close();

            byte[] data = bout.toByteArray();

            response.setContentType( BINARY );
            response.setContentLength( data.length );

            OutputStream out = 
                            response.getOutputStream();
            out.write( data );
            out.close();
        } else {
            response.setContentType( HTML );

            PrintWriter out = response.getWriter();
            out.write( "<HTML><BODY>" );
            out.write( counter.toString() );
            out.write( "</BODY></HTML>" );
            out.close();
        }
    }
}

Compile and install this on a servlet-enabled Web server, mapping 
it to the path "/counter".  For example, if you use the Tomcat 
Web server, place the class file in the ROOT web application's 
WEB-INF\classes directory (create the directory if necessary). 
Then add the following lines to the WEB-INF\web.xml file:

  <servlet>
    <servlet-name>Counter</servlet-name>
    <servlet-class>Counter</servlet-class>
  </servlet>
    
  <servlet-mapping>
    <servlet-name>Counter</servlet-name>
    <url-pattern>/counter</url-pattern>
  </servlet-mapping>
   
Use a Web browser to invoke the servlet -- for Tomcat surf to 
http://localhost:7080/counter -- and press the browser's refresh 
button several times. You should see the counter value increment. 
The servlet generates HTML output unless the User-Agent header 
sent with the response includes the string "CLDC", in which case,
it writes the counter value directly to the output stream as 
a raw integer.

Here's the code for a simple MIDlet that makes multiple requests 
to the servlet shown above. The response to the first request is 
scanned for a Set-Cookie header, and the cookie is then used on 
all subsequent requests:

import java.io.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.io.*;

/**
 * A class that repeatedly makes requests to
 * the same URL, displaying a counter value
 * sent back by the web server.
 */

public class CounterTest extends MIDlet {

    private Display display;

    private Command exitCommand =
               new Command( "Exit", Command.EXIT, 1 );
    private Command cancelCommand =
               new Command( 
                        "Cancel", Command.CANCEL, 1 );

    // The hardcoded URL -- adjust appropriately.

    private String URL = 
                       "http://localhost:7080/counter";

    // Standard MIDlet stuff....

    public CounterTest(){
    }

    protected void destroyApp( boolean unconditional )
                    throws MIDletStateChangeException {
        exitMIDlet();
    }

    protected void pauseApp(){
    }

    protected void startApp()
                    throws MIDletStateChangeException {
        if( display == null ){
            initMIDlet();
        }
    }

    private void initMIDlet(){
        display = Display.getDisplay( this );
        display.setCurrent( new Tester() );
    }

    public void exitMIDlet(){
        notifyDestroyed();
    }

    // Utility routine to display exceptions.

    void displayError( Throwable e ){
        System.out.println( e.toString() );
        exitMIDlet();
    }

    // Utility routine to split a string into two.

    static String[] split( String in, char ch ){
        String[] result = new String[2];
        int      pos = in.indexOf( ch );

        if( pos != -1 ){
            result[0] = in.substring( 0, pos ).trim();
            result[1] = in.substring( pos+1 ).trim();
        } else {
            result[0] = in.trim();
        }

        return result;
    }

    // Simple list used to display the counter values.
    // Spawns a thread that repeatedly connects to a
    // web server and reads a counter value encoded in
    // the response.

    class Tester extends List
                implements Runnable, CommandListener {
        private HttpConnection conn;
        private boolean        done;

        Tester(){
            super( "Counter Test", Choice.IMPLICIT );

            addCommand( cancelCommand );
            setCommandListener( this );

            Thread t = new Thread( this );
            t.start();
        }

        // Here we either exit or else set the
        // flag to cancel the HTTP operation.

        public void commandAction( Command c,
                                   Displayable d ){
            if( c == exitCommand ){
                exitMIDlet();
            } else {
                done = true;
                removeCommand( cancelCommand );
            }
        }

        // Do the connection and processing on
        // a separate thread...

        public void run(){
            int            count = 20;
            HttpConnection conn = null;
            String         cookie = null;

            while( !done && count-- > 0 ){
                try {
                    conn = (HttpConnection)
                                Connector.open( URL );

                    // Set required headers

                    conn.setRequestProperty( 
                                          "User-Agent",
        "Profile/MIDP-1.0 Configuration/CLDC-1.0" );
                    conn.setRequestProperty(
                         "Content-Language", "en-US" );

                    // If we have a cookie, send it

                    if( cookie != null ){
                        conn.setRequestProperty(
                         "Cookie", cookie );
                    }

                    // Connect, then read cookie value
                    // if we don't have one already
                    
                    int rc = conn.getResponseCode();

                    if( cookie == null ){
                        cookie = readCookie( conn );
                    }

                    // Read counter value

                    InputStream in =
                          conn.openInputStream();
                    DataInputStream din =
                          new DataInputStream( in );
                    Integer counter =
                          new Integer( din.readInt() );

                    append( counter.toString(), null );
                    in.close();
                }
                catch( IOException e ){
                    displayError( e );
                }

                if( conn != null ){
                    try {
                        conn.close();
                    }
                    catch( IOException e ){
                        displayError( e );
                    }
                }
            }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -