Skip to content

kipcd/spring-portlet-example

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 

Repository files navigation

This repository contains a simple spring portlet. It is intended as a step by step tutorial.

  1. Create a new maven web application project. Maven archetype can be used to generate the application (e.g. com.liferay.maven.archetypes:liferay-portlet-archetype). mvn archetype:generate
  2. Add dependencies on Spring into pom.xml.
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc-portlet</artifactId>
  <version>3.2.6.RELEASE</version>
</dependency>
  1. Insert spring initalization code inot web.xml.
  • Insert spring context listener
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  • Specify the application spring configuration file location
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-context/portlet-application-context.xml</param-value>
    </context-param>
  • Add servlet for view processing
    <servlet>
        <servlet-name>ViewRendererServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>ViewRendererServlet</servlet-name>
        <url-pattern>/WEB-INF/servlet/view</url-pattern>
    </servlet-mapping>
  1. Create the application configuration file portlet-application-context.xml.
  2. Activate annotation and configure view resolver in main context file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!--Enables @Autowired annotation-->
    <context:annotation-config/>

    <!-- Spring MVC VIEW Configuration -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="contentType" value="text/html;charset=UTF-8" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>
  1. Define spring portlet
  • Define portlet in portlet.xml
  <portlet>
      <portlet-name>BasicSpringPortlet</portlet-name>
      <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
      <init-param>
          <name>contextConfigLocation</name>
          <value>/WEB-INF/spring-context/portlet/basic-spring-portlet.xml</value>
      </init-param>
      <supports>
          <mime-type>text/html</mime-type>
          <portlet-mode>VIEW</portlet-mode>
      </supports>
      <supported-locale>en</supported-locale>
      <supported-locale>cs</supported-locale>
      <resource-bundle>content.basic-spring-portlet</resource-bundle>
  </portlet>
  • Configure portlet in liferay-portlet.xml
  <portlet>
      <portlet-name>BasicSpringPortlet</portlet-name>
      <instanceable>false</instanceable>
      <header-portlet-css>/css/main.css</header-portlet-css>
      <header-portlet-javascript>/js/main.js</header-portlet-javascript>
  </portlet>
  • Configure portlet in liferay-display.xml

     <category name="category.sample">
           <portlet id="BasicSpringPortlet" />
     </category>
    
  • Create portlet spring context file

     <?xml version="1.0" encoding="UTF-8"?>
     <!--suppress SpringFacetInspection -->
     <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     
         <!-- Spring MVC Message Source -->
         <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
             <property name="useCodeAsDefaultMessage" value="true"/>
             <property name="basenames">
                 <list>
                     <value>content.basic-spring-portlet</value>
                 </list>
             </property>
         </bean>
     
     </beans>
    
  • Create resource bundles

  1. Create Spring Controller
package eu.ibacz.sample.portlet.bascispring;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.portlet.bind.annotation.RenderMapping;

/**
 * This class is base controller for VIEW mode.
 */
@Controller
@RequestMapping("VIEW")
public class BasicSpringPortletViewController {


    @RenderMapping
    public String doView() {
        return BasicSpringPortletConstants.MAIN_VIEW;
    }


}
  1. Create view - view.jsp
  2. Add component scan to spring portlet configuration.
 <context:component-scan base-package="eu.ibacz.sample.portlet.bascispring.**"/>
  1. Add a simple form to jsp file.
<%@ page import="eu.ibacz.sample.portlet.bascispring.BasicSpringPortletConstants" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0" %>

<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<c:set var="ns"><portlet:namespace/></c:set>

<spring:message code="basicspring-question"/>
<br/>
<portlet:actionURL var="actionUrl" name="<%=BasicSpringPortletConstants.TEST_ACTION%>"/>
<form action="${actionUrl}" method="POST">
    <input type="text" name="${ns}<%=BasicSpringPortletConstants.NAME_PARAM%>">
    <input type="submit" value="<spring:message code="basicspring-submit"/>" />
</form>
  1. Handle the form data in controler.
    @ActionMapping(BasicSpringPortletConstants.TEST_ACTION)
    public void doAction(@RequestParam(BasicSpringPortletConstants.NAME_PARAM) String name) {
        LOG.warn("I've got name " + name);
    }
  1. Add a greetings view.
  • Add additional render method to the controller
  @RenderMapping(params = PARAM_VIEW + "=" + GREETING)
  public String greeting(
          @RequestParam(NAME_PARAM) String name,
          Model model) {
      model.addAttribute(NAME_PARAM,name);
      return GREETING_VIEW;
  }

  @ActionMapping(TEST_ACTION)
  public void doAction(ActionRequest request, ActionResponse response) {
      LOG.warn("Processing name.");

      //order if these lines is important!
      response.setRenderParameters(request.getParameterMap());
      response.setRenderParameter(PARAM_VIEW, GREETING);
  }
  • Add greetings.jsp
 <%@page contentType="text/html" pageEncoding="UTF-8" %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <%@ taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0" %>
 
 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
 
 
 <spring:message code="basicspring-greeting"/>&nbsp;<b><c:out value="${name}"/></b>!!!
 <br/>
 <a href="<portlet:renderURL />"><spring:message code="basicspring-back"/> </a>
  1. Create transfer object PersonPto
  public class PersonPto {
     private String name;
     private DateTime dateOfBirth;
 
     public DateTime getDateOfBirth() {
         return dateOfBirth;
     }
 
     public void setDateOfBirth(DateTime dateOfBirth) {
         this.dateOfBirth = dateOfBirth;
     }
 
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this.name = name;
     }
 
     @Override
     public String toString() {
         return "PersonPto{" +
                 "dateOfBirth=" + dateOfBirth +
                 ", name='" + name + '\'' +
                 "} " + super.toString();
     }
 }
  1. Switch from parameters to model attribute.
@ActionMapping(TEST_ACTION)
   public void doAction(
           @ModelAttribute(PERSON_PTO) PersonPto personPto,
           BindingResult result,
           ActionResponse response) {
       LOG.warn("Processing person " + personPto);

       response.setRenderParameter(PARAM_VIEW, GREETING);
   }
  1. Register InitBinder for joda time.
    @InitBinder
   public void initBinder(WebDataBinder binder) {
       binder.registerCustomEditor(DateTime.class, new JodaDateEditor(DATE_TIME_PATTERN));
   }
  1. Change the simple form to spring form.
<portlet:actionURL var="actionUrl" name="<%=TEST_ACTION%>"/>
<form:form action="${actionUrl}" method="POST" modelAttribute="<%=PERSON_PTO%>">
   <p>
       <form:label path="name" for="${ns}name"><spring:message code="basicspring-form-name"/></form:label>
       <form:input path="name" id="${ns}name"/>
   </p>
   <p>
       <form:label path="dateOfBirth" for="${ns}dateOfBirth"><spring:message code="basicspring-form-date-of-birth"/></form:label>
       <form:input path="dateOfBirth" id="${ns}dateOfBirth"/>
   </p>

   <input type="submit" value="<spring:message code="basicspring-submit"/>" />
</form:form>
  1. Calculate days till birthday.
    private Integer daysToBirthday(DateTime dateOfBirth) {
       DateTime now = (new DateTime()).withTimeAtStartOfDay();
       int year = now.getYear();
       DateTime birthday = dateOfBirth.withYear(year);
       if (birthday.isBeforeNow()) {
           birthday = birthday.plusYears(1);
       }
       return Days.daysBetween(now, birthday).getDays();
   }
  1. Add validation
  • Create Validator
  @Component
 public class PersonPtoValidator implements Validator {
     private static final DateTime minDate = DateTime.now().minusYears(130);
     private static final DateTime maxDate = DateTime.now().plusYears(130);
 
     @Override
     public boolean supports(Class<?> clazz) {
         return PersonPtoValidator.class.isAssignableFrom(clazz);
     }
 
     @Override
     public void validate(Object target, Errors errors) {
         ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "basicspring-err-null-value");
         ValidationUtils.rejectIfEmptyOrWhitespace(errors, "dateOfBirth", "basicspring-err-null-value");
         if (!errors.hasErrors()) {
             PersonPto personPto = (PersonPto) target;
             if (personPto.getDateOfBirth().isBefore(minDate)) {
                 errors.rejectValue("dateOfBirth", "basicspring-err-to-early");
             }
             if (personPto.getDateOfBirth().isAfter(maxDate)) {
                 errors.rejectValue("dateOfBirth", "basicspring-err-to-late");
             }
         }
     }
 }
  • Use validator in action.
       personPtoValidator.validate(personPto,result);
       if (!result.hasErrors()) {
           response.setRenderParameter(PARAM_VIEW, GREETING);
       }
  • Add validation error message placeholders.
 <form:errors path="name"  element="span" cssClass="${errorClass}"/>