PureOOP 教程:第一部分
免费的开源 PureOOP 浏览器和开发人员库。
引言
本文是介绍 PureOOP Rich Web UI 库和浏览器的系列文章的第一部分。
PureOOP 库 用于使用 Java 或 C#.NET 开发丰富的 Web GUI 应用程序。当我第一次遇到这个库和网站时,我以为这是另一个允许开发人员使用面向对象语言语法创建应用程序的库,最终会生成在浏览器中渲染的 HTML 和 CSS 代码。结果发现,这个软件与 HTML、JavaScript 或 CSS 没有任何关系。PureOOP 浏览器会渲染来自服务器数据的桌面 GUI。服务器是一个 PureOOP 库,可以在 Java 和 C# 应用程序中使用。您使用标准的 Java 或 C# 编写应用程序,并将 PureOOP 库用作 UI 库,所有客户端和服务器之间的通信、协议以及其他一切的底层工作都由 PureOOP 组件内部处理。我过去曾使用过其他声称能做类似事情的产品,但我没有发现任何产品能够可靠地工作并且易于使用。如果您一直从事桌面应用程序开发,您会发现使用 PureOOP 技术开发 Web 应用程序会非常轻松。以下是我计划在 CodeProject 网站上发布的系列教程的第一部分。
创建一个项目
要创建项目,您需要 Visual Studio 进行 .NET 开发,或者需要像 Eclipse 这样的 Java IDE 来创建 Java PureOOP 应用程序。虽然无论是使用 Java 还是 C# 开发,语法上几乎没有区别,但由于您使用不同的 IDE 来开发这两种语言,因此项目创建步骤明显不同。
要使用 Visual Studio 创建 .NET 项目,请按照以下步骤操作
- 从“文件”菜单中选择“新建”->“项目”。
- 展开“Visual C#”节点,点击“Web”,选择“C# ASP.NET 网站”模板,输入新项目的名称,然后点击“确定”。
- 安装 PureOOP 时,它会在 Windows 的 c:\PureOOP 目录下安装所有内容。您需要将您的应用程序链接到的一个文件是 SWServer.dll 文件,它位于 PureOOP 文件夹下。
- 在 Visual Studio 的“解决方案资源管理器”面板中,右键点击项目层次结构中的“引用”,然后从上下文菜单中选择“添加”->“引用”。浏览到 c:\PureOOP 目录,然后选择 SWServer.dll 文件,为您的项目添加引用。
- 修改 default.aspx 文件,使其只包含 Visual Studio 生成的第一行。您必须删除所有其他行才能使其正常工作。保留的第一行应如下所示:
- 修改 Web.config 文件,在
system.web
元素中添加以下设置: - 修改 default.aspx.cs 文件,使
Page_Load
函数包含以下代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="YourProjectName._Default" %>
<system.web>
<customErrors mode="Off"/>
<caching>
<outputCache enableOutputCache="false"/>
</caching>
</system.web>
protected void Page_Load(object sender, EventArgs e))
{
try
{
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Response.Cache.SetMaxAge(TimeSpan.Zero);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.Now);
Response.Cache.SetLastModified(DateTime.Now);
Response.Cache.SetAllowResponseInBrowserHistory(false);
}
catch (Exception ee) { }
SWServerMain.ProcessRequest(new ApplicationFactory(), Request, Response);
}
要使用 Eclipse 创建 Java 项目,请按照以下步骤操作:
- 从“文件”菜单中选择“新建”->“项目”,在“Web”下选择“动态 Web 项目”模板,然后点击“下一步”。
- 输入项目名称,输入项目位置或接受默认工作区下的默认位置,然后点击“完成”,Eclipse 将创建以下项目结构。
- 现在将 SWServer.jar 添加到项目类路径中,该文件应位于 c:\PureOOP 目录下。在我们将 jar 文件添加到项目类路径之前,请将其复制到项目 WebContent/WEB-INF 目录下的 LIB 文件夹中。
- 现在右键点击项目节点,从上下文菜单中选择“刷新”。展开 WebContent 节点,以便您可以看到 WEB-INF/lib 节点下的 SWServer.jar 节点,右键点击 jar 文件并选择“构建路径”->“添加到构建路径”,这将把 SWServer jar 添加到您的项目类路径中。
- 将以下元素添加到 web.xml 文件中,该文件位于 WebContent/WEB-INF 下。这些元素必须添加为 web-app 根元素的子元素:
<web-app...>
...
</welcome-file-list>
<servlet>
<servlet-name>MainServlet</servlet-name>
<servlet-class>com.agmvc.main.MainServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MainServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app...>
此时,您的项目已准备好与 PureOOP 库集成。接下来,我们将开发构成我们应用程序的类。从这里开始,Java 和 .NET 的说明应该几乎相同。PureOOP.com 网站上有这两种语言的教程,但在此教程中,我将使用 Java 来完成本教程的其余部分。
首先,每个 PureOOP 应用程序都必须有一个类继承自 SWApplication
,这将是应用程序的入口点。应用程序类实现了两个函数:getLicenseString
和 getMainFrame
。getLicenseString
函数可以返回一个空字符串,或者 PureOOP 颁发的用于抑制广告的有效许可证字符串。getMainFrame
**必须** 返回表示用户启动应用程序时看到的第一个屏幕的类的实例。这可以是登录屏幕或主屏幕。在本教程中,我将构建一个实现购物车功能的单屏应用程序。这是我的应用程序类的实现,它返回 ShoppingCart
的一个实例作为我应用程序的主屏幕。
请注意,应用程序类**必须**创建在 **com.main** 包下。
package com.main;
import com.agmvc.baseobjects.SWApplication;
import com.agmvc.baseobjects.SWScreen;
import com.shoppingcart.ShoppingCart;
public class AppMain extends SWApplication {
@Override
public String getLicenseString() {
return "";
}
@Override
public SWScreen getMainFrame() {
return new ShoppingCart();
}
}
创建购物车屏幕
如您所见,应用程序类返回 ShoppingCart 屏幕的实例。我们将在 com.shoppingcart 包下创建此类。要做到这一点:
- 右键点击项目 => Java 资源下的 src 节点,然后从菜单中选择新建 => 类。
- 将包名设置为 com.shoppingcart,类名设置为 ShoppingCart,然后点击“完成”。
- 更改类,使其继承自
SWScreen
,并实现该类的抽象函数,如下所示:
package com.shoppingcart;
import com.agmvc.baseobjects.SWScreen;
public class ShoppingCart extends SWScreen {
@Override
public String getQualifiedClassName() {
return "com.shoppingcart.ShoppingCart";
}
@Override
protected void getView() {
}
}
出于某种原因,框架要求您为每个屏幕或对话框类返回完全限定的类名。要返回它,您必须实现 getQualifiedClassName
函数,并返回包括包名的类的完整名称。getView
函数是您创建和布局屏幕组件的地方。如果您熟悉 Swing、SWT 和 Windows Forms 等 GUI 框架,它们都实现了一个称为布局管理器(layout manager)的东西。布局管理器允许您在一个面板中布局组件,从而使布局具有流动性,这意味着屏幕可以调整大小,并且布局会自动拉伸和重新定位组件以适应屏幕的新尺寸。PureOOP 实现了一个网格布局,它非常灵活,允许您将屏幕划分为行和列,然后您可以配置每一行和每一列,使其固定或可拉伸。布局中的每一行都可以配置为固定高度,或 FILL
高度。FILL
高度意味着在屏幕调整大小时,该行会自动拉伸,固定高度不会超过您设置的高度。列也同样适用。
每个屏幕和对话框都包含通常称为根面板(root panel)的东西。根面板是嵌入在每个屏幕和每个对话框中的面板,用于向该屏幕和对话框添加组件。在 getView
函数中,您通过调用 getContentPane()
来获取根面板的引用,该方法返回 SWPanel
的一个实例。SWPanel
实例包含 setLayout
方法,您可以调用它来设置面板的布局。setLayout
函数接受两个数组作为参数:一个列数组和一个行数组。每个数组都是一个整数数组。每个数组中的元素数量对应于您希望将面板划分为的列数或行数。
现在,我们将修改 ShoppingCart
类,使其在屏幕左侧显示一个按钮菜单,该按钮菜单将包含每个产品类别的按钮。我们还将在类别菜单的右侧有一个按钮网格组件,用于显示属于所选类别的商品。在该商品列表的右侧,我们将有一个网格,用于存放所有已添加到购物车中的商品。要实现所有这些,请修改 ShoppingCart
类,使其包含以下代码:
package com.shoppingcart;
import com.agmvc.baseobjects.SWButtonGrid;
import com.agmvc.baseobjects.SWButtonMenu;
import com.agmvc.baseobjects.SWGrid;
import com.agmvc.baseobjects.SWPanel;
import com.agmvc.baseobjects.SWScreen;
public class ShoppingCart extends SWScreen {
SWButtonMenu _categories = new SWButtonMenu();
SWButtonGrid _categoryItems = new SWButtonGrid();
SWGridMemory _cart = new SWGridMemory();
@Override
public String getQualifiedClassName() {
return "com.shoppingcart.ShoppingCart";
}
@Override
protected void getView() {
SWPanel contentPane = getContentPane();
contentPane.setLayout(new int[]{200,300,SWPanel.FILL},
new int[]{SWPanel.FILL,25,25,25});
contentPane.addComponent(_categories, 0, 0, 1, 4);
contentPane.addComponent(_categoryItems, 1, 0, 1, 4);
contentPane.addComponent(_cart, 2, 0, 1, 1);
}
}
如果您现在通过 Tomcat 在 Eclipse 中运行此应用程序,Eclipse 将显示我们正在运行的应用程序的 URL,复制该 URL,然后将其粘贴到 PureOOP 浏览器中,然后点击“GO”,您应该会看到以下屏幕出现:
现在,让我们通过向类别菜单添加类别来初始化组件,然后注册监听器,以便在我们用户点击类别、商品和其他操作时接收事件。将以下代码追加到 getView
函数的末尾:
_categories.addItem("Candy", "Candy","");
_categories.addItem("Soda", "Soda","");
_categories.addItem("Juice", "Juice","");
_categories.addItem("Lottery", "Lottery","");
_cart.setTitle("Cart Items");
_cart.addColumn("Item Name", Alignment.LEFT, false, EditStyle.TEXT, "", 2);
_cart.addColumn("Quantity", Alignment.RIGHT, false, EditStyle.NUMERIC, "", 2);
_cart.addColumn("Unit Price", Alignment.RIGHT, false, EditStyle.NUMERIC, "", 2);
_categories.setActionListener(this);
_categoryItems.setActionListener(this);
当您的类将自身注册为操作监听器时,它必须实现 com.agmvc.listeners.ActionListener
接口。要实现此接口,您必须实现 actionPerformed
函数,通过调用 setActionListener
来接收由您注册了操作监听器的组件触发的任何操作事件。我们需要在 actionPerformed
中添加代码来处理用户点击类别时的场景,以便我们可以使用属于所点击类别的商品来加载 _categoryItems
组件。为此,请在 actionPerformed
中添加以下代码:
@Override
public SWScreen actionPerformed(SWComponent source, String actionName, String customData) {
if(source == _categories) {
_categoryItems.clear();
if("Soda".equals(actionName)) {
_categoryItems.addItem("Code","Coke","images/coke.gif");
_categoryItems.addItem("7Up","7Up","images/7up.gif");
_categoryItems.addItem("Crush","Crush","images/crush.gif");
_categoryItems.addItem("RC","RC","images/rc.gif");
}
else if("Lottery".equals(actionName)) {
_categoryItems.addItem("SuperLotto","SuperLotto","images/SuperLotto.gif");
_categoryItems.addItem("Fantasy5","Fantasy5","images/Fantasy5.gif");
_categoryItems.addItem("PowerBall","PowerBall","images/PowerBall.gif");
}
}
return null;
}
现在我们需要将我们为类别商品设置的图像放在 images 文件夹下。images 文件夹必须与 WebContent 下的 WEB-INF 文件夹位于同一级别。在 images 文件夹下保存图像文件后,右键点击 Eclipse 中的项目节点并选择“刷新”。在 Tomcat 中运行应用程序,然后在 PureOOP 中输入 URL,点击“Soda”类别,您应该会看到以下内容:
下一步是为用户点击 categoryItems
组件中的商品时触发的事件编写代码,以便将商品添加到网格(购物车)中。在 actionPerformed
中添加以下代码来处理该逻辑:
@Override
public SWScreen actionPerformed(SWComponent source, String actionName, String customData) {
if(source == _categories) {
_categoryItems.clear();
if("Soda".equals(actionName)) {
_categoryItems.addItem("Code","Coke","images/coke.gif");
_categoryItems.addItem("7Up","7Up","images/7up.gif");
_categoryItems.addItem("Crush","Crush","images/crush.gif");
_categoryItems.addItem("RC","RC","images/rc.gif");
}
else if("Lottery".equals(actionName)) {
_categoryItems.addItem("SuperLotto","SuperLotto","images/SuperLotto.gif");
_categoryItems.addItem("Fantasy5","Fantasy5","images/Fantasy5.gif");
_categoryItems.addItem("PowerBall","PowerBall","images/PowerBall.gif");
}
}
else if(source == _categoryItems) {
if(_cart.addRow()) {
_cart.setValue("Item Name", actionName);
_cart.setValue("Quantity","1");
_cart.setValue("Unit Price","1.00");
}
}
return null;
}
当在 _categoryItems
组件中点击一个商品时,我们最后添加的代码会向购物车添加一个新商品,商品的名称设置为 actionName
,数量和单价都设置为 1。如果您运行代码并点击 _CategoryItems
中的某个商品,您应该会看到您点击的每个商品都会被添加到购物车中,如下所示:
接下来,我们将在购物车网格下方添加一个“保存”按钮,以便当用户点击保存按钮时,我们的代码将捕获已添加到购物车的所有商品,并将它们作为订单保存在数据库中。为此,请在每个部分中添加以下代码,如所示。
- 作为
ShoppingCart
类的实例添加按钮的声明。
SWButton _saveBtn = new SWButton();
getView
函数的末尾初始化按钮。protected void getView() {
...
contentPane.addComponent(_saveBtn,2,3,1,1);
...
_saveBtn.setText("Save");
_saveBtn.setActionName("Save");
_saveBtn.setActionListener(this);
_categories.setActionListener(this);
_categoryItems.setActionListener(this);
}
actionPerformed
函数的末尾添加以下 else 块:public SWScreen actionPerformed(SWComponent source, String actionName, String customData) {
...
else if(source == _saveBtn) {
Connection dbConnection = null;
PreparedStatement preparedStatement = null;
String insertTableSQL = "INSERT INTO orderdetail"
+ "(orderno,itemname, quantity, unitprice, price) VALUES"
+ "(?,?,?,?,?)";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
dbConnection = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:sales", "username","password");
preparedStatement = dbConnection.prepareStatement(insertTableSQL);
int newOrderNo = 1;
int rowCount = _cart.getRowCount();
for(int rowIndex = 0;rowIndex<rowCount;rowIndex++) {
String itemName = _cart.getValue(rowIndex,"Item Name");
String quantity = _cart.getValue(rowIndex,"Quantity");
String unitPrice = _cart.getValue(rowIndex,"Unit Price");
double itemPrice = NumberUtil.stringToDouble(quantity)*NumberUtil.stringToDouble(unitPrice);
//
preparedStatement.setInt(1, newOrderNo);
preparedStatement.setString(2, itemName);
preparedStatement.setString(3, quantity);
preparedStatement.setString(4, unitPrice);
preparedStatement.setString(5, Double.toString(itemPrice));
preparedStatement.executeUpdate();
}
} catch (ClassNotFoundException e) {
} catch (SQLException e) {
} finally {
if (preparedStatement != null) {
preparedStatement.close();
}
if (dbConnection != null) {
dbConnection.close();
}
}
}
}
如果您现在运行代码,您应该会在购物车网格下方看到“保存”按钮。添加几个商品到购物车并点击“保存”。您还需要更改连接字符串并创建一个名为 orderdetail 的表,以便此代码能够成功将订单保存到数据库中。
历史
本教程到此结束,请继续关注第二部分。