Monday 4 December 2017

Tile Integration with Spring


Tile integration with Spring.



My System configuration:

Windows 10
Spring Tool Suite
Platform: Eclipse Neon.1 (4.6.1)
java version "1.8.0_131"




To create Tile Integration with Spring we have to follow these steps:




1)Create a maven project




2)Select Maven project





3) Select option create a simple project(skip archetype selection)







4) Give group id and artifact id and some extra details and then finish.








After this step our maven project will be created but showing some error.
One error is inside pom.xml





*Note: This image is for explanation purpose only, value of tag may be different from current project.
           Please follow only error part and how to remove.



If u hold your mouse on cross sign/error place then u can see this





and the message is:
                             web.xml is missing and <failOnMissingWebXml> is set to true

To avoid this problem we have to add some code in pom.xml (I will show u shortly).

Second thing is not an error but it is showing older version of Deployment Descriptor. We have to change this too.



Now my pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.asif.tile</groupId>
  <artifactId>TileSpringIntegration</artifactId>
  <version>0.1</version>
  <packaging>war</packaging>
  <name>Tile Integration with Spring</name>
  <description>In this project I am integrating tile with spring4</description>
  
  <properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <jdk.version>1.8</jdk.version> 
  <spring.version>4.3.10.RELEASE</spring.version>
  <maven.compiler.version>3.1</maven.compiler.version>
  <maven.war.version>2.6</maven.war.version>
  <javax.validation.constraint.version>2.0.0.Final</javax.validation.constraint.version>
  </properties>
  
  <build>
     <plugins>
         <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>${maven.compiler.version}</version>
          <configuration>
              <source>${jdk.version}</source>
              <target>${jdk.version}</target>
          </configuration>
      </plugin>
     
      <!-- To avoid web.xml error -->
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-war-plugin</artifactId>
             <version>${maven.war.version}</version>
             <configuration>
                 <failOnMissingWebXml>false</failOnMissingWebXml>
             </configuration>
         </plugin>
     </plugins>
   </build>

<dependencies>

<dependency>
     <groupId>jstl</groupId>
     <artifactId>jstl</artifactId>
     <version>1.2</version>
</dependency>

<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
</dependency>

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>${spring.version}</version>
</dependency>
 
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>${spring.version}</version>
</dependency>
 
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>${spring.version}</version>
</dependency>
 
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-test</artifactId>
     <version>${spring.version}</version>
     <scope>test</scope>
</dependency>
 
<dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.12</version>
     <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.6</version>
</dependency>
 
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>4.3.10.RELEASE</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>
 
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>${javax.validation.constraint.version}</version>
</dependency>

<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>3.0.7</version>
</dependency>
 
</dependencies>

</project>



After saving pom.xml you have to upate maven project.
Even after this if you observe deployment descriptor still it is showing old version like this


*Note: This image is for explanation purpose only, value of tag may be different from current project.

           Please follow only error part and how to remove.




To change it to latest version we have to close project and then open again.

Now once I closed project and open again then you can see change






*Note: This image is for explanation purpose only, value of tag may be different from current project.
           Please follow only error part and how to remove.


You can check that now Deployment descriptor becomes 3.1 previously it was 2.5.


Simply maven update your project.
Now our project is created and having no error.


We will see our coding part now.
In this project for all configurations we are using Java class only, no xml file.


First we will create TileWebConfig class in which we will do configuration of our tile.
Here is our class


package org.asif.tile.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

@Configuration
@EnableWebMvc //Enable Spring MVC
@ComponentScan("org.asif.tile.web") //Enable component-scanning
public class TileWebConfig extends WebMvcConfigurerAdapter{

@Bean
public TilesConfigurer tilesConfigurer(){
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[]{"/WEB-INF/layout/tiles.xml"});
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}


@Bean
public ViewResolver viewResolver() {
return new TilesViewResolver();
}

//configure static content handling
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}

}


*NOTE: If you change your package name then please don't forget to change 
@ComponentScan("Here please give your package name")

If you forgot to change package name or any miss match to provide proper package then may be project deploy and you can see your project in tomcat manager but if you try to access your project it gives you error that path not found.
Please take care of this.

tilesConfigurer.setDefinitions(new String[]{"/WEB-INF/layout/tiles.xml"});
This is the place where I have to keep my tiles.xml file.



Spring web Initialize class 

package org.asif.tile.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class TileSpringIntegrationWebAppInitializer  extends AbstractAnnotationConfigDispatcherServletInitializer{

@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}

//Specify configuration class
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{TileWebConfig.class};
}

//Map DispatcherServlet to /
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}

}




RootConfig class

package org.asif.tile.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages={"org.asif.tile"}, excludeFilters={@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {

}



tilesConfigurer.setDefinitions(new String[]{"/WEB-INF/layout/tiles.xml"});
This is the place where I have to keep my tiles.xml file.

First we have to create folder "WEB-INF" inside webapp folder and then "layout" folder.


tiles.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN" "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<definition name="base" template="/WEB-INF/layout/page.jsp">
<put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
<put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
</definition>
<definition name="home" extends="base">
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />
</definition>
<definition name="registerForm" extends="base">
<put-attribute name="body" value="/WEB-INF/views/register-form.jsp" />
</definition>
</tiles-definitions> 


Explanation:
Here we are adding one header and one footer page inside "page.jsp" and passing our required jsp page as body.

<definition name="base" template="/WEB-INF/layout/page.jsp">
<put-attribute name="header" value="/WEB-INF/layout/header.jsp" />
<put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />
</definition>

Above page.jsp page behave as base page for all where we included header and footer.jsp.

<definition name="home" extends="base">
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />
</definition>

In this tag we extends our base page where we already included header and footer.jsp and then redirect to our required jsp page.
here we are redirecting to home.jsp.

Now we will discuss our page.jsp

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="t" %>
<%@ page session="false" %>

<html>
<head>
<title>Spittr</title>
<link rel="stylesheet" type="text/css" href="<s:url value="/resources/style.css" />" >
</head>
<body>
<div id="header">
<t:insertAttribute name="header" />
</div>
<div id="content">
<t:insertAttribute name="body" />
</div>
<div id="footer">
<t:insertAttribute name="footer" />
</div>
</body>
</html>


Explanation

<div id="header">
<t:insertAttribute name="header" />
</div>

Including header part
header attribute coming from tiles.xml file

<put-attribute name="header" value="/WEB-INF/layout/header.jsp" />



<div id="footer">
<t:insertAttribute name="footer" />
</div>

including footer part:
this is attribute name="footer" from tiles.xml file
<put-attribute name="footer" value="/WEB-INF/layout/footer.jsp" />

for body 

<div id="content">
<t:insertAttribute name="body" />
</div>

attribute from tiles.xml
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />


header.jsp
<h2>Header.jsp</h2>

footer.jsp
<h2>Footer.jsp</h2>


path of footer.jsp, header.jsp, page.jsp and tiles.xml is

/webapp/WEB-INF/layout/



Now we will create our controller class


package org.asif.tile.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {

@RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView myModelMethod(Model model){
    ModelAndView mav = new ModelAndView("home");
    return mav;
    }
@RequestMapping(value="/registerform", method=RequestMethod.GET)
public ModelAndView registerForm(){
ModelAndView mav = new ModelAndView("registerForm");
    return mav;
}
}

ModelAndView mav = new ModelAndView("home");

here "home" must match with tiles.xml file name="home" tag.


<definition name="home" extends="base">
<put-attribute name="body" value="/WEB-INF/views/home.jsp" />
</definition>

here "home" view set in ModelAndView class view name will match with tiles.xml <definition name="home"
and our view will be <put-attribute name="body" value="/WEB-INF/views/home.jsp" />, home.jsp.

Here header and footer already added in page.jsp and that jsp we are using as base in tiles. 
So whenever we return a view from our controller will be added by header and footer jsp page.



home.jsp


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<h1>Welcome Tile Integration</h1>

<a href="<c:url value="/registerform" />">Register</a>

its simple jsp where I am redirecting to other page, this first hit our controller and from controller we are going to decide which has to choose.


package org.asif.tile.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HomeController {

@RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView myModelMethod(Model model){
    ModelAndView mav = new ModelAndView("home");
    return mav;
    }
@RequestMapping(value="/registerform", method=RequestMethod.GET)
public ModelAndView registerForm(){
ModelAndView mav = new ModelAndView("registerForm");
    return mav;
}
}


url : http://localhost:8080/TileSpringIntegration/

where 8080 depends on your tomcat port

myModelMethod() -> this method will hit on this url:  http://localhost:8080/TileSpringIntegration/

my home jsp page in browser



Where Header.jsp and Footer.jsp are added automatically.

path of home and register-form.jsp :   /webapp/WEB-INF/views

content of home.jsp

Welcome Tile Integration

Register


this home.jsp as return from controller as view and added as a body in the page using tile.

When we click Register link in home page then we will hit 

@RequestMapping(value="/registerform", method=RequestMethod.GET)
public ModelAndView registerForm(){
ModelAndView mav = new ModelAndView("registerForm");
     return mav;
}

and will hit tiles.xml file


<definition name="registerForm" extends="base">
<put-attribute name="body" value="/WEB-INF/views/register-form.jsp" />
</definition>

now it would redirect to register-form.jsp 

register-form.jsp content.

<h1>Register Form jsp</h1>