Ajax - 基础教程第八章例子学习二

来源:互联网 发布:专业网络整合推广 编辑:程序博客网 时间:2024/05/23 01:19

天气预报版块 

要学习这个版块,那首先应该知道作者怎么得到这个服务的(不要照着书完成了例子就觉得行啦),作者是从这里http://www.webservicex.net/WeatherForecast.asmx 得到天气预报服务的(美国的),它提供两种方法查询天气预报,一种是查询PlaceName(地点名称), 一种是查询ZipCode(邮政编码)。

跟这个版块相关的类

ArrayOfWeatherData.class
WeatherData.class
WeatherForecast.class
WeatherForecastLocator.class
WeatherForecasts.class
WeatherForecastSoap.class
WeatherForecastSoapStub.class

我查看了代码,发现每个都是by the Apache Axis 1.2.1 Jun 14, 2005 (09:15:57 EDT) WSDL2Java emitter

没错上面的类都是WSDL2Java工具生成的,下面是我两天的努力的成果 。

服务的wsdl是:http://www.webservicex.net/WeatherForecast.asmx?WSDL   点击看看

在eclipse中,点击项目-》右击-》运行方式-》运行-》弹出运行对话框

在对话框中,1.在左边的框中 点击java应用程序-》新建

                        2.在右边的框中 如果新建成功,主要-》main类是空的,先选中下面的“搜身main类是包括库”

                        点击搜索WSDL2Java

                        或者直接填 org.apache.axis.wsdl.WSDL2Java

                       3. 在右边的框中,点击(x=)自变量-》程序自变量 里面填下面的内容:

                          -o ./src

                          -Nurn:WeatherForecast  ajaxdashboard.ws.weatherforecast

                                      http://www.webservicex.net/WeatherForecast.asmx?WSDL

                        这里说明下 -o 输出文件所在目录(“. ” -代表当前目录

                  -Nurn:命名空间 包名(这个我试了没用) wsdl

其实上面的过程就是java org.apache.axis.wsdl.WSDL2Java  -o ./src -Nurn:WeatherForecast  ajaxdashboard.ws.weatherforecast  http://www.webservicex.net/WeatherForecast.asmx?WSDL

查下你项目的src文件夹,下面有个net.webservicex.www包

ArrayOfWeatherData.java
WeatherData.java
WeatherForecast.java
WeatherForecastLocator.java
WeatherForecasts.java
WeatherForecastSoap.java
WeatherForecastSoapStub.java

这些类跟源代码里面的类一模一样,把包名改下就行了

 一。 weatherForecast.jsp页面

代码清单8-2 weatherForecast.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 

<div id="root" style="left:20px; top:20px;">
    
<div id="handle">
            
        
<table width="100%" border="0" class="textbox">
            
<tr>
                
<td align="left" class="controls">
                    
<span id="forecastLocation">
                        
<%@ include file="weatherLocation.jsp" %>
                    
</span>
                
</td>
                
<td align="right">
                    
<class="controls" href="javascript:minimize('weatherContent');">
                        -
                    
</a>
                    
&nbsp;
                    
<class="controls" href="javascript:maximize('weatherContent');">
                        +
                    
</a>
                
</td>
            
</tr>
        
</table>

    
</div>
    
    
<div class="normalText">
        Zip Code: 
        
<input type="text" name="forecastZipCode" id="forecastZipCode" 
            onkeyup
="handleZipCodeChange();" class="normalText" 
            value
="<%=ajaxdashboard.Constants.DEFAULT_WEATHER_ZIP_CODE%>"/>
            
    
</div>
    
    
<div id="weatherContent">
       
<%@ include file="weatherTable.jsp" %>
    
</div>
</div>

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 
此tag是 jstl1.1的核心tag

<div id="root" style="left:20px; top:20px;">
            <div id="handle">
这个页面中,最外层有个id为root的div,root里面有一个id为handle的div,一个输入zipcode的div,最后一个是显示天气内容的div。

在ajaxDashboard.js中,在加载页面是执行了 initDomDrag("handle", "root");

function initDomDrag(handleID, rootID) {
    var handle = document.getElementById(handleID);
    var root = document.getElementById(rootID);
    Drag.init(handle, root);
}

Drag.init(handle, root)是dom-drag.js的功能。使主组件跟着某个子组件鼠标拖动。

id为handle的div就是这个子组件,root就是这个父组件。

<td align="right">
                    
<class="controls" href="javascript:minimize('weatherContent');">
                        -
                    
</a>
                    
&nbsp;
                    
<class="controls" href="javascript:maximize('weatherContent');">
                        +
                    
</a>
                
</td>
            
</tr>

minimize()和maximize()在common.js中

 Zip Code: 
        <input type="text" name="forecastZipCode" id="forecastZipCode" 
            onkeyup
="handleZipCodeChange();" class="normalText" 
            value
="<%=ajaxdashboard.Constants.DEFAULT_WEATHER_ZIP_CODE%>"/>
这是一个输入框,默认值是<%=ajaxdashboard.Constants.DEFAULT_WEATHER_ZIP_CODE%>,由于DEFAULT_WEATHER_ZIP_CODE是一个static的变量,所以可以直接引用。

整个页面

 rootDIV{

        handleDIV{

                  table

                             tr{weather for 地名,州代码                        +-}

                 }

        }

        DIV{
        ZipCode:<input>
 

       }

       weatherContentDIV{

       天气内容

       }

二。 在天气预报的主页,include了2个页面,一个是报位置的,一个是报内容的,来看看他们的代码清单吧

代码清单8-3 weatherLocation.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 

Weather 
for ${forecastData.placeName}, ${forecastData.stateCode}

代码清单8-4 weatherTable.jsp

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 

<table>
    
<tbody>
        
<tr>
            
<c:forEach var="forecast" items="${forecastData.details.weatherData}">    
                
<td>
                    ${forecast.day}

                    
<br/>
                    High: ${forecast.maxTemperatureF}

                    
<br/>
                    Low: ${forecast.minTemperatureF}

                    
<br/>
                    
<img src="${forecast.weatherImage}" alt="forecast image"/>
                
</td>
            
</c:forEach>
        
</tr>
    
</tbody>    
</table>

${forecastData.placeName} 这些哪里来的,不用慌张! 这里用的是EL表达式,forecastData是一个request的变量名,request.setAttribute("forecastData", forecastService.getForecastFor("55431"));
这是在WeatherForecastServlet中找到的。forecastData的结构 看 类WeatherForecasts,因为前者是后者的一个对象。

三。 整个版块的工作过程

1. 加载页面时,ajaxDashboard.js运行handleZipCodeChange(); 

    上面的方法在weatherForecast.js中定义的,

    var weatherForecastIntervalID = 0;         //定时器开关

     function handleZipCodeChange() {
                 var zipCode = document.getElementById("forecastZipCode").value;//取得输入的邮政编码的值
                 if(isValidZipCode(zipCode)) {                        //验证邮政编码值是否正确
                           updateWeatherForecast();
                           startWeatherUpdateInterval();
                }
               else {
                    if(weatherForecastIntervalID != 0) {
                          window.clearInterval(weatherForecastIntervalID);
                          weatherForecastIntervalID = 0;
                  }
             }
     }
    

     function updateWeatherForecast() { //ajax启动,下面的语句是taconite框架的用法
              var ajaxRequest = new AjaxRequest("UpdateWeatherForecast");//" "里面是用到的Servlet
              ajaxRequest.addFormElementsById("forecastZipCode");               //" "里面是邮政编码输入框的Id,想加其他参数用 ("","");这种方法 
              ajaxRequest.sendRequest();
     }

     function startWeatherUpdateInterval() {      //设置定时器,300秒(5分钟)自动更新一次
              weatherForecastIntervalID = window.setInterval("updateWeatherForecast()", 300000);
    }

2. UpdateWeatherForecastServlet

    在源代码中, 跟天气预报版块有关的Servlet有2个UpdateWeatherForecastServlet.java,
WeatherForecastServlet.java   但WeatherForecastServlet.java 在我本人竭尽全力的搜索中,却还是没发现它有被应用到的痕迹.

    在web.xml中添加

<servlet>
        
<servlet-name>UpdateWeatherForecastServlet</servlet-name>
        
<servlet-class>ajaxdashboard.servlet.UpdateWeatherForecastServlet</servlet-class>
    
</servlet>
    
<servlet-mapping>
        
<servlet-name>UpdateWeatherForecastServlet</servlet-name>
        
<url-pattern>/UpdateWeatherForecast</url-pattern>
    
</servlet-mapping>

 

    跟UpdateWeatherForecastServlet有关联的一个类是WeatherForecastService ,它是个服务类, 作用是把取得的日期如 sunday, July 05,2007格式 转化成比较短的日期sun,07/05这样的格式,注意如果您身处美国, 那这个类用起来没问题, 如果您是在中国, 有2个地方需要修改, 红色为修改部分

SimpleDateFormat parser = new SimpleDateFormat("EEEE, MMMM dd, yyyy", Locale.US);
            
SimpleDateFormat formatter 
= new SimpleDateFormat("EEE. MM/dd", Locale.US);
可能在中国,Locale.CHINA是默认的吧, 像第二个不改,显示的应该是 星期天,07/05, 结果显示乱码就成了???,07/05了

     代码清单8-5 UpdateWeatherForecastServlet.java

package ajaxdashboard.servlet;

import ajaxdashboard.service.WeatherForecastService;
import ajaxdashboard.ws.weatherforecast.WeatherForecasts;

import java.io.*;
import java.util.Date;

import javax.servlet.*;
import javax.servlet.http.*;

public class UpdateWeatherForecastServlet extends HttpServlet {
    
protected void processRequest(HttpServletRequest request
                                            , HttpServletResponse response)
                                            
throws ServletException, IOException {
        
        String zipCode 
= request.getParameter("forecastZipCode");

        WeatherForecasts weaths 
= new WeatherForecasts();
        
        WeatherForecastService forecastService 
= new WeatherForecastService();
        
        weaths 
= forecastService.getForecastFor(zipCode);
        
        request.setAttribute(
"forecastData"
                                    , weaths);
//forecastService.getForecastFor(zipCode));
        
        System.out.println(
"Weather updated at: " + new Date().toString());
        
        request.getRequestDispatcher(
"/weather/weatherForecastAjax.jsp")
                                                    .forward(request, response);
    }
    
protected void doGet(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
    
protected void doPost(HttpServletRequest request, HttpServletResponse response)
    
throws ServletException, IOException {
        processRequest(request, response);
    }
}

代码清单8-6 WeatherForecastService.java

package ajaxdashboard.service;

import ajaxdashboard.ws.weatherforecast.WeatherData;
import ajaxdashboard.ws.weatherforecast.WeatherForecast;
import ajaxdashboard.ws.weatherforecast.WeatherForecastLocator;
import ajaxdashboard.ws.weatherforecast.WeatherForecastSoap;
import ajaxdashboard.ws.weatherforecast.WeatherForecasts;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;

import javax.xml.rpc.ServiceException;

public class WeatherForecastService {
    
public WeatherForecasts getForecastFor(String zipCode) {
        WeatherForecasts forecasts 
= null;
        
try {
            forecasts 
= getWeatherForecastSoap().getWeatherByZipCode(zipCode);
            WeatherData[] dataArray 
= forecasts.getDetails().getWeatherData();
            
            WeatherData data 
= null;
            //相对于源代码,下边的2句做了正确的修改
            SimpleDateFormat parser 
= new SimpleDateFormat("EEEE, MMMM dd, yyyy",Locale.US);
            
            SimpleDateFormat formatter 
= new SimpleDateFormat("EEE. MM/dd",Locale.US);

            
for(int i = 0; i < dataArray.length; i++) {
                data 
= dataArray[i];
                
try {
                    data.setDay(formatter.format(parser.parse(data.getDay())));
                }
                
catch(Exception e) {
                    System.out.println(
" Parsing Exception: " + e );
                }
            }

        } 
        
catch(java.rmi.RemoteException ex) {
            
// TODO handle remote exception
            ex.printStackTrace();
        }

        
return forecasts;
    }

    
private WeatherForecastSoap getWeatherForecastSoap() {
        WeatherForecastSoap weatherForecastSoap 
= null;
        
try {
            weatherForecastSoap 
= new WeatherForecastLocator().getWeatherForecastSoap();
        } 
        
catch (ServiceException ex) {
            ex.printStackTrace();
        }
        
        
return weatherForecastSoap;
    }
}

        request.setAttribute("forecastData"
                                    , 
forecastService.getForecastFor(zipCode));
        
        request.getRequestDispatcher("/weather/weatherForecastAjax.jsp")
                                                    .forward(request, response);
3. 在前面学过的AJAX例子中, 在Servlet中得到结果后就要PrintWriter返回结果,但这个例子也完全不是这样做的,那是因为taconite框架的原因,  看看weatherForecastAjax.jsp

代码清单8-7 weatherForecastAjax.jsp

<%@ taglib uri="http://taconite.sf.net/tags" prefix="tac" %>

<tac:taconiteRoot>

    
<tac:replaceChildren contextNodeID="forecastLocation" parseOnServer="true">

        
<%@ include file="weatherLocation.jsp" %>
    
    
</tac:replaceChildren>

    
<tac:replaceChildren contextNodeID="weatherContent" parseOnServer="true">
        
        
<%@ include file="weatherTable.jsp" %>

    
</tac:replaceChildren>
    
</tac:taconiteRoot>

       多亏了taconite框架的神奇, 在处理一个AJAX请求的响应时要动态的更新页面, 现在不用花时间去写W3C DOM了,相反, taconite会为你生成 JavaScript, 生成的JavaScript 将返回浏览器,并在浏览器执行来生成所需的结果

       下面一行一行地分析weatherForecastAjax.jsp的代码, 以便了解Taconite框架是怎么工作的. 文件的第一行是只是一个Jsp tiglib声明,声明了Taconite taglib.

       <tac:taconiteRoot>标记是所有Taconite响应的根标记。在后台,Taconite总是向浏览器返回一个xml文档。在XML中可能嵌有JavaScript(如果解析在服务器端完成)或XHTML(如果解析在浏览器端完成)。<tac:taconiteRoot>要作为所返回的XML的根标记,使用Taconite标记库的所有JSP文件都必须使用<tac:taconiteRoot>标记。

       每次作出Ajax请求来更新天气预报时,都必须更新天气预报组件中的两项:位置(跟zipcode有关)和具体的预报。<tac:taconiteRoot>标记中有两个<tac:replaceChildren>作为其直接子标记,第一个是更新预报位置,第二个是更新天气预报。

       具体的工作就是在<tac:replaceChildren>中完成的,它的作用是:" 对于有指定Id属性值的元素,要用以下的内容替换该元素的所有子元素"。<tac:replaceChildren>标记有一个必要的属性:contextNodeID,contextNodeID指定了要用<tac:replaceChildren>标记的内容替换那个节点的子元素。

       在这个例子中,第一个<tac:replaceChildren>标记的contextNodeID属性值为forecastLocation,在weather/weatherForecast.jsp中你应该可以找到个id为forecastLocation的span元素。所以,这个<tac:replaceChildren>标记告诉Taconite框架:forecastLocation的span元素的子元素都应用<tac:replaceChildren>标记指定的内容替换。而指定的内容来自weatherLocation.jsp文件。

       第二个<tac:replaceChildren>标记会更新天气预报的内容,这个标记中的contextNodeID属性值为weatherContent,在weather/weatherForecast.jsp中,你应该可以找到个id为weatherContent的div元素。这个div元素的子元素将会被<tac:replaceChildren>标记指定的内容替换,指定的内容来自weatherTable.jsp。

       这个例子中,每个<tac:replaceChildren>标记都有一个名为parseOnServer的属性,这是一个可选的属性,如果没这个属性的,其默认值为true,则指示Taconite要在服务器端将指定内容解析为JavaScript,并把JavaScript嵌在响应XML中发回给浏览器。如果值为false,则指示在浏览器把内容解析为JavaScript,工作也在浏览器上完成。

 修正了上面两出问题后,相信你的weaherForecast.jsp应该能正常的运行了。

注意:到了晚上,7天的预报会变成6天预报而已

下一部分新闻版块的说明

http://blog.csdn.net/lin49940/archive/2007/09/05/1773439.aspx

原创粉丝点击