Skip to content

Commit

Permalink
Revised documentation for PDF, Excel and JSON views
Browse files Browse the repository at this point in the history
Issue: SPR-17180
Issue: SPR-17182
  • Loading branch information
jhoeller committed Aug 14, 2018
1 parent de38af6 commit c0c9e08
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public void setExtractValueFromSingleKeyModel(boolean extractValueFromSingleKeyM
* Filter out undesired attributes from the given model.
* The return value can be either another {@link Map} or a single value object.
* <p>The default implementation removes {@link BindingResult} instances and entries
* not included in the {@link #setModelKeys renderedAttributes} property.
* not included in the {@link #setModelKeys modelKeys} property.
* @param model the model, as passed on to {@link #renderMergedOutputModel}
* @return the value to be rendered
*/
Expand Down
211 changes: 42 additions & 169 deletions src/docs/asciidoc/web/webmvc-view.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ extensive set of features that will make such a transition easier. Thymeleaf is
developed and maintained. For a more complete introduction see the
http://www.thymeleaf.org/[Thymeleaf] project home page.

The Thymeleaf integration with Spring MVC is managed by the Thymeleaf project. The
configuration involves a few bean declarations such as
The Thymeleaf integration with Spring MVC is managed by the Thymeleaf project.
The configuration involves a few bean declarations such as
`ServletContextTemplateResolver`, `SpringTemplateEngine`, and `ThymeleafViewResolver`.
See http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] for more details.

Expand Down Expand Up @@ -941,9 +941,8 @@ The preceding JSP assumes that the variable name of the form backing object is
==== The input tag

This tag renders an HTML 'input' tag using the bound value and type='text' by default.
For an example of this tag, see <<mvc-view-jsp-formtaglib-formtag>>. Starting with Spring
3.1 you can use other types such HTML5-specific types like 'email', 'tel', 'date', and
others.
For an example of this tag, see <<mvc-view-jsp-formtaglib-formtag>>. You may also use
HTML5-specific types like 'email', 'tel', 'date', and others.


[[mvc-view-jsp-formtaglib-checkboxtag]]
Expand Down Expand Up @@ -1563,12 +1562,12 @@ The corresponding `@Controller` method is shown below:
[[mvc-view-jsp-formtaglib-html5]]
==== HTML5 tags

Starting with Spring 3, the Spring form tag library allows entering dynamic attributes,
which means you can enter any HTML5 specific attributes.
The Spring form tag library allows entering dynamic attributes, which means you can
enter any HTML5 specific attributes.

In Spring 3.1, the form input tag supports entering a type attribute other than 'text'.
This is intended to allow rendering new HTML5 specific input types such as 'email',
'date', 'range', and others. Note that entering type='text' is not required since 'text'
The form input tag supports entering a type attribute other than 'text'. This is
intended to allow rendering new HTML5 specific input types such as 'email', 'date',
'range', and others. Note that entering type='text' is not required since 'text'
is the default type.


Expand Down Expand Up @@ -1801,7 +1800,6 @@ Similar requirements apply for implementing `AbstractRssFeedView`, as shown belo
HttpServletRequest request, HttpServletResponse response) throws Exception {
// implementation omitted
}
}
----

Expand All @@ -1822,7 +1820,7 @@ https://spring.io/blog/2009/03/16/adding-an-atom-view-to-an-application-using-sp


[[mvc-view-document-intro]]
=== Introduction
=== Introduction to document views

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
Expand All @@ -1843,166 +1841,45 @@ vulnerability for untrusted PDF content.



[[mvc-view-document-config]]
=== Configuration

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).



[[mvc-view-document-configviews]]
=== View definition

First, 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:

[literal]
[subs="verbatim,quotes"]
----
home.(class)=xslt.HomePage
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
home.root=words
xl.(class)=excel.HomePage
pdf.(class)=pdf.HomePage
----

__If you want to start with a template spreadsheet or a fillable PDF form to add your
model data to, specify the location as the 'url' property in the view definition__



[[mvc-view-document-configcontroller]]
=== Controller

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!



[[mvc-view-document-configsubclasses]]
=== Excel views

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
`org.springframework.web.servlet.view.document.AbstractExcelView` (for Excel files
generated by POI) or `org.springframework.web.servlet.view.document.AbstractJExcelView`
(for JExcelApi-generated Excel files) and implementing the `buildExcelDocument()` method.

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:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
package excel;
// 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 < words.size(); i++) {
cell = getCell(sheet, 2+i, 0);
setText(cell, (String) words.get(i));
}
}
}
----
[[mvc-view-document-pdf]]
=== PDF views

And the following is a view generating the same Excel file, now using JExcelApi:
A simple PDF view for a word list could extend
`org.springframework.web.servlet.view.document.AbstractPdfView` and implement the
`buildPdfDocument()` method as follows:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
package excel;
public class PdfWordList extends AbstractPdfView {
// imports omitted for brevity
public class HomePage extends AbstractJExcelView {
protected void buildExcelDocument(Map model, WritableWorkbook wb,
protected void buildPdfDocument(Map<String, Object> model, Document doc, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response) throws Exception {
WritableSheet sheet = wb.createSheet("Spring", 0);
sheet.addCell(new Label(0, 0, "Spring-Excel test"));
List words = (List) model.get("wordList");
for (int i = 0; i < words.size(); i++) {
sheet.addCell(new Label(2+i, 0, (String) words.get(i)));
List<String> words = (List<String>) model.get("wordList");
for (String word : words) {
doc.add(new Paragraph(word));
}
}
}
----

Note the differences between the APIs. We've found that the JExcelApi is somewhat more
intuitive, and furthermore, JExcelApi has slightly better image-handling capabilities.
There have been memory problems with large Excel files when using JExcelApi however.

If you now amend the controller such that it returns `xl` as the name of the view (
`return new ModelAndView("xl", map);`) 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.
A controller may return such a view either from an external view definition
(referencing it by name) or as a `View` instance from the handler method.



[[mvc-view-document-configsubclasspdf]]
=== PDF views

The PDF version of the word list is even simpler. This time, the class extends
`org.springframework.web.servlet.view.document.AbstractPdfView` and implements the
`buildPdfDocument()` method as follows:

[source,java,indent=0]
[subs="verbatim,quotes"]
----
package pdf;
// 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<words.size(); i++) {
doc.add( new Paragraph((String) words.get(i)));
}
}
[[mvc-view-document-pdf]]
=== Excel views

}
----
Since Spring Framework 4.2,
`org.springframework.web.servlet.view.document.AbstractXlsView` is provided as a base
class for Excel views based on POI, with specialized subclasses `AbstractXlsxView`
and `AbstractXlsxStreamingView`, superseding the outdated `AbstractExcelView` class.

Once again, amend the controller to return the `pdf` view with `return new
ModelAndView("pdf", map);`, and reload the URL in your application. This time a PDF
document should appear listing each of the words in the model map.
The programming model is similar to `AbstractPdfView`, with `buildExcelDocument()`
as the central template method and controllers being able to return such a view from
an external definition (by name) or as a `View` instance from the handler method.



Expand All @@ -2014,16 +1891,16 @@ document should appear listing each of the words in the model map.


[[mvc-view-json-mapping]]
=== JSON
=== Jackson-based JSON views
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same in Spring WebFlux>>#

The `MappingJackson2JsonView` uses the Jackson library's `ObjectMapper` to render the response
content as JSON. By default, the entire contents of the model map (with the exception of
framework-specific classes) will be encoded as JSON. For cases where the contents of the
map need to be filtered, users may specify a specific set of model attributes to encode
via the `RenderedAttributes` property. The `extractValueFromSingleKeyModel` property may
also be used to have the value in single-key models extracted and serialized directly
rather than as a map of model attributes.
via the `modelKeys` property. The `extractValueFromSingleKeyModel` property may also be
used to have the value in single-key models extracted and serialized directly rather than
as a map of model attributes.

JSON mapping can be customized as needed through the use of Jackson's provided
annotations. When further control is needed, a custom `ObjectMapper` can be injected
Expand All @@ -2033,7 +1910,7 @@ serializers/deserializers need to be provided for specific types.


[[mvc-view-xml-mapping]]
=== XML
=== Jackson-based XML views
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same in Spring WebFlux>>#

The `MappingJackson2XmlView` uses the
Expand All @@ -2051,11 +1928,11 @@ serializers/deserializers need to be provided for specific types.


[[mvc-view-xml-marshalling]]
== XML
== XML marshalling

The `MarshallingView` uses an XML `Marshaller` defined in the `org.springframework.oxm`
package to render the response content as XML. The object to be marshalled can be set
explicitly using ``MarhsallingView``'s `modelKey` bean property. Alternatively, the view
explicitly using ``MarshallingView``'s `modelKey` bean property. Alternatively, the view
will iterate over all model properties and marshal the first type that is supported
by the `Marshaller`. For more information on the functionality in the
`org.springframework.oxm` package refer to the chapter
Expand All @@ -2065,7 +1942,7 @@ by the `Marshaller`. For more information on the functionality in the


[[mvc-view-xslt]]
== XSLT
== XSLT views

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
Expand All @@ -2084,9 +1961,8 @@ document ready for transformation.
[[mvc-view-xslt-beandefs]]
=== Beans

Configuration is standard for a simple Spring application.
The MVC configuration has to define a `XsltViewResolver` bean and
regular MVC annotation configuration.
Configuration is standard for a simple Spring web application: The MVC configuration
has to define an `XsltViewResolver` bean and regular MVC annotation configuration.

[source,java,indent=0]
[subs="verbatim,quotes"]
Expand All @@ -2103,7 +1979,6 @@ public class WebConfig implements WebMvcConfigurer {
viewResolver.setSuffix(".xslt");
return viewResolver;
}
}
----

Expand All @@ -2115,7 +1990,7 @@ And we need a Controller that encapsulates our word generation logic.
=== Controller

The controller logic is encapsulated in a `@Controller` class, with the
handler method being defined like so...
handler method being defined as follows:

[source,java,indent=0]
[subs="verbatim,quotes"]
Expand All @@ -2125,7 +2000,6 @@ handler method being defined like so...
@RequestMapping("/")
public String home(Model model) throws Exception {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element root = document.createElement("wordList");
Expand All @@ -2140,7 +2014,6 @@ handler method being defined like so...
model.addAttribute("wordList", root);
return "home";
}
}
----

Expand Down

0 comments on commit c0c9e08

Please sign in to comment.