Roo Spring MVC quick-start

Một phần của tài liệu Manning spring roo in action (Trang 162 - 171)

Remember the pizza shop example from chapter 1? The MVC setup was only two lines of Roo commands. In this section, you’ll see how to direct Roo to generate and config- ure an entire web application structure, even the Tomcat and Jetty web servers, in just one command. We’ll review components that Roo creates, such as the controller and view, and explain how to pass model information to the view for rendering. Let’s go!

5.2.1 The web application and first controller

When Roo built your Course Manager application, it just configured it as a jar proj- ect. JAR projects are useful for things like command-line utilities, but they can’t be deployed directly to a web application container such as Tomcat or Jetty. To get Roo to change the project type to a web application and output a war artifact, you need to execute the Spring MVC setup command:

roo> web mvc setup

Roo responds with a ton of output. Here’s a bit of it:

Created SRC_MAIN_JAVA/.../web ...

Managed ROOT/pom.xml ➥

[Added dependency org.springframework:spring-web:${spring.version}]

Managed ROOT/pom.xml ➥

[Added dependency org.springframework:spring-webmvc:${spring.version}]

...

Managed ROOT/pom.xml ...

Managed SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties Managed SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx

Spring beans (business logic) View

Map request

Send model Resolve

and render view

Execute business logic Dispatcher servlet

E t

Spring MVC controller

Figure 5.1 Spring MVC key components

As usual, Roo just did your dirty work for you. It upgraded your project to a fully func­

tional web application, installed Spring MVC, and configured a user interface that now includes a number of features: a menu system, header, footer, localization‚ and a bunch of custom JSP tags to make it easy to build pages and forms.

Roo installs Spring MVC artifacts in the src/main/webapp directory. This directory can contain raw HTML, JavaScript, CSS files, and other static resources. Table 5.1 shows key subdirectories of this root directory and their purpose.

Table 5.1 Key directories in src/main/webapp

File/Directory Description

WEB-INF The web descriptor directory—holds web.xml and other subdirectories.

WEB-INF/spring Contains webmvc-config.xml, which defines the Spring MVC configuration.

WEB-INF/i18n Contains all localized properties files. These files define the values of mes­

sages, labels, form elements‚ and page titles.

WEB-INF/layouts Spring Roo uses Apache Tiles, a layout engine, to render views. The overall Tiles page layouts are defined in this directory.

WEB-INF/tags Spring Roo custom JSPX tag libraries, used by views to render pages, forms, fields, and other elements.

WEB-INF/views Contains the view files, which are comprised of JSPX pages and Apache Tiles view composition files.

If you had to configure all of the installed features yourself, you’d probably spend the better part of a couple of days researching and experimenting, perhaps with some cut­

and-paste operations from other projects and examples on blogs and forum posts.

Instead, Roo gives you a good starting place: a fully configured MVC project.

5.2.2 Creating your first controller

Ultimately you just want Roo to create a controller for you, so to do this you issue the web mvc controller command:

roo> web mvc controller --class ~.web.TestDriveController

You receive output similar to this:

Created SRC_MAIN_JAVA/org/rooinaction/coursemanager/web/➥

TestDriveController.java

Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties Created SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx

Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties Created SRC_MAIN_WEBAPP/WEB-INF/views/testdrive

Created SRC_MAIN_WEBAPP/WEB-INF/views/testdrive/views.xml Created SRC_MAIN_WEBAPP/WEB-INF/views/testdrive/index.jspx Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/menu.tagx Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/item.tagx Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/category.tagx Updated SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx

131 Roo Spring MVC quick-start

Roo builds the TestDriveController class and view artifacts, and even configures an entry on the menu system as well. Let’s take a look at the generated TestDrive- Controller, shown in the following listing.

Listing 5.1 TestDriveController.java

package ...web;

...

@RequestMapping("/testdrive/**")

@Controller

public class TestDriveController {

POST  @RequestMapping(method = RequestMethod.POST,

/testdrive/id value = "{id}")

public void post(@PathVariable Long id, ModelMap modelMap, HttpServletRequest request,

HttpServletResponse response) {

} GET

testdrive/*

@RequestMapping

public String index() { return "testdrive/index";

} }

This controller uses the @RequestMapping annotation, which tells Spring MVC to map any requests with the given pattern to methods within this controller. The classlevel mapping, /testdrive/**, makes sure anything with a URL that begins with /testdrive is handled by this controller. Each method then provides its own request mapping, defining a unique URL subpattern, based on portions of the path, request attributes, request types (POST, GET), and other options.

Two methods are mapped:

 POST on/testdrive/{id} via the post method—The post method defines a further

@RequestMapping with two further refinements: that the method responds to an HTTP POST call, and that the path includes a value after /testdrive/ which is mapped to the variable id. Note the curly-brace matcher syntax. A POST call to / testdrive/234 would be received by this method, and the id variable automati­

cally converted to a Long variable.

 GET on/testdrive/* via the index() method—Because the index() method doesn’t further refine the path, and the default method of @RequestMapping is GET, a simple GET to any path starting with /testdrive will call this method. This method actually functions, returning a view with the path of demo/index, which Spring’s dispatcher servlet then resolves to a file named WEB-INF/views/

testdrive/index.jspx‚ and renders the JSP file.

Controllers wouldn’t be useful without a way to display the data that they place in their models. Let’s take a look at the next component of your web application, the view.

Spring MVC and convention-driven programming

To better understand what’s going on here, you need to know the underlying conven­

tions. Spring MVC is a convention-driven API, which means that it processes methods based on the presence or absence of annotations, parameters‚ and return types in controller method definitions. Here are a few key concepts to keep in mind as you begin to look at some of these methods.

 If you define an HttpServletRequest, HttpServletResponse, HttpSession, ModelMap (map of values to render in the view), an Errors object‚ or a number of other components, they’ll be injected automatically.

 If the method returns a String (as in the index() method above) it will be treated as a view name, and Spring MVC will attempt to resolve it based on the Roo-configured path for all views, /WEB-INF/views.

 As you saw earlier, index and post are all annotated with @RequestMapping, and although the post method currently does nothing, it can respond to POST requests to /testdrive. The index method responds to /testdrive/id, where id is a number. You’ll see why this is important when we discuss Roo scaffolding in section 5.3.

5.2.3 Views, tags, and templates

One of the more complex parts of Spring Roo is the way it configures and manages MVC views. Roo uses an XML-compliant version of Java Server Pages, known as JSPX. These files must be XML-parseable, so that the Roo shell can manipulate them. As you’ll see later, Roo can generate and maintain forms and form fields in your views automatically.

Roo uses the Apache Tiles templating framework to provide layout and a consis­

tent look and feel from view to view, and to provide support for a menuing system, headers‚ and footers for each page. In addition, Roo makes heavy use of its own JSPX custom tags to simplify the view code.

When you installed TestDriveController, Spring Roo generated the testdrive directory in WEB-INF/views. In this directory are two files, index.jspx and views.xml.

Ignore the views.xml file for now. The view for your controller’s index() method is index.jspx, shown next.

Listing 5.2 The testdrive/index.jspx view

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<div xmlns:jsp="http://java.sun.com/JSP/Page"

xmlns:util="urn:jsptagdir:/WEB-INF/tags/util" Install taglibs xmlns:spring="http://www.springframework.org/tags"

version="2.0">

<jsp:directive.page contentType="text/html;charset=UTF-8"/>

133

Store in

${title}

Fetch app name

Roo Spring MVC quick-start

<jsp:output omit-xml-declaration="yes"/>

<spring:message code="label_testdrive_index" htmlEscape="false"

var="title"/>

<util:panel id="title"

title="${title}">

<spring:message code="application_name"

htmlEscape="false" var="app_name"/>

<h3>

<spring:message arguments="${app_name}"

code="welcome_titlepane"/>

</h3>

</util:panel>

</div>

No <? XML ?>

Container element

Print message

This is a pretty compact view file, for several reasons. First Roo installs several tag libraries—the Spring MVC spring: tag library, JSTL tags, and the Roo-specific util:

tag library. Next, because Roo uses Apache Tiles, the bulk of the page structure is hid­

den within a template. You’re viewing only a fragment of the page, known as the tile, that represents the display area for your controller. The other tiles are combined with it to render the title, header, footer, and menu structure that you saw back in chapters 1 and 2.

The page:page tag wraps the page content in a bordered box, complete with a title bar.1 The content is a simple message. However, how it’s computed requires a bit of explanation.

LABELS AND THE MESSAGE TAG

This view makes heavy use of the <spring:message /> tag, which fetches properties from two files, application.properties and messages.properties, located in the webapp directory WEB-INF/i18n. This tag can be used in two ways—first to fetch messages from localized properties files and store them in page variables, such as in this frag­

ment, which stores the value of the property application_name in the local page vari­

able app_name:

<spring:message code="application_name" var="app_name"/>

It can also be used to render output, such as in this fragment, which renders the mes­

sage welcome_titlepane, using the fetched variable above as an argument:

<spring:message arguments="${app_name}" code="welcome_titlepane"/>

The application_name message referred to by the first example is located in the web application’s WEB-INF/i18n directory, in a file named application.properties:

application_name=coursemanager-chapter-05

This is actually a Dojo rich JavaScript component, as are the fields that provide client-side validation and drop- down date fields. You can use Dojo to build your own view with your own hand-selected components. For now, keep in mind that Roo uses rich web interface components like this to give your web application a dynamic look and feel.

1

You may change your application’s friendly name by editing that file. The welcome_titlepane message is located in another file in that directory—messages .properties:

#welcome page

welcome_titlepane=Welcome to {0}

The two files serve slightly different purposes:

messages.properties —This provides the Roo web framework scaffolding page ele­

ment labels, such as button_save, which defines the label for all Save buttons, and field_invalid_integer, which defines the error message to display when a field doesn’t contain a valid integer value. Generally you don’t need to add anything to this file that’s application-specific.

application.properties—This provides your application-specific and navigational framework label values, such as the label to use for each field, or for each ele­

ment in the menu structure. The application_name in this file shows the name of your application in the title bar, and elements such as label_testdrive _index describe the labels to use for menu items that trigger controller invoca­

tions—in this case the TestDriveController.index() method. This file is heavily used by the scaffolding engine that we discuss later in this chapter.

CUSTOMIZING TEXT IN PROPERTIES FILES You may customize the text of gener­

ated labels in application.properties. Roo will not overwrite your entries, and will not touch the ones created even by itself—once an entry is created in this file, it’s available for customization by you from that point forward.

When you’re defining your own labels for nonscaffolded controllers, generally you’ll want to place them in the application.properties file in src/main/resources/META­ INF/spring. You’ll also have to register the filename (without extension) in the p:basenames property of the ReloadableResourceBundleMessageSource in src/

main/webapp/WEB-INF/webmvc-config.xml.

After that, you can use the <spring:message code="your code" /> tag to display your message. You could place messages in application.properties, as well, but since Roo adjusts that file each time it scaffolds, you could have a harder time organizing your properties.

5.2.4 Launching the web application

Now that you’ve created your controller and view, what do they do? Let’s find out by fir­

ing up the server. Issue the following Maven command in your Roo project directory:

mvn package tomcat:run

The package keyword builds your Roo application, as you’ve seen in earlier chap­

ters. The tomcat:run command launches Apache Tomcat on port 8080, and auto­

matically loads your application to a web URI based on the name of your project, in this case /coursemanager.

135 Roo Spring MVC quick-start

PICK YOUR FAVORITE WEB CONTAINER Roo installs both the Apache Tomcat and Jetty web container plug-ins. Choose between Tomcat and Jetty by issuing tomcat:run or jetty:run. See below for details on Jetty.

Browse to http://localhost:8080/coursemanager to view your web application’s default page. Figure 5.2 shows the terribly exciting view.

If you’re a SpringSource Tool Suite user, you can drag the project to a configured server in the Servers pane and install it in Tomcat or SpringSource tc Server automat- ically. If you leave your web server running, STS will automatically redeploy the appli- cation when it recompiles the project.

You can also run Jetty as your web server. In fact, some developers really dig Jetty because it’s so easily customizable, and it’s quite polite: it even tells you your web application name if you hit the root of the server by mistake! To kick off your applica- tion with Jetty, just use

mvn package jetty:run

Figure 5.2 The default view page—terribly exciting!

Running on a different port

Tomcat runs by default on port 8080. You can customize what port the Tomcat web server runs on by modifying the plug-in settings within the pom.xml file. For example, replace the existing plug-in definition with something like this:

<plugin>

<groupId>org.codehaus.mojo</groupId>

<artifactId>tomcat-maven-plugin</artifactId>

...

<configuration>

<port>9090</port>

</configuration>

</plugin>

Review other options for the Tomcat plug-in by visiting the plug-in’s website at http://

mng.bz/IgJ5.

Customizing the Jetty plug-in

Here’s a nice customization for you—Jetty has a setting, scanIntervalSeconds, that will scan for changes to the Maven project, and reload the web application auto­

matically. You can edit the Maven pom.xml file in the root of your project, and change the jetty-maven-plugin to take advantage of this feature:

<groupId>org.mortbay.jetty</groupId>

<artifactId>jetty-maven-plugin</artifactId>

<version>7.4.2.v20110526</version>

<configuration>

<scanIntervalSeconds>5</scanIntervalSeconds>

</configuration>

</plugin>

Now every time you perform an mvn package command, Jetty will automatically reload. There are a ton of other configuration features in jetty-maven-plugin; it’s worth spending an hour reviewing the documentation, at http://mng.bz/1MM6.

5.2.5 Customizing your view

Of course, Roo isn’t psychic. It can’t automatically figure out what you want the TestDriveController to do. It expects you to actually code something in that index() method before it returns the view name. So, let’s start small. What if you wanted to render the current time? You’d have to place the current date and time in the Model, so that you can render it in the view.

To do this, you just add a parameter to the index method, Model map, and then use the addAttribute method of the model to inject the currentDate attribute to the view. Let’s change the index() method in the TestController class to something like this:

@RequestMapping

public String index(Model map) {

map.addAttribute("currentDate", new java.util.Date());

return "testdrive/index";

}

When Spring MVC sees the ModelMap class, it injects it into the method automatically.

In the testdrive/index.jspx view file, you can now reference ${currentDate} and omit the String value of the current date. The lines between <util:panel> and </

util:panel> can be changed to

<h3>

<spring:message arguments="${app_name}" code="welcome_titlepane"/>

</h3>

<p>

It is now ${currentDate} - you should be doing something productive.

</p>

You’ve changed Java code, so restart the server. Figure 5.3 shows the newly customized example, complete with dynamic evaluation from the controller.

137 Roo Spring MVC quick-start

Figure 5.3 index.jspx rendering the time

How does Spring MVC resolve the right view?

When the method returns testdrive/index, Spring MVC delegates to the Tiles view resolving mechanism, passing it a template named testdrive/index. Look in the WEB-INF/views directory for the testdrive subdirectory, and review views.xml:

<definition extends="default" name="testdrive/index">

<put-attribute name="body"

value="/WEB-INF/views/testdrive/index.jspx"/>

</definition>

Roo configures a definition for a tile named testdrive/index. It uses the default layout, and the body tile resolves to testdrive/index.jspx.

5.2.6 Customize that message!

Simply done, eh? But to be a better web developer (cue the music) you should proba­

bly follow the Spring Roo conventions and externalize this message. Add your mes­

sage to the end of the #welcome page section of WEB-INF/i18n/messages.properties, keeping the original welcome_titlepane message:

#welcome page

welcome_titlepane=Welcome to {0}

testdrive_date_message=It is now {0}

and you should be doing something productive.

To use this message in the view, replace the ${currentDate} paragraph fragment with this snippet:

<p>

<spring:message arguments="${currentDate}"

code="testdrive_date_message" />

</p>

Spring replaces the value of {0} in the message with the model attribute, currentDate, and uses some built-in formatting rules to render it properly. More complex objects, including things like a list of query results, can be placed in the model map, which is generally how Spring MVC deals with data that needs to be rendered in a view.

You’ll learn more about messages and locales in chapter 6.

Một phần của tài liệu Manning spring roo in action (Trang 162 - 171)

Tải bản đầy đủ (PDF)

(406 trang)