This tutorial is a step-by-step guide to creating and running your own Moqui component with a user interface, logic, and database interaction.
Part 1: To get started you'll be creating your own component and a simple "Hello world!" screen.
Part 2: Continuing from there you'll define your own entity (database table) and add forms to your screen to find and create records for that entity.
Part 3: To finish off the fun you will create some custom logic instead of using the default CrUD logic performed by the framework based on the entity definition.
The running approach used in this document is a simple one using the embedded servlet container. For more complete coverage of running and deployment options, and of the general directory structure of Moqui Framework, please read the Run and Deploy document.
If you haven't already downloaded Moqui Framework, do that now.
Run Moqui using the Running and Deployment Instructions.
In your browser go to http://localhost:8080/, log in as John Doe, and look around a bit.
Now quit (<ctrl>-c in the command line) and you're ready to go...
Moqui follows the "convention over code" principle for components, so all you really have to do to create a Moqui component is create a directory:
$ cd runtime/component
$ mkdir tutorial
Now go into the directory and create some of the standard directories that you'll use later in this tutorial:
$ cd tutorial
$ mkdir data
$ mkdir entity
$ mkdir screen
$ mkdir script
$ mkdir service
With your component in place just start up Moqui (with ./gradlew load then ./gradlew run or the like).
Using your favorite IDE or text editor add a screen XML file in:
For now let this be a super simple screen with just a "Hello world!" label in it. The contents should look something like:
<?xml version="1.0" encoding="UTF-8"?> <screen require-authentication="false"> <widgets> <label type="h1" text="Hello world!"/> </widgets> </screen>
To make your screen available it needs to be added as a subscreen to a screen that is already under the root screen somewhere. In Moqui screens the URL path to the screen and the menu structure are both driven by the subscreen hierarchy, so this will setup the URL for the screen and add a menu tab for it.
For the purposes of this tutorial we'll use the existing root screen and header/footer/etc that are in the included runtime directory. This runtime directory has a webroot component with the root screen at:
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. See the Run and Deploy guide for more information on the Moqui Conf XML file.
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:
Add a subscreens-item element as a sub-element under the subscreens element in the apps.xml file like:
<subscreens default-item="AppList"> <subscreens-item name="tutorial" menu-title="Tutorial" location="component://tutorial/screen/tutorial.xml"/> </subscreens>
The name attribute specifies the value for the path in the URL to the screen, so your screen is now available in your browser at:
If you don't want to modify an existing screen file and still want to mount your screen as a subscreen of another you can do so with a record in the database that looks like this:
<SubscreensItem screenLocation="component://webroot/screen/webroot/apps.xml" subscreenName="tutorial" menuTitle="Tutorial" menuIndex="1" menuInclude="Y" subscreenLocation="component://tutorial/screen/tutorial.xml"/>
Instead of using the label element we can get the HTML from a file that is "under" the screen.
First create a simple HTML file located at:
The HTML file can contain any HTML, and since this will be included in a screen whose parent screens take care of header/footer/etc we can keep it very simple:
<h1>Hello world! (from hello.html file)</h1>
Now just explicitly include the HTML file in the tutorial.xml screen definition using the render-mode.text element:
<?xml version="1.0" encoding="UTF-8"?> <screen require-authentication="false"> <widgets> <label type="h1" text="Hello world!"/> <render-mode> <text type="html,vuet" location="component://tutorial/screen/tutorial/hello.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.
Since Moqui 2.1.0 the Vue JS based hybrid client/server rendering functionality is available. This uses the render mode 'vuet' instead of 'html' because the output is actually a Vue template and not standard HTML. The [email protected] attribute is "html,vuet" so that the HTML from the file is included for both render modes.
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 tutorial directory as a sibling of the tutorial.xml file.
Now all we have to do is:
With those done your screen XML file should look like:
<?xml version="1.0" encoding="UTF-8"?> <screen require-authentication="false" include-child-content="true"> <subscreens default-item="hello.html"/> <widgets> <label type="h1" text="Hello world!"/> <subscreens-active/> </widgets> </screen>
To see the content go to a URL that tells Moqui that you want the hello.html file that is under the tutorial screen:
With the default subscreens item specified you can also just go to the tutorial screen's URL:
An entity is a basic tabular data structure, and usually just a table in a database. An entity value is equivalent to a row in the database. Moqui does not do object-relational mapping, so all we have to do is define an entity, and then start writing code using the Entity Facade (or other higher level tools) to use it.
To create a simple entity called "Tutorial" with fields "tutorialId" and "description" create an entity XML file at:
<?xml version="1.0" encoding="UTF-8"?> <entities> <entity entity-name="Tutorial" package="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.
We'll create a UI to enter data later on, and you can use the Auto Screen or Entity Data UI in the Tools application to work with records in your new entity. Data files are useful for seed data that code depends on, data for testing, and data to demonstrate how a data model should be used. So, let's try it.
Create an entity facade XML file at:
<?xml version="1.0" encoding="UTF-8"?> <entity-facade-xml type="seed"> <tutorial.Tutorial tutorialId="TestOne" description="Test one description."/> <tutorial.Tutorial tutorialId="TestTwo" description="Test two description."/> </entity-facade-xml>
To load this just run $ ant load or one of the other load variations described in the Run and Deploy document.
Add the XML screen definition below as a subscreen for the tutorial screen by putting it in the file:
<?xml version="1.0" encoding="UTF-8"?> <screen require-authentication="anonymous-all"> <transition name="findTutorial"><default-response url="."/></transition> <actions> <entity-find entity-name="tutorial.Tutorial" list="tutorialList"> <search-form-inputs/></entity-find> </actions> <widgets> <form-list name="ListTutorials" list="tutorialList" transition="findTutorial"> <auto-fields-entity entity-name="tutorial.Tutorial" field-type="find-display"/> </form-list> </widgets> </screen>
This screen has a few key parts:
To view this screen use this URL:
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-entity element, like this:
<form-list name="ListTutorials" list="tutorialList" transition="findTutorial"> <auto-fields-entity entity-name="tutorial.Tutorial" field-type="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.
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 findTutorial transition:
<transition name="createTutorial"> <service-call name="create#tutorial.Tutorial"/> <default-response url="."/> </transition>
This transition calls the create#tutorial.Tutorial service, and then goes back to the current screen.
Where did the create#tutorial.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:
<container-dialog id="CreateTutorialDialog" button-text="Create Tutorial"> <form-single name="CreateTutorial" transition="createTutorial"> <auto-fields-entity entity-name="tutorial.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-entity element 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.
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:
<services> <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> </services>
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 [email protected] attribute has changed, and the actions element has been added.
<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.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:
<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 (#).
What if you want to implement the service in Groovy (or some other supported scripting language) instead of the inline XML Actions? In that case the service definition would look like this:
<service verb="create" noun="Tutorial" type="script" location="component://tutorial/script/tutorial/createTutorial.groovy"> <in-parameters> <auto-parameters include="all"/> </in-parameters> <out-parameters> <auto-parameters include="pk" required="true"/> </out-parameters> </service>
Here is what the script would look like in that location:
def tutorial = ec.entity.makeValue("tutorial.Tutorial") tutorial.setFields(context, true, null, null) if (!tutorial.tutorialId) tutorial.setSequencedIdPrimary() tutorial.create()
When in Groovy, or other languages, you'll be using the Moqui Java API which is based on the ExecutionContext class which is available in the script with the variable name "ec". For more details on the API see the API JavaDocs and specifically the doc for the ExecutionContext class which has links to the other major API interface pages.
Now that you have soiled your hands with the details of Moqui Framework, see the full documentation for the framework and a summary of Mantle Business Artifacts in the book Making Apps with Moqui (PDF).
More documentation for Moqui Framework is also being added to moqui.org here in the Moqui Framework wiki space. Eventually we plan to migrate and update all content from the Making Apps with Moqui book to the moqui.org wiki.
You may also enjoy reading through the Framework Features document.