454 lines
24 KiB
HTML
454 lines
24 KiB
HTML
<!-- BeginDsi "dsi/head.html" -->
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Embedthis Appweb 4.3.4 Documentation</title>
|
|
<meta name="keywords" content="embedded web server, web server software, embedded HTTP, application web server,
|
|
embedded server, small web server, HTTP server, library web server, library HTTP, HTTP library" />
|
|
<meta name="description" content="Embedthis Sofware provides commercial and open source embedded web servers for
|
|
devices and applications." />
|
|
<meta name="robots" content="index,follow" />
|
|
<link href="../../../doc.css" rel="stylesheet" type="text/css" />
|
|
<link href="../../../print.css" rel="stylesheet" type="text/css" media="print"/>
|
|
<!--[if IE]>
|
|
<link href="../../../iehacks.css" rel="stylesheet" type="text/css" />
|
|
<![endif]-->
|
|
<link href="http://www.google.com/cse/style/look/default.css" type="text/css" rel="stylesheet" />
|
|
</head>
|
|
|
|
<body>
|
|
<div class="top">
|
|
<a class="logo" href="http://appwebserver.org/"> </a>
|
|
<div class="topRight">
|
|
<div class="search">
|
|
<div id="cse-search-form"></div>
|
|
<div class="version">Embedthis Appweb 4.3.4</div>
|
|
</div>
|
|
</div>
|
|
<div class="crumbs">
|
|
<a href="../../../index.html">Home</a>
|
|
<!-- EndDsi -->
|
|
> <a href="index.html">ESP Guide</a> > <b>ESP MVC Tour</b>
|
|
</div>
|
|
</div>
|
|
<div class="content">
|
|
<div class="contentRight">
|
|
<h1>Quick Nav</h1>
|
|
<ul class="nav">
|
|
<li><a href="#blog">Blog App</a></li>
|
|
<li><a href="#create">Creating a New App</a></li>
|
|
<li><a href="#run">Run the App</a></li>
|
|
<li><a href="#hello">Hello World</a></li>
|
|
<li><a href="#layout">Layout Pages</a></li>
|
|
<li><a href="#dynamic">Dynamic Content</a></li>
|
|
<li><a href="#scaffolds">Scaffolds</a></li>
|
|
<li><a href="#newPosts">Create New Posts</a></li>
|
|
<li><a href="#homePage">Edit the Home Page</a></li>
|
|
<li><a href="#layout">Changing the Layout</a></li>
|
|
<li><a href="#validations">Validations</a></li>
|
|
<li><a href="#learn">Learn More</a></li>
|
|
</ul>
|
|
<!-- BeginDsi "dsi/espSeeAlso.html" -->
|
|
<h1>See Also</h1>
|
|
<ul class="nav">
|
|
<li><a href="../../../guide/esp/users/using.html">ESP Overview</a></li>
|
|
<li><a href="../../../guide/esp/users/tour.html">ESP Tour</a></li>
|
|
<li><a href="../../../guide/esp/users/template.html">Templates and Layouts</a></li>
|
|
<li><a href="../../../guide/esp/users/controls.html">HTML Controls</a></li>
|
|
<li><a href="../../../guide/esp/users/config.html">ESP Configuration Directives</a></li>
|
|
<li><a href="../../../guide/esp/users/mvc.html">Model-View-Controller</a></li>
|
|
<li><a href="../../../guide/esp/users/generator.html">Application Generator</a></li>
|
|
<li><a href="../../../guide/esp/users/controllers.html">Controllers and Actions</a></li>
|
|
<li><a href="../../../guide/esp/users/database.html">Database Interface</a></li>
|
|
<li><a href="../../../guide/appweb/users/caching.html">Caching Responses</a></li>
|
|
</ul>
|
|
<!-- EndDsi -->
|
|
</div>
|
|
<div class="contentLeft">
|
|
<h1>ESP MVC Tour</h1>
|
|
<p>This quick tour of the ESP MVC Framework provides an overview of the ESP Model-View-Controller
|
|
framework and how to use it for your web applications.</p>
|
|
<p>First make sure you have read the <a href="../../appweb/users/quickStart.html">Quick Start</a>,
|
|
and <a href="tour.html">ESP Tour</a> and that you have ESP installed on your system so you
|
|
can type along as you go. This tour uses the <em><a href="generator.html">esp</a></em> application
|
|
generator.</p>
|
|
|
|
<a id="blog"></a>
|
|
<a id="create"></a>
|
|
<h2 class="section">Creating a New Application</h2>
|
|
<p>To create a new ESP application, you will use <em>esp</em>, the ESP application generator
|
|
program. Type the following esp command in a command terminal window:</p>
|
|
<pre>
|
|
<b>home></b> esp generate app blog<b>
|
|
[CREATE] Directory: blog
|
|
[CREATE] Directory: blog/cache
|
|
[CREATE] Directory: blog/controllers
|
|
[CREATE] Directory: blog/db
|
|
[CREATE] Directory: blog/layouts
|
|
[CREATE] Directory: blog/static
|
|
[CREATE] Directory: blog/static/images
|
|
[CREATE] Directory: blog/static/js
|
|
[CREATE] Directory: blog/static/themes
|
|
[CREATE] Directory: blog/views
|
|
[CREATE] File: blog/layouts/default.esp
|
|
[CREATE] File: blog/static/images/banner.jpg
|
|
[CREATE] File: blog/static/images/favicon.ico
|
|
[CREATE] File: blog/static/images/splash.jpg
|
|
[CREATE] File: blog/static/index.esp
|
|
[CREATE] File: blog/static/js/jquery.esp.js
|
|
[CREATE] File: blog/static/js/jquery.js
|
|
[CREATE] File: blog/static/js/jquery.tablesorter.js
|
|
[CREATE] File: blog/static/layout.css
|
|
[CREATE] File: blog/static/themes/default.css
|
|
[CREATE] File: blog/appweb.conf
|
|
[CREATE] Database: blog/db/blog.mdb
|
|
[TASK] Complete</b>
|
|
</pre>
|
|
<p>This simple command accomplished quite a bit. It first created a new directory called <b>blog</b> for
|
|
the application, and then created subdirectories for various parts of the application. Initially, some of
|
|
these directories are empty, but they will be used as your application grows.</p>
|
|
<p>The command also created an appweb.conf configuration file to allow you to run appweb for your application.
|
|
The appweb.conf configuration file is the place where you can define your database name, and other
|
|
configuration settings. The ESP web framework follows the <i>"convention over
|
|
configuration"</i> philosophy popularized by <a href="http://www.rubyonrails.org">Ruby on Rails</a>. This
|
|
means that ESP adopts certain conventions about where files and directories should be placed and about
|
|
how names are used. If you work with these conventions, then you need to do little or no configuration.
|
|
Things will just work.</p>
|
|
<p>Here are the most important directories:</p>
|
|
<table title="directories">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>cache</td>
|
|
<td>Cached controller and view modules</td>
|
|
</tr>
|
|
<tr>
|
|
<td>controllers</td>
|
|
<td>Application controller code</td>
|
|
</tr>
|
|
<tr>
|
|
<td>db</td>
|
|
<td>Database file and database initialization scripts</td>
|
|
</tr>
|
|
<tr>
|
|
<td>layouts</td>
|
|
<td>Page layout templates</td>
|
|
</tr>
|
|
<tr>
|
|
<td>static</td>
|
|
<td>Static web pages</td>
|
|
</tr>
|
|
<tr>
|
|
<td>views</td>
|
|
<td>View web pages</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>See the "<a href="generator.html">esp</a>" command documentation for an explanation of the other generated
|
|
directories.</p>
|
|
|
|
<!--
|
|
<p>The purpose of the other directories:</p>
|
|
<table title="directories">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th><th>Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr><td>.tmp</td><td>Temporary files</td></tr>
|
|
<tr><td>bin</td><td>Binary programs and tools</td></tr>
|
|
<tr><td>doc</td><td>Generated documentation for the application</td></tr>
|
|
<tr><td>logs</td><td>Application logs</td></tr>
|
|
<tr><td>messages</td><td>Message catalogues for internationalized applications</td></tr>
|
|
<tr><td>test</td><td>Unit tests</td></tr>
|
|
<tr><td>utils</td><td>Source for utility scripts and programs</td></tr>
|
|
</tbody>
|
|
</table>
|
|
-->
|
|
<a id="run"></a>
|
|
<h2 class="section">Running your Application</h2>
|
|
<p>You can immediately run your application after generation. The <em>esp</em> command will invoke appweb
|
|
to run your application: </p>
|
|
<pre>
|
|
<b>home></b> cd blog
|
|
<b>home/blog></b> esp run
|
|
<b>[RUN] appweb -v
|
|
appweb: 2: Configuration for Embedthis Appweb
|
|
appweb: 2: ---------------------------------------------
|
|
appweb: 2: Host: magnetar.local
|
|
appweb: 2: CPU: x86_64
|
|
appweb: 2: OS: MACOSX
|
|
appweb: 2: Distribution: Apple 10.7.1
|
|
appweb: 2: Version: 4.0.0-B0
|
|
appweb: 2: BuildType: DEBUG
|
|
appweb: 2: ---------------------------------------------
|
|
appweb: 2: Config File /private/tmp/blog/appweb.conf
|
|
appweb: 2: Upload directory: /tmp
|
|
appweb: 2: Set connector "netConnector"
|
|
appweb: 2: Add handler "fileHandler" on host "default" for extensions:
|
|
html git jpeg jpg png pdf ico css js ""
|
|
appweb: 2: Activating module (Loadable) espHandler
|
|
appweb: 2: Add handler "espHandler" on host "default" for extensions: *.esp
|
|
appweb: 2: Add handler "espHandler" on host "default" for route: ""
|
|
appweb: 2: Configured host ":4000" at "."
|
|
appweb: 1: Started HTTP service on "*:4000"
|
|
appweb: 1: HTTP services Started at Wed Oct 05 18:08:45 2013 PDT
|
|
appweb: 1: Starting host named: "127.0.0.1:4000"</b>
|
|
</pre>
|
|
<p>Then enter <em>localhost:4000</em> in your browser. You should see your first application home
|
|
page.</p>
|
|
|
|
<img src="../../../images/esp/tour/home.png" class="screen" alt="home" />
|
|
<a id="hello"></a>
|
|
<h2 class="section">Hello World</h2>
|
|
<p>The next step is to create a simple "Hello World" web page. ESP web pages have an <em>.esp</em>
|
|
extension. Create a file called <em>hello.esp</em> under the <em>static</em> directory with the following
|
|
content:</p>
|
|
<pre>
|
|
<%@ layout ""%>
|
|
<html>
|
|
<body>
|
|
<h1>Hello World</h1>
|
|
</body>
|
|
</pre>
|
|
<p>Don't worry about the layout directive for now, that tells ESP not to use a layout page.</p>
|
|
<p>To view the "Hello" web page, type in the following url:
|
|
<em>http://localhost:4000/static/hello.esp</em> in your browser.</p>
|
|
|
|
<img src="../../../images/esp/tour/hello.png" alt="hello" class="bare-screen" />
|
|
<a id="layouts"></a>
|
|
<h2>Layouts</h2>
|
|
<p>The ESP templating engine can apply a layout page to allow each page so that it inherits its layout and
|
|
look and feel from a master layout page. The ESP layout directive allows you to control what layout
|
|
page (if any) is used. In the previous example, we set the layout page to "" which means —
|
|
"don't use a layout page". If we remove that directive, the page will use the default layout. In this case
|
|
we remove the html and body elements as well as the layout page has been defined with those. The new page
|
|
now has a single line.</p>
|
|
<pre>
|
|
<h1>Hello Bright New World</h1>
|
|
</pre>
|
|
<p>And the web page now looks like this in your browser:</p>
|
|
<img src="../../../images/esp/tour/hello-layout.png" alt="hello" class= "bare-screen" />
|
|
|
|
<a id="dynamic"></a>
|
|
<h2 class="section">Dynamic Content</h2>
|
|
<p>While that was fun, the output is static and boring, so let's add some dynamic content. You can embed
|
|
"C" language code and ESP function calls by including them inside a special ESP web page directive that
|
|
will be executed and converted to HTML before being sent to the client. There are a variety of server-side
|
|
ESP web page directives, the one you'll use first is: <em><%= expression %></em>.</p>
|
|
<p>To add the current date and time, modify the hello.esp web page and add the highlighted line:</p>
|
|
<pre>
|
|
<h2><b>Generated on <%= mprGetDate(0); %></b></h2>
|
|
</pre>
|
|
<p>Now when you re-run the page, it will display the current date and time:</p>
|
|
|
|
<img src="../../../images/esp/tour/hello-dynamic.png" alt="hello" class="bare-screen" />
|
|
<h3>No Restart Require</h3>
|
|
<p>Notice that you did not have to restart the web server, nor did you have to manually recompile the
|
|
application. Rather, ESP transparently recompiled the web page in the background. ESP noticed that the hello.esp
|
|
web page has been modified and it re-parsed and compiled it into a loadable module, ready for
|
|
execution.</p>
|
|
<p>You can also embed more complex ESP into our page, like:</p>
|
|
<pre>
|
|
<h3><% render("Request method is %s", getMethod()); %></h3>
|
|
<%
|
|
int i;
|
|
for (int i = 0; i < 10; i++) {
|
|
render(" Line: %d</br>\r\n", i);
|
|
}
|
|
%>
|
|
</pre>
|
|
<p>By using the ESP statement directive <em><% code %></em>, you can embed arbitrary "C" language
|
|
statements in your web page. The <em>render</em> function allows you to write arbitrary data which is patched
|
|
back where the directive was defined in the page. See the <a href="template.html">Views and Layouts</a>
|
|
document for full details about all the ESP web page directives.</p>
|
|
|
|
<a id="views"></a>
|
|
<a id="scaffolds"></a>
|
|
<h2 class="scaffolds">Scaffolds</h2>
|
|
<p>Scaffolding is a quick way to generate pieces of your application. The <em>esp</em> command can generate
|
|
database tables, views and controllers for you. The command below will create a <em>post</em> database table
|
|
with a blog post title and post comment body. The <em>title</em> is a string data type and the <em>body</em> is a
|
|
multi-line text field.</p>
|
|
<pre>
|
|
<b>home/blog></b> esp generate scaffold post title:string body:text
|
|
<b> [CREATE] /private/tmp/blog/controllers/post.c
|
|
[CREATE] /private/tmp/blog/views/post-list.c
|
|
[CREATE] /private/tmp/blog/views/post-edit.c
|
|
[UPDATE] Database schema
|
|
[TASK] Complete</b>
|
|
</pre>
|
|
<p>This command created a database table called <em>post</em> and a post controller with
|
|
<em>post-list</em> and <em>post-edit</em> views.</p>
|
|
<p>Now if you set your browser to the URI for the post controller, you will see your post listing screen.
|
|
<img src="../../../images/esp/tour/post-list.png" alt="postList" class="bare-screen" />
|
|
|
|
<a id="newPosts"></a></p>
|
|
<h2 class="section">Create New Posts</h2>
|
|
<p>The new post button directs your browser to the <em>/post/init</em> URI. Behind the scenes, Appweb
|
|
parses this URI and and selects the appropriate request route and handler for the request. It
|
|
then identifies <em>post</em> as the name of the controller and <em>init</em> as the name of an action to invoke.
|
|
The controller file <em>controllers/post.c</em> defines the controller action to respond to this
|
|
request.</p>
|
|
<p>The controller file defines functions called actions, that are bound to URIs of the same name. Actions
|
|
are defined using the <em>espDefineAction</em> API in the initialization function of the controller. When
|
|
a request comes for a given action, the corresponding action method is invoked.</p>
|
|
<p>A minimal controller file looks like this:</p>
|
|
<pre>
|
|
#include "esp-app.h"
|
|
static void hello() {
|
|
render("Hello World\n");
|
|
}
|
|
ESP_EXPORT int esp_controller_<b>NAME</b>(EspRoute *eroute, MprModule *module)
|
|
{
|
|
espDefineAction(eroute, "hello", hello);
|
|
return 0;
|
|
}
|
|
</pre>
|
|
<p>Where <em>NAME</em> is the name of the controller.</p>
|
|
<h3>Actions</h3>
|
|
<p>The job of the action is to respond to the request and generate the response via views for the
|
|
client. Here is the <em>create</em> action in the generated <em>post</em> controller.</p>
|
|
<pre>
|
|
static void create() {
|
|
if (writeRec(createRec("post", params()))) {
|
|
inform("New post created");
|
|
redirect("@");
|
|
} else {
|
|
renderView("post-edit");
|
|
}
|
|
}
|
|
</pre>
|
|
<p>The <em>create</em> action above creates a new post record based on the request parameters and then
|
|
uses the <em>views/post-edit.esp</em> view to render a response to the client. ESP <em>edit</em> scaffolds
|
|
handle the work of both <em>edit</em> and <em>create</em> views because they are so similar.</p>
|
|
<p>If an action does not call any of the <em>render</em> methods (as the <em>list</em> action does not),
|
|
ESP will automatically invoke a view of the same name. In the case of the <em>list</em> action, the
|
|
<em>views/post-list.esp</em> will be used to generate the response.</p>
|
|
|
|
<img src= "../../../images/esp/tour/create.png" alt="createPost" class="bare-screen" />
|
|
<p>Click OK to add the new blog post.</p>
|
|
|
|
<a id="homePage"></a>
|
|
<h2>Edit the Home Page</h2>
|
|
<p>You can edit the application's home page to add a link to your post listing page. Change
|
|
<em>static/index.esp</em> to contain just the following:</p>
|
|
<pre>
|
|
<h2><% label("Go to My Blog", "@post/"); %></h2>
|
|
</pre>
|
|
<p>The <em>@post/</em> link means redirect to the <em>post</em> controller if the label is clicked.
|
|
Reload the page and you will see:</p>
|
|
<img src="../../../images/esp/tour/home-link.png" alt="homeLink" class="bare-screen" />
|
|
<h2>Code Errors</h2>
|
|
<p>What happens if you make a mistake entering the embedded "C" code in an ESP page. Say you forgot the
|
|
semicolon in the last example. You will see an error like this in your browser:</p>
|
|
<img src="../../../images/esp/tour/error.png" alt="homeLink" class="screen" />
|
|
<p>You can suppress these errors by setting <em>EspShowErrors</em> to <em>off</em> in the appweb.conf
|
|
configuration file.</p>
|
|
<a id="layout"></a>
|
|
<h2>Changing the Layout</h2>
|
|
<p>You may wish to add some tabs to navigate your blog app. ESP provides a layout
|
|
template engine that is used by all views to provide a common look and feel to your application. View pages
|
|
leverage templates so they don't need to repeat page elements that are common across the application. Edit
|
|
the layout template file <em>layouts/default.esp</em> and change it to use the <em>tabs</em>
|
|
view control.</p>
|
|
<pre>
|
|
<div class="top">
|
|
<h1>Blog Application</h1>
|
|
<b> <% tabs(makeRec("{ \
|
|
'Blog Posts': '~/post', \
|
|
'New Post': '~/post/init', \
|
|
}"), 0); %>
|
|
</b></div>
|
|
</pre>
|
|
<p>This will create two tab buttons to navigate your application.</p>
|
|
<p>After modifying the layout, you will need to re-compile the cached web pages. Normally, ESP
|
|
transparently compiles the web pages whenever you modify a web page. However, if you change a layout,
|
|
you may need to recompile the app. This is easy to do via the <em>esp</em> command.</p>
|
|
<pre>
|
|
esp compile
|
|
</pre>
|
|
<img src="../../../images/esp/tour/tabs.png" alt="tabs" class="bare-screen" />
|
|
|
|
<a id="validations">
|
|
</a>
|
|
<h2 class="section">Validations</h2>
|
|
<p>ESP provides flexible validation methods to help ensure the data you save is correct.</p>
|
|
<p>You can add calls to validate record data before it is saved to the database. To do this, edit the
|
|
<em>controllers/post.c</em> file and add calls to <em>ediAddValidation</em>.</p>
|
|
<pre>
|
|
ESP_EXPORT int esp_controller_post(EspRoute *eroute, MprModule *module)
|
|
{
|
|
<b>Edi *edi;</b>
|
|
/* Existing code */
|
|
<b>edi = getDatabase();
|
|
ediAddValidation(edi, "present", "post", "title", 0);
|
|
ediAddValidation(edi, "present", "post", "body", 0);
|
|
ediAddValidation(edi, "unique", "post", "title", 0);</b>
|
|
return 0;
|
|
}
|
|
</pre>
|
|
<p>This will cause the database to automatically validate that the <em>title</em> and <em>body</em> fields are
|
|
not blank and that the <em>title</em> is unique in the database.</p>
|
|
|
|
<p>If you click OK in the Post <em>edit</em> web page without entering any data
|
|
you will see the following:</p>
|
|
|
|
<img src="../../../images/esp/tour/validate.png" alt="validate" class="screen" />
|
|
<p>This automatically identified the input fields in error and generated a summary of the errors above the
|
|
form. Of course, this default error highlighting behavior can be overridden if desired by modifying the
|
|
application style sheets.<p>
|
|
|
|
<p>Other validation types include: checkNumber, checkBoolean, checkDate and checkFormat.
|
|
You can also define new validation types by calling
|
|
<a href="../../../api/esp.html#group___edi_service_1ga889df64bdd239f71c66b4fa920be8f46">ediDefineValidation</a>.
|
|
<a id="learn"></a>
|
|
<h2 class="section">Learn More ...</h2>
|
|
<p>That concludes the a quick tour through some of the capabilities of the ESP web framework.</p>
|
|
<p>To learn more, please read:
|
|
<ul>
|
|
<li><a href="index.html">ESP Documentation</a></li>
|
|
<li><a href="tour.html">ESP Web Framework Tour</a></li>
|
|
<li><a href="../../../ref/esp/espArchitecture.html">ESP Web Framework Architecture</a></li>
|
|
</ul>
|
|
<p>You may also like to ask questions at the <a href="http://www.ejscript.org/forum/">ESP Support Forum</a>.</p>
|
|
</div>
|
|
</div>
|
|
<!-- BeginDsi "dsi/bottom.html" -->
|
|
<div class="bottom">
|
|
<p class="footnote">
|
|
<a href="../../../product/copyright.html" >© Embedthis Software LLC, 2003-2013.
|
|
All rights reserved. Embedthis, Appweb, ESP, Ejscript and Embedthis GoAhead are trademarks of Embedthis Software LLC.</a>
|
|
</p>
|
|
</div>
|
|
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
|
|
<script type="text/javascript">
|
|
google.load('search', '1', {language : 'en'});
|
|
google.setOnLoadCallback(function() {
|
|
var customSearchControl = new google.search.CustomSearchControl(
|
|
'000262706376373952077:1hs0lhenihk');
|
|
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
|
|
var options = new google.search.DrawOptions();
|
|
options.enableSearchboxOnly("http://appwebserver.org/search.html");
|
|
customSearchControl.draw('cse-search-form', options);
|
|
}, true);
|
|
</script>
|
|
<script type="text/javascript">
|
|
var _gaq = _gaq || [];
|
|
_gaq.push(['_setAccount', 'UA-179169-2']);
|
|
_gaq.push(['_trackPageview']);
|
|
(function() {
|
|
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|