Struts meets Swing 1 (翻译)

原文:[URL]http://javaboutique.internet.com/tutorials/Swing/index.html[/URL]

[size=large]1.简介:[/size]
Jakarta Struts是基于MVC模式创建servlet应用程序的框架。大部分的Struts应用程序都是使用浏览器作为客户端,实际上Struts足够的开放,它可以使用其它的客户端模式。在这里我将在我 "Coding your second Jakarta Struts Application"这篇文章里的一个浏览器应用实例改成Swing客户端模式,只需要修改一点代码。
这篇文章主要介绍如何使用Swing客户端去连接已经存在的Servlet应用。如果你打算开发一个java应用程序,既能够使用浏览器做客户端也可以用Swing做客户端,你就需要根据你程序的需要灵活的选择构架,如EJB或web service,他们提供了简单的接口。

[size=large]2.Struts结构[/size]
在我们开始之前,先看看浏览器如何和Struts应用通信的。这些将在我们的Swing应用程序中体现。
*Struts应用程序是由servlet接受到GET或POST请求开始的。
*servlet决定调用哪个"action",是从URL中获得信息的。
*实现了Action的java类是在struts-config.xml中配置的。
* Struts的输出由jsp来显示,jsp的名字也在struts-config.xml文件中指定。
所以第一个非浏览器应用需要能够给servlet发送一个请求,并且能从jsp页面得到响应。

[size=large]3.The URLConnection class
[/size]
使用URLConnection类能够很简单的使用java编写servlet请求代码。这个类很有趣,因为它有一些奇怪的设计。如果你想看看它的实现,我建议你读一读"Dodge the traps hiding in the URLConnection class".
如果想发送一个带有"list"action的请求,并接受打印响应,你需要这样写代码:

[code]URL url = new URL("http://myserver/project/list.do");
URLConnection conn = url.openConnection();

BufferedReader in =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
[/code]

一般来讲你通常需要在请求的同时发送一些数据--就像提交表单那样。这些数据需要在你读取响应前发送过去。

[code]URL url = new URL("http://myserver/project/list.do");
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.setRequestProperty("user-agent","SWING");

BufferedWriter out =
new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
out.write("name1=value1&name2=value2");
out.flush();
out.close();

String c = conn.getHeaderField("Set-Cookie");
BufferedReader in =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
[/code]

这个例子同时也显示了如何读写HTTP头信息。
第一个例子使用GET方法与HTTP通信,而第二个例子使用POST方法通信。你同样可以使用GET方法来给servlet传送数据,但是就必须要把数据加到URL里,像这样:
[code]URL url = new URL("http://myserver/project/list.do?name1=value1&name2=value2");[/code]

[size=large]4.Identifying the client[/size]
现在我们知道怎么发送和请求数据了,但是我们怎么接受数据呢?如果响应是给浏览器的,那响应里就包含了HTML或者还有JavaScript和样式。对于我们的Swing客户端,我们只需要数据。这将带来一个新问题:Struts应用程序如何能识别出客户端是一个浏览器,是个Swing还是其它什么呢?
一种解决办法是在每个请求里添加参数时其能间鉴别出是哪种客户端。我在第二个例子里已经使用了user-agent这个头信息来使其识别出是个Swing客户端。
当Struts应用程序准备好给客户端返回数据时,它就会检测user-agent的值,然后选择适合客户端的jsp页面。这将会替代Struts Action类设置的跳转信息。

[code]String client = (String)request.getHeader("user-agent");
// Forward control to the list page
if (client.equals("SWING"))
return (mapping.findForward("swinglist"));
else return (mapping.findForward("list"));
[/code]

"list"和"swinglist"的在Struts配置文件里定义:
[code]<forward name="list" path="/list.jsp"/>
<forward name="swinglist" path="/swinglist.jsp"/>[/code]

list.jsp是为在浏览器显示的,swinglist.jsp则是在Swing上显示的。

在我们开始创建swinglist.jsp前,先看一个例子程序,改程序将使用文章里提到的方法。

[size=large]The DVD application
[/size]
这个应用程序是在xml文件里管理DVD的。它将会以列表的方式显示所有的DVD,并且可以在详细页面里添加,修改或删除DVD.列表像这样。
[color=red]图片见原文[/color]

DVDManager类监听DVD应用程序,它将DVD信息保存为JDOM的树结构。DVDManager从xml文件中读取DVD信息,并能够将这些信息再保存到xml文件里。xml格式很明显是返回数据给Swing应用程序的一种选择。

[size=large]Returning XML data to the client[/size]

这就意味着,swinglist.jsp要返回数据给Swing客户端,就必须以xml的方式来存放DVD。JDOM有能将树结构转换成PRintWriter的方法,我们只要简单的获取这些输出流并将它发送给Swing客户端即可。DVDmanager里的第一个新方法就是:
[code]public void outList(PrintWriter out) {
XMLOutputter outputter = new XMLOutputter("",false);
// NB: the outputter does not accept XML headers:
outputter.setOmitDeclaration(true);
try {
outputter.output(doc, out);
} catch (IOException e) {
e.printStackTrace();
}
}[/code]

这个方法将被swinglist.jsp调用:

[code]<%@ page language="java" %>
<%@ page import="java.io.*" %>

<jsp:useBean id="dvds"
class="hansen.playground.DVDManager" scope="session"/>

<%
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
dvds.outList(pw);
pw.flush();
out.print(sw.toString());
%>
[/code]

相似的方法我们创建一个swingdetail.jsp页面,这个页面将返回一个的xml文件,包含着单个的DVD信息:

[code]<%@ page language="java" %>
<%@ page import="java.io.*" %>

<jsp:useBean id="dvds"
class="hansen.playground.DVDManager" scope="session"/>

<%
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
dvds.outListElement(pw);
pw.flush();
out.print(sw.toString());
%>[/code]

我们可以不使用JDOM的XMLOutputter类来创建xml响应而直接手动编码。让我来给个例子:如果我们只想返回DVD的名字,我们能创建一个像这样的jsp页面:

[code]<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>

<jsp:useBean id="dvds"
class="hansen.playground.DVDManager" scope="session"/>

<collection>
<logic:iterate id="dvd" indexId="i" name="dvds" property="dvds">
<%
// Transfer the iteration index to the DVDManager
dvds.setIndex(i.intValue());
%>
<dvd>
<title><bean:write name="dvds" property="title"/></title>
</dvd>
</logic:iterate>
</collection>[/code]

当这个页面执行,它将会产生一个像这样的输出。

[code]<collection>
<dvd>
<title>Amadeus</title>
</dvd>
<dvd>
<title>Lord of the Rings: The Fellowship of the Ring</title>
</dvd>
<dvd>
<title>The Matrix</title>
</dvd>
</collection>[/code]

[size=large]Testing the Swing jsp-pages
[/size]

除了错误页面,DVD应用程序只使用了swinglist.jsp和swingdetail.jsp,所以让我们用DemoRequest来测试一下这两个jsp页面。
它包含一个request方法能发送一个请求给servlet,并将响应输出到System.out。注意怎样设置请求的user-agent为"SWING"。如果我们像这样请求:
[code]DemoRequest dr = new DemoRequest("http://localhost:8080/dvdapp2/list.do");
dr.request();[/code]

我们得到输出:

[code]<collection>
<dvd id="C">
<title>Amadeus</title>
<length>158</length>
<actor>F. Murray Abraham</actor>
<actor>Tom Hulce</actor>
<actor>Elizabeth Berridge</actor>
</dvd>
<dvd id="A">
<title>Lord of the Rings: The Fellowship of the Ring</title>
<length>178</length>
<actor>Ian Holm</actor>
<actor>Elijah Wood</actor>
<actor>Ian McKellen</actor>
</dvd>
<dvd id="B">
<title>The Matrix</title>
<length>136</length>
<actor>Keanu Reeves</actor>
<actor>Laurence Fishburne</actor>
</dvd>
</collection>[/code]


如果和第三个代码相比,你会发现他们很像。让我们来发送个请求来请求第一个DVD的详细信息。

[code]DemoRequest dr = new DemoRequest("http://localhost:8080/dvdapp2/list.do");
dr.request();
dr = new DemoRequest("http://localhost:8080/dvdapp2/detail.do");
dr.setData("index=0");
dr.request(); [/code]

结果不是我们期望的。我们得到了正确的DVD列表,但是输出却是这样的:
[code]<html>
<head>
<title>System Error</title>
</head>
<body>
<h2>System Error</h2>

No DVD information available

</body>
</html>[/code]

这是error.jsp页面返回的,它告诉我们处理Detail页面的Struts Action类没有在session范围内找到DVD列表信息。

[size=large]Maintaining the Session
[/size]

这种错误你可能要花数小时去确定。或一下子就找到了原因。这里是原因。

当服务显示的为浏览器用户提供服务时,我们都经常会忘记session状态为每个用户创建了cookie,并通过cookie来识别用户。当我们第一次访问应用时cookie会被发送到我们机器上。当我们进行下一次请求时,就该我们把cookie送还给服务器了,这样服务器就能识别出session.在测试程序里我们没有做这个,所以现在我们必须修改代码来存储返回来的cookie,并再以后的请求中把cookie发送回去。DemoRequestCookie这个新类,看这里。

新的请求就像这样:

[code]DemoRequestCookie dr =
new DemoRequestCookie("http://localhost:8080/dvdapp2/list.do");
dr.request();
String cookie = dr.getCookie();
dr = new DemoRequestCookie("http://localhost:8080/dvdapp2/detail.do");
dr.setData("index=0");
dr.setCookie(cookie);
dr.request(); [/code]


这次输出就和期望的相符了。
[code]
. . . (list of all DVDs) . . .
<dvd id="C">
<title>Amadeus</title>
<length>158</length>
<actor>F. Murray Abraham</actor>
<actor>Tom Hulce</actor>
<actor>Elizabeth Berridge</actor>
</dvd>
[/code]

[size=large]Updating the Struts configuration file
[/size]

我们必须在struts-config.xml里配置前面的方法。每个定义都必须包含jsp文件,且这个文件必须要Swing-counterpart。比较下配置文件。
section
name
refers to

global-forwards
error
error.jsp

list
list.jsp

detail
detail.jsp

action-mappings
create
detail.jsp

update
detail.jsp

delete
list.jsp

cancel
list.jsp


我们添加新节点。

section
name
refers to

global-forwards
swingerror
swingerror.jsp

swinglist
swinglist.jsp

swingdetail
swingdetail.jsp

action-mappings
swingcreate
empty.jsp

swingupdate
empty.jsp

swingdelete
empty.jsp

swingcancel
empty.jsp

就像你看到的action mappings的empty.jsp节点,它有如下内容:

<empty/>

它包含一个单独的xml元素所以是个有效的xml文件。你会发现很奇怪的是,在创建,删除和去掉时不会需要返回任何信息,但是原因很简单。Swing客户端是胖客户端,而浏览器是瘦客户端。胖客户端能存储当前DVD的数据和可能所有DVD的列表。

所以,胖客户端只需要从服务器段获取一次DVD列表即可,此后它将数据保存在本地。如果DVD列表不高喊所有的DVD数据,没那么当选择某个DVD时,它将会从服务器获取。这就是swingdetail action停止调用swingdetail.jsp的原因。

有一点需要指出。在下一版本的Struts(1.1)中,将会包含不止一个配置文件。通过阅读给我的初步说明,Swing actions可能会放到其它配置文件中,这也许会是个让代码整洁的解决办法。

[size=large]Coding the Swing client[/size]
我们完成了Swing客户端的代码:
我们知道了怎样通过URLConnection和Session cookies调用servlet。我们知道了怎样格式化xml响应。
在下一篇文章里,我将讲述如何创建一个Swing客户端,来解析和显示xml响应,并且我们来看看如何找到错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值