好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

Windchill常用开发大全.ppt

284页
  • 卖家[上传人]:公****
  • 文档编号:577359010
  • 上传时间:2024-08-21
  • 文档格式:PPT
  • 文档大小:4.48MB
  • / 284 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • AgendalWindchill开发内容集合l开发目录介绍l开发环境搭建lWindchill 模型环境搭建lWindchill类的介绍lWindchill各个业务对象的模型介绍lWindchill常用开发类和方法介绍 开发规范开发规范lJAVA开发规范,请遵守sun标准lWindchill开发规范–由于将来系统生产环境是Cluster架构,所以在编写代码时,要尽量避免使用Static的Class变量,测试环境配置多个Method Server,以防止编写的代码在Cluster环境中运行出现问题–系统运行的错误信息,要显示在UI界面上,以便用户和系统管理员了解,同时需要在系统log中记录–Debug语句要有开关控制,避免直接使用System.out.println()打印,导致将来的生产环境产生大量日志–每个客制点之间,设定一个Debug开关,方便自身模块的调试Debug的开关,缺省值设置为false客制点之间的输入和输出部分,需要输出Debug信息,方便客制点之间的调试–工作流中的表达式,具体实现,都写在WfUtil中,只在工作流中调用WfUtil中的方法WfUtil中的方法注释中,需要说明该段代码,将在那些workflow中被调用。

      –系统OOTB配置部分通过XML配置文件交付方便新系统可以直接通过LoadFileSet导入配置–系统内部值,例如IBA,全部由英文字母和数字组成,不能包含特殊字符–禁止反编译系统OOTB的Class文件,然后在此基础上修改做客制,导致系统无法升级–需要对出厂文件(HTML template等)修改时,需要保存原出厂文件的备份在wtSafeArea\ptcOrig目录下,修改后的文件另存到wtSafeArea\siteMod目录–需要增加的properties属性不要放置在wt.properties中(service的注册除外),其他都放置在codebase\com\itbg\ext.properties–客制的新增Class文件放置在codebase\com\itbg对应的目录下不要放在系统原有的包中除非使用了系统原有的Protected Method,这种用法要尽量避免). 设计规范设计规范l设计规范之建模–仅对持久化对象建模    只有数据需要保存到数据库中的持久化业务对象才允许进行建模其余的操作类(例如:Processor、Delegate、Helper类等)    不被允许进行建模。

      –模型命名规则对象的名称、属性名称、方法名称应该满足命名规则,同Java编码规范的类命名、变量命名和方法命名     例如:类名 TRApplyDoc     属性名trPhase     方法名getFormData     说明:历史的模型如果要更改将要做数据迁移因此只要求对新建立的模型,历史模型不做要求 设计规范设计规范–字段扩展    对于对象的属性,一般情况下采用默认长度建模时要求考虑属性长度是否符合要求,如果需要加大长度,在模型中设置相应的值即可–选择父类     对于建模,尽量继承底层的Windchill类,例如:Managed\Item等,继承上层的具有实际业务含义的Windchill类(例如:WTPart、WTDocument)时,在业务上符合“是一个(As -is)”的含义,例如:EleadPart是一个WTPart–不预留属性    对象建模,不预留属性对于已有对象的预留属性,因属性名称业务含义,也不允许使用历史模型已预留的属性不做要求     例如:不再使用以前建模留下的reserv1、reserv2等预留属性 设计规范设计规范–关联关系    两个对象关联时,需要使用模型的关联关系。

      尽量不要采用建模为两个独立对象,在一个对象的属性中记录另一个对象的某个标志属性的方式     例如:     错误的建模方法:CBBCounter类有一个属性cbbNumber,记录CBB的编码     正确的建模方法:引入一个Link对象,记录CBBCounter类和WTPartMaster类的关系–布局    类图中尽量保证各部分分布均匀,连线尽量不要交叉,整个类图能够显示在一个屏幕范围之内(标准1024*768分辨率),对于引用的其他包的类、接口,可以将其属性、方法隐藏起来避免占用过大的显示空间 建模搭建环境建模搭建环境l进入到\Windchill+Information+Modeler-091_F000l\Rational_Rose_for_Windows\setup.exe安装l安装完成之后,load注册文件l进入到{WT_HOME}\roseAddIn,将VirtualPathMap.AddIn.reg和Windchill.AddIn.reg文件中的路径修订为个人本机环境的路径并注册     建模搭建环境建模搭建环境l启动rose,点击“Edit Path Map…”查看注册信息     Rose模型介绍模型介绍l打开Rose模型,点击FileOpenl选择src\wt\WTdesigner.mdl Rose模型使用模型使用l点击【是】,系统会加载l其中Logical View是系统核心      逻辑显示,其中3rd是Windchilll      中使用了哪些Java技术模块、ext      是系统客制化扩展模型目录、wnc是Windchill核心业务逻辑组成l点击Save AS,重新命名为HelloWorld.mdl文件,弹出框选择No,环境搭建好后,即可创建模型 扩展模型扩展模型 模型扩展模型扩展(续续)l针对上面的图示,自定义个模型EleadDocs,继承WTDocument,该模型自定义方法getEleadDocName()和属性eleadDocType,且将其属性设置constrain=false,点击保存(遇到提示,点击No)l选择菜单Units.Control docs,保存为docs.cat 模型扩展模型扩展(续续)l生成系统文件,选中docs包 模型扩展模型扩展(续续)l生成系统文件.mData和EleadDocs.java文件l在src目录下自动生成包路径和文件 docs.mData和EleadDocs.java 模型扩展模型扩展(续续)l系统会自动生成SQL【WT_HOME】\db\sql3\ext\elead\docsl生成.ser文件【WT_HOME】\codebase\ext\elead\docsl执行SQL语句–进入到 Oracle SQL*Plus路径,执行命令:–操作完成之后,即可使用EleadDocs对象了! 模型扩展模型扩展(续续) 模型扩展模型扩展(续续)l完整的例子说明–在windchill/src/目录下建立一个helloWorld目录,在windchill/codebase/目录下也建立一个helloWorld目录–打开rose软件,依次打开fileopen定位到windchill/src/wt/WTdesigner.mdl,打开–出现这个对话框,选择是,然后就耐心等待系统加载完这个文件。

      当完全加载完以后把这个文件保存到上面建立的windchill/src/helloWorld目录下,名称为helloWorld 模型扩展模型扩展(续续)l打开helloWorld. Mdl,打开后如下图–你可以发现你打开的时候是没有wt,java,helloWorld这3个package的,因为这3个package中wt和java是从左边的方框中拖过来的,而helloWorld这个是我自己建立的,然后把helloWorld和wt,java这2个package建立关系如上图然后双击helloWorld这个package在这个package中开始创建类 模型扩展模型扩展(续续)l打开helloWorld这个package后会出现下图 模型扩展模型扩展(续续)l你打开的时候是什么都没有的,这里面person,personLink这2个类是自己建立的,可以从中间的那个条中选择到的,然后对这2个类进行编辑,选中person这个类,点右键,会出现l点击第一个,然后就会出现 模型扩展模型扩展(续续) 模型扩展模型扩展(续续)l选择attributes这个标签 模型扩展模型扩展(续续)l然后在空白的地方点右键就会出现一个快捷菜单,在这个菜单中可以创建一个变量,然后双击变量会出现 模型扩展模型扩展(续续)l在这个里面会对这个变量的类型进行设置,然后点windchill标签–找到constrain这项,设置value为false,每个变量都需要这样进行设置,然后让这个类继承wt.fc.Item这个抽象类,这样就表明person这个类现在是持久的。

      同理把person这个类和wtpart这个类建立关联,关联的类为PersonLink然后让personLink继承ObjectToObjectLink这个类,然后把这个helloWorld. mdl保存一下,然后依次打开fileunitscontrol,然后再依次打开,toolswindchillsystem generation 模型扩展模型扩展(续续)–选中前3项点OK,然后这个时候你就可以在windchill/src/helloWorld这个目录下看到有Person.java和PersonLink.java这2个java文件,并且在windchill/db/sql3/helloWorld这个目录下面也会产生几个sql文件,把这几个sql文件导入到数据库中建立相关的表,要注意建立的先后顺序:只用操作以create开头的3个sql文件 模型扩展模型扩展(续续)l修改Person.java加入下面的代码protected void initialize() throws WTException{Date today = new Date();super.initialize();System.out.println("Person - initialize executing!");String s = String.valueOf(today.toLocaleString());setId(s); }然后把person.java和personLink.java这两个文件放到windchill/codebase/helloWorld/目录下进行编译。

      模型扩展模型扩展(续续)l写测试代码public class HelloWorldTest {public static void main(String[] args) {String userName = args[0];        String password = args[1];        RemoteMethodServer methodserver = RemoteMethodServer.getDefault();        methodserver.setUserName(userName);        methodserver.setPassword(password);        HelloWorldTest test = new HelloWorldTest();        test.test();} 模型扩展模型扩展(续续)l测试代码public void test(){try{Person p = Person.newPerson();p.setName("111");p.setTitle("222");p.setAge(1111);p = (Person) PersistenceHelper.manager.save(p);WTPart part = getPartByNumber("D3_0000000064");if(part==null){Debug.P("part is null");return;}PersonLink link = PersonLink.newPersonLink(part, p);link = (PersonLink) PersistenceHelper.manager.save(link);if(link==null){Debug.P("link is null");return;}WTPart part1 = link.getUse();Person p1 = link.getUsed();if(part1==null){Debug.P("part1 is null");}else{Debug.P("part1 is "+part1.getNumber());}if(p1==null){Debug.P("p1 is null");}else{Debug.P("p1 is "+p1.getName());}}catch(Exception e){e.printStackTrace();}} 模型扩展模型扩展(续续)public static WTPart getPartByNumber(String number){   WTPart part = null;   try{   QuerySpec qs = new QuerySpec(WTPart.class);       SearchCondition sc = new SearchCondition(WTPart.class, WTPart.NUMBER, "=", number);       qs.appendWhere(sc);       QueryResult qr1 = PersistenceHelper.manager.find(qs);       while(qr1.hasMoreElements()){       part = (WTPart)qr1.nextElement();       }    }catch(Exception e){   e.printStackTrace();    }    return part;} 模型扩展模型扩展(续续)l把这个测试类在windchill shell 中运行,运行结果为下图l然后我们现在看下数据库中的情况 模型扩展模型扩展(续续)在person和personlink这两张表中都有了数据,测试结果正确注意事项•在进行建模之前要对一些参数进行设置,也就是把rose的操作目录指向windchill的目录 开发目录介绍开发目录介绍WT_HOMEwtCustom wtSafeAreasrc db siteModptcCurrentptcOrigsql comitbgitbgtasks comitbgcomtemplatesloadfilesloadXMLFilescomitbgcomitbgcodebase com itbgcom itbgjspnetmarkets comitbg1、、wtCustom 放入修改系统的放入修改系统的rbInfo文件文件2、、wtSateArea 下的下的siteMod文件中放入修改后的系统文件,比如文件中放入修改后的系统文件,比如.jspf文件、文件、html、、xml;;ptcCurrent文件放系统当前版本的文件;文件放系统当前版本的文件;ptcOrig放系统最原始的文件放系统最原始的文件      ant -f bin/swmaint.xml installSiteChanges3、、codebase是运行时目录,放编译后的是运行时目录,放编译后的.class文件、放文件、放WEB相关文件、放模板文件相关文件、放模板文件(.html)4、、src目录放客制化的源文件,放国际化目录放客制化的源文件,放国际化.rbInfo文件。

      文件5、、tasks目录放系统服务文件目录放系统服务文件.xml文件,文件,Info*Engine配置文件配置文件6、、loadFiles目录,放置需要导入到系统的工作流、生命周期等目录,放置需要导入到系统的工作流、生命周期等 7、、loadXMLFiles目录,放置配置系统的信息的目录,放置配置系统的信息的.xml文件文件8、、DB目录,放置建立模型后生成的目录,放置建立模型后生成的SQL语句语句 Windchill类的介绍类的介绍l1.如何在系统中查找对象对应的类l2.如何通过类在数据库中查找相关的表     如何在系如何在系统中中查找找对象象对应的的类打开类型管理器,选择部件,这个部件就对应了系统中的一个对象,页面的右部就会显示这个类的具体信息,在名称这栏中的wt.part.WTPart就是系统中部件对应的类,wt.part是包名,WTPart就是类的名称,这个时候就可以在Eclipse中查看这个类有那些相关的函数,同时也可以到wt.part这个包中查看其它的一些类,这些类也都是和WTPart有关 如何通如何通过在系在系统中中查找找对象象对应的的类l系统中的业务对象在Rose模型中都可以看到相应的方法 系统类的设计系统类的设计l系统中的服务类设计为xxHelper.java文件和xxService.java是组合关系,系统中的所有业务对象对应的方法在对应的service中,通过xxHelper.serivce.方法  l部件操作:WTPartHelper.service.方法l文档操作:WTDocumentHelper.service.方法lEC操作:ChangeHelper2.service.方法l文件夹的操作:FolderHelper.service.方法l生命周期的操作:LifeCycleHelper.manager.方法l推进流程对象的操作:MaturityHelper.service.方法l通知机制对象的操作:NotificationHelper.service.方法l位号的操作:OccurrenceHelper.service.方法l参与者的操作:OrganizationServicesHelper.manager.方法l版本的操作:VersionControlHelper.service.方法 如何通如何通过类在数据在数据库中中查找相关的表找相关的表在类型管理器中定义的那些对象在数据库中都有相对应的表存在,表的名称也就是类的名称。

      例如:部件对象的类名称是WTPart,则数据库中就对应了一张名为WTPart的表WINDCHILL的数据库中的一张表其实对应的就是系统中的一个类名,所以有很多开发可以以数据库的表为入手点,如果你知道系统中的某个信息是存储在数据库中的具体表中的时候,就可以根据表的名称去系统中查找相关的类,来获取你需要的数据     如何通如何通过类在数据在数据库中中查找相关的表找相关的表上面就是数据库中WTPart的表,这里面的数据在WTPart这个类中就可以获取,例如你如果想要获取一个部件的生命周期状态,数据库中对应的字段是STATESTATE这个字段,那么你就可以在在代码中通过part.getLifeCycleState().getDisplay()这个函数来获取,所以在学习WINDCHILL系统的开发的时候一定不能忽略数据库的作用     Windchill各个包的介绍各个包的介绍PackageFunctionalityaccess Functionality for access control; used to define access policies and object ownership (that is, define rules for what users or groups have access to what information).admin Functionality to create administrative domains and policies.change2Functionality to manipulate change items (change issue, request, investigation, proposal, order, and change activity). container.batch Functionality for a client application to gather a group of create, modify, and delete assertions, and submit them to a service method for processing in one transaction. content Functionality for handling content data (attaching files and URLs to content holders, such as documents and change objects) and associating business information metadata (such as the author) with content.docFunctionality for document management. effectivity Functionality to assert that a PDM object is effective under certain conditions. Windchill各个包的介绍各个包的介绍 Windchill各个包的介绍各个包的介绍 Windchill各个包的介绍各个包的介绍 Windchill中的中的Model简介介l lDocumentDocument   CustomizersCustomizers–Windchill中的中的Model简介介–Windchill Document客制方法介客制方法介绍–Windchill中中UI介介绍 Windchill各个业务对象的模型介绍各个业务对象的模型介绍 Windchill Document客制方法介客制方法介绍l文档属性文档属性在在Windchill document中中WTDocumentMaster和和WTDocument是两个主要是两个主要对象象:–在WTDocumentMaster中对于文件中所有的版本版序有相同的值。

       –如果文件已建立很多版本版序,当master改变时将影响所有的版本版序 –在 WTDocument每一个版序有不同的值对应,因此WTDocument的改变只影响一种版序 l如果想如果想规定一个从一个版序到另一个版序定一个从一个版序到另一个版序变化的属性,化的属性,则需需要要扩展展 WTDocument  Windchill Document客制方法介客制方法介绍l类型型–枚举类型(值列表)领域,在windchill中让用户能够进行分类管理的文件  –类型的值被定义在 wt.doc.DocumentTypeRB中–如果有一个要求不显示doctype属性,只需要把类型管理中设置类型的实例化中的勾去掉即可,不可删除 Windchill Document客制方法介客制方法介绍lDepartment–在Windchill中允许用户选择区域,负责文件的管理–枚举类型–值都被定义在 wt.doc.DepartmentListRB中 Windchill Document客制方法介客制方法介绍l文件与文件之文件与文件之间的关系的关系:–文件文件结构构 :: 一个文件可以使用很多其它子文件,其下一个文件可以使用很多其它子文件,其下层子文件也可以被其它文件使用。

      子文件也可以被其它文件使用使用与被使用的关系使用与被使用的关系)–文件参考文件参考 ::一个文件涉及的信息存在于其他文件中一个文件涉及的信息存在于其他文件中参参考与被参考的关系考与被参考的关系) Windchill Document客制方法介客制方法介绍l文件文件结构构 Windchill Document客制方法介客制方法介绍l文件參考文件參考 Windchill Document客制方法介客制方法介绍l创建文件以及文件的主文档、建文件以及文件的主文档、删除文件除文件l添加文件的附件、添加文件的附件、删除附件除附件l文件的出文件的出库、入、入库以及修改主文档以及修改主文档l文件下文件下载l文件与文件之文件与文件之间创建关建关联(文件参考、文件文件参考、文件结构构) Windchill Document客制方法介客制方法介绍三种三种创建文件的构造方法:建文件的构造方法:lnewWTDocument ();lnewWTDocument(WTDocumentMaster master) ;lnewWTDocument(String number,String name, DocumentType type)  Windchill Document客制方法介客制方法介绍l創建文件實例WTDocument newDoc = null;newDoc = WTDocument.newWTDocument();newDoc.setName("创建主文档22");//文件的名称必设项newDoc.setNumber("888822");//文件编号必设项newDoc.setDepartment(DepartmentList.toDepartmentList("ENG"));//设置departmentlist即文件所属的部门,必设项DocumentType doctype=DocumentType.toDocumentType("$$Document");//必设项,文件类型为一般文件newDoc.setDocType(doctype);setType(newDoc,"wt.doc.WTDocument|com.elead.Drawing");newDoc = (WTDocument)PersistenceHelper.manager.save(newDoc);//保存文件 Windchill Document客制方法介客制方法介绍以上只是以上只是对文件的基本信息文件的基本信息进行了行了设置也就相当在置也就相当在创建文件的模板中只建文件的模板中只是是填写了基本信息填写了基本信息没有没有上上传文档文档时生成的不含主文档的文件。

      以下是生成的不含主文档的文件以下是创建主文档:建主文档: ContentHolder contentHolder=ContentHelper.service.getContents(newDoc);//获得文件的ContentHolderApplicationData appdata =ApplicationData.newApplicationData(contentHolder);appdata.setRole(ContentRoleType.PRIMARY);通过ApplicationData 去设置主文档的名称、大小、以及文件上传路径等.ContentServerHelper.service.updateContent(contentHolder,appdata,fileStream);//主文档创建成功参数fileStream是要上传的文件输入流 Windchill Document客制方法介客制方法介绍l删除文件只只删除主文档除主文档ContentHolder contentHolder=ContentHelper.service.getContents(newDoc);ContentItem contentitem =ContentHelper.getPrimary((FormatContentHolder)contentHolder);ContentServerHelper.service.deleteContent(contentHolder,contentitem);删除文件和主文档都除文件和主文档都删除除PersistenceHelper.manager.delete(doc); Windchill Document客制方法介客制方法介绍l添加附件文件添加附件和文件添加主文档方法文件添加附件和文件添加主文档方法类似,唯一似,唯一不同的就是不同的就是ContentRoleType类型。

      型主文档的主文档的类型是型是ContentRoleType. PRIMARY附件的附件的类型是型是ContentRoleType.SECONDARY Windchill Document客制方法介客制方法介绍l刪除附件ContentHolder contentHolder=ContentHelper.service.getContents(doc);Vector vData =ContentHelper.getApplicationData(contentHolder);if (vData != null && vData.size() > 0){for (int i = 0; i < vData.size(); i++){ApplicationData appData = (ApplicationData) vData.get(i);if (strFilename != null && strFilename.length()>0&&strFilename.equals(appData.getFileName())){ContentServerHelper.service.deleteContent(contentHolder, appData);}}} Windchill Document客制方法介客制方法介绍l文件出库入库l为什么要什么要对文件出文件出库入入库??l什么情况下什么情况下对文件文件进行出行出库入入库?? 对文件的出文件的出库主要的目的之一是主要的目的之一是为了防止一个文件同了防止一个文件同时两个人修改,由此可以看出只要是两个人修改,由此可以看出只要是和文件更新相关的操和文件更新相关的操作作都要都要对文件文件进行出行出库,然后,然后对出出库后的副本后的副本进行更新行更新操作,最后入操作,最后入库。

      Windchill Document客制方法介客制方法介绍l文件出库文件文件出出库库时, Windchil会自会自动将一个工作复本放入資料夾将一个工作复本放入資料夾中的中的Checked Out文件文件夹中中首先得到文件夹中的checkout文件夹:Folder myFolder = WorkInProgressHelper.service.getCheckoutFolder();然后对文件出库放入checkout文件夹中:CheckoutLink checkout_link = WorkInProgressHelper.service.checkout(doc, myFolder, “”);最后得到工作复本:doc = (WTDocument) checkout_link.getWorkingCopy(); Windchill Document客制方法介客制方法介绍l出库实例if (!wt.vc.wip.WorkInProgressHelper.isCheckedOut((Workable) doc))//判断文件是不是出库状态{if (!FolderHelper.inPersonalCabinet((CabinetBased) doc) && !WorkInProgressHelper.isWorkingCopy((Workable) doc)){ Folder myFolder = WorkInProgressHelper.service.getCheckoutFolder();CheckoutLink checkout_link = WorkInProgressHelper.service.checkout(doc, myFolder, ""); doc = (WTDocument) checkout_link.getWorkingCopy();}} Windchill Document客制方法介客制方法介绍l文件的入库对文件复本文件复本进行入行入库::updateDoc=(WTDocument)WorkInProgressHelper.service.checkin(updateDoc, comment);参数updateDoc出库的副本文件;comment入库时的版序注解 Windchill Document客制方法介客制方法介绍l入庫實例WTDocument updateDoc = null;if (wt.vc.wip.WorkInProgressHelper.isCheckedOut((Workable) doc)){if(WorkInProgressHelper.isWorkingCopy(doc)){updateDoc = doc;}else{updateDoc = (WTDocument) WorkInProgressHelper.service.workingCopyOf(doc);}updateDoc = (WTDocument) WorkInProgressHelper.service.checkin(updateDoc, comment);PersistenceHelper.manager.refresh(updateDoc);}else{updateDoc = (WTDocument) WorkInProgressHelper.service.checkin(updateDoc, comment);} Windchill Document客制方法介客制方法介绍l修改主文檔主文档的修改是主文档的主文档的修改是主文档的删除和除和创建建组合,在修改主文档合,在修改主文档时应该找到原来的主文档找到原来的主文档删除除之后再之后再创建新的主文档。

      建新的主文档具体具体实例例见前面的主文档前面的主文档创建和建和删除方法 Windchill Document客制方法介客制方法介绍l文件下载首先得到要下载文件的最新版本(Iterated iter = null;boolean flag = false;LatestConfigSpec latestconfigspec = new LatestConfigSpec();QueryResult queryresult =ConfigHelper.service.filteredIterationsOf(master, latestconfigspec);while (queryresult.hasMoreElements() && (!flag)){iter = (Iterated) (queryresult.nextElement());flag = iter.isLatestIteration();}) Windchill Document客制方法介客制方法介绍l然后取得文件的主文档或附件下载ContentHolder contentholder = ContentHelper.service.getContents(downDOC);ContentItem contentitem =ContentHelper.getPrimary((FormatContentHolder) contentholder);//得到主文档ApplicationData applicationdata = (ApplicationData) contentitem;ContentServerHelper.service.writeContentStream(applicationdata, sourcePath);参数Applicationdata是下载的文件,参数sourcePath为下载文件要存放的路径和文件名。

      Windchill Document客制方法介客制方法介绍l文件的关联-文件结构文件与文件的使用关系创建(删除类似):首先 判断有没有关联,得到文件之间关联是通过:PersistenceHelper.manager.find();查找得到;然后创建uselink关联:WTDocumentUsageLink usageLink = WTDocumentUsageLink.newWTDocumentUsageLink(WTDocument,WTDocumentMaster);PersistenceServerHelper.manager.insert(usageLink);  //关联创建成功 Windchill Document客制方法介客制方法介绍l文件的关联-文件参考文件与文件之间参考关系的创建(删除类似):首先查看是不是两者之间已有此关系:WTDocumentHelper.service.getDependsOnWTDocuments(WTDocument);其次创建DependencyLink关联:WTDocumentDependencyLink.newWTDocumentDependencyLink(WTDocument,WTDocument);最后把创建的关联插入数据库:PersistenceServerHelper.manager.insert(WTDocumentDependencyLink); Windchill Document客制方法介客制方法介绍l/**l * 获取一个文档的各个大版本的最新小版本l * @param docNumber  String对象,就是获取这个编码对应的对象的各个大版本的最新小版本l * @return Vector对象,这个对象中的元素都是WTDocument类型的l */lpublic static Vector getDocMaxVersion(WTDocuemntMaster docMaster) throws WTException{   lVector v=new Vector();l    QueryResult qr1 = VersionControlHelper.service.allVersionsOf(docMaster);l    while(qr1.hasMoreElements()){l    Object obj = qr1.nextElement();l    if(VersionControlHelper.isLatestIteration((Iterated) obj)){l    v.add(obj);l    }l    }lreturn v;l} Windchill Document客制方法介客制方法介绍l修改WTDocument的编码、名称方法:WTDocumentHelper.service.changeWTDocumentIdentity(existDocument, name, number, null);doc = (WTDocument) PersistenceHelper.manager.save(doc);l修改EPMDocument的名称、编码方法:Identified identified = (Identified) epm.getMaster();EPMDocumentMasterIdentity epmMI = (EPMDocumentMasterIdentity) identified.getIdentificationObject();epmMI.setName(cadName);epmMI.setNumber(newNumber);IdentityHelper.service.changeIdentity(identified, epmMI);PersistenceHelper.manager.refresh(epm); Windchill Document客制方法介客制方法介绍/** * 設定文档檔狀態 * @param epm * @return */public String setDocumentState(WTObject obj) {try {State state = State.toState("RELEASED");  String lifeState="";     if(obj instanceof EPMDocument){     EPMDocument tempEPM=(EPMDocument)obj;     lifeState=tempEPM.getLifeCycleState().toString();     obj=tempEPM;     }     if(obj instanceof WTDocument){     WTDocument tempDoc=(WTDocument)obj;     lifeState= tempDoc.getLifeCycleState().toString();     obj=tempDoc;     }     if(!lifeState.equals("RELEASED")){LifeCycleHelper.service.setLifeCycleState((LifeCycleManaged) obj,state);return "1"; }} catch (WTException ex) {ex.printStackTrace();return "setEPMDocumentState error:" + ex.toString();}return "";} Windchill Document客制方法介客制方法介绍l通过EPMDocument得到相应的推进流程WTHashSet epmHashSet = new WTHashSet();epmHashSet.add(epm);WTCollection collection=MaturityHelper.service.getPromotionNotices(epmHashSet);Object[] promoteObject = collection.toArray();for (int i = 0; i < promoteObject.length; i++) {// 將WTSe中的元素取出String assnotice = (String) promoteObject[i].toString();ReferenceFactory referencefactory = new ReferenceFactory();PromotionNotice pn = (PromotionNotice) referencefactory.getReference(assnotice).getObject();} Windchill Document客制方法介客制方法介绍l//通过2D档案寻找3D档案 QueryResult qr = EPMStructureHelper.service.navigateReferences(epm, null, false);while (qr.hasMoreElements()) {                EPMReferenceLink link = (EPMReferenceLink) qr.nextElement(); EPMDocumentMaster master = (EPMDocumentMaster) link.getReferences();                    QueryResult qs = VersionControlHelper.service.allVersionsOf(master);                    EPMDocument refEPM = (EPMDocument) qs.nextElement();}} Windchill Document客制方法介客制方法介绍//EPMDocuement与WTPart的描述关系QueryResult qr = StructHelper.service.navigateDescribes(epm, EPMDescribeLink.class, false); while (qr.hasMoreElements()) {                EPMDescribeLink link = (EPMDescribeLink) qr.nextElement();} Windchill Document客制方法介客制方法介绍//EPMDocument 与EPMDocumentMaster的关联:EPMVariantLink Windchill Document客制方法介客制方法介绍l//EPMDocument 与与EPMDocumentMaster的关的关联::EPMMemberLink(使用关系)(使用关系) Windchill Document客制方法介客制方法介绍EMPDocument 管理管理CAD档的档的结构,故相关的构,故相关的结构构操作是:操作是: Windchill WTPart客制方法介客制方法介绍l零件中的包零件中的包结构构 Windchill WTPart客制方法介客制方法介绍l零件中的屬性零件中的屬性 Windchill WTPart客制方法介客制方法介绍l零件中的属性零件中的属性–WTPartMaster§在WTPartMaster中对于零件中所有的版本版序有相同的值。

       §如果零件已建立很多版本版序,当master改变时将影响所有的版本版序–Source§枚举类型(值列表)领域,在windchill中让用户能够进行分类管理的零件来源  §类型的值被定义在 wt.part.SourceRB_zh_TW.rbInfo中§如果有一个要求不显示source属性中的一项,只需要在此项最后加入key.selectable=false Windchill WTPart客制方法介客制方法介绍l零件中的属性零件中的属性–PartType§枚举类型(值列表)领域,在windchill中让用户能够进行分类管理的零件 §类型的值被定义在 wt.part.PartTypeRB_zh_TW.rbInfo中–QuantityUnit§在Windchill中允许用户选择区域,负责零件单位的管理§枚举类型§值都被定义在 wt.part.QuantityUnitRB.rbInfo中 Windchill WTPart客制方法介客制方法介绍l零件中的關聯關系l零件中存在以下的关系:Ø零件结构–一个部件可以使用很多其它子零件,其下层子零件也可以被其它零件使用使用与被使用的关系)Ø取代/交替零件和取代零件的显示,有全局替代和特定域替代。

      Ø相关文件Ø描述零件通过特定版序的文件描述零件(描述被描述的关系)Ø零件参考零件可以参考最新版序的文件(参考被参考关系) Windchill WTPart客制方法介客制方法介绍l零件结构 Windchill WTPart客制方法介客制方法介绍l零件交替(全局替代) Windchill WTPart客制方法介客制方法介绍l零件取代(特定域替代) Windchill WTPart客制方法介客制方法介绍l什么是替代?l什么是全局替代,什么是特定替代?l什么是全局替代用于,什么是特定替代用于?l如何建立零件间的替代关联? Windchill WTPart客制方法介客制方法介绍l什么是替代?–在BOM结构中,有一些物料与别的物料有着可以替换的关系如果将某种物料A替换成物料B,而产品的主要功能并不发生变化那么就说物料B是物料A的替代料而物料B与物料A的这种关系,就是替代关系计算机显示适配器主板7900GT8800GT他们之间互为替代料,是替代关系 Windchill WTPart客制方法介客制方法介绍l什么是全局替代?什么是特定替代?l例:一种的BOMA主板A屏幕A机壳A按钮A如果按钮A和按钮B除了制造厂商不同,其他功能、规格全都相同。

      任何地方都可以相互替代那么便可以将他们二者设为双向全局替代关系按钮A按钮B双向全局替代比如规定了要尽量使用按钮A,在特殊的情况下才会使用按钮B,不会出现使用按钮A替代按钮B的情况这时候可以将按钮A和按钮B设为全局替代关系按钮B全局替代按钮A按钮A按钮B全局替代全局替代的替代范围是整个Windchill系统 Windchill WTPart客制方法介客制方法介绍l什么是全局替代?什么是特定替代?l例:一种的BOMA主板A屏幕A机壳A按钮A假定机壳A是白色的,机壳B和机壳A只在颜色上不同,是黑色A虽然默认定为使用白色机壳(机壳A),但也有黑色机壳的版本(机壳B)而且有一种B也可以使用这种机壳但只可以使用白色(机壳A)那么设置机壳A跟机壳B为全局替代关系就会出现问题这时候应该设置特定替代B主板G屏幕D机壳A按钮E特定替代机壳B Windchill WTPart客制方法介客制方法介绍l什么是全局替代用于,什么是特定替代用于?l如下图,Part A的“全局替代”为Part B而Part B的“全局替代用于”为Part Al如下图,Part A的“特定替代”为Part B而Part B的“特定替代用于”为Part A.Part APart B全局替代BOMPart APart B特定替代 如何建立零件如何建立零件间的全局替代关的全局替代关联??l替代关联,是在产品结构总管(PSE)中建立的l打开产品结构总管的“取代”选择卡如需建立双向替代,将此值改为true即可 如何建立零件如何建立零件间的特定替代关的特定替代关联??–和全局替代类似,只是特定替代只有在有父零件的零件中才可以添加(即,该零件在BOM结构中)。

      研究发现,如将B挂在F零件下F零件下的BOM结构中,E仍然是PartC的特定替代 Windchill WTPart客制方法介客制方法介绍l描述零件 Windchill WTPart客制方法介客制方法介绍l零件参考 Windchill WTPart客制方法介客制方法介绍l介绍Part的主要客制方法Ø理解并完成Part的创建、删除、修改、查询Ø理解AML、AVL的创建、删除、修改、查询Ø创建AML、AVL与part的关联Ø建立part的结构Ø建立part的交替与取代Ø建立part的描述文件Ø建立part的参考文件 零件的零件的创建建l通通过API可以可以查到零件的到零件的创建有三种方式:建有三种方式:Ø无参构造函数:WTPart.newWTPart();Ø两个参数的构造函数:WTPart.newWTPart(String number,String name)number:零件的编号;name:零件的名称Ø三个参数的构造函数:WTPart.newWTPart(String number,String name,QuantityUnit defaultUnit)number和name同上;defaultUnit:零件的单位 零件零件创建建实例例WTPart newPart = null;newPart= WTPart.newWTPart(number, name); //两个参数的实例newPart.setSource(Source.BUY);//设置自然属性sourcenewPart.setDefaultUnit(QuantityUnit.EA);//设置单位View view = ViewHelper.service.getView(OtherAttribute.PART_VIEW);//取零件的检视ViewReference viewRef = ViewReference.newViewReference(view);newPart.setView(viewRef);//设置检视newPart.setPartType(PartType.COMPONENT);//设置零件组件模式为组件从PartTypeRB.rbinfo中读出的值setType(newPart,“WCTYPE|wt.part.WTPart”);//零件的类型为零件newPart = (WTPart) PersistenceHelper.manager.save(newPart);//创建成功 零件的零件的软属性属性赋值上面的创建零件只是设置了一些自然属性,有时用户会要求用到一些软属性,软属性如何赋值呢?软属性的赋值不像自然属性直接在创建时set,而是当零件创建完成即save后,才可以为软属性赋值。

      例如:前提newPart已经创建成功IBAUtil  iba = new IBAUtil(newPart);//得到newPart软属性iba.set(“Customer”,“Dell”);//给part中的customer属性赋值Delliba.updateIBAHolder(newPart); 零件的零件的删除除对于一些对象的添加、删除、修改、更新、查询这种与数据操作语言有关的方法都是用:wt.fc.PersistenceHelper中manager接口中相应方法方法由此可以知道删除零件是:PersistenceHelper.manager.delete(WTPart newpart); 零件的修改零件的修改有上面的介绍可知道零件的修改最核心的部分和创建是一样的:PersistenceHelper.manager.save(newPart);不同的就是对零件进行更新时需要对零件首先获取零件最新版本并进行出库动作;其次更新复本零件属性;(不能更新number和name)然后对复本零件进行入库动作对零件的出库入库动作是和文件的出库入库动作通用主要通过:wt.vc.wip.WorkInProgressHelper包中的WorkInProgressHelper.service.checkout(WTCollection objects,Folder folder,String note);WorkInProgressHelper.service.checkin(Workable object,String note ); 零件零件编号的修改号的修改对零件编号的修改要去修改零件的master属性:首先获得零件的Master属性;然后修改number。

      代码:WTPartMaster partmaster = (WTPartMaster)wtpart.getMaster();WTPartMasterIdentity partmasteridentity = null;partmasteridentity =(WTPartMasterIdentity)partmaster.getIdentificationObject();partmasteridentity.setNumber(number);partmaster =(WTPartMaster)IdentityHelper.service.changeIdentity(partmaster,partmasteridentity);第二种方法:WTPartHelper.service.changeWTPartIdentity(existPart, name, number, null);part= (WTPart) PersistenceHelper.manager.save(part); 零件的零件的查询查询零件的有两种方式:Ø无条件查询Q查询所有的零件Ø有条件查询Q自然属性的查询Q软属性的查询 查询所有的零件所有的零件l查询所有的wtpart零件:lClass class1 = Class.forName(“wt.part.WTPart”);//零件类型lQuerySpec queryspec = new QuerySpec(class1);lQueryResult queryresult =lPersistenceHelper.manager.find(queryspec); 零件的自然属性的零件的自然属性的查询根据零件的编号和名称查询零件Class class1 = Class.forName(“wt.part.WTPart”);//零件类型QuerySpec queryspec = new QuerySpec(class1);if (!“”.equals(number)&&number!=null)//number传入的零件编号{    number = number.trim();    String s = getQueryName(class1, "number");    appendWhere(queryspec, class1, s, number);//添加条件s为数据库中的字段名,number为用户输入的值}  if (!"".equals(name)){     if (!"".equals(number))     queryspec.appendAnd();//用and连接条件     name = name.trim();     String s = getQueryName(class1, "name");     appendWhere(queryspec, class1, s, name);}     QueryResult queryresult =      PersistenceHelper.manager.find(queryspec); 查询条件的添加条件的添加自然属性条件查询实例appendWhere(QuerySpec queryspec, Class class1, String s, String s1){int i =queryspec.getFromClause().getPosition(class1);obj =new ConstantExpression(convertWildCards(s1));s2 =s1.indexOf(‘*’) != -1? “ LIKE ” : “=”;//模糊查询还是精确查询SearchCondition contion =SearchCondition(new ClassAttribute(class1, s), s2, ((wt.query.RelationalExpression) (obj)));queryspec.appendWhere(contion, i);} 零件零件软属性的属性的查询根据客户软属性查询零件Class class1 =Class.forName(“wt.part.WTPart”);//零件类型QuerySpec queryspec = new QuerySpec(class1);if (!customerpnve.equals("")){queryspec =appendUserAttribute(queryspec, "CustomerPNVersion", customerpnve);}//参数CustomerPNVersion为软属性,customerpnve查询的值PersistenceHelper.manager.find(queryspec); 零件零件软属性的属性的查询public static QuerySpec appendUserAttribute(QuerySpec queryspec, String s, String s1) throws WTException{AttributeDefDefaultView attributedefdefaultview = lookupAttributeDefinition(s);Class classA = queryspec.getClassAt(0);if (attributedefdefaultview == null){throw new IllegalArgumentException("Attribute " + s + " does not exist");}else{Class class1 = getAttributeValueClass(attributedefdefaultview);int i = queryspec.appendClassList(class1, false);SearchCondition searchcondition = new SearchCondition(new ClassAttribute(classA, "thePersistInfo.theObjectIdentifier.id"), "=", new ClassAttribute(class1, "theIBAHolderReference.key.id"));queryspec.appendWhere(searchcondition, queryspec.getFromClause().getPosition(classA), i);queryspec.appendAnd();queryspec.appendWhere(new SearchCondition(class1, "definitionReference.hierarchyID", "=", IBAUtility.numericID(s)), i);queryspec.appendAnd();queryspec.appendWhere(generateWhere(attributedefdefaultview, s1), i);return queryspec;}} AML、、AVL的的创建建创建AML也就是创建制造商零件,这和创建普通零件相似。

      无参的:ManufacturerPart.newManufacturerPart();两个参数的:ManufacturerPart.newManufacturerPart(String number,String Name);创建AVL也就是创建供应商零件:无参的:VendorPart.newVendorPart();两个参数的:VendorPart.newVendorPart(String Number,String Name); 获取取AXLContext首先介绍AXLContext的获取,AXLContext是用来存放AML/AVL的容器,在web页面表现是Source前后关系,比如Default、Dell等根据名称去查找AXLContextAXLContext axlcontext = null;if (sourcingcontext != null && sourcingcontext.trim().length() > 0){QuerySpec criteria = new QuerySpec(AXLContext.class);criteria.appendSearchCondition(newSearchCondition(AXLContext.class, AXLContext.NAME,SearchCondition.EQUAL, sourcingcontext.toUpperCase(), false));QueryResult results = PersistenceHelper.manager.find(criteria);if (results.hasMoreElements()){axlcontext = (AXLContext) results.nextElement();}}}// sourcingcontext为source关系的名称 建立建立AML与与part的关的关联if (wtpart != null && mpart != null) {ManufacturerPartMaster manufacturermaster = (ManufacturerPartMaster)mpart.getMaster();AXLContext sourcingcontext =getAXLContextByName(OtherAttribute.SOURCING_CONTEXT_DEFAULT,“ELEAD");AXLPreference axlpreference = AXLPreference.toAXLPreference("isnull");// (OtherAttribute.PREFERENCE_NA);boolean is = AXLServerHelper.service.hasAML(sourcingcontext,wtpart,manufacturermaster);if (is == false) {AXLHelper.service.addAML(sourcingcontext, wtpart,null,mpart,axlpreference);}}//方法的入参是WTPart和ManufacturerPart 建立建立AVL与与part的关的关联AXLEntry axlentry = null;if (wtpart != null && vpart != null) {VendorPartMaster vpartmaster = (VendorPartMaster) vpart.getMaster();AXLContext sourcingcontext = getAXLContextByName(context);AXLPreference axlpreference =AXLPreferenc.toAXLPreference("preferred");//(OtherAttribute.PREFERENCE_RECOMMENDif (wtpart != null && vpart != null && sourcingcontext != null&& axlpreference != null) {axlentry = AXLServerHelper.service.findAVL(sourcingcontext,wtpart, vpartmaster, false);if (axlentry == null) {AXLHelper.service.addAVL(sourcingcontext, wtpart, null,vpart, axlpreference);axlentry = AXLServerHelper.service.findAVL(sourcingcontext,wtpart, vpartmaster, false);}}}//方法的入参是Stringcontext,WTPart wtpart,VendorPart vpart 删除除AML、、AVL关关联//从Default中删除AML关系OrgContainer orgcontainer = WTContainerHelper.service.getOrgContainer(part.getOrganization());WTContainerRef wtcontainerref = WTContainerRef.newWTContainerRef(orgcontainer);AXLContext axlContext = AXLHelper.service.getDefaultContext(wtcontainerref);wt.fc.collections.WTCollection wtcollection = (wt.fc.collections.WTCollection)AXLHelper.service.getManufacturerParts(axlContext, part);if (!wtcollection.isEmpty()) {for (Iterator iterator = wtcollection.persistableIterator(); iterator.hasNext();) {Object obj = iterator.next();if (obj instanceof ManufacturerPart){ManufacturerPart manufacturerpart = (ManufacturerPart) obj;AXLHelper.service.removeAML(axlContext, part, manufacturerpart);//AML删除//AXLHelper.service.removeAVL(AXLContext,WTPart,VendorPart);//AVL删除}}}}} 建立建立Part的的结构构建立part结构也就是建立part与part之间的使用关系,使用关系的建立和document之间的使用关系建立相似,比较如下:part的使用关系类是wt.part. WTPartUsageLink;document的使用关系类是wt.doc.WTDocumentUsageLink;Part使用关系的创建WTPartUsageLink usageLink = WTPartUsageLink.newWTPartUsageLink(parentPart, childPartMaster);PersistenceServerHelper.manager.insert(usageLink);Document使用关系的创建WTDocumentUsageLink usageLink = WTDocumentUsageLink.newWTDocumentUsageLink(parentDoc,childDocMaster);PersistenceServerHelper.manager.insert(usageLink);在part的使用关系自然属性的设置(如用量、location等),在document中没有。

      取得取得part的交替(全域替代)的交替(全域替代)public static Vector getAlternatesLink(WTPartMaster partMaster){Vector deVE = new Vector();try {QueryResult queryresult = WTPartHelper.service.getAlternatesWTPartMasters(partMaster);//得到全局替代的零件//QueryResult queryresult = WTPartHelper.service.getAlternateForWTPartMasters(partMaster);全局替代用于的零件if(queryresult != null && queryresult.size() > 0){while(queryresult.hasMoreElements()){WTPartAlternateLink alertnateLink=(WTPartAlternateLink)queryresult.nextElement(); WTPartMaster master = alertnateLink.getAlternates();//WTPartMaster master = alertnateLink.getAlternateFor()deVE.add(master); } }} catch (WTException e) {e.printStackTrace();}return deVE;} 建立建立part的交替(全域替代)的交替(全域替代)public static WTPartAlternateLink createAlternatePart(WTPart part,WTPart alertPart){try {WTPartAlternateLink alertnateLink = null;if(part!=null&&alertPart!=null){WTPartMaster partMaster = (WTPartMaster) part.getMaster();WTPartMaster alertPartMaster = (WTPartMaster) alertPart.getMaster();Vector alertVE = getAlternatesLink(partMaster);if(!alertVE.contains(alertPartMaster)){alertnateLink =WTPartAlternateLink.newWTPartAlternateLink(partMaster,alertPartMaster);PersistenceServerHelper.manager.insert(alertnateLink);  return alertnateLink;}}} catch (WTException e) {e.printStackTrace();}return null;} 取得取得part的取代(特定替代)的取代(特定替代)public static Vector getSubstituteLink(WTPartUsageLink usageLink){Vector deVE = new Vector();QueryResultqueryresult=WTPartHelper.service.getSubstitutesWTPartMasters(usageLink); if(queryresult != null && queryresult.size() > 0){while(queryresult.hasMoreElements()){ WTPartSubstituteLink WTPartSubstituteLink = (WTPartSubstituteLink)queryresult.nextElement();WTPartMaster master = WTPartSubstituteLink.getSubstitutes();deVE.add(master); } }return deVE;} 建立建立Part的取代(特定取代)的取代(特定取代)public static WTPartSubstituteLink createSubstitutePart(WTPartUsageLink usageLink,WTPart substitutePart){WTPartSubstituteLink substituteLink = null;if(usageLink!=null&&substitutePart!=null){WTPartMaster substitutePartMaster = (WTPartMaster) substitutePart.getMaster();Vector alertVE = getSubstituteLink(usageLink);if(!alertVE.contains(substitutePartMaster)){substituteLink = WTPartSubstituteLink.newWTPartSubstituteLink(usageLink,substitutePartMaster);PersistenceServerHelper.manager.insert(substituteLink);  return substituteLink;}}return null;} 文件与零件关系的建立文件与零件关系的建立文件与零件间的描述关系类是wt.part. WTPartDescribeLinkWTPartDescribeLink describelink =WTPartDescribeLink.newWTPartDescribeLink(part, doc);PersistenceServerHelper.manager.insert(describelink);文件与零件间的参考关系类是wt.part. WTPartReferenceLinkWTPartReferenceLink describelink =WTPartReferenceLink.newWTPartReferenceLink(part, docMaster);PersistenceServerHelper.manager.insert(describelink); 零件生命周期模板的零件生命周期模板的获取及关取及关联零件零件lLifeCycleTemplate lifecycletemplate =LifeCycleHelper.service.getLifeCycleTemplate(lifecycle,part.getContainerReference());//通过生命周期模板名称来获取生命周期模板lifecycletemplate = (LifeCycleTemplate);VersionControlHelper.getLatestIteration(lifecycletemplate);//获取到最新版本的生命周期模板LifeCycleHelper.setLifeCycle(part, lifecycletemplate);//给零件设置生命周期模板LifeCycleServerHelper.setState(part, State.toState(“SB”));//设置生命周期状态,这种生命周期状态一定要在前面设置的生命周期模板里有才行 Windchill WTPart搜索搜索QuerySpec qSpec =null;QueryResult qrResult =null;qSpec =new QuerySpec(WTDocument.class);qSpec.appendSearchCondition(new SearchCondition(WTDocument.class,WTDocument.NUMBER, SearchCondition.EQUAL, number));qSpec.appendOrderBy(new OrderBy(new KeywordExpression("length(A0.versionida2versioninfo)"),true));qSpec.appendOrderBy(new OrderBy(new KeywordExpression("A0.versionida2versioninfo"),true));qSpec.appendOrderBy(new OrderBy(new KeywordExpression("length(A0.iterationida2iterationinfo)"),true));qSpec.appendOrderBy(new OrderBy(new KeywordExpression("A0.iterationida2iterationinfo"),true));//System.out.println(qSpec);qrResult = PersistenceHelper.manager.find(qSpec);WTDocument wtdoc =null;while (qrResult.hasMoreElements()) {wtdoc = (WTDocument) qrResult.nextElement();break;}} 通过通过VR得到对象,且得到得到对象,且得到ORReferenceFactory rFactory = new ReferenceFactory();WTReference reference = rFactory.getReference(“OR:wt.part.WTPart:48024”);从URL地址截取的将’%3A’换作’:’Object refObject = reference.getObject();if (refObject instanceof WTPart) {   WTPart part=(WTPart)refObject;} 高高级搜索搜索l下面是一个简单的查询示例:–QuerySpec,定义查询的对象–SearchCondition定义查询条件–QueryResult查询结果 高高级搜索搜索l需求:该方法用来查询生命周期状态为‘RELEASED’或‘INWORK’的最新的文档查询设计:  1.搜索条件§1)最后修改时间(输入从开始时间到结束时间)§2)状态为'RELEASED'或'INWORK‘§3)同一文档只返回一个版本(通过WTDocumentMaster返回一个)§4)后缀名称为.ELEAD 高高级搜索搜索l如上述需求,用如上述需求,用SQL查询的的逻辑为::SELECT * FROM wtdocumentmaster wt,wtdocument w where (wt.ida2a2=w.ida3masterreference)AND (((wt.name like‘%.elead%’))OR ((w.statestate=‘INWORK’))OR ((w.statestate=‘RELEASED’))AND ((w.modifystampa2 BETWEEN TO_DATE(‘09/09/2011 02:59:58’,’MM/DD/YYYY HH24:MI:SS’)AND TO_DATE(’10/10/2011 03:03:03’,’MM/DD/YYYY HH24:MI:SS’))))) 高高级搜索搜索 高高级搜索搜索 高高级搜索注意点搜索注意点l1)高级查询一般用于有多种约束条件的数据查询.用高级查询主要用来减少数据查询的次数,提高查询的效率.l2)如果对查询没有把握,可以先试着用sql在数据库里操作一下l3)查询尽可能考虑条件的优化l4)减少查询次数并不是必然的,如果多个表关联查询,要考虑这些表的数据量的问题,必要时将不消耗资源的查询先做了l5)测试过程,可以建立一些临时表,用工具导入尽可能多的测试数据,这高级查询产生的SQL去执行,看一下执行的效率 高高级搜索的元素搜索的元素 高高级搜索的元素搜索的元素lTable Expression in FROM Clause 高高级搜索的搜索的实例代例代码lQuerySpec qs = new QuerySpec(); int fromIndex = qs.appendFrom(new ExternalTableExpression("dual")); TableColumn dummyColumn = new TableColumn("dual", "dummy");SQLFunction currentDate = SQLFunction.new SQLFunction(SQLFunction.SYSDATE);qs.appendSelect(dummyColumn, new int[] { fromIndex }, false);qs.appendSelect(currentDate, null, false); 高高级搜索的元素搜索的元素lExpression in WHERE Clause 高高级搜索搜索lQuerySpec qs = new QuerySpec(); lint partIndex = qs.appendClassList(wt.part.WTPartMaster.class, false);lint alternatePartIndex = qs.appendClassList(wt.part.WTPartMaster.class, false);lint linkIndex = qs.appendClassList(wt.part.WTPartAlternateLink.class, false);l// Define the attributes in the query lClassAttribute partName = lnew ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NAME);lClassAttribute alternatePartName = lnew ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NAME); lClassAttribute partNumber = lnew ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NUMBER);lClassAttribute alternatePartNumber = lnew ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NUMBER); l// Define constants used in the criteria lConstantExpression subStringStart = new ConstantExpression(new Long(2));lConstantExpression subStringEnd = new ConstantExpression(new Long(4));lConstantExpression wildcardExpression = new ConstantExpression("E% [ ]");l// Add items to the select and join the classes lqs.appendSelect(partName, new int[] { 0 }, false); lqs.appendSelect(alternatePartName, new int[] { 1 }, false); lqs.appendJoin(linkIndex, wt.part.WTPartAlternateLink.ALTERNATES_ROLE, partIndex);lqs.appendJoin(linkIndex, wt.part.WTPartAlternateLink.ALTERNATE_FOR_ROLE,lalternatePartIndex); 高高级搜索搜索l参考: WCCustomizersGuide.pdfl((1233-1246)) 部件、文档的相关操作部件、文档的相关操作l版本相关操作版本相关操作lpublic static void setVersionIteration(Iterated object, String version,lString iteration) throws Exception {lif (version != null && version.length() > 0) {lMultilevelSeries multilevelSeries = MultilevelSeriesl.newMultilevelSeries("wt.vc.VersionIdentifier", version);lVersionIdentifier versionIdentifier = VersionIdentifierl.newVersionIdentifier(multilevelSeries);lVersionControlHelper.setVersionIdentifier((Versioned) object,lversionIdentifier, false);l}lif (iteration != null && iteration.length() > 0) {lSeries series = Series.newSeries("wt.vc.IterationIdentifier",literation);lIterationIdentifier iterationIdentifier = IterationIdentifierl.newIterationIdentifier(series);lVersionControlHelper.setIterationIdentifier(object,literationIdentifier);l}l} 部件、文档的相关操作部件、文档的相关操作l根据容器名称得到容器根据容器名称得到容器对象象lpublic static WTContainer getContainerByName(String containerName,lString containerType) throws Exception {lWTContainer container = null;lQueryResult qResult = null;lif (containerType != null) {lQuerySpec qsQuerySpec = new QuerySpec(Class.forName(containerType));lif (containerName != null && containerName.length() > 1) {lqsQuerySpec.appendWhere(new SearchCondition(Classl.forName(containerType), "containerInfo.name",lSearchCondition.EQUAL, containerName));l}lSystem.out.println(qsQuerySpec);lqResult = PersistenceHelper.manager.find(qsQuerySpec);lif (qResult != null && qResult.hasMoreElements()) {lcontainer = (WTContainer) qResult.nextElement();l}l}lreturn container;l} 部件、文档的相关操作部件、文档的相关操作l创建建WTPartUsageLinklWTPartUsageLink usageLink = WTPartUsageLink.newWTPartUsageLink(partA,l(WTPartMaster) partB.getMaster());lusageLink = (WTPartUsageLink) IBAValueHelper. servicel.refreshAttributeContainerWithoutConstraints(usageLink);lif (unit != null && !unit.equals("")) {// 单位的设置lunit = unit.substring(unit.lastIndexOf(""), 1);l}lQuantity qt = Quantity.newQuantity(Double.parseDouble(quantity),lQuantityUnit.toQuantityUnit(unit));lusageLink.setQuantity(qt);lif (lineNumber != null && !lineNumber.equals("")) {// 行号的设置lLineNumber iNumber = LineNumber.newLineNumber(Longl.parseLong((String) lineNumber));lusageLink.setLineNumber(iNumber);l}lPersistenceServerHelper.manager.insert(usageLink); // 设置位号lOccurrenceHelper.service.setSkipValidation(true);lif (referenceDesignators != nulll&& !referenceDesignators.equalsIgnoreCase("")) {l// Vector vector=splitString(referenceDesignators);lWTKeyedHashMap kMap = new WTKeyedHashMap();lPartUsesOccurrence partUsesOccurrence = PartUsesOccurrencel.newPartUsesOccurrence(usageLink);lpartUsesOccurrence.setName(referenceDesignators);lkMap.addElement(partUsesOccurrence);lOccurrenceHelper.service.saveUsesOccurrenceAndData(kMap);l} 部件、文档的相关操作部件、文档的相关操作l断开部件与文件的关断开部件与文件的关联关系关系lpublic static void deleteRalationLink(WTPart part, WTDocument document,lString relationType) throws WTException {lQueryResult queryResult = null;lqueryResult = StructHelper.service.navigateReferences(part, false);lwhile (queryResult.hasMoreElements()) {lWTPartReferenceLink referenceLink = (WTPartReferenceLink) queryResultl.nextElement();lif (referenceLink.getRoleBObject().equals(document.getMaster())) {lPersistenceServerHelper.manager.remove(referenceLink);l}l}l} 部件、文档的相关操作部件、文档的相关操作l设置物件置物件类型型lpublic static void setType(Typed type, String softType) {ltry {lTypedUtility.initTypeDefinitions();lTypeDefinitionReference reference = TypedUtilityl.getTypeDefinitionReference(softType);lif (reference == null) {lreference = TypeDefinitionReferencel.newTypeDefinitionReference();l}ltype.setTypeDefinitionReference(reference);l} catch (Exception e) {le.printStackTrace();l}l} 部件、文档的相关操作部件、文档的相关操作l根据根据资料料夹名称得到名称得到资料料夹lpublic static SubFolder getSubFolderByName(String subFolderName,lWTContainer container) throws WTException {lWTReference reference = WTContainerRef.newWTContainerRef(container);lObject refObject = reference.getObject();lSubFolder folder = null;lif (refObject instanceof WTContainer) {lcontainer = (WTContainer) refObject;lCabinet cabinet = container.getDefaultCabinet();lQueryResult qResult = PersistenceHelper.manager.navigate(cabinet,l"member", SubFolderLink.class);lif (qResult != null) {lwhile (qResult.hasMoreElements()) {lfolder = (SubFolder) qResult.nextElement();lif (folder.getName().equalsIgnoreCase(subFolderName)) {lreturn folder;}}}}return null;} 部件、文档的相关操作部件、文档的相关操作l获取最新版本lpublic static Versioned getLastObject(Versioned object)lthrows PersistenceException, WTException {lQueryResult qResult = VersionControlHelper.servicel.allVersionsOf(object);lif (qResult.hasMoreElements()) {lreturn (Versioned) qResult.nextElement();l} else {lreturn null;l}l} 部件、文档的相关操作部件、文档的相关操作private static WTContainer wtContainer = null;public ArrayList BASELINE_OBJECTS = new ArrayList();public ArrayList SBASELINE_OBJECTS = new ArrayList();public HashMap BLHASHMAP = new HashMap();public ArrayList BOM_OBJECTS = new ArrayList();public HashMap BOMHASHMAP = new HashMap();/** * 子阶初始行数 */public int CHILD_NUM = 3; 部件、文档的相关操作部件、文档的相关操作/** * 获取Baseline,及通过BaseLine获取基线物件**/public ManagedBaseline getBaseline(String baselineName) throws WTException {QuerySpec qs =new QuerySpec(ManagedBaseline.class);qs.appendWhere(WTContainerHelper.getWhereContainerIs(wtContainer));qs.appendAnd();qs.appendWhere(new SearchCondition(ManagedBaseline.class,ManagedBaseline.NAME, SearchCondition.EQUAL, baselineName,false));QueryResult qr = PersistenceHelper.manager.find(qs);ManagedBaseline baseline =null;while (qr.hasMoreElements()) {WTObject obj = (WTObject) qr.nextElement();if (obj instanceof ManagedBaseline) {baseline = (ManagedBaseline) obj;}}return baseline;} 部件、文档的相关操作部件、文档的相关操作/** * 获取Baseline,及通过BaseLine获取基线物件 */public ArrayList getAllBaselines(WTPart part) throws WTException {QuerySpec qs =new QuerySpec(ManagedBaseline.class);qs.appendWhere(WTContainerHelper.getWhereContainerIs(part.getContainer()));QueryResult qr = PersistenceHelper.manager.find(qs);ManagedBaseline baseline =null;ArrayList baselinelist =new ArrayList();while (qr.hasMoreElements()) {WTObject obj = (WTObject) qr.nextElement();if (obj instanceof ManagedBaseline) {baselinelist.add(((ManagedBaseline) obj).getName());}}return baselinelist;} 部件、文档的相关操作部件、文档的相关操作/** * 获取BaseLine中料件, * 

    • 其中,BASELINE_OBJECTS包含主对象,而SBASELINE_OBJECTS不包含 */public ArrayList getBaselineObjects(ManagedBaseline baseline) {QueryResult qres;try {qres = BaselineHelper.service.getBaselineItems(baseline);WTPart part = getBaselineTopObject(baseline);while (qres.hasMoreElements()) {WTPart tempPart = (WTPart) qres.nextElement();BASELINE_OBJECTS.add(tempPart);SBASELINE_OBJECTS.add(tempPart);}if (SBASELINE_OBJECTS.contains(part)) {SBASELINE_OBJECTS.remove(part);}}catch (WTException e) {e.printStackTrace();}return BASELINE_OBJECTS;} 部件、文档的相关操作部件、文档的相关操作/** * 获取BaseLine基线下零件结构HashMap */public void getBLHashMap() {for (int i = 0; i < BASELINE_OBJECTS.size(); i++) {WTPart tempPart = (WTPart) BASELINE_OBJECTS.get(i);try {ArrayList list = getChildParts(tempPart);if (list != null && list.size() != 0) {ArrayList lista =new ArrayList();for (int j = 0; j < list.size(); j++) {WTPart lpart = (WTPart) list.get(j);for (int k = 0; k < BASELINE_OBJECTS.size(); k++) {WTPart tempPart1 = (WTPart) BASELINE_OBJECTS.get(k);if (lpart.getNumber().equals(tempPart1.getNumber())) {lista.add(tempPart1);}}}if (lista != null && lista.size() != 0) {BLHASHMAP.put(tempPart.getNumber(), lista);}}}catch (WTException e) {e.printStackTrace();}}} 部件、文档的相关操作部件、文档的相关操作/** * 获取BOM结构下零件 */public void getBOMSubPart(WTPart part, ArrayList list) {if (part != null) {BOM_OBJECTS.add(part);LatestConfigSpec latestConfig = new LatestConfigSpec();QueryResult qr;try {qr = WTPartHelper.service.getUsesWTParts(part, latestConfig);ArrayList alist = new ArrayList();while (qr != null && qr.hasMoreElements()) {Persistable apersistable[] = (Persistable[]) qr.nextElement();WTPart tempPart = (WTPart) apersistable[1];getBOMSubPart(tempPart, BOM_OBJECTS);}} catch (WTException e) {e.printStackTrace();}}} 部件、文档的相关操作部件、文档的相关操作/** * 获取BOM结构下HashMap */public void getBOMHashPart(WTPart part) {getBOMSubPart(part, BOM_OBJECTS);if (BOM_OBJECTS != null && BOM_OBJECTS.size() != 0) {for (int i = 0; i < BOM_OBJECTS.size(); i++) {WTPart tempPart = (WTPart) BOM_OBJECTS.get(i);try {ArrayList list = getChildParts(tempPart);if (list != null && list.size() != 0) {BOMHASHMAP.put(tempPart.getNumber(), list);}} catch (WTException e) {e.printStackTrace();}}}} 部件、文档的相关操作部件、文档的相关操作/** * 获取BaseLine主物件 */public WTPart getBaselineTopObject(ManagedBaseline baseline) {WTPart part = null;Object lobj = baseline.getTopObjectReference().getObject();if (lobj instanceof WTPart) {part = (WTPart) lobj;}return part;} 部件、文档的相关操作部件、文档的相关操作public WTPart getParentPart(WTPartMaster childPart) {//根据产品的WTPartMaster获得父件WTPart part =null;try {QueryResult qr = WTPartHelper.service.getUsedByWTParts(childPart);System.out.println("qr size = " + qr.size());while (qr.hasMoreElements()) {part = (WTPart) qr.nextElement();System.out.println("part Name = " + part.getName());}}catch (Exception e) {e.printStackTrace();}return part;} 部件、文档的相关操作部件、文档的相关操作/** *得到部件所在的层数**/public int getPartLayer(WTPart part) throws QueryException, WTException {int i = 0;WTPartMaster partMaster = getPartMasterByNumber(part.getNumber());if (partHasParent(partMaster)) {WTPart parentPart = getParentPart(partMaster);i++;i = i + getPartLayer(parentPart);}return i;} 部件、文档的相关操作部件、文档的相关操作/** * 通过Number获取Part Master */public WTPartMaster getPartMasterByNumber(String partNumber)throws wt.query.QueryException, wt.util.WTException {wt.part.WTPartMaster wtmaster = null;partNumber = partNumber.trim();try {QueryResult qr = null;QuerySpec qs = new QuerySpec(wt.part.WTPartMaster.class);qs.appendWhere(new SearchCondition(wt.part.WTPartMaster.class,wt.part.WTPartMaster.NUMBER, SearchCondition.EQUAL,partNumber, false));qr = PersistenceHelper.manager.find(qs);while (qr.hasMoreElements()) {wtmaster = (wt.part.WTPartMaster) qr.nextElement();}} catch (Exception e) {return wtmaster;}return wtmaster;} 部件、文档的相关操作部件、文档的相关操作/** *得到部件的数量**/public int getPartAmount(WTPart part) throws QueryException, WTException {int i = 0;WTPartMaster master = getPartMasterByNumber(part.getNumber());// System.out.println("========gerPartAmount :befor if");if (partHasParent(master)) {WTPart parentPart = getParentPart(master);if (parentPart != null) {WTPartUsageLink link = getPartUsageLink(parentPart, part);i = (int) link.getQuantity().getAmount();}}return i;} 部件、文档的相关操作部件、文档的相关操作/** * 获取对象的子阶零件列表 */public ArrayList getChildParts(WTPart parentpart) throws WTException {//获得parentpart的子零件列表﹐parentpart版本不同﹐获得的零件可能不同ArrayList list =new ArrayList();// list.add(parentpart);LatestConfigSpec latestconfigspec =new LatestConfigSpec();QueryResult qr = WTPartHelper.service.getUsesWTParts(parentpart,latestconfigspec);while (qr.hasMoreElements()) {Persistable apersistable[];apersistable = (Persistable[]) qr.nextElement();WTPart childpart = (WTPart) apersistable[1];list.add(childpart);}return list;} 部件、文档的相关操作部件、文档的相关操作/** * 获取BOM料件之间Link */public WTPartUsageLink getPartBOMUsageLink(WTPart parentPart,WTPart childPart) {WTPartUsageLink usageLink =null;try {LatestConfigSpec latestconfigspec =new LatestConfigSpec();QueryResult qr = WTPartHelper.service.getUsesWTParts(parentPart,latestconfigspec);Persistable apersistable[];while (qr.hasMoreElements()) {apersistable = (Persistable[]) qr.nextElement();WTPart tempPart = (wt.part.WTPart) apersistable[1];if (tempPart.getNumber().equals(childPart.getNumber())) {usageLink = (WTPartUsageLink) apersistable[0];break;}}}catch (Exception e) {e.printStackTrace();}return usageLink;} 参与者相关操作参与者相关操作l获取系取系统当前用当前用户–WTUser currentUser = (WTUser)SessionHelper.manager.getPrincipal();l得到得到产品上下文品上下文团队–首先得到首先得到产品品–PDMLinkProduct product=(PDMLinkProduct)container;–ContainerTeam containerTeam=(ContainerTeam)product.getContainerTeamReference().getObject(); 参与者相关操作参与者相关操作l获取角色、取角色、获取角色中的所有者取角色中的所有者(WTGroup\WTUser)lRole role=Role.toRole(roleName);lif(role!=null){lArrayList roleList = containerTeam.getAllPrincipalsForTarget(role);lfor (int j = 0; j < roleList.size(); j++) {lWTPrincipalReference principalReference = (WTPrincipalReference) roleList.get(j);lWTPrincipal wtPrincipal=principalReference.getPrincipal();lif(wtPrincipal instanceof WTUser){l   WTUser user=(WTUser)wtPrincipal;l}else if(wtPrincipal instanceof WTGroup){l    WTGroup group=(WTGroup)wtPrincipal;l}l}l}return false;} 参与者相关操作参与者相关操作l判断用判断用户是否在群是否在群组中中lpublic boolean isGroupMember(WTUser user, WTGroup group) throws WTException {lboolean flag = false;lEnumeration enu = group.members();lif (enu == null)lreturn false;lwhile (enu.hasMoreElements()) {lObject obj = (Object) enu.nextElement();lif (obj != null) {lif (obj instanceof WTUser) {lWTUser tempUser = (WTUser) obj;lif (user.equals(tempUser)) {lflag = true;lbreak;l}l} else if (obj instanceof WTGroup) {lWTGroup tempGroup = null;ltempGroup = (WTGroup) obj;lisGroupMember(user, tempGroup);l}}}return flag;l} 参与者相关操作参与者相关操作/** * 判断角色参与者是否为空 *@param self流程条件式中的流程条件式中的Self指流程自身指流程自身 *@param role流程参与者角色流程参与者角色 *@return */public boolean isRoleNull(ObjectReference self,String role) {boolean isRole = false;if(self != null) {WfProcess process = (WfProcess) self.getObject();//获取参与者的角色Role role_temp = Role.toRole(role);Enumeration en =null;try {en = process.getPrincipals(role_temp);}catch (WTException e) {e.printStackTrace();}isRole = en==null?false:en.hasMoreElements();}return isRole;} 参与者相关操作参与者相关操作/** * 用于获取流程中的审核记录 */publicVector getReviewInfo(WTChangeOrder2 order2) throws WTException {HashMap reviewer =new HashMap();HashMap signMap =new HashMap();Vector sr =new Vector();Vector vector =new Vector();vector = LifeCycleHelper.service.getAllSignatures((LifeCycleManaged) order2);for (int i = 0; i < vector.size(); i++) {LifeCycleSignature lifecyclesignature = (LifeCycleSignature) vector.elementAt(i);String roleName = lifecyclesignature.getRoleName();SimpleDateFormat sdf =new SimpleDateFormat("yyyy/MM/dd");TimeZone timezone = TimeZone.getTimeZone("Asia/Shanghai");sdf.setTimeZone(timezone);String comment = lifecyclesignature.getComments();String reviewDate = sdf.format(lifecyclesignature.getCreateTimestamp()).toString();WTUser wtuser =null;wtuser = OrganizationServicesHelper.manager.getUser(lifecyclesignature.getSignerName(), "");String signer = wtuser.getName();if ("CountersignUnits".equals(roleName)) {signMap.put(signer, comment + ";;;;" + reviewDate);// 【用户名】=【会签意见;;;;会签日期】}else {reviewer.put(roleName, signer);reviewer.put(roleName + "_Date", reviewDate);reviewer.put(roleName + "_Comment", comment);}}sr.add(reviewer);sr.add(signMap);return sr;} 参与者相关操作参与者相关操作/***发送邮件**/public void send(WTDocument doc, ChangeOrder2 order2, Team team,ArrayList roleArray, String subject, String context)throws WTException {for (int i = 0; i < roleArray.size(); i++) {Role role = (Role) roleArray.get(i);String context_temp = "Dear " + role.getFullDisplay() + context;for (Enumeration enUser = team.getPrincipalTarget(role); enUser.hasMoreElements();) {WTPrincipal pricipal = ((WTPrincipalReference) enUser.nextElement()).getPrincipal();EMailMessage email = EMailMessage.newEMailMessage();email.setSubject("To " + ((WTUser) pricipal).getFullName()+ ": " + subject);email.addPart(context_temp, "text/html");email.setOriginator(SessionHelper.manager.getAdministrator());email.addRecipient(pricipal);email.send(true);}}} 参与者相关操作参与者相关操作搜索LDAP的用户public static Enumeration findUsers(String paramString1,String paramString2, Locale paramLocale) {if (paramString1 != null)paramString1 = paramString1.trim();if ((paramString1 == null) || (paramString1.length() == 0))paramString1 = "*";if (paramString2 != null)paramString2 = paramString2.trim();if ((paramString2 == null) || (paramString2.length() == 0))paramString2 = "ALL";SortedEnumeration localSortedEnumeration = null;try {String[] arrayOfString = { (String) ((paramString2.equalsIgnoreCase("ALL")) ? OrganizationServicesHelper.manager.getDirectoryServiceNames() : paramString2) };ArrayList localArrayList = new ArrayList(2);localArrayList.add(OrganizationServicesHelper.manager.newDirectoryContextProvider(arrayOfString, null));StringBuffer localStringBuffer = new StringBuffer(64);localStringBuffer.append("name");localStringBuffer.append("='");localStringBuffer.append(paramString1);localStringBuffer.append("'");localStringBuffer.append('|');localStringBuffer.append("fullName");localStringBuffer.append("='");localStringBuffer.append(paramString1);localStringBuffer.append("'");Enumeration localEnumeration = OrganizationServicesHelper.manager.queryPrincipals(WTUser.class,localStringBuffer.toString(),(DirectoryContextProvider[]) localArrayList.toArray(new DirectoryContextProvider[localArrayList.size()]));if (localEnumeration != null)localSortedEnumeration = new SortedEnumeration(localEnumeration, new PrincipalCollationKeyFactory(paramLocale));} catch (Exception localException) {localException.printStackTrace();}return localSortedEnumeration;} 参与者相关操作参与者相关操作搜索LDAP群组public static Enumeration findGroups(String paramString1,String paramString2, Locale paramLocale) {if (paramString1 != null)paramString1 = paramString1.trim();if ((paramString1 == null) || (paramString1.length() == 0))paramString1 = "*";if (paramString2 != null)paramString2 = paramString2.trim();if ((paramString2 == null) || (paramString2.length() == 0))paramString2 = "ALL";SortedEnumeration localSortedEnumeration = null;try {String[] arrayOfString = { (String) ((paramString2.equalsIgnoreCase("ALL")) ? OrganizationServicesHelper.manager.getDirectoryServiceNames() : paramString2) };ArrayList localArrayList = new ArrayList(2);localArrayList.add(OrganizationServicesHelper.manager.newDirectoryContextProvider(arrayOfString, null));StringBuffer localStringBuffer = new StringBuffer(64);localStringBuffer.append("name");localStringBuffer.append("='");localStringBuffer.append(paramString1);localStringBuffer.append("'");Enumeration localEnumeration = OrganizationServicesHelper.manager.queryPrincipals(WTGroup.class,localStringBuffer.toString(),(DirectoryContextProvider[]) localArrayList.toArray(new DirectoryContextProvider[localArrayList.size()]));if (localEnumeration != null)localSortedEnumeration = new SortedEnumeration(localEnumeration, new PrincipalCollationKeyFactory(paramLocale));} catch (Exception localException) {localException.printStackTrace();}return localSortedEnumeration;} EC相关操作相关操作lEC的所有操作,通的所有操作,通过ChangeHelper2.services.方方法法() EC相关操作相关操作 EC相关操作相关操作 EC相关操作相关操作 EC相关操作相关操作 EC相关操作相关操作 EC相关操作相关操作 EC相关操作相关操作问题报告类图 变更研究更研究 变更提更提议 分析活分析活动 EC相关操作相关操作ptc\Windchill\src\wt\change2\CategoryRB.rbInfoptc\Windchill\src\wt\change2\RequestPriorityRB.rbInfo ECA创建建实例例WTChangeActivity2 task = WTChangeActivity2.newWTChangeActivity2(String name);task.setDescription(String description));task.setNeedDate(new Timestamp(long date));task.setContainer(WTContainer container);//同时需要设定审核者跟提交者Team caTeam = TeamHelper.service.getTeam(task);Vector roles = caTeam.getRoles();Role role;Enumeration penum;Role reviewer_role = null;Role assignee_role = null;for (int i = 0; i < roles.size(); i++){role = (Role) roles.get(i);if (role.toString().equalsIgnoreCase("ASSIGNEE")) EC相关操作相关操作{assignee_role = role;}else if (role.toString().equalsIgnoreCase("REVIEWER")){reviewer_role = role;}else{continue;}penum = caTeam.getPrincipalTarget(role);if (penum != null){while (penum.hasMoreElements()){WTPrincipalReference princeRef = (WTPrincipalReference) penum.nextElement();caTeam.deletePrincipalTarget(role, princeRef.getPrincipal());}}}//最后savetask = (WTChangeActivity2) ChangeHelper2.service.saveChangeActivity(wtchangeorder2, task); ECA的的软属性属性赋值lEC各种实例软属性的赋值与零件相同软属性的赋值不向自然属性直接在创建时set,而是当EC实例创建完成即save后,才可以为软属性赋值。

      例如:前提eca已经创建成功IBAUtil  iba = new IBAUtil(ECA);//得到eca软属性iba.set(“Customer”,“Dell”);//给ECA中的customer属性赋值Dell ECA获取受影响数据跟取受影响数据跟结果数据果数据//获取影响数据:QueryResult queryresult = ChangeHelper2.service.getChangeablesBefore(ECA,boolean flag);//Flag为true,该结果集中为影响数据的实例 如:WTPart、WTDocument//如果为false,该结果集中为实例的引用//获取结果资料:QueryResult queryresult = ChangeHelper2.service.getChangeablesAfter(ECA);QueryResult queryresult = ChangeHelper2.service.getChangeablesAfter(ECA,boolean flag);//有两种方法,第二种方法的参数同获取影响数据的参数设置 ECA添加受影响数据添加受影响数据lEC的影响数据可以是零件,也可以是文件lAffectedActivityData affectedactivitydata = AffectedActivityData.newAffectedActivityData(changeable2, changeactivity2);lvector.add(affectedactivitydata);lChangeHelper2.service.saveAffectedActivityData(vector);Changeable2(part or doc), ChangeActivity2 创建建ECOl创建ECO,ECR等与创建ECA基本相同WTChangeOrder2 eco =WTChangeOrder2.newWTChangeOrder2(String name);生成ECO实例之后进行描述,容器的设置(可参考ECA的创建)然后save。

      注意ECO的save有两个入参,必须要有ECR才会有ECO,每个ECO实例都会对应一个ECR实例,保存ECO时要传入ECO对应的ECR实例ChangeHelper2.service.saveChangeOrder(ECR实例, eco) ECO获取影响数据与取影响数据与结果数据果数据l根据ECO获取影像数据QueryResult queryresult = ChangeHelper2.service.getChangeablesBefore(ECO)根据ECO获取结果数据QueryResult queryresult = ChangeHelper2.service.getChangeablesAfter(ECO)QueryResult queryresult = ChangeHelper2.service.getChangeablesAfter(ECO,boolean flag)根据ECO获取结果数据有两种方法,解释同ECA获取结果资料 创建建ECRl程序创建ECR也类似lWTChangeRequest2 ecr =WTChangeRequest2.newWTChangeRequest2(String name);l然后进行容器等属性的设置lChangeHelper2.service.saveChangeRequest(ecr); 根据根据ECR获取相关的取相关的产品品l影响的最终项目lQueryResult queryresult = ChangeHelper2.service.getSubjectProducts(wtchangerequest2);if (queryresult != null && queryresult.size() > 0){while (queryresult.hasMoreElements()){WTProductMaster wtproductmaster = (WTProductMaster) queryresult.nextElement();vec.add(wtproductmaster.getNumber());}} 根据根据ECR获取影响数据取影响数据lECR为变更请求,是在变更执行之前,l因此ECR只有影响数据,不存在结果数据lECR影响数据的获取QueryResult  queryresult = ChangeHelper2.service.getChangeables(ECR)l在ECO未开始之前的EC对象,如ECR,ChangeIssue(问题报告)等,他们都只有影响数据而没有结果数据,并且获取影响数据的方法相同,都是该方法l只是入参不同(方法重载) EC相关操作相关操作RelevantRequestData2 relevantrequestdata2;try{relevantrequestdata2 = RelevantRequestData2.newRelevantRequestData2(changeable2, changerequest2);relevantrequestdata2 = (RelevantRequestData2) PersistenceHelper.manager.save(relevantrequestdata2);}catch (WTException e){e.printStackTrace();} EC查询查询lEC查询与零件查询一样Ø无条件查询Q查询所有的ECA或者ECO等Ø有条件查询Q自然属性的查询Q软属性的查询 查询所有的所有的ECR-以以ECR为例例l查询所有的ECR:lClass class1 = Class.forName(“wt.change2.WTChangeRequest2”);//ECR类型lQuerySpec queryspec = new QuerySpec(class1);lQueryResult queryresult = lPersistenceHelper.manager.find(queryspec); ECR的自然属性的的自然属性的查询根据ECR的编号和名称查询零件Class class1 = Class.forName(“wt.change2.WTChangeRequest2”);//ECR类名QuerySpec queryspec = new QuerySpec(class1);if (!“”.equals(number))//number传入的EC编号{number = number.trim();String s = getQueryName(class1, "number");appendWhere(queryspec, class1, s, number);//添加条件s为数据库中的字段名,number为用户输入的值}if (!"".equals(name)){if (!"".equals(number))queryspec.appendAnd();//用and连接条件name = name.trim();String s = getQueryName(class1, "name");appendWhere(queryspec, class1, s, name);}QueryResult queryresult = PersistenceHelper.manager.find(queryspec); 查询条件的添加条件的添加l自然属性条件查询实例appendWhere(QuerySpec queryspec, Class class1, String s, String s1){int i =queryspec.getFromClause().getPosition(class1);obj =new ConstantExpression(convertWildCards(s1));s2 =s1.indexOf(‘*’) != -1? “ LIKE ” : “=”;//模糊查询还是精确查询SearchCondition contion =SearchCondition(new ClassAttribute(class1, s), s2, ((wt.query.RelationalExpression) (obj)));queryspec.appendWhere(contion, i);} ECR软属性的属性的查询根据客户软属性查询零件Class class1 =Class.forName(“wt.change2.WTChangeRequest2”);QuerySpec queryspec = new QuerySpec(class1);if (!customerpnve.equals("")){queryspec =appendUserAttribute(queryspec, “CustomerPNVersion", customerpnve);}//参数CustomerPNVersion为软属性(这里对应的为ECR软属性),customerpnve查询的值PersistenceHelper.manager.find(queryspec); ECR软属性的属性的查询软属性条件查询appendWhere(QuerySpec queryspec, Class class1, String s, String s1){int i =queryspec.getFromClause().getPosition(class1);obj =new ConstantExpression(convertWildCards(s1));s2 =s1.indexOf(‘*’) != -1? “ LIKE ” : “=”;//模糊查询还是精确查询SearchCondition contion =SearchCondition(new ClassAttribute(class1, s), s2, ((wt.query.RelationalExpression) (obj)));queryspec.appendWhere(contion, i);} 根据根据ECA获取取ECOl理论上一个ECA只能对应一个ECO,而一个ECO则可以对应多个ECAQueryResult queryresult;queryresult = ChangeHelper2.service.getChangeOrder(changeactivity2);l利用ECA实例获取的ECO结果集,理论上该结果集只有一笔数据 根据根据ECA获取取ECOl理论上一个ECA只能对应一个ECO,而一个ECO则可以对应多个ECAQueryResult queryresult;queryresult = ChangeHelper2.service.getChangeOrder(changeactivity2);l利用ECA实例获取的ECO结果集,理论上该结果集只有一笔数据 根据根据ECO获取取ECRlECO来自ECR,通过ECO可以获取ECR跟ECO与ECA的关系类似,ECR跟ECO也是1对多的关系就是说,1个ECR可以创建多个ECO,一个ECO有且只有一个ECR与之对应然而目前实际业务中ECR与ECO是一一对应的关系QueryResult queryresult=ChangeHelper2.service.getChangeRequest(ECO实例);l根据ECO实例获取ECR结果集,理论该结果集为1笔数据 通通过ECR获取取ECOl通过ECO可以过去到ECRl反过来通过ECR获取ECO也可以lQueryResult q =ChangeHelper2.service.getChangeOrders(ECR);l通过ECR实例获取ECO,该结果集可能会有多笔l通过ECO获取ECA也一样lChangeHelper2.service.getChangeActivities(ECO)l返回的结果集可能为多笔 通通过ECO获取取ECA也一也一样lChangeHelper2.service.getChangeActivities(ECO)l返回的结果集可能有多笔数据 EC相关操作相关操作l下下载ECA的附件的附件 EC相关操作相关操作l下下载ECN的附件的附件 EC相关操作相关操作l下下载ECR的附件的附件 EC总结l怎么怎么获取取变更前后的数据?更前后的数据?lEC对象相互之象相互之间是怎么是怎么获取的?取的?l获取了取了变更前后的数据,更前后的数据,针对部件一般比部件一般比较什么?什么?–BOM是否是否发生生变化:父子化:父子项关系是否关系是否发生生变化?和化?和WTPartUsageLink是否是否发生了生了变化化(单位、位、行号、位号行号、位号)–属性(属性(MBA、、IBA))–关关联关系关系(描述、参考、全域替代、特定替代、描述、参考、全域替代、特定替代、MPN、、VPN) Workflow相关操作相关操作 Workflow相关操作相关操作 Workflow相关操作相关操作l l已指派的活动,是指派给一或多个使用者或使用者群组或实行者执行的已指派的活动,是指派给一或多个使用者或使用者群组或实行者执行的已指派的活动,是指派给一或多个使用者或使用者群组或实行者执行的已指派的活动,是指派给一或多个使用者或使用者群组或实行者执行的活动。

      活动随机活动,是指派给使用者以定义执行时期活动群组的活动活动群组随机活动,是指派给使用者以定义执行时期活动群组的活动活动群组随机活动,是指派给使用者以定义执行时期活动群组的活动活动群组随机活动,是指派给使用者以定义执行时期活动群组的活动活动群组类似简单的区块类似简单的区块类似简单的区块类似简单的区块区块代表一组活动、连接器或自动机制建立可于需要时展开的活动区区块代表一组活动、连接器或自动机制建立可于需要时展开的活动区区块代表一组活动、连接器或自动机制建立可于需要时展开的活动区区块代表一组活动、连接器或自动机制建立可于需要时展开的活动区块,可帮您降低流程的复杂性块,可帮您降低流程的复杂性块,可帮您降低流程的复杂性块,可帮您降低流程的复杂性l lProxyProxyProxyProxy流程是内嵌于主要父流程中的子流程,这些流程可以构成巢状,以流程是内嵌于主要父流程中的子流程,这些流程可以构成巢状,以流程是内嵌于主要父流程中的子流程,这些流程可以构成巢状,以流程是内嵌于主要父流程中的子流程,这些流程可以构成巢状,以降低复杂性,并供重复使用降低复杂性,并供重复使用降低复杂性,并供重复使用降低复杂性,并供重复使用。

      当所有前置任务链接都触发时,「和」连接器才会触发,而不会先触发当所有前置任务链接都触发时,「和」连接器才会触发,而不会先触发当所有前置任务链接都触发时,「和」连接器才会触发,而不会先触发当所有前置任务链接都触发时,「和」连接器才会触发,而不会先触发管理工作流程管理工作流程管理工作流程管理工作流程16-916-916-916-9l l当任何一个前置任务链接触发时,「或」连接器就会触发若选取了「触当任何一个前置任务链接触发时,「或」连接器就会触发若选取了「触当任何一个前置任务链接触发时,「或」连接器就会触发若选取了「触当任何一个前置任务链接触发时,「或」连接器就会触发若选取了「触发时终止开启前置任务活动发时终止开启前置任务活动发时终止开启前置任务活动发时终止开启前置任务活动(Terminate Open Predecessor Activities(Terminate Open Predecessor Activities(Terminate Open Predecessor Activities(Terminate Open Predecessor Activitieswhen Fired)when Fired)when Fired)when Fired)」,就会终止先前活动。

      」,就会终止先前活动」,就会终止先前活动」,就会终止先前活动 条件式路由器可让您根据条件表达式将流程分支条件式路由器可让您根据条件表达式将流程分支条件式路由器可让您根据条件表达式将流程分支条件式路由器可让您根据条件表达式将流程分支 Workflow相关操作相关操作l l当用户定义的前置任务链接数都触发时,「临界值」连接器才会触发当用户定义的前置任务链接数都触发时,「临界值」连接器才会触发当用户定义的前置任务链接数都触发时,「临界值」连接器才会触发当用户定义的前置任务链接数都触发时,「临界值」连接器才会触发若选取了「触发时终止开启前置任务活动若选取了「触发时终止开启前置任务活动若选取了「触发时终止开启前置任务活动若选取了「触发时终止开启前置任务活动(Terminate Open (Terminate Open PredecessorActivities when Fired)PredecessorActivities when Fired)」,就会终止先前活动」,就会终止先前活动」,就会终止先前活动」,就会终止先前活动l l结束可停止流程所有的流程活动最后都会连接到结束结束可停止流程。

      所有的流程活动最后都会连接到结束结束可停止流程所有的流程活动最后都会连接到结束结束可停止流程所有的流程活动最后都会连接到结束l l接地会停止流程中平行的活动分支,但不会停止流程接地会停止流程中平行的活动分支,但不会停止流程接地会停止流程中平行的活动分支,但不会停止流程接地会停止流程中平行的活动分支,但不会停止流程l l   通知自动机制利用用户定义的电子邮件,来通知适当的使用者您可通知自动机制利用用户定义的电子邮件,来通知适当的使用者您可通知自动机制利用用户定义的电子邮件,来通知适当的使用者您可通知自动机制利用用户定义的电子邮件,来通知适当的使用者您可以使用括号分隔为流程或节点所建立的变量,例如以使用括号分隔为流程或节点所建立的变量,例如以使用括号分隔为流程或节点所建立的变量,例如以使用括号分隔为流程或节点所建立的变量,例如{varname}{varname}使用反斜杠来隔开分隔符,例如反斜杠来隔开分隔符,例如反斜杠来隔开分隔符,例如反斜杠来隔开分隔符,例如\{{varname}}\\{{varname}}\l l方法自动机制代表您将自动机制加入至流程时,执行的许多单一动作方法自动机制代表您将自动机制加入至流程时,执行的许多单一动作方法自动机制代表您将自动机制加入至流程时,执行的许多单一动作方法自动机制代表您将自动机制加入至流程时,执行的许多单一动作之一。

      不需要其他组态不需要其他组态不需要其他组态不需要其他组态 Workflow相关操作相关操作l lWorkflowWorkflow的设计规范的设计规范的设计规范的设计规范l l流程图布局流程图布局流程图布局流程图布局流程图的布局遵循阅读习惯,按流程的走向从左到右,自上向下的流程图的布局遵循阅读习惯,按流程的走向从左到右,自上向下的流程图的布局遵循阅读习惯,按流程的走向从左到右,自上向下的流程图的布局遵循阅读习惯,按流程的走向从左到右,自上向下的原则,节点对齐,连线平直,节点不能重叠,连线尽量不要交叉原则,节点对齐,连线平直,节点不能重叠,连线尽量不要交叉原则,节点对齐,连线平直,节点不能重叠,连线尽量不要交叉原则,节点对齐,连线平直,节点不能重叠,连线尽量不要交叉建议尽量控制在一屏建议尽量控制在一屏建议尽量控制在一屏建议尽量控制在一屏( (标准标准标准标准10241024* *768768分辨率分辨率分辨率分辨率) )显示全部的流程节点显示全部的流程节点显示全部的流程节点显示全部的流程节点如不能再一屏显示完,建议横向不超边界,纵向伸展,最可能运如不能再一屏显示完,建议横向不超边界,纵向伸展,最可能运如不能再一屏显示完,建议横向不超边界,纵向伸展,最可能运如不能再一屏显示完,建议横向不超边界,纵向伸展,最可能运行到的分支或是先运行到的节点放在第一屏。

      行到的分支或是先运行到的节点放在第一屏行到的分支或是先运行到的节点放在第一屏行到的分支或是先运行到的节点放在第一屏l l节点下方预留空间节点下方预留空间节点下方预留空间节点下方预留空间   建议节点下方预留两行文字的高度,即在节点名下方预留一行文字建议节点下方预留两行文字的高度,即在节点名下方预留一行文字建议节点下方预留两行文字的高度,即在节点名下方预留一行文字建议节点下方预留两行文字的高度,即在节点名下方预留一行文字的高度说明:在进程管理器的查看进程信息的时候,节点的状态会显示在说明:在进程管理器的查看进程信息的时候,节点的状态会显示在说明:在进程管理器的查看进程信息的时候,节点的状态会显示在说明:在进程管理器的查看进程信息的时候,节点的状态会显示在节点名称的下方,避免排列太挤导致状态信息显示不完全节点名称的下方,避免排列太挤导致状态信息显示不完全节点名称的下方,避免排列太挤导致状态信息显示不完全节点名称的下方,避免排列太挤导致状态信息显示不完全l l节点命名节点命名节点命名节点命名节点要以其主要功能命名,尽量不要重名(除非是完成同样功能的节点要以其主要功能命名,尽量不要重名(除非是完成同样功能的节点要以其主要功能命名,尽量不要重名(除非是完成同样功能的节点要以其主要功能命名,尽量不要重名(除非是完成同样功能的节点,或设置状态节点),名称为动宾结构或主谓结构的短语。

      节点,或设置状态节点),名称为动宾结构或主谓结构的短语节点,或设置状态节点),名称为动宾结构或主谓结构的短语节点,或设置状态节点),名称为动宾结构或主谓结构的短语例如:申请人提交、记录流程信息到文件、通过例如:申请人提交、记录流程信息到文件、通过例如:申请人提交、记录流程信息到文件、通过例如:申请人提交、记录流程信息到文件、通过TQCTQC Workflow相关操作相关操作l l设置状态节点命名设置状态节点命名设置状态节点命名设置状态节点命名          设置状态节点要将状态显示在节点名中,且注意中英文状态使用的设置状态节点要将状态显示在节点名中,且注意中英文状态使用的设置状态节点要将状态显示在节点名中,且注意中英文状态使用的设置状态节点要将状态显示在节点名中,且注意中英文状态使用的是中文就是中文名,状态使用是英文就用英文状态名,命名形式为是中文就是中文名,状态使用是英文就用英文状态名,命名形式为是中文就是中文名,状态使用是英文就用英文状态名,命名形式为是中文就是中文名,状态使用是英文就用英文状态名,命名形式为” ”设置设置设置设置XXXX状态状态状态状态” ”设置状态为中文设置状态为中文。

      设置状态为中文设置状态为中文“ “已取消已取消已取消已取消” ”,则命名为,则命名为,则命名为,则命名为“ “设置已取消设置已取消设置已取消设置已取消状态状态状态状态” ”;如果状态使用英文;如果状态使用英文;如果状态使用英文;如果状态使用英文“ “CancelledCancelled” ”, ,则命名为则命名为则命名为则命名为“ “设置设置设置设置CancelledCancelled状态状态状态状态” ”l l工作流和生命周期命名工作流和生命周期命名工作流和生命周期命名工作流和生命周期命名工作流的导出文件,扩展名位工作流的导出文件,扩展名位工作流的导出文件,扩展名位工作流的导出文件,扩展名位jarjar,不允许使用,不允许使用,不允许使用,不允许使用zipzip,文件命名以,文件命名以,文件命名以,文件命名以”w”w开开开开头头头头” ”,英文首字母大写,用下划线区分单词,不允许出现中文(如:,英文首字母大写,用下划线区分单词,不允许出现中文(如:,英文首字母大写,用下划线区分单词,不允许出现中文(如:,英文首字母大写,用下划线区分单词,不允许出现中文(如:W_Product_Certification_Workflow.jarW_Product_Certification_Workflow.jar))))          生命周期的导出文件,扩展名位生命周期的导出文件,扩展名位生命周期的导出文件,扩展名位生命周期的导出文件,扩展名位jar,jar,不允许使用不允许使用不允许使用不允许使用zip,zip,文件命名以文件命名以文件命名以文件命名以“ “L L” ”开头,英文首字母大写,用下划线区分单词,不允许出现中文(如:开头,英文首字母大写,用下划线区分单词,不允许出现中文(如:开头,英文首字母大写,用下划线区分单词,不允许出现中文(如:开头,英文首字母大写,用下划线区分单词,不允许出现中文(如:L_Product_Certifiction_LifeCycle.jarL_Product_Certifiction_LifeCycle.jar))))说明:统一工作流和生命周期命名规则、如果有中文,在不同操作系统说明:统一工作流和生命周期命名规则、如果有中文,在不同操作系统说明:统一工作流和生命周期命名规则、如果有中文,在不同操作系统说明:统一工作流和生命周期命名规则、如果有中文,在不同操作系统或命令下,很容易出现问题或命令下,很容易出现问题或命令下,很容易出现问题或命令下,很容易出现问题             Workflow相关操作相关操作l l流程变量和路由命名流程变量和路由命名流程变量和路由命名流程变量和路由命名流程变量统一使用英文命名,遵循流程变量统一使用英文命名,遵循流程变量统一使用英文命名,遵循流程变量统一使用英文命名,遵循javajava的变更命名原则,不能使用的变更命名原则,不能使用的变更命名原则,不能使用的变更命名原则,不能使用空格和标点符号。

      然后可以为其定义中文显示名称空格和标点符号然后可以为其定义中文显示名称空格和标点符号然后可以为其定义中文显示名称空格和标点符号然后可以为其定义中文显示名称路由名称不能使用空格和标点符号路由名称不能使用空格和标点符号路由名称不能使用空格和标点符号路由名称不能使用空格和标点符号建议变量和路由的名称尽量简短,一般不超过建议变量和路由的名称尽量简短,一般不超过建议变量和路由的名称尽量简短,一般不超过建议变量和路由的名称尽量简短,一般不超过2020个英文字符或个英文字符或个英文字符或个英文字符或1010个个个个汉字              例如:路由例如:路由例如:路由例如:路由“ “提交项目经理提交项目经理提交项目经理提交项目经理” ”、、、、“ “完成签收完成签收完成签收完成签收” ”l l工作流中的代码提取到独立类中工作流中的代码提取到独立类中工作流中的代码提取到独立类中工作流中的代码提取到独立类中              工作流中(如任务节点的转变条件和表达式自动机中的代码)不建工作流中(如任务节点的转变条件和表达式自动机中的代码)不建工作流中(如任务节点的转变条件和表达式自动机中的代码)不建工作流中(如任务节点的转变条件和表达式自动机中的代码)不建议直接调用议直接调用议直接调用议直接调用WindchillWindchill的的的的APIAPI,也不能包含复杂的逻辑。

      建议把相关代,也不能包含复杂的逻辑建议把相关代,也不能包含复杂的逻辑建议把相关代,也不能包含复杂的逻辑建议把相关代码封装为独立的函数,放到流程相关的码封装为独立的函数,放到流程相关的码封装为独立的函数,放到流程相关的码封装为独立的函数,放到流程相关的XXWfUtilXXWfUtil类中,然后在工作流类中,然后在工作流类中,然后在工作流类中,然后在工作流中调用说明:中调用说明:中调用说明:中调用说明:          便于系统升级,如果工作流中调用了便于系统升级,如果工作流中调用了便于系统升级,如果工作流中调用了便于系统升级,如果工作流中调用了WindchillWindchill的的的的 API API,而在,而在,而在,而在WindchillWindchill升级时升级时升级时升级时APIAPI发生了变化,这时就必须把运行中的流程都停下发生了变化,这时就必须把运行中的流程都停下发生了变化,这时就必须把运行中的流程都停下发生了变化,这时就必须把运行中的流程都停下来,给升级带来困难来,给升级带来困难来,给升级带来困难来,给升级带来困难 Workflow相关操作相关操作l l例如:例如:例如:例如:l l以下代码不应该直接写到流程中:以下代码不应该直接写到流程中:以下代码不应该直接写到流程中:以下代码不应该直接写到流程中:S Stringtring userName=wt.sesssion.SessionHelper.manager.getPrincipal userName=wt.sesssion.SessionHelper.manager.getPrincipal().getName();().getName();try{try{      wt.session.SessionHelper.manager.setAdministrator();       wt.session.SessionHelper.manager.setAdministrator();      wt.ownership.OwnershipHelper.service.releaseOwnership((wt.ownership.Ownawt.ownership.OwnershipHelper.service.releaseOwnership((wt.ownership.Ownable)primaryBusinessObject);ble)primaryBusinessObject);            primaryBusinessObject=(wt.change2.WTChangeRequest2)wt.ownership.OwnerprimaryBusinessObject=(wt.change2.WTChangeRequest2)wt.ownership.OwnershipHelper.serivce.assignOwnership((wt.ownership.Ownable)primaryBusinessshipHelper.serivce.assignOwnership((wt.ownership.Ownable)primaryBusinessObject,(wt.org.WTPrincipal)(ext.elead.ec.ELEADECR)primaryBusinessObject).gObject,(wt.org.WTPrincipal)(ext.elead.ec.ELEADECR)primaryBusinessObject).getCreator().getObject();etCreator().getObject();}finally{}finally{     wt.session.SessionHelper.manager.setPrincipal(userName);     wt.session.SessionHelper.manager.setPrincipal(userName);} }以下代码为建议的封装方式:以下代码为建议的封装方式:以下代码为建议的封装方式:以下代码为建议的封装方式:// //设置文档使用范围变更申请单状态为设置文档使用范围变更申请单状态为设置文档使用范围变更申请单状态为设置文档使用范围变更申请单状态为“ “已关闭已关闭已关闭已关闭” ” Workflow相关操作相关操作l l不要把不要把不要把不要把WindchillWindchill对象和客制化对象作为流程变量对象和客制化对象作为流程变量对象和客制化对象作为流程变量对象和客制化对象作为流程变量不要把不要把不要把不要把WindchillWindchill对象和客制化对象作为流程变量,正确的做法是把对象和客制化对象作为流程变量,正确的做法是把对象和客制化对象作为流程变量,正确的做法是把对象和客制化对象作为流程变量,正确的做法是把WindchillWindchill对象和客制化对象的对象和客制化对象的对象和客制化对象的对象和客制化对象的ReferenceReference作为作为作为作为StringString类型的流程变量。

      类型的流程变量类型的流程变量类型的流程变量需要用到对象时,通过需要用到对象时,通过需要用到对象时,通过需要用到对象时,通过ReferenceReference获取如果需要一组对象,则声明获取如果需要一组对象,则声明获取如果需要一组对象,则声明获取如果需要一组对象,则声明流程变量对一个集合流程变量对一个集合流程变量对一个集合流程变量对一个集合( (例如例如例如例如ArrayListArrayList对象对象对象对象) ),把这些对象的,把这些对象的,把这些对象的,把这些对象的ReferenceReference保存到集合中保存到集合中保存到集合中保存到集合中说明:系统升级时需要尽量做到流程不中断,说明:系统升级时需要尽量做到流程不中断,说明:系统升级时需要尽量做到流程不中断,说明:系统升级时需要尽量做到流程不中断,WindchillWindchill对象和客制化对对象和客制化对对象和客制化对对象和客制化对象在系统升级前后,其类结构可能发生变化,而一旦这些对象作为流象在系统升级前后,其类结构可能发生变化,而一旦这些对象作为流象在系统升级前后,其类结构可能发生变化,而一旦这些对象作为流象在系统升级前后,其类结构可能发生变化,而一旦这些对象作为流程变量进行了序列化,则升级后的流程在继续运行的时候就会出现错程变量进行了序列化,则升级后的流程在继续运行的时候就会出现错程变量进行了序列化,则升级后的流程在继续运行的时候就会出现错程变量进行了序列化,则升级后的流程在继续运行的时候就会出现错误。

      如果流程变量中保存的是误如果流程变量中保存的是误如果流程变量中保存的是误如果流程变量中保存的是Reference,Reference,就不会出现错误就不会出现错误就不会出现错误就不会出现错误例如:声明流程变量例如:声明流程变量例如:声明流程变量例如:声明流程变量“ “eleadDocOideleadDocOid” ”, ,类型为类型为类型为类型为“ “java.lang.Stringjava.lang.String” ”流程变量中保存对象的流程变量中保存对象的流程变量中保存对象的流程变量中保存对象的ReferenceReference、、、、eleadDocOid=new eleadDocOid=new wt.fc.ReferenceFactory().getReferenceString(eleadDoc);wt.fc.ReferenceFactory().getReferenceString(eleadDoc);注意:其严格为注意:其严格为注意:其严格为注意:其严格为“ “VR:ext.elead.doc.EleadDoc:788874VR:ext.elead.doc.EleadDoc:788874” ”, ,其中的其中的其中的其中的“ “: :” ”不能用不能用不能用不能用“ “%3A%3A” ”代替。

      需要使用对象时通过代替需要使用对象时通过代替需要使用对象时通过代替需要使用对象时通过ReferenceReference获取:获取:获取:获取:ext.elead.doc.EleadDoc doc=(ext.elead.doc.EleadDoc)new ext.elead.doc.EleadDoc doc=(ext.elead.doc.EleadDoc)new wt.fc.ReferenceFactory().getReference(wt.fc.ReferenceFactory().getReference(eleadDocOideleadDocOid).getObject();).getObject(); Workflow相关操作相关操作l l获取系统配置的角色获取系统配置的角色获取系统配置的角色获取系统配置的角色流程中需要自动获取系统配置的角色的时候,应该在尽量靠近用到该角色的地方再获取流程中需要自动获取系统配置的角色的时候,应该在尽量靠近用到该角色的地方再获取流程中需要自动获取系统配置的角色的时候,应该在尽量靠近用到该角色的地方再获取流程中需要自动获取系统配置的角色的时候,应该在尽量靠近用到该角色的地方再获取。

      例如:当用户没有指定例如:当用户没有指定例如:当用户没有指定例如:当用户没有指定PDTPDT经理时系统提示经理时系统提示经理时系统提示经理时系统提示“ “不能指定不能指定不能指定不能指定PQAPQA自己担当自己担当自己担当自己担当PDTPDT经理,请经理,请经理,请经理,请重新指定重新指定重新指定重新指定PDTPDT经理!经理!经理!经理!” ”l l权限控制权限控制权限控制权限控制实现权限控制时,优先考虑使用实现权限控制时,优先考虑使用实现权限控制时,优先考虑使用实现权限控制时,优先考虑使用OOTBOOTB的设置,例如策略管理器管理的静态权限,生命周的设置,例如策略管理器管理的静态权限,生命周的设置,例如策略管理器管理的静态权限,生命周的设置,例如策略管理器管理的静态权限,生命周期管理器的权限设置,流程中的节点期管理器的权限设置,流程中的节点期管理器的权限设置,流程中的节点期管理器的权限设置,流程中的节点PBOPBO权限设置当以上方式无法满足需求时,再权限设置当以上方式无法满足需求时,再权限设置当以上方式无法满足需求时,再权限设置当以上方式无法满足需求时,再考虑使用客制化代码实现考虑使用客制化代码实现。

      考虑使用客制化代码实现考虑使用客制化代码实现l l循环链接循环链接循环链接循环链接尽量减少红线(循环链接)的使用,一个循环中红线只使用一次尽量减少红线(循环链接)的使用,一个循环中红线只使用一次尽量减少红线(循环链接)的使用,一个循环中红线只使用一次尽量减少红线(循环链接)的使用,一个循环中红线只使用一次说明:一条红线就可以将流程中的循环节点都是更新一次,同一个循环中如果使用多条红说明:一条红线就可以将流程中的循环节点都是更新一次,同一个循环中如果使用多条红说明:一条红线就可以将流程中的循环节点都是更新一次,同一个循环中如果使用多条红说明:一条红线就可以将流程中的循环节点都是更新一次,同一个循环中如果使用多条红线,会造出额外的性能开销线,会造出额外的性能开销线,会造出额外的性能开销线,会造出额外的性能开销l l嵌套子流程嵌套子流程嵌套子流程嵌套子流程不使用嵌套子流程,说明:子流程容易带来流程不匹配问题例如:父流程和子流程同时不使用嵌套子流程,说明:子流程容易带来流程不匹配问题例如:父流程和子流程同时不使用嵌套子流程,说明:子流程容易带来流程不匹配问题例如:父流程和子流程同时不使用嵌套子流程,说明:子流程容易带来流程不匹配问题。

      例如:父流程和子流程同时更新,已启动的旧的父流程实例在启动子流程时,会启动新的子流程的实例,有可能更新,已启动的旧的父流程实例在启动子流程时,会启动新的子流程的实例,有可能更新,已启动的旧的父流程实例在启动子流程时,会启动新的子流程的实例,有可能更新,已启动的旧的父流程实例在启动子流程时,会启动新的子流程的实例,有可能引起问题因此,应尽量避免使用子流程引起问题因此,应尽量避免使用子流程引起问题因此,应尽量避免使用子流程引起问题因此,应尽量避免使用子流程 Workflow相关操作相关操作l l橙色连接器节点橙色连接器节点橙色连接器节点橙色连接器节点橙色连接器节点(与、或、有条件的、阀值)中不可调用保存流程的操作橙色连接器节点(与、或、有条件的、阀值)中不可调用保存流程的操作橙色连接器节点(与、或、有条件的、阀值)中不可调用保存流程的操作橙色连接器节点(与、或、有条件的、阀值)中不可调用保存流程的操作说明:在连接说明:在连接说明:在连接说明:在连接器节点更新流程,会在数据库中锁定流程,容易造出数据库死锁器节点更新流程,会在数据库中锁定流程,容易造出数据库死锁器节点更新流程,会在数据库中锁定流程,容易造出数据库死锁。

      器节点更新流程,会在数据库中锁定流程,容易造出数据库死锁l l完成任务时避免复杂的操作完成任务时避免复杂的操作完成任务时避免复杂的操作完成任务时避免复杂的操作避免在用户完成任务时做复杂的操作,导致用户长时间完成不了任务避免在用户完成任务时做复杂的操作,导致用户长时间完成不了任务避免在用户完成任务时做复杂的操作,导致用户长时间完成不了任务避免在用户完成任务时做复杂的操作,导致用户长时间完成不了任务说明:用户完成任务时的系统操作,可以放到任务后面的表达式自动机中,进行后台处理说明:用户完成任务时的系统操作,可以放到任务后面的表达式自动机中,进行后台处理说明:用户完成任务时的系统操作,可以放到任务后面的表达式自动机中,进行后台处理说明:用户完成任务时的系统操作,可以放到任务后面的表达式自动机中,进行后台处理l l流程节点的合并与增加流程节点的合并与增加流程节点的合并与增加流程节点的合并与增加合理规划流程节点,建议相似任务合并到同一个节点,减少流程在合理规划流程节点,建议相似任务合并到同一个节点,减少流程在合理规划流程节点,建议相似任务合并到同一个节点,减少流程在合理规划流程节点,建议相似任务合并到同一个节点,减少流程在QueueQueue中的排队次数。

      中的排队次数中的排队次数中的排队次数同时为了避免连线交叉,增加流程的可阅读性,也可以增加同时为了避免连线交叉,增加流程的可阅读性,也可以增加同时为了避免连线交叉,增加流程的可阅读性,也可以增加同时为了避免连线交叉,增加流程的可阅读性,也可以增加“ “或节点或节点或节点或节点” ”作为连机器作为连机器作为连机器作为连机器l l同步自动机与定时器同步自动机与定时器同步自动机与定时器同步自动机与定时器尽量少使用同步自动机与定时器,如果使用同步自动机,建议使用尽量少使用同步自动机与定时器,如果使用同步自动机,建议使用尽量少使用同步自动机与定时器,如果使用同步自动机,建议使用尽量少使用同步自动机与定时器,如果使用同步自动机,建议使用“ “对象事件同步对象事件同步对象事件同步对象事件同步” ”类型类型类型类型的同步自动机的同步自动机的同步自动机的同步自动机 “表达式表达式表达式表达式” ”和和和和“ “类事件同步类事件同步类事件同步类事件同步” ”类型的同步自动机,对系统性能影响大,类型的同步自动机,对系统性能影响大,类型的同步自动机,对系统性能影响大,类型的同步自动机,对系统性能影响大,不建议使用不建议使用不建议使用不建议使用 Workflow相关操作相关操作一般在工作流的“条件表达式”,“执行表达式”“活动的转变条件”中放JAVA代码。

      Workflow相关操作相关操作l条件表达式:“条件表达式”中的代码一般用来自动选择路由 Workflow相关操作相关操作l活动的“转变条件”“转变条件”在任务启动和结束时执行一些操作:“开始”里面的代码会在任务启动时触发,如果这里出错,任务将无法启动;“完成”里面的代码会在任务完成时触发,如果这里出错,在点击“完成任务”按纽里会弹出错误提示,任务无法完成 Workflow相关操作相关操作 Workflow相关操作相关操作l表达式中可以写代表达式中可以写代码 Workflow相关操作相关操作流程变量:在工作流中创建变量,变量能在代码中引用变量能显示在任务中l l更新流程:更新流程:更新流程:更新流程:public static void updateProcess(WfProcess process){public static void updateProcess(WfProcess process){    WfProcess result=process;    WfProcess result=process;    result=(WfProcess)PersistenceHelper.manager.save(result);    result=(WfProcess)PersistenceHelper.manager.save(result);    PersistenceHelper.manager.refresh(result);    PersistenceHelper.manager.refresh(result);} } Workflow相关操作相关操作l l定义变量定义变量定义流程时,可在开始状况或是自动路由表示式中使用变量。

      定义流程时,可在开始状况或是自动路由表示式中使用变量变量可以是全局变量变量可以是全局变量( (适用于流程本身适用于流程本身) )或是局部变量或是局部变量( (适用于适用于指派的活动或子流程指派的活动或子流程) )变量可宣告为任何变量可宣告为任何JavaJava类型或任何类型或任何WindchillWindchill类别唯一的限制是变量必须是可串行化类别唯一的限制是变量必须是可串行化(Serializable)(Serializable)如果变量的类型为如果变量的类型为WindchillWindchill企业对象,则企业对象,则该对象的属性可透过标准取得者该对象的属性可透过标准取得者(Getter) API(Getter) API参考可如下参考可如下所示宣告变量:所示宣告变量:• •显示或隐藏显示或隐藏• •必要或选用必要或选用• •只读或读只读或读/ /写写• •可重新设定或静态的可重新设定或静态的变量值可以在某项活动或子流程中从父流程变量进行变量值可以在某项活动或子流程中从父流程变量进行初始化,也可以在活动或子流程完成时复制到父流程变量中初始化,也可以在活动或子流程完成时复制到父流程变量中。

      Workflow相关操作相关操作有二种默认的变数︰ self和primaryBusinessObjectself变数是指在执行时期的已指派活动PrimaryBusinessObject变量保有与执行时期工作流程相关的企业对象 Workflow相关操作相关操作若要定义针对变若要定义针对变量所显示的显示量所显示的显示名称,请单击「名称,请单击「定义显示名称定义显示名称( (DefineDefineDisplay Name)Display Name)」 Workflow相关操作相关操作在如上所示的「一般在如上所示的「一般( (GeneralGeneral) )」标签」标签面板中,您可以指定名称、类别、负面板中,您可以指定名称、类别、负责的角色,以及指派之活动的描述责的角色,以及指派之活动的描述名称是唯一必要的属性名称是唯一必要的属性您可以从「类别您可以从「类别( (CategoryCategory) )」下拉式」下拉式清单将活动分类举例来说,您可以清单将活动分类举例来说,您可以有反映项目团队或产品类型的活动类有反映项目团队或产品类型的活动类别WindchillWindchill提供许多预先定义的类提供许多预先定义的类别。

      类别是列举类型,您可以在别类别是列举类型,您可以在wt.workflow.definer.WfTemplateCatewt.workflow.definer.WfTemplateCategorygory档案中定义其他类别档案中定义其他类别 Workflow相关操作相关操作在如在如左所示的「活动左所示的「活动( (ActivityActivity) )」标签面板中,您可以指定使」标签面板中,您可以指定使用者或群组要用者或群组要执行的任务请从下拉式列表执行的任务请从下拉式列表中选取任务,另外,如果需要中选取任务,另外,如果需要的话,可在「指的话,可在「指示示( (InstructionsInstructions) )」文字区域中」文字区域中输入指示您可以利用括号分输入指示您可以利用括号分隔变量,例如隔变量,例如{varname{varname} }请使用反斜杠来请使用反斜杠来隔开分隔符,如下列范例所示:隔开分隔符,如下列范例所示:\{{varname}}\\{{varname}}\附注:只有附注:只有wt.properties文件中的「电子证件文件中的「电子证件(Electronic Identification)」属性设为」属性设为TRUE时,时,才能使用签名才能使用签名。

      Workflow相关操作相关操作若要建立「定义项目团队」活动,请从「活动若要建立「定义项目团队」活动,请从「活动(Activity)(Activity)」下拉式清单选取」下拉式清单选取「定义项目团队「定义项目团队(Define Teams)(Define Teams)」工作流程活动也必须建立一个」工作流程活动也必须建立一个wt.team.Teamwt.team.Team变量,供这个活动使用您通常可以这样做:建立一个流程阶层变量,供这个活动使用您通常可以这样做:建立一个流程阶层wt.team.Teamwt.team.Team变量及复本,以将该流程阶层变量指派至活动中所定义的变量及复本,以将该流程阶层变量指派至活动中所定义的wt.team.Teamwt.team.Team变数指派工作流程时,您可以建立一个新的项目团队实例,并将它指派至您建指派工作流程时,您可以建立一个新的项目团队实例,并将它指派至您建立的立的wt.team.Teamwt.team.Team变数当您替变量指派「项目团队」对象的实例时,必变数当您替变量指派「项目团队」对象的实例时,必须决定变量的用法须决定变量的用法如果希望以电子邮件通知用户任务指派,请勾选「传送通知如果希望以电子邮件通知用户任务指派,请勾选「传送通知(Send(SendNotification)Notification)」复选框。

      电子邮件通知是选用的,因为任务一定会加入至」复选框电子邮件通知是选用的,因为任务一定会加入至适当的用户的工作清单适当的用户的工作清单(Windchill Foundation & PDM)(Windchill Foundation & PDM)或「工作总览」表或「工作总览」表格格(Windchill PDMLink(Windchill PDMLink或或Windchill ProjectLink)Windchill ProjectLink)中如果「活动如果「活动(Activity)(Activity)」卷标中显示「必须签名」卷标中显示「必须签名(Signing Required)(Signing Required)」核取方」核取方块,而您希望必须有电子签名才能完成活动,请选取该复选框如需电子块,而您希望必须有电子签名才能完成活动,请选取该复选框如需电子签章的详细信息,请参阅在工作流程中要求电子签名(后续有讲)签章的详细信息,请参阅在工作流程中要求电子签名(后续有讲) Workflow相关操作相关操作虽然可以选择将活动任务指派给实际的用户或是用户群组,作为流程定虽然可以选择将活动任务指派给实际的用户或是用户群组,作为流程定义的一部分,但最好是选取实行者、角色或项目团队做为参与者,当流程定义的一部分,但最好是选取实行者、角色或项目团队做为参与者,当流程定义实例化时,这些参与者就会对应至使用者或是群组。

      以这种方式指定参与义实例化时,这些参与者就会对应至使用者或是群组以这种方式指定参与者可提供较大的弹性,并促进在各种前后关联中重新使用流程定义者可提供较大的弹性,并促进在各种前后关联中重新使用流程定义 Workflow相关操作相关操作在如下所示的「截止日期在如下所示的「截止日期( (DeadlineDeadline) )」标签面板上,您可以设定活动的到期」标签面板上,您可以设定活动的到期时间您可以依据活动或是父流程的开始时间,设定其截止日期如果您将时间您可以依据活动或是父流程的开始时间,设定其截止日期如果您将两者都设定截止日期,则系统会使用较早的截止日期您也可以指定结果,两者都设定截止日期,则系统会使用较早的截止日期您也可以指定结果,以及过期时是否要接获通知以及过期时是否要接获通知若要指定超过截止若要指定超过截止日期的结论,请选日期的结论,请选择下列其中一个复择下列其中一个复选框:选框:• •略过略过• •标记完成标记完成• •重新指派负责的重新指派负责的角色角色 Workflow相关操作相关操作若要指定通知的对象和时间,请选择以下任意数量的复选框:若要指定通知的对象和时间,请选择以下任意数量的复选框:• •活动过期时,若要通知具有特定角色的使用者活动过期时,若要通知具有特定角色的使用者( (除了负责的角色除了负责的角色之外之外) ),,请选取「通知选取的角色请选取「通知选取的角色(Notify the selected roles)(Notify the selected roles)」复选框。

      」复选框接着选择任意数量的角色接着选择任意数量的角色• •若要在活动截止日期之前通知负责的角色,请选取「通知负责若要在活动截止日期之前通知负责的角色,请选取「通知负责的角色的角色 (Notify the responsible role)(Notify the responsible role)」上方复选框,并填入截止日期多」上方复选框,并填入截止日期多久之前您希望传送通知的日数、时数和久之前您希望传送通知的日数、时数和( (或或) )分钟数• •若要在活动截止日期之后通知负责的角色,请选取「通知负责若要在活动截止日期之后通知负责的角色,请选取「通知负责的角色的角色 (Notify the responsible role)(Notify the responsible role)」下方复选框,并填入截止日期多」下方复选框,并填入截止日期多久之后您希望传送通知的日数、时数和久之后您希望传送通知的日数、时数和( (或或) )分钟数如果您没有指定时间,则到截止日期时,即使您没有选择任何复如果您没有指定时间,则到截止日期时,即使您没有选择任何复选框,都会将通知传送给负责的角色如果两个负责角色的通知复选框选框,都会将通知传送给负责的角色。

      如果两个负责角色的通知复选框您都选取了,并填入时间,截止日期之前和之后都会传送通知您都选取了,并填入时间,截止日期之前和之后都会传送通知 Workflow相关操作相关操作l l路由路由路由路由路由类型:路由类型:• •「无「无( (NoneNone) )」是指没有路由」是指没有路由「路由事件「路由事件( (Routing EventsRouting Events) )」」和「路由和「路由表示式表示式( (Routing ExpressionRouting Expression) )」文」文字区域也无法使用字区域也无法使用• •「条件式「条件式( (ConditionalConditional) )」会自」会自动触发指定的事件动触发指定的事件• •「手动「手动( (ManualManual) )」让用户选取」让用户选取此标签内指定的一或多个路由事此标签内指定的一或多个路由事件• •「手动独占「手动独占( (Manual exclusiveManual exclusive) )」仅允许用户选取此标签内指定」仅允许用户选取此标签内指定的其中的其中一个路由事件一个路由事件 Workflow相关操作相关操作活活动-转移移从「转移从「转移( (TransitionsTransitions) )」清单中」清单中选取一个条件,并在条件文字选取一个条件,并在条件文字区域中键入区域中键入表示式,即可将该条件加入转表示式,即可将该条件加入转移中。

      条件为标准的移中条件为标准的JavaJava表示表示式,若转移条式,若转移条件应继续执行,会将件应继续执行,会将resultresult变量变量设定为设定为TRUETRUE,若不应继续则设,若不应继续则设定为定为FALSEFALSE单击「检查语法单击「检查语法( (Check SyntaxCheck Syntax) )」,以确认您」,以确认您输入的输入的JavaJava程序程序码正确无误码正确无误 Workflow相关操作相关操作l活活动执行行选项 Workflow相关操作相关操作 Workflow相关操作相关操作 Workflow相关操作相关操作 Workflow相关操作相关操作l l活动活动活动活动————————定义子流程定义子流程定义子流程定义子流程子流程或子流程或ProxyProxy流程可作为另一流程流程可作为另一流程( (父流程父流程) )的节点若要在流程定义中加入若要在流程定义中加入ProxyProxy流程,请将「流程,请将「ProxyProxy流程」图标流程」图标( )( )拖曳至拖曳至流程图中「属性流程图中「属性( (propertiesproperties) )」窗口会开启。

      您可以指定类别,输入描述,」窗口会开启您可以指定类别,输入描述,并以浏览的方式来选取现有流程,此流程将会成为并以浏览的方式来选取现有流程,此流程将会成为ProxyProxy流程若要确保原流程若要确保原始流程变更时,始流程变更时,ProxyProxy流程也会更新,请选取「使用最新版序流程也会更新,请选取「使用最新版序( (Use LatestUse LatestIterationIteration) )」流程的名称会以「参考流程」流程的名称会以「参考流程( (Referenced ProcessReferenced Process) )」连结的方」连结的方式显示如果没有选择流程,您就无法回到流程图中您必须单击「取消如果没有选择流程,您就无法回到流程图中您必须单击「取消(Cancel)(Cancel)」」,,ProxyProxy流程节点就会由流程图中消失流程节点就会由流程图中消失 Workflow相关操作相关操作l l流程变量的获取流程变量的获取流程变量的获取流程变量的获取ProcessData processdata = wfProcess.getContext();if(processdata.isVariable(varibleName)){obj = processdata.getValue(varibleName);} Workflow相关操作相关操作WfProcess wfProcess = ……………….根据oid获取流程对象或通过其他方法获取ProcessData processdata1 = wfProcess.getContext();String varName = “testVarName”;if(processdata1.isVariable(key.toString())){processdata1.setValue(varName,value);//value可为任意串行化对象}PersistenceHelper.manager.save(wfProcess);在活动节点中self变量为WfActivity对象引用,self.getObject()可获取WfActivity对象WfActivity wfActivity = (WfActivity)self.getObject();WfProcess wfProcess = wfActivity. getParentProcess();也是获取流程对象的一种方法 但是作为全局变量的self指的则是流程对象本身的引用 Workflow相关操作相关操作l自动启动流程RevisionControlled rc=null; //實現RevisionControlled接口才可以取得TeamIdWTContained contained=null; //實現WTContained接口才可以取得Containe rc=(RevisionControlled)object; contained=(WTContained)object;WfProcess wfprocess = null; WTContainerRef containerRef = contained.getContainerReference(); //取得PBO的容器WfProcessDefinition processDefinition=null;TeamReference teamRef = rc.getTeamId(); //得到文檔審核的團隊if (containerRef != null) {//針對某容器下的處理—一般指該產品 processDefinition = wt.workflow.definer.WfDefinerHelper.service.getProcessDefinition(workflowName,containerRef); wfprocess = WfEngineHelper.service.createProcess(processDefinition, teamRef, containerRef); } //場地下的處理 processDefinition = wt.workflow.definer.WfDefinerHelper.service.getProcessDefinition(workflowName); wfprocess = WfEngineHelper.service.createProcess(processDefinition, teamRef); Workflow相关操作相关操作 //取得流程变量集合ProcessData processData = wfprocess.getContext(); //设置流程PBO主物件processData.setValue("primaryBusinessObject",object); //启动流程 wfprocess = wfprocess.start(processData, 0,truetrue); Workflow相关操作相关操作-获取流程获取流程public static WfProcess getProcess(Object paramObject) {if (paramObject == null)return null;try {Object localObject = null;if (paramObject instanceof ObjectIdentifier)localObject = PersistenceHelper.manager.refresh((ObjectIdentifier) paramObject);else if (paramObject instanceof ObjectReference) {localObject = ((ObjectReference) paramObject).getObject();}if (localObject instanceof WorkItem) {localObject = ((WorkItem) localObject).getSource().getObject();}if (localObject instanceof WfActivity) {localObject = ((WfActivity) localObject).getParentProcess();}if (localObject instanceof WfConnector) {localObject = ((WfConnector) localObject).getParentProcessRef().getObject();}if (localObject instanceof WfBlock) {localObject = ((WfBlock) localObject).getParentProcess();}if (localObject instanceof WfProcess) {return ((WfProcess) localObject);}return null;} catch (Exception localException) {localException.printStackTrace();}return null;} Workflow相关操作相关操作l l判断当前用户是否对该物件是否有读取权限判断当前用户是否对该物件是否有读取权限判断当前用户是否对该物件是否有读取权限判断当前用户是否对该物件是否有读取权限if (!(AccessControlHelper.manager.hasAccess(localWTPrincipal, localWTDocument,AccessPermission.READ))) Workflow相关操作相关操作-得到流程的得到流程的urlpublic static String getWorkflowLink(Object paramObject,String paramString1, String paramString2, String paramString3) {if (paramObject == null)return "";String str = "";try {WfProcess localWfProcess = getProcess(paramObject);if (localWfProcess == null)return "";HashMap localHashMap = new HashMap();localHashMap.put("Action", paramString1);localHashMap.put("oid",new ReferenceFactory().getReferenceString(localWfProcess));URLFactory localURLFactory = (URLFactory) MethodContext.getContext().get("URLFactory");if (localURLFactory == null)localURLFactory = new URLFactory();str = GatewayServletHelper.buildAuthenticatedHREF(localURLFactory,"wt.enterprise.URLProcessor", "generateForm", localHashMap);if ((paramString3 == null) || (paramString3.length() == 0))paramString3 = "window.open";str = ""+ paramString2 + "";} catch (Exception localException) {localException.printStackTrace();}return str;} Workflow相关操作相关操作 UI 培训培训lUI即即 User Interface 针对Windchill9.0之后的版本主要包括:之后的版本主要包括:table、、tree、、information page、、wizard、、dynamic javascript menu;;这些些组件都件都 共用一些元素:共用一些元素:actions、、action models 和和GUI    components用于用于显示示lWindchill基本基本JSP框架框架–begin.jspf文件文件:path::codebase/netmarkets/jsp/util.该文件文件包括:包括:tag显示示Windchill的首部信息和一、二的首部信息和一、二级导航菜航菜单–用于用于实例化例化beans(context,clipboard,session)–引入了一些系引入了一些系统的的.js和和.css文件文件–引入引入了了HTML片段片段–创建一些建一些HTML form数据数据 –提供并支持关提供并支持关闭弹出框和刷新主出框和刷新主页面面 UI 培训培训lend.jspf–Path:codebase/netmarkets/jsp/util–完成完成begin.jspf的内容的内容–显示系示系统的的footer–捕捕获并并显示异常信息示异常信息lbeginWizard.jspf文件,区文件,区别begin.jspf文件只是不会文件只是不会渲染一渲染一级和二和二级导航菜航菜单lAction Service–使用使用xml的配置,将系的配置,将系统的的动作作显示和后台示和后台处理理类联系在一起系在一起lValidation Service–验证动作的作的显示、示、验证wizard的前一步、后一步的的前一步、后一步的逻辑。

      UI 培训培训l系系统组件的可重复使用件的可重复使用–在我在我们定制系定制系统UI时,有一些基本步,有一些基本步骤来来创建建这些些组件件(table、、tree、、property panel)§描述描述组件件(describe * tags)§获取必要数据取必要数据(get *tags)§渲染渲染组件件(render * tags)l增加客制化代增加客制化代码到指系到指系统UI的的实现–增加新增的增加新增的javascript、、css、需要添加到、需要添加到codebase/netmarkets/jsp/util/begin_custim.jspf UI 培训培训l系系统中的主要中的主要Javascript函数函数–Path:codebase/netmarkets/javascript/util/main.js–Codebase/netmarkets/javascript/wizard.js UI 培训培训l系系统UI,,针对9.1重要的是重要的是JCA :JSP Client Architecture,客客户端端JSP框架框架……ElementTypeDescriptionStandardNmActionService (and corresponding helper and forwarder).javaThe StandardNmActionService manages the actions and actionmodels in the system. Run time Location:\codebase\com\ptc\netmarkets\util\miscClearCase Location:\ClientArchitecture\CommonComponents\src\com\ptc\netmarkets\util\misc actions.xml.xmlDefault system xml file for defining actions in the system.Run time Location:\codebase\config\actionsClearCase Location:ClientArchitecture/CommonComponents/src_web/config/actions/ UI 培训培训……actionmodels.xml*.xmlDefault system xml file for defining action models ins the system. Run time Location:\codebase\config\actionsClearCase Location:ClientArchitecture/CommonComponents/src_web/config/actions/actions.dtd.xmlDefault system dtd file for defining structure of an actions*.xmlRun time Location:\codebase\config\actionsClearCase Location:ClientArchitecture/CommonComponents/src_web/config/actions/actionmodels.dtd*.xmlDefault system dtd file for defining structure of an actionsmodels*.xmlRun time Location:\codebase\config\actionsClearCase Location:ClientArchitecture/CommonComponents/src_web/config/actions/ElementTypeDescription UI 培训培训Procedure – Defining a new action在系统中的操作进行唯一标识的操作和对象类型的名称。

      他们应遵循基于 codebasecodebase/config/actions/actions.dtd 的结构的 xml 文件中定义这里是新建文档向导操作定义的示例                                                                           UI 培训培训lObjecttype 名称是一种创建的命名空间,以及为特定的对象或功能区域相关的操作包装方法。

      在上面的示例中,名称为"文档"创建一个唯一的名称空间是适用于 wt.doc.WTDocuments 的操作lObjecttype 的名称的命名约定,可以是字母数字字符的任意组合大多数的 objecttypes 是操作所涉及的持久对象的别名应用于任何对象类型,如拷贝、 操作可以放在 objecttype 的“对象”我们建议所有的 objecttypes 具有特定于的业务对象下表描述了 objecttype 的有效参数…… UI 培训培训l详细信息在codebase/config/actions/actions.dtd文件中……ParameterDefault ValuePossible valuesRequired?Descriptionnamen/a any combination of alpha-numeric characters YesThe name used to reference this object-typeclassn/aA valid java classYesObject class for the enclosed actionsresourceBundlen/aAny valid resource bundle class nameNoClass name for the default resource bundle to use for the properties of the actions that are to be localized UI 培训培训l动作名称是在上下文中的对象类型的行动的唯一标识符。

      结合动作名称中的对象类型将的动作在系统内唯一默认情况下,操作名称对应于 jsp 命名为 objecttype 的包中的名称包装是相对于基本代码/netmarkets/jsp例如,在上述的情况下,xml 操作名称调用创建、 内的文档 objecttype jsp 代码库/netmarkets/jsp/文档中的被称为 create.jsp操作的名称的命名约定,可以是字母数字字符的任意组合我们建议所有的动作都有一个特定产品的对象动作下表描述了行动的有效参数…… UI 培训培训lPossible Action AttributeslDetails about these parameters can also be found in the codebase/config/actions/actions.dtd……ParameterDefault ValuePossible valuesRequired?Descriptionnamen/aallYesThis is the name by which the action will be referencedn/aPageComponentRowthirdLevelNavpopupMenuNoSpecifies the scope of the refreshajaxActionClassn/aNoThe jsp that is requested via ajaxcadfalsetrueNoIndicates if this action is only valid within the Wildfire embedded browser UI 培训培训……enabledwhensuspendedfalsetrueNoEnabled when the project is suspended/cancelled/completedinstallTypen/aWINDCHILL,PDM,PDM/PJL,PDMNoApplicable actions based on the installed components. This is for legacy purposes only. multiselectfalsefalse / trueNoUsed to indicate that multi-selection of row data can be used for this action.selectRequiredfalsefalse / trueNoDetermines if the UI should allow the action to proceed if nothing has been selected. Results in “Nothing Selected” popup UI 培训培训……afterJSn/aNoJS function name to invoke on client side validation for a wizard step after the step is completed. See the Wizard Best Practice for more detailed information. beforeJSn/aNoJS function name to invoke client side validation for a wizard step when the step is loaded See the Wizard Best Practice for more detailed information. afterVKn/aNoServer validator name to invoke client side validation for a wizard step after it is finished. See the Wizard Best Practice for more detailed information. beforeVKn/aNoServer validator name to invoke client side validation for a wizard step when the step is loaded. See the Wizard Best Practice for more detailed information. UI 培训培训……idobjecttype.actionNoOverrides the id of the wizard step (default is objecttype.action)preloadWizardPagetruefalse / trueNoSpecifies that the wizard step is to be downloaded when the wizard is launched See the Wizard Best Practice for more detailed information. hiddenfalsefalse / trueNoA wizard step to be hidden first, or that an action is rendered as non-clickable See the Wizard Best Practice for more detailed information. UI 培训培训……requiredfalsefalse / trueNoUsed for an wizard action that represents a step in the wizard. Specifies the wizard step is required. See the Wizard Best Practice for more detailed information. resourceBundleNoClass name for the resource bundle to use for the properties of the actions that are to be localizedrenderTypePDMNoDefault:http:///General:http:///General with context:http:///?oid=...PDM: url generated by URLactionDelegate; used for template processing or DCA UI 培训培训……uicomponentNoReferences entry n roleaccessprefs.xml (uic.name) to specifiy role-based access. See the Role Based UI best practice for more detailed information. postloadJSNoThe javascript function is executed after a wizard step is loaded into memory, but before it is displayed to the user. See the Wizard Best Practice for more detailed information. 标记中的标记的机构为界定的处理方面的行动。

       类别的界定哪些类属性,使用处理 属性的方法界定哪些方法来执行在类 类型(windowtype)的属性窗口确定什么行动,采取 在上面的示例命令是在新文件的行动是一个向导的类型(windowtype),是“弹出" 该框架将添加JavaScript,发起这项行动在新窗口中 指明该类和方法是执行提交后的向导…… UI 培训培训lPossible Command Attributes……ParameterDefault ValuePossible valuesRequired?Descriptionclassn/aNoThe class to handle postmethodn/aNoThe method in the class to execute and handle posturln/aNoUsed to override the generated urlonClickn/aNoSpecified an additional onclick function to call. Useful for confirming with the user whether to execute a special actionwindowTypepageNew|no_content| normal|page| popup|wizard_stepNoNew: like a popup, except includes a browser barno_content: no window actionnormal: default, submit the formwizard_step: display the action as a wizard steppage: display a new pagepopup: creat a non-modal popupdialog, typically a wizard. Sets come form of data UI 培训培训For example:  The documentResource.rbinfo file contains an entry as follows: document.create.title.value=New Documentdocument.create.description.value=New Documentdocument.create.tooltip.value=Add a new document with or without attached contentdocument.create.icon.value=newdoc.gifdocument.create.moreurlinfo.value=height=1000,width=820…… UI 培训培训lAction Report–http:////netmarkets/jsp/carambola/tools/actionReport/action.jsp…… UI 培训培训lAction Model Report–http://///netmarkets/jsp/carambola/tools/actionReport/actionModel.jsp UI 培训培训lDebug tooll在在URL地址后加入地址后加入&jcaDebug=1lType.action \service.properties \actionModel…… UI 培训培训lJCA Table l主要元素主要元素……ElementTypeDescription.jspjspYour JCA Property Panel implementation jsp file.service.propertiespropertiesData utilities and services are defined here.Run time Location: \codebasecomponents.tldtldTags can be defined here.Run time Location: \codebase\-INF\tlds\ UI 培训培训l首先需要引入:首先需要引入: <%@ taglib uri=" prefix="jca"%>lDescribe the property panel">                        " />在这里可以访问报告的工具,使有关可使用哪些属性的详细信息http:////netmarkets/jsp/property/propertyReport.jsp…… UI 培训培训lAcquire the Data for the property panel"       descriptor="${}"       serviceName="wt.fc.StandardPersistenceManager"       methodName="refresh">    Render the Property Panel}"/>/codebase/netmarkets/jsp/carambola/propertyPanel/examples.jsp…… UI 培训培训ldescribePropertyPanel tag ponents.DescribePropertyPanelTag and the body content is “scriptless”.…… UI 培训培训……ParameterDefault ValuePossible valuesRequired?Descriptionvar-Any String valueYesName of the exported scoped variable for the property panel descriptor.The type of the variable is ponents.descriptor.ComponentDescriptor.scopepageCan be: ‘page’, ‘request’, ‘session’ or ‘application’(case-insensitive)NoThe name of the scope to export the var attribute to.modeVIEWString form of com.ptc.core.ui.resources.ComponentMode enum: VIEW, CREATE, EDIT, SEARCHNoSets the ComponentMode that will be used for validation and for data utilities to determine what kind of GUI component to return. componentTypeTABLEString form of com.ptc.core.ui.resources.ComponentType enum: TABLE, WIZARD, WIZARD_TABLE, INFO_ATTRIBUTES_TABLE, SIMPLE, INFO, PICKER, SEARCH NoSets the ComponentType that will be used for validation and for data utilities to determine what kind of GUI component to return. UI 培训培训describeProperty tag ponents.DescribePropertyTag and the body content is “scriptless”…… UI 培训培训ParameterDefault ValuePossible valuesRequired?Descriptionid-name of an attribute, data utility id or logical attributeYesThe identifier for this property descriptor. This is used to look up default properties for the column. If the parent table supports configurable views, then this id is used to look up the view configurations.var-Any String valueYesName of the exported scoped variable for the property panel descriptor. The type of the variable is ponents.descriptor.ComponentDescriptor.label-Any String valueNoA localized display label for this property. If the label is not specified, then the infrastructure will attempt to look up a labelscopepageCan be: “page” , “request”, “session” or “application” (case-insensitive).NoThe name of the scope to export the var attribute to. modevalue inherited from describePropertyPanel tagString form of com.ptc.core.ui.resources.ComponentMode enum: VIEW, CREATE, EDIT, SEARCHNoSets the ComponentMode that will be used for validation and for data utilities to determine what kind of GUI component to return. UI 培训培训lrenderPropertyPanel tag attributesl/codebase/netmarkets/jsp/carambola/customization/examples/propertyPanel/examples.jsp……ParameterDefault ValuePossible valuesRequired?Descriptionmodel-Of type ponents.descriptor.ComponentModelYesThe model to render. If there are no child tags just the model is rendered. If there are child tags, then the model is just used as the default model for any addProperty tags that don't specify a model. UI 培训培训lConfiguring Tables – Set sortable columnsl This code snippet will sort the column “name” at the page load time (defaultSort="true"). As well as user can sort the column as and when required(sortable=”true”).…… UI 培训培训lConfiguring Tables – Enabling single/multiple row selection–…… UI 培训培训lConfiguring Tables – Adding pagination and page limit–…… UI 培训培训lPreference Manager…… UI 培训培训lConfiguring Tables – Adding an info page hyperlink to table data–…… UI 培训培训lConfiguring Tables - Making a Windchill Client Architecture Table Configurable–lConfiguring Tables – Enable Scrolling–lConfiguring Tables – Enable Table Count–…… UI 培训培训lConfiguring Tables – Hiding column of the table–

      此ID已为所有采摘的独特,在一个页面中,无论是不同类型或同一类型 ID应该不包含“ (点)的名称这是一个必需的属性–componentId:一个组件的ID,决定应该出现在搜索条件给定的选择器面板的属性默认值是pickerSearch–pickerCallback:自定义的回调函数的名称,用户将不得不实施–multiSelect :决定,结果表是否应“单一选择”或“多选择”默认值是“假”,这意味着它是单一的选择–defaultValue :选择器所呈现的文本框的默认值如果不提供,这是一个空白值("")–defaultHiddenValue:与机械手相关的隐藏的文本框的默认值如果不提供,这是一个空白值(""). UI 培训培训–baseWhereClause:附加条款,如果用户希望过滤搜索结果,不管用户输入的一些具体准则这whereclause只会得到“相与”的内部whereclause默认为空白;– label :标签选择器例如为用户选择器,它可以是“我的用户选择器”–displayAttribute:应的属性的名称后,选择了从选择器的结果显示给用户默认值是“名称”以外的所有用户选择器选择器。

      对于用户的选择器,默认值是“全名”–pickedDataFetcher:将由AJAX调用的使用过程中选择的结果的数据提取程序文件的URL如何推出使用提供的标记库的拾荒者的默认URL是/ netmarkets/ JSP /搜索/ pickerData.jsp对于选择器开始使用任何其他机制启动,默认URL是:/ JSP /组件/ defaultPickedDataFetcher.jsp–containerRef:containerRef在其中一个用户希望限制搜索的价值默认值是“” UI 培训培训–•pickerTitle:采摘标题不同采摘的默认值是:用户选择器:用户组织选择器:组织选择器组:组上下文选择器:上下文项目选择器:项目–•编辑:该属性定义一个选择器是否有可编辑的渲染或不可编辑渲染默认值是“真”–•的ObjectType:该属性仅支持开展通用选择器是一个必需的属性这应该有一个要启动机械手的对象类型,其中的价值•readOnlyPickerTextBox:这个属性定义是否应编辑或选择器“文本框中默认的是“假”,即是可编辑的文本框•typeComponentId:此参数是传递给定义可以在类型选取器中显示的类型设置。

      此参数可以通过采摘,即项目类型选择器选择器,项目主选择器和上下文选择器/ COM/ PTC/ Windchill的/企业/搜索/服务器/ SearchableTypes.properties文件中定义的类型给予typeComponentId UI 培训培训    • inline :此参数是通过一个选择器时应该从表级别的行动或内嵌推出允许的值是“真”或“假”默认值是“假”•pickedAttributes:这个参数包含一个逗号分隔的列表属性,用户要选择器获取这是适用的,只有当内联是“真”除用户选择器所有采摘的默认值是“名”对于用户的选择器,默认值是“全名”缺省机制来填充文本框选择器提供OOTB如果用户想要做别的事情,那么他们可以通过指定自己的pickerCallback功能这个函数应该有一个参数,将一个JSON对象名称“pickedObject”的数组用户可以遍历找出请求的属性值,通过这个对象以下列方式:function myPickerCallback(objects){   var myJSONObjects = objects.pickedObject;   for(var i=0; i< myJSONObjects.length;i++) {   var oid = myJSONObject[i].oid;   var displayAttribute=myJSONObject[i]./   }}   ////用户可以自己定义pickedDataFetcher 返回一个JSON 的对象 UI 培训培训lPicker Taglib开开发–<%@ taglib prefix="wctags" tagdir="/WEB-INF/tags" %>lLaunching Organization Picker<%-- launching organization picker--%>  lLaunching User picker<%-- launching user picker --%>  lLaunching Group picker<%-- launching group picker --%>     UI 培训培训lLaunching Context Picker<%-- launching context  picker--%>   lLaunching Item Picker–lLaunching Item Master Picker<%--    launching Item  Masterpicker--%>   UI 培训培训lLaunching Generic Picker<%--    launching Generic Picker--%>  lLaunching Picker from Table Level Action假设一个表级别的动作定义的名称为“multiUserPicker”。

      相应的multiUserPicker.jsp文件将类似于: UI 培训培训lAdvanced Picker Launching   。

    • 点击阅读更多内容
      相关文档
      【全国硕士研究生入学统一考试政治】2020年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2015年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2010年考研政治真题.docx 【全国硕士研究生入学统一考试政治】1996年政治考研真题(理科)及参考答案.doc 【全国硕士研究生入学统一考试政治】2001年政治考研真题(理科)及参考答案.doc 【全国硕士研究生入学统一考试政治】2016年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2000年政治考研真题(文科)及参考答案.doc 【全国硕士研究生入学统一考试政治】1997年政治考研真题(理科)及参考答案.doc 【全国硕士研究生入学统一考试政治】2007年考研政治真题.doc 【全国硕士研究生入学统一考试政治】1997年政治考研真题(文科)及参考答案.doc 【全国硕士研究生入学统一考试政治】2004年考研政治真题.doc 【全国硕士研究生入学统一考试政治】2003年考研政治真题.doc 【全国硕士研究生入学统一考试政治】2019年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2009年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2001年政治考研真题(文科)及参考答案.doc 【全国硕士研究生入学统一考试政治】2021年考研政治真题.doc 【全国硕士研究生入学统一考试政治】2014年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2018年考研政治真题.docx 【全国硕士研究生入学统一考试政治】2008年考研政治真题.doc 【全国硕士研究生入学统一考试政治】2011年考研政治真题.docx
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.