Configuration
using-lishys-notes.notes

Guide


The guide pane on the right contains information organized into sections.

Use the and buttons to move through the sections, or click an accordion tab (shown below) to go directly to a particular topic.



Code Reference


Each paragraph in the guide is usually associated with a particular piece of code. An orange arrow indicates that the code displayed in the middle pane is relevant to the guide text.



If the arrow is gray, simply click anywhere on the paragraph and the relevant code will be displayed.



Code Highlighter


The highlight feature identifies areas of the code which relate to a word or term in the guide. Hover the mouse over any underlined word and the relevant code will be highlighted.



You can disable the highlighting feature at any time by clicking on the button.

Don't forget to make the appropriate code page visible by clicking on any paragraph with a gray arrow.
FileUploadController.java
package lishy.config.web;

import java.io.IOException;
import java.util.Arrays;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class FileUploadController {
    
    @RequestMapping(value="/file-upload.html", method=RequestMethod.POST)
    public ModelAndView fileUpload(@RequestParam("file") MultipartFile file) throws Exception {
        
        int size = Math.min(file.getBytes().length, 50);
        String contents = new String(Arrays.copyOf(file.getBytes(), size));
        
        if (file.getOriginalFilename().equals("")) {
            throw new IOException("No file was uploaded");
        } else if (!contents.matches("\\p{ASCII}*")) {
            throw new UnsupportedOperationException("Please use a file containing text only");    
        }
        
        return new ModelAndView("file", "contents", contents);
    }
    
    @ExceptionHandler(UnsupportedOperationException.class)
    public ModelAndView handleException(UnsupportedOperationException ex) {
      return new ModelAndView("file-error", "exception", ex.getMessage());
    }

}
LanguageController.java
package lishy.config.web;

import java.util.Locale;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class LanguageController {
     
    @Autowired
    private MessageSource messages;
    
    @RequestMapping(value="/locale.html")
    public ModelAndView localeRequest(Locale locale) {
           
        String[] params = {locale.getCountry(),
                           locale.getLanguage()};        
        
        String message = messages.getMessage("welcome.info", 
                                             params,
                                             locale);
        
        return new ModelAndView("locale", "text", message);
        
    }

}
LogInterceptor.java
package lishy.config.web;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LogInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, 
                           HttpServletResponse response,
                           Object handler, 
                           ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, 
                                Object handler, 
                                Exception ex)
            throws Exception {
        System.out.println("afterCompletion");
    }

}
LookAndFeelController.java
package lishy.config.web;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.RequestContextUtils;

@Controller
public class LookAndFeelController {
    
    @RequestMapping(value="/themes.html")
    public ModelAndView themesRequest(HttpServletRequest request) {
        
        String themeName = RequestContextUtils.getTheme(request).getName();
        
        return new ModelAndView("themes", "text", "The theme is " + themeName);
        
    }

}
SimpleController.java
package lishy.config.web;

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

@Controller
public class SimpleController {
     
    @RequestMapping(value="/simple.html")
    public ModelAndView simpleRequest() {
        
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("simple");
        modelAndView.addObject("text", "This was put in the model as the 'text' attribute");
        return modelAndView;
        
    }

}
fancy.properties
styleSheet=/config/css/fancy.css
picture=/config/images/world.jpg
plain.properties
styleSheet=/config/css/plain.css
picture=
fancy.css
body {
  font-family:  sans-serif;
  font-size:    10pt;
  color:        gray
}

h1 {
  font-size:  25px; 
  color:      SteelBlue;
}

a {
  color:            gray;
  font-weight:      bold;
  text-decoration:  none;
}

a:hover {
  color:  OrangeRed;
}
plain.css
h1 {
  color: DimGray
}
world.jpg
error.jsp
<html>
  <body>
    <h1>Error!</h1>
    
    <p style="color:red">${exception}</p>
    
    <p><a href="../index.html">back</a></p>
  </body>
</html>
file-error.jsp
<html>
  <body>
    <h1>Error!</h1>
    
    <p style="color:red">${exception}</p>
    
    <p><a href="file.html">back</a></p>
  </body>
</html>
file.jsp
<html>
  <body>

    <h1>File Upload</h1>
   
    <p style="color:green">${contents}</p>

    <form method="post" action="file-upload.html" enctype="multipart/form-data">
        Choose a text file
        <input type="file" name="file">
        <input type="submit">
    </form>

    <p><a href="../index.html">back</a></p>

  </body>
</html> 
locale.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
  <body>

    <h1><spring:message code="welcome.header"></h1>
    
    <a href="?locale=en_us">us</a> | 
    <a href="?locale=en_gb">gb</a> | 
    <a href="?locale=es_es">es</a> | 
    <a href="?locale=de_de">de</a>
   
    <p style="color:green">
      ${text},
      <spring:message code="welcome.param" arguments="${(empty param.locale) ? 'not set' : param.locale}">
    </p>

    <p>
      <a href="../index.html">
        <spring:message code="welcome.button.back">
      </a>
    </p>

  </body>
</html> 
simple.jsp
<html>
  <body>

    <h1>Simple</h1>
   
    <p style="color:green">${text}</p>

    <p><a href="../index.html">back</a></p>

  </body>
</html> 
static.jsp
<html>
  <body>

    <h1>Static Page</h1>

    <p><a href="../index.html">back</a></p>

  </body>
</html> 
themes.jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>

  <head>
    <link rel="stylesheet" href="<spring:theme code='styleSheet'/>" type="text/css">
  </head>

  <body>

    <h1>Themes</h1>
    
    <a href="?theme-name=plain">plain</a> or 
    <a href="?theme-name=fancy">fancy</a>
   
    <p style="color:green">
      ${text}
    </p>
    
    <img src="<spring:theme code='picture'/>" alt="picture of the world">

    <p>
      <a href="../index.html">back</a>
    </p>

  </body>
</html> 
messages.properties
welcome.header=Welcome!
welcome.info=country = {0}, language = {1}
welcome.param=parameter = {0}
welcome.button.back=back
messages_de.properties
welcome.header=Willkommen!
welcome.info=land = {0}, sprache = {1}
welcome.param=parameter = {0}
welcome.button.back=Startseite
messages_es.properties
welcome.header=Bienvenida!
welcome.info=país = {0}, idioma = {1}
welcome.param=parámetro = {0}
welcome.button.back=volver
config-servlet.xml
<?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:p="http://www.springframework.org/schema/p"
       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-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <!-- Controllers -->
  <context:component-scan base-package="lishy.config.web"/>

  <bean id="fallback"
        class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>


  <!-- Handler Mapping -->
  <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"
        p:defaultHandler="fallback"/> 
        
        
  <!-- View resolver -->
  <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:prefix="/WEB-INF/jsp/"
        p:suffix=".jsp"/>
 
 
  <!-- Interceptor -->
  <mvc:interceptors>
    <mvc:interceptor>
      <mvc:mapping path="/simple*"/>
      <bean class="lishy.config.web.LogInterceptor"/>
    </mvc:interceptor>
  </mvc:interceptors>
  
  
  <!-- Themes -->   
  <bean id="themeSource"
        class="org.springframework.ui.context.support.ResourceBundleThemeSource"
        p:basenamePrefix="/themes/"/>

  <mvc:interceptors>
    <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"
          p:paramName="theme-name"/>
  </mvc:interceptors>
      
  <bean id="themeResolver"
        class="org.springframework.web.servlet.theme.CookieThemeResolver"
        p:defaultThemeName="plain"/>
        
       
  <!-- Locale -->        
  <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
        p:basename="/WEB-INF/messages/messages"/>

  <mvc:interceptors>
     <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
  </mvc:interceptors>

  <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
        p:cookieName="MyLocale"/>


  <!-- Multipart File Upload -->
  <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
        p:maxUploadSize="100000"/>
        
        
  <!-- Exception Handling -->
  <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
      <map>
        <entry key="IOException" value="file-error"/>
      </map>
    </property>
    <property name="defaultErrorView" value="error"/>
  </bean>

</beans>
web.xml
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID"
         version="2.5">
         
  <display-name>Controllers</display-name>
  
  <!-- DispatcherServlet -->
  <servlet>
    <servlet-name>config</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!-- Mapping DispatcherServlet to /app/* makes things a lot easier.
       
       Static resources can be placed outside of /app
       This includes static html files, css, javascript, images etc.
       Other mappings such as / and /* can cause problems with static resources.
       
       org.tuckey.web.filters.urlrewrite.UrlRewriteFilter can be used to tidy this up.
       
  -->
  <servlet-mapping>
    <servlet-name>config</servlet-name>
    <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
  
  <!-- Welcome file -->
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  
</web-app>
index.html
<html>

  <body>
    <h1>Configuration</h1>
    
    <p>
      <a href="app/simple.html">Simple Controller</a><br/>
      <a href="app/static.html">Static Page</a>
    </p>  
   
    <p>    
      <a href="app/themes.html">Themes</a><br/>
      <a href="app/locale.html">Locale</a><br/>
      <a href="app/file.html">Multipart file upload</a>
    </p>

  </body>
  
</html> 

Controllers

During start up, component-scan will look for annotated controller classes in the base-package and register them as beans in the application context.

Filters can be used to include or exclude classes based on annotation type, an AspectJ or regex expression, whether they are assignable to a class or interface (extends/implements) or using a custom filter.

All handlers must resolve to a logical view name, either explicitly (by returning a String, View or ModelAndViewModelAndView:eq(1)) or implicitly (based on conventions).

Here we tell Spring to go to the simple""simple"" view.

InternalResourceViewResolver translates this logical view name into the name of the JSP page to be displayed.

For JSP pages that use the Standard Tag Library, the viewClass property of InternalResourceViewResolver must be set to JstlView. However, if the jstl.jar file is on the classpath, this will be done by default.

Handler Mapping

DefaultAnnotationHandlerMapping maps URLs to @RequestMapping annotations on controllers, and is registered by default.

However, by specifying this bean ourselves, we can set the defaultHandler property to be a UrlFilenameViewController, which will transform the virtual path of a URL into a view name, if no specific mapping is found.
For example,

http://host/root/app/static.html

does not map to a specific controller.
Instead it uses UrlFilenameViewController to produce a logical view name of 'static'. This is useful for JSP pages which don't require a custom controller.

A handler interceptor allows additional functionality to be added to a handler for certain requests.

preHandlepreHandle:eq(0) is called before the actual handler is executed, postHandlepostHandle:eq(0) is called after the handler is executed, and and afterCompletionafterCompletion:eq(0) is called after the complete request has finished.
Handler interceptors are registered with the <mvc:interceptors>mvc:interceptors element.

Here, LogInterceptor is a custom interceptor which is only triggered for handlers mapped to a path beginning with simple/simple*.

ThemeChangeInterceptor is a Spring interceptor which allows for changing the current theme on every request.

Themes

Themes are defined by specifying resources in properties files which are named after the theme. Typically, resources include the CSS, JavaScript and images that will determine the look and feel of the application.
We tell Spring the location/themes/ of these properties files when we register the themeSource bean.

On a JSP page, the appropriate resource is accessed by specifying the name of a property in the code attribute of the <spring:theme>spring:theme element.

ThemeChangeInterceptor uses a configurable request parameter to set the required theme.

This example uses theme-name for this purpose, but if the default value of theme is acceptable then this can be omitted.

CookieThemeResolver uses a cookie to store the users preference with a fallback to a defaultdefaultThemeName if no theme has been set.

We can now switch between themes by adding the theme-name parameter to the request.

Locales

Localized messages are held in properties files with the relevant language code appended. A file with no language suffix acts as a default for messages which are not found in a specific language file.

The numbers in curly braces are placeholders for values to be substituted at runtime.
We tell Spring the locationmessages/messages of these files when we register the messageSource bean.

Localized messages are displayed on a JSP page using the <spring:message>spring:message tag which specifies the required message key in the code attribute, and an optional list of placeholder values in the arguments attribute.

Spring can also inject a MessageSourceMessageSource:eq(1) object, if access to the messagesgetMessage is required in the Java code.

LocaleChangeInterceptor changes the locale to the value specified in a configurable request parameter.
We use the default locale?locale parameter to switch between languages. However, if this request parameter is omitted then the HTTP accept-language header is used instead.
CookieLocaleResolver then stores this custom setting in a cookie called MyLocale.
Other options for resolving the locale are AcceptHeaderLocaleResolver (the default) which detects the locale from the HTTP accept-language header, SessionLocaleResolver which uses the user's session and FixedLocaleResolver for a fixed default locale.

Multipart File Upload

Suppose we wish to upload a file to our application using a file""file"":eq(0) input on a form.
We simply annotate a MultipartFileMultipartFile:eq(1) argument with @RequestParam in our controller, and the file contents are available to us using the getBytes()getByte method.

Spring uses Apache Commons FileUpload for the MultipartResolver implementation.

maxUploadSize sets the maximum allowed size (in bytes) before uploads are refused.

Handling Exceptions

We can configure Spring to map exception class names to view names using SimpleMappingExceptionResolver.

In this example, any IOExceptions will be sent to the file-error view and and any other exceptions will be sent to the default error view.

Another way to handle exceptions is to use the @ExceptionHandler annotation. This annotation specifies which method is invoked (in this case handleException) when an exception of a specific typeUnsupportedOperationException is thrown during the execution of this controller's methods.
Home  |  Getting Started  |  Controllers  |  Views  |  Forms  |  REST  |  Testing  |  Configuration  |  MVC Walkthrough  |   lishblog  |  Email Lishy