转自 http://www.moqui.org/framework/docs/Tutorial.html
本教程是一步一步的指导,建立和运行自己的Moqui组件的用户界面,逻辑,与数据库交互。
jiasudu 15000850008
概述
第1部分
下载Moqui框架
新建一个组件
添加Screen
添加Subscreen
添加显示的内容
添加子内容
第2部分
第一个实体定义
添加一些数据
自动查询Form
一个明确的字段
添加Create Form
第3部分
创建自定义Service
Groovy服务
下一步是什么?
jiasudu 15000850008
概述
第1:创建一个新的component和一个“Hello world!的screen。
第2:定义新的实体(数据库表)和form添加到screen,并创建该实体。
第3:创建一些自定义的逻辑,而不是使用默认的CRUD,对实体进行操作。
本文档中使用的方法是一个简单的使用内嵌的servlet容器。更完整部署方法,请阅读运行和部署文件。
第1部分
下载Moqui框架
下载Moqui框架. 下载之后在 moqui-<version>目录下,有 moqui-<version>.war 文件 和默认 runtime 目录 .
在Moqui根目录下.
如果你是全新下载, 你可以加载数据和运行服务器:
$ ant load
$ ant run
在浏览器输入 http://localhost:8080/, 使用 John Doe登陆, 可以浏览系统.
在命令行输入(<ctrl>-c ) 停止系统。
新建Component
Moqui 遵循 "约定优于配置" 的原则, 你可以新建一个 Moqui component 在下面目录:
$ cd runtime/component
$ mkdir tutorial
然后进入目录,创建其他标准目录:
$ cd tutorial
$ mkdir data
$ mkdir entity
$ mkdir screen
$ mkdir script
$ mkdir service
然后重启 Moqui (或者使用 $ ant run ).
jiasudu 15000850008
新建 Screen
使用 IDE 或者文本编辑器新增一个 screen 的XML 文件:
runtime/component/tutorial/screen/tutorial.xml
然后我们编写一个最简单的screen,里面只显示 "Hello world!" . 内容如下 :
1
2
3
4
5
6
7
8
|
<? xml version = "1.0" encoding = "UTF-8" ?>
require-authentication = "false" >
< widgets >
< label type = "h1" text = "Hello world!" />
</ widgets >
</ screen >
|
新增一个Subscreen
screen必须添加为根screen的子屏幕才是可以使用的。Moqui screens 的URL路径和菜单结构是对应的,所以需要设置URL给Screen和添加一个菜单tab。
在本教程中,我们将使用根 screen和header/footer/etc ,。runtime目录下有一个webroot的组件和webroot的Screen:
runtime/component/webroot/screen/webroot.xml
On a side note, the root screen is specified in the Moqui Conf XML file using the webapp-list.webapp.root-screen element, and you can have multiple elements to have different root screens for different host names.
To make the subscreen hierarchy more flexible this root screen only has a basic HTML head and body, with no header and footer content, so let's put our screen under the "apps" screen which adds a header menu and will give our screen some context. Modify the apps screen by changing:
runtime/component/webroot/screen/webroot/apps.xml
在apps.xml 新增subscreens元素,在subscreens 里面新增subscreens-item元素:
1
2
|
< subscreens-item name = "tutorial" menu-title = "Tutorial"
|
screen的name属性对应Url的路径 , 所以你可以在浏览器上使用下面的url:
http://localhost:8080/apps/tutorial
如果你不想修改已经存在的 screen 文件 并且仍然想添加新的子screen,你可以编辑一条数据库记录:
1
2
3
4
|
subscreenName = "tutorial" userGroupId = "ALL_USERS"
menuTitle = "Tutorial" menuIndex = "1" menuInclude = "Y" />
|
添加显示内容
Instead of using the label element we can get the HTML from a file that is "under" the screen.
新建一个简单的HTML 文件:
runtime/component/tutorial/screen/tutorial/hello.html
这个 HTML文件包含 一些HTML元素, 采用 included 父screen的 header/footer/etc :
1
|
< h1 >Hello world! (from hello.html file)</ h1 >
|
现在include这个HTML 文件到 tutorial.xml screen,使用render-mode.text元素:
1
2
3
4
5
6
7
8
9
10
11
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< widgets >
< label type = "h1" text = "Hello world!" />
< render-mode >
< text type = "html"
</ render-mode >
</ widgets >
</ screen >
|
So what is this render-mode thingy? Moqui XML Screens are meant to platform agnostic and may be rendered in various environments. Because of this we don't want anything in the screen that is specific to a certain mode of rendering the screen without making it clear that it is. Under the render-mode element you can have various sub-elements for different render modes, even for different text modes such as HTML, XML, XSL-FO, CSV, and so on so that a single screen definition can be rendered in different modes and produce output as needed for each mode.
The screen is available at the same URL, but now includes the content from the HTML file instead of having it inline as a label in the screen definition.
添加子内容
Another way to show the contents fo the hello.html file is to treat it as screen sub-content.
To do this the hello.html file must by in a sub-directory with the same name as the screen, ie in a tutorialdirectory as a sibling of the tutorial.xml file.
Now all we have to do is:
- tell the tutorial.xml screen to include child content by setting the screen.@include-child-contentattribute to true
- tell the screen where to include subscreens and child content by adding a widgets.subscreens-active element
screen XML 文件如下:
1
2
3
4
5
6
7
8
9
|
<? xml version = "1.0" encoding = "UTF-8" ?>
include-child-content = "true" >
< widgets >
< label type = "h1" text = "Hello world!" />
< subscreens-active />
</ widgets >
</ screen >
|
To see the content now you'll need to go to a different URL to tell Moqui that you want the hello.html file that is under the tutorial screen:
http://localhost:8080/apps/tutorial/hello.html
第二部分
第一个实体定义
一个 entity 是一个二维的数据结构, 并对应数据库的一张表结构. 一个entity值对应在数据库中为一行. Moqui 没有做ORM, 以致我们必须定义一个entity, 然后调用 Entity Facade写代码 (或其他更高级的公斤or other higher level tools) 来调用他.
创建一个简单的实体"Tutorial" ,里面有2个字段 "tutorialId" 和 "description" 。新建 entity XML 文件:
runtime/component/tutorial/entity/TutorialEntities.xml
内容:
1
2
3
4
5
6
7
8
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< entity entity-name = "Tutorial" package-name = "tutorial" >
< field name = "tutorialId" type = "id" is-pk = "true" />
< field name = "description" type = "text-long" />
</ entity >
</ entities >
|
If you're running Moqui in dev mode the entity definition cache clears automatically so you don't have to restart, and for production mode or if you don't want to wait (since Moqui does start very fast) you can just stop and start the JVM.
How do you create the table? Unless you turn the feature off (in the Moqui Conf XML file) the Entity Facade will create the table (it it doesn't already exist) the first time the entity is used.
添加数据
The Entity Facade has functionality to load data from, and write data to, XML files that basically elements that match entity names and attributes that map field names.
我们随后可以创建UI界面录入数据, 你也可以用系统工具中的自动 Screen或Entity数据UI 录入该实体的数据. 被数据模型使用的数据文件有 程序依赖的种子数据,测试数据 , 和演示数据.
创建一个 entity facade的 XML 文件:
runtime/component/tutorial/data/TutorialData.xml
内容如下:
1
2
3
4
5
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< entity-facade-xml type = "seed" >
< Tutorial tutorialId = "TestOne" description = "Test one description." />
< Tutorial tutorialId = "TestTwo" description = "Test two description." />
</ entity-facade-xml >
|
为了加载数据,我们可以执行一下 $ ant load 也可以查看 Run and Deploy文档采用其他方式执行.
自动查询Form
新增 XML screen 定义作为子页面,添加到tutorial screen 中:
runtime/component/tutorial/screen/tutorial/FindTutorial.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< transition name = "findTutorial" >< default-response url = "." /></ transition >
< actions >
< entity-find entity-name = "Tutorial" list = "tutorialList" >
< search-form-inputs />
</ entity-find >
</ actions >
< widgets >
< form-list name = "ListTutorials" list = "tutorialList"
transition = "findTutorial" >
< auto-fields-entity entity-name = "Tutorial"
field-type = "find-display" />
</ form-list >
</ widgets >
</ screen >
|
screen 分为以下几部分:
-
transition Think of links between screens as an ordered graph where each screen is a node and the transitions defined in each screen are how you go from that screen to another (or back to the same), and as part of that transition possibly run actions or a service.
- A single transition can have multiple responses with conditions and for errors resulting in transition to various screens as needed by your UI design.
- This particular transition very simply just refers back to the current screen.
-
actions.entity-find There is just one action run when this screen is rendered: an entity-find.
- Normally with an entity-find element (or in the Java API an EntityFind object) you would specify conditions, fields to order by, and other details about the find to run.
- In this case we are doing a find on an entity using standard parameters from an XML Form, so we can use the search-form-inputs sub-element to handle these automatically.
- To get an idea of what the parameters should be like just view the HTML source in your browser that is generated by the XML Form.
-
widgets.form-list This is the actual form definition, specifically for a "list" form for multiple records/rows (as opposed to a "single" form).
- The name here can be anything as long as it is unique within the XML Screen.
- Note that the list refers to the result of the entity-find in the actions block, and the transitionattribute refers to the transition defined at the top of the screen.
- Since the goal was to have a form automatically defined based on an entity we use the auto-fields-entity element with the name of our Tutorial entity, and find-display option for the field-typeattribute which creates find fields in the header and display fields for each record in the table body.
用下面的URL看看这个screen:
http://localhost:8080/apps/tutorial/FindTutorial
一个明确的字段
Instead of the default for the description field, what if you wanted to specify how it should look at what type of field it should be?
To do this just add a field element inside the form-list element, and just after the auto-fields-entityelement, like this:
1
2
3
4
5
6
7
8
9
|
< form-list name = "ListTutorials" list = "tutorialList" transition = "findTutorial" >
< auto-fields-entity entity-name = "Tutorial" field-type = "find-display" />
< field name = "description" >
< header-field show-order-by = "true" >
< text-find hide-options = "true" />
</ header-field >
< default-field >< display /></ default-field >
</ field >
</ form-list >
|
Because the field name attribute is the same as a field already created by the auto-fields-entity element it will override that field. If the name was different an additional field would be created. The result of this is basically the same as what was automatically generated using the auto-fields-entity element, and this is how you would do it explicitly.
新建 Create Form
Let's add a button that will pop up a Create Tutorial form, and a transition to process the input.
First add the transition to the FindTutorial.xml screen you created before, right next to the findTutorialtransition:
1
2
3
4
|
< transition name = "createTutorial" >
< service-call name = "create#Tutorial" />
< default-response url = "." />
</ transition >
|
This transition just calls the create#Tutorial service, and then goes back to the current screen.
Where did the create#Tutorial service come from? We haven't defined anything like that yet. The Moqui Service Facade supports a special kind of service for entity CrUD operations that don't need to be defined, let alone implemented. This service name consists of two parts, a verb and a noun, separated by a hash (#). As long as the verb is create, update, store, or delete and the noun is a valid entity name the Service Facade will treat it as an implicit entity-auto service and do the desired operation. It does so based on the entity definition and the parameters passed to the service call. For example, with the create verb and an entity with a single primary key field if you pass in a value for that field it will use it, otherwise it will automatically sequence a value using the entity name as the sequence key.
Next let's add the create form, in a hidden container that will expand when a button is clicked. Put this inside the widget element, just above the form-list element in the original FindTutorial screen you created before so that it appears above the list form in the screen:
1
2
3
4
5
6
7
8
|
< container-dialog id = "CreateTutorialDialog" button-text = "Create Tutorial" >
< form-single name = "CreateTutorial" transition = "createTutorial" >
< auto-fields-entity entity-name = "Tutorial" field-type = "edit" />
< field name = "submitButton" >
< default-field title = "Create" >< submit /></ default-field >
</ field >
</ form-single >
</ container-dialog >
|
The form definition refers to the transition you just added to the screen, and uses the auto-fields-entityelement with edit for the field-type to generate edit fields. The last little detail is to declare a button to submit the form, and it's ready to go. Try it out and see the records appear in the list form that was part of the original screen.
第三部分
创建自定义Service
The createTutorial transition from our screen above used the implicit entity-auto service create#Tutorial. Let's see what it would look like to define and implement a service manually.
First lets define a service and use the automatic entity CrUD implementation:
runtime/component/tutorial/service/tutorial/TutorialServices.xml
1
2
3
4
5
6
7
8
|
< service verb = "create" noun = "Tutorial" type = "entity-auto" >
< in-parameters >
< auto-parameters include = "all" />
</ in-parameters >
< out-parameters >
< auto-parameters include = "pk" required = "true" />
</ out-parameters >
</ service >
|
This will allow all fields of the Tutorial entity to be passed in, and will always return the PK field (tutorialId). Note that with the auto-parameters element we are defining the service based on the entity, and if we added fields to the entity they would be automatically represented in the service.
Now change that service definition to add an inline implementation as well. Notice that the service.@typeattribute has changed, and the actions element has been added.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
< service verb = "create" noun = "Tutorial" type = "inline" >
< in-parameters >
< auto-parameters include = "all" />
</ in-parameters >
< out-parameters >
< auto-parameters include = "pk" required = "true" />
</ out-parameters >
< actions >
< entity-make-value entity-name = "Tutorial" value-field = "tutorial" />
< entity-set value-field = "tutorial" include = "all" />
< if condition = "!tutorial.tutorialId" >
< entity-sequenced-id-primary value-field = "tutorial" />
</ if >
< entity-create value-field = "tutorial" />
</ actions >
</ service >
|
Now to call the service instead of the implicit entity-auto one just change the transition to refer to this service:
1
2
3
4
|
< transition name = "createTutorial" >
< service-call name = "tutorial.TutorialServices.create#Tutorial" />
< default-response url = "." />
</ transition >
|
Note that the service name for a defined service like this is like a fully qualified Java class name. It has a "package", in this case "tutorial" which is the directory (possibly multiple directories separated by dots) under the component/service directory. Then there is a dot and the equivalent of the class name, in this case "TutorialServices" which is the name of the XML file the service is in, but without the .xml extension. After that is another dot, and then the service name with the verb and noun optionally separated by a hash (#).
Groovy 服务
你可以采用Groovy (也支持其他脚本语言)实现服务 来代替 XML 操作? 下面定义一个示例服务:
1
2
3
4
5
6
7
8
9
|
< service verb = "create" noun = "Tutorial" type = "script"
< in-parameters >
< auto-parameters include = "all" />
</ in-parameters >
< out-parameters >
< auto-parameters include = "pk" required = "true" />
</ out-parameters >
</ service >
|
Notice that the service.@type attribute has changed to script, and there is now a service.@locationattribute which specifies the location of the script.
Here is what the script would look like in that location:
1
2
3
4
|
def tutorial = ec.entity.makeValue( "Tutorial" )
tutorial.setFields(context, true, null , null )
if (!tutorial.tutorialId) tutorial.setSequencedIdPrimary()
tutorial.create() |
当用 Groovy, 或者其他语言, 你可以用 Moqui Java API ,执行上下文 ExecutionContext class 在脚本中定义了变量名为 "ec". 关于API 的更多详细信息请看 API JavaDocs 以及 ExecutionContext 看具体的页面.
下一步?
现在你已经了解了Moqui Framework初步情况, 你可以阅读 (或者再次阅读) Moqui Framework简介的 PDF 文件,里面介绍框架的,一些思路,和如何工作. 该文件可以去 SourceForgehere 下载.
你也可以去读 Framework Features 的一些文档.
相关推荐
Moqui生态系统是一组以一个共同的框架和一系列通用的业务构件为中心的软件包。
欢迎使用Moqui框架 有关代码,讨论,支持等的社区基础结构的信息,请参阅《社区指南》: 有关运行和部署Moqui的详细信息,请参见: 请注意,运行时目录是Moqui Framework运行所必需的,但不包含在源存储库中。 ...
"moqui-runtime-angular-master" 是一个基于 Moqui 框架和 AngularJS 开发的项目。Moqui 是一个全面的企业级应用框架,主要用于构建复杂的业务应用程序,而 AngularJS 是一个前端 JavaScript 框架,用于构建动态网页...
此系统基于Moqui框架,利用Mantle业务工件,并配备了直观的用户界面,确保用户能够轻松上手并高效工作。 Moqui框架是一个全面的、开源的企业级应用开发平台,由Groovy和Grails构建,强调可扩展性和灵活性。Moqui...
Moqui Scripts,正如其名,是一组专为Moqui框架量身定制的脚本,旨在简化在不同方案和操作系统下的环境配置过程。Moqui是一个全面的企业级应用框架,基于Java语言,强调敏捷开发和灵活配置。它提供了一个强大的基础...
HiveMind:HiveMind是面向服务组织的项目管理和ERP应用程序。 它具有项目任务管理,请求跟踪,时间跟踪,费用,发票付款,总分类帐和内容管理(wiki)的功能。 HiveMind基于Moqui框架,Mantle业务工件和简单屏幕
使用它的方式与Moqui框架中的REST Api类似。 GraphQL端点是/graphql/v1?query={graphQLQueryString}或/graphql/v1?query={graphQLQueryString}&&variables={graphQLVariables} GraphQL Schema的配置为组件服务...
根据提供的文件信息,文档标题为“moqui文档资源分享”,但主要内容来自于文档“HEMPlight”,这是“Holistic Enterprise Mechanization Process”(整体企业机械化过程)中的一部分,由David E. Jones撰写。HEMP是...
Moqui生态系统是用于企业应用程序的一系列开源组件,所有这些组件都建立在用Java和Groovy编写的通用框架(Moqui Framework)上。 这些组件包括插入框架,业务工件和应用程序的工具。 一些流行的工具插件包括Elastic...
Moqui运行时 Moqui Framework的默认运行时目录。 要运行Moqui Framework,需要运行时目录。 Gradle get组件会根据moqui目录中addons.xml中的配置自动安装,加载和运行任务。
它还引用了"moqui.org"作为获取更多信息的来源,说明Mantle是基于Moqui框架开发的。此外,《使用Moqui制作应用程序》这本书对通用数据模型有详细的介绍,这本书的PDF可以在指定链接下载,读者可以通过阅读该书来深入...
ERP模型构件说明 本人收藏了3年的资源 现放出 都是总结了很多系统 软件项目实施过程中的经验的 慢慢积累的
Moqui Marble ERP 是一种规划和管理应用程序,适用于生产商品和服务并销售给个人 (B2C) 和组织 (B2B) 的企业。 这是一个全面的 ERP 应用程序,而不是专注于 POP Commerce ERP 之类的商品或 HiveMind PM & Admin 之类...
2. **Moqui Framework**:Moqui是一个全面的企业级应用框架,它包含了一个完整的开发工具集、工作流引擎、事件驱动的架构以及一套可扩展的服务层。Moqui强调可重用性、模块化和灵活性,与Mantle USL结合,可以为企业...
Moqui-zsys
CS50网站– Capstone项目:商业伙伴演示: : Business Buddy是CRM(客户关系管理)软件,可帮助公司的销售团队与潜在客户取得联系。 假设您是一家网络开发服务提供商,并且拥有一家名为“ TNL IT解决方案”的公司。...