view.xml 110.5 KB
Newer Older
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
<chapter id="view">
  <title>View technologies</title>

  <section id="view-introduction">
    <title>Introduction</title>

    <para>One of the areas in which Spring excels is in the separation of view
    technologies from the rest of the MVC framework. For example, deciding to
    use Velocity or XSLT in place of an existing JSP is primarily a matter of
    configuration. This chapter covers the major view technologies that work
    with Spring and touches briefly on how to add new ones. This chapter
    assumes you are already familiar with <xref linkend="mvc-viewresolver" />
    which covers the basics of how views in general are coupled to the MVC
    framework.</para>
  </section>

  <section id="view-jsp">
    <title>JSP &amp; JSTL</title>

    <para>Spring provides a couple of out-of-the-box solutions for JSP and
    JSTL views. Using JSP or JSTL is done using a normal view resolver defined
    in the <interfacename>WebApplicationContext</interfacename>. Furthermore,
26 27
    of course you need to write some JSPs that will actually render the
    view.</para>
28 29 30 31 32 33 34 35

    <section id="view-jsp-resolver">
      <title>View resolvers</title>

      <para>Just as with any other view technology you're integrating with
      Spring, for JSPs you'll need a view resolver that will resolve your
      views. The most commonly used view resolvers when developing with JSPs
      are the <classname>InternalResourceViewResolver</classname> and the
36 37
      <classname>ResourceBundleViewResolver</classname>. Both are declared in
      the <interfacename>WebApplicationContext</interfacename>:</para>
38

39 40 41 42
      <programlisting language="xml"><lineannotation>&lt;!-- the <classname>ResourceBundleViewResolver</classname> --&gt;</lineannotation>
&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"&gt;
  &lt;property name="basename" value="views"/&gt;
&lt;/bean&gt;
43

44
<lineannotation># And a sample properties file is uses (views.properties in WEB-INF/classes):</lineannotation>
45 46 47 48
welcome.class=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp

productList.class=org.springframework.web.servlet.view.JstlView
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
productList.url=/WEB-INF/jsp/productlist.jsp</programlisting>

      <para>As you can see, the
      <classname>ResourceBundleViewResolver</classname> needs a properties
      file defining the view names mapped to 1) a class and 2) a URL. With a
      <classname>ResourceBundleViewResolver</classname> you can mix different
      types of views using only one resolver.</para>

      <programlisting language="xml">&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
  &lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
  &lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
  &lt;property name="suffix" value=".jsp"/&gt;
&lt;/bean&gt;</programlisting>

      <para>The <classname>InternalResourceBundleViewResolver</classname> can
      be configured for using JSPs as described above. As a best practice, we
      strongly encourage placing your JSP files in a directory under the
      <filename class="directory">'WEB-INF'</filename> directory, so there can
      be no direct access by clients.</para>
68 69 70 71 72
    </section>

    <section id="view-jsp-jstl">
      <title>'Plain-old' JSPs versus JSTL</title>

73 74 75
      <para>When using the Java Standard Tag Library you must use a special
      view class, the <classname>JstlView</classname>, as JSTL needs some
      preparation before things such as the i18N features will work.</para>
76 77 78 79 80 81 82 83 84 85 86 87
    </section>

    <section id="view-jsp-tags">
      <title>Additional tags facilitating development</title>

      <para>Spring provides data binding of request parameters to command
      objects as described in earlier chapters. To facilitate the development
      of JSP pages in combination with those data binding features, Spring
      provides a few tags that make things even easier. All Spring tags have
      <emphasis>HTML escaping</emphasis> features to enable or disable
      escaping of characters.</para>

88 89 90 91
      <para>The tag library descriptor (TLD) is included in the <filename
      class="libraryfile">spring.jar</filename> as well in the distribution
      itself. Further information about the individual tags can be found in
      the appendix entitled <xref linkend="spring.tld" />.</para>
92 93 94 95 96 97 98 99
    </section>

    <section id="view-jsp-formtaglib">
      <title>Using Spring's form tag library</title>

      <para>As of version 2.0, Spring provides a comprehensive set of data
      binding-aware tags for handling form elements when using JSP and Spring
      Web MVC. Each tag provides support for the set of attributes of its
100 101 102
      corresponding HTML tag counterpart, making the tags familiar and
      intuitive to use. The tag-generated HTML is HTML 4.01/XHTML 1.0
      compliant.</para>
103

104 105
      <para>Unlike other form/input tag libraries, Spring's form tag library
      is integrated with Spring Web MVC, giving the tags access to the command
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
      object and reference data your controller deals with. As you will see in
      the following examples, the form tags make JSPs easier to develop, read
      and maintain.</para>

      <para>Let's go through the form tags and look at an example of how each
      tag is used. We have included generated HTML snippets where certain tags
      require further commentary.</para>

      <section id="view-jsp-formtaglib-configuration">
        <title>Configuration</title>

        <para>The form tag library comes bundled in
        <literal>spring.jar</literal>. The library descriptor is called
        <literal>spring-form.tld</literal>.</para>

121 122
        <para>To use the tags from this library, add the following directive
        to the top of your JSP page:</para>
123

124
        <programlisting language="xml">&lt;%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %&gt;</programlisting>
125

126 127
        <para>... where <literal>form</literal> is the tag name prefix you
        want to use for the tags from this library.</para>
128 129 130 131 132
      </section>

      <section id="view-jsp-formtaglib-formtag">
        <title>The <literal>form</literal> tag</title>

133 134
        <para>This tag renders an HTML 'form' tag and exposes a binding path
        to inner tags for binding. It puts the command object in the
135
        <literal>PageContext</literal> so that the command object can be
136 137
        accessed by inner tags. <emphasis>All the other tags in this library
        are nested tags of the <literal>form</literal> tag</emphasis>.</para>
138 139 140 141 142 143 144 145

        <para>Let's assume we have a domain object called
        <classname>User</classname>. It is a JavaBean with properties such as
        <literal>firstName</literal> and <literal>lastName</literal>. We will
        use it as the form backing object of our form controller which returns
        <literal>form.jsp</literal>. Below is an example of what
        <literal>form.jsp</literal> would look like:</para>

146
        <programlisting language="xml">&lt;form:form&gt;
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="firstName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="lastName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="2"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>

        <para>The <literal>firstName</literal> and <literal>lastName</literal>
        values are retrieved from the command object placed in the
166 167 168
        <interfacename>PageContext</interfacename> by the page controller.
        Keep reading to see more complex examples of how inner tags are used
        with the <literal>form</literal> tag.</para>
169 170 171

        <para>The generated HTML looks like a standard form:</para>

172
        <programlisting language="xml">&lt;form method="POST"&gt;
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
      &lt;table&gt;
        &lt;tr&gt;
            &lt;td&gt;First Name:&lt;/td&gt;
            &lt;td&gt;&lt;input name="firstName" type="text" value="Harry"/&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Last Name:&lt;/td&gt;
            &lt;td&gt;&lt;input name="lastName" type="text" value="Potter"/&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td colspan="2"&gt;
              &lt;input type="submit" value="Save Changes" /&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form&gt;</programlisting>

        <para>The preceding JSP assumes that the variable name of the form
191 192 193
        backing object is <literal>'command'</literal>. If you have put the
        form backing object into the model under another name (definitely a
        best practice), then you can bind the form to the named variable like
194 195
        so:</para>

196 197
        <programlisting language="xml">&lt;form:form <lineannotation><emphasis
              role="bold">commandName="user"</emphasis></lineannotation>&gt;
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="firstName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="lastName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="2"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-inputtag">
        <title>The <literal>input</literal> tag</title>

        <para>This tag renders an HTML 'input' tag with type 'text' using the
        bound value. For an example of this tag, see <xref
        linkend="view-jsp-formtaglib-formtag" />.</para>
      </section>

      <section id="view-jsp-formtaglib-checkboxtag">
        <title>The <literal>checkbox</literal> tag</title>

227 228
        <para>This tag renders an HTML 'input' tag with type
        'checkbox'.</para>
229

230 231 232
        <para>Let's assume our <classname>User</classname> has preferences
        such as newsletter subscription and a list of hobbies. Below is an
        example of the <classname>Preferences</classname> class:</para>
233 234
      </section>

235
      <programlisting language="java">public class Preferences {
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

      private boolean receiveNewsletter;

      private String[] interests;

      private String favouriteWord;

      public boolean isReceiveNewsletter() {
          return receiveNewsletter;
      }

      public void setReceiveNewsletter(boolean receiveNewsletter) {
          this.receiveNewsletter = receiveNewsletter;
      }

      public String[] getInterests() {
          return interests;
      }

      public void setInterests(String[] interests) {
          this.interests = interests;
      }

      public String getFavouriteWord() {
          return favouriteWord;
      }

      public void setFavouriteWord(String favouriteWord) {
          this.favouriteWord = favouriteWord;
      }
  }</programlisting>

      <para>The <literal>form.jsp</literal> would look like:</para>

270
      <programlisting language="xml">&lt;form:form&gt;
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;Subscribe to newsletter?:&lt;/td&gt;
              <lineannotation>&lt;%-- Approach 1: Property is of type <classname>java.lang.Boolean</classname> --%&gt;</lineannotation>
              &lt;td&gt;&lt;form:checkbox path="preferences.receiveNewsletter"/&gt;&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr&gt;
              &lt;td&gt;Interests:&lt;/td&gt;
              &lt;td&gt;
                  <lineannotation>&lt;%-- Approach 2: Property is of an array or of type <interfacename>java.util.Collection</interfacename> --%&gt;</lineannotation>
                  Quidditch: &lt;form:checkbox path="preferences.interests" value="Quidditch"/&gt;
                  Herbology: &lt;form:checkbox path="preferences.interests" value="Herbology"/&gt;
                  Defence Against the Dark Arts: &lt;form:checkbox path="preferences.interests"
                      value="Defence Against the Dark Arts"/&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Favourite Word:&lt;/td&gt;
              &lt;td&gt;
                  <lineannotation>&lt;%-- Approach 3: Property is of type <classname>java.lang.Object</classname> --%&gt;</lineannotation>
                  Magic: &lt;form:checkbox path="preferences.favouriteWord" value="Magic"/&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>

298 299
      <para>There are 3 approaches to the <literal>checkbox</literal> tag
      which should meet all your checkbox needs. <itemizedlist>
300 301 302 303
          <listitem>
            <para>Approach One - When the bound value is of type
            <literal>java.lang.Boolean</literal>, the
            <literal>input(checkbox)</literal> is marked as 'checked' if the
304 305 306 307
            bound value is <literal>true</literal>. The
            <literal>value</literal> attribute corresponds to the resolved
            value of the <literal>setValue(Object)</literal> value
            property.</para>
308 309 310 311 312 313 314 315 316 317 318 319 320 321
          </listitem>

          <listitem>
            <para>Approach Two - When the bound value is of type
            <literal>array</literal> or
            <interfacename>java.util.Collection</interfacename>, the
            <literal>input(checkbox)</literal> is marked as 'checked' if the
            configured <literal>setValue(Object)</literal> value is present in
            the bound <interfacename>Collection</interfacename>.</para>
          </listitem>

          <listitem>
            <para>Approach Three - For any other bound value type, the
            <literal>input(checkbox)</literal> is marked as 'checked' if the
322 323
            configured <literal>setValue(Object)</literal> is equal to the
            bound value.</para>
324 325 326 327 328 329
          </listitem>
        </itemizedlist></para>

      <para>Note that regardless of the approach, the same HTML structure is
      generated. Below is an HTML snippet of some checkboxes:</para>

330
      <programlisting language="xml">&lt;tr&gt;
331 332 333 334 335 336 337 338 339 340 341 342 343 344
      &lt;td&gt;Interests:&lt;/td&gt;
      &lt;td&gt;
          Quidditch: &lt;input name="preferences.interests" type="checkbox" value="Quidditch"/&gt;
          &lt;input type="hidden" value="1" name="_preferences.interests"/&gt;
          Herbology: &lt;input name="preferences.interests" type="checkbox" value="Herbology"/&gt;
          &lt;input type="hidden" value="1" name="_preferences.interests"/&gt;
          Defence Against the Dark Arts: &lt;input name="preferences.interests" type="checkbox"
              value="Defence Against the Dark Arts"/&gt;
          &lt;input type="hidden" value="1" name="_preferences.interests"/&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>

      <para>What you might not expect to see is the additional hidden field
      after each checkbox. When a checkbox in an HTML page is
345 346 347 348 349 350 351 352 353 354
      <emphasis>not</emphasis> checked, its value will not be sent to the
      server as part of the HTTP request parameters once the form is
      submitted, so we need a workaround for this quirk in HTML in order for
      Spring form data binding to work. The <literal>checkbox</literal> tag
      follows the existing Spring convention of including a hidden parameter
      prefixed by an underscore ("_") for each checkbox. By doing this, you
      are effectively telling Spring that <quote>
          <emphasis>the checkbox was visible in the form and I want my object
          to which the form data will be bound to reflect the state of the
          checkbox no matter what</emphasis>
355 356 357 358 359 360 361 362 363
        </quote>.</para>

      <section id="view-jsp-formtaglib-checkboxestag">
        <title>The <literal>checkboxes</literal> tag</title>

        <para>This tag renders multiple HTML 'input' tags with type
        'checkbox'.</para>

        <para>Building on the example from the previous
364 365 366 367 368 369 370 371 372 373
        <classname>checkbox</classname> tag section. Sometimes you prefer not
        to have to list all the possible hobbies in your JSP page. You would
        rather provide a list at runtime of the available options and pass
        that in to the tag. That is the purpose of the
        <classname>checkboxes</classname> tag. You pass in an
        <classname>Array</classname>, a <classname>List</classname> or a
        <classname>Map</classname> containing the available options in the
        "items" property. Typically the bound property is a collection so it
        can hold multiple values selected by the user. Below is an example of
        the JSP using this tag:</para>
374 375
      </section>

376
      <programlisting language="xml">&lt;form:form&gt;
377 378 379 380 381 382 383 384 385 386 387 388 389 390
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;Interests:&lt;/td&gt;
              &lt;td&gt;
                  <lineannotation>&lt;%-- Property is of an array or of type <interfacename>java.util.Collection</interfacename> --%&gt;</lineannotation>
                  &lt;form:checkboxes path="preferences.interests" items="${interestList}"/&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>

      <para>This example assumes that the "interestList" is a
      <classname>List</classname> available as a model attribute containing
      strings of the values to be selected from. In the case where you use a
391 392 393 394
      Map, the map entry key will be used as the value and the map entry's
      value will be used as the label to be displayed. You can also use a
      custom object where you can provide the property names for the value
      using "itemValue" and the label using "itemLabel".</para>
395 396 397 398 399 400

      <section id="view-jsp-formtaglib-radiobuttontag">
        <title>The <literal>radiobutton</literal> tag</title>

        <para>This tag renders an HTML 'input' tag with type 'radio'.</para>

401 402
        <para>A typical usage pattern will involve multiple tag instances
        bound to the same property but with different values.</para>
403

404
        <programlisting language="xml">&lt;tr&gt;
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
      &lt;td&gt;Sex:&lt;/td&gt;
      &lt;td&gt;Male: &lt;form:radiobutton path="sex" value="M"/&gt; &lt;br/&gt;
          Female: &lt;form:radiobutton path="sex" value="F"/&gt; &lt;/td&gt;
  &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-radiobuttonstag">
        <title>The <literal>radiobuttons</literal> tag</title>

        <para>This tag renders multiple HTML 'input' tags with type
        'radio'.</para>

        <para>Just like the <classname>checkboxes</classname> tag above, you
        might want to pass in the available options as a runtime variable. For
        this usage you would use the <classname>radiobuttons</classname> tag.
        You pass in an <classname>Array</classname>, a
        <classname>List</classname> or a <classname>Map</classname> containing
422 423 424 425 426
        the available options in the "items" property. In the case where you
        use a Map, the map entry key will be used as the value and the map
        entry's value will be used as the label to be displayed. You can also
        use a custom object where you can provide the property names for the
        value using "itemValue" and the label using "itemLabel".</para>
427

428
        <programlisting language="xml">&lt;tr&gt;
429 430 431 432 433 434 435 436 437 438 439
      &lt;td&gt;Sex:&lt;/td&gt;
      &lt;td&gt;&lt;form:radiobuttons path="sex" items="${sexOptions}"/&gt;&lt;/td&gt;
  &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-passwordtag">
        <title>The <literal>password</literal> tag</title>

        <para>This tag renders an HTML 'input' tag with type 'password' using
        the bound value.</para>

440
        <programlisting language="xml">&lt;tr&gt;
441 442 443 444 445 446 447
      &lt;td&gt;Password:&lt;/td&gt;
      &lt;td&gt;
          &lt;form:password path="password" /&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>

        <para>Please note that by default, the password value is
448 449
        <emphasis>not</emphasis> shown. If you do want the password value to
        be shown, then set the value of the <literal>'showPassword'</literal>
450 451
        attribute to true, like so.</para>

452
        <programlisting language="xml">&lt;tr&gt;
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
      &lt;td&gt;Password:&lt;/td&gt;
      &lt;td&gt;
          &lt;form:password path="password" value="^76525bvHGq" showPassword="true" /&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-selecttag">
        <title>The <literal>select</literal> tag</title>

        <para>This tag renders an HTML 'select' element. It supports data
        binding to the selected option as well as the use of nested
        <literal>option</literal> and <literal>options</literal> tags.</para>

        <para>Let's assume a <classname>User</classname> has a list of
        skills.</para>

470
        <programlisting language="xml">&lt;tr&gt;
471 472 473 474
      &lt;td&gt;Skills:&lt;/td&gt;
      &lt;td&gt;&lt;form:select path="skills" items="${skills}"/&gt;&lt;/td&gt;
  &lt;/tr&gt;</programlisting>

475 476
        <para>If the <literal>User's</literal> skill were in Herbology, the
        HTML source of the 'Skills' row would look like:</para>
477

478
        <programlisting language="xml">&lt;tr&gt;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
      &lt;td&gt;Skills:&lt;/td&gt;
      &lt;td&gt;&lt;select name="skills" multiple="true"&gt;
          &lt;option value="Potions"&gt;Potions&lt;/option&gt;
          &lt;option value="Herbology" selected="selected"&gt;Herbology&lt;/option&gt;
          &lt;option value="Quidditch"&gt;Quidditch&lt;/option&gt;&lt;/select&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-optiontag">
        <title>The <literal>option</literal> tag</title>

        <para>This tag renders an HTML 'option'. It sets 'selected' as
        appropriate based on the bound value.</para>

494
        <programlisting language="xml">&lt;tr&gt;
495 496 497 498 499 500 501 502 503 504 505
      &lt;td&gt;House:&lt;/td&gt;
      &lt;td&gt;
          &lt;form:select path="house"&gt;
              &lt;form:option value="Gryffindor"/&gt;
              &lt;form:option value="Hufflepuff"/&gt;
              &lt;form:option value="Ravenclaw"/&gt;
              &lt;form:option value="Slytherin"/&gt;
          &lt;/form:select&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>

506 507
        <para>If the <literal>User's</literal> house was in Gryffindor, the
        HTML source of the 'House' row would look like:</para>
508

509
        <programlisting language="xml">&lt;tr&gt;
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
      &lt;td&gt;House:&lt;/td&gt;
      &lt;td&gt;
          &lt;select name="house"&gt;
              &lt;option value="Gryffindor" selected="selected"&gt;Gryffindor&lt;/option&gt;
              &lt;option value="Hufflepuff"&gt;Hufflepuff&lt;/option&gt;
              &lt;option value="Ravenclaw"&gt;Ravenclaw&lt;/option&gt;
              &lt;option value="Slytherin"&gt;Slytherin&lt;/option&gt;
          &lt;/select&gt;
      &lt;/td&gt;
   &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-optionstag">
        <title>The <literal>options</literal> tag</title>

        <para>This tag renders a list of HTML 'option' tags. It sets the
        'selected' attribute as appropriate based on the bound value.</para>

528
        <programlisting language="xml">&lt;tr&gt;
529 530 531 532 533 534 535 536 537 538 539 540
      &lt;td&gt;Country:&lt;/td&gt;
      &lt;td&gt;
          &lt;form:select path="country"&gt;
              &lt;form:option value="-" label="--Please Select"/&gt;
              &lt;form:options items="${countryList}" itemValue="code" itemLabel="name"/&gt;
          &lt;/form:select&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>

        <para>If the <classname>User</classname> lived in the UK, the HTML
        source of the 'Country' row would look like:</para>

541
        <programlisting language="xml">&lt;tr&gt;
542 543 544 545 546 547 548 549 550 551 552 553 554
      &lt;td&gt;Country:&lt;/td&gt;
      &lt;td&gt;
          &lt;select name="country"&gt;
              &lt;option value="-"&gt;--Please Select&lt;/option&gt;
              &lt;option value="AT"&gt;Austria&lt;/option&gt;
              &lt;option value="UK" selected="selected"&gt;United Kingdom&lt;/option&gt;
              &lt;option value="US"&gt;United States&lt;/option&gt;
          &lt;/select&gt;
      &lt;/td&gt;
  &lt;/tr&gt;</programlisting>

        <para>As the example shows, the combined usage of an
        <literal>option</literal> tag with the <literal>options</literal> tag
555 556 557 558 559 560 561 562 563 564 565 566
        generates the same standard HTML, but allows you to explicitly specify
        a value in the JSP that is for display only (where it belongs) such as
        the default string in the example: "-- Please Select".</para>

        <para>The <literal>items</literal> attribute is typically populated
        with a collection or array of item objects.
        <literal>itemValue</literal> and <literal>itemLabel</literal> simply
        refer to bean properties of those item objects, if specified;
        otherwise, the item objects themselves will be stringified.
        Alternatively, you may specify a <literal>Map</literal> of items, in
        which case the map keys are interpreted as option values and the map
        values correspond to option labels. If <literal>itemValue</literal>
567 568 569 570 571 572 573 574 575 576
        and/or <literal>itemLabel</literal> happen to be specified as well,
        the item value property will apply to the map key and the item label
        property will apply to the map value.</para>
      </section>

      <section id="view-jsp-formtaglib-textAreatag">
        <title>The <literal>textarea</literal> tag</title>

        <para>This tag renders an HTML 'textarea'.</para>

577
        <programlisting language="xml">&lt;tr&gt;
578 579 580 581 582 583 584 585 586
      &lt;td&gt;Notes:&lt;/td&gt;
      &lt;td&gt;&lt;form:textarea path="notes" rows="3" cols="20" /&gt;&lt;/td&gt;
      &lt;td&gt;&lt;form:errors path="notes" /&gt;&lt;/td&gt;
  &lt;/tr&gt;</programlisting>
      </section>

      <section id="view-jsp-formtaglib-hiddeninputtag">
        <title>The <literal>hidden</literal> tag</title>

587 588
        <para>This tag renders an HTML 'input' tag with type 'hidden' using
        the bound value. To submit an unbound hidden value, use the HTML
589 590
        <literal>input</literal> tag with type 'hidden'.</para>

591
        <programlisting language="xml">&lt;form:hidden path="house" /&gt;
592 593
  </programlisting>

594 595
        <para>If we choose to submit the 'house' value as a hidden one, the
        HTML would look like:</para>
596

597
        <programlisting language="xml">&lt;input name="house" type="hidden" value="Gryffindor"/&gt;
598 599 600 601 602 603 604 605 606 607 608
  </programlisting>
      </section>

      <section id="view-jsp-formtaglib-errorstag">
        <title>The <literal>errors</literal> tag</title>

        <para>This tag renders field errors in an HTML 'span' tag. It provides
        access to the errors created in your controller or those that were
        created by any validators associated with your controller.</para>

        <para>Let's assume we want to display all error messages for the
609 610
        <literal>firstName</literal> and <literal>lastName</literal> fields
        once we submit the form. We have a validator for instances of the
611 612 613
        <classname>User</classname> class called
        <classname>UserValidator</classname>.</para>

614
        <programlisting language="java">public class UserValidator implements Validator {
615 616 617 618 619 620 621 622 623 624 625 626 627

      public boolean supports(Class candidate) {
          return User.class.isAssignableFrom(candidate);
      }

      public void validate(Object obj, Errors errors) {
          ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.");
          ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.");
      }
  }</programlisting>

        <para>The <literal>form.jsp</literal> would look like:</para>

628
        <programlisting language="xml">&lt;form:form&gt;
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="firstName" /&gt;&lt;/td&gt;
              <lineannotation>&lt;%-- Show errors for firstName field --%&gt;</lineannotation>
              &lt;td&gt;&lt;form:errors path="firstName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="lastName" /&gt;&lt;/td&gt;
              <lineannotation>&lt;%-- Show errors for lastName field --%&gt;</lineannotation>
              &lt;td&gt;&lt;form:errors path="lastName"  /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="3"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>

        <para>If we submit a form with empty values in the
        <literal>firstName</literal> and <literal>lastName</literal> fields,
        this is what the HTML would look like:</para>

655
        <programlisting language="xml">&lt;form method="POST"&gt;
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;input name="firstName" type="text" value=""/&gt;&lt;/td&gt;
              <lineannotation>&lt;%-- Associated errors to firstName field displayed --%&gt;</lineannotation>
              &lt;td&gt;&lt;span name="firstName.errors"&gt;Field is required.&lt;/span&gt;&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;input name="lastName" type="text" value=""/&gt;&lt;/td&gt;
              <lineannotation>&lt;%-- Associated errors to lastName field displayed --%&gt;</lineannotation>
              &lt;td&gt;&lt;span name="lastName.errors"&gt;Field is required.&lt;/span&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="3"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form&gt;</programlisting>

        <para>What if we want to display the entire list of errors for a given
        page? The example below shows that the <literal>errors</literal> tag
        also supports some basic wildcarding functionality.</para>

        <itemizedlist>
          <listitem>
            <para><literal>path="*"</literal> - displays all errors</para>
          </listitem>

          <listitem>
            <para><literal>path="lastName*"</literal> - displays all errors
            associated with the <literal>lastName</literal> field</para>
          </listitem>
        </itemizedlist>

693 694
        <para>The example below will display a list of errors at the top of
        the page, followed by field-specific errors next to the fields:</para>
695

696
        <programlisting language="xml">&lt;form:form&gt;
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
      &lt;form:errors path="*" cssClass="errorBox" /&gt;
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="firstName" /&gt;&lt;/td&gt;
              &lt;td&gt;&lt;form:errors path="firstName" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;form:input path="lastName" /&gt;&lt;/td&gt;
              &lt;td&gt;&lt;form:errors path="lastName"  /&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="3"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
      &lt;/table&gt;
  &lt;/form:form&gt;</programlisting>

        <para>The HTML would look like:</para>

719
        <programlisting language="xml">&lt;form method="POST"&gt;
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
      &lt;span name="*.errors" class="errorBox"&gt;Field is required.&lt;br/&gt;Field is required.&lt;/span&gt;
      &lt;table&gt;
          &lt;tr&gt;
              &lt;td&gt;First Name:&lt;/td&gt;
              &lt;td&gt;&lt;input name="firstName" type="text" value=""/&gt;&lt;/td&gt;
              &lt;td&gt;&lt;span name="firstName.errors"&gt;Field is required.&lt;/span&gt;&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr&gt;
              &lt;td&gt;Last Name:&lt;/td&gt;
              &lt;td&gt;&lt;input name="lastName" type="text" value=""/&gt;&lt;/td&gt;
              &lt;td&gt;&lt;span name="lastName.errors"&gt;Field is required.&lt;/span&gt;&lt;/td&gt;
          &lt;/tr&gt;
          &lt;tr&gt;
              &lt;td colspan="3"&gt;
                  &lt;input type="submit" value="Save Changes" /&gt;
              &lt;/td&gt;
          &lt;/tr&gt;
  &lt;/form&gt;</programlisting>
      </section>
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790

      <section id="rest-method-conversion">
        <title>HTTP Method Conversion</title>

        <para>A key principle of REST is the use of the Uniform Interface.
        This means that all resources (URLs) can be manipulated using the same
        four HTTP methods: GET, PUT, POST, and DELETE. For each methods, the
        HTTP specification defines the exact semantics. For instance, a GET
        should always be a safe operation, meaning that is has no side
        effects, and a PUT or DELETE should be idempotent, meaning that you
        can repeat these operations over and over again, but the end result
        should be the same. While HTTP defines these four methods, HTML only
        supports two: GET and POST. Fortunately, there are two possible
        workarounds: you can either use JavaScript to do your PUT or DELETE,
        or simply do a POST with the 'real' method as an additional parameter
        (modeled as a hidden input field in an HTML form). This latter trick
        is what Spring's <classname>HiddenHttpMethodFilter</classname> does.
        This filter is a plain Servlet Filter and therefore it can be used in
        combination with any web framework (not just Spring MVC). Simply add
        this filter to your web.xml, and a POST with a hidden _method
        parameter will be converted into the corresponding HTTP method
        request.</para>

        <para>To support HTTP method conversion the Spring MVC form tag was
        updated to support setting the HTTP method. For example, the following
        snippet taken from the updated Petclinic sample</para>

        <programlisting language="xml">&lt;form:form method="delete"&gt;
      &lt;p class="submit"&gt;&lt;input type="submit" value="Delete Pet"/&gt;&lt;/p&gt;
&lt;/form:form&gt;</programlisting>

        <para>This will actually perform an HTTP POST, with the 'real' DELETE
        method hidden behind a request parameter, to be picked up by the
        <classname>HiddenHttpMethodFilter</classname>, as defined in web.xml:</para>
        <programlisting language="java">&lt;filter&gt;
    &lt;filter-name&gt;httpMethodFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;org.springframework.web.filter.HiddenHttpMethodFilter&lt;/filter-class&gt;
&lt;/filter&gt;

&lt;filter-mapping&gt;
    &lt;filter-name&gt;httpMethodFilter&lt;/filter-name&gt;
    &lt;servlet-name&gt;petclinic&lt;/servlet-name&gt;
&lt;/filter-mapping&gt;</programlisting><para>The corresponding @Controller method
        is shown below:</para>

        <programlisting language="java">@RequestMapping(method = RequestMethod.DELETE)
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
  this.clinic.deletePet(petId);
  return "redirect:/owners/" + ownerId;
}</programlisting>
      </section>
791 792 793 794 795 796 797 798 799 800 801 802 803
    </section>
  </section>

  <section id="view-tiles">
    <title>Tiles</title>

    <para>It is possible to integrate Tiles - just as any other view
    technology - in web applications using Spring. The following describes in
    a broad way how to do this.</para>

    <para><emphasis>NOTE:</emphasis> This section focuses on Spring's support
    for Tiles 2 (the standalone version of Tiles, requiring Java 5+) in the
    <literal>org.springframework.web.servlet.view.tiles2</literal> package.
804 805 806 807
    Spring also continues to support Tiles 1.x (a.k.a. "Struts Tiles", as
    shipped with Struts 1.1+; compatible with Java 1.4) in the original
    <literal>org.springframework.web.servlet.view.tiles</literal>
    package.</para>
808

809
    <section id="view-tiles-dependencies">
810 811 812 813 814 815 816 817 818 819
      <title>Dependencies</title>

      <para>To be able to use Tiles you have to have a couple of additional
      dependencies included in your project. The following is the list of
      dependencies you need.</para>

      <para><itemizedlist spacing="compact">
          <listitem>
            <para><literal>Tiles version 2.0.4 or higher</literal></para>
          </listitem>
820

821 822 823
          <listitem>
            <para><literal>Commons BeanUtils</literal></para>
          </listitem>
824

825 826 827
          <listitem>
            <para><literal>Commons Digester</literal></para>
          </listitem>
828

829 830 831 832 833
          <listitem>
            <para><literal>Commons Logging</literal></para>
          </listitem>
        </itemizedlist></para>

834 835
      <para>These dependencies are all available in the Spring
      distribution.</para>
836 837 838 839 840 841 842 843
    </section>

    <section id="view-tiles-integrate">
      <title>How to integrate Tiles</title>

      <para>To be able to use Tiles, you have to configure it using files
      containing definitions (for basic information on definitions and other
      Tiles concepts, please have a look at <ulink
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
      url="http://tiles.apache.org" />). In Spring this is done using the
      <classname>TilesConfigurer</classname>. Have a look at the following
      piece of example ApplicationContext configuration:</para>

      <programlisting language="xml">&lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"&gt;
  &lt;property name="definitions"&gt;
    &lt;list&gt;
      &lt;value&gt;/WEB-INF/defs/general.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/widgets.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/administrator.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/customer.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/templates.xml&lt;/value&gt;
    &lt;/list&gt;
  &lt;/property&gt;
&lt;/bean&gt;</programlisting>
859 860

      <para>As you can see, there are five files containing definitions, which
861 862 863 864 865 866 867 868 869 870
      are all located in the <filename
      class="directory">'WEB-INF/defs'</filename> directory. At initialization
      of the <interfacename>WebApplicationContext</interfacename>, the files
      will be loaded and the definitions factory will be initialized. After
      that has been done, the Tiles includes in the definition files can be
      used as views within your Spring web application. To be able to use the
      views you have to have a <interfacename>ViewResolver</interfacename>
      just as with any other view technology used with Spring. Below you can
      find two possibilities, the <classname>UrlBasedViewResolver</classname>
      and the <classname>ResourceBundleViewResolver</classname>.</para>
871 872

      <section id="view-tiles-url">
873 874 875
        <title>
          <classname>UrlBasedViewResolver</classname>
        </title>
876

877 878 879 880 881 882 883
        <para>The <classname>UrlBasedViewResolver</classname> instantiates the
        given <literal>viewClass</literal> for each view it has to
        resolve.</para>

        <programlisting language="xml">&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"&gt;
  &lt;property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/&gt;
&lt;/bean&gt;</programlisting>
884 885 886
      </section>

      <section id="view-tiles-resource">
887 888 889
        <title>
          <classname>ResourceBundleViewResolver</classname>
        </title>
890

891 892 893 894 895 896 897
        <para>The <classname>ResourceBundleViewResolver</classname> has to be
        provided with a property file containing viewnames and viewclasses the
        resolver can use:</para>

        <programlisting language="xml">&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"&gt;
  &lt;property name="basename" value="views"/&gt;
&lt;/bean&gt;</programlisting>
898

899
        <programlisting language="java">...
900
welcomeView.class=org.springframework.web.servlet.view.tiles2.TilesView
901
welcomeView.url=welcome <lineannotation>(this is the name of a Tiles definition)</lineannotation>
902 903

vetsView.class=org.springframework.web.servlet.view.tiles2.TilesView
904
vetsView.url=vetsView <lineannotation>(again, this is the name of a Tiles definition)</lineannotation>
905 906 907

findOwnersForm.class=org.springframework.web.servlet.view.JstlView
findOwnersForm.url=/WEB-INF/jsp/findOwners.jsp
908
...</programlisting>
909

910 911 912
        <para>As you can see, when using the
        <classname>ResourceBundleViewResolver</classname>, you can easily mix
        different view technologies.</para>
913 914
      </section>

915 916 917 918
      <para>Note that the <classname>TilesView</classname> class for Tiles 2
      supports JSTL (the JSP Standard Tag Library) out of the box, whereas
      there is a separate <classname>TilesJstlView</classname> subclass in the
      Tiles 1.x support.</para>
919 920

      <section id="view-tiles-preparer">
921 922
        <title><classname>SimpleSpringPreparerFactory</classname> and
        <classname>SpringBeanPreparerFactory</classname></title>
923 924

        <para>As an advanced feature, Spring also supports two special Tiles 2
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
        <interfacename>PreparerFactory</interfacename> implementations. Check
        out the Tiles documentation for details on how to use
        <interfacename>ViewPreparer</interfacename> references in your Tiles
        definition files.</para>

        <para>Specify <classname>SimpleSpringPreparerFactory</classname> to
        autowire ViewPreparer instances based on specified preparer classes,
        applying Spring's container callbacks as well as applying configured
        Spring BeanPostProcessors. If Spring's context-wide annotation-config
        has been activated, annotations in ViewPreparer classes will be
        automatically detected and applied. Note that this expects preparer
        <emphasis>classes</emphasis> in the Tiles definition files, just like
        the default <classname>PreparerFactory</classname> does.</para>

        <para>Specify <classname>SpringBeanPreparerFactory</classname> to
        operate on specified preparer <emphasis>names</emphasis> instead of
        classes, obtaining the corresponding Spring bean from the
        DispatcherServlet's application context. The full bean creation
        process will be in the control of the Spring application context in
        this case, allowing for the use of explicit dependency injection
        configuration, scoped beans etc. Note that you need to define one
        Spring bean definition per preparer name (as used in your Tiles
        definitions).</para>

        <programlisting language="xml">&lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"&gt;
  &lt;property name="definitions"&gt;
    &lt;list&gt;
      &lt;value&gt;/WEB-INF/defs/general.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/widgets.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/administrator.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/customer.xml&lt;/value&gt;
      &lt;value&gt;/WEB-INF/defs/templates.xml&lt;/value&gt;
    &lt;/list&gt;
  &lt;/property&gt;

  <lineannotation>&lt;!-- resolving preparer names as Spring bean definition names --&gt;</lineannotation>
  &lt;property name="preparerFactoryClass"
       value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/&gt;

&lt;/bean&gt;</programlisting>
      </section>
966 967 968 969 970 971
    </section>
  </section>

  <section id="view-velocity">
    <title>Velocity &amp; FreeMarker</title>

972 973 974 975 976 977
    <para><ulink url="http://velocity.apache.org">Velocity</ulink> and <ulink
    url="http://www.freemarker.org">FreeMarker</ulink> are two templating
    languages that can both be used as view technologies within Spring MVC
    applications. The languages are quite similar and serve similar needs and
    so are considered together in this section. For semantic and syntactic
    differences between the two languages, see the <ulink
978 979 980 981 982
    url="http://www.freemarker.org">FreeMarker</ulink> web site.</para>

    <section id="view-velocity-dependencies">
      <title>Dependencies</title>

983 984 985 986 987 988 989
      <para>Your web application will need to include <filename
      class="libraryfile">velocity-1.x.x.jar</filename> or <filename
      class="libraryfile">freemarker-2.x.jar</filename> in order to work with
      Velocity or FreeMarker respectively and <filename
      class="libraryfile">commons-collections.jar</filename> needs also to be
      available for Velocity. Typically they are included in the
      <literal>WEB-INF/lib</literal> folder where they are guaranteed to be
T
Thomas Risberg 已提交
990
      found by a Java EE server and added to the classpath for your application.
991 992 993 994 995 996 997 998 999
      It is of course assumed that you already have the <filename
      class="libraryfile">spring.jar</filename> in your <filename
      class="directory">'WEB-INF/lib'</filename> directory too! The latest
      stable Velocity, FreeMarker and Commons Collections jars are supplied
      with the Spring framework and can be copied from the relevant <filename
      class="libraryfile">/lib/</filename> sub-directories. If you make use of
      Spring's 'dateToolAttribute' or 'numberToolAttribute' in your Velocity
      views, you will also need to include the <filename
      class="libraryfile">velocity-tools-generic-1.x.jar</filename></para>
1000 1001 1002 1003 1004 1005
    </section>

    <section id="view-velocity-contextconfig">
      <title>Context configuration</title>

      <para>A suitable configuration is initialized by adding the relevant
1006 1007
      configurer bean definition to your <filename>'*-servlet.xml'</filename>
      as shown below:</para>
1008

1009
      <programlisting language="xml"><lineannotation>&lt;!-- 
1010 1011 1012
  This bean sets up the Velocity environment for us based on a root path for templates.
  Optionally, a properties file can be specified for more control over the Velocity
  environment, but the defaults are pretty sane for file based template loading.
1013 1014 1015 1016
--&gt;</lineannotation>
&lt;bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"&gt;
  &lt;property name="resourceLoaderPath" value="/WEB-INF/velocity/"/&gt;
&lt;/bean&gt;
1017

1018
<lineannotation>&lt;!-- 
1019 1020 1021 1022

  View resolvers can also be configured with ResourceBundles or XML files. If you need
  different view resolving based on Locale, you have to use the resource bundle resolver.

1023 1024 1025 1026 1027 1028
--&gt;</lineannotation>
&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"&gt;
  &lt;property name="cache" value="true"/&gt;
  &lt;property name="prefix" value=""/&gt;
  &lt;property name="suffix" value=".vm"/&gt;
&lt;/bean&gt;</programlisting>
1029

1030 1031 1032 1033
      <programlisting><lineannotation>&lt;!-- freemarker config --&gt;</lineannotation>
&lt;bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"&gt;
  &lt;property name="templateLoaderPath" value="/WEB-INF/freemarker/"/&gt;
&lt;/bean&gt;
1034

1035
<lineannotation>&lt;!-- 
1036 1037 1038 1039

  View resolvers can also be configured with ResourceBundles or XML files. If you need
  different view resolving based on Locale, you have to use the resource bundle resolver.

1040 1041 1042 1043 1044 1045
--&gt;</lineannotation>
&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"&gt;
  &lt;property name="cache" value="true"/&gt;
  &lt;property name="prefix" value=""/&gt;
  &lt;property name="suffix" value=".ftl"/&gt;
&lt;/bean&gt;</programlisting>
1046

1047 1048 1049 1050 1051
      <note>
        <para>For non web-apps add a
        <classname>VelocityConfigurationFactoryBean</classname> or a
        <classname>FreeMarkerConfigurationFactoryBean</classname> to your
        application context definition file.</para>
1052 1053 1054 1055 1056 1057 1058
      </note>
    </section>

    <section id="view-velocity-createtemplates">
      <title>Creating templates</title>

      <para>Your templates need to be stored in the directory specified by the
1059 1060 1061
      <literal>*Configurer</literal> bean shown above. This document does not
      cover details of creating templates for the two languages - please see
      their relevant websites for information. If you use the view resolvers
1062 1063
      highlighted, then the logical view names relate to the template file
      names in similar fashion to
1064 1065
      <classname>InternalResourceViewResolver</classname> for JSP's. So if
      your controller returns a ModelAndView object containing a view name of
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
      "welcome" then the resolvers will look for the
      <literal>/WEB-INF/freemarker/welcome.ftl</literal> or
      <literal>/WEB-INF/velocity/welcome.vm</literal> template as
      appropriate.</para>
    </section>

    <section id="view-velocity-advancedconfig">
      <title>Advanced configuration</title>

      <para>The basic configurations highlighted above will be suitable for
      most application requirements, however additional configuration options
      are available for when unusual or advanced requirements dictate.</para>

      <section id="view-velocity-example-velocityproperties">
        <title>velocity.properties</title>

        <para>This file is completely optional, but if specified, contains the
        values that are passed to the Velocity runtime in order to configure
        velocity itself. Only required for advanced configurations, if you
        need this file, specify its location on the
        <literal>VelocityConfigurer</literal> bean definition above.</para>

1088
        <programlisting language="xml">&lt;bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"&gt;
1089 1090 1091 1092 1093 1094 1095
  &lt;property name="configLocation value="/WEB-INF/velocity.properties"/&gt;
&lt;/bean&gt;</programlisting>

        <para>Alternatively, you can specify velocity properties directly in
        the bean definition for the Velocity config bean by replacing the
        "configLocation" property with the following inline properties.</para>

1096 1097 1098 1099 1100
        <programlisting language="xml">&lt;bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"&gt;
  &lt;property name="velocityProperties"&gt;
    &lt;props&gt;
      &lt;prop key="resource.loader"&gt;file&lt;/prop&gt;
      &lt;prop key="file.resource.loader.class"&gt;
1101
        org.apache.velocity.runtime.resource.loader.FileResourceLoader
1102 1103 1104 1105 1106 1107
      &lt;/prop&gt;
      &lt;prop key="file.resource.loader.path"&gt;${webapp.root}/WEB-INF/velocity&lt;/prop&gt;
      &lt;prop key="file.resource.loader.cache"&gt;false&lt;/prop&gt;
    &lt;/props&gt;
  &lt;/property&gt;
&lt;/bean&gt;</programlisting>
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127

        <para>Refer to the <ulink
        url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/ui/velocity/VelocityEngineFactory.html">API
        documentation</ulink> for Spring configuration of Velocity, or the
        Velocity documentation for examples and definitions of the
        <filename>'velocity.properties'</filename> file itself.</para>
      </section>

      <section id="views-freemarker">
        <title>FreeMarker</title>

        <para>FreeMarker 'Settings' and 'SharedVariables' can be passed
        directly to the FreeMarker <literal>Configuration</literal> object
        managed by Spring by setting the appropriate bean properties on the
        <literal>FreeMarkerConfigurer</literal> bean. The
        <literal>freemarkerSettings</literal> property requires a
        <literal>java.util.Properties</literal> object and the
        <literal>freemarkerVariables</literal> property requires a
        <literal>java.util.Map</literal>.</para>

1128 1129 1130 1131 1132 1133 1134 1135
        <programlisting language="xml">&lt;bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"&gt;
  &lt;property name="templateLoaderPath" value="/WEB-INF/freemarker/"/&gt;
  &lt;property name="freemarkerVariables"&gt;
    &lt;map&gt;
      &lt;entry key="xml_escape" value-ref="fmXmlEscape"/&gt;
    &lt;/map&gt;
  &lt;/property&gt;
&lt;/bean&gt;
1136

1137
&lt;bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/&gt;</programlisting>
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188

        <para>See the FreeMarker documentation for details of settings and
        variables as they apply to the <classname>Configuration</classname>
        object.</para>
      </section>
    </section>

    <section id="view-velocity-forms">
      <title>Bind support and form handling</title>

      <para>Spring provides a tag library for use in JSP's that contains
      (amongst other things) a <literal>&lt;spring:bind/&gt;</literal> tag.
      This tag primarily enables forms to display values from form backing
      objects and to show the results of failed validations from a
      <literal>Validator</literal> in the web or business tier. From version
      1.1, Spring now has support for the same functionality in both Velocity
      and FreeMarker, with additional convenience macros for generating form
      input elements themselves.</para>

      <section id="view-bind-macros">
        <title>The bind macros</title>

        <para>A standard set of macros are maintained within the
        <literal>spring.jar</literal> file for both languages, so they are
        always available to a suitably configured application.</para>

        <para>Some of the macros defined in the Spring libraries are
        considered internal (private) but no such scoping exists in the macro
        definitions making all macros visible to calling code and user
        templates. The following sections concentrate only on the macros you
        need to be directly calling from within your templates. If you wish to
        view the macro code directly, the files are called spring.vm /
        spring.ftl and are in the packages
        <literal>org.springframework.web.servlet.view.velocity</literal> or
        <literal>org.springframework.web.servlet.view.freemarker</literal>
        respectively.</para>
      </section>

      <section id="view-simple-binding">
        <title>Simple binding</title>

        <para>In your html forms (vm / ftl templates) that act as the
        'formView' for a Spring form controller, you can use code similar to
        the following to bind to field values and display error messages for
        each input field in similar fashion to the JSP equivalent. Note that
        the name of the command object is "command" by default, but can be
        overridden in your MVC configuration by setting the 'commandName' bean
        property on your form controller. Example code is shown below for the
        <literal>personFormV</literal> and <literal>personFormF</literal>
        views configured earlier;</para>

1189
        <programlisting language="xml">&lt;!-- velocity macros are automatically available --&gt;
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
&lt;html&gt;
...
&lt;form action="" method="POST"&gt;
  Name: 
  #springBind( "command.name" )
  &lt;input type="text" 
    name="${status.expression}" 
    value="$!status.value" /&gt;&lt;br&gt;
  #foreach($error in $status.errorMessages) &lt;b&gt;$error&lt;/b&gt; &lt;br&gt; #end
  &lt;br&gt;
  ... 
  &lt;input type="submit" value="submit"/&gt;
&lt;/form&gt;
...
&lt;/html&gt;</programlisting>

1206
        <programlisting language="xml">&lt;!-- freemarker macros have to be imported into a namespace.  We strongly
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
recommend sticking to 'spring' --&gt;
&lt;#import "spring.ftl" as spring /&gt;
&lt;html&gt;
...
&lt;form action="" method="POST"&gt;
  Name: 
  &lt;@spring.bind "command.name" /&gt; 
  &lt;input type="text" 
    name="${spring.status.expression}" 
    value="${spring.status.value?default("")}" /&gt;&lt;br&gt;
  &lt;#list spring.status.errorMessages as error&gt; &lt;b&gt;${error}&lt;/b&gt; &lt;br&gt; &lt;/#list&gt;
  &lt;br&gt;
  ... 
  &lt;input type="submit" value="submit"/&gt;
&lt;/form&gt;
...
&lt;/html&gt;</programlisting>

        <para><literal>#springBind</literal> /
        <literal>&lt;@spring.bind&gt;</literal> requires a 'path' argument
        which consists of the name of your command object (it will be
        'command' unless you changed it in your FormController properties)
        followed by a period and the name of the field on the command object
        you wish to bind to. Nested fields can be used too such as
        "command.address.street". The <literal>bind</literal> macro assumes
        the default HTML escaping behavior specified by the ServletContext
        parameter <literal>defaultHtmlEscape</literal> in web.xml</para>

        <para>The optional form of the macro called
        <literal>#springBindEscaped</literal> /
        <literal>&lt;@spring.bindEscaped&gt;</literal> takes a second argument
        and explicitly specifies whether HTML escaping should be used in the
        status error messages or values. Set to true or false as required.
        Additional form handling macros simplify the use of HTML escaping and
        these macros should be used wherever possible. They are explained in
        the next section.</para>
      </section>

      <section id="views-form-macros">
        <title>Form input generation macros</title>

        <para>Additional convenience macros for both languages simplify both
        binding and form generation (including validation error display). It
        is never necessary to use these macros to generate form input fields,
        and they can be mixed and matched with simple HTML or calls direct to
        the spring bind macros highlighted previously.</para>

        <para>The following table of available macros show the VTL and FTL
        definitions and the parameter list that each takes.</para>

        <table id="views-macros-defs-tbl">
          <title>Table of macro definitions</title>

          <tgroup cols="3">
            <colspec align="left" />

            <thead>
              <row>
                <entry align="center">macro</entry>

                <entry align="center">VTL definition</entry>

                <entry align="center">FTL definition</entry>
              </row>
            </thead>

            <tbody>
              <row>
                <entry><emphasis role="bold">message</emphasis> (output a
                string from a resource bundle based on the code
                parameter)</entry>

                <entry><literal>#springMessage($code)</literal></entry>

                <entry><literal>&lt;@spring.message
                code/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">messageText</emphasis> (output a
                string from a resource bundle based on the code parameter,
                falling back to the value of the default parameter)</entry>

                <entry><literal>#springMessageText($code
                $text)</literal></entry>

                <entry><literal>&lt;@spring.messageText code,
                text/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">url</emphasis> (prefix a relative
                URL with the application's context root)</entry>

                <entry><literal>#springUrl($relativeUrl)</literal></entry>

                <entry><literal>&lt;@spring.url
                relativeUrl/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formInput</emphasis> (standard
                input field for gathering user input)</entry>

                <entry><literal>#springFormInput($path
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formInput path, attributes,
                fieldType/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formHiddenInput *</emphasis>
                (hidden input field for submitting non-user input)</entry>

                <entry><literal>#springFormHiddenInput($path
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formHiddenInput path,
                attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formPasswordInput</emphasis> *
                (standard input field for gathering passwords. Note that no
                value will ever be populated in fields of this type)</entry>

                <entry><literal>#springFormPasswordInput($path
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formPasswordInput path,
                attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formTextarea</emphasis> (large
                text field for gathering long, freeform text input)</entry>

                <entry><literal>#springFormTextarea($path
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formTextarea path,
                attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formSingleSelect</emphasis> (drop
                down box of options allowing a single required value to be
                selected)</entry>

                <entry><literal>#springFormSingleSelect( $path $options
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formSingleSelect path, options,
                attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formMultiSelect</emphasis> (a
                list box of options allowing the user to select 0 or more
                values)</entry>

                <entry><literal>#springFormMultiSelect($path $options
                $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formMultiSelect path, options,
                attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formRadioButtons</emphasis> (a
                set of radio buttons allowing a single selection to be made
                from the available choices)</entry>

                <entry><literal>#springFormRadioButtons($path $options
                $separator $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formRadioButtons path, options
                separator, attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">formCheckboxes</emphasis> (a set
                of checkboxes allowing 0 or more values to be
                selected)</entry>

                <entry><literal>#springFormCheckboxes($path $options
                $separator $attributes)</literal></entry>

                <entry><literal>&lt;@spring.formCheckboxes path, options,
                separator, attributes/&gt;</literal></entry>
              </row>

              <row>
                <entry><emphasis role="bold">showErrors</emphasis> (simplify
                display of validation errors for the bound field)</entry>

                <entry><literal>#springShowErrors($separator
                $classOrStyle)</literal></entry>

                <entry><literal>&lt;@spring.showErrors separator,
                classOrStyle/&gt;</literal></entry>
              </row>
            </tbody>
          </tgroup>
        </table>

        <para>* In FTL (FreeMarker), these two macros are not actually
        required as you can use the normal <literal>formInput</literal> macro,
        specifying '<literal>hidden</literal>' or
        '<literal>password</literal>' as the value for the
        <literal>fieldType</literal> parameter.</para>

        <para>The parameters to any of the above macros have consistent
        meanings:</para>

        <itemizedlist>
          <listitem>
            <para>path: the name of the field to bind to (ie
            "command.name")</para>
          </listitem>

          <listitem>
            <para>options: a Map of all the available values that can be
            selected from in the input field. The keys to the map represent
            the values that will be POSTed back from the form and bound to the
            command object. Map objects stored against the keys are the labels
            displayed on the form to the user and may be different from the
            corresponding values posted back by the form. Usually such a map
            is supplied as reference data by the controller. Any Map
            implementation can be used depending on required behavior. For
            strictly sorted maps, a <literal>SortedMap</literal> such as a
            <literal>TreeMap</literal> with a suitable Comparator may be used
            and for arbitrary Maps that should return values in insertion
            order, use a <literal>LinkedHashMap</literal> or a
            <literal>LinkedMap</literal> from commons-collections.</para>
          </listitem>

          <listitem>
            <para>separator: where multiple options are available as discreet
            elements (radio buttons or checkboxes), the sequence of characters
            used to separate each one in the list (ie "&lt;br&gt;").</para>
          </listitem>

          <listitem>
            <para>attributes: an additional string of arbitrary tags or text
            to be included within the HTML tag itself. This string is echoed
            literally by the macro. For example, in a textarea field you may
            supply attributes as 'rows="5" cols="60"' or you could pass style
            information such as 'style="border:1px solid silver"'.</para>
          </listitem>

          <listitem>
            <para>classOrStyle: for the showErrors macro, the name of the CSS
            class that the span tag wrapping each error will use. If no
            information is supplied (or the value is empty) then the errors
            will be wrapped in &lt;b&gt;&lt;/b&gt; tags.</para>
          </listitem>
        </itemizedlist>

        <para>Examples of the macros are outlined below some in FTL and some
        in VTL. Where usage differences exist between the two languages, they
        are explained in the notes.</para>

        <section id="views-form-macros-input">
          <title>Input Fields</title>

1474
          <para><programlisting language="xml">&lt;!-- the Name field example from above using form macros in VTL --&gt;
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
...
    Name:
    #springFormInput("command.name" "")&lt;br&gt;
    #springShowErrors("&lt;br&gt;" "")&lt;br&gt;</programlisting></para>

          <para>The formInput macro takes the path parameter (command.name)
          and an additional attributes parameter which is empty in the example
          above. The macro, along with all other form generation macros,
          performs an implicit spring bind on the path parameter. The binding
          remains valid until a new bind occurs so the showErrors macro
          doesn't need to pass the path parameter again - it simply operates
          on whichever field a bind was last created for.</para>

          <para>The showErrors macro takes a separator parameter (the
          characters that will be used to separate multiple errors on a given
          field) and also accepts a second parameter, this time a class name
          or style attribute. Note that FreeMarker is able to specify default
          values for the attributes parameter, unlike Velocity, and the two
          macro calls above could be expressed as follows in FTL:</para>

1495
          <programlisting language="xml">&lt;@spring.formInput "command.name"/&gt;
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
&lt;@spring.showErrors "&lt;br&gt;"/&gt;</programlisting>

          <para>Output is shown below of the form fragment generating the name
          field, and displaying a validation error after the form was
          submitted with no value in the field. Validation occurs through
          Spring's Validation framework.</para>

          <para>The generated HTML looks like this:</para>

          <programlisting>Name:
  &lt;input type="text" name="name" value=""     
&gt;
&lt;br&gt;
  &lt;b&gt;required&lt;/b&gt;
&lt;br&gt;
&lt;br&gt;</programlisting>

          <para>The formTextarea macro works the same way as the formInput
          macro and accepts the same parameter list. Commonly, the second
          parameter (attributes) will be used to pass style information or
          rows and cols attributes for the textarea.</para>
        </section>

        <section id="views-form-macros-select">
          <title>Selection Fields</title>

          <para>Four selection field macros can be used to generate common UI
          value selection inputs in your HTML forms.</para>

          <itemizedlist>
            <listitem>
              <para>formSingleSelect</para>
            </listitem>

            <listitem>
              <para>formMultiSelect</para>
            </listitem>

            <listitem>
              <para>formRadioButtons</para>
            </listitem>

            <listitem>
              <para>formCheckboxes</para>
            </listitem>
          </itemizedlist>

          <para>Each of the four macros accepts a Map of options containing
          the value for the form field, and the label corresponding to that
          value. The value and the label can be the same.</para>

          <para>An example of radio buttons in FTL is below. The form backing
          object specifies a default value of 'London' for this field and so
          no validation is necessary. When the form is rendered, the entire
          list of cities to choose from is supplied as reference data in the
          model under the name 'cityMap'.</para>

          <programlisting>...
  Town:
  &lt;@spring.formRadioButtons "command.address.town", cityMap, "" /&gt;&lt;br&gt;&lt;br&gt;</programlisting>

          <para>This renders a line of radio buttons, one for each value in
          <literal>cityMap</literal> using the separator "". No additional
          attributes are supplied (the last parameter to the macro is
          missing). The cityMap uses the same String for each key-value pair
          in the map. The map's keys are what the form actually submits as
          POSTed request parameters, map values are the labels that the user
          sees. In the example above, given a list of three well known cities
          and a default value in the form backing object, the HTML would
          be</para>

          <programlisting>Town:
&lt;input type="radio" name="address.town" value="London"
   
&gt;
London
&lt;input type="radio" name="address.town" value="Paris"
  checked="checked" 
&gt;
Paris
&lt;input type="radio" name="address.town" value="New York"
   
&gt;
New York</programlisting>

          <para>If your application expects to handle cities by internal codes
          for example, the map of codes would be created with suitable keys
          like the example below.</para>

1585
          <programlisting language="java">protected Map referenceData(HttpServletRequest request) throws Exception {
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
  Map cityMap = new LinkedHashMap();
  cityMap.put("LDN", "London");
  cityMap.put("PRS", "Paris");
  cityMap.put("NYC", "New York");
  
  Map m = new HashMap();
  m.put("cityMap", cityMap);
  return m;
}</programlisting>

          <para>The code would now produce output where the radio values are
          the relevant codes but the user still sees the more user friendly
          city names.</para>

          <programlisting>Town:
&lt;input type="radio" name="address.town" value="LDN"
   
&gt;
London
&lt;input type="radio" name="address.town" value="PRS"
  checked="checked" 
&gt;
Paris
&lt;input type="radio" name="address.town" value="NYC"
   
&gt;
New York</programlisting>
        </section>
      </section>

      <section id="views-form-macros-html-escaping">
        <title>HTML escaping and XHTML compliance</title>

        <para>Default usage of the form macros above will result in HTML tags
        that are HTML 4.01 compliant and that use the default value for HTML
        escaping defined in your web.xml as used by Spring's bind support. In
        order to make the tags XHTML compliant or to override the default HTML
        escaping value, you can specify two variables in your template (or in
        your model where they will be visible to your templates). The
        advantage of specifying them in the templates is that they can be
        changed to different values later in the template processing to
        provide different behavior for different fields in your form.</para>

        <para>To switch to XHTML compliance for your tags, specify a value of
        'true' for a model/context variable named xhtmlCompliant:</para>

        <programlisting>## for Velocity..
#set($springXhtmlCompliant = true)

&lt;#-- for FreeMarker --&gt;
&lt;#assign xhtmlCompliant = true in spring&gt;</programlisting>

        <para>Any tags generated by the Spring macros will now be XHTML
        compliant after processing this directive.</para>

        <para>In similar fashion, HTML escaping can be specified per
        field:</para>

1644
        <programlisting language="xml">&lt;#-- until this point, default HTML escaping is used --&gt;
1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669

&lt;#assign htmlEscape = true in spring&gt;
&lt;#-- next field will use HTML escaping --&gt;
&lt;@spring.formInput "command.name" /&gt;

&lt;#assign htmlEscape = false in spring&gt;
&lt;#-- all future fields will be bound with HTML escaping off --&gt;</programlisting>
      </section>
    </section>
  </section>

  <section id="view-xslt">
    <title>XSLT</title>

    <para>XSLT is a transformation language for XML and is popular as a view
    technology within web applications. XSLT can be a good choice as a view
    technology if your application naturally deals with XML, or if your model
    can easily be converted to XML. The following section shows how to produce
    an XML document as model data and have it transformed with XSLT in a
    Spring Web MVC application.</para>

    <section id="view-xslt-firstwords">
      <title>My First Words</title>

      <para>This example is a trivial Spring application that creates a list
1670 1671 1672 1673 1674 1675 1676
      of words in the <interfacename>Controller</interfacename> and adds them
      to the model map. The map is returned along with the view name of our
      XSLT view. See the section entitled <xref linkend="mvc-controller" />
      for details of Spring Web MVC's
      <interfacename>Controller</interfacename> interface. The XSLT view will
      turn the list of words into a simple XML document ready for
      transformation.</para>
1677 1678 1679 1680 1681 1682

      <section id="view-xslt-beandefs">
        <title>Bean definitions</title>

        <para>Configuration is standard for a simple Spring application. The
        dispatcher servlet config file contains a reference to a
1683 1684 1685 1686 1687
        <interfacename>ViewResolver</interfacename>, URL mappings and a single
        controller bean...</para>

        <programlisting language="xml">&lt;bean id="homeController"class="xslt.HomeController"/&gt;</programlisting>

1688 1689 1690 1691 1692 1693 1694
        <para>... that encapsulates our word generation logic.</para>
      </section>

      <section id="view-xslt-controllercode">
        <title>Standard MVC controller code</title>

        <para>The controller logic is encapsulated in a subclass of
1695 1696 1697 1698
        <classname>AbstractController</classname>, with the handler method
        being defined like so...</para>

        <programlisting language="java">protected ModelAndView handleRequestInternal(
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
    HttpServletRequest request,
    HttpServletResponse response) throws Exception {
        
    Map map = new HashMap();
    List wordList = new ArrayList();
        
    wordList.add("hello");
    wordList.add("world");
       
    map.put("wordList", wordList);
      
    return new ModelAndView("home", map);
1711
}</programlisting>
1712 1713 1714 1715 1716 1717

        <para>So far we've done nothing that's XSLT specific. The model data
        has been created in the same way as you would for any other Spring MVC
        application. Depending on the configuration of the application now,
        that list of words could be rendered by JSP/JSTL by having them added
        as request attributes, or they could be handled by Velocity by adding
1718 1719 1720 1721 1722 1723 1724 1725
        the object to the <classname>VelocityContext</classname>. In order to
        have XSLT render them, they of course have to be converted into an XML
        document somehow. There are software packages available that will
        automatically 'domify' an object graph, but within Spring, you have
        complete flexibility to create the DOM from your model in any way you
        choose. This prevents the transformation of XML playing too great a
        part in the structure of your model data which is a danger when using
        tools to manage the domification process.</para>
1726 1727 1728 1729 1730 1731 1732 1733
      </section>

      <section id="view-xslt-subclassing">
        <title>Convert the model data to XML</title>

        <para>In order to create a DOM document from our list of words or any
        other model data, we must subclass the (provided)
        <classname>org.springframework.web.servlet.view.xslt.AbstractXsltView</classname>
1734 1735 1736 1737 1738 1739 1740
        class. In doing so, we must also typically implement the abstract
        method <methodname>createXsltSource(..)</methodname> method. The first
        parameter passed to this method is our model map. Here's the complete
        listing of the <classname>HomePage</classname> class in our trivial
        word application:</para>

        <programlisting language="java">
1741 1742
package xslt;

1743
<lineannotation>// imports omitted for brevity</lineannotation>
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763

public class HomePage extends AbstractXsltView {

    protected Source createXsltSource(Map model, String rootName, HttpServletRequest
        request, HttpServletResponse response) throws Exception {

        Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        Element root = document.createElement(rootName);

        List words = (List) model.get("wordList");
        for (Iterator it = words.iterator(); it.hasNext();) {
            String nextWord = (String) it.next();
            Element wordNode = document.createElement("word");
            Text textNode = document.createTextNode(nextWord);
            wordNode.appendChild(textNode);
            root.appendChild(wordNode);
        }
        return new DOMSource(root);
    }

1764
}</programlisting>
1765

1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776
        <para>A series of parameter name/value pairs can optionally be defined
        by your subclass which will be added to the transformation object. The
        parameter names must match those defined in your XSLT template
        declared with <literal>&lt;xsl:param
        name="myParam"&gt;defaultValue&lt;/xsl:param&gt;</literal>. To specify
        the parameters, override the <methodname>getParameters()</methodname>
        method of the <classname>AbstractXsltView</classname> class and return
        a <interfacename>Map</interfacename> of the name/value pairs. If your
        parameters need to derive information from the current request, you
        can override the <methodname>getParameters(HttpServletRequest
        request)</methodname> method instead.</para>
1777 1778 1779 1780 1781 1782 1783 1784 1785
      </section>

      <section id="view-xslt-viewdefinitions">
        <title>Defining the view properties</title>

        <para>The views.properties file (or equivalent xml definition if
        you're using an XML based view resolver as we did in the Velocity
        examples above) looks like this for the one-view application that is
        'My First Words':</para>
1786 1787

        <programlisting>home.class=xslt.HomePage
1788
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799
home.root=words</programlisting>

        <para>Here, you can see how the view is tied in with the
        <classname>HomePage</classname> class just written which handles the
        model domification in the first property <literal>'.class'</literal>.
        The <literal>'stylesheetLocation'</literal> property points to the
        XSLT file which will handle the XML transformation into HTML for us
        and the final property <literal>'.root'</literal> is the name that
        will be used as the root of the XML document. This gets passed to the
        <classname>HomePage</classname> class above in the second parameter to
        the <methodname>createXsltSource(..)</methodname> method(s).</para>
1800 1801 1802 1803 1804 1805
      </section>

      <section id="view-xslt-transforming">
        <title>Document transformation</title>

        <para>Finally, we have the XSLT code used for transforming the above
1806 1807
        document. As shown in the above
        <filename>'views.properties'</filename> file, the stylesheet is called
1808 1809
        <filename>'home.xslt'</filename> and it lives in the war file in the
        <filename class="directory">'WEB-INF/xsl'</filename> directory.</para>
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830

        <programlisting language="xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

    &lt;xsl:output method="html" omit-xml-declaration="yes"/&gt;

    &lt;xsl:template match="/"&gt;
        &lt;html&gt;
            &lt;head&gt;&lt;title&gt;Hello!&lt;/title&gt;&lt;/head&gt;
            &lt;body&gt;
                &lt;h1&gt;My First Words&lt;/h1&gt;
                &lt;xsl:apply-templates/&gt;
            &lt;/body&gt;
        &lt;/html&gt;
    &lt;/xsl:template&gt;

    &lt;xsl:template match="word"&gt;
        &lt;xsl:value-of select="."/&gt;&lt;br/&gt;
    &lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;</programlisting>
1831 1832 1833 1834 1835 1836 1837 1838
      </section>
    </section>

    <section id="view-xslt-summary">
      <title>Summary</title>

      <para>A summary of the files discussed and their location in the WAR
      file is shown in the simplified WAR structure below.</para>
1839

1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863
      <programlisting>ProjectRoot
  |
  +- WebContent
      |
      +- WEB-INF
          |
          +- classes
          |    |
          |    +- xslt
          |    |   |
          |    |   +- HomePageController.class 
          |    |   +- HomePage.class
          |    |
          |    +- views.properties
          |
          +- lib
          |   |
          |   +- spring.jar
          |
          +- xsl
          |   |
          |   +- home.xslt
          |
          +- frontcontroller-servlet.xml</programlisting>
1864 1865 1866

      <para>You will also need to ensure that an XML parser and an XSLT engine
      are available on the classpath. JDK 1.4 provides them by default, and
T
Thomas Risberg 已提交
1867
      most Java EE containers will also make them available by default, but it's
1868
      a possible source of errors to be aware of.</para>
1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
    </section>
  </section>

  <section id="view-document">
    <title>Document views (PDF/Excel)</title>

    <section id="view-document-intro">
      <title>Introduction</title>

      <para>Returning an HTML page isn't always the best way for the user to
      view the model output, and Spring makes it simple to generate a PDF
      document or an Excel spreadsheet dynamically from the model data. The
      document is the view and will be streamed from the server with the
      correct content type to (hopefully) enable the client PC to run their
      spreadsheet or PDF viewer application in response.</para>

      <para>In order to use Excel views, you need to add the 'poi' library to
      your classpath, and for PDF generation, the iText.jar. Both are included
      in the main Spring distribution.</para>
    </section>

    <section id="view-document-config">
      <title>Configuration and setup</title>

      <para>Document based views are handled in an almost identical fashion to
      XSLT views, and the following sections build upon the previous one by
      demonstrating how the same controller used in the XSLT example is
      invoked to render the same model as both a PDF document and an Excel
      spreadsheet (which can also be viewed or manipulated in Open
      Office).</para>

      <section id="view-document-configviews">
        <title>Document view definitions</title>

        <para>Firstly, let's amend the views.properties file (or xml
        equivalent) and add a simple view definition for both document types.
        The entire file now looks like this with the XSLT view shown from
        earlier.. <programlisting>home.class=xslt.HomePage
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
home.root=words

xl.class=excel.HomePage

pdf.class=pdf.HomePage</programlisting> <emphasis>If you want to start with a
        template spreadsheet to add your model data to, specify the location
        as the 'url' property in the view definition</emphasis></para>
      </section>

      <section id="view-document-configcontroller">
        <title>Controller code</title>

        <para>The controller code we'll use remains exactly the same from the
        XSLT example earlier other than to change the name of the view to use.
        Of course, you could be clever and have this selected based on a URL
        parameter or some other logic - proof that Spring really is very good
        at decoupling the views from the controllers!</para>
      </section>

      <section id="view-document-configsubclasses">
        <title>Subclassing for Excel views</title>

        <para>Exactly as we did for the XSLT example, we'll subclass suitable
        abstract classes in order to implement custom behavior in generating
        our output documents. For Excel, this involves writing a subclass of
        <literal>org.springframework.web.servlet.view.document.AbstractExcelView</literal>
1934 1935 1936 1937
        (for Excel files generated by POI) or
        <literal>org.springframework.web.servlet.view.document.AbstractJExcelView</literal>
        (for JExcelApi-generated Excel files). and implementing the
        <literal>buildExcelDocument</literal></para>
1938

1939 1940 1941
        <para>Here's the complete listing for our POI Excel view which
        displays the word list from the model map in consecutive rows of the
        first column of a new spreadsheet.. <programlisting language="java">package excel;
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975

// imports omitted for brevity

public class HomePage extends AbstractExcelView {

    protected void buildExcelDocument(
        Map model,
        HSSFWorkbook wb,
        HttpServletRequest req,
        HttpServletResponse resp)
        throws Exception {
    
        HSSFSheet sheet;
        HSSFRow sheetRow;
        HSSFCell cell;

        // Go to the first sheet
        // getSheetAt: only if wb is created from an existing document
        //sheet = wb.getSheetAt( 0 );
        sheet = wb.createSheet("Spring");
        sheet.setDefaultColumnWidth((short)12);

        // write a text at A1
        cell = getCell( sheet, 0, 0 );
        setText(cell,"Spring-Excel test");

        List words = (List ) model.get("wordList");
        for (int i=0; i &lt; words.size(); i++) {
            cell = getCell( sheet, 2+i, 0 );
            setText(cell, (String) words.get(i));

        }
    }
}</programlisting></para>
1976 1977 1978

        <para>And this a view generating the same Excel file, now using
        JExcelApi: <programlisting language="java">package excel;
1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
			
// imports omitted for brevity

public class HomePage extends AbstractExcelView {

    protected void buildExcelDocument(Map model,
        WritableWorkbook wb,
        HttpServletRequest request,
        HttpServletResponse response)
    throws Exception {
			
        WritableSheet sheet = wb.createSheet("Spring");

        sheet.addCell(new Label(0, 0, "Spring-Excel test");
		
        List words  = (List)model.get("wordList");
        for (int i = -; i &lt; words.size(); i++) {
            sheet.addCell(new Label(2+i, 0, (String)words.get(i));
        }
    }
}
2000 2001 2002 2003 2004 2005
</programlisting></para>

        <para>Note the differences between the APIs. We've found that the
        JExcelApi is somewhat more intuitive and furthermore, JExcelApi has a
        bit better image-handling capabilities. There have been memory
        problems with large Excel file when using JExcelApi however.</para>
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020

        <para>If you now amend the controller such that it returns
        <literal>xl</literal> as the name of the view (<literal>return new
        ModelAndView("xl", map);</literal>) and run your application again,
        you should find that the Excel spreadsheet is created and downloaded
        automatically when you request the same page as before.</para>
      </section>

      <section id="view-document-configsubclasspdf">
        <title>Subclassing for PDF views</title>

        <para>The PDF version of the word list is even simpler. This time, the
        class extends
        <literal>org.springframework.web.servlet.view.document.AbstractPdfView</literal>
        and implements the <literal>buildPdfDocument()</literal> method as
2021
        follows.. <programlisting language="java">package pdf;
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052

// imports omitted for brevity

public class PDFPage extends AbstractPdfView {

    protected void buildPdfDocument(
        Map model,
        Document doc,
        PdfWriter writer,
        HttpServletRequest req,
        HttpServletResponse resp)
        throws Exception {
        
        List words = (List) model.get("wordList");
        
        for (int i=0; i&lt;words.size(); i++)
            doc.add( new Paragraph((String) words.get(i)));
    
    }
}</programlisting> Once again, amend the controller to return the
        <literal>pdf</literal> view with a <literal>return new
        ModelAndView("pdf", map);</literal> and reload the URL in your
        application. This time a PDF document should appear listing each of
        the words in the model map.</para>
      </section>
    </section>
  </section>

  <section id="view-jasper-reports">
    <title>JasperReports</title>

2053 2054 2055 2056 2057 2058
    <para>JasperReports (<ulink
    url="http://jasperreports.sourceforge.net"></ulink>) is a powerful
    open-source reporting engine that supports the creation of report designs
    using an easily understood XML file format. JasperReports is capable of
    rendering reports output into four different formats: CSV, Excel, HTML and
    PDF.</para>
2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070

    <section id="view-jasper-reports-dependencies">
      <title>Dependencies</title>

      <para>Your application will need to include the latest release of
      JasperReports, which at the time of writing was 0.6.1. JasperReports
      itself depends on the following projects:</para>

      <itemizedlist mark="bullet">
        <listitem>
          <para>BeanShell</para>
        </listitem>
2071

2072 2073 2074
        <listitem>
          <para>Commons BeanUtils</para>
        </listitem>
2075

2076 2077 2078
        <listitem>
          <para>Commons Collections</para>
        </listitem>
2079

2080 2081 2082
        <listitem>
          <para>Commons Digester</para>
        </listitem>
2083

2084 2085 2086
        <listitem>
          <para>Commons Logging</para>
        </listitem>
2087

2088 2089 2090
        <listitem>
          <para>iText</para>
        </listitem>
2091

2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
        <listitem>
          <para>POI</para>
        </listitem>
      </itemizedlist>

      <para>JasperReports also requires a JAXP compliant XML parser.</para>
    </section>

    <section id="view-jasper-reports-configuration">
      <title>Configuration</title>

2103 2104 2105 2106 2107
      <para>To configure JasperReports views in your Spring container
      configuration you need to define a
      <interfacename>ViewResolver</interfacename> to map view names to the
      appropriate view class depending on which format you want your report
      rendered in.</para>
2108 2109

      <section id="view-jasper-reports-configuration-resolver">
2110 2111
        <title>Configuring the
        <interfacename>ViewResolver</interfacename></title>
2112

2113 2114 2115 2116 2117 2118 2119
        <para>Typically, you will use the
        <classname>ResourceBundleViewResolver</classname> to map view names to
        view classes and files in a properties file.</para>

        <programlisting language="xml">&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"&gt;
    &lt;property name="basename" value="views"/&gt;
&lt;/bean&gt;</programlisting>
2120

2121 2122 2123 2124 2125
        <para>Here we've configured an instance of the
        <classname>ResourceBundleViewResolver</classname> class that will look
        for view mappings in the resource bundle with base name
        <literal>views</literal>. (The content of this file is described in
        the next section.)</para>
2126 2127 2128 2129 2130
      </section>

      <section id="view-jasper-reports-configuration-views">
        <title>Configuring the <literal>View</literal>s</title>

2131 2132 2133 2134 2135
        <para>The Spring Framework contains five different
        <interfacename>View</interfacename> implementations for JasperReports,
        four of which correspond to one of the four output formats supported
        by JasperReports, and one that allows for the format to be determined
        at runtime:</para>
2136 2137

        <table id="view-jasper-reports-configuration-views-classes">
2138 2139
          <title>JasperReports <interfacename>View</interfacename>
          classes</title>
2140 2141 2142 2143 2144 2145 2146 2147 2148

          <tgroup cols="2">
            <colspec colname="c1" colwidth="1*" />

            <colspec colname="c2" colwidth="1*" />

            <thead>
              <row>
                <entry>Class Name</entry>
2149

2150 2151 2152 2153 2154 2155 2156
                <entry>Render Format</entry>
              </row>
            </thead>

            <tbody>
              <row>
                <entry><classname>JasperReportsCsvView</classname></entry>
2157

2158 2159
                <entry>CSV</entry>
              </row>
2160

2161 2162
              <row>
                <entry><classname>JasperReportsHtmlView</classname></entry>
2163

2164 2165
                <entry>HTML</entry>
              </row>
2166

2167 2168
              <row>
                <entry><classname>JasperReportsPdfView</classname></entry>
2169

2170 2171 2172 2173 2174
                <entry>PDF</entry>
              </row>

              <row>
                <entry><classname>JasperReportsXlsView</classname></entry>
2175

2176 2177
                <entry>Microsoft Excel</entry>
              </row>
2178

2179 2180
              <row>
                <entry><classname>JasperReportsMultiFormatView</classname></entry>
2181 2182 2183 2184

                <entry>The view is <link
                linkend="view-jasper-reports-configuration-multiformat-view">decided
                upon at runtime</link></entry>
2185 2186 2187 2188 2189
              </row>
            </tbody>
          </tgroup>
        </table>

2190 2191 2192
        <para>Mapping one of these classes to a view name and a report file is
        a matter of adding the appropriate entries into the resource bundle
        configured in the previous section as shown here:</para>
2193

2194 2195
        <programlisting>simpleReport.class=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper</programlisting>
2196

2197 2198 2199 2200 2201 2202
        <para>Here you can see that the view with name
        <literal>simpleReport</literal> is mapped to the
        <classname>JasperReportsPdfView</classname> class, causing the output
        of this report to be rendered in PDF format. The
        <literal>url</literal> property of the view is set to the location of
        the underlying report file.</para>
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
      </section>

      <section id="view-jasper-reports-configuration-report-files">
        <title>About Report Files</title>

        <para>JasperReports has two distinct types of report file: the design
        file, which has a <literal>.jrxml</literal> extension, and the
        compiled report file, which has a <literal>.jasper</literal>
        extension. Typically, you use the JasperReports Ant task to compile
        your <literal>.jrxml</literal> design file into a
        <literal>.jasper</literal> file before deploying it into your
2214 2215 2216 2217 2218 2219 2220
        application. With the Spring Framework you can map either of these
        files to your report file and the framework will take care of
        compiling the <literal>.jrxml</literal> file on the fly for you. You
        should note that after a <literal>.jrxml</literal> file is compiled by
        the Spring Framework, the compiled report is cached for the lifetime
        of the application. To make changes to the file you will need to
        restart your application.</para>
2221 2222 2223
      </section>

      <section id="view-jasper-reports-configuration-multiformat-view">
2224 2225 2226 2227 2228 2229 2230 2231
        <title>Using
        <classname>JasperReportsMultiFormatView</classname></title>

        <para>The <classname>JasperReportsMultiFormatView</classname> allows
        for report format to be specified at runtime. The actual rendering of
        the report is delegated to one of the other JasperReports view classes
        - the <classname>JasperReportsMultiFormatView</classname> class simply
        adds a wrapper layer that allows for the exact implementation to be
2232 2233 2234 2235
        specified at runtime.</para>

        <para>The <classname>JasperReportsMultiFormatView</classname> class
        introduces two concepts: the format key and the discriminator key. The
2236 2237 2238 2239 2240
        <classname>JasperReportsMultiFormatView</classname> class uses the
        mapping key to lookup the actual view implementation class and uses
        the format key to lookup up the mapping key. From a coding perspective
        you add an entry to your model with the formay key as the key and the
        mapping key as the value, for example:</para>
2241

2242
        <programlisting language="java">public ModelAndView handleSimpleReportMulti(HttpServletRequest request,
2243 2244 2245 2246 2247 2248 2249 2250 2251
HttpServletResponse response) throws Exception {

  String uri = request.getRequestURI();
  String format = uri.substring(uri.lastIndexOf(".") + 1);

  Map model = getModel();
  model.put("format", format);

  return new ModelAndView("simpleReportMulti", model);
2252
}</programlisting>
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262

        <para>In this example, the mapping key is determined from the
        extension of the request URI and is added to the model under the
        default format key: <literal>format</literal>. If you wish to use a
        different format key then you can configure this using the
        <literal>formatKey</literal> property of the
        <classname>JasperReportsMultiFormatView</classname> class.</para>

        <para>By default the following mapping key mappings are configured in
        <classname>JasperReportsMultiFormatView</classname>:</para>
2263

2264
        <table id="view-jasper-reports-configuration-multiformat-view-mappings">
2265 2266
          <title><classname>JasperReportsMultiFormatView</classname> Default
          Mapping Key Mappings</title>
2267

2268 2269
          <tgroup cols="2">
            <colspec colname="c1" colwidth="1*" />
2270

2271
            <colspec colname="c2" colwidth="1*" />
2272

2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283
            <thead>
              <row>
                <entry>Mapping Key</entry>

                <entry>View Class</entry>
              </row>
            </thead>

            <tbody>
              <row>
                <entry>csv</entry>
2284

2285 2286
                <entry><classname>JasperReportsCsvView</classname></entry>
              </row>
2287

2288 2289
              <row>
                <entry>html</entry>
2290

2291 2292
                <entry><classname>JasperReportsHtmlView</classname></entry>
              </row>
2293

2294 2295
              <row>
                <entry>pdf</entry>
2296

2297 2298
                <entry><classname>JasperReportsPdfView</classname></entry>
              </row>
2299

2300 2301
              <row>
                <entry>xls</entry>
2302

2303 2304 2305 2306 2307
                <entry><classname>JasperReportsXlsView</classname></entry>
              </row>
            </tbody>
          </tgroup>
        </table>
2308

2309 2310 2311 2312 2313
        <para>So in the example above a request to URI /foo/myReport.pdf would
        be mapped to the <literal>JasperReportsPdfView</literal> class. You
        can override the mapping key to view class mappings using the
        <literal>formatMappings</literal> property of
        <classname>JasperReportsMultiFormatView</classname>.</para>
2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324
      </section>
    </section>

    <section id="view-jasper-reports-model">
      <title>Populating the <classname>ModelAndView</classname></title>

      <para>In order to render your report correctly in the format you have
      chosen, you must supply Spring with all of the data needed to populate
      your report. For JasperReports this means you must pass in all report
      parameters along with the report datasource. Report parameters are
      simple name/value pairs and can be added be to the
2325 2326
      <interfacename>Map</interfacename> for your model as you would add any
      name/value pair.</para>
2327 2328 2329

      <para>When adding the datasource to the model you have two approaches to
      choose from. The first approach is to add an instance of
2330 2331 2332 2333 2334 2335 2336
      <classname>JRDataSource</classname> or a
      <interfacename>Collection</interfacename> type to the model
      <interfacename>Map</interfacename> under any arbitrary key. Spring will
      then locate this object in the model and treat it as the report
      datasource. For example, you may populate your model like so:</para>

      <programlisting language="java">private Map getModel() {
2337 2338 2339 2340
  Map model = new HashMap();
  Collection beanData = getBeanData();
  model.put("myBeanData", beanData);
  return model;
2341
}</programlisting>
2342 2343 2344 2345 2346 2347

      <para>The second approach is to add the instance of
      <literal>JRDataSource</literal> or <literal>Collection</literal> under a
      specific key and then configure this key using the
      <literal>reportDataKey</literal> property of the view class. In both
      cases Spring will instances of <literal>Collection</literal> in a
2348 2349 2350 2351
      <literal>JRBeanCollectionDataSource</literal> instance. For
      example:</para>

      <programlisting language="java">private Map getModel() {
2352 2353 2354 2355 2356 2357
  Map model = new HashMap();
  Collection beanData = getBeanData();
  Collection someData = getSomeData();
  model.put("myBeanData", beanData);
  model.put("someData", someData);
  return model;
2358
}</programlisting>
2359

2360 2361 2362 2363 2364
      <para>Here you can see that two <literal>Collection</literal> instances
      are being added to the model. To ensure that the correct one is used, we
      simply modify our view configuration as appropriate:</para>

      <programlisting>simpleReport.class=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
2365
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper
2366
simpleReport.reportDataKey=myBeanData</programlisting>
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395

      <para>Be aware that when using the first approach, Spring will use the
      first instance of <literal>JRDataSource</literal> or
      <literal>Collection</literal> that it encounters. If you need to place
      multiple instances of <literal>JRDataSource</literal> or
      <literal>Collection</literal> into the model then you need to use the
      second approach.</para>
    </section>

    <section id="view-jasper-reports-subreports">
      <title>Working with Sub-Reports</title>

      <para>JasperReports provides support for embedded sub-reports within
      your master report files. There are a wide variety of mechanisms for
      including sub-reports in your report files. The easiest way is to hard
      code the report path and the SQL query for the sub report into your
      design files. The drawback of this approach is obvious - the values are
      hard-coded into your report files reducing reusability and making it
      harder to modify and update report designs. To overcome this you can
      configure sub-reports declaratively and you can include additional data
      for these sub-reports directly from your controllers.</para>

      <section id="view-jasper-reports-subreports-config-reports">
        <title>Configuring Sub-Report Files</title>

        <para>To control which sub-report files are included in a master
        report using Spring, your report file must be configured to accept
        sub-reports from an external source. To do this you declare a
        parameter in your report file like so:</para>
2396 2397 2398 2399 2400 2401

        <programlisting language="xml">&lt;parameter name="ProductsSubReport" class="net.sf.jasperreports.engine.JasperReport"/&gt;</programlisting>

        <para>Then, you define your sub-report to use this sub-report
        parameter:</para>

2402
        <programlisting language="xml">&lt;subreport&gt;
2403 2404 2405 2406 2407 2408 2409 2410 2411
    &lt;reportElement isPrintRepeatedValues="false" x="5" y="25" width="325"
        height="20" isRemoveLineWhenBlank="true" backcolor="#ffcc99"/&gt;
    &lt;subreportParameter name="City"&gt;
        &lt;subreportParameterExpression&gt;&lt;![CDATA[$F{city}]]&gt;&lt;/subreportParameterExpression&gt;
    &lt;/subreportParameter&gt;
    &lt;dataSourceExpression&gt;&lt;![CDATA[$P{SubReportData}]]&gt;&lt;/dataSourceExpression&gt;
    &lt;subreportExpression class="net.sf.jasperreports.engine.JasperReport"&gt;
                  &lt;![CDATA[$P{ProductsSubReport}]]&gt;&lt;/subreportExpression&gt;
&lt;/subreport&gt;</programlisting>
2412 2413 2414

        <para>This defines a master report file that expects the sub-report to
        be passed in as an instance of
2415 2416 2417 2418 2419
        <literal>net.sf.jasperreports.engine.JasperReports</literal> under the
        parameter <literal>ProductsSubReport</literal>. When configuring your
        Jasper view class, you can instruct Spring to load a report file and
        pass into the JasperReports engine as a sub-report using the
        <literal>subReportUrls</literal> property:</para>
2420 2421 2422 2423 2424 2425

        <programlisting language="xml">&lt;property name="subReportUrls"&gt;
    &lt;map&gt;
        &lt;entry key="ProductsSubReport" value="/WEB-INF/reports/subReportChild.jrxml"/&gt;
    &lt;/map&gt;
&lt;/property&gt;</programlisting>
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444

        <para>Here, the key of the <interfacename>Map</interfacename>
        corresponds to the name of the sub-report parameter in th report
        design file, and the entry is the URL of the report file. Spring will
        load this report file, compiling it if necessary, and will pass into
        the JasperReports engine under the given key.</para>
      </section>

      <section id="view-jasper-reports-subreports-config-datasources">
        <title>Configuring Sub-Report Data Sources</title>

        <para>This step is entirely optional when using Spring configure your
        sub-reports. If you wish, you can still configure the data source for
        your sub-reports using static queries. However, if you want Spring to
        convert data returned in your <literal>ModelAndView</literal> into
        instances of <literal>JRDataSource</literal> then you need to specify
        which of the parameters in your <literal>ModelAndView</literal> Spring
        should convert. To do this configure the list of parameter names using
        the <literal>subReportDataKeys</literal> property of the your chosen
2445
        view class: <programlisting language="xml">&lt;property name="subReportDataKeys"
2446
    value="SubReportData"/&gt;</programlisting> Here, the key you supply MUST
2447 2448 2449
        correspond to both the key used in your
        <literal>ModelAndView</literal> and the key used in your report design
        file.</para>
2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
      </section>
    </section>

    <section id="view-jasper-reports-exporter-parameters">
      <title>Configuring Exporter Parameters</title>

      <para>If you have special requirements for exporter configuration -
      perhaps you want a specific page size for your PDF report, then you can
      configure these exporter parameters declaratively in your Spring
      configuration file using the <literal>exporterParameters</literal>
      property of the view class. The <literal>exporterParameters</literal>
2461 2462 2463 2464 2465 2466
      property is typed as <interfacename>Map</interfacename> and in your
      configuration the key of an entry should be the fully-qualified name of
      a static field that contains the exporter parameter definition and the
      value of an entry should be the value you want to assign to the
      parameter. An example of this is shown below:</para>

2467
      <programlisting language="xml">&lt;bean id="htmlReport" class="org.springframework.web.servlet.view.jasperreports.JasperReportsHtmlView"&gt;
2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479
  &lt;property name="url" value="/WEB-INF/reports/simpleReport.jrxml"/&gt;
  &lt;property name="exporterParameters"&gt;
    &lt;map&gt;
      &lt;entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER"&gt;
        &lt;value&gt;Footer by Spring!
          &amp;lt;/td&amp;gt;&amp;lt;td width="50%"&amp;gt;&amp;amp;nbsp; &amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
          &amp;lt;/table&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
        &lt;/value&gt;
      &lt;/entry&gt;
    &lt;/map&gt;
  &lt;/property&gt;
&lt;/bean&gt;</programlisting>
2480 2481 2482 2483

      <para>Here you can see that the
      <classname>JasperReportsHtmlView</classname> is being configured with an
      exporter parameter for
2484 2485 2486 2487
      <literal>net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER</literal>
      which will output a footer in the resulting HTML.</para>
    </section>
  </section>
2488

2489
  <section id="view-feeds">
2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569
    <title>Feed Views</title>

    <para>Both <classname>AbstractAtomFeedView</classname> and
    <classname>AbstractRssFeedView</classname> inherit from the base class
    <classname>AbstractFeedView</classname> and are used to provide Atom and
    RSS Feed views respectfully. They are based on java.net's <ulink
    url="https://rome.dev.java.net">ROME</ulink> project and are located in
    the package
    <literal>org.springframework.web.servlet.view.feed</literal>.</para>

    <para><classname>AbstractAtomFeedView</classname> requires you to
    implement the <methodname>buildFeedEntries</methodname> method and
    optionally override the <methodname>buildFeedMetadata</methodname> method
    (the default implementation is empty), as shown below</para>

    <programlisting language="java">public class SampleContentAtomView extends AbstractAtomFeedView {

  @Override
  protected void buildFeedMetadata(Map&lt;String, Object&gt; model, Feed feed,
                                   HttpServletRequest request) {
      // implementation omitted
  }

  @Override
  protected List&lt;Entry&gt; buildFeedEntries(Map&lt;String, Object&gt; model,
                                         HttpServletRequest request,
                                         HttpServletResponse response) throws Exception {

      // implementation omitted
  }
}</programlisting>

    <para>Similar requirements apply for implementing
    <classname>AbstractRssFeedView</classname>, as shown below</para>

    <programlisting language="java">public class SampleContentAtomView extends AbstractRssFeedView {

  @Override
  protected void buildFeedMetadata(Map&lt;String, Object&gt; model, Channel feed,
                                   HttpServletRequest request) {
    // implementation omitted
  }

  @Override
  protected List&lt;Item&gt; buildFeedItems(Map&lt;String, Object&gt; model,
                                      HttpServletRequest request,
                                      HttpServletResponse response) throws Exception {
    // implementation omitted
  }

}</programlisting>

    <para>The <methodname>buildFeedItems</methodname> and
    <methodname>buildFeedEntires</methodname> pass in the HTTP request in case
    you need to access the Locale. The HTTP response is passed in only for the
    setting of cookies or other HTTP headers. The feed will automatically be
    written to the response object after the method returns.</para>

    <para>For an example of creating a Atom view please refer to Alef
    Arendsen's SpringSource TeamBlog <ulink
    url="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/">entry</ulink>.</para>
  </section>

  <section>
    <title>XML Marshalling View</title>

    <para>The <classname>MarhsallingView</classname> uses a XML
    <interfacename>Marshaller</interfacename> defined in the
    <classname>org.springframework.oxm</classname> package to render the
    response content as XML. The object to be marshalled can be set explicitly
    using <classname>MarhsallingView</classname>'s
    <property>modelKey</property> bean property. Alternatively, the view will
    iterate over all model properties marhsall only those types that are
    supported by the <interfacename>Marshaller</interfacename>. For more
    information on the functionality in the
    <classname>org.springframework.oxm</classname> package refer to the
    chapter <link linkend="oxm">Marshalling XML using O/X
    Mappers</link>.</para>
  </section>
</chapter>