Spring Web MVC

Preview:

DESCRIPTION

Spring Web MVC. Ievads. T īmekļa lietojumprogrammas ir iespējams programmēt pa tiešo izmantojot Java Servlet un JSP tehnoloģijas Eksistē vairāki tīmekļa lietojumprogrammu izstrādes ietvari (web application frameworks), kuri atbalsta dinamisko tīmekļa lietojumprogrammu izstrādi - PowerPoint PPT Presentation

Citation preview

Spring Web MVC

Ievads

• Tīmekļa lietojumprogrammas ir iespējams programmēt pa tiešo izmantojot Java Servlet un JSP tehnoloģijas

• Eksistē vairāki tīmekļa lietojumprogrammu izstrādes ietvari (web application frameworks), kuri atbalsta dinamisko tīmekļa lietojumprogrammu izstrādi

• Piemēri: Spring MVC , Play!, JSF, Struts, Tapestry, Stripes, Wicket un daudzi citi

Spring

• Spring ir atklāta koda Java/JavaEE lietojumprogrammu izstrādes ietvars

• Viens no interesantākiem

komponentiem ir

Spring Web MVC

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/overview.html

Tīmekļa lietojumprogrammu uzdevumi

• Tipiskie un svarīgie uzdevumi, kuri ir jāatrisina izstrādājot tīmekļa lietojumprogrammu :• Stāvokļu pārvaldība (state management)• Darba plūsma (workflow)• Validācija

• Spring MVC ietvars ir uzprojektēts, lai palīdzēt izstrādātājiem risināt šīs problēmas

Model-View-Controller Pattern

• Model-View-Controller (MVC) ir arhitektūras paraugs (aprakstīts 1979. gadā, Smalltalk valodā)

• Pamata mērķis: atdalīt datus (Model) no

lietotāja interfeisa (View)

• MVC atrisina

problēmu ieviešot

starpnieka komponenti - kontrolieri (Controller)

Model-View-Controller Pattern

• Model - Represents enterprise data and the business rules.

• View - Renders the contents of a model. Accesses enterprise data through the model and specifies how that data should be presented.

• Controller - Translates interactions with the view (button clicks, menu selections) into actions to be performed by the model (activating processes, changing the state of the model).

http://ash-mvc.org/

Spring MVC application architecture

• Spring MVC applications are broken down into a series of layers

• A layer is a discrete, orthogonal area of concern within an application

General, high-level layers in a web application

Spring MVC application layers

• Typical Spring MVC applications have at least five layers of abstraction

• Isolating problem domains into separate layers creates a flexible and testable application

• The interface is a contract for a layer, making it easy to keep implementations and their details hidden while enforcing correct layer usage

Spring MVC application layers

• The user interface layer (also known as the view) is responsible for rendering output for the client

• The web layer manages the user’s navigation through the site

• The service layer provides a stateless, coarse-grained interface for clients to use for system interaction

• The domain model is the collection of nouns in the system, it also contains the business logic of the system

• The data access layer is responsible for interfacing with the persistence mechanism to store and retrieve instances of the object model

Required JAR dependencies

Maven dependency configuration (for Spring 3.1.3):<dependency>

<groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>3.1.3.RELEASE</version>

</dependency>

<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>3.1.3.RELEASE</version>

</dependency>

<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.0.1</version>

</dependency>

Spring MVC komponenti

Spring MVC sastāv no vairākiem komponentiem, starp kuriem notiek sadarbība apstrādājot klienta pieprasījumu

Pieprasījuma dzīves cikls (1)

• Klients sūta pieprasījumu, kurš tiek nodots DispatcherServlet komponentam

• Visi pieprasījumi vienmēr tiek nodoti vienam servletam, kuru

sauc par

priekšējo kontrolieri

(front controller)

Pieprasījuma dzīves cikls (2)

• Komponents, kurš atbild par pieprasījuma apstrādi ir Controller

• Lai nolemt kuram kontrolierim atdot

pieprasījumu, DispatcherController

izmanto

HandlerMapping

komponentus

• HandlerMapping:

URL piesaistīšana kontrolieriem

Pieprasījuma dzīves cikls (3-4)

• Kad DispatcherServlet ir izvēlējies kontroliera objektu, tad parsūta tam pieprasījumu, lai kontrolieris izpilda biznesa loģiku

• Pēc darba pabeigšanas Controller atgriež ModelAndView objektu

• ModelAndView saturView objektu vaiskata loģisko vārdu un modeli

Pieprasījuma dzīves cikls (5)

• Ja ModelAndView objekts satur skata loģisko vārdu, tad DispatcherServlet izmanto ViewResolver komponenti

• ViewResolver

atrod atbilstošu

View objektu,

lai attēlot atbildi

klientam

Pieprasījuma dzīves cikls (6)

• Visbeidzot, DispatcherServlet atdod pieprasījumu tam View objektam, uz kuru norāda ModelAndView

• View objekts ir atbildīgs par pieprasījumaatbildes atgriešanu un parādīšanu klientam

Spring MVC sequence diagram

Front Controller

• At the heart of Spring MVC is DispatcherServlet, a servlet that functions as a front controller

• A front controller is a common web-application pattern where a single servlet delegates responsibility for a request to other components of an application to perform the actual processing

Processing workflow

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html

DispatcherServlet config

Jākonfigurē programmas/WEB-INF/web.xml failā:

<servlet> <servlet-name>training</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup></servlet>

Nākamais solis ir nodefinēt servlet mapping:

<servlet-mapping><servlet-name>training</servlet-name><url-pattern>/training/*</url-pattern>

</servlet-mapping>

DispatcherServlet context

• WebApplicationContext tiek ielādēts no faila:

training-servlet.xml

kurš atrodas direktorijā WEB-INF (blakus web.xml failam)

• Ir iespējams arī sadalīt

konfigurāciju starp

vairākiem failiem

Context hierarchy in Spring Web MVC

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html

Konfigurācijas faila piemērs

<?xml version="1.0" encoding="UTF-8"?>

<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">

<!-- the application context definition for the DispatcherServlet -->

</beans>

• DispatcherServlet konfigurācijas faila piemērs:

• Šīs fails satur bean definitions, kurus izmanto DispatcherServlet

Vienkāršas Web lapas izveidošana

Nepieciešamie soļi, lai izveidot Web lapu ar Spring MVC:

1. Uzrakstīt kontroliera klasi, kas izpildīs biznesa loģiku

2. Iekonfigurēt kontrolieri DispatcherServlet konteksta konfigurācijas failā (training-servlet.xml)

3. Iekonfigurēt view resolver, kurš piesaistīs kontrolieri pie JSP

4. Uzrakstīt JSP, kas attēlos lapu klientam

Kontrolieru izveidošanas veidi

Ir divi pamata kontrolieru izveidošanas veidi:

• [pirms 2.5] Paplašināt klases no piedāvātas kontrolieru hierarhijas

• [sākot no 2.5] Izmantot anotācijas

Kontroliera izveidošana ( < 2.5 stils)import org.springframework.web.servlet.mvc.Controller;import org.springframework.web.servlet.ModelAndView;

public class HomeController implements Controller {

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {

return new ModelAndView("home", "message", greeting); }

private String greeting; public void setGreeting(String greeting) { this.greeting = greeting; }}

• Nodarbojas ar pieprasījuma apstrādāšanu• Pamata metodes signatūra ir līdzīga servleta

service() metodei• Atgriež ModelAndView objektu

Kontroliera konfigurēšana

• Kontrolieri ir jāieraksta DispatcherServlet konteksta konfigurācijas failā (training-servlet.xml) :

<bean name="/home" class="com.springinaction.training.mvc.HomeController"><property name="greeting"> <value>Welcome to Spring Training!</value></property></bean>

• The default handler mapping is BeanNameUrlHandlerMapping, which uses the base name as the URL pattern

• When a request comes with a URL that ends with “/home”, DispatcherServlet will dispatch the request to HomeController

Kontroliera izveidošana ( >= 2.5 stils)@Controller

public class HomeController {

@RequestMapping("/home")

public ModelAndView helloWorld() {

ModelAndView mav = new ModelAndView();

mav.setViewName("home");

mav.addObject("message", greeting);

return mav;

}

private String greeting;

public void setGreeting(String greeting) {

this.greeting = greeting;

}

}

Lai izmantot anotācijas ir nepieciešama papildus konfigurācija!Lai izmantot anotācijas ir nepieciešama papildus konfigurācija!

Enable annotation support

<?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- Enable autodetection of annotated controllers -->

<context:component-scan base-package="com.web.music.portal.mvc"/>

<bean class="org.springframework.web.servlet.mvc

.annotation.DefaultAnnotationHandlerMapping"/> . . .

</beans>

View Resolver deklarēšana• View resolver darbs ir pēc skata loģiska vārda (kurš ir

atgriezts ModelAndView objektā) atrast pašu skatu

• Viens no variantiem ir izmantot skata vārdu kā JSP faila vārdu (jāieraksta training-servlet.xml):<bean id="viewResolver" class="org.springframework.web.

servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property></bean>

“home” /WEB-INF/jsp/home.jsp

JSP izveidošana

• Pēdējais kas palika – izveidot pašu JSP

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

<html><head><title>Spring Training, Inc.</title></head><body><h2><c:out value="${message}"/></h2></body></html>

• Failu ir jānosauc par “home.jsp” un ir jāieliek /WEB-INF/jsp/ direktorijā

JSTL konfigurēšana

Lai izmantot JSTL (c:out tagu) JSP lapā, ir nepieciešamas papildus bibliotēkas• Step 1: download standard.jar and jstl.jar

• Step 2: ensure that both files are packaged in /WEB-INF/lib directory of WAR file

• Step 3: Write JSP file that can use core tags

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

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

Rezultāta apskatīšana

• Palika izveidot tīmekļa lietojumprogrammas WAR failu (mvn package) un palaist to uz servera

• Pārlūkprogrammā uzrakstīt URL:http://localhost:8080/my_app/training/home.htm

Kopsavilkums

HandlerMapping

• Tipiski piesaista specifisku kontrolieri pie URL adreses parauga

• Spring piedāvā sekojošas noderīgas HandlerMapping implementācijas

• DefaultAnnotationHandlerMapping

• BeanNameUrlHandlerMapping

• SimpleUrlHandlerMapping

DefaultAnnotationHandlerMapping

• Introduced in Spring 2.5 - maps handlers based on HTTP paths expressed through the @RequestMapping annotation inside controller classes annotated with @Controller

• Registered by default in DispatcherServlet on Java 5+

BeanNameUrlHandlerMapping

• Piesaista URL adresi pie kontroliera, kurš ir reģistrēts konfigurācijas failā ar tādu pašu vārdu• e.g. /simple.htm maps to a bean named “/simple.htm”

• Ir jāizmanto name atribūtu, jo “/” nav atļauts XML atribūtā id

<bean class="org.springframework.web.servlet. handler.BeanNameUrlHandlerMapping"/>

<bean name="/simple.htm" class="com.mvc.web.SimpleController">. . .</bean>

SimpleUrlHandlerMapping

• Pats vispārīgs veids kā piesaistīt pieprasījuma URLus kontrolieriem

• Tiek konfigurēts kā saraksts no name/value pāriem (URL/kontrolieru vārds)

<bean id="simpleUrlMapping" class="org.springframework.web .servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings"> <props> <prop key="/listCourses.htm">listCoursesController</prop> <prop key="/register.htm">registerStudentController</prop> <prop key="/displayCourse.htm">displayCourseController</prop> </props> </property></bean>

Multiple handler mappings

• Ir iespējams deklarēt vairākus handler mappings vienā lietojumprogrammā

• Handler mapping klases implementē Spring Ordered interfeisu

• Var uzstādīt order īpašību, lai norādīt izpildes kārtību attiecībā uz citiem handler mapping komponentiem

Multiple handler mappings

<bean id="beanNameUrlMapping" class="org.springframework.web.

servlet.handler.BeanNameUrlHandlerMapping">

<property name="order"><value>1</value></property></bean>

<bean id="simpleUrlMapping" class="org.springframework.web.

servlet.handler.SimpleUrlHandlerMapping"> <property name="order"><value>0</value></property> <property name="mappings"> … </property></bean>

Kontrolieri

Ja DispatcherServlet ir Spring MVC sirds, tad kontrolieri ir smadzenes

Kontrolieru hierarhija ( < 2.5)

• Spring piedāvā bagātu kontrolieruhierarhiju

• Hierarhijas virsotnē atrodas Controller interfeiss

• Parasti ir jāizmantokādu no implementācijas apakšklasēm

AbstractController

Pats vienkāršākais kontrolieris

public class SampleController extends AbstractController {

public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception {

return new ModelAndView("hello", "message", "Hello World!");

}}

ModelAndView objekts

• Iekapsulē skatu un modeļa datus, kurus skats attēlos

• Modelis ir realizēts kā java.util.Map

• Ērts konstruktors viena modeļa objekta gadījumam:

ModelAndView(

String viewName,

String modelName,

Object modelObject)

ModelAndView objekts

Ir iespējams arī pievienot modelim vairākus objektus:

public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception {

ModelAndView mav = new ModelAndView("welcome"); mav.addObject("message1", "Welcome!"); mav.addObject("message2", "Nice to see you!"); return mav; }

Parametru apstrāde

Web pieprasījums bieži satur vienu vai vairākus parametrus

Kādā veidā varētu piekļūt parametriem kontroliera kodā???

<form action="/login" method="POST"> Login: <input id=“login" name="login"/> Password: <input id="password" name="password" type="password"/> <input type="submit" value="Login"/></form>

Risinājums

Varētu izmantot AbstractController un nolasīt parametrus no HttpServletRequest

public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception {

String login = request.getParameter("login"); String pass = request.getParameter("password"); . . .}

Spring piedāvā ērtāku iespēju!

AbstractCommandController

• Automātiski ieraksta parametrus speciālajā komandas objektā (command object)

• Ir iespēja pievienot validatoru, lai nodrošināt to, ka parametri ir pareizi

• Galvenā izpildes metode:

handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)

AbstractCommandController

public class DisplayCourseController extends AbstractCommandController {

public DisplayCourseController() {

setCommandClass(DisplayCourseCommand.class);

}

protected ModelAndView handle(HttpServletRequest request,

HttpServletResponse response, Object command,

BindException errors) throws Exception {

DisplayCourseCommand displayCommand =

(DisplayCourseCommand) command;

Course course = courseService.getCourse(displayCommand.getId());

return new ModelAndView("courseDetail", "course", course);

}

Command Object

• A command object is a bean that is meant to hold request parameters for easy access

public class DisplayCourseCommand {private Integer id;public void setId(Integer id) {

this.id = id;}public Integer getId() {

return id;}

}

• Spring will attempt to match any parameters passed in the request to properties in the command object

Binding a Form to a Bean

• DataBinder is responsible for setting object properties from expression strings and their values

• These expressions, in the form of property.property[2].property, are the names of HTML fields inside HTML forms

• The values come from the submitted HTTP request parameters

name.firstName=joe getName().setFirstName("joe")

Binding a Form to a Bean

• The DataBinder supports setting properties of type String, primitives, and nearly any type, through its use of PropertyEditors

• You can also bind to properties of objects that live inside collections, such as Sets, arrays, Lists, and Maps

• You can create and register your own PropertyEditor to meet your specific needs

Defining custom property editor

To create and register your own custom property editor override initBinder method in your controller

@Overrideprotected void initBinder(HttpServletRequest request,

ServletRequestDataBinder binder) throws Exception

{ binder.registerCustomEditor(Date.class, new CustomDateEditor(

new SimpleDateFormat("yyyy-MM-dd"), false));}

Pārskats

Formu apstrāde

• Tipiska tīmekļa lietojumprogramma satur vismaz vienu formu

• Lietotājs aizpilda formu un aizsūta to• Dati tiek nosūtīti serverim• Kad datu apstrāde ir pabeigta, lietotājs saņem

vienu no variantiem:• Lapa ar veiksmīgas izpildes paziņojumu• Formas lapa ar kļūdu paziņojumiem

Kādā veidā varētu to realizēt???

Risinājums

• Izmantot AbstractController formas attēlošanai

• Izmantot AbstractCommandController formas apstrādei

• Trūkums: vajag uzturēt divus dažādus kontrolierus, kuri kopā nodarbojas ar viena uzdevuma risināšanu

SimpleFormController

Formu kontroliera funkcionalitāte:• Attēlo formu uz HTTP GET pieprasījuma

• Apstrādā formu uz HTTP POST pieprasījuma

• Ja notiek kļūda, tad atkārtoti parāda formu

public class PersonFormController extends SimpleFormController {

public PersonFormController() {setCommandClass(Person.class);

}

public void doSubmitAction(Object command){Person person = (Person)object;personService.save(person);

}. . .}

Formas JSP

Spring piedāvā speciālu formas tagu bibliotēku

<%@ page session="false"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %><html><body><h1>Add new Person</h1>

<form:form commandName="person"> <form:hidden path="id"/> <label for="name">Name</label> <form:input path="name"/> <label for="surname">Surname</label> <form:input path="surname"/> <input type="submit" value="Save"/></form:form>

</body></html>

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/spring-form.tld.html

SimpleFormController config

• Kontrolieris ir uzprojektēts tādā veidā, lai pēc iespējas vairāk atdalīt skatu detaļas no kontroliera koda

<bean name="personFormController" class="com.web.music.portal.mvc.PersonFormController">

<property name="formView" value="add_person_form"/> <property name="successView"

value="person_added"/> <property name="commandName"

value="person"/> . . .</bean>

HTTP GET

• Ja ir nepieciešams aizsūtīt datus skatam, tad vajag izmantot onSubmit() metodi

Formu validācija

• Viens no svarīgiem uzdevumiem ir formas datu validācija

• Par validāciju atbild sekojošais interfeisspublic interface Validator { void validate(Object obj, Errors errors); boolean supports(Class clazz);}

• Implementējot interfeisa validate() metodi vajag pārbaudīt objekta atribūtu vērtības un noraidīt nepareizas vērtības izmantojot Errors objektu

Validatora piemērspublic class PersonFormValidator implements Validator {

public boolean supports(Class givenClass){ return givenClass.equals(Person.class);}

public void validate(Object obj, Errors errors){ Person person = (Person)obj; if (person == null) errors.reject("error.nullpointer", "Null data received"); else{ if (person.getName().equals("")){ errors.rejectValue(

"name", "error.empty", "Name is required!"); } if (person.getSurname().equals("")){ errors.rejectValue(

"surname", "error.empty", "Surname is required!"); } }}}

Validatora reģistrēšana

Validatoru vajag piesaistīt kontrolierim konfigurācijas failā

<bean id="registerStudentController" class="com.springinaction.training.mvc.

RegisterStudentController">… <property name="validator"> <bean class="com.web.music.portal.

mvc.PersonFormValidator"/> </property></bean>

Kļūdu attēlošana formā

<form:form commandName="person">

<form:hidden path="id"/>

<p><label for="name">Name</label></br> <form:input path="name"/> <form:errors path="name" cssStyle="color: red"/> </p>

<p><label for="surname">Surname</label></br> <form:input path="surname"/> <form:errors path="surname" cssStyle="color: red" /> </p>

<p><input type="submit" value="Save"/></form:form>

Objekta modificēšana tajā pašā formā

• Jauna objekta pievienošanas un eksistējoša objekta modificēšanas formas bieži ir identiskas

• Abiem gadījumiem ir iespējams izmantot vienu un to pašu SimpleFormController

• Lai attēlot formā eksistējoša objekta datus ir nepieciešams kā parametru padot objekta ID

<c:forEach var="person" items="${person_list}"><a href="/music-portal/music/add_person?id=${person.id}"> <c:out value="${person.id}"/></a><br></c:forEach>

Metode formBackingObject

• Metode ir definēta klasē AbstractFormController

• Pēc noklusējuma atgriež jauno commandClass instanci, kas ir iekonfigurēts kontrolierim

• Metodi var pārrakstīt, piemērām, lai ielādēt objektu no datubāzes (to objektu, kuru tālāk modificēs formā)

• Lai izmantot form-backing objektu visā formas darba plūsmā (lai uz POST pieprasījumu netiktu izveidota jauna instence) ir jāaktivizē sesijas formas režīmu (sessionForm = true)

Piemērs: formBackingObjectpublic class PersonFormController extends SimpleFormController{

public PersonFormController(){ setCommandClass(Person.class); setSessionForm(true); }

@Override protected Object formBackingObject(HttpServletRequest request){ Person person = new Person(); if (!isFormSubmission(request)){ String idString = request.getParameter("id"); if (idString != null && !idString.equals("")) { long id = Long.parseLong(request.getParameter("id")); person = personService.getById(id); } } return person; } . . .}

onSubmit metodes

• Ir piedāvātas vairākas metodes, kur var apstrādāt formas iesniegšanu (submit)

• Nākamajā slaidā ir attēlota SimpleFormController aktivitāšu diagramma (activity diagram)

SimpleFormController

Expert Spring MVC And Web Flow

Metode referenceData

• Metode ir definēta klasē SimpleFormController

• Dod iespēju savākt kopā un atgriezt palīgobjektus (piemērām, objektu sarakstus combo-box elementiem), kuri ir nepieciešami, lai attēlot formu

• Pirms rādīt formu, kontrolieris izveidos kombinētu modeli, kur savienos formas objektu, modeli no referenceData() un iespējamas kļūdas un aizsūtīs to skatam

Piemērs: referenceData

@Overrideprotected Map referenceData(HttpServletRequest request) throws Exception { Map data = new HashMap();

List<Language> languages = loadLanguages(); data.put("languages", languages);

List<Country> countries = loadCountries(); data.put("countries", countries);

return data;}

Redirect After Submit pattern

• There is a common problem with the handling the display of the confirmation page

• The success view is rendered in the same request as the initial POST, leaving the browser in a state with the ability to replay the form submit

• The user can simply reload the page, resubmitting the form

Redirect After Submit pattern

• Redirect After Submit pattern simply redirects the user to the success view instead of internally forwarding the request

• A client redirect is not the same as a RequestDispatcher.forward()• Forwarding method internally redirect a request to

another handler inside the servlet container

• A client redirect instructs the client to issue another GET request

Spring’s support for redirect

• Special class exists for this purposeorg.springframework.web.servlet.view.RedirectView

• Spring MVC provides shorthand for redirect views

• The UrlBasedViewResolver (the superclass for InternalResourceViewResolver) recognizes the special prefix redirect: <bean name="personFormController"

class="com.web.music.portal.mvc.PersonFormController"> . . . <property name="successView" value="redirect:person_listall"/> . . .</bean>

Annotation-based controller configuration

• Spring 2.5 introduces an annotation-based programming model for MVC controllers, using annotations such as • @Controller• @RequestMapping• @RequestParam• @ModelAttribute • etc

Enable annotation support

<?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" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- Enable autodetection of annotated controllers -->

<context:component-scan base-package="com.web.music.portal.mvc"/>

<bean class="org.springframework.web.servlet.mvc

.annotation.DefaultAnnotationHandlerMapping"/> . . .

</beans>

Annotated controller 1@Controller@RequestMapping("/genre_listall")public class ListAllGenreController {

// need to configure this bean in XML

private GenreService genreService;

@Autowired public ListAllGenreController(GenreService genreService){ this.genreService = genreService; }

@RequestMapping(method = RequestMethod.GET) public String listAllGenres(ModelMap model) {

List<Genre> genres = genreService.findAll();model.addAttribute("list", genres);return "genre_listall";

}}

Annotation-based controllers

• The @Controller annotation acts as a stereotype for the annotated class, indicating its role

• The dispatcher scans such annotated classes for mapped methods and detects @RequestMapping annotations

• @RequestMapping annotation maps URLs such as /appointments onto an entire class or a particular handler method

Annotated controller 2-1

@Controller

@RequestMapping("/add_genre")

@SessionAttributes("genre")

public class GenreFormController {

// need to configure in XML

private GenreService genreService;

private GenreFormValidator genreFormValidator;

@Autowired

public GenreFormController(GenreService genreService, GenreFormValidator

genreFormValidator){

this.genreService = genreService;

this.genreFormValidator = genreFormValidator;

}

. . .

Annotated controller 2-2. . .@RequestMapping(method = RequestMethod.GET)public String setupForm( @RequestParam(required = false, value = "id") Long genreId, ModelMap model) { Genre genre = new Genre(); if (genreId != null && !genreId.equals("")) {

genre = genreService.getById(genreId);}

model.addAttribute("genre", genre); return "add_genre_form";}. . .

Annotated controller 2-3. . .@RequestMapping(method = RequestMethod.POST)public String processSubmit(

@ModelAttribute("genre") Genre genre, BindingResult result, SessionStatus status) {

genreFormValidator.validate(genre, result);

if (result.hasErrors()) { return "add_genre_form"; } else { genreService.save(genre); status.setComplete(); return "redirect:genre_listall";

} }. . .

Method arguments and return types

• Request or response objects (ServletRequest or HttpServletRequest)

• Session object (HttpSession)

• WebRequest or NativeWebRequest - Allows for generic request parameter access as well as request/session attribute access

• @PathVariable annotated parameters for access to URI template variables

• @RequestParam annotated parameters for access to specific Servlet request parameters

Method arguments and return types

• @RequestHeader annotated parameters for access to specific request HTTP headers

• @RequestBody annotated parameters for access to the HTTP request body

• HttpEntity<?> parameters for access to the Servlet request HTTP headers and contents

• Map / Model / ModelMap for enriching the implicit model that is exposed to the web view

• ...

Check-box list in the form [1-2]

<form:form commandName="order">

...

<h3>Select items:</h3>

<table>

<c:forEach var="item" items="${items}">

<tr><td>

<form:checkbox path="selectedIds" value="${item.id}"/>

<c:out value="${item.description}" />

</td></tr>

</c:forEach>

</table>

...

</form:form>

Mapping collection of ids in the form:

Check-box list in the form [2-2]

public class Order {

...

private List<Long> selectedIds;

...

public List<Long> getSelectedIds() {

return selectedIds;

}

public void setSelectedIds(List<Long> invitedIds) {

this.selectedIds = invitedIds;

}

}

Form baking object:

Vairāku darbību apstrāde• Visi līdz šīm apskatītie kontrolieri pildīja kādu

vienu uzdevumu• Veidot vairākus kontrolierus, lai pildīt līdzīgus

uzdevumus, nav īsti racionāli• Piemērām, vajag attēlot kursu sarakstu dažādos

variantos:• Nesakārtotā veidā• Sakārtoti pēc datuma• Sakārtoti pēc nosaukuma

Kādā veidā varētu to realizēt???

MultiActionControllerpublic class ListAllArtistController extends MultiActionController {

private ArtistService artistService;

public ModelAndView all(HttpServletRequest request, HttpServletResponse response) {

return doSearch(ArtistType.ALL); }

public ModelAndView singer(HttpServletRequest request, HttpServletResponse response) {

return doSearch(ArtistType.SINGER); }

public ModelAndView band(HttpServletRequest request, HttpServletResponse response) {

return doSearch(ArtistType.MUSIC_BAND); }. . .}

Metodes vārda noteikšana

The MethodNameResolver is supposed to resolve method names based on the request coming in:

• ParameterMethodNameResolver

• Resolves the execution method name based on a parameter in the request

• InternalPathMethodNameResolver

• Retrieves the filename from the path and uses that as the method name

• PropertiesMethodNameResolver

• Resolves the name of the execution method by consulting a list of key/value pairs

ParameterMethodNameResolver<bean name="listallArtistController“

class="com.web.music.portal.mvc.ListAllArtistController">

<property name="artistService" ref="artistService"/>

<property name="methodNameResolver">

<ref bean="listallArtistMethodResolver"/>

</property>

</bean>

<bean id="listallArtistMethodResolver“

class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">

<property name="paramName"><value>mode</value></property>

</bean>

<bean id="urlMapping"

class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<props>

<key="/artist_listall">listallArtistController</prop>

</props>

</property>

</bean>

Vienkāršāk ar anotācijām@Controller

public class DisplaySubjectController {

@RequestMapping(value = "/subject", method = RequestMethod.GET)

public String displayStartPage(ModelMap model, HttpSession session,

@RequestParam(value = ATTR_ID) Long subjectId) {...}

@RequestMapping(value = "/userActionForSubject", params = "addComment", method = RequestMethod.POST)

public String addNewComment(ModelMap model, HttpSession session,

@RequestParam(value = "subject_id") Long subjectId,

@RequestParam(value = "comment_text") String commentText) {...}

@RequestMapping(value = "/userActionForSubject", params = "addFavourite", method = RequestMethod.POST)

public String addFavourite(ModelMap model, HttpSession session,

@RequestParam(value = "subject_id") Long subjectId,

@RequestParam(value = "comment_text") String commentText) {...}

...

Wizard (daudzekrānu) formas

Uzdevums – realizēt aptaujas formu ar 40 jautājumiem

Variants – izmantot SimpleFormController, izvietot visus jautājumus vienā lapā.Bet tas nav ērti lietotājam!

Kādā veidā varētu to realizēt???

Wizard formas

• Spring piedāvā kontrolieri, kas atbild par secīgu virzīšanos cauri vairākām lapām

AbstractWizardFormController

• Līdzīgs parastai formai, bet ir iespējams validēt datus pa daļām (katrā ekrānā savu daļu)

• Formas apstrāde parasti notek pašās beigās

• Ir iespēja visu procesu atcelt (cancel) jebkurā brīdī

Wizard formas kontrolieris

public class FeedbackWizardControllerextends AbstractWizardFormController {

public FeedbackWizardController() {setCommandClass(FeedbackSurvey.class);

}

protected ModelAndView processFinish(HttpServletRequest request,HttpServletResponse response, Object command,BindException errors) throws Exception {

FeedbackSurvey feedback = (FeedbackSurvey) command;feedbackService.submitFeedback(feedback);return new ModelAndView("thankyou");

}

Wizard formas konfigurēšana

• Formas kontroliera konfigurēšana

<bean id="feedbackController" class="com.springinaction.training.mvc.MyWizardController">

<property name="pages"> <list> <value>general</value> <value>instructor</value> <value>course</value> </list></property></bean>

• Šeit tiek definētas visas lapas

Wizard formas lapas

Pa lapām var pārvietoties ierakstot pieprasījumā parametru ar vārdu "_targetX", kur X ir lapas numurs

<form method="POST" action="feedback.htm">…<input type="submit" value="Back" name="_target1"> <input type="submit" value="Next" name="_target3"></form>

Wizard formas finish/cancel

• Formas pabeigšana - tiks izsaukta metode processFinish()

<input type="submit" value="Finish" name="_finish">

• Formas atcelšana - tiks izsaukta metode processCancel()

<input type="submit" value="Cancel" name="_cancel">

Wizard formas validācija

Formas komandas objekts tiek validēts pa lapām

protected void validatePage(Object command, Errors errors, int page) {

FeedbackSurvey feedback = (FeedbackSurvey) command;FeedbackValidator validator =

(FeedbackValidator) getValidator();if(page == 0) { validator.validateEmail(feedback.getEmail(), errors);}. . .}

Pārskats

ThrowawayController

• Nav Controller hierarhijas daļa

• Netiek izmantots HTTP pieprasījums vai komandas objekts

• Parametri tiek ierakstīti tieši kontrolierī• Ir noderīgi, kad nav modeļa objekta, kuru varētu

izmantot• Atšķirībā no citiem kontrolieriem, nav singleton

public interface ThrowawayController { ModelAndView execute() throws Exception;}

ThrowawayController

public class DisplayCourseController

implements ThrowawayController {

private Integer id;

public void setId(Integer id) { this.id = id; }

public ModelAndView execute() throws Exception {

Course course = courseService.getCourse(id);

return new ModelAndView(

"courseDetail", "course", course);

}

}

Interceptors

• Iespēja pievienot papildus funkcionalitāti pirms un pēc pieprasījuma (līdzīgi servletu filtriem)

• Satur divas interception metodes – preHandle un postHandle

• Satur vienu callback metodi –afterCompletion

• Tiek piesaistīts kontrolieru kopai kopā ar HandlerMapping

Piemērs: Interceptor config<beans> <bean id="handlerMapping" class="org.springframework.web.

servlet.handler.SimpleUrlHandlerMapping">

<property name="interceptors"> <list> <ref bean="officeHoursInterceptor"/> </list> </property> <property name="mappings"> <value> /*.form=editAccountFormController

</value> </property> </bean>

<bean id="officeHoursInterceptor" class="samples.TimeBasedAccessInterceptor"> <property name="openingTime" value="9"/> <property name="closingTime" value="18"/> </bean><beans>

Piesaista interceptoruvisiem pieprasījumiem

Piemērs: Interceptor kods

public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

. . .

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

Calendar cal = Calendar.getInstance(); int hour = cal.get(HOUR_OF_DAY); if (openingTime <= hour < closingTime) { return true; } else { response.sendRedirect(

"http://host.com/outsideOfficeHours.html");

return false; } }}

Resursi

• Spring Homehttp://www.springsource.org/

• C. Walls, R.Breidenbach. Spring in Action • http://www.manning.com/walls2/

• Seth Ladd et al. Expert Spring MVC And Web Flowhttp://www.amazon.com/Expert-Spring-MVC-Web-Flow/dp/

159059584X

• Spring Web MVC Framework http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html

Resursi

• Spring form tagshttp://static.springsource.org/spring/docs/current/spring-framework-reference/html/spring-form.tld.html