Changes for page Your First Rest Project
Last modified by Steve Peery on 2013/09/06 11:02
From version 27.1
edited by Filippo Laurìa
on 2013/07/22 12:51
on 2013/07/22 12:51
Change comment:
There is no comment for this version
Summary
-
Page properties (2 modified, 0 added, 0 removed)
Details
- Page properties
-
- Author
-
... ... @@ -1,1 +1,1 @@ 1 -XWiki. filippolauria1 +XWiki.skcodes - Content
-
... ... @@ -1,5 +3,3 @@ 1 - 2 - 3 3 {{toc/}} 4 4 5 5 = Introduction = ... ... @@ -122,8 +122,6 @@ 122 122 123 123 The model should show up in a window that looks like this: 124 124 125 -[[image:attach:EOModeler.png]] 126 - 127 127 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. 128 128 129 129 In the Entity Modeler window, click on **Default**, and for the **URL** field, type ... ... @@ -185,12 +185,8 @@ 185 185 186 186 If you did everything well, the list of attributes should look like this: 187 187 188 -[[image:attach:list_wlock.png]] 189 - 190 190 You will notice that the attributes have a column with a lock in it. When a lock is present, it will use the value of that attribute for //UPDATE ... WHERE attribute = ''// statement. This is to do optimistic locking, aka to prevent data conflict when the data object was modified by two different users. Using timestamps for optimistic locking is not a good idea because for certain RDBMS, the value can be different because of milliseconds, so remove the locks on the **creationDate** attribute. The final list should look like this: 191 191 192 -[[image:attach:list.png]] 193 - 194 194 Next step is to create the **Author** entity. Create a new entity with **Author** at its name (and also as the table name), and for the class name, use **your.app.model.Author**. The attributes for this entity are: 195 195 196 196 |=((( ... ... @@ -224,12 +224,8 @@ 224 224 225 225 Final list of attributes should look like this: 226 226 227 -[[image:attach:author_list.png]] 228 - 229 229 Now, it's time to link the two entities together. An Author can have multiple blog entries, and a BlogEntry can only have one author. To create the relationship (the join), right-click on **Author** and select **New Relationship**. On your right, select **BlogEntry** in the list. On your left, select **to many BlogEntries**, and on your right, select **to one Author**. Now, in BlogEntry, we need to store the primary key of the author so that we can make the join. The relationship builder allow us to add that attribute, so make sure **and a new foreign key named** is checked (it is checked by default). The **Create Relationship** pane should look like this: 230 230 231 -[[image:attach:relationship.png]] 232 - 233 233 If you check in the **Outline** tab, you should see that **Author** now have a **blogEntries** relationship, and **BlogEntry** have a **author** relationship. 234 234 235 235 You are now ready to save the model. Save it (File -> Save) and close the **Entity Modeler** window. If you open the **Sources** in the main Eclipse window, you will notice that the **Sources** folder contains a package named **your.app.model**. (If this folder doesn't appear, you may need to set your preferences to automatically generate these source files; see the second suggestion on [[http:~~/~~/wiki.wocommunity.org/display/documentation/Useful+Eclipse+or+WOLips+Preferences>>url:http://wiki.wocommunity.org/display/documentation/Useful+Eclipse+or+WOLips+Preferences||rel="nofollow" shape="rect" class="external-link"]].) ... ... @@ -239,6 +239,7 @@ 239 239 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: 240 240 241 241 {{code}} 230 + 242 242 public String fullName() { 243 243 return this.firstName() + " " + this.lastName(); 244 244 } ... ... @@ -248,6 +248,7 @@ 248 248 Nothing fancy here. Now open **BlogEntry.java** and add the following method: 249 249 250 250 {{code}} 240 + 251 251 @Override 252 252 public void awakeFromInsertion(EOEditingContext editingContext) { 253 253 super.awakeFromInsertion(editingContext); ... ... @@ -277,6 +277,7 @@ 277 277 Remove the pound char in front of those two properties: 278 278 279 279 {{code}} 270 + 280 280 #er.migration.migrateAtStartup=true 281 281 #er.migration.createTablesIfNecessary=true 282 282 ... ... @@ -285,6 +285,7 @@ 285 285 After removing the pound char, the two properties should look like this: 286 286 287 287 {{code}} 279 + 288 288 er.migration.migrateAtStartup=true 289 289 er.migration.createTablesIfNecessary=true 290 290 ... ... @@ -293,6 +293,7 @@ 293 293 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: 294 294 295 295 {{code}} 288 + 296 296 BlogRest[62990] INFO er.extensions.migration.ERXMigrator - Upgrading BlogModel to version 0 with migration 'your.app.model.migrations.BlogModel0@4743bf3d' 297 297 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) 298 298 BlogRest[62990] INFO er.extensions.jdbc.ERXJDBCUtilities - Executing ALTER TABLE Author ADD PRIMARY KEY (id) ... ... @@ -348,6 +348,7 @@ 348 348 Add this method in **BlogEntryController**: 349 349 350 350 {{code}} 344 + 351 351 protected ERXKeyFilter filter() { 352 352 ERXKeyFilter personFilter = ERXKeyFilter.filterWithAttributes(); 353 353 personFilter.setAnonymousUpdateEnabled(true); ... ... @@ -364,6 +364,7 @@ 364 364 Now, let's implement the **createAction** method: 365 365 366 366 {{code}} 361 + 367 367 public WOActionResults createAction() throws Throwable { 368 368 BlogEntry entry = create(filter()); 369 369 editingContext().saveChanges(); ... ... @@ -377,6 +377,7 @@ 377 377 Last step in the controller: implementing the **indexAction** method. Again, the code is simple: 378 378 379 379 {{code}} 375 + 380 380 public WOActionResults indexAction() throws Throwable { 381 381 NSArray<BlogEntry> entries = BlogEntry.fetchAllBlogEntries(editingContext()); 382 382 return response(entries, filter()); ... ... @@ -393,6 +393,7 @@ 393 393 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: 394 394 395 395 {{code}} 392 + 396 396 ERXRouteRequestHandler restRequestHandler = new ERXRouteRequestHandler(); 397 397 restRequestHandler.addDefaultRoutes(BlogEntry.ENTITY_NAME); 398 398 ERXRouteRequestHandler.register(restRequestHandler); ... ... @@ -402,7 +402,7 @@ 402 402 403 403 The **addDefaultRoutes** method do all of the required magic, and use convention. That's why we had to name the controller **BlogEntryController**, because the convention is <EntityName>Controller. 404 404 405 -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_>>url:http://youripsomeport||shape="rect"]] 402 +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_>>url:http://yourip:someport/cgi-bin/WebObjects/BlogRest.woa_||shape="rect"]] 406 406 407 407 == Adding posts and authors with curl == 408 408 ... ... @@ -417,6 +417,7 @@ 417 417 The response should look this: 418 418 419 419 {{code}} 417 + 420 420 HTTP/1.0 201 Apple WebObjects 421 421 Content-Length: 249 422 422 x-webobjects-loadaverage: 0 ... ... @@ -429,6 +429,7 @@ 429 429 To get a list of blog entries: 430 430 431 431 {{code}} 430 + 432 432 curl -X GET http://192.168.0.102:52406/cgi-bin/WebObjects/BlogRest.woa/ra/blogEntries.json 433 433 434 434 {{/code}} ... ... @@ -440,6 +440,7 @@ 440 440 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: 441 441 442 442 {{code}} 442 + 443 443 @Override 444 444 protected boolean isAutomaticHtmlRoutingEnabled() { 445 445 return true; ... ... @@ -452,6 +452,7 @@ 452 452 The next step to get it to work is to make **BlogEntryIndexPage** to implement the **er.rest.routes.IERXRouteComponent** interface. 453 453 454 454 {{code}} 455 + 455 455 import er.rest.routes.IERXRouteComponent; 456 456 457 457 public class BlogEntryIndexPage extends WOComponent implements IERXRouteComponent { ... ... @@ -461,6 +461,7 @@ 461 461 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: 462 462 463 463 {{code}} 465 + 464 464 public NSArray<BlogEntry> entries() { 465 465 EOEditingContext ec = ERXEC.newEditingContext(); 466 466 return BlogEntry.fetchAllBlogEntries(ec, BlogEntry.CREATION_DATE.descs()); ... ... @@ -471,6 +471,7 @@ 471 471 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**: 472 472 473 473 {{code}} 476 + 474 474 private BlogEntry entryItem; 475 475 476 476 public BlogEntry entryItem() { ... ... @@ -486,6 +486,7 @@ 486 486 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: 487 487 488 488 {{code}} 492 + 489 489 <wo:loop list="$entries" item="$entryItem"> 490 490 <p><wo:str value="$entryItem.title" /></p> 491 491 <p><wo:str value="$entryItem.author.fullName" /></p> ... ... @@ -502,6 +502,7 @@ 502 502 Open **BlogEntryShowPage.java** and make sure the class implements **er.rest.routes.IERXRouteComponent**. 503 503 504 504 {{code}} 509 + 505 505 import er.rest.routes.IERXRouteComponent; 506 506 507 507 public class BlogEntryShowPage extends WOComponent implements IERXRouteComponent { ... ... @@ -511,6 +511,7 @@ 511 511 We need to add other methods to receive the BlogEntry object from the controller. In **BlogEntryShowPage.java**, add: 512 512 513 513 {{code}} 519 + 514 514 private BlogEntry blogEntry; 515 515 516 516 @ERXRouteParameter ... ... @@ -529,6 +529,7 @@ 529 529 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: 530 530 531 531 {{code}} 538 + 532 532 <h1><wo:str value="$blogEntry.title" /></h1> 533 533 <p><wo:str value="$blogEntry.content" /></p> 534 534 <p>Created on: <wo:str value="$blogEntry.creationDate" dateformat="%Y/%m/%d" /></p> ... ... @@ -539,6 +539,7 @@ 539 539 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: 540 540 541 541 {{code}} 549 + 542 542 <p><wo:str value="$entryItem.title" /></p> 543 543 544 544 {{/code}} ... ... @@ -546,6 +546,7 @@ 546 546 with: 547 547 548 548 {{code}} 557 + 549 549 <p><wo:ERXRouteLink entityName="BlogEntry" record="$entryItem" action="show"><wo:str value="$entryItem.title" /></wo:ERXRouteLink></p> 550 550 551 551 {{/code}}