`
zhangziyangup
  • 浏览: 1075861 次
文章分类
社区版块
存档分类
最新评论

从 XMLBeans 接收事件,定制 XMLBean POJO,把数据模型的更改通知观察器

 
阅读更多

XML 模式描述 XML 的类型、元素和结构。Simple API for XML(SAX)、Document Object Model(DOM)和 XML Object Model(XOM)等一般性工具很难简便地使用这些信息。XMLBeans 这种数据绑定框架可以从 XML 模式创建 POJO,允许快速地读取、操作和写 XML。

在处理 POJO 时,尤其是胖客户机,需要知道对象什么时候发生变化 — 通常称为事件(eventing)通知(notification)。事件是 Model View Controller(MVC)和 Model 2 模式的核心组件,这些模式的主要意图是在图形用户界面(GUI)代码和模型代码之间形成松散耦合。我们将以 Sudoku 游戏为例,讲解如何用 XMLBeans 扩展在基于 XML 的 Java 应用程序中添加事件功能。

Sudoku 是一个 9 乘 9 的网格,它划分为 9 个 3 乘 3 的子网格。在游戏开始时,一些单元格已经填上了 1 到 9 的数字。玩家的任务是根据以下限制填写余下的单元格:

  1. 所有单元格必须包含 1 到 9 的数字。这由 XMLBeans 生成的代码处理。
  2. 每行中的所有 9 个单元格必须是惟一的。
  3. 每列中的所有 9 个单元格必须是惟一的。
  4. 每个子网格中的所有 9 个单元格必须是惟一的。

图 1 给出 Sudoku 的游戏板。我们开发了一个应用程序,它使用 XMLBeans 事件功能检验是否满足限制 2-4。如果不满足某个限制,就更新视图,把与限制冲突的单元格显示为红色。


图 1. Sudoku 游戏板示例
Sudoku 游戏板示例

关于 Sudoku 的历史和策略的更多信息参见 参考资料

过程流概述

Observer 设计模式可以把更改通知给对此感兴趣的对象。本文中描述的 XMLBeans 事件代码是这种设计模式的实例。这种模式的思想是,允许对象进行注册,请求在运行时获得 XmlObject 中模型更改的通知。按照这种方式,就可以在 Sudoku 单元格上连接监听器,对每个更改进行检验。

XMLBeans 允许使用一个配置文件(也称为 XSDCONFIG 文件)定制代码生成过程。XSDCONFIG 文件包含以下方面的 XML 配置:

  1. Java 包的名称空间映射
  2. Java 类的类型和元素 QName 映射
  3. 在生成的代码中添加方法
  4. 在模型更改之前和之后添加实现

如果在编译时知道对更改感兴趣的对象,第 4 项 就支持为它们生成事件。但糟糕的是,通常不会提前知道这些对象。关于 XSDCONFIG 文件内容的更多信息参见 参考资料

为了启用事件,需要实现 第 3 项第 4 项。这需要完成以下四个步骤:

  1. 编写一个接口扩展,从而允许向 XmlObject 注册监听器。
  2. 编写一个 PrePostSet 扩展,它把模型更改通知监听器。
  3. 创建一个包含必要配置信息的 XSDCONFIG 文件。
  4. 把关于 XSDCONFIG 文件的信息告诉 XMLBeans 实用程序 scomp

编写一个接口扩展

XMLBeans 的接口扩展特性允许在生成的 POJO 中添加具有定制实现的方法。XMLBeans 要求创建一个接口,并为这个接口中的每个方法提供静态的实现。我们创建的接口放在 com.ibm.wsrc.xmlbeans.IModelChangeEmitter 中,它包含四个方法,见 清单 1


清单 1. com.ibm.wsrc.xmlbeans.IModelChangeEmitter.java

publicinterfaceIModelChangeEmitter...{
publicvoidfireModelChangeEvent(ModelChangeEventevent);
publicvoidaddModelChangeListener(IModelChangeListenermodelChangeListener);
publicvoidremoveModelChangeListener(IModelChangeListenermodelChangeListener);
publicbooleanhasModelChangeListeners();
}

这个接口有两个生命周期管理监听器方法, addModelChangeListener()removeModelChangeListener();一个监听器检测,hasModelChangeListeners(),以及一个实用程序方法,fireModelChangeEvent(),这个方法用来把模型更改通知注册的所有监听器。

当任何过程调用这些方法之一时,XMLBeans 把调用这个方法的 XmlObject 和参数传递给一个静态实现。在这个示例中,静态实现放在 com.ibm.xmlbeans.eventing.ModelChangeEmitterHandler.java 中。因为这是一个静态实现,而且不能在 XmlObject 中存储实例变量,所以需要在别处存储对更改感兴趣的对象的列表。在这个实现中,列表存储在一个静态 HashMap 中。清单 2 给出这个类中的 Java 代码内容。


清单 2. com.ibm.wsrc.xmlbeans.ModelChangeEmitterHandler.java

publicclassModelChangeEmitterHandler...{
privatestaticHashMap<XmlObject,LinkedList<IModelChangeListener>>listeners=
newHashMap<XmlObject,LinkedList<IModelChangeListener>>();

publicstaticvoidfireModelChangeEvent(XmlObjectxo,ModelChangeEventevent)...{
LinkedList
<IModelChangeListener>list=listeners.get(xo);
if(list==null)
return;

for(IModelChangeListenerlistener:list)
listener.modelChange(event);
}


publicstaticvoidaddModelChangeListener(XmlObjectxo,
IModelChangeListenermodelChangeListener)
...{
LinkedList
<IModelChangeListener>list=listeners.get(xo);
if(list==null)...{
list
=newLinkedList<IModelChangeListener>();
listeners.put(xo,list);
}

list.add(modelChangeListener);
}


publicstaticvoidremoveModelChangeListener(XmlObjectxo,
IModelChangeListenermodelChangeListener)
...{
LinkedList
<IModelChangeListener>list=listeners.get(xo);
if(list==null)
return;
list.remove(modelChangeListener);

//removereferencesoflistandXmlObject
if(list.isEmpty())
listeners.remove(xo);
}


publicstaticbooleanhasModelChangeListeners(XmlObjectxo)...{
returnlisteners.containsKey(xo);
}

}

addModelChangeListener() 方法很好地演示了如何使用监听器列表。addModelChangeListener() 方法首先检查是否已经为这个 XmlObject 注册了监听器列表,如果这个列表不存在,就创建它。最后,在这个列表中添加监听器。

编写 PrePostSet 扩展

PrePostSet 扩展使我们能够在 XMLBeans 中添加定制的处理。我们使用一个静态类,其中包含在 XmlObject 更改之前和之后运行的方法,见 清单 3


清单 3. PrePostSet 扩展伪代码

if(PrePostSetExtension.preSet())
updateXmlObject();
PrePostSetExtension.postSet();

静态方法 preSet()postSet() 具有相同的签名:*Set(int opType, XmlObject xo, QName propertyName, boolean isAttr, int index)。初看上去,postSet() 方法似乎可以包含所有事件代码。但是,postSet() 方法并不掌握触发事件所需的所有信息。postSet() 需要向注册的所有监听器触发一个事件,事件包含更新的对象、更新的操作、更新之前的值和目前的值。在 postSet() 方法中不知道以前的值。因此,需要静态地存储以前的对象内容。

以前的值存储在静态 HashMap oldValues 中。在 preSet() 方法中,把原来的值复制到这个 HashMap 中;在 postSet() 方法中,执行实际的事件触发操作。清单 4 给出 preSet() 方法的代码。


清单 4. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler.preSet()

publicstaticbooleanpreSet(intopType,XmlObjectxo,QNamepropertyName,
booleanisAttr,intindex)...{
IModelChangeEmitteremitter
=(IModelChangeEmitter)xo;
if(!emitter.hasModelChangeListeners())
returntrue;

//getthechildthatwillbechanged
XmlObjectoldXO=null;
if(isAttr)
oldXO
=xo.selectAttribute(propertyName);
else...{
switch(opType)...{
casePrePostExtension.OPERATION_SET:
casePrePostExtension.OPERATION_REMOVE:
oldXO
=getChildXO(xo,propertyName,index);
break;
casePrePostExtension.OPERATION_INSERT:
break;
}

}


//storetheoldvalue
inthash=hashCode(xo,propertyName,isAttr,index);
ObjectoldValue
=null;
if(oldXO==null)
oldValue
=null;
elseif(oldXOinstanceofSimpleValue)...{
oldValue
=((SimpleValue)oldXO).getObjectValue();
if(oldValueinstanceofXmlObject)
oldValue
=((XmlObject)oldValue).copy();
}
else
oldValue
=oldXO.copy();

oldValues.put(hash,oldValue);

returntrue;
}

在这个方法中,代码检查模型对象上是否连接了任何监听器。如果有监听器,就缓存当前的属性值。如果它不是属性,就调用实用程序方法 getChildXO()。最后,如果它是非常量 XmlObject,就复制它的值。然后,把副本或原来的值存储在 oldValues HashMap 中。清单 5 给出 postSet() 方法的代码。


清单 5. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler.postSet()

publicstaticbooleanpostSet(intopType,XmlObjectxo,QNamepropertyName,
booleanisAttr,intindex)...{
IModelChangeEmitteremitter
=(IModelChangeEmitter)xo;
if(!emitter.hasModelChangeListeners())
returntrue;

//gettheoldvalue;
inthash=hashCode(xo,propertyName,isAttr,index);
ObjectoldValue
=oldValues.get(hash);
oldValues.remove(hash);

ModelChangeEvent.Actionaction
=ModelChangeEvent.Action.UPDATE;

//getthenewxmlobject
XmlObjectnewXO=null;
if(isAttr)
newXO
=xo.selectAttribute(propertyName);
else...{
switch(opType)...{
casePrePostExtension.OPERATION_SET:
newXO
=getChildXO(xo,propertyName,index);
break;
casePrePostExtension.OPERATION_INSERT:
XmlObject[]children
=xo.selectChildren(propertyName);

//onaninsert,itisalwaysthelastelement
newXO=children[children.length-1];
action
=ModelChangeEvent.Action.CREATE;
break;
casePrePostExtension.OPERATION_REMOVE:
action
=ModelChangeEvent.Action.DELETE;
break;
}

}


//getthenewvalue
ObjectnewValue=null;
if(newXO==null)
newValue
=null;
elseif(newXOinstanceofSimpleValue)
newValue
=((SimpleValue)newXO).getObjectValue();
else
newValue
=newXO;

//ifnewValue!=oldValue
if(((newValue==null)&&(oldValue!=null))||((newValue!=null)
&&(!newValue.equals(oldValue))))
emitter.fireModelChangeEvent(
newModelChangeEvent(propertyName,
emitter,oldValue,newValue,action,index));
returntrue;
}

postSet() 方法首先检查是否有任何监听器连接这个 XmlObject。如果有,代码就从 oldValues HashMap 获取原来的值。它从当前的 XmlObject 获取当前值并赋值给 newValue 变量。最后,postSet() 检查 oldValue,确定它与 newValue 不相等。XmlObject 创建并触发一个模型更改事件。清单 6 给出实用程序方法。


清单 6. com.ibm.xmlbeans.eventing.ModelChangePrePostHandler 实用程序方法

privatestaticXmlObjectgetChildXO(XmlObjectxo,QNamepropertyName,intindex)...{
XmlObjectchildXO
=null;
XmlObject[]values
=xo.selectChildren(propertyName);
if(values.length!=0)...{
if(index==-1)
childXO
=values[0];
elseif(index<values.length)
childXO
=values[index];
}

returnchildXO;
}


privatestaticinthashCode(XmlObjectxo,QNamepropertyName,booleanisAttr,intindex)...{
finalintprime=31;
intresult=1;
result
=prime*result+index;
result
=prime*result+(isAttr?1231:1237);
result
=prime*result+((propertyName==null)?0:propertyName.hashCode());
result
=prime*result+((xo==null)?0:xo.hashCode());
returnresult;
}

getChildXO() 方法从 XmlObject 获取一个属性值。如果返回多个值,就使用 selectChildren() 方法并获取适当的子元素。hashCode() 方法为 XmlObjectXmlObject 的属性计算一个惟一的散列值;Eclipse 会自动创建这个方法。

配置 XMLBeans 的代码生成

为了在 XMLBeans 上实现事件,需要使用并配置接口扩展特性和 PrePostSet 扩展特性。清单 7 给出 XSDCONFIG 文件。


清单 7. XMLBeans 事件的 XSDCONFIG 文件

<xb:configxmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config">
<xb:extensionfor="*">
<xb:interfacename="com.ibm.xmlbeans.eventing.IModelChangeEmitter">
<xb:staticHandler>
com.ibm.xmlbeans.eventing.ModelChangeEmitterHandler
</xb:staticHandler>
</xb:interface>
</xb:extension>

<xb:extensionfor="*">
<xb:prePostSet>
<xb:staticHandler>
com.ibm.xmlbeans.eventing.ModelChangePrePostHandler
</xb:staticHandler>
</xb:prePostSet>
</xb:extension>
</xb:config>

xb:config 的第一个 xb:extension 元素包含接口扩展的配置。在这里,它为生成的所有 XmlObject 定义接口来扩展 IModeChangeEmitter。XMLBeans 将运行 ModelChangeEmitterHandler 中的实现。

xb:config 的第二个 xb:extension 元素包含 PrePostSet 扩展的配置。它让 XMLBeans 在修改属性之前和之后分别调用 ModelChangePrePostHandler 类中的 preSet()postSet()

最后,为了把配置文件输入生成器,需要在 scomp 的最后一个参数中指定 XSDCONFIG 文件。对于这个 Sudoku 游戏,在一个 Java 类中指定这个参数,见 清单 8


清单 8. com.ibm.xmlbeans.generator.SudokuSchemaGenerator.java

publicclassSudokuSchemaGenerator...{
publicstaticvoidmain(String[]args)...{
String[]xmlBeanArgs
=newString[]...{
"-d","xb_bin",
"-src","xb_src",
"-out","lib/sudokuXB.jar",
"-javasource","1.5",
"schema/sudokuXBE.xsd",
"schema/eventing.xsdconfig"
}
;
org.apache.xmlbeans.impl.tool.SchemaCompiler.main(xmlBeanArgs);
}

}

关于 scomp 和命令行参数的更多信息参见 参考资料

在运行这个命令之后,现在就有了来自 sudokuXBE.xsd 的 POJO,这些 POJO 在发生更改时可以通知对更改感兴趣的对象。


创建 Sudoku 游戏 RCP 应用程序

Sudoku 游戏是一个 RCP 应用程序,当用户在一个单元格中填写了不合适的值时,这个程序会通知用户。程序会根据行、列和子网格中的其他单元格检查值是否符合限制。如果有任何值不符合限制,就把单元格显示为红色,见 图 2


图 2. Sudoku 游戏
Sudoku 游戏的两个屏幕图

按照以下步骤实现这个游戏的图形用户界面(UI):

  1. 创建一个代表游戏板的 Sudoku 模式。
  2. 从这个模式生成一组包含事件功能的 XMLBeans。
  3. 使用生成的 XMLBeans 创建一个 MVC 风格的应用程序。

这个应用程序的设计原则是消除视图和模型之间的耦合。控制器是 Standard Widget Toolkit(SWT)键监听器,它首先修改模型。然后,模型把更改通知检验器。检验器检查它们控制的单元格是否是有效的;如果有效,它们设置有效标志。然后,框架触发另一个事件,视图(单元格)会捕捉这个事件。这会更新单元格的背景颜色。图 3 在一个流程图中显示这四个步骤。


图 3. Sudoku RCP 应用程序的事件流
Sudoku RCP 应用程序的事件流

在 XML 模式中对 Sudoku 游戏进行建模

模式定义很简单,首先建立游戏板。游戏板包含 9 行和 9 列单元格,单元格只能包含 1 到 9 的值。使用这个简单的定义创建模式。图 4 所示的游戏板类型由 9 个行类型的元素组成。


图 4. BoardType XML 模式类型
BoardType XML 模式类型

然后定义行类型,见 图 5。这样就足以定义整个 9 乘 9 的 Sudoku 网格。


图 5. RowType XML 模式类型
RowType XML 模式类型

行类型包含 9 个单元格类型的元素。通过把行类型划分为 9 个单元格类型的元素,就可以定义行中每个单元格中的值,见 图 6


图 6. CellType XML 模式类型
CellType XML 模式类型

单元格类型是一个简单的元素,其中可以包含 1 到 9 的值和点号(.),点号表示没有值。单元格类型还有一个属性,它根据行、列和子网格限制表示这个单元格是否有效,见 图 7


图 7. CellStringType XML 模式类型
CellStringType XML 模式类型

单元格字符串类型进一步定义单元格,把其中的值限制为 1 到 9 的值和点号。

生成 XMLBeans

通过使用这个模式定义和 配置 XMLBeans 的代码生成 中定义的 XMLBeans 生成代码,生成一组 POJO,它们代表这个模式并包含事件功能,当模型发生任何更改时,可以通知 UI。

编写应用程序 UI

由于事件功能是生成的 XMLBeans 的组成部分,所以可以按照典型的 MVC 风格编写 UI。模型的视图是使用 Eclipse 平台开发的。这个 RCP 应用程序本质上是一个 Eclipse 插件,并在这个 Eclipse 插件启动时初始化一个视图。在创建每个 SWT 文本部件并把它添加到视图中时,通过 text.addKeyListener() 方法调用添加一个键监听器。这样,当用户在空单元格中输入值时,就可以截取按键操作。见 清单 9


清单 9. com.ibm.xmlbeans.tutorial.View.addKeyListeners().new KeyAdapter() {...}

publicvoidkeyPressed(KeyEvente)...{
switch(e.keyCode)...{
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
if(text.getEditable())...{
finalCellStringType.EnumnewValue=
CellStringType.Enum.forString(String.valueOf(e.character));
Jobjob
=newJob("RunValidation")...{
protectedIStatusrun(IProgressMonitorarg0)...{
XbeUtilities.getCell(Activator.getDefault().getBoard(),myRow,myCol)
.setCellValue(newValue);
returnStatus.OK_STATUS;
}

}
;
text.setText(String.valueOf(e.character));
job.schedule();
}

break;
caseSWT.BS:
caseSWT.DEL:
case'.':
case'':
if(text.getEditable())...{
Jobjob
=newJob("RunValidation")...{
protectedIStatusrun(IProgressMonitorarg0)...{
XbeUtilities.getCell(Activator.getDefault().getBoard(),myRow,myCol)
.setCellValue(CellStringType.X);
returnStatus.OK_STATUS;
}

}
;
job.schedule();
text.setText(
"");
}

break;
//...arrownavigationcode...
}

e.doit
=false;
}

然后通过 setCellValue(newValue) 调用设置模型中的值。这个调用会更新 XML 模式定义的模型。XMLBeans 事件代码触发一个事件,通知所有监听器模型已经更改了。

事件模型的关键部分是,根据单元格在行、列和子网格中的位置,通知单元格的有效性。在 modelChange(ModelChangeEvent event) 方法中,调用 runValidation() 方法来检验单元格的值,见 清单 10


清单 10. com.ibm.xmlbeans.listeners.CellValidatorListener.modelChange(ModelChangeEvent)

publicvoidmodelChange(ModelChangeEventevent)...{
if(XbeUtilities.CELLVALUE_QNAME.equals(event.getPropertyName()))...{
//ifthecurrentcellvalueisset
if(!CellStringType.X.equals(cell.getCellValue()))...{
if(cell.equals(event.getSource()))...{
//runmanualvalidation
intcount=runValidation();
numInvalid
=count;
}
else...{
//anothercell
if(cell.getCellValue().equals(CellStringType.Enum.forString(
(String)event.getNewValue())))
numInvalid
++;
else...{
if(cell.getCellValue().equals(CellStringType.Enum.forString(
(String)event.getOldValue())))
numInvalid
--;
}

}

}
elseif(cell.equals(event.getSource()))
numInvalid
=0;

if(numInvalid==0)
cell.setValid(
true);
elseif(numInvalid<0)...{
Activator.getDefault().getLog().log(
newStatus(IStatus.WARNING,Activator.PLUGIN_ID,
"Cellvalidatorhasanegativenumberofinvalidcells.Thisisimpossible."));
}
else
cell.setValid(
false);
}

}

可以看到,首先检查更改了哪个属性。在 清单 10 中,它应该是 CELLVALUE_QNAME 属性。如果这个单元格是事件源,那么调用 runValidation() 来针对所有条件执行检验。但是,如果事件源是另一个单元格,那么只需检查值是否不等于新值。如果相等,就需要把 numInvalid 加 1。如果值等于原来的值,就需要把 numInvalid 减 1。最后,如果 numInvalid 是零,就可以通过 cell.setValid(true) 把单元格的有效标志设置为 true。否则,需要通过 cell.setValid(false) 把单元格的有效标志设置为 false。通过这些调用设置单元格的有效标志之后,XMLBeans 事件机制触发另一个事件。视图监听器处理这个事件,更新单元格的背景颜色,见 清单 11


清单 11. com.ibm.xmlbeans.tutorial.View.addTextNotifier(...).new IModelChangeListener() {...}.modelChange(ModelChangeEvent)

publicvoidmodelChange(ModelChangeEventevent)...{
if(XbeUtilities.VALID_QNAME.equals(event.getPropertyName()))...{
//mightnotbeinthedisplaythread,needtoruninitto
//modifythebackground!
text.getDisplay().asyncExec(newRunnable()...{
publicvoidrun()...{
if(cell.getValid())
text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_WHITE));
else
text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_RED));
}

}
);
}

}

可以看到,当触发 modelChange 事件时,单元格会得到通知,因为每个单元格中都添加了 modelChangeListener()。在处理这个事件时,单元格检查它是否有效,并适当地设置对应的文本部件的背景颜色。

结束语

通过使用事件,可以采用简单的编程模型,消除用户界面对模型的依赖性。因此,可以快速创建 Sudoku 游戏应用程序,并避免视图和模型之间的耦合。

可以通过使用 XMLBeans 中的两个扩展点(接口和 PrePostSet)在 XMLBeans 中添加事件功能。使用接口扩展在 XMLBeans 中添加监听器,使用 PrePostSet 扩展捕捉更改并通知相关对象。最后,通过一个配置文件把这些扩展集成到 XMLBeans 生成过程中。

下载

描述 名字 大小 下载方法 XMLBeans 事件和 Sudoku 游戏 Eclipse 项目 用 XML 描述的 Sudoku 游戏板 针对 Windows 编译的 Sudoku 游戏
x-xmlbeanse/SudokuProject.zip 2694KB HTTP
x-xmlbeanse/SudokuBoards.zip 4KB HTTP
x-xmlbeanse/SudokuApplication-Win32.zip 146346KB HTTP


分享到:
评论

相关推荐

    安卓选择器类库,包括日期及时间选择器(可用于出生日期、营业时间等)

    安卓选择器类库,包括日期及时间选择器(可用于出生日期、营业时间等)、单项选择器(可用于性别、民族、职业、学历、星座等)、二三级联动选择器(可用于车牌号、基金定投日期等)、城市地址选择器(分省级、地市级及区县级)、数字选择器(可用于年龄、身高、体重、温度等)、日历选日期择器(….zip

    整个系统采用 Java 语言基于 Spring 全家桶,与MySQL数据库等相结合开发

    虽然现如今电商行业发展迅速,平台成熟,但是小的个体商家想要在头部电商平台中交易还是代价很高,各种供应链拖欠货款层出不穷,当客户和平台由于商品问题产生纠纷后,平台整体会倾向于客户处理,总之,还是要有自己的商城系统,构成所谓的两条腿发展,做到既可以利用第三方平台销售,也需要自己建立平台。我们开发的乐优商城,具备全品类商品的买卖能力,并且组建了一整套高性能服务,可以实现高并发高可用,满足电商的各种促销。为中小企业全方位解决搭建交易平台的难题。 乐优商城开发功能目标: 1、 商品管理模块:实现商品分类,品牌,规格参数,商品自身管理,商 品的上架,下架处理。 2、 搜索系统:基于 elasticSearch 实现商品搜索,搜索自动提示,高亮, 排序,搜索过滤。 3、登录系统:实现用户的登录以及登出,过期时间刷新。 4、购物车系统:基于 SpringData 及 MongoDB 实现购物车增删改查。 5、下单系统:下单减库存,使用分布式事务解决方案 Seata 6、支付系统:调用第三方电子支付平台完成支付及回调,动态修改订单 状态为已支付,为后续发货物流,做好保障工作。

    毕业设计+Python+基于OpenCV的交通路口红绿灯控制系统设计+Sqlite +PyCharm 8.zip.zip

    本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!! 本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!! 本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。有任何问题也可以随时私信博主,博主会第一时间给您解答!!

    Java毕业设计-基于Springboot+Vue水果购物网站源码+数据库+PPT文档+演示视频(高分项目).zip

    Java毕业设计-基于Springboot+Vue水果购物网站源码+数据库+PPT文档+演示视频(高分项目).zip该项目是个人高分毕业设计项目源码,已获导师指导认可通过,答辩评审分达到97分,在window10/11测试环境严格调试,下载即用,确保可以运行,部署教程齐全,也可以作为期末作业。 Java毕业设计-基于Springboot+Vue水果购物网站源码+数据库+PPT文档+演示视频(高分项目).zip该项目是个人高分毕业设计项目源码,已获导师指导认可通过,答辩评审分达到97分,在window10/11测试环境严格调试,下载即用,确保可以运行,部署教程齐全,也可以作为期末作业。 Java毕业设计-基于Springboot+Vue水果购物网站源码+数据库+PPT文档+演示视频(高分项目).zip该项目是个人高分毕业设计项目源码,已获导师指导认可通过,答辩评审分达到97分,在window10/11测试环境严格调试,下载即用,确保可以运行,部署教程齐全,也可以作为期末作业。Java毕业设计-基于Springboot+Vue水果购物网站源码+数据库+PPT文档+演示视频(高分项目

    浙江财经大学东方学院-论文PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    node-v13.13.0-linux-armv7l.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    修复windows系统库软件

    windows系统,安装软件后,经常会遇到缺少系统库的情况,通常有三种方法 方法2:修复系统库。双击运行这个软件即可自动修复。

    基于matlab的说话人语音识别源码+PPT+报告(优质项目).zip

    基于matlab的说话人语音识别源码+PPT+报告(优质项目).zip个人经导师指导并认可通过的98分毕业设计项目,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者。也可作为课程设计、期末大作业。包含全部项目源码、该项目可以直接作为毕设使用。项目都经过严格调试,确保可以运行! 基于matlab的说话人语音识别源码+PPT+报告(优质项目).zip个人经导师指导并认可通过的98分毕业设计项目,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者。也可作为课程设计、期末大作业。包含全部项目源码、该项目可以直接作为毕设使用。项目都经过严格调试,确保可以运行! 基于matlab的说话人语音识别源码+PPT+报告(优质项目).zip个人经导师指导并认可通过的98分毕业设计项目,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者。也可作为课程设计、期末大作业。包含全部项目源码、该项目可以直接作为毕设使用。项目都经过严格调试,确保可以运行!基于matlab的说话人语音识别源码+PPT+报告(优质项目).zip个人经导师指导并认可通过的98分毕业

    2020年美国大学生数学建模竞赛C题代码.zip

    最全的数学建模美赛C题和代码、大量刷题题库、逻辑清晰易于学习

    2024年全球无尘料斗装载机行业总体规模、主要企业国内外市场占有率及排名.docx

    2024年全球无尘料斗装载机行业总体规模、主要企业国内外市场占有率及排名

    基于STM32单片机的智能停车场设计源码+全部资料.zip

    基于STM32单片机的智能停车场设计源码+全部资料(优质毕业设计).zip主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者。也可作为课程设计、期末大作业。包含全部项目源码、该项目可以直接作为毕设使用。项目都经过严格调试,确保可以运行

    user+name.csv

    user+name.csv

    2022年机动车车牌识别挑战赛Top1方案.zip

    2022年机动车车牌识别挑战赛Top1方案.zip

    济南大学-答辩PPT模板我给母校送模板作品.pptx

    PPT模板,答辩PPT模板,毕业答辩,学术汇报,母校模板,我给母校送模板作品,周会汇报,开题答辩,教育主题模板下载。PPT素材下载。

    2024-2030全球与中国中空纤维膜市场现状及未来发展趋势.docx

    2024-2030全球与中国中空纤维膜市场现状及未来发展趋势

    NIUCLOUD-ADMIN 是一款快速开发SaaS通用管理系统后台框架.zip

    springboot框架 一、Spring Boot基础应用 Spring Boot特征 概念: 约定优于配置,简单来说就是你所期待的配置与约定的配置一致,那么就可以不做任何配置,约定不符合期待时才需要对约定进行替换配置。 特征: 1. SpringBoot Starter:他将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中。 2,使编码变得简单,SpringBoot采用 JavaConfig的方式对Spring进行配置,并且提供了大量的注解,极大的提高了工作效率,比如@Configuration和@bean注解结合,基于@Configuration完成类扫描,基于@bean注解把返回值注入IOC容器。 3.自动配置:SpringBoot的自动配置特性利用了Spring对条件化配置的支持,合理地推测应用所需的bean并自动化配置他们。 4.使部署变得简单,SpringBoot内置了三种Servlet容器,Tomcat,Jetty,undertow.我们只需要一个Java的运行环境就可以跑SpringBoot的项目了

    085ssm-vue大学生兼职跟踪系统.zip(可运行源码+数据库文件+文档)

    L文主要是对大学生兼职跟踪系统进行了介绍,包括研究的现状,还有涉及的开发背景,然后还对系统的设计目标进行了论述,还有系统的需求,以及整个的设计方案,对系统的设计以及实现,也都论述的比较细致,最后对大学生兼职跟踪系统进行了一些具体测试。 本文以Java为开发技术,实现了一个大学生兼职跟踪系统。大学生兼职跟踪系统的主要实现功能包括:管理员:首页、个人中心、商家管理、学生管理、兼职招聘管理、兼职应聘管理、商家投诉管理、投诉处理管理、论坛管理、系统管理等等。学生后台模块:首页、个人中心、兼职应聘管理、商家投诉管理、我的收藏管理,商家;首页、个人中心、兼职招聘管理、兼职应聘管理、投诉处理管理等等通过这些功能模块的设计,学生前台:首页、兼职招聘、兼职论坛、系统公告、我的、跳转到后台。基本上实现了整个大学生兼职跟踪系统的过程。 具体在系统设计上,采用了B/S的结构,同时,也使用Java技术在动态页面上进行了设计,后台上采用Mysql数据库,是一个非常优秀的大学生兼职跟踪系统。 关键词 :大学生兼职跟踪系统;Java技术;Mysql数据库;B/S结构

    开发 bilibili 网站爬虫,大数据分析研究.zip

    开发 bilibili 网站爬虫,大数据分析研究.zip

    WinCE工具和小软件合集包括计算器闹钟电子阅读器万年历画图工具词典等(58款).zip

    WinCE工具和小软件合集包括计算器闹钟电子阅读器万年历画图工具词典等(58款): ToWinCe.exe WinCE内存释放工具 WinCE桌面工具软件Explorer WINCE浏览器 WinCE软件合集大全(60款).zip YFGo2CE.rar 一体机全屏手写输入法 任务管理 修改端口程序 关机.exe 内存清理.exe 内存释放.exe 内存释放.rar 切换软件工具 、图片预览 媒体播放 工具-中文汉化版 幻 灯 开关任务栏-移动窗口 截图工具 手写板 掌心万年历 文件检查 文件管理 文本编辑器 文本转换 新远峰机器有硬关机了 日程安排 显示速度 显示速度、经纬度,高度的小工具 替代SQ的精编软件ST(有桌面版) 极品时刻表 极品火车时刻表 桌面透明 注册表编辑器 浏览器.exe 海鹰完美版(含五笔、拼音、符号) 海鹰输入法 清理内存工具 游戏 环境优化 电子阅读器HaaliReader 画图工具 福昕浏览器 系统信息 虚拟键盘 计算器 记事本 词典 语音阅读器 调出输入法 资源管理 资源管理.exe 进程管理.exe 重启.exe 闹 钟 黄历

    实验三-进程通信(一).doc

    实验三-进程通信(一).doc

Global site tag (gtag.js) - Google Analytics