Spring Content Negotiation
June 24, 2019
This page will walk through Spring content negotiation example with AbstractExcelView, AbstractPdfView, MappingJackson2JsonView and MappingJackson2XmlView. Content Negotiation is determining view on the basis of media type of user request. Media types can be determined by file extension, "Accept" header or a request parameter. First priority is file extension then "Accept" header etc. There will also be a fall back for default content type. In our example the user will have only one URL but different file extension in URL. We are handling here .xls, .pdf, .json, .xml and .html. If no extension is provided default view will be as html. AbstractExcelView and AbstractPdfView will handle view for excel and PDF respectively. MappingJackson2JsonView and MappingJackson2XmlView will handle view for JSON and XML respectively.
Software Used
Find the software used in our demo.1. Java 7
2. Spring 4.1.6
3. Gradle
4. Eclipse
5. Tomcat 8
Project Structure in Eclipse
Find the project structure in eclipse.build.gradle
Find the build file.build.gradle
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'war' archivesBaseName = 'Spring4' version = '1' repositories { mavenCentral() } dependencies { compile 'org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE' compile 'com.lowagie:itext:4.2.1' compile 'org.apache.poi:poi:3.13' compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.6.2' compile 'org.codehaus.woodstox:woodstox-core-asl:4.4.1' compile 'jstl:jstl:1.2' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.2.3.RELEASE' }
JavaConfig: Define configureContentNegotiation() and configureViewResolvers()
Find the JavaConfig which is defining configureContentNegotiation() and configureViewResolvers() methods.AppConfiguration.java
package com.concretepage.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.json.MappingJackson2JsonView; import org.springframework.web.servlet.view.xml.MappingJackson2XmlView; import com.concretepage.view.ContentExcelView; import com.concretepage.view.ContentPdfView; @Configuration @ComponentScan("com.concretepage") @EnableWebMvc public class AppConfiguration extends WebMvcConfigurerAdapter { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.ignoreUnknownPathExtensions(false).defaultContentType(MediaType.TEXT_HTML); } @Override public void configureViewResolvers(ViewResolverRegistry registry) { MappingJackson2JsonView jsonView = new MappingJackson2JsonView(); jsonView.setPrettyPrint(true); MappingJackson2XmlView xmlView = new MappingJackson2XmlView(); xmlView.setPrettyPrint(true); registry.enableContentNegotiation(jsonView, xmlView, new ContentExcelView(), new ContentPdfView()); registry.jsp("/WEB-INF/view/", ".jsp"); } }
package com.concretepage.config; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class Initializer implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(AppConfiguration.class); ctx.setServletContext(servletContext); Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx)); dynamic.addMapping("/"); dynamic.setLoadOnStartup(1); } }
AbstractExcelView for Excel
ContentExcelView.javapackage com.concretepage.view; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.springframework.web.servlet.view.document.AbstractExcelView; import com.concretepage.bean.MyContent; public class ContentExcelView extends AbstractExcelView { @Override protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception { HSSFSheet sheet = workbook.createSheet("My Content"); Row row = sheet.createRow(0); CellStyle style = workbook.createCellStyle(); style.setFillBackgroundColor(IndexedColors.YELLOW.getIndex()); style.setFillPattern(CellStyle.ALIGN_FILL); Font font = workbook.createFont(); font.setColor(IndexedColors.RED.getIndex()); style.setFont(font); Cell cell1 = row.createCell(0); cell1.setCellValue("ID"); cell1.setCellStyle(style); Cell cell2 = row.createCell(1); cell2.setCellValue("TITLE"); cell2.setCellStyle(style); Cell cell3 = row.createCell(2); cell3.setCellValue("DESCRIPTION"); cell3.setCellStyle(style); Cell cell4 = row.createCell(3); cell4.setCellValue("PUBDATE"); cell4.setCellStyle(style); Cell cell5 = row.createCell(4); cell5.setCellValue("LINK"); cell5.setCellStyle(style); Object ob = model.get("contents"); if (ob instanceof List){ for(int i = 0; i < ((List<?>)ob).size(); i++){ Object feedObj = ((List<?>) ob).get(i); MyContent myContent = (MyContent)feedObj; row = sheet.createRow(i+1); cell1 = row.createCell(0); cell1.setCellValue(myContent.getId()); cell2 = row.createCell(1); cell2.setCellValue(myContent.getTitle()); cell3 = row.createCell(2); cell3.setCellValue(myContent.getDescription()); cell4 = row.createCell(3); cell4.setCellValue(myContent.getPubDate()); cell5 = row.createCell(4); cell5.setCellValue(myContent.getLink()); } } } }
AbstractPdfView for PDF
ContentPdfView.javapackage com.concretepage.view; import java.awt.Color; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.view.document.AbstractPdfView; import com.concretepage.bean.MyContent; import com.lowagie.text.Document; import com.lowagie.text.Element; import com.lowagie.text.Rectangle; import com.lowagie.text.pdf.PdfPTable; import com.lowagie.text.pdf.PdfWriter; public class ContentPdfView extends AbstractPdfView{ @Override protected void buildPdfMetadata(Map<String, Object> model, Document document, HttpServletRequest request) { Rectangle rec = new Rectangle(600, 800); document.setPageSize(rec); document.setPageCount(1); } @Override protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { PdfPTable table = new PdfPTable(5); table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER); table.getDefaultCell().setVerticalAlignment(Element.ALIGN_MIDDLE); table.getDefaultCell().setBackgroundColor(Color.CYAN); Object ob = model.get("contents"); if (ob instanceof List){ for(int i = 0; i < ((List<?>)ob).size(); i++){ Object feedObj = ((List<?>) ob).get(i); MyContent myContent = (MyContent)feedObj; table.addCell(myContent.getId()); table.addCell(myContent.getTitle()); table.addCell(myContent.getDescription()); table.addCell(myContent.getPubDate().toString()); table.addCell(myContent.getLink()); } } table.completeRow(); document.add(table); } }
Bean
MyContent.javapackage com.concretepage.bean; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.springframework.stereotype.Repository; @Repository public class MyContent { private String id; private String title; private String description; private Date pubDate; private String link; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public List<MyContent> createContent() { List<MyContent> feeds = new ArrayList<>(); MyContent feed1 = new MyContent(); feed1.setId("100"); feed1.setTitle("Title one"); feed1.setDescription("This is description one"); feed1.setLink("http://www.urlone.com"); feed1.setPubDate(new Date()); feeds.add(feed1); MyContent feed2 = new MyContent(); feed2.setId("200"); feed2.setTitle("Title two"); feed2.setDescription("This is description two"); feed2.setLink("http://www.urltwo.com"); feed2.setPubDate(new Date()); feeds.add(feed2); return feeds; } }
MappingJackson2JsonView for JSON
For JSON content type, we will configure MappingJackson2JsonView
in our JavaConfig creating its instance as below.
MappingJackson2JsonView jsonView = new MappingJackson2JsonView(); jsonView.setPrettyPrint(true);
MappingJackson2XmlView for XML
For XML content type, we will configureMappingJackson2XmlView
in our JavaConfig creating its instance as below.
MappingJackson2XmlView xmlView = new MappingJackson2XmlView(); xmlView.setPrettyPrint(true);
View for HTML
result.jsp<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <title>Spring 4 Content Negotiation Example</title> <body> <table> <c:forEach items="${contents}" var="element"> <tr> <td>${element.id}</td> <td>${element.title}</td> <td>${element.description}</td> <td>${element.pubDate}</td> <td>${element.link}</td> </tr> </c:forEach> </table> </body> </html>
Controller Class
ContentController.javapackage com.concretepage.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import com.concretepage.bean.MyContent; @Controller public class ContentController { @Autowired private MyContent myContent; @RequestMapping(value="/content", method=RequestMethod.GET) public ModelAndView getContent() { ModelAndView mav = new ModelAndView(); mav.setViewName("result"); mav.addObject("contents", myContent.createContent()); return mav; } }
Output
1. URL for Excel http://localhost:8080/Spring4-1/content.xls2. URL for PDF http://localhost:8080/Spring4-1/content.pdf
3. URL for JSON http://localhost:8080/Spring4-1/content.json
4. URL for XML http://localhost:8080/Spring4-1/content.xml
5. URL for HTML http://localhost:8080/Spring4-1/content.html
or http://localhost:8080/Spring4-1/content