天气预报版块
要学习这个版块,那首先应该知道作者怎么得到这个服务的(不要照着书完成了例子就觉得行啦),作者是从这里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
< 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" >
< a class ="controls" href ="javascript:minimize('weatherContent');" >
-
</ a >
< a 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">
<a class="controls" href="javascript:minimize('weatherContent');">
-
</a>
<a 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
Weather for ${forecastData.placeName}, ${forecastData.stateCode}
代码清单8-4 weatherTable.jsp
< 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-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
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
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 ;
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
< 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