Table of Contents |
---|
Introduction
In the first part of the Blog tutorial, you will learn:
...
The model should show up in a window that looks like this:
If it didn't show up, the window might have opened behind the main Eclipse window. If that's the case, open the Window menu and select the windows that have Entity Modeler in its name.
...
What we are going to do is to write a simple method that returns the full name of an author, e.g. a method that simply concatenate the first name, a space and the last name of the author. To do so, double-click on Author.java and add the following methods:
Code Block |
---|
public String fullName() {
return this.firstName() + " " + this.lastName();
}
|
Nothing fancy here. Now open BlogEntry.java and add the following method:
Code Block |
---|
@Override
public void awakeFromInsertion(EOEditingContext editingContext) {
super.awakeFromInsertion(editingContext);
NSTimestamp now = new NSTimestamp();
setCreationDate(now);
setLastModified(now);
}
|
...
Remove the pound char in front of those two properties:
Code Block |
---|
#er.migration.migrateAtStartup=true
#er.migration.createTablesIfNecessary=true
|
After removing the pound char, the two properties should look like this:
Code Block |
---|
er.migration.migrateAtStartup=true
er.migration.createTablesIfNecessary=true
|
You are now ready to start the application so that it creates the database! To do so, right-click on Application.java (in the your.app folder) and select Run As -> WOApplication. In Eclipse's Console tab, you should see some output, including something similar to:
Code Block |
---|
BlogRest[62990] INFO er.extensions.migration.ERXMigrator - Upgrading BlogModel to version 0 with migration 'your.app.model.migrations.BlogModel0@4743bf3d'
BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing CREATE TABLE Author(email VARCHAR(100) NOT NULL, firstName VARCHAR(50) NOT NULL, id INTEGER NOT NULL, lastName VARCHAR(50) NOT NULL)
BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing ALTER TABLE Author ADD PRIMARY KEY (id)
BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing CREATE TABLE BlogEntry(authorID INTEGER NOT NULL, content TIMESTAMP NOT NULL, creationDate TIMESTAMP NOT NULL, id INTEGER NOT NULL, title VARCHAR(255) NOT NULL)
BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing ALTER TABLE BlogEntry ADD PRIMARY KEY (id)
BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing ALTER TABLE BlogEntry ADD CONSTRAINT "FOREIGN_KEY_BLOGENTRY_AUTHORID_AUTHOR_ID" FOREIGN KEY (authorID) REFERENCES Author (id)
BlogRest[62990] DEBUG NSLog - evaluateExpression: <er.h2.jdbcadaptor.ERH2PlugIn$H2Expression: "UPDATE _dbupdater SET version = ? WHERE modelname = ?" withBindings: 1:0(version), 2:"BlogModel"(modelName)>
|
...
Add this method in BlogEntryController:
Code Block |
---|
protected ERXKeyFilter filter() {
ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes();
personFilter.setAnonymousUpdateEnabled(true);
ERXKeyFilter filter = ERXKeyFilter.filterWithAttributes();
filter.include(BlogEntry.AUTHOR, personFilter);
filter.setUnknownKeyIgnored(true);
return filter;
}
|
Now, let's implement the createAction method:
Code Block |
---|
public WOActionResults createAction() throws Throwable {
BlogEntry entry = create(filter());
editingContext().saveChanges();
return response(entry, filter());
}
|
...
Last step in the controller: implementing the indexAction method. Again, the code is simple:
Code Block |
---|
public WOActionResults indexAction() throws Throwable {
NSArray<BlogEntry> entries = BlogEntry.fetchAllBlogEntries(editingContext());
return response(entries, filter());
}
|
...
A route in ERRest is simply a way to define the URL for the entities and to specify which controller the route should use. When your controller extends from ERXDefaultRouteController, it's easy to register a controller and a route. In Application.java, in the Application constructor, add the following code:
Code Block |
---|
ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler();
restRequestHandler.addDefaultRoutes(BlogEntry.ENTITY_NAME);
ERXRouteRequestHandler.register(restRequestHandler);
setDefaultRequestHandler(restRequestHandler);
|
...
We are now reading to add and list blog postings! Start the application and take notice of the URL. It should be something like _http://yourip:someport/cgi-bin/WebObjects/BlogRest.woa_
Adding posts and authors with curl
...
The response should look this:
Code Block |
---|
HTTP/1.0 201 Apple WebObjects
Content-Length: 249
x-webobjects-loadaverage: 0
Content-Type: application/json
{"id":1,"type":"BlogEntry","content":"Some text","creationDate":"2011-12-27T21:59:08Z","title":"First post","author":{"id":1,"type":"Author","email":"probert@macti.ca","firstName":"Pascal","lastName":"Robert"}}
|
To get a list of blog entries:
Code Block |
---|
curl -X GET http://192.168.0.102:52406/cgi-bin/WebObjects/BlogRest.woa/ra/blogEntries.json
|
...
Now, let's build a HTML view for blog posts (you don't want your readers to get your posts by JSON, right?). Again, we will use convention to make it work easily. Open up BlogEntryController and add the following method:
Code Block |
---|
@Override
protected boolean isAutomaticHtmlRoutingEnabled() {
return true;
}
|
...
The next step to get it to work is to make BlogEntryIndexPage to implement the er.rest.routes.IERXRouteComponent interface.
Code Block |
---|
import er.rest.routes.IERXRouteComponent;
public class BlogEntryIndexPage extends WOComponent implements IERXRouteComponent {
|
So now, the automatic HTML routing will send the request for ra/blogEntries.html to the BlogEntryIndexPage component. But we don't have any content in this component, so let's make a method to fetch all blog entries per creation date in descending order. So in BlogEntryIndexPage.java, add the following method:
Code Block |
---|
public NSArray<BlogEntry> entries() {
EOEditingContext ec = ERXEC.newEditingContext();
return BlogEntry.fetchAllBlogEntries(ec, BlogEntry.CREATION_DATE.descs());
}
|
We need to use that method in a WORepetition, and for that loop, we need a BlogEntry variable to iterate in the list, so add the following code to BlogEntryIndexPage.java:
Code Block |
---|
private BlogEntry entryItem;
public BlogEntry entryItem() {
return entryItem;
}
public void setEntryItem(BlogEntry entryItem) {
this.entryItem = entryItem;
}
|
The Java part is done, so let's add the loop inside the component. Open BlogEntryIndexPage.wo (it's located in the Component folder) and right after the <body> tag, add:
Code Block |
---|
<wo:loop list="$entries" item="$entryItem">
<p><wo:str value="$entryItem.title" /></p>
<p><wo:str value="$entryItem.author.fullName" /></p>
</wo:loop>
|
...
Open BlogEntryShowPage.java and make sure the class implements er.rest.routes.IERXRouteComponent.
Code Block |
---|
import er.rest.routes.IERXRouteComponent;
public class BlogEntryShowPage extends WOComponent implements IERXRouteComponent {
|
We need to add other methods to receive the BlogEntry object from the controller. In BlogEntryShowPage.java, add:
Code Block |
---|
private BlogEntry blogEntry;
@ERXRouteParameter
public void setBlogEntry(BlogEntry blogEntryFromController) {
this.blogEntry = blogEntryFromController;
}
public BlogEntry blogEntry() {
return this.blogEntry;
}
|
...
The Java part of the work is done, so save the Java class. It's time to work on the component part. Open BlogEntryShowPage.wo and between the <body></body> part, add:
Code Block |
---|
<h1><wo:str value="$blogEntry.title" /></h1>
<p><wo:str value="$blogEntry.content" /></p>
<p>Created on: <wo:str value="$blogEntry.creationDate" dateformat="%Y/%m/%d" /></p>
<p>Added by: <wo:str value="$blogEntry.author.fullName" /></p>
|
Our view component is done, the only thing remaining is a link for the blog entry list (BlogEntryIndexPage) to the view page (BlogEntryShowPage). Save BlogEntryShowPage.wo and open BlogEntryIndexPage.wo. We are going to add a link on the title, you will replace to replace this:
Code Block |
---|
<p><wo:str value="$entryItem.title" /></p>
|
with:
Code Block |
---|
<p><wo:ERXRouteLink entityName="BlogEntry" record="$entryItem" action="show"><wo:str value="$entryItem.title" /></wo:ERXRouteLink></p>
|
...