Spring MVC Beginner’s Guide Beginner's Amuthan G

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 545 [warning: Documents this large are best viewed by clicking the View PDF Link!]

SpringMVCBeginnersGuide
TableofContents
SpringMVCBeginnersGuide
Credits
AbouttheAuthor
AbouttheReviewers
www.PacktPub.com
Supportfiles,eBooks,discountoffers,andmore
Whysubscribe?
FreeaccessforPacktaccountholders
Preface
Whatthisbookcovers
Whatyouneedforthisbook
Whothisbookisfor
Conventions
Timeforaction–heading
Whatjusthappened?
Popquiz–heading
Haveagohero–heading
Readerfeedback
Customersupport
Downloadingtheexamplecode
Errata
Piracy
Questions
1.ConfiguringaSpringDevelopmentEnvironment
SettingupJava
Timeforaction–installingJDK
Timeforaction–settingupenvironmentvariables
Configuringabuildtool
Timeforaction–installingtheMavenbuildtool
Installingawebserver
Timeforaction–installingtheTomcatwebserver
Configuringadevelopmentenvironment
Timeforaction–installingSpringToolSuite
Timeforaction–configuringTomcatonSTS
Whatjusthappened?
Timeforaction–configuringMavenonSTS
CreatingourfirstSpringMVCproject
Timeforaction–creatingaSpringMVCprojectinSTS
Whatjusthappened?
SpringMVCdependencies
Timeforaction–addingSpringjarstotheproject
Whatjusthappened?
Timeforaction–addingJavaversionpropertiesinpom.xml
Ajump-starttoMVC
Timeforaction–addingawelcomepage
Whatjusthappened?
Thedispatcherservlet
Timeforaction–configuringthedispatcherservlet
Whatjusthappened?
Deployingourproject
Timeforaction–runningtheproject
Summary
2.SpringMVCArchitecture–ArchitectingYourWebStore
Thedispatcherservlet
Timeforaction–examiningrequestmapping
Whatjusthappened?
Popquiz–requestmapping
Thewebapplicationcontext
Timeforaction–understandingthewebapplicationcontext
Whatjusthappened?
Popquiz–thewebapplicationcontext
Thewebapplicationcontextconfiguration
Popquiz–webapplicationcontextconfiguration
Viewresolvers
Timeforaction–understandingInternalResourceViewResolver
Whatjusthappened?
ModelViewController
AnoverviewoftheSpringMVCrequestflow
Thewebapplicationarchitecture
Thedomainlayer
Timeforaction–creatingadomainobject
Whatjusthappened?
Thepersistencelayer
Timeforaction–creatingarepositoryobject
Whatjusthappened?
Theservicelayer
Timeforaction–creatingaserviceobject
Whatjusthappened?
Haveagohero–accessingtheproductdomainobjectviaaservice
Anoverviewofthewebapplicationarchitecture
Haveagohero–listingallourcustomers
Summary
3.ControlYourStorewithControllers
Definingacontroller
Timeforaction–addingclass-levelrequestmapping
Whatjusthappened?
Popquiz–class-levelrequestmapping
TheroleofacontrollerinSpringMVC
Handlermapping
UsingURItemplatepatterns
Timeforaction–showingproductsbasedoncategory
Whatjusthappened?
Popquiz–requestpathvariable
Usingmatrixvariables
Timeforaction–showingtheproductsbasedonfilter
Whatjusthappened?
Understandingrequestparameters
Timeforaction–addingtheproductdetailspage
Whatjusthappened?
Popquiz–therequestparameter
Timeforaction–implementingamasterdetailview
Whatjusthappened?
Haveagohero–addingmultiplefilterstolistproducts
Summary
4.WorkingwithSpringTagLibraries
Servingandprocessingforms
Timeforaction–servingandprocessingforms
Whatjusthappened?
Customizingdatabinding
Timeforaction–whitelistingformfields
Whatjusthappened?
Externalizingtextmessages
Timeforaction–externalizingmessages
Whatjusthappened?
UsingSpringSecuritytags
Timeforaction–addingaloginpage
Whatjusthappened?
Summary
5.WorkingwithViewResolver
Resolvingviews
Theredirectview
Timeforaction–examiningRedirectView
Whatjusthappened?
Popquiz–redirectview
Servingstaticresources
Timeforaction–servingstaticresources
Whatjusthappened?
Popquiz–staticview
Timeforaction–addingimagestotheproductdetailpage
Whatjusthappened?
Themultipartrequestinaction
Timeforaction–addingimagestotheproductpage
Whatjusthappened?
Haveagohero–uploadingproductusermanualstotheserver
UsingContentNegotiatingViewResolver
Timeforaction–configuringContentNegotiatingViewResolver
Whatjusthappened?
Workingwiththehandlerexceptionresolver
Timeforaction–addingtheresponsestatusexception
Whatjusthappened?
Timeforaction–addinganexceptionhandler
Whatjusthappened?
Summary
6.InterceptYourStorewithInterceptor
Workingwithinterceptors
Timeforaction–configuringaninterceptor
Whatjusthappened?
Popquiz–interceptor
Internationalization(i18n)
Timeforaction–addinginternationalization
Whatjusthappened?
Haveagohero–fullyinternationalizetheproductdetailpage
Auditlogging
Timeforaction–addingthedataauditinterceptor
Whatjusthappened?
Conditionalredirecting
Timeforaction–interceptingofferpagerequests
Whatjusthappened?
Summary
7.ValidateYourProductswithaValidator
Beanvalidation
Timeforaction–addingbeanvalidationsupport
Whatjusthappened?
Haveagohero–addingmorevalidationintheaddproductspage
CustomvalidationwithJSR-303/beanvalidation
Timeforaction–addingcustomvalidationsupport
Whatjusthappened?
Haveagohero–addingcustomvalidationtoacategory
Springvalidation
Timeforaction–addingSpringvalidation
Whatjusthappened?
Timeforaction–combiningSpringandbeanvalidations
Whatjusthappened?
Haveagohero–addingSpringvalidationtotheproductimage
Summary
8.GiveRESTtoYourApplicationwithAjax
IntroducingREST
Timeforaction–implementingRESTfulwebservices
Whatjusthappened?
Timeforaction–consumingRESTwebservices
Whatjusthappened?
HandlingawebserviceinAjax
Timeforaction–consumingRESTwebservicesviaAjax
Whatjusthappened?
Summary
9.ApacheTilesandSpringWebFlowinAction
WorkingwithSpringWebFlow
Timeforaction–implementingtheorder-processingservice
Whatjusthappened?
Timeforaction–implementingthecheckoutflow
Whatjusthappened?
Understandingtheflowdefinition
Understandingthecheckoutflow
Popquiz–webflow
Timeforaction–creatingviewsforeveryviewstate
Whatjusthappened?
Haveagohero–addingadecisionstate
EnhancingreusabilitythroughApacheTiles
Timeforaction–creatingviewsforeveryviewstate
Whatjusthappened?
Popquiz–ApacheTiles
Summary
10.TestingYourApplication
Unittesting
Timeforaction–unit-testingdomainobjects
Whatjusthappened?
Haveagohero–addingtestsforcart
IntegrationtestingwiththeSpringTestContextframework
Timeforaction–testingtheproductvalidator
Whatjusthappened?
Timeforaction–testingtheproductcontroller
Whatjusthappened?
Timeforaction–testingRESTcontrollers
Whatjusthappened?
Haveagohero–addingtestsfortheremainingRESTmethods
Summary
A.UsingtheGradleBuildTool
InstallingGradle
TheGradlebuildscriptforyourproject
UnderstandingtheGradlescript
B.PopQuizAnswers
Chapter2,SpringMVCArchitecture–ArchitectingYourWebStore
Popquiz–requestmapping
Popquiz–thewebapplicationcontext
Popquiz–webapplicationcontextconfiguration
Chapter3,ControlYourStorewithControllers
Popquiz–class-levelrequestmapping
Popquiz–requestpathvariable
Popquiz–therequestparameter
Chapter5,WorkingwithViewResolver
Popquiz–redirectview
Popquiz–staticview
Chapter6,InterceptYourStorewithInterceptor
Popquiz–interceptor
Chapter9,ApacheTilesandSpringWebFlowinAction
Popquiz–webflow
Popquiz–ApacheTiles
Index
SpringMVCBeginnersGuide
SpringMVCBeginnersGuide
Copyright©2014PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,
ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthe
publisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyofthe
informationpresented.However,theinformationcontainedinthisbookissoldwithout
warranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,andits
dealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecaused
directlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthe
companiesandproductsmentionedinthisbookbytheappropriateuseofcapitals.
However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:June2014
Productionreference:1190614
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78328-487-0
www.packtpub.com
CoverimagebyAniketSawant(<aniket_sawant_photography@hotmail.com>)
Credits
Author
AmuthanG
Reviewers
RafałBorowiec
PawanChopra
RubénClementeSerna
AcquisitionEditor
VinayArgekar
ContentDevelopmentEditor
AzharuddinSheikh
TechnicalEditors
MonicaJohn
NehaMankare
ShinyPoojary
CopyEditors
GladsonMonteiro
InsiyaMorbiwala
AdityaNair
StutiSrivastava
ProjectCoordinators
KinjalBari
WendellPalmer
Proofreaders
SimranBhogal
StephenCopestake
MariaGould
AmeeshaGreen
PaulHindle
Indexer
HemanginiBari
Graphics
DishaHaria
AbhinashSahu
ProductionCoordinator
AparnaBhagat
CoverWork
AparnaBhagat
AbouttheAuthor
AmuthanGhasoversixyearsofexperienceasaprofessionalsoftwaredeveloper.He
currentlyworksforalargecloudplatformcompanyandhasstrongproductdevelopment
experienceinJava,Spring,JPA,andmanyotherenterprisetechnologies.Inhisfreetime,
heenjoysbloggingonhissite(http://www.madebycode.in).Hecanbecontactedat
<mr.amuthan@gmail.com>.
IwouldliketogratefullyandsincerelythankMr.VincentKokforhisguidance,
understanding,patience,andmostimportantly,hisfriendshipduringmyfirstjobat
EducatorInc.Hismentorshiphasshapedmetobecomeawell-roundedprofessional.He
encouragedmetonotonlygrowasadeveloper,butalsoasanindependentthinker.
IwanttotakeamomentandexpressmygratitudetotheentireteamatPacktPublishing
fortheirpatienceandcooperation.WhenIsignedupforthisbook,Ireallyhadnoidea
howthingswouldturnout.Icouldn’thavepulledthisoffwithouttheirguidance.
Iwouldliketoexpressmygratitudetoallmyfriendsandfamilyforprovidingmewith
unendingencouragementandsupport.Ioweeverychallengeandaccomplishmenttoall
mylovelycolleagueswhotaughtmealotovertheyears.
AspecialthankstoDivyaandArunfortheirencouragement,friendship,andsupport.
Theywereastrongshouldertoleanoninthemostdifficulttimesduringthewritingof
thisbook.
Finally,andmostimportantly,IwouldliketothankmywifeManjuwhobelievesmemore
thanmyself.Hersupport,encouragement,quietpatience,andunwaveringlovewere
undeniablythebedrockuponwhichmylifehasbeenbuilt.
AbouttheReviewers
RafałBorowiecisanITspecialistwithabouteightyearsofcommercialexperience,
specializinginsoftwaretestingandqualityassurance,softwaredevelopment,project
management,andteamleadership.
HecurrentlyholdsthepositionofaTeamLeaderatGoyello,whereheismainly
responsibleforbuildingandmanagingteamsofprofessionaldevelopersandtesters.Heis
alsoresponsibleformaintainingrelationswithcustomersandacquiringnewones,mainly
throughconsultancy.
Hebelievesinagileprojectmanagementandisabigfanoftechnology,especially
technologythatisJavarelated(butnotlimitedtoit).Helikessharingknowledgeabout
softwaredevelopmentandpracticesthroughhisblog(blog.codeleak.pl)andTwitter
account(@kolorobot)andalsoatinternalandexternaleventssuchasconferencesor
workshops.
PawanChopraisanAgiledeveloperwitheightyearsofexperienceinthesoftware
industry.HecurrentlyworksatWebners(http://www.webnersolutions.com/)onsomecool
JavaScript,Java,HTML5,Node,andAngularJSprojects.Heisanopensourceenthusiast.
Helovessharingknowledgethroughtrainingandblogging.Heisalsoverystrongonthe
serversidewithvastexperienceinSpringandHibernatetools.Heblogsat
www.itspawan.com.
RubénClementeSernaisasoftwareengineerbyprofessionwithovereightyearsof
experienceinsoftwaredevelopment.HerecentlymovedtotheUKandiscurrently
workingasaJavaDeveloperatPiksel,acompanythatcreatesandmanagesOTTvideo
solutionsforsomeoftheworld’sleadingmediabrands.PriortoPiksel,hehasworkedat
GFIInformáticainSpainonmanyJavadevelopmentprojects,mainlyfortelecomand
governmentservicecustomers.
Moredetailedinformationabouthisskillsandexperiencecanbefoundat
http://www.linkedin.com/in/rubenclementeserna.Hecanbecontactedat
<rubenclemente@gmail.com>.
www.PacktPub.com
Supportfiles,eBooks,discountoffers,and
more
Youmightwanttovisitwww.PacktPub.comforsupportfilesanddownloadsrelatedto
yourbook.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFand
ePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandas
aprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwith
usat<service@packtpub.com>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signup
forarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooks
andeBooks.
http://PacktLib.PacktPub.com
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigital
booklibrary.Here,youcanaccess,readandsearchacrossPackt’sentirelibraryofbooks.
Whysubscribe?
FullysearchableacrosseverybookpublishedbyPackt
Copyandpaste,printandbookmarkcontent
Ondemandandaccessibleviawebbrowser
FreeaccessforPacktaccountholders
IfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccess
PacktLibtodayandviewnineentirelyfreebooks.Simplyuseyourlogincredentialsfor
immediateaccess.
Preface
Thisbookhasaveryclearaim:tointroduceyoutotheincrediblesimplicityandpowerof
SpringMVC.IstillrememberfirstlearningabouttheSpringframeworkbackin2009.
Thebestwaytotestwhetherornotyoureallyunderstandaconceptistotrytoteachitto
someoneelse.Inmycase,IhavetaughtSpringMVCtoMVC;areyouconfused?Imean
thatbackin2009,ItaughtittomywifeManjuViswambaranChandrika(MVC).During
thatcourse,Iwasabletounderstandthekindofdoubtsthatariseinabeginnersmind.I
havegatheredallmyteachingknowledgeandputitinthisbookinanelegantwaysothat
itcanbeunderstoodwithoutconfusion.
Thisbookfollowsathemeofdevelopingasimplee-commercesitestep-by-step.Inevery
successivechapter,youwilllearnanewconceptofSpringMVC.Obviously,theaimisto
teachyouhowyoucanuseSpringMVCeffectively.Developingafull-blown,production-
readye-commercesiteisnotthepurposeofthisbook.
Whatthisbookcovers
Chapter1,ConfiguringaSpringDevelopmentEnvironment,willgiveyouaquick
overviewofSpringMVCanditsarchitectureandguideyouthroughdetailednotesand
step-by-stepinstructionstosetupyourdevelopmentenvironment.Afterinstallingthe
requiredprerequisites,youwilltryoutaquickexampleofhowtodevelopanapplication
withSpringMVC.Althoughthechapterdoesn’texplainallthecodeindetail,you’llpick
upafewthingsintuitively.
Chapter2,SpringMVCArchitecture–ArchitectingYourWebStore,willlaydownthe
groundworkforthesampleapplicationthatwearegoingtobuildalongtheway,chapter
bychapter.Thischapterwillintroduceyoutoconceptssuchasrequestmapping,web
applicationcontext,SpringMVCrequestflow,andthelayeredarchitectureofatypical
webapplication.
Chapter3,ControlYourStorewithControllers,willtakeyouthroughtheconceptofa
controller;youwilllearnmoreabouthowtodefineacontroller,anduseURItemplate
patterns,matrixvariables,andrequestparameters.
Chapter4,WorkingwithSpringTagLibraries,willteachyouhowtouseSpringand
Springformtaglibrariesinwebformhandling.Youwilllearnhowtobinddomainobjects
withviewsandhowtousemessagebundlestoexternalizelabelcaptiontexts.Attheend
ofthischapter,youwillseehowtoaddaloginform.
Chapter5,WorkingwithViewResolver,willpresenttheinnermechanicsofhow
InternalResourceViewResolverresolvesaviewandtakesyouthroughhowtouse
variousviewtypes,suchasredirectviewandstaticview.Youwillalsolearnaboutthe
multipartresolverandcontentnegotiationviewresolver.Finally,youwilllearnhowtouse
exceptionhandlerresolvers.
Chapter6,InterceptYourStorewithInterceptor,willpresenttheconceptofaninterceptor
toyou.Youwilllearnhowtoleveragetheinterceptortohandleortransformrequestsand
responsesflexibly.Thischapterwillteachyouhowtomakeyourwebpagesupport
internalizationwiththehelpofLocaleChangeInterceptor.Thischapteralsointroduces
howtoperformauditlogginginalogfileusingtheinterceptorconcept.
Chapter7,ValidateYourProductswithaValidator,willgiveyouanoverviewofthe
validationconcept.Youwilllearnaboutbeanvalidation,andyouwilllearnhowto
performcustomvalidationalongwiththestandardbeanvalidation.Youwillalsolearn
abouttheclassicSpringvalidationandhowtocombineitwithbeanvalidation.
Chapter8,GiveRESTtoYourApplicationwithAjax,willteachyouthebasicprinciplesof
RESTandAjax.YouwilllearnhowtodevelopanapplicationinRESTfulservices.The
basicconceptofHTTPverbsandhowtheyarerelatedtostandardCRUDoperationswill
beexplained,andyouwilllearnhowtofireanAjaxrequestandhandleitfromaweb
page.
Chapter9,ApacheTilesandSpringWebFlowinAction,willteachyouhowtousethe
Springwebflowtodevelopworkflow-basedwebpages.Youwilllearnmoreaboutstates
andtransitionsinwebflowandhowtodefineaflowdefinition.Thischapteralsoteaches
youhowtodecomposeapageusingApachetiles.Youwillalsolearnmoreabout
TileViewResolverandhowtodefinereusableApachetilestemplates.
Chapter10,TestingyourApplication,willteachyouhowtoleveragetheSpringtesting
capabilitytotestyourcontrollers.Youwilllearnhowtoloadthetestcontextandhowto
mocktheserviceandrepositorylayers.ThischapteralsointroducesyoutotheSpring
MVCtestmoduleandteachesyouhowtousethat.
AppendixA,UsingtheGradleBuildTool,introducesyoutousingtheGradlebuildtool
foroursampleapplication.YouwilllearnabouttheGradlescriptthatisrequiredtobuild
ourprojectusingGradlebuildtool.
Whatyouneedforthisbook
Toruntheexamplesinthebook,thefollowingsoftwarewillberequired:
JavaSEDevelopmentKit7u45ornewer
Maven3.1.0
ApacheTomcat7.0
STS3.4.0release(SpringToolSuite)
Whothisbookisfor
Thisbookisdesignedtobefollowedfrombeginningtoend,althoughthosewithexisting
knowledgeofSpringMVCwillbeabletojumpintothelaterchaptersandpickoutthings
thatareimportanttothem.YouarenotexpectedtobeexperiencedwiththeSpring
framework.Someknowledgeofservletprogramminganddependencyinjectionwillbe
helpfulbutnotessential.Inanutshell,thebookprovidesclearpictures,illustrations,
concepts,andisideallysuitedforbeginnersandintermediatedevelopers.
Conventions
Inthisbook,youwillfindseveralheadingsappearingfrequently.
Togiveclearinstructionsofhowtocompleteaprocedureortask,weuse:
Timeforaction–heading
1. Action1
2. Action2
3. Action3
Instructionsoftenneedsomeextraexplanationsothattheymakesense,sotheyare
followedwith:
Whatjusthappened?
Thisheadingexplainstheworkingoftasksorinstructionsthatyouhavejustcompleted.
Youwillalsofindsomeotherlearningaidsinthebook,including:
Popquiz–heading
Theseareshortmultiple-choicequestionsintendedtohelpyoutestyourown
understanding.
Haveagohero–heading
Thesepracticalchallengesgiveyouideasforexperimentingwithwhatyouhavelearned.
Youwillalsofindanumberofstylesoftextthatdistinguishbetweendifferentkindsof
information.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.
Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,
pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Once
thedownloadisfinished,gotothedownloadeddirectoryandextractthe.zipfileintoa
convenientdirectoryofyourchoice.”
Ablockofcodeissetasfollows:
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>${greeting}</h1>
<p>${tagline}</p>
</div>
</div>
</section>
</body>
Whenwewishtodrawyourattentiontoaparticularpartofacodeblock,therelevant
linesoritemsaresetinbold:
<servlet>
<servlet-name>DefaultServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
Anycommand-lineinputoroutputiswrittenasfollows:
C:\>mvn-version
ApacheMaven3.2.1(ea8b2b07643dbb1b84b6d16e1f08391b666bc1e9;2014-02-
14T12:37:52-05:00)
Mavenhome:C:\ProgramFiles\apache-maven-3.2.1
Javaversion:1.7.0_51,vendor:OracleCorporation
Javahome:C:\ProgramFiles\Java\jdk1.7.0_51\jre
Defaultlocale:en_SG,platformencoding:Cp1252
OSname:"windows7",version:"6.1",arch:"amd64",family:"windows"
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,in
menusordialogboxesforexample,appearinthetextlikethis:“ASystemProperties
windowwillappear;inthiswindow,selecttheAdvancedtabandclickonthe
EnvironmentVariablesbuttontoopentheenvironmentvariableswindow.”
Note
Warningsorimportantnotesappearinaboxlikethis.
Tip
Tipsandtricksappearlikethis.
Readerfeedback
Feedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthis
book—whatyoulikedormayhavedisliked.Readerfeedbackisimportantforusto
developtitlesthatyoureallygetthemostoutof.
Tosendusgeneralfeedback,simplysendane-mailto<feedback@packtpub.com>,and
mentionthebooktitlethroughthesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingor
contributingtoabook,seeourauthorguideonwww.packtpub.com/authors.
Customersupport
NowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelp
youtogetthemostfromyourpurchase.
Downloadingtheexamplecode
YoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfrom
youraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcan
visithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlyto
you.
Errata
Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdo
happen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthe
code—wewouldbegratefulifyouwouldreportthistous.Bydoingso,youcansave
otherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.If
youfindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-
errata,selectingyourbook,clickingontheerratasubmissionformlink,andenteringthe
detailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedand
theerratawillbeuploadedtoourwebsite,oraddedtoanylistofexistingerrata,underthe
Erratasectionofthattitle.
Piracy
PiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.At
Packt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucome
acrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswith
thelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<copyright@packtpub.com>withalinktothesuspectedpirated
material.
Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluable
content.
Questions
Youcancontactusat<questions@packtpub.com>ifyouarehavingaproblemwithany
aspectofthebook,andwewilldoourbesttoaddressit.
Chapter1.ConfiguringaSpring
DevelopmentEnvironment
Inthischapter,wearegoingtakealookathowwecancreateabasicSpringMVC
application.InordertodevelopaSpringMVCapplication,weneedsomeprerequisite
softwareandtools.First,wearegoingtolearnhowtoinstallalltheprerequisitesthatare
requiredtosetupourdevelopmentenvironmentsothatwecanstartdevelopingthe
application.
ThesetupandinstallationstepsgivenhereareforWindowsoperatingsystems,butdon’t
worry,asthestepsmaychangeonlyslightlyforotheroperatingsystems.Youcanalways
refertotherespectivetools/softwarevendorswebsitestoinstalltheminotheroperating
systems.Inthischapter,wewilllearnhowtosetupJavaandconfiguretheMavenbuild
tool,installtheTomcatwebserver,installandconfiguretheSpringtoolsuite,andcreate
andrunourfirstSpringMVCproject.
SettingupJava
Obviously,thefirstthingthatweneedtodoisgetstartedwithJava.Themoretechnical
nameforJavaisJavaDevelopmentKit(JDK).JDKincludesaJavacompiler(javac),a
Javavirtualmachine,andavarietyofothertoolstocompileandrunJavaprograms.
Timeforaction–installingJDK
WearegoingtouseJava7butJava6oranyhigherversionisalsosufficient.Let’stakea
lookathowwecaninstallJDKonWindowsoperatingsystems:
1. GototheJavaSEdownloadpageontheOraclewebsitebyenteringthefollowing
URLinyourbrowser:
http://www.oracle.com/technetwork/java/javase/downloads/index.html.
2. ClickontheJavaplatformJDK7downloadlink;thiswilltakeyoutothelicense
agreementpage.Acceptthelicenseagreementbyselectingthatoptioninradio
button.
3. Now,clickonthelisteddownloadlinkthatcorrespondstoyourWindowsoperating
systemarchitecture;forinstance,ifyouroperatingsystemisoftype32bit,clickon
thedownloadlinkthatcorrespondstoWindowsx86.Or,ifyouroperatingsystemis
oftype64bit,clickonthedownloadlinkthatcorrespondstoWindowsx64.
4. Now,itwillstartdownloadingtheinstaller.Oncethedownloadisfinished,gotothe
downloadeddirectoryanddouble-clickontheinstaller.Thiswillopenupthe
followingwizardwindow;justclickontheNextbuttoninthewizard,leavingthe
defaultoptionsalone,andclickontheClosebuttonattheendofthewizard:
JDKinstallationwizard
Tip
Additionally,aseparatewizardalsopromptsyoutoinstallJavaRuntime
Environment(JRE).GothroughthatwizardaswelltoinstallJREinyoursystem.
5. NowyoucanseetheinstalledJDKdirectoryinthedefaultlocation;inourcase,the
defaultlocationisC:\ProgramFiles\Java\jdk1.7.0_25.
Timeforaction–settingupenvironment
variables
AfterinstallingJDK,westillneedtoperformsomemoreconfigurationstouseJava
convenientlyfromanydirectoryonourcomputer.Bysettinguptheenvironmentvariables
forJavaintheWindowsoperatingsystem,wecanmaketheJavacompilerandtools
availabletotheentireoperatingsystem:
1. NavigatetoControlPanel|System|Advancedsystemsettings.
2. ASystemPropertieswindowwillappear;inthiswindow,selecttheAdvancedtab
andclickontheEnvironmentVariablesbuttontoopentheenvironmentvariables
window.
3. Now,clickontheNewbuttonintheSystemvariablespanel,enterJAVA_HOMEasthe
variablename,andentertheinstalledJDKdirectorypathasthevariablevalue;inour
case,thisisC:\ProgramFiles\Java\jdk1.7.0_51.Incaseyoudonothaveproper
rightsfortheoperatingsystem,youwillnotbeabletoeditSystemvariables;inthat
case,youcancreatetheJAVA_HOMEvariableundertheUservariablespanel.
4. Now,inthesameSystemvariablespanel,double-clickonthePATHvariableentry;
anEditSystemVariablewindowwillappear.
SettingPATHEnvironmentvariable
5. EditVariablevalueofPathbyappendingthe;%JAVA_HOME%\bintexttoitsexisting
value.
Tip
Editthepathvariablecarefully;youshouldonlyappendthetextattheendofexisting
value.Don’tdeleteordisturbtheexistingvalues;makesureyouhaven’tmissedthe;
(semicolon)markasthatisthefirstletterinthetextthatyouwillappend.
6. NowclickontheOKbutton.
NowwehaveinstalledJavainourcomputer.Toverifywhetherourinstallationhasbeen
carriedoutcorrectly,openanewcommandwindowandtypejava–versionandpress
Enter;youwillseetheinstalledversionofJavaonthescreen:
C:\>java-version
javaversion"1.7.0_51"
Java(TM)SERuntimeEnvironment(build1.7.0_51-b13)
JavaHotSpot(TM)64-BitServerVM(build24.51-b03,mixedmode)
Configuringabuildtool
Buildingasoftwareprojecttypicallyincludessomeactivitiessuchasthefollowing:
Compilingallthesourcecode
Generatingthedocumentationfromthesourcecode
PackagingthecompiledcodeintoaJARorWARarchivefile
Installingthepackagedarchivesfilesonaserver
Manuallyperformingallthesetasksistimeconsumingandispronetoerrors.Therefore,
wetakethehelpofabuildtool.Abuildtoolisatoolthatautomateseverythingrelatedto
buildingasoftwareproject,fromcompilingtodeploying.
Timeforaction–installingtheMaven
buildtool
ManybuildtoolsareavailableforbuildingaJavaproject.WearegoingtouseMaven
3.2.1asourbuildtool.Let’stakealookathowwecaninstallMaven:
1. GotoMaven’sdownloadpagebyenteringthefollowingURLonyourbrowser:
http://maven.apache.org/download.cgi
2. Clickontheapache-maven-3.2.1-bin.zipdownloadlink,andstartthedownload.
3. Oncethedownloadisfinished,gotothedownloadeddirectoryandextractthe.zip
fileintoaconvenientdirectoryofyourchoice.
4. Nowweneedtocreateonemoreenvironmentvariable,calledM2_HOME,inawaythat
issimilartothewayinwhichwecreatedJAVA_HOME.EntertheextractedMavenzip
directory’spathasthevaluefortheM2_HOMEenvironmentvariable.
5. Createonemoreenvironmentvariable,calledM2,withthevalue%M2_HOME%\bin,as
showninthefollowingscreenshot:
SettingtheM2environmentvariable
6. FinallyappendtheM2variabletothePATHenvironmentvariableaswellbysimply
appendingthe;%M2%texttothePATHvariable’svalue.
NowwehaveinstalledtheMavenbuildtoolinourcomputer.Toverifywhetherour
installationhasbeencarriedoutcorrectly,weneedtofollowstepsthataresimilartothe
Javainstallationverification.Openanewcommandwindow,typemvn–version,and
pressEnter;youwillseethefollowingdetailsoftheMavenversion:
C:\>mvn-version
ApacheMaven3.2.1(ea8b2b07643dbb1b84b6d16e1f08391b666bc1e9;2014-02-
14T12:37:52-05:00)
Mavenhome:C:\ProgramFiles\apache-maven-3.2.1
Javaversion:1.7.0_51,vendor:OracleCorporation
Javahome:C:\ProgramFiles\Java\jdk1.7.0_51\jre
Defaultlocale:en_SG,platformencoding:Cp1252
OSname:"windows7",version:"6.1",arch:"amd64",family:"windows"
Installingawebserver
Sofar,wehavelearnedhowtoinstallJDKandMaven.Usingthesetools,wecancompile
theJavasourcecodeintothe.classfilesandpackagethese.classfilesintothe.jaror
.wararchives.However,howdowerunourpackagedarchives?Todothis,wetakethe
helpofawebserver;awebserverwillhostourpackagedarchivesasarunning
application.
Timeforaction–installingtheTomcat
webserver
ApacheTomcatisapopularJavawebservercumservletcontainer.Wearegoinguse
ApacheTomcatVersion7.0.Let’stakealookathowwecaninstalltheTomcatweb
server:
1. GototheApacheTomcathomepageusingthefollowingURLlink:
http://tomcat.apache.org/
2. ClickontheTomcat7.0downloadlink,anditwilltakeyoutothedownloadpage.
3. Clickonthe32-bit/64-bitWindowsServiceInstallerlink;itwillstartdownloading
theinstaller.
4. Oncethedownloadisfinished,gotothedownloadeddirectoryanddouble-clickon
theinstaller;thiswillopenupawizardwindow.
5. Justclickthroughthenextbuttonsinthewizard,leavingthedefaultoptionsalone,
andclickontheFinishbuttonattheendofthewizard.Notethatbeforeclickingon
theFinishbutton,justensurethatyouhaveuncheckedRunApacheTomcat
checkbox.
InstallingApacheTomcatwiththedefaultoptionworkssuccessfullyonlyifyouhave
installedJavainthedefaultlocation.Otherwise,youhavetocorrectlyprovidetheJRE
pathaccordingtothelocationofyourJavainstallationduringtheinstallationofTomcat,
asshowninthefollowingscreenshot:
TheJavaruntimeselectionfortheTomcatinstallation
Configuringadevelopmentenvironment
WeinstalledJavaandMaventocompileandpackageJavasourcecode,andweinstalled
Tomcattodeployandrunourapplication.However,priortoallthis,wehavetowritethe
SpringMVCcodesothatwecancompile,package,andrunthecode.
Wecanuseanysimpletexteditoronourcomputertowriteourcode,butthatwon’thelp
usmuchwithfeaturessuchasfindingsyntaxerrorsaswetype,autosuggestingimportant
keywords,syntaxhighlighting,easynavigation,andsoon.
IntegratedDevelopmentEnvironment(IDE)canhelpuswiththesefeaturestodevelop
thecodefasteranderrorfree.WearegoingtouseSpringToolSuite(STS)asourIDE.
Timeforaction–installingSpringTool
Suite
STSisthebestEclipse-powereddevelopmentenvironmenttobuildSpringapplications.
Let’stakealookathowwecaninstallSTS:
1. GototheSTSdownloadpageathttp://spring.io/tools/sts/all.
2. ClickontheSTSinstaller.exelinktodownloadthefilethatcorrespondstoyour
windowsoperatingsystemarchitecturetype(32bitor62bit);thiswillstartthe
downloadoftheinstaller.TheSTSstablereleaseversionatthetimeofwritingthis
bookisSTS3.4.0.RELEASEbasedonEclipse4.3.1.
3. Oncethedownloadisfinished,gotothedownloadeddirectoryanddouble-clickon
theinstaller;thiswillopenupawizardwindow.
4. Justclickthroughthenextbuttonsinthewizard,leavingthedefaultoptionsalone;if
youwanttocustomizetheinstallationdirectory,youcanspecifythatinthestepsyou
performinthewizard.
Tip
Downloadingtheexamplecode
YoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchased
fromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbook
elsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethe
filese-maileddirectlytoyou.
5. Instep5ofthewizard,youhavetoprovidetheJDKpath;justentertheJDKpath
thatyouconfiguredfortheJAVA_HOMEenvironmentvariable,asshowninthe
followingscreenshot:
SettingtheJDKpathduringtheSTSinstallation
WehavealmostinstalledallthetoolsandsoftwarerequiredtodevelopaSpringMVC
application,sonow,wecancreateourSpringMVCprojectonSTS.However,before
jumpingintocreatingaproject,weneedtoperformafinalconfigurationforSTS.
Timeforaction–configuringTomcaton
STS
AsIalreadymentioned,wecanusetheTomcatwebservertodeployourapplication,but
wehavetoinformSTSaboutthelocationoftheTomcatcontainersothatwecaneasily
deployourprojectfromSTStoTomcat.Let’sconfigureTomcatonSTS:
1. OpenSTSfromthestartmenuoptionorthedesktopicon.
2. STSwillaskyoutoprovideaworkspacedirectorylocation;provideaworkspace
directorypathasyouwishandclickontheOKbutton.
3. Now,STSwillshowyouawelcomescreen.Closethewelcomescreenandgotothe
menubarandnavigatetoWindow|preferences|Server|RuntimeEnvironments.
4. Youcanseetheavailableserverslistedontheright-handside;youmayalsosee
VMwarevFabrictcServerlistedundertheavailableservers,whichcomesalong
withtheSTSinstallation.
5. NowclickontheAddbuttontoaddourTomcatwebserver.
6. Awizardwindowwillappear;typetomcatintheSelectthetypeofruntime
environment:textbox,andalistofavailableTomcatversionswillbeshown.Just
selectTomcatv7.0andselecttheCreateanewlocalservercheckbox.Finally,click
ontheNextbutton,asshowninthefollowingscreenshot:
SelectingtheservertypeduringtheTomcatconfigurationonSTS
7. Inthenextwindow,clickontheBrowsebuttonandlocateTomcat’sinstalled
directory,andclickontheOKbutton.YoucanfindTomcat’sinstalleddirectory
underC:\ProgramFiles\ApacheSoftwareFoundation\Tomcat7.0ifyouhave
installedTomcatinthedefaultlocation.Then,clickontheFinishbutton,asshownin
thefollowingscreenshot:
SelectingtheTomcatlocationduringtheTomcatconfigurationonSTS
Whatjusthappened?
Instep2,weprovidedaworkspacepathforSTS.WhenyouopenSTSfortheveryfirst
timeafterinstallingSTS,itwillaskyoutoprovideaworkspacelocation.Thisisbecause
whenyoucreateaprojectonSTS,allyourprojectfileswillbecreatedunderthislocation
only.
OnceweenterSTS,weshouldinformSTSwheretheTomcathasbeeninstalled.Only
thencanSTSuseyourTomcatwebservertodeploytheproject.Thisisalsoaone-time
configuration;youneednotperformthisconfigurationeverytimeyouopenSTS.Wedid
thisbycreatinganewserverruntimeenvironmentinstep5.AlthoughSTSmightcome
withaninternalVMwarevFabrictcServer,wechosetousetheTomcatwebserveras
ourserverruntimeenvironment.
Timeforaction–configuringMavenon
STS
WelearnedhowtoconfigureTomcatonSTS.Similarly,tobuildourproject,STSwilluse
Maven.ButwehavetotellSTSwhereMavenhasbeeninstalledsothatitcanusethe
Maveninstallationtobuildourprojects.Let’stakealookathowwecanconfigureMaven
onSTS:
1. OpenSTSifitisnotalreadyopen.
2. NavigatetoWindow|Preferences|Maven|Installations.
3. Ontheright-handside,youcanseetheAddbutton,tolocateMaven’sinstallation.
4. ClickontheAddbuttonandchooseMaven’sinstalleddirectory,asshowninthe
followingscreenshot:
SelectingMaven’slocationduringtheMavenconfigurationonSTS
5. NowclickontheOKbuttoninthePreferenceswindowandcloseit.
CreatingourfirstSpringMVCproject
Sofar,wehavelearnedhowwecaninstallalltheprerequisitetoolsandsoftware.Nowwe
aregoingtodevelopourfirstSpringMVCapplicationusingSTS.STSprovidesaneasy-
to-useprojecttemplate.Usingthesetemplates,wecanquicklycreateourprojectdirectory
structureswithoutmanyproblems.
Timeforaction–creatingaSpringMVC
projectinSTS
Let’screateourfirstspringMVCprojectinSTS:
1. InSTS,navigatetoFile|New|Project;aNewProjectwizardwindowwillappear.
2. SelectMavenProjectfromthelistandclickontheNextbutton,asshowninthe
followingscreenshot:
Mavenproject’stemplateselection
3. Now,aNewMavenProjectdialogwindowwillappear;justselectthecheckboxthat
hastheCreateasimpleproject(skiparchetypeselection)caption,andclickonthe
Nextbutton.
4. Thewizardwillaskyoutospecifyartifact-relatedinformationforyourproject;just
enterGroupIdascom.packt,ArtifactIdaswebstore.Then,selectPackagingas
warandclickontheFinishbutton,asshowninthefollowingscreenshot:
Whatjusthappened?
Wejustcreatedthebasicprojectstructure.AnyJavaprojectfollowsacertaindirectory
structuretoorganizeitssourcecodeandstaticresources.Insteadofmanuallycreatingthe
wholedirectoryhierarchybyourselves,wejusthandedoverthatjobtoSTS.Bycollecting
somebasicinformationaboutourproject,suchasGroupId,ArtifactId,andthe
Packagingstylefromus,itisclearthatSTSissmartenoughtocreatethewholeproject
directorystructurewiththehelpoftheMavenplugin.Actually,whatishappeningbehind
thescreenisthatSTSisinternallyusingMaventocreatetheprojectstructure.
Wewantourprojecttobedeployableinanyservletcontainer-basedwebserver,suchas
Tomcat,andthat’swhyweselectedthePackagingstyleaswar.Afterexecutingstep4,
youwillseetheprojectstructureinPackageExplorer,asshowninthefollowing
screenshot:
Theprojectstructureoftheapplication
SpringMVCdependencies
AswearegoingtouseSpringMVCAPIsheavilyinourproject,weneedtheSpringjars
inourprojectduringthedevelopment.AsIalreadymentioned,Mavenwilltakecareof
managingdependenciesandpackagingtheproject.
Timeforaction–addingSpringjarsto
theproject
Let’stakealookathowwecanaddthespring-relatedjarsviatheMavenconfiguration:
1. Openpom.xml;youcanfindpom.xmlundertherootdirectoryoftheprojectitself.
2. Youwillseesometabsatthebottomofthepom.xmlfile.Ifyoudonotseethesetabs,
thenright-clickonpom.xmlandselecttheOpenWithoptionfromthecontextmenu
andchooseMavenPOMeditor.SelecttheDependenciestabandclickontheAdd
buttonintheDependenciessection.Don’tgetconfusedwiththeAddbuttonofthe
DependenciesManagementsection.YoushouldchoosetheAddbuttonintheleft-
handsidepane.
3. ASelectDependencywindowwillappear;enterGroupIdas
org.springframework,ArtifactIdasspring-webmvc,andVersionas
4.0.3.RELEASE.SelectScopeascompileandthenclickontheOKbutton,asshown
inthefollowingscreenshot:
4. Similarly,addthedependencyforJavaServerPagesStandardTagLibrary(JSTL)
byclickingonthesameAddbutton;thistime,enterGroupIdasjavax.servlet,
ArtifactIdasjstl,Versionas1.2,andselectScopeascompile.
5. Finally,addonemoredependencyforservlet-api;repeatthesamestepwithGroup
Idasjavax.servlet,ArtifactIdasjavax.servlet-api,andVersionas3.1.0,but
thistime,selectScopeasprovidedandthenclickontheOKbutton.
6. Asalaststep,don’tforgettosavethepom.xmlfile.
Whatjusthappened?
IntheMavenworld,pom.xml(ProjectObjectModel)istheconfigurationfilethatdefines
therequireddependencies.Whilebuildingourproject,Mavenwillreadthatfileandtryto
downloadthespecifiedjarsfromtheMavencentralbinaryrepository.YouneedInternet
accessinordertodownloadjarsfromMaven’scentralrepository.Mavenusesan
addressingsystemtolocateajarinthecentralrepository,whichconsistsofGroupId,
ArtifactId,andVersion.
Everytimeweaddadependency,anentrywillbemadewithinthe<dependencies></
dependencies>tagsinthepom.xmlfile.Forexample,ifyougotothepom.xmltabafter
finishingstep3,youwillseeanentryforspring-mvcasfollowswithinthe
<dependencies></dependencies>tag:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.3.RELEASE</version>
</dependency>
Weaddedthedependencyforspring-mvcinstep3,andinstep4,weaddedthe
dependencyforJSTL.JSTLisacollectionofusefulJSPtagsthatcanbeusedtowriteJSP
pageseasily.Finally,weneedaservlet-apijarinordertouseservlet-relatedcode;thisis
whatweaddedinstep5.
However,thereisalittledifferenceinthescopeoftheservlet-apidependencycompared
totheothertwodependencies.Weonlyneedservlet-apiwhilecompilingourproject.
Whilepackagingourprojectaswar,wedon’twanttotheshipservlet-apijaraspartofour
project.ThisisbecausetheTomcatwebserverwouldprovidetheservlet-apijarwhile
deployingourproject.Thisiswhyweselectedthescopeasprovidedfortheservlet-api.
Afterfinishingstep6,youwillseeallthedependentjarsconfiguredinyourproject,as
showninthefollowingscreenshot,undertheMavenDependencieslibrary:
Weaddedonlythreejarsasourdependencies,butifyounoticeinourMavendependency
librarylist,youwillseemorethanthreejarentries.Canyouguesswhy?Whatifour
dependentjarshaveadependencyonotherjarsandsoon?
Forexample,ourspring-mvcjarisdependentonthespring-core,spring-context,and
spring-aopjars,butwehavenotspecifiedthosejarsinourpom.xmlfile;thisiscalled
transitivedependenciesintheMavenworld.Inotherwords,wecansaythatourproject
istransitivelydependentonthesejars.Mavenwillautomaticallydownloadallthese
transitivedependentjars;thisisthebeautyofMaven.Itwilltakecareofallthe
dependencymanagementautomatically;weneedtoinformMavenonlyaboutthefirst
leveldependencies.
Timeforaction–addingJavaversion
propertiesinpom.xml
Wesuccessfullyaddedalltherequiredjarstoourproject,butweneedtoperformone
smallconfigurationinourpom.xmlfile,thatis,tellingMaventouseJavaVersion7while
buildingourproject.HowdowetellMaventodothis?Simplyaddtwopropertyentriesin
pom.xml.Let’sdothis.
1. Openpom.xml.Youwillseesometabsatthebottomofpom.xml;selecttheOverview
tabfromthebottomofpom.xml,expandthepropertiesaccordion,andclickonthe
Createbutton.
2. Now,anAddpropertywindowwillappear;enterNameasmaven.compiler.source
andValueas1.7.
AddingtheJavacompilerversionpropertiestoPOM
3. Similarly,createonemorepropertywithNameasmaven.compiler.targetand
Valueas1.7.
4. Finally,savepom.xml.
Ajump-starttoMVC
Wecreatedourprojectandaddedalltherequiredjars,sowearereadytocode.Weare
goingtoincrementallybuildanonlinewebstorethroughoutthisbook,chapterbychapter.
Asafirststep,let’screateahomepageinourprojecttowelcomeourcustomers.
Ouraimissimple;whenweenterthehttp://localhost:8080/webstore/URLonthe
browser,wewouldliketoshowawelcomepagethatissimilartothefollowing
screenshot:
Don’tworryifyouarenotabletounderstandsomeofthecode;wearegoingtotakea
lookateachconceptindetailintheupcomingchapters.Asofnow,ouraimistohave
quickhands-onexperienceofdevelopingasimplewebpageusingSpringMVC.
Timeforaction–addingawelcomepage
Tocreateandaddawelcomepage,weneedtoexecutethefollowingsteps:
1. CreateaWEB-INF/jsp/directorystructureunderthesrc/main/webapp/directory;
createajspviewfilecalledwelcome.jspunderthesrc/main/webapp/WEB-INF/jsp/
directory,andaddthefollowingcodesnippetsintoitandsaveit:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-
1">
<linkrel="stylesheet"
href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<title>Welcome</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>${greeting}</h1>
<p>${tagline}</p>
</div>
</div>
</section>
</body>
</html>
2. CreateaclasscalledHomeControllerunderthecom.packt.webstore.controller
packageinthesourcedirectorysrc/main/java,andaddthefollowingcodeintoit:
packagecom.packt.webstore.controller;
importorg.springframework.stereotype.Controller;
importorg.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclassHomeController{
@RequestMapping("/")
publicStringwelcome(Modelmodel){
model.addAttribute("greeting","WelcometoWebStore!");
model.addAttribute("tagline","Theoneandonlyamazingwebstore");

return"welcome";
}
}
Whatjusthappened?
Instep1,wejustcreatedaJSPview;theimportantthingweneedtonoticehereisthe
<h1>tagandthe<p>tag.Boththetagshavesomeexpressionthatissurroundedbycurly
bracesandprefixedbythe$symbol:
<h1>${greeting}</h1>
<p>${tagline}</p>
So,whatisthemeaningof${greeting}?Itmeansthatgreetingisakindofvariable;
duringtherenderingofthisJSPpage,thevaluestoredinthegreetingvariablewillbe
shownintheheader1style,andsimilarly,thevaluestoredinthetaglinevariablewillbe
shownasaparagraph.
Sonow,thenextquestionofwherewewillassignvaluestothosevariablesarises.Thisis
wherethecontrollerwillbeofhelp;withinthewelcomemethodoftheHomeController
class,takealookatthefollowinglinesofcode:
model.addAttribute("greeting","WelcometoWebStore!");
model.addAttribute("tagline","Theoneandonlyamazingwebstore");
Youcanobservethatthetwovariablenames,greetingandtagline,arepassedasafirst
parameteroftheaddAttributemethodandthecorrespondingsecondparameteristhe
valueforeachvariable.Sowhatwearedoinghereissimplyputtingtwostrings,"Welcome
toWebStore!"and"Theoneandonlyamazingwebstore",intothemodelwiththeir
correspondingkeysasgreetingandtagline.Asofnow,simplyconsiderthefactthat
modelisakindofmap.Folkswithknowledgeofservletprogrammingcanconsiderthe
factthatmodel.addAttributeworksexactlylikerequest.setAttribute.
So,whatevervalueweputintothemodelcanberetrievedfromtheview(jsp)usingthe
correspondingkeywiththehelpofthe${}placeholderexpressionnotation.
Thedispatcherservlet
Wecreatedacontrollerthatcanputvaluesintothemodel,andwecreatedtheviewthat
canreadthosevaluesfromthemodel.So,themodelactsasanintermediatebetweenthe
viewandthecontroller;withthis,wehavefinishedallthecodingpartrequiredtopresent
thewelcomepage.Sowillwebeabletorunourprojectnow?No;atthisstage,ifwerun
ourprojectandenterthehttp://localhost:8080/webstore/URLonthebrowser,we
willgetanHTTPStatus404error.Thisisbecausewehavenotperformedanyservlet
mappingyet.InaSpringMVCproject,wemustconfigureafrontservletmapping.The
frontservlet(sometimescalledthefrontcontroller)mappingisadesignpatternwhereall
requestsforaparticularwebapplicationaredirectedtothesameservlet.Onesuchfront
servletgivenbySpringMVCframeworkisthedispatcherservlet
(org.springframework.web.servlet.DispatcherServlet).Wehavenotconfigureda
dispatcherservletforourprojectyet;thisiswhywegettheHTTPStatus404error.
Timeforaction–configuringthe
dispatcherservlet
ThedispatcherservletiswhatexaminestheincomingrequestURLandinvokestheright
correspondingcontrollermethod.Inourcase,thewelcomemethodfromthe
HomeControllerclassneedstobeinvokedifweenterthe
http://localhost:8080/webstore/URLonthebrowser.Solet’sconfigurethe
dispatcherservletforourproject:
1. Createweb.xmlunderthesrc/main/webapp/WEB-INF/directoryinyourprojectand
enterthefollowingcontentinsideweb.xmlandsaveit:
<web-appversion="3.0"xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>DefaultServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>DefaultServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2. NowcreateonemorexmlfilecalledDefaultServlet-servlet.xmlunderthesame
src/main/webapp/WEB-INF/directoryandenterthefollowingcontentintoitand
saveit:
<?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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<mvc:annotation-driven/>
<context:component-scanbase-package="com.packt.webstore"/>

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver
">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
</beans>
Whatjusthappened?
Ifyouknowaboutservletprogramming,youmightbequitefamiliarwiththeservlet
configurationandweb.xml.Inweb.xml,weconfiguredaservletnamedDefaultServlet,
whichismoreorlesssimilartoanyothernormalservletconfiguration.Theonly
differenceisthatwehavenotcreatedanyservletclassforthatconfiguration.Instead,the
servletclass(org.springframework.web.servlet.DispatcherServlet)isprovidedby
theSpringMVCframework,andwemakeuseofitinweb.xml.Afterthisstep,our
configuredDispatcherServlet(DefaultServlet)willbereadytohandleanyrequests
thatcometoourapplicationonruntimeandwilldispatchtherequesttothecorrect
controllersmethod.
However,DispatcherServletshouldknowwhereourcontrollersandviewfilesare
locatedinourproject,andonlythencanitproperlydispatchtherequesttothecorrect
controllers.SowehavetogivesomehinttoDispatcherServlettolocatethecontrollers
andviewfiles.Thisiswhatweconfiguredinstep2throughtheDispatcherServlet-
servlet.xmlfile.
Don’tworryifyouarenotabletounderstandeachandeveryconfigurationinweb.xmland
DispatcherServlet-servlet.xml;wewilltakealookattheseconfigurationfilesinnext
chapter.Asofnow,justrememberthatthisisaone-timeconfigurationthatisneededto
runourprojectsuccessfully.
Deployingourproject
Wesuccessfullycreatedtheprojectinthelastsection,soyoumightbecurioustoknow
whatwouldhappenifwerunourprojectnow.Asourprojectisawebproject,weneeda
webservertorunit.
Timeforaction–runningtheproject
AswealreadyconfiguredtheTomcatwebserverinourSTS,let’suseTomcattodeploy
andrunourproject:
1. Right-clickonyourprojectfromPackageExplorerandnavigatetoRunAs|Run
onServer.
2. Aserverselectionwindowwillappearwithalltheavailableserverslisted;justselect
theserverthatwehaveconfigured,Tomcatv7.0.
3. Atthebottomofthewindow,youcanseeacheckboxwiththecaptionthatsays
Alwaysusethisserverwhenrunningthisproject;selectthischeckboxandenter
theFinishbutton,asshowninthefollowingscreenshot:
ConfiguringthedefaultserverforaSpringMVCproject
4. Nowyouwillseeawebpagethatwillshowyouawelcomemessage.
Summary
Inthischapter,wesawhowtoinstallalltheprerequisitesthatareneededtogetstartedand
runourfirstSpringMVCapplication,forexample,installingJDK,theMavenbuildtool,
theTomcatservletcontainer,andSTSIDE.
WealsolearnedhowtoperformvariousconfigurationsinourSTSIDEforMavenand
Tomcat,createdourfirstSpringMVCproject,andaddedallSpring-relateddependentjars
throughtheMavenconfiguration.
Wehadaquickhands-onexperienceofdevelopingawelcomepageforourwebstore
application.Duringthatcourse,welearnedhowtoputvaluesintoamodelandhowto
retrievethesevaluesfromthemodel.
WhateverwehaveseensofarisjustaglimpseofSpringMVC,butthereismuchmoreto
uncover,forexample,howthemodelandviewcontrollerareconnectedtoeachotherand
howtherequestflowoccurs.Wearegoingtoexplorethesetopicsinthenextchapter,so
seeyouthere!
Chapter2.SpringMVCArchitecture–
ArchitectingYourWebStore
WhatwesawinthefirstchapterisnothingbutaglimpseofSpringMVC;intheprevious
chapter,ourtotalfocuswasjustongettingittorunaSpringMVCapplication.Now,it’s
timeforustodeep-diveintoSpringMVCarchitecture.
Bytheendofthischapter,youwillhaveaclearunderstandingof:
Thedispatcherservletandrequestmapping
Thewebapplicationcontextandconfiguration
TheSpringMVCrequestflowandWebMVC
Thewebapplicationarchitecture
Thedispatcherservlet
Inthefirstchapter,wewereintroducedtothedispatcherservletandsawhowtodefinea
dispatcherservletinweb.xml.Welearnedthateverywebrequestfirstcomestothe
dispatcherservlet.Thedispatcherservletistheonethatdecidesthecontrollermethodthat
itshoulddispatchthewebrequestto.Inthepreviouschapter,wecreatedawelcomepage
thatwillbeshownwheneverweentertheURLhttp://localhost:8080/webstore/on
thebrowser.MappingaURLtotheappropriatecontrollermethodistheprimarydutyofa
dispatcherservlet.
SothedispatcherservletreadsthewebrequestURLandfindstheappropriatecontroller
methodthatcanservethatwebrequestandinvokesit.Thisprocessofmappingaweb
requesttoaspecificcontrollermethodiscalledrequestmapping,andthedispatcher
servletisabletodothiswiththehelpofthe@RequestMappingannotation
(org.springframework.web.bind.annotation.RequestMapping).
Timeforaction–examiningrequest
mapping
Let’sobservewhatwillhappenwhenyouchangethevalueattributeofthe
@RequestMappingannotationbyexecutingthefollowingsteps:
1. OpenyourSTSandrunthewebstoreproject;justright-clickonyourprojectand
chooseRunAs|RunonServer.Youwillbeabletoviewthesamewelcome
messageonthebrowser.
2. Now,gototheaddressbarofthebrowserandentertheURL,
http://localhost:8080/webstore/welcome.
3. YouwillseetheHTTPStatus404errorpageonthebrowser,andyouwillalsosee
thefollowingwarningintheconsole:
WARNING:NomappingfoundforHTTPrequestwithURI[/webstore/welcome]
inDispatcherServletwithname'DefaultServlet'
Anerrorlogdisplayingthe“Nomappingfound”warningmessage
4. Now,opentheHomeControllerclass,changethe@RequestMappingannotation’s
valueattributeto/welcome,andsaveit.Basically,yournewrequestmapping
annotationwilllooklike@RequestMapping("/welcome").
5. Again,runtheapplicationandenterthesameURLthatyouenteredinstep2;now
youwillbeabletoseethesamewelcomemessageonthebrowser,withoutany
requestmappingerror.
6. Finally,opentheHomeControllerclassandrevertthechangesthatweremadetothe
@RequestMappingannotation’svalue;justmakeit@RequestMapping("/")againand
saveit.
Whatjusthappened?
Afterstartingourapplication,whenweentertheURL
http://localhost:8080/webstore/welcomeonthebrowser,thedispatcherservlet
(org.springframework.web.servlet.DispatcherServlet)immediatelytriestofinda
matchingcontrollermethodfortherequestpath,/welcome.
Tip
InaSpringMVCapplication,theURLcanlogicallybedividedintofiveparts(seethe
followingfigure);the@RequestMappingannotationonlymatchesagainsttheURLrequest
path.Itomitsthescheme,hostname,applicationname,andsoon.
The@RequestMappingannotationhasonemoreattributecalledmethodtofurthernarrow
downthemappingbasedontheHTTPrequestmethodtypes(GET,POST,HEAD,OPTIONS,
PUT,DELETE,andTRACE).Ifwedonotspecifythemethodattributeinthe
@RequestMappingannotation,thedefaultmethodwillbeGET.Wewilllearnmoreabout
themethodattributeofthe@RequestMappingannotationinChapter4,WorkingwithSpring
TagLibraries,underthesectiononformprocessing.
ThelogicalpartsofatypicalSpringMVCapplicationURL
Sincewedon’thaveacorrespondingrequestmappingforthegivenURLpath,/welcome,
wegettheHTTPStatus404erroronthebrowserandthefollowingerrorlogonthe
console:
WARNING:NomappingfoundforHTTPrequestwithURI[/webstore/welcome]in
DispatcherServletwithname'DefaultServlet'
Fromtheerrorlog,wecanclearlyunderstandthatthereisnorequestmappingforthe
URLpath,/webstore/welcome.So,wetrytomapthisURLpathtotheexistingcontroller
method;that’swhy,instep4,weputonlytherequestpathvalue,/welcome,inthe
@RequestMappingannotationasthevalueattribute.Noweverythingworksperfectlyfine.
Finally,werevertedour@RequestMappingannotation’svalueto/againinstep6.Whydid
wedothis?BecausewewantittoshowthewelcomepageunderthewebrequestURL
http://localhost:8080/webstore/again.Observecarefullythatherethelastsingle
character/istherequestpath.Wewillseemoreaboutrequestmappinginupcoming
chapters.
Popquiz–requestmapping
Q1.IfwehaveaSpringMVCapplicationforlibrarymanagementcalledBookPediaand
wanttomapawebrequestURL,
http://localhost:8080/BookPedia/category/fiction,toacontrollermethod,how
willweformthe@RequestMappingannotation?
1. @RequestMapping("/fiction").
2. @RequestMapping("/category/fiction").
3. @RequestMapping("/BookPedia/category/fiction").
Thewebapplicationcontext
InaSpring-basedapplication,ourapplicationobjectslivewithinanobjectcontainer.This
containercreatesobjectsandassociationsbetweenobjects,andmanagestheircomplete
lifecycle.ThesecontainerobjectsarecalledSpring-managedbeans(orsimplybeans),and
thecontaineriscalledanapplicationcontextintheSpringworld.
ASpringcontainerusesdependencyinjection(DI)tomanagethebeansthatmakeupan
application.Anapplicationcontext
(org.springframework.context.ApplicationContext)createsbeansandassociate
beanstogetherbasedonthebeanconfigurationanddispensesbeansonrequest.Abean
configurationcanbedefinedviaanXMLfile,annotation,orevenviaJavaconfiguration
classes.WewilluseonlyXML-andannotation-basedbeanconfigurationsinourchapters.
Awebapplicationcontextistheextensionofanapplicationcontext,designedtowork
withthestandardservletcontext(javax.servlet.ServletContext).Awebapplication
contexttypicallycontainsfrontend-relatedbeans,suchasviewsandviewresolvers.Inthe
firstchapter,wecreatedanXMLfilecalledDefaultServlet-servlet.xml,whichis
nothingbutabeanconfigurationfileforourwebapplicationcontext.
Timeforaction–understandingtheweb
applicationcontext
Youhavereceivedenoughofanintroductiononthewebapplicationcontext;now,tweaka
littlebitwiththenameandlocationofthewebapplicationcontextconfigurationfile
(DefaultServlet-servlet.xml)andobservetheeffect.Performthefollowingsteps:
1. RenametheDefaultServlet-servlet.xmlfiletoDispatcherServlet-
servlet.xml;youcanfindDefaultServlet-servlet.xmlunderthe
src/main/webapp/WEB-INF/directory.
2. Then,runyourwebstoreprojectagainandentertheURL,
http://localhost:8080/webstore/;youwillseeanHTTPStatus500error
messageonyourwebpageandaFileNotFoundExceptionerrorinthestacktraceas
follows:
java.io.FileNotFoundException:CouldnotopenServletContextresource
[/WEB-INF/DefaultServlet-servlet.xml]
AnerrormessagedisplayingFileNotFoundExceptionforDefaultServlet-servlet.xml
3. Tofixthiserror,changethenameofDefaultServlettoDispatcherServletin
web.xml;basically,afterchangingthenametoDispatcherServlet,yourservlet
configurationwilllooklikethefollowingintheweb.xmlfile:
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
4. Now,runyourapplicationandentertheURL,http://localhost:8080/webstore/;
youwillseethewelcomemessageagain.
5. RenameyourDispatcherServlet-servlet.xmlfiletoDispatcherServlet-
context.xmloncemore.
6. Next,createadirectorystructurespring/webcontext/undertheWEB-INFdirectory
andmovetheDispatcherServlet-context.xmlfiletothesrc/main/webapp/WEB-
INF/spring/webcontext/directory.
7. Then,runyourapplication,andyouwillseeanHTTPStatus500errormessageon
yourwebpageagainandaFileNotFoundExceptionerrormessageinthestacktrace:
java.io.FileNotFoundException:CouldnotopenServletContextresource
[/WEB-INF/DispatcherServlet-servlet.xml]
8. Tofixthiserror,addthefollowingtagswithinthe<servlet>and</servlet>tags
inweb.xmlasshowninthefollowingcode:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/webcontext/DispatcherServlet-context.xml
</param-value>
</init-param>
9. Now,runtheapplicationagainandentertheURL,
http://localhost:8080/webstore/;youwillbeabletoseethewelcomemessage
again.
Whatjusthappened?
So,whatwedidfirstwasrenamedtheDefaultServlet-servlet.xmlfileto
DispatcherServlet-servlet.xml,andwegotaFileNotFoundExceptionerrorat
runtime,asfollows:
java.io.FileNotFoundException:CouldnotopenServletContextresource
[/WEB-INF/DefaultServlet-servlet.xml]
Tofixtheerror,wechangedourdispatcherservletconfiguration,asfollows,inthe
web.xmlfile:
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
WechangedtheservletnametoDispatcherServletinordertoalignwiththeweb
applicationcontextconfigurationfilenamedDispatcherServlet-servlet.xml.So,based
onthisexercise,wecanlearnthatduringthestart-upofanySpringMVCproject,the
dispatcherservletwilllookforawebapplicationcontextconfigurationfileofthepattern
<ConfigureddispatcherServletName>-servlet.xmlundertheWEB-INFdirectory.It
isourresponsibilitytokeepthewebapplicationcontextconfigurationfileundertheWEB-
INFdirectorywiththerightname.However,whatifwewishtokeepthefileinsomeother
directory?
Tip
Oneoftheimportantthingstobenotedin<servlet-mapping>isthevalueofthe<url-
pattern>/</url-pattern>tag.Byassigning/astheURLpatternforthedispatcher
servlet,wemakeDispatcherServletthedefaultservletforourwebapplication.So,
everywebrequestcomingtoourwebapplicationwillbehandledbyDispatcherServlet.
Forinstance,insteps5and6,werenamedthewebapplicationcontextconfigurationfile
andmovedittoacompletelynewdirectory(src/main/webapp/WEB-
INF/spring/webcontext/).Inthatcase,howdidwefixtheHTTPStatus500error?The
answerlieswithinapropertycalledcontextConfigLocation.Forthedispatcherservletto
locatethewebcontextconfigurationfileeasily,wegavethelocationofthisfiletothe
dispatcherservletthroughapropertycalledcontextConfigLocation.That’swhywe
addedthispropertytothedispatcherservletinstep8,asfollows:
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/webcontext/DispatcherServlet-context.xml
</param-value>
</init-param>
</servlet>
Now,weareabletorunourapplicationwithoutanyproblem.Okay,weplayedalotwith
thewebapplicationcontextconfigurationfileandlearnedthatthedispatcherservlet
shouldknowaboutthewebapplicationcontextconfigurationfileduringthestart-upof
ourproject.Sothenextquestionis:whyisthedispatcherservletlookingforthisweb
contextconfigurationfile,andwhatisdefinedinsidethisfile?Let’sfindouttheanswer,
butbeforethat,youmayanswerthefollowingpopquizquestionstomakesureyou
understandtheconceptofthewebapplicationcontextconfiguration.
Popquiz–thewebapplicationcontext
Q1.IfthecontextConfigLocationpropertywasnotconfiguredinourdispatcherservlet
configuration,underwhichlocationwouldSpringMVClookforthewebapplication
contextconfigurationfile?
1. IntheWEB-INFdirectory
2. InWEB-INF/spring
3. InWEB-INF/spring/appServlet
Q2.IfwedonotwanttoprovidecontextConfigLocationtothefollowingdispatcher
servletconfiguration,howdoweavoidtheHTTPStatus500error?
<servlet>
<servlet-name>FrontController</servlet-name>
<servlet-
class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
1. BycreatingacontextfilecalledFrontController-context.xmlintheWEB-INF
directory
2. BycreatingafilecalledDispatcherServlet-context.xmlinWEB-INF
3. BycreatingafilecalledFrontController-servlet.xmlinWEB-INF
Thewebapplicationcontextconfiguration
Thewebapplicationcontextconfigurationfile(DispatcherServlet-context.xml)is
nothingbutasimpleSpringbeanconfigurationfile.Springwillcreatebeans(objects)for
everybeandefinitionmentionedinthisfileduringbootupofourapplication.Ifyouopen
thiswebapplicationcontextconfigurationfile(/WEB-
INF/spring/webcontext/DispatcherServlet-context.xml),youwillfindsome
configurationandbeandefinitionasfollows:
<?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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<mvc:annotation-driven/>
<context:component-scanbase-package="com.packt.webstore"/>

<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
</beans>
Thefirsttagwithinthe<beans>definitionis<mvc:annotation-driven/>.Bythistag,
wetellSpringMVCtoconfiguretheDefaultAnnotationHandlerMapping,
AnnotationMethodHandlerAdapter,andExceptionHandlerExceptionResolverbeans.
ThesebeansarerequiredforSpringMVCtodispatchrequeststothecontrollers.
Actually<mvc:annotation-driven/>doesmanythingsbehindthescreen.Italso
enablessupportforvariousconvenientannotationssuchas@NumberFormatand
@DateTimeFormattoformattheformbeanfieldsduringformbinding.Similarly,wehave
the@Validannotationtovalidatethecontrollermethod’sparameters.ItalsosupportsJava
objectsto/fromanXMLorJSONconversionviathe@RequestBodyand@ResponseBody
annotationsinthe@RequestMappingor@ExceptionHandlermethodduringformbinding.
Wewillseetheusageoftheseannotationsinlaterchapters.Asofnow,justrememberthat
the<mvc:annotation-driven/>tagisneededtoenableannotationssuchas
@controllerand@RequestMapping.
Whatisthepurposeofthesecondtag,<context:component-scan>?Youneedabitof
backgroundinformationtounderstandthepurposeofthe<context:component-scan>tag.
The@Controllerannotationindicatesthataparticularclassservestheroleofacontroller.
Wealreadylearnedthatthedispatcherservletsearchessuchannotatedclassesformapped
methods(the@RequestMappingannotatedmethods)toserveawebrequest.Inorderto
makethecontrolleravailableforsearching,weneedtocreateabeanforthiscontrollerin
ourwebapplicationcontext.
Wecancreatebeansforcontrollersexplicitlyviathebeanconfiguration(usingthe<bean>
tag—youcanseehowwecreatedabeanfortheInternalResourceViewResolverclass
usingthe<bean>taginthenextsection),orwecanhandoverthattasktoSpringviathe
autodetectionmechanism.Toenabletheautodetectionofthe@Controllerannotated
classes,weneedtoaddcomponentscanningtoourconfigurationusingthe
<context:component-scan>tag.Now,youfinallyunderstandthepurposeofthe
<context:component-scan>tag.
Springwillcreatebeans(objects)forevery@Controllerclassatruntime.Thedispatcher
servletwillsearchforthecorrectrequestmappingmethodinevery@Controllerbean
basedonthe@RequestMappingannotation,toserveawebrequest.Thebase-package
propertyofa<context:component-scan>tagindicatesthepackageunderwhichSpring
shouldsearchforcontrollerclassestocreatebeans:
<context:component-scanbase-package="com.packt.webstore"/>
TheprecedinglineinstructsSpringtosearchforcontrollerclasseswithinthe
com.packt.webstorepackageanditssubpackages.
Tip
The<context:component-scan>tagnotonlyrecognizescontrollerclasses,italso
recognizesotherstereotypessuchasservicesandrepositoryclassesaswell.Wewilllearn
moreaboutservicesandrepositorieslater.
Popquiz–webapplicationcontextconfiguration
Q1.WhatneedstobedonetoidentifyaclassbySpringasacontroller?
1. Thatparticularclassshouldhavethe@Controllerannotation.
2. The<mvc:annotation-driven/>and<context:component-scan>tagsshouldbe
specifiedinthewebapplicationcontextconfigurationfile.
3. Thatparticularclassshouldbeputupinapackageorsubpackagethathasbeen
specifiedasabasepackageinthe<context:component-scan>tag.
4. Alloftheabove.
Viewresolvers
Wesawthepurposeofthefirsttwotagsthatarespecifiedwithinthewebapplication
contextconfigurationfile:
<mvc:annotation-driven/>
<context:component-scanbase-package="com.packt.webstore"/>
Basedonthesetags,Springcreatesthenecessarybeanstohandleawebrequestandalso
createsbeansforallthe@Controllerclasses.However,torunaSpringMVCapplication
successfully,Springneedsonemorebean;thisbeaniscalledaviewresolver.
Aviewresolverhelpsthedispatcherservletidentifytheviewsthathavetoberenderedas
theresponseforaspecificwebrequest.SpringMVCprovidesvariousviewresolver
implementationstoidentifyviews,andInternalResourceViewResolverisonesuch
implementation.Thefinaltaginthewebapplicationcontextconfigurationisthebean
definitionfortheInternalResourceViewResolverclassasfollows:
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
Throughtheprecedingbeandefinitioninthewebapplicationcontextconfiguration,we
instructSpringMVCtocreateabeanfortheInternalResourceViewResolverclass
(org.springframework.web.servlet.view.InternalResourceViewResolver).Wewill
learnmoreabouttheviewresolverinChapter5,WorkingwithViewResolver.
Timeforaction–understanding
InternalResourceViewResolver
WeinstructSpringtocreateabeanforanInternalResourceViewResolverclass,but
why?Whoisgoingtousethisbean?Whatistheroleofthe
InternalResourceViewResolverbeaninSpringMVC?Findtheanswertothese
questionsthroughthefollowingexercise:
1. OpenDispatcherServlet-context.xml;youcanfindthisfileunderthe
src/main/webapp/WEB-INF/spring/webcontext/directoryinyourproject.
2. ChangetheprefixpropertyvalueoftheInternalResourceViewResolverbeanas
follows:
<propertyname="prefix"value="/WEB-INF/views/"/>
3. Now,runyourwebstoreprojectagainandentertheURL
http://localhost:8080/webstore/.YouwillseeanHTTPStatus404error
messageinyourbrowserasshowninthefollowingscreenshot:
Anerrorpagedisplayingthenoresourcefoundmessage
4. Then,renamethejspdirectory(/src/main/webapp/WEB-INF/jsp)toviews.
5. Finally,runyourapplicationandentertheURL,
http://localhost:8080/webstore/.Youwillseethewelcomemessageagain.
Whatjusthappened?
AfterchangingtheprefixpropertyvalueoftheInternalResourceViewResolverbean,
wegotanHTTPStatus404errorwhenweenteredtheURL,
http://localhost:8080/webstore/,inthebrowser.TheHTTPStatus404errormeans
thattheservercouldnotfindthewebpagethatweaskedfor.Ifthatisthecase,thenwhich
webpagedidweaskfor?
Asamatteroffact,wedidn’taskforanywebpagefromtheserverdirectly;instead,the
dispatcherservletasksaparticularwebpagefromtheserver.Whatwealreadylearnedis
thatthedispatcherservletinvokesamethodinanyofthecontrollerbeansthatcanserve
thiswebrequest.Inourcase,thismethodisnothingbutthewelcomemethodofour
HomeControllerclass,becausethisistheonlyrequestmappingmethodthatcanmatch
therequestpathofthegivenURL,http://localhost:8080/webstore/,inits
@RequestMappingannotation.
Now,observethefollowing:
TheprefixpropertyvalueoftheInternalResourceViewResolverbeandefinitionin
DispatcherServlet-context.xml;thatis,/WEB-INF/views/
ThereturnvalueofthewelcomemethodfromtheHomeControllerclass;thatis,
welcome
Finally,thesuffixpropertyvalueoftheInternalResourceViewResolverbean,that
is,.jsp
Ifyoucombinethesethreevaluestogether,youwillgetawebpagerequestURL:/WEB-
INF/views/welcome.jsp.Now,notetheerrormessageinthepreviousscreenshot,
showingtheHTTPStatus404errorforthesamewebpageURL:/WEB-
INF/views/welcome.jspundertheapplicationname,webstore/.
So,theconclusionisthatInternalResourceViewResolverresolvestheactualviewfile
pathbyprependingtheconfiguredprefixvalueandappendingthesuffixvaluewiththe
viewname—theviewnameisthevalueusuallyreturnedbythecontrollermethod.So,the
controllermethoddoesn’treturnthepathoftheactualviewfile;itreturnsonlythelogical
viewname.ItisthejobofInternalResourceViewResolvertoformtheURLoftheactual
viewfilecorrectly.
WhoisgoingtousethisfinalformedURL?Theansweristhedispatcherservlet.After
gettingthefinalformedURLoftheviewfilefromtheviewresolver,thedispatcherservlet
willtrytogettheviewfilefromtheserver.Duringthistime,iftheformedURLisfound
tobewrong,thenyouwillgettheHTTPStatus404error.
Usually,afterinvokingthecontrollermethod,thedispatcherservletwillwaittogetthe
logicalviewnamefromit.Oncethedispatcherservletgetsthelogicalviewname,itgives
thisnametotheviewresolver(InternalResourceViewResolver)togettheURLpathof
theactualviewfile;oncetheviewresolverreturnstheURLpathtothedispatcherservlet,
therenderedviewfileisservedtotheclientbrowserasawebpagebythedispatcher
servlet.
However,whydidwegettheerrorinstep3?Sincewechangedtheprefixpropertyofthe
InternalResourceViewResolverbeaninstep2,theURLpathvaluereturnedfrom
InternalResourceViewResolverbecame/WEB-INF/views/welcome.jspinstep3,which
isaninvalidpathvalue(thereisnodirectorycalledviewsunderWEB-INF).Thatswhy,we
renamedthedirectoryjsptoviewsinstep4toalignitwiththepathgeneratedby
InternalResourceViewResolversothateverythingworksfineagain.
ModelViewController
Sofar,wehaveseenlotsofconcepts,suchasthedispatcherservlet,requestmapping,
controllers,andviewresolver;itwouldbegoodtoseetheoverallpictureoftheSpring
MVCrequestflowsothatwecanunderstandeachcomponent’sresponsibilities.However,
beforethat,weneedtounderstandtheModelViewController(MVC)conceptsome
more.Everyenterprise-levelapplication’spresentationlayercanlogicallybedividedinto
thefollowingthreemajorparts:
Thepartthatmanagesthedata(Model)
Thepartthatcreatestheuserinterfaceandscreens(View)
Thepartthathandlesinteractionsbetweentheuser,userinterface,anddata
(Controller)
Thefollowingdiagramwillhelpyouunderstandtheeventflowandcommandflowwithin
anMVCpattern:
TheclassicMVCpattern
Wheneverauserinteractswiththeviewbyclickingonalinkorbutton,theviewissuesan
eventnotificationtothecontroller,andthecontrollerissuesacommandnotificationtothe
modeltoupdatethedata.Similarly,wheneverthedatainthemodelgetsupdatedor
changed,achangenotificationeventisissuedtotheviewbythemodelinresponse,and
theviewissuesastatequerycommandtothemodeltogetthelatestdatafromthemodel.
Here,themodelandviewcaninteractdirectly;thispatterniscalledtheclassicMVC
pattern.However,whatSpringMVCemploysissomethingcalledawebMVCpattern
duetothelimitationsintheHTTPprotocol.
Tip
WebapplicationsrelyontheHTTPprotocol,whichisastatelesspullprotocol.Thismeans
thatnorequestimpliesnoreply;everytime,weneedtorequesttheapplicationtoknowits
state.TheMVCdesignpatternrequiresapushprotocolfortheviewstobenotifiedbythe
model.SoinwebMVC,thecontrollertakesmoreresponsibilityforthestatechanging,
statequerying,andchangenotification.
InwebMVC,everyinteractionbetweenthemodelandviewistakenthroughthe
controlleronly.So,thecontrolleractsasabridgebetweenthemodelandview.Thereisno
directinteractionbetweenthemodelandview,asintheclassicMVCpattern.
AnoverviewoftheSpringMVCrequest
flow
ThemainentrypointforawebrequestinaSpringMVCapplicationisviathedispatcher
servlet.Thedispatcherservletactsasthefrontcontrolleranddispatchestherequeststothe
othercontroller.Thefrontcontrollersmaindutyistofindtheappropriatecontrollerto
handovertherequestforfurtherprocessing.Thefollowingdiagramshowsanoverviewof
therequestflowinaSpringMVCapplication:
TheSpringMVCrequestflow
Now,let’sreviewtheSpringMVCrequestflowinshort:
1. WhenweenteraURLinthebrowser,therequestcomestothedispatcherservlet.
Thedispatcherservletthenactsasacentralizedentrypointtothewebapplication.
2. Thedispatcherservletdeterminesasuitablecontrollerthatiscapableofhandlingthe
requestanddispatchingthisrequesttothecontroller.
3. Thecontrollermethodupdatesobjectsinthemodelandreturnsthelogicalviewname
andupdatedmodeltothedispatcherservlet.
4. Thedispatcherservletconsultswiththeviewresolvertodeterminewhichviewto
renderandpassesthemodeldatatothatview.
5. Theviewfurnishesthedynamicvaluesinthewebpageusingthemodeldata,renders
thefinalwebpage,andreturnsthiswebpagetothedispatcherservlet.
6. Attheend,thedispatcherservletreturnsthefinal,renderedpageasaresponsetothe
browser.
Thewebapplicationarchitecture
Now,weunderstandtheoverallrequestflowandresponsibilityofeachcomponentina
typicalSpringMVCapplication.However,thisisnotenoughforustobuildanonlineweb
storeapplication.Wealsoneedtoknowthebestpracticestodevelopanenterprise-level
webapplication.Oneofthebestpracticesinatypicalwebapplicationistoorganize
sourcecodeintolayers,whichwillimprovereusabilityandloosecoupling.Atypicalweb
applicationnormallyhasfourlayers:thepresentation,domain,services,andpersistence.
Sofar,whateverwehaveseen,suchasthedispatcherservlet,controllers,viewresolvers,
andsoon,isconsideredapartofthepresentationlayercomponents.Let’sunderstandthe
remaininglayersandcomponentsonebyone.
Thedomainlayer
Let’sstartwiththedomainlayer.Adomainlayertypicallyconsistsofadomainmodel.So,
whatisadomainmodel?Adomainmodelisarepresentationofthedatastoragetypes
requiredbythebusinesslogic.Itdescribesthevariousdomainobjects(entities);their
attributes,roles,andrelationships;plustheconstraintsthatgoverntheproblemdomain.
Takealookatthefollowingdomainmodeldiagramfororderprocessingtogetaquick
ideaaboutthedomainmodel:
Sampledomainmodel
Eachblockintheprecedingdiagramrepresentsabusinessentity,andthelinesrepresent
theassociationsbetweentheentities.Basedontheprecedingdomainmodeldiagram,we
canunderstandthat,inanorderprocessingdomain,acustomercanhavemanyorders,
eachordercanhavemanyorderitems,andeachorderitemrepresentsasingleproduct.
Duringcoding,thedomainmodelwillbeconvertedintocorrespondingdomainobjects
andassociationsbyadeveloper.Adomainobjectisalogicalcontainerofpuredomain
information.Sincewearegoingtobuildanonlinewebstoreapplication,inourdomain,
theprimarydomainobjectmightbeaproduct.So,let’sstartwiththedomainobjectto
representaproduct.
Timeforaction–creatingadomainobject
Sofar,inyourwebstore,youhaveshowedonlyawelcomemessage.Itisnowtimefor
youtoshowyourfirstproductonthewebpage.Dothisbycreatingadomainobject,as
follows,torepresenttheproductinformation:
1. CreateaclasscalledProductunderthecom.packt.webstore.domainpackageinthe
sourcefoldersrc/main/java.Now,addthefollowingcodeintoit:
packagecom.packt.webstore.domain;
importjava.math.BigDecimal;
publicclassProduct{
privateStringproductId;
privateStringname;
privateBigDecimalunitPrice;
privateStringdescription;
privateStringmanufacturer;
privateStringcategory;
privatelongunitsInStock;
privatelongunitsInOrder;
privatebooleandiscontinued;
privateStringcondition;
publicProduct(){
super();
}
publicProduct(StringproductId,Stringname,BigDecimalunitPrice){
this.productId=productId;
this.name=name;
this.unitPrice=unitPrice;
}
//addsettersandgettersforallthefieldshere
@Override
publicbooleanequals(Objectobj){
if(this==obj)
returntrue;
if(obj==null)
returnfalse;
if(getClass()!=obj.getClass())
returnfalse;
Productother=(Product)obj;
if(productId==null){
if(other.productId!=null)
returnfalse;
}elseif(!productId.equals(other.productId))
returnfalse;
returntrue;
}
@Override
publicinthashCode(){
finalintprime=31;
intresult=1;
result=prime*result
+((productId==null)?0:productId.hashCode());
returnresult;
}
@Override
publicStringtoString(){
return"Product[productId="+productId+",name="+name+"]";
}
}
Addsettersandgettersforallofthefieldsintheprecedingclass.Ihaveomitteditto
makethecodecompact,butitisamust,sopleasedoaddit.
2. Now,createonemoreclasscalledProductControllerunderthe
com.packt.webstore.controllerpackageinthesourcefoldersrc/main/javaand
addthefollowingcodeintoit:
packagecom.packt.webstore.controller;
importjava.math.BigDecimal;
importorg.springframework.stereotype.Controller;
importorg.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping;
importcom.packt.webstore.domain.Product;
@Controller
publicclassProductController{
@RequestMapping("/products")
publicStringlist(Modelmodel){
Productiphone=newProduct("P1234","iPhone5s",new
BigDecimal(500));
iphone.setDescription("AppleiPhone5ssmartphonewith4.00-inch
640x1136displayand8-megapixelrearcamera");
iphone.setCategory("SmartPhone");
iphone.setManufacturer("Apple");
iphone.setUnitsInStock(1000);

model.addAttribute("product",iphone);

return"products";
}
}
3. Finally,addonemoreJSPviewfilecalledproducts.jspunderthedirectory
src/main/webapp/WEB-INF/views/,addthefollowingcodesnippetsintoit,andsave
it:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-
1">
<linkrel="stylesheet"

href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<title>Products</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>Products</h1>
<p>Alltheavailableproductsinourstore</p>
</div>
</div>
</section>
<sectionclass="container">
<divclass="row">
<divclass="col-sm-6col-md-3"style="padding-bottom:15px">
<divclass="thumbnail">
<divclass="caption">
<h3>${product.name}</h3>
<p>${product.description}</p>
<p>${product.unitPrice}USD</p>
<p>Available${product.unitsInStock}unitsinstock</p>
</div>
</div>
</div>
</div>
</section>
</body>
</html>
4. Finally,runtheapplicationandentertheURL
http://localhost:8080/webstore/products.Youwillbeabletoseeawebpage
displayingtheproductinformationasshowninthefollowingscreenshot:
TheProductspagedisplayingtheproductinformation
Whatjusthappened?
Ouraimistoshowthedetailsofaproductonourwebpage;thus,inordertodothis,we
firstneedadomainobjecttoholdthedetailsoftheproduct.That’swhatwedidinstep1;
wejustcreatedaclasscalledProduct(Product.java)tostoreinformationaboutthe
product,suchasthename,description,price,andsoon.
AswehavealreadylearnedfromtheAnoverviewoftheSpringMVCrequestflowsection,
toshowanydynamicdataonawebpage,priortothis,weneedtoputthisdatainamodel;
onlythenwilltheviewbeabletoreadthisdatafromthemodelandrenderitontheweb
page.So,toputtheproductinformationinamodel,wejustcreatedonemorecontroller
calledProductController(ProductController.java)instep3.
IntheProductControllerclass,wejusthaveasinglemethodcalledlistwhose
responsibilityistocreateaproductdomainobjecttoholdtheinformationabouttheApple
iPhone5sandaddthatobjecttothemodel.Andfinally,wereturntheviewnameas
products.That’swhatweweredoingthroughthefollowinglinesinthelistmethodof
ProductController:
model.addAttribute("product",iphone);
return"products";
SinceweconfiguredInternalResourceViewResolverasourviewresolverintheweb
applicationcontextconfigurationfile,intheprocessofresolvingtheviewfileforthe
givenviewname(inourcase,theviewnameisproducts),theviewresolverwilltryto
lookforafileproducts.jspunder/WEB-INF/views/.That’swhy,wecreated
products.jspinstep4.Ifyouskipstep4,youwillgettheHTTPStatus404errorwhen
runningtheproject.
Forabettervisualexperience,products.jspcontainslotsofdivtagswithBootstrapCSS
stylesapplied(BootstrapisanopensourceCSSframework),sodon’tthinkthat
products.jspisverycomplex;asamatteroffact,itisverysimple.Youneednotbother
aboutthedivtags.Thesearepresentjustfortheappeal.Youonlyneedtoobservethe
followingfourtagscarefullyinproducts.jsptounderstanddataretrievalfromthemodel:
<h3>${product.name}</h3>
<p>${product.description}</p>
<p>${product.unitPrice}USD</p>
<p>Available${product.unitsInStock}unitsinstock</p>
Notethe${product.unitPrice}expressioncarefully;thetextproductintheexpression
isthenameofthekeythatweusedtostoretheiphoneobjectinthemodel.(Remember
thislinemodel.addAttribute("product",iphone);fromtheProductController
class.)ThetextunitPriceisnothingbutoneofthefieldsfromtheProductdomainclass
(Product.java).Similarly,weshowsomeimportantfieldsoftheproductdomainclassin
theproducts.jspfile.
Tip
WhenIsaythatpriceisthefieldname,Iamactuallymakinganassumptionherethatyou
havefollowedthestandardJavabeannamingconventionsforthegettersandsettersof
yourdomainclass.
Thisisbecause,whenSpringevaluatestheexpression${product.unitPrice},itis
actuallytryingtocallthegettermethodofthefieldtogetthevalue,soitwillexpecta
getUnitPrice()methodintheProduct.javafile.
Aftercompletingstep4,ifwerunourapplicationandentertheURL
http://localhost:8080/WebStore/products,wewillbeabletoseeawebpage
displayingtheproductinformationasshowninthepreviousscreenshot.
So,wehavecreatedadomainclasstoholdinformationaboutaproduct,createdasingle
productobjectinthecontroller,andaddedittothemodel.Finally,weshowedtheproduct
informationintheview.
Thepersistencelayer
Sincewehadasingleproduct,wejustinstantiateditinthecontrolleritselfanddisplayed
thisproductinformationonourwebpagesuccessfully.However,atypicalwebstore
containsthousandsofproducts;alltheinformationfortheseproductsisusuallystoredina
database.So,weneedtomakeourProductControllerclasssmartenoughtoloadallthe
productinformationfromthedatabaseintothemodel.However,ifwewriteallthedata
retrievallogicintheProductControllerclassitselftoretrieveproductinformationfrom
thedatabase,ourProductControllerclasswillblowdownintoabigchunkoffile.
Logicallyspeaking,dataretrievalisnotthedutyofthecontrollerbecausethecontrolleris
apresentationlayercomponent.Moreover,weneedtoorganizedataretrievalcodeina
separatelayersothatwecanreusethislogicasmuchaspossiblefromothercontrollers
andlayers.
HowdoweretrievedatafromthedatabasetheSpringMVCway?Therecomesthe
conceptofthepersistencelayer.Apersistencelayerusuallycontainsrepositoryobjectsto
accessdomainobjects.Arepositoryobjectmakesqueriestothedatasourceforthedata,
thereaftermapsthedatafromthedatasourcetoadomainobject,andfinally,persiststhe
changesinthedomainobjecttothedatasource.So,arepositoryobjectistypically
responsibleforCRUDoperations(Create,Read,Update,andDelete)ondomainobjects.
The@Repositoryannotation(org.springframework.stereotype.Repository)isan
annotationthatmarksaspecificclassasarepository.The@Repositoryannotationalso
indicatesthattheSQLexceptionsthrownfromtherepositoryobject’smethodsshouldbe
translatedintoSpring’sDataAccessExceptions.Let’screatearepositorylayerforour
application.
Timeforaction–creatingarepository
object
Performthefollowingstepstocreatearepositoryclasstoaccessyourproductdomain
objects:
1. CreateaninterfacecalledProductRepositoryunderthepackage
com.packt.webstore.domain.repositoryinthesourcefoldersrc/main/java.Add
asinglemethoddeclarationinit,asfollows:
List<Product>getAllProducts();
2. CreateaclasscalledInMemoryProductRepositoryunderthepackage
com.packt.webstore.domain.repository.implinthesourcefolder
src/main/java.Now,addthefollowingcodeintoit:
packagecom.packt.webstore.domain.repository.impl;
importjava.math.BigDecimal;
importjava.util.ArrayList;
importjava.util.List;
importorg.springframework.stereotype.Repository;
importcom.packt.webstore.domain.Product;
importcom.packt.webstore.domain.repository.ProductRepository;
@Repository
publicclassInMemoryProductRepositoryimplementsProductRepository{

privateList<Product>listOfProducts=newArrayList<Product>();

publicInMemoryProductRepository(){
Productiphone=newProduct("P1234","iPhone5s",new
BigDecimal(500));
iphone.setDescription("AppleiPhone5ssmartphonewith4.00-inch
640x1136displayand8-megapixelrearcamera");
iphone.setCategory("SmartPhone");
iphone.setManufacturer("Apple");
iphone.setUnitsInStock(1000);

Productlaptop_dell=newProduct("P1235","DellInspiron",new
BigDecimal(700));
laptop_dell.setDescription("DellInspiron14-inchLaptop(Black)
with3rdGenerationIntelCoreprocessors");
laptop_dell.setCategory("Laptop");
laptop_dell.setManufacturer("Dell");
laptop_dell.setUnitsInStock(1000);

Producttablet_Nexus=newProduct("P1236","Nexus7",new
BigDecimal(300));
tablet_Nexus.setDescription("GoogleNexus7isthelightest7inch
tabletWithaquad-coreQualcommSnapdragon™S4Proprocessor");
tablet_Nexus.setCategory("Tablet");
tablet_Nexus.setManufacturer("Google");
tablet_Nexus.setUnitsInStock(1000);

listOfProducts.add(iphone);
listOfProducts.add(laptop_dell);
listOfProducts.add(tablet_Nexus);
}
publicList<Product>getAllProducts(){
returnlistOfProducts;
}
}
3. OpenProductControllerfromthepackagecom.packt.webstore.controllerin
thesourcefoldersrc/main/java,andaddaprivatereferencetoProductRepository
withthe@Autowiredannotation
(org.springframework.beans.factory.annotation.Autowired),asfollows:
@Autowired
privateProductRepositoryproductRepository;
4. Now,alterthebodyofthelistmethod,asfollows,inProductController:
@RequestMapping("/products")
publicStringlist(Modelmodel){
model.addAttribute("products",productRepository.getAllProducts());
return"products";
}
5. Then,opentheviewfileproducts.jspfromsrc/main/webapp/WEB-INF/views/,
andremovealloftheexistingcodeandreplaceitwiththefollowingcodesnippet:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-
8859-1">
<linkrel="stylesheet"

href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<title>Products</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>Products</h1>
<p>Alltheavailableproductsinourstore</p>
</div>
</div>
</section>
<sectionclass="container">
<divclass="row">
<c:forEachitems="${products}"var="product">
<divclass="col-sm-6col-md-3"style="padding-bottom:15px">
<divclass="thumbnail">
<divclass="caption">
<h3>${product.name}</h3>
<p>${product.description}</p>
<p>$${product.unitPrice}</p>
<p>Available${product.unitsInStock}unitsinstock</p>
</div>
</div>
</div>
</c:forEach>
</div>
</section>
</body>
</html>
6. Finally,runtheapplicationandentertheURL
http://localhost:8080/webstore/products.Youwillseeawebpagedisplaying
theproductinformationasshowninthefollowingscreenshot:
TheProductspagedisplayingalloftheproductinformationfromthein-memory
repository
Whatjusthappened?
Sincewedon’twanttowriteallofthedataretrievallogicinsideProductController
itself,wedelegatedthistasktoanotherclasscalledInMemoryProductRepository.The
InMemoryProductRepositoryclasshasasinglemethodcalledgetAllProducts(),which
returnsalistofproductdomainobjects.
Asthenameimplies,InMemoryProductRepositoryisjustadummy,in-memoryproduct
repository.Itdoesnotretrieveanyrealproductdomainobjectinformationfromany
databaseassuch;rather,itjustinstantiatesalistofproductdomainobjectsinits
constructor.So,instep2,wejustcreatedtheInMemoryProductRepositoryclass,addeda
singlemethodgetAllProducts()toit,andinstantiatedsomeproductsintheconstructor.
Youmaywonder,then,whatwedidinstep1.Instep1,wejustcreatedaninterfacecalled
ProductRepository,whichdefinestheexpectedbehaviorofaproductrepository.Asof
now,theonlyexpectedbehaviorofaProductRepositoryinterfaceistoreturnalistof
productdomainobjects(getAllProducts),andourInMemoryProductRepositoryclassis
justanimplementationofthisinterface.
Writingrealdataretrievalcodeisbeyondthescopeofthisbook,soIhavecreated
InMemoryProductRepositoryjustfordemonstrationpurposes.However,itispossibleto
replacetheInMemoryProductRepositoryclasswithanyotherrealimplementationthat
canretrieverealdatafromthedatabase.
Whydowehaveaninterfaceandanimplementationfortheproductrepository?
Rememberthatweareactuallycreatingapersistencelayerforourapplication.Whois
goingtouseourpersistencelayerrepositoryobject?Itwillpossiblybeusedbya
controllerobject(inourcase,ProductController)fromthecontrollerlayer,soitisnot
thebestpracticetoconnecttwolayers(controllerandpersistence)withadirectreference.
Instead,wecan,infuture,haveaninterfacereferenceinthecontrollersothatwecan
easilyswitchtodifferentimplementationsoftherepositorywithoutdoinganycode
changesinthecontrollerclass,ifwewant.
That’sthereasonwhywehadtheProductRepositoryreferenceinour
ProductControllerclassinstep3,andnottheInMemoryProductRepositoryclass
reference.NotethefollowinglinesinProductController:
@Autowired
privateProductRepositoryproductRepository;
Whatistheneedofthe@Autowiredannotationhere?Ifyouobservethe
ProductControllerclasscarefully,youmaywonderwhywedidn’tinstantiateanyobject
forthereference,productRepository.Nowherecouldweseeasinglelinesaying
somethinglikeproductRepository=newInMemoryProductRepository();.
SohowcometheexecutionofthelineproductRepository.getAllProducts()worksjust
finewithoutanyNullPointerExceptionerrorinthelistmethodofthe
ProductControllerclass?
model.addAttribute("products",productRepository.getAllProducts());
WhoassignstheInMemoryProductRepositoryobjecttotheproductRepository
reference?TheansweristhattheSpringFrameworkassignsthe
InMemoryProductRepositoryobjecttotheproductRepositoryreference.
RememberwelearnedthatSpringcreatesandmanagesbeans(objects)forevery
@controllerclass?Similarly,Springcreatesandmanagesbeansfor@Repositoryclasses
aswell.AssoonasSpringseesthe@Autowiredannotationontopofthe
ProductRepositoryreference,itassignstheobjectofInMemoryProductRepositoryto
thisreferencesinceSpringalreadycreatedandholdstheInMemoryProductRepository
objectinitsobjectcontainer(thewebapplicationcontext).
Ifyouremember,weconfiguredacomponentscanthroughthefollowingtagintheweb
applicationcontextconfigurationfile:
<context:component-scanbase-package="com.packt.webstore"/>
Also,welearnedearlierthatifweconfigureourwebapplicationcontextasmentioned,it
notonlydetectscontrollers(@controller),butitalsodetectsotherstereotypessuchas
repositories(@Repository)andservices(@Service).
Sinceweaddedthe@RepositoryannotationontopoftheInMemoryProductRepository
class,SpringknowsthatifanyreferenceofthetypeproductRepositoryhasan
@Autowiredannotationontopofit,thenitshouldassigntheimplementationobject
InMemoryProductRepositorytothatreference.Thisprocessofmanagingthedependency
betweenclassesiscalleddependencyinjectionorwiringintheSpringworld.So,tomark
anyclassasarepositoryobject,weneedtoannotatethatclasswiththe@Repository
annotation(org.springframework.stereotype.Repository).
Weunderstandhowthepersistencelayerworks,butaftertherepositoryobjectreturnsa
listofproducts,howdoweshowitonthewebpage?Ifyourememberhowweaddedour
firstproducttothemodel,itisverysimilartothat.Insteadofasingleobject,thistimewe
addalistofobjectstothemodelthroughthefollowinglineinthelistmethodof
ProductController:
model.addAttribute("products",productRepository.getAllProducts());
Intheprecedingcode,productRepository.getAllProducts()justreturnsalistof
productdomainobjects(List<Product>),andwedirectlyaddthislisttothemodel.
Inthecorrespondingviewfile(products.jsp),usingthe<C:forEach>tag,weloop
throughthelistanddisplaytheinformationforeachproductinsideastyleddivtag:
<c:forEachitems="${products}"var="product">
<divclass="col-sm-6col-md-3"style="padding-bottom:15px">
<divclass="thumbnail">
<divclass="caption">
<h3>${product.name}</h3>
<p>${product.description}</p>
<p>${product.unitPrice}USD</p>
<p>Available${product.unitsInStock}unitsinstock</p>
</div>
</div>
</div>
</c:forEach>
Again,notethatthetextproductsintheexpression${products}isnothingbutthekey
thatweusedwhenaddingtheproductlisttothemodelfromtheProductController
class.
TheforeachloopisaspecialJSTLloopingtagthatwillrunthroughthelistofproducts
andassigneachproducttoavariablecalledproduct(var="product")oneachiteration.
Fromtheproductvariable,wefetchinformationsuchasthename,description,and
unitPriceoftheproductanddisplayitwithinthe<h3>and<p>tags.That’showweare
finallyabletoseethelistofproductsontheproductswebpage.
Theservicelayer
Sofarsogood;wecreatedapresentationlayerthatcontainsacontroller,dispatcher
servlet,viewresolvers,andsoon.Then,wecreatedadomainlayerthatcontainsasingle
domainclass,Product.Finally,wecreatedthepersistencelayer,whichcontainsa
repositoryinterfaceandanimplementationtoaccessourProductdomainobjects.
However,wearestillmissingonemoreconceptcalledtheservicelayer.Whydoweneed
theservicelayer?Wesawhowapersistencelayerdealswithallofthelogicrelatedtodata
access(CRUD)andthepresentationlayerdealswithalloftheactivitiesrelatedtotheweb
requestandview;thedomainlayercontainsclassestoholdinformationthatisretrieved
fromdatabaserecords/thepersistencelayer.However,wherecanweputthecodefor
businessoperations?
TheservicelayerexposesbusinessoperationsthatcouldbecomposedofmultipleCRUD
operations.TheseCRUDoperationsareusuallyperformedbytherepositoryobjects.For
example,youcouldhaveabusinessoperationtoprocessacustomerorder,andinorderto
performsuchabusinessoperation,youwouldneedtoperformthefollowingoperations:
1. First,ensurethatalloftheproductsintherequestedorderareavailableinyourstore.
2. Second,haveasufficientquantityoftheseproductsinyourstore.
3. Finally,updatetheproductinventorybyreducingtheavailablecountforeach
productthatwasordered.
Serviceobjectsaregoodcandidatesforsuchbusinessoperationslogic.Theservice
operationscouldalsorepresenttheboundariesofSQLtransactions;thismeansthatallof
theelementaryCRUDoperationsperformedinsidethebusinessoperationshouldbeinside
atransaction:eitherallofthemshouldsucceedortheyshouldrollbackincaseoferror.
Timeforaction–creatingaserviceobject
Performthefollowingstepstocreateaserviceobjectthatwillperformthesimplebusiness
operationoforderprocessing:
1. OpentheinterfaceProductRepositoryfromthepackage
com.packt.webstore.domain.repositoryinthesourcefoldersrc/main/java,and
addonemoremethoddeclarationonit,asfollows:
ProductgetProductById(StringproductID);
2. OpentheimplementationclassInMemoryProductRepositoryandaddan
implantationforthepreviouslydeclaredmethod,asfollows:
publicProductgetProductById(StringproductId){
ProductproductById=null;

for(Productproduct:listOfProducts){
if(product!=null&&product.getProductId()!=null&&
product.getProductId().equals(productId)){
productById=product;
break;
}
}

if(productById==null){
thrownewIllegalArgumentException("Noproductsfoundwiththe
productid:"+productId);
}

returnproductById;
}
3. CreateaninterfacecalledOrderServiceunderthepackage
com.packt.webstore.serviceinthesourcefoldersrc/main/java.Now,adda
methoddeclarationinitasfollows:
voidprocessOrder(StringproductId,intcount);
4. CreateaclasscalledOrderServiceImplunderthepackage
com.packt.webstore.service.implinthesourcefoldersrc/main/java.Then,add
thefollowingcodeintoit:
packagecom.packt.webstore.service.impl;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importcom.packt.webstore.domain.Product;
importcom.packt.webstore.domain.repository.ProductRepository;
importcom.packt.webstore.service.OrderService;
@Service
publicclassOrderServiceImplimplementsOrderService{
@Autowired
privateProductRepositoryproductRepository;

publicvoidprocessOrder(StringproductId,longquantity){
ProductproductById=productRepository.getProductById(productId);

if(productById.getUnitsInStock()<quantity){
thrownewIllegalArgumentException("OutofStock.AvailableUnits
instock"+productById.getUnitsInStock());
}

productById.setUnitsInStock(productById.getUnitsInStock()-
quantity);
}
}
5. Now,createonemorecontrollerclasscalledOrderControllerunderthepackage
com.packt.webstore.controllerinthesourcefoldersrc/main/java,andaddthe
followingcodeintoit:
packagecom.packt.webstore.controller;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Controller;
importorg.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping;
importcom.packt.webstore.service.OrderService;
@Controller
publicclassOrderController{

@Autowired
privateOrderServiceorderService;
@RequestMapping("/order/P1234/2")
publicStringprocess(){
orderService.processOrder("P1234",2);
return"redirect:/products";
}
}
6. Finally,runtheapplicationandentertheURL
http://localhost:8080/webstore/order/P1234/2.Youwillbeabletoseeaweb
pagedisplayingtheproductinformationasshowninthefollowingscreenshot(note
thattheavailableunitsinstockforiPhone5sshowasAvailable998unitsinstock):
TheProductspagedisplayingtheproductinformationafterthestockwasupdated
viaaservicecall
Whatjusthappened?
Beforegoingthroughthesteps,Ijustwanttoremindyouofafactregardingrepository
objects:allofthedataaccess(CRUD)operationsonadomainobjectshouldbecarried
throughrepositoryobjectsonly.Factnumbertwoisthatserviceobjectsrelyonrepository
objectstocarryoutalloperationsrelatedtodataaccess.That’swhy,beforecreatingthe
actualserviceinterface/implementation,wecreatedarepositoryinterface/
implementationmethod(getProductById)insteps1and2.
ThegetProductByIdmethodfromtheInMemoryProductRepositoryclassjustreturnsa
productdomainobjectforthegivenproductID.Weneedthismethodwhenwewritethe
logicforourserviceobjectmethod(processOrder)intheOrderServiceImplclass.Ifthe
productisnotfoundforthegivenID,thenInMemoryProductRepositorythrows
IllegalArgumentException.
Now,let’sreviewsteps3and4,wherewecreatedtheactualservicedefinitionand
implementation.Instep3,wecreatedaninterfacecalledOrderServicetodefineallofthe
expectedresponsibilityofanorderservice.Wedefinedonlyoneresponsibility,asofnow,
withinthatinterface;thatis,toprocesstheorderviathemethod,processOrder.The
processOrdermethodhastwoparameters:oneisproductIdandtheotherisquantity.In
step4,weimplementedtheprocessOrdermethodwithintheOrderServiceImplclass,
wherewereducedtheamountofstockavailableforthegivenproductIdbythequantity
parameter.
Inthepreviousexercise,withintheProductControllerclass,weconnectedcontroller
andrepositorythroughtheProductRepositoryinterfacereferencetomaximizeloose
coupling.Similarly,wehavenowconnectedtheservicelayerandrepositorylayerthrough
theProductRepositoryinterfacereference,asfollows,intheOrderServiceImplclass:
@Autowired
privateProductRepositoryproductRepository;
Aswehavealreadylearned,SpringassignedtheInMemoryProductRepositoryobjectto
theproductRepositoryreferenceinthepreviouslymentionedcodebecausethe
productRepositoryreferencehasthe@Autowiredannotation,andweknowthatSpring
createsandmanagesallofthe@Serviceand@Repositoryobjects.Notethat
OrderServiceImplhasthe@Serviceannotation
(org.springframework.stereotype.Service)ontopofit.Weusedthe
productRepositoryreferencetogettheproductforthegivenIDwithintheprocessOrder
methodoftheOrderServiceImplclassasfollows:
publicvoidprocessOrder(StringproductId,longquantity){
ProductproductById=productRepository.getProductById(productId);

if(productById.getUnitsInStock()<quantity){
thrownewIllegalArgumentException("OutofStock.AvailableUnitsin
stock"+productById.getUnitsInStock());
}

productById.setUnitsInStock(productById.getUnitsInStock()-quantity);
}
Tip
Toensuretransactionalbehavior,Springprovidesthe@Transactionalannotation
(org.springframework.transaction.annotation.Transactional).Weneedtoannotate
servicemethodswiththe@Transactionalannotationtodefinetransactionattributes,and
weneedtodosomemoreconfigurationinourapplicationcontextfortransactional
behaviortotakeeffect.
However,sinceweareusingdummy,in-memoryrepositoriestomimicdataaccess,to
annotateservicemethodswiththe@Transactionalannotationismeaningless.Toknow
moreabouttransactionmanagementinSpring,referto
http://docs.spring.io/spring/docs/current/spring-framework-
reference/html/transaction.html.
Wealreadycreatedtheservicelayer,andnowitisreadytobeconsumedfromthe
presentationlayer.Itistimeforustoconnectourservicelayerwiththecontroller.Instep
5,wecreatedonemorecontroller,OrderController,witharequestmappingmethod
calledprocessinitthatisshowninthefollowingcodesnippet:
@RequestMapping("/order/P1234/2")
publicStringprocess(){
orderService.processOrder("P1234",2);
return"redirect:/products";
}
TheprocessmethodfromtheOrderControllerclassusesourorderServicereferenceto
processtheorderfortheproductID,P1234.Aftersuccessfullyexecutingtheprocess
methodofOrderController,theavailableunitsinstockshouldgetreducedby2forthe
productwiththeID,P1234.
Youwillalsonoticethatwemappedthe/order/P1234/2URLpathtotheprocess
methodusingthe@RequestMappingannotation.So,whenwefinallytrytohittheURL
http://localhost:8080/webshop/order/P1234/2,wewillbeabletoseethatthe
availableunitsinstockgetreducedbytwofortheproduct,P1234.
Haveagohero–accessingtheproductdomain
objectviaaservice
InourProductControllerclass,weonlyhavetheProductRepositoryreferenceto
accesstheProductdomainobject.However,toaccessProductRepositorydirectlyfrom
ProductControllerisnotthebestpractice;itisalwaysgoodtoaccessthepersistence
layerrepositoryviatheserviceobject.However,wehavenotcreatedanyserviceobjectto
mediatebetweenProductControllerandProductRepository.
Whydon’tyoucreateaservicelayertomediatebetweenProductControllerand
ProductRepository?Thefollowingaresomeofthethingsyoucantryout:
1. CreateaninterfacecalledProductServicewithamethoddeclaration,List
<Products>getAllProducts();.
2. Createanimplementationclass,ProductServiceImpl,fortheProductService
interface.
3. AutowiretheProductRepositoryreferenceintheProductServiceImplclassand
usethisreferencewithinthegetAllProductsmethodtogetalloftheproductsfrom
ProductRepository.
4. ReplacetheProductRepositoryreferencewiththeProductServicereferenceinthe
ProductControllerclass.Accordingly,changethelistmethodinthe
ProductControllerclass.
5. Afterfinishingthis,youwillbeabletoseethesameproductlistingsundertheURL,
http://localhost:8080/webshop/products/.
Anoverviewofthewebapplication
architecture
Sofar,wehaveseenhowtoorganizeourcodeintolayerssothatwecanavoidtight
couplingbetweenvariouscodefiles,andimprovereusabilityandtheseparationof
concerns.Wejustcreatedonedomainclass,onerepositoryclass,andoneserviceclassfor
demonstrationpurposes,butatypical,real-worldMVCapplicationmaycontainasmany
domain,repository,andserviceclassesasrequired.Eachlayerisusuallyconnected
throughinterfacesandalwayscontrolleraccessdomainobjectsfromtherepositoryviathe
serviceinterfaceonly.
Everytypical,enterprise-levelSpringMVCapplicationwilllogicallyhavefourlayers:
presentation,domains,persistence,andservices.Thedomainlayerissometimescalledthe
modellayer.Thefollowingblockdiagramwillhelpyouconceptualizethisidea:
ThelayersofaSpringMVCapplication
So,welearnedhowtocreateaservicelayerobjectandrepositorylayerobject;whatwe
sawintheservicelayerandrepositorylayerwasjustaglimpse.Springhasextensive
supporttodealwithdatabasesandtransactions;handlingtheseisaveryvasttopicand
deservesitsownbook.Intheupcomingchapters,wewillconcentratemoreonthe
presentationlayer,whichcontainsmostoftheconceptsrelatedtoSpringMVCratherthan
thoserelatedtothedatabaseandtransaction.
Haveagohero–listingallourcustomers
ItisgreatthatyouhavelistedalloftheproductsinyourwebapplicationundertheURL,
http://localhost:8080/webstore/products,butinordertobecomeasuccessfulweb
store,maintainingonlytheproductinformationisnotenough.Youneedtomaintain
informationaboutthecustomeraswellsothatyoucanattractthembygivingspecial
discountsbasedontheirpurchasehistory.
Whydon’tyoumaintaincustomerinformationinyourapplication?Executethefollowing
stepstomakesomeimprovementstoyourapplicationtomaintaincustomerinformation:
1. AddonemoredomainclasscalledtheCustomerdomainclassinthesamepackage
wheretheproductexists.
2. AddfieldssuchascustomerId,name,address,andnoOfOrdersMadetotheCustomer
class.
3. Createapersistencelayertoreturnallcustomers.
4. CreateaninterfacecalledCustomerRepositorywithamethoddeclaration,List
<Customers>getAllCustomers();.
5. CreateanimplementationInMemoryCustomerRepositoryforCustomerRepository
andinstantiateadummycustomerintheconstructorof
InMemoryCustomerRepository,asyoudidforInMemoryProductRepository.
6. Createaservicelayertogetallofthecustomersfromtherepository.
7. CreateaninterfacecalledCustomerServicewithamethoddeclaration,List
<Customers>getAllCustomers().
8. CreateanimplementationCustomerServiceImplforCustomerService.
9. CreateonemorecontrollercalledCustomerController.
10. AddarequestmappingmethodtomaptheURL,
http://localhost:8080/webstore/customers.
11. Createaviewfilecalledcustomers.jsp.
Afterfinishingthisexercise,youwillbeabletoseeallofyourcustomersundertheURL,
http://localhost:8080/webstore/customers.Thisisverysimilartothewaywelisted
allofourproductsundertheURL,http://localhost:8080/webstore/products.
Summary
Atthestartofthischapter,welearnedthedutyofadispatcherservletandhowitmapsa
requestusingthe@RequestMappingannotation.Next,wesawwhatawebapplication
contextisandhowtoconfigureitforourwebapplication.Afterthat,wegotalittle
introductionaboutviewresolversandhowInternalResourceViewResolverresolvesthe
viewfileforthegivenlogicalviewname.WealsolearnedtheconceptofMVCandthe
overallrequestflowofaSpringMVCapplication,andthenwelearnedaboutweb
applicationarchitecture.Inthewebapplicationarchitecturesection,wesawhowtocreate
andorganizecodeunderthevariouslayersofaSpringMVCapplication,suchasthe
domainlayer,persistencelayer,andservicelayer.Atthesametime,wesawhowto
retrieveproductdomainobjectsfromtherepositoryandpresentthemonthewebpage
usingthecontroller.Wealsolearnedwhereaserviceobjectfitsin.Finally,wesawan
overviewofthewebapplicationarchitecture.
IhopeyougotagoodoverviewofSpringMVCandthevariouscomponentsinvolvedin
developingaSpringMVCapplication.Inthenextchapter,wearespecificallygoingto
learnmoreaboutcontrollersandrelatedconcepts.Meetyouinthenextchapter!
Chapter3.ControlYourStorewith
Controllers
InChapter2,SpringMVCArchitecture–ArchitectingYourWebStore,welearnedthe
overallarchitectureofaSpringMVCapplication.Wedidn’tgointoanyoftheconceptsin
detail;ourtotalaimwastounderstandtheoverallflow.Inthischapter,wearegoingto
haveanin-depthlookatthecontrollersinSpringMVCastheyhaveanimportantrole.
Thischapterwillcoverthefollowingconcepts:
Definingacontroller
URItemplatepatterns
Matrixvariables
Requestparameters
Definingacontroller
Controllersarepresentationlayercomponentsthatareresponsibleforrespondingtouser
actions.TheseactionscouldbeenteringaparticularURLonthebrowser,clickingona
link,submittingaformonawebpage,andsoon.AnyregularJavaclasscanbe
transformedintoacontrollerbysimplybeingannotatedwiththe@Controllerannotation
(org.springframework.stereotype.Controller).
Andwehadalreadylearnedthatthe@ControllerannotationsupportsSpring’s
autodetectionmechanismforauto-registeringthebeandefinitioninthewebapplication
context.Toenablesuchauto-registering,wemustaddthe<context:component-scan>tag
inthewebapplicationcontextconfigurationfile;wehaveseenhowtodothatintheThe
webapplicationcontextconfigurationsectionofChapter2,SpringMVCArchitecture–
ArchitectingYourWebStore.
Acontrollerclassismadeupofrequest-mappedmethods,alsocalledhandlermethods.
Handlermethodsareannotatedwiththe@RequestMappingannotation
(org.springframework.web.bind.annotation.RequestMapping).The@RequestMapping
annotationisusedtomapURLstoparticularhandlermethods.InChapter2,SpringMVC
Architecture–ArchitectingYourWebStore,wesawabriefintroductiononthe
@RequestMappingannotationandlearnedhowtoapplythe@RequestMappingannotation
onthehandlermethodlevel.However,inSpringMVC,wecanevenspecifythe
@RequestMappingannotationatthecontrollerclasslevel.Inthatcase,SpringMVCwill
considerthecontrollerclasslevel@RequestMappingannotationvaluebeforemappingthe
URLtothehandlermethods.Thisfeatureiscalledrelativerequestmapping.
Note
Thetermsrequestmappedmethod,mappedmethod,handlermethod,andcontroller
methodallmeanthesamething;thesetermsareusedtospecifythecontrollermethod
withan@RequestMappingannotation.Theyhavebeenusedinterchangeablyinthisbook.
Timeforaction–addingclass-level
requestmapping
Let’sadda@RequestMappingannotationonourProductControllerclasstodemonstrate
therelativerequestmappingfeature.However,beforethat,wejustwanttoensurethatyou
havealreadyreplacedtheProductRepositoryreferencewiththeProductService
referenceintheProductControllerclassaspartofthepreviouschaptersTimeforaction
–creatingaserviceobjectsection.Becausecontactingthepersistencelayerdirectlyfrom
thepresentationlayerisnotabestpractice,allaccesstothepersistencelayershouldgo
throughtheservicelayer.Performthefollowingsteps(thosewhohavecompletedthis
exercisecandirectlystartfromstep5;otherspleasecontinuefromstep1):
1. CreateaninterfacecalledProductServiceunderthecom.packt.webstore.service
packageinsrc/main/javaandaddtwomethoddeclarationsinitasfollows:
List<Product>getAllProducts();
ProductgetProductById(StringproductID);
2. CreateaclasscalledProductServiceImplunderthe
com.packt.webstore.service.implpackageinsrc/main/javaandaddthe
followingcodeintoit:
packagecom.packt.webstore.service.impl;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importcom.packt.webstore.domain.Product;
importcom.packt.webstore.domain.repository.ProductRepository;
importcom.packt.webstore.service.ProductService;
@Service
publicclassProductServiceImplimplementsProductService{

@Autowired
privateProductRepositoryproductRepository;
publicList<Product>getAllProducts(){
returnproductRepository.getAllProducts();
}
publicProductgetProductById(StringproductID){
returnproductRepository.getProductById(productID);
}
}
3. OpenProductController,removetheexistingProductRepositoryreference,and
addtheProductServicereferenceasfollows:
@Autowired
privateProductServiceproductService;
4. Now,alterthebodyofthelistmethodintheProductControllerclassasfollows
(notethatthistimeweusedtheproductServicereferencetogetalloftheproducts):
@RequestMapping("/products")
publicStringlist(Modelmodel){
model.addAttribute("products",productService.getAllProducts());

return"products";
}
5. IntheProductControllerclass,addthefollowingannotationontopoftheclass:
@RequestMapping("/products")
6. Fromthelistmethod’s@RequestMappingannotation,removethevalueattribute
completely;sonow,thelistmethodwillhaveaplain@RequestMappingannotation
withoutanyattributesasfollows:
@RequestMapping
publicStringlist(Modelmodel){
7. Now,addonemorehandlermethodintheProductControllerclassasfollows:
@RequestMapping("/all")
publicStringallProducts(Modelmodel){
model.addAttribute("products",productService.getAllProducts());

return"products";
}
8. Finally,runtheapplicationagainandentertheURL
http://localhost:8080/webstore/products/allinthebrowsertoviewallofthe
products.
Whatjusthappened?
Whatwehavedemonstratedhereisasimpleconceptcalledrelativerequestmapping.We
didthefollowingthreethingsintheProductControllerclass:
Weaddedan@RequestMappingannotationattheclasslevelwithavalueattribute
definedas"/products"instep5
Weremovedthevalueattributefromthe@RequestMappingannotationofthelist
methodinstep6
Finally,weaddedonemorehandlermethodcalledallProducts,whichalsoputsthe
samelistofproductsonthemodelasthelistmethod,butunderadifferentURL
mapping—@RequestMapping("/all")
Inallourpreviousexamples,weannotatedthe@RequestMappingannotationsonlyatthe
controllermethodlevel,butSpringMVCalsoallowsustospecifyrequestmappingatthe
controllerclasslevel.Inthiscase,SpringMVCmapsaspecificURLpathatthemethod
levelthatisrelativetotheclasslevel@RequestMappingURLvalue.
Instep5,wejustaddedthe@RequestMappingannotationattheProductControllerclass
levelwiththeURLmappingvalue/products.Andinstep7,weaddedanewhandler
methodcalledallProductswithaURLmappingvalue/all.So,thefinalrequestpathfor
theallProductsmethodisformedbycombiningtheclassandmethodrequestmapping
values,whichis/products/all.So,ifwedefinedanyclasslevelrequestmapping,
SpringMVCwouldconsiderthatclasslevelrequestpathbeforemappingtherequestto
themethod.
Note
Steps1to4justteachyouhowtocreateandconnectaservicelayerobjectwiththe
ProductControllerclass.Asofnow,theProductServiceImplclassdoesnothaveany
distinguishablebusinesslogicinit;rather,itsimplydelegatesthecalltothepersistence
layersrepositoryobject(ProductRepository)toaccesstheProductdomainobject.Soas
ofnow,thereisnorealmeaningtohaveaservicelayerforProductRepository;however,
infuture,ifwedecidetoreplacetheInMemoryProductRepositoryobjectwithareal
databasebackedrepositoryobject,wewilldefinitelyneedthisservicelayertowritecode
tohandletransaction-relatedtasks.So,justtomaintaintheindustry’sbestpractices,Ihave
retainedtheservicelayersinmostoftheexamplesinthisbook.
Instep6,wesimplydidn’tspecifyanyrequestpathvalueinthe@RequestMapping
annotationofthelistmethod.Bydoingso,wemadethelistmethodthedefaultrequest
mappingmethodfortheProductControllerclass.So,wheneverarequestURLendsup
withthecontrollerclasslevelrequestpathvaluewithoutanyfurtherrelativepath,Spring
MVCinvokesthismethodasaresponsetotherequest.
So,finallyinourcase,theURLhttp://localhost:8080/webstore/productswillbe
mappedtothelistmethodandhttp://localhost:8080/webstore/products/allwill
bemappedtotheallProductsmethod.
Note
Ifyouspecifymorethanonedefaultmappingmethodinsideacontroller,youwillget
IllegalStateExceptionwiththemessageAmbiguousmappingfound.So,acontroller
canhaveonlyonedefaultrequestmappingmethodatmost.
Popquiz–class-levelrequestmapping
Q1.Inawebapplicationcalledlibrarythathasthefollowingrequestmappingata
controllerclasslevelandinthemethodlevel,whichistheappropriaterequestURLto
maptherequesttothebooksmethod?
@RequestMapping("/books")
publicclassBookController{
...
@RequestMapping(value="/list")
publicStringbooks(Modelmodel){
...
1. http://localhost:8080/library/books/list
2. http://localhost:8080/library/list
3. http://localhost:8080/library/list/books
4. http://localhost:8080/library/
Q2.IfwehaveanotherhandlermethodcalledbookDetailsunderBookControlleras
follows,whatwilltheURLthatmapstothatmethodbe?
@RequestMapping()
publicStringbookDetails(Modelmodel){
...
1. http://localhost:8080/library/books/details
2. http://localhost:8080/library/books
3. http://localhost:8080/library/details
4. http://localhost:8080/library/
TheroleofacontrollerinSpringMVC
InSpringMVC,controllermethodsarethefinaldestinationpointthatawebrequestcan
reach.Afterbeinginvoked,thecontrollermethodstartstoprocessthewebrequestby
interactingwiththeservicelayertocompletetheworkthatneedstobedone.Usually,the
servicelayerexecutessomebusinessoperationsondomainobjectsandcallsthe
persistencelayertoupdatethedomainobjects.Aftertheprocessinghasbeencompleted
bytheservicelayerobject,thecontrollerisresponsibleforupdatingandbuildingupthe
modelobjectandchoosesaviewfortheusertoseenextasaresponse.
RememberthatSpringMVCalwayskeepsthecontrollersunawareofanyview
technologyused.That’swhythecontrollerreturnsonlyalogicalviewname;later,
DispatcherServletconsultswithViewResolvertofindouttheexactviewtobe
rendered.Accordingtothecontroller,ModelisacollectionofarbitraryobjectsandViewis
specifiedwithalogicalname.
Inallourpreviousexercises,thecontrollersusedtoreturnthelogicalviewnameand
updatethemodelviathemodelparameteravailableinthecontrollermethod.Thereis
another,seldomusedwayofupdatingthemodelandreturningtheviewnamefromthe
controllerwiththehelpoftheModelAndViewobject
(org.springframework.web.servlet.ModelAndView).Lookatthefollowingcode
snippet,forexample:
@RequestMapping("/all")
publicModelAndViewallProducts(){
ModelAndViewmodelAndView=newModelAndView();

modelAndView.addObject("products",productService.getAllProducts());
modelAndView.setViewName("products");
returnmodelAndView;
}
Theprecedingcodesnippetjustshowshowwecanencapsulatethemodelandviewusing
theModelAndViewobject.
Handlermapping
WehavelearnedthatDispatcherServletistheonethatdispatchestherequesttothe
handlermethodsbasedontherequestmapping;however,inordertointerpretthe
mappingsdefinedintherequestmapping,DispatcherServletneedsaHandlerMapping
implementation(org.springframework.web.servlet.HandlerMapping).The
DispatcherServletconsultswithoneormoreHandlerMappingimplementationstofind
outwhichcontroller(handler)canhandletherequest.So,HandlerMapping
determineswhichcontrollertocall.
TheHandlerMappinginterfaceprovidestheabstractionformappingrequeststohandlers.
TheHandlerMappingimplementationsarecapableofinspectingtherequestandcoming
upwithanappropriatecontroller.SpringMVCprovidesmanyHandlerMapping
implementations,andtheoneweareusingtodetectandinterpretmappingsfromthe
@RequestMappingannotationistheRequestMappingHandlerMappingclass
(org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
TostartusingRequestMappingHandlerMapping,wehavetoaddthe<mvc:annotation-
driven>elementinourwebapplicationcontextconfigurationfilesothatSpringMVC
cancreateandregisterabeanforRequestMappingHandlerMappinginourwebapplication
context.Wealreadyconfigured<mvc:annotation-driven>inChapter2,SpringMVC
Architecture–ArchitectingYourWebStore,intheThewebapplicationcontext
configurationsection.
UsingURItemplatepatterns
Inthepreviouschapters,wesawhowtomapaparticularURLtoacontrollermethod;for
example,iftheURLenteredwashttp://localhost:8080/webstore/products,we
mappedthatrequesttothelistmethodofProductControllerandlistedalltheproduct
informationonthewebpage.
Whatifwewanttolistonlyasubsetoftheproductsbasedoncategory,forinstance,we
wanttodisplayonlytheproductsthatfallunderthecategoryoflaptopsiftheuserentered
theURLhttp://localhost:8080/webstore/products/laptop?Similarly,whatifthe
URLishttp://localhost:8080/webstore/products/tabletandwewouldliketoshow
onlytabletsonthewebpage?
Onewaytodothisistohaveaseparaterequestmappingmethodinthecontrollerfor
everyuniquecategory.However,itwon’tscaleifwehavehundredsofcategories;inthat
case,we’llhavetowriteahundredrequestmappingmethodsinthecontroller.Sohowdo
wedothisinanelegantway?
WeusetheSpringMVCURItemplatepatternfeature.IfyounotethefollowingURLs,
theonlypartthatchangesintheURListhecategorytype(laptopandtablet);otherthan
that,everythingremainsthesame:
http://localhost:8080/webstore/products/laptop
http://localhost:8080/webstore/products/tablet
So,wecandefineacommonURItemplateforthepreviouslymentionedURLs,which
mightlooklikehttp://localhost:8080/webstore/products/{category}.SpringMVC
canleveragethisfactandmakethattemplateportion({category})oftheURLavariable,
calledapathvariableintheSpringworld.
Timeforaction–showingproductsbased
oncategory
Let’saddacategoryviewtotheproductspageusingthepathvariable:
1. OpentheProductRepositoryinterfaceandaddonemoremethoddeclarationonits
getProductsByCategorymethod:
List<Product>getProductsByCategory(Stringcategory);
2. OpentheimplementationclassInMemoryProductRepositoryandaddan
implementationforthepreviouslydeclaredmethodasfollows:
publicList<Product>getProductsByCategory(Stringcategory){
List<Product>productsByCategory=newArrayList<Product>();

for(Productproduct:listOfProducts){
if(category.equalsIgnoreCase(product.getCategory())){
productsByCategory.add(product);
}
}

returnproductsByCategory;
}
3. Similarly,opentheProductServiceinterfaceandaddonemoremethoddeclaration
onitsgetProductsByCategorymethod:
List<Product>getProductsByCategory(Stringcategory);
4. OpentheserviceimplementationclassProductServiceImplandaddan
implementationasfollows:
publicList<Product>getProductsByCategory(Stringcategory){
returnproductRepository.getProductsByCategory(category);
}
5. OpentheProductControllerclassandaddonemorerequestmappingmethodas
follows:
@RequestMapping("/{category}")
publicStringgetProductsByCategory(Modelmodel,
@PathVariable("category")StringproductCategory){
model.addAttribute("products",
productService.getProductsByCategory(productCategory));
return"products";
}
6. RuntheapplicationandentertheURL
http://localhost:8080/webstore/products/tablet;youwillseesomethingas
specifiedinthefollowingscreenshot:
Showingproductsbycategorywiththehelpofpathvariables
Whatjusthappened?
Step5isthemostimportantinthewholesequencefromthepreviouslist,becauseallthe
stepspriortostep5aretheprerequisitesforstep5.Whatwearedoinginstep5isnothing
butaddingalistofproductobjectstothemodellikewenormallywould:
model.addAttribute("products",productService.getProductsByCategory(ProductC
ategory));
OnethingweneedtonotehereisthegetProductsByCategorymethodfrom
productService;weneedthismethodtogetthelistofproductsforthegivencategory,
andproductServiceassuchcannotgivethelistofproductsforthegivencategory.Itwill
asktherepository.That’swhy,instep4,weusedtheproductRepositoryreferencetoget
thelistofproductsbycategorywithintheProductServiceImplclass.Notethefollowing
codesnippetfromProductServiceImpl:
returnproductRepository.getProductsByCategory(category);
Anotherimportantthingtobenotedinthecodesnippetfromstep5isthe
@RequestMappingannotation’srequestpathvalueasfollows:
@RequestMapping("/{category}")
Byenclosingaportionofarequestpathwithincurlybraces,weindicatetotheSpring
MVCthatitisaURItemplatevariable.AccordingtoSpringMVCdocumentation,aURI
templateisaURI-likestringthatcontainsoneormorevariablenames.Whenyou
substitutevaluesforthesevariables,thetemplatebecomesaURI.
Forexample,theURItemplate
http://localhost:8080/webstore/products/{category}containsthevariable
category.Assigningthevaluelaptoptothevariableyields
http://localhost:8080/webstore/products/laptop.InSpringMVC,wecanusethe
@PathVariableannotation
(org.springframework.web.bind.annotation.PathVariable)toreadaURItemplate
variable.
Sincewehavethe@RequestMapping("/products")annotationattheProductController
level,theactualrequestpathofthegetProductsByCategorymethodwillbe
/products/{category}.Soatruntime,ifwegiveawebrequestURLas
http://localhost:8080/webstore/products/laptop,thenthecategorypathvariable
willhavethevaluelaptop.Similarly,forthewebrequest
http://localhost:8080/webstore/products/tablet,thecategorypathvariablewill
havethevaluetablet.
HowdoweretrievethevaluestoredintheURItemplatepathvariablecategory?Aswe
alreadymentioned,the@PathVariableannotationwillhelpusreadthatvariable.Allwe
needtodoissimplyannotatethegetProductsByCategorymethodparameterwiththe
@PathVariableannotationasfollows:
publicStringgetProductsByCategory(@PathVariable("category")String
productCategory,Modelmodel){
So,SpringMVCwillreadwhatevervalueispresentinthecategoryURItemplate
variableandassignittothemethodparameterproductCategory.So,wehavethe
categoryvalueinavariable,andwejustpassittoproductServicetogetthelistof
productsinthatcategory.Oncewegetthatlistofproducts,wesimplyaddittothemodel
andreturnthesameviewnamethatwehaveusedtolistalltheproducts.
Thevalueattributeinthe@PathVariableannotationshouldbethesameasthevariable
nameinthepathexpressionofthe@RequestMappingannotation.Forexample,ifthepath
expressionis"/products/{identity}",thentoretrievethepathvariableidentity,you
havetoformthe@PathVariableannotationas@PathVariable("identity").
Note
Ifthe@PathVariableannotationhasbeenspecifiedwithoutanyvalueattribute,itwilltry
toretrieveapathvariablewiththesamenameasthatofthevariablethatithasbeen
annotatedwith.
Forexample,ifyouspecifysimply@PathVariableStringproductId,thenSpringwill
assumethatitshouldlookforaURItemplatevariable"{productId}"intheURL.A
requestmappingmethodcanhaveanynumberof@PathVariableannotations.
Finally,instep6,whenweentertheURL
http://localhost:8080/webstore/products/tablet,weseeinformationabout
Google’sNexus7,whichisatablet.Similarly,ifweentertheURL
http://localhost:8080/webstore/products/laptop,weseeinformationaboutDell’s
Inspironlaptop.
Popquiz–requestpathvariable
Q1.InawebapplicationcalledWebStorethathasthefollowingrequestmappingata
controllerclasslevelandinthemethodlevel,whichistheappropriaterequestURLthat
canbeused?
@RequestMapping("/items")
publicclassProductController{
...
@RequestMapping(value="/type/{type}",method=RequestMethod.GET)
publicStringproductDetails(@PathVariable("type")StringproductType,
Modelmodel){
1. http://localhost:8080/WebStore/items/electronics
2. http://localhost:8080/WebStore/items/type/electronics
3. http://localhost:8080/WebStore/items/productType/electronics
4. http://localhost:8080/WebStore/type/electronics
Q2.Forthefollowingrequestmappingannotation,whicharethecorrectmethod
signaturestoretrievethepathvariables?
@RequestMapping(value="/manufacturer/{
manufacturerId}/product/{productId}")
1. publicStringproductByManufacturer(@PathVariableString
manufacturerId,@PathVariableStringproductId,Modelmodel)
2. publicStringproductByManufacturer(@PathVariableStringmanufacturer,
@PathVariableStringproduct,Modelmodel)
3. publicStringproductByManufacturer(@PathVariable("manufacturer")
StringmanufacturerId,@PathVariable("product")StringproductId,Model
model)
4. publicStringproductByManufacturer(@PathVariable("manufacturerId")
Stringmanufacturer,@PathVariable("productId")Stringproduct,Model
model)
Usingmatrixvariables
Inthelastsection,wesawtheURItemplatefacilitytobindvariablesintheURLrequest
path.However,thereisonemorewaytobindvariablesintherequestURLinaname-
valuepairstyle;theseboundvariablesarereferredtoasmatrixvariableswithinSpring
MVC.LookatthefollowingURL:
http://localhost:8080/webstore/products/filter/price;low=500;high=1000
InthisURL,theactualrequestpathisjustupto
http://localhost:8080/webstore/products/filter/price,afterwhichwehave
somethinglikelow=500;high=1000;here,lowandhigharejustmatrixvariables.
However,whatmakesmatrixvariablessospecialistheabilitytoassignmultiplevalues
forasinglevariable;thismeansthatwecanassignalistofvaluestoaURIvariable.Take
alookatthefollowingURL:
http://localhost:8080/webstore/products/filter/ByCriteria;brand=google,dell;category=tablet,laptop
InthegivenURL,wehavetwovariables,namely,brandandcategory;bothhave
multiplevalues,brand=google,dellandcategory=tablet,laptop.Howdoweread
thesevariablesfromtheURLduringrequestmapping?Weusethespecialbinding
annotation@MatrixVariable
(org.springframework.web.bind.annotation.MatrixVariable).Onecoolthingabout
the@MatrixVariableannotationisthatitallowsustocollectthematrixvariablesina
mapofcollections(Map<String,List<String>>),whichwillbemorehelpfulwhenwe
aredealingwithcomplexwebrequests.
Timeforaction–showingtheproducts
basedonfilter
Considerasituationwherewewanttofiltertheproductlistbasedonthebrandand
categoryvariables.Forexample,youwanttolistalltheproductsthatfallunderthe
categorylaptopandtabletsandfromthemanufacturersgoogleanddell.Withthehelp
ofthematrixvariables,wecanformaURLtobindthebrandandcategoryvariables’
valuesintotheURLasfollows:
http://localhost:8080/webstore/products/filter/ByCriteria;brand=google,dell;category=tablet,laptop
Let’smapthisURLtoahandlermethodwiththehelpofthe@MatrixVariableannotation:
1. OpentheProductRepositoryinterfaceandaddonemoremethoddeclaration,
getProductsByFilter,onit:
Set<Product>getProductsByFilter(Map<String,List<String>>
filterParams);
2. Opentheimplementationclass,InMemoryProductRepository,andaddthefollowing
methodimplementationforgetProductsByFilter:
publicSet<Product>getProductsByFilter(Map<String,List<String>>
filterParams){
Set<Product>productsByBrand=newHashSet<Product>();
Set<Product>productsByCategory=newHashSet<Product>();
Set<String>criterias=filterParams.keySet();

if(criterias.contains("brand")){
for(StringbrandName:filterParams.get("brand")){
for(Productproduct:listOfProducts){
if(brandName.equalsIgnoreCase(product.getManufacturer())){
productsByBrand.add(product);
}
}
}
}

if(criterias.contains("category")){
for(Stringcategory:filterParams.get("category")){

productsByCategory.addAll(this.getProductsByCategory(category));
}
}

productsByCategory.retainAll(productsByBrand);

returnproductsByCategory;
}
3. OpentheinterfaceProductServiceandaddonemoremethoddeclarationonit
calledgetProductsByFilterasfollows:
Set<Product>getProductsByFilter(Map<String,List<String>>
filterParams);
4. Opentheserviceimplementationclass,ProductServiceImpl,andaddthefollowing
methodimplementationforgetProductsByFilter:
publicSet<Product>getProductsByFilter(Map<String,List<String>>
filterParams){
returnproductRepository.getProductsByFilter(filterParams);
}
5. OpenProductControllerandaddonemorerequestmappingmethodasfollows:
@RequestMapping("/filter/{ByCriteria}")
publicStringgetProductsByFilter(@MatrixVariable(pathVar=
"ByCriteria")Map<String,List<String>>filterParams,Modelmodel){
model.addAttribute("products",
productService.getProductsByFilter(filterParams));
return"products";
}
6. Openthewebapplicationcontextconfigurationfile(DispatcherServlet-
context.xml)fromsrc/main/webapp/WEB-INF/spring/webcontext/andenable
matrixvariablesupportbysettingenable-matrix-variablestotrueinthe
<mvc:annotation-driven>tagasfollows:
<mvc:annotation-drivenenable-matrix-variables="true"/>
7. Finally,runtheapplicationandentertheURL
http://localhost:8080/webstore/products/filter/ByCriteria;brand=google,dell;category=tablet,laptop
youwillseetheproductlistingasshowninthefollowingscreenshot:
Usageofmatrixvariablesshowingproductlistfilteredbycriteria
Whatjusthappened?
OuraimistoretrievethematrixvariablevaluesfromtheURLanddosomethinguseful;
inourcase,theURLwearetryingtomapis
http://localhost:8080/webstore/products/filter/ByCriteria;brand=google,dell;category=tablet,laptop
wherewewanttoextractthematrixvariablesbrandandcategory.Thebrandand
categoryvariableshavethevaluesgoogle,dellandtablet,laptop,respectively.Inthe
previousURL,therequestpathisupto
http://localhost:8080/webstore/products/filter/ByCriteriaonly.That’swhy,in
step5,weannotatedourgetProductsByFilterrequestmappingmethodasfollows:
@RequestMapping("/filter/{ByCriteria}")
However,youmaywonderwhywehaveaURItemplate(/{ByCriteria})inthe
@RequestMappingannotation,whichislikemappingtoapathvariable.Itisbecauseifour
requestURLcontainsthematrixvariable,thenwewillhavetoformthe@RequestMapping
annotationwithaURItemplatetoidentifythestartingofmatrixvariable’ssegments
withinURL.That’swhywedefinedByCriteriaasaURItemplateintherequestmapping
annotation(@RequestMapping("/filter/{ByCriteria}")).
Note
AURLcanhavemultiplematrixvariables;eachmatrixvariablewillbeseparatedwitha;
(semicolon).Toassignmultiplevaluestoasinglevariable,eachvaluemustbeseparated
bya“,”(comma),orwecanrepeatthevariablename.SeethefollowingURL,whichisa
repeatedvariableversionofthesameURLthatweusedinourexample:
http://localhost:8080/webstore/products/filter/ByCategory;brand=google;brand=dell;category=tablet;category=laptop
NotethatwerepeatedthevariablesbrandandcategorytwiceintheURL.
WemappedthewebrequesttothegetProductsByFiltermethod,buthowdoweretrieve
thevaluefromthematrixvariables?Theansweristhe@MatrixVariableannotation.Itis
quitesimilartothe@PathVariableannotation;ifyounoticethegetProductsByFilter
methodsignatureinstep5,weannotatedthemethodparameterfilterParamswiththe
@MatrixVariableannotationasfollows:
publicStringgetProductsByFilter(@MatrixVariable(pathVar="ByCriteria")
Map<String,List<String>>filterParams,Modelmodel)
So,SpringMVCwillreadallthematrixvariablesfoundintheURLafterthe
{ByCriteria}URItemplateandplacethosematrixvariablesintothemapofthemethod
parameterfilterParams.ThefilterParamsmapwillhaveeachmatrixvariablenameas
keyandthecorrespondinglistwillcontainthemultiplevaluesassignedforthematrix
variable.ThepathVarattributefromthe@MatrixVariableannotationisusedtoidentify
thematrixvariablesegmentintheURL;that’swhyithasthevalueByCriteria,whichis
nothingbuttheURItemplatevaluethatweusedinourrequestmappingURL.
AURLcanhavemultiplematrixvariablesegments.TakealookatthefollowingURL:
http://localhost:8080/webstore/products/filter/ByCriteria;brand=google,dell;category=tablet,laptop/BySpecification;dimention=10,20,15;color=red,green,blue
Itcontainstwomatrixvariablesegments,eachidentifiedbytheprefixesByCriteriaand
BySpecification,respectively.Soinordertocaptureeachmatrixvariablesegmentintoa
map,wehavetoformthecontrollermethodsignatureasfollows:
@RequestMapping("/filter/{ByCriteria}/{BySpecification}")
publicStringfilter(@MatrixVariable(pathVar="ByCriteria")
Map<String,List<String>>criteriaFilter,@MatrixVariable(pathVar="
BySpecification")Map<String,List<String>>specFilter,Modelmodel){
WegotthevalueofthematrixvariablesintothemethodparameterfilterParams,but
whatdidwedowiththatfilterParamsmap?Wesimplypasseditasaparametertothe
servicemethodtoretrievetheproductsbasedoncriteriaasfollows:
productService.getProductsByFilter(filterParams)
Again,theservicepassesthatmaptotherepositorytogetthelistofproductsbasedonthe
criteria.Oncewegetthelist,wesimplyaddthatlisttothemodelandreturnthesame
viewnamethatwasusedtolisttheproducts.
ToenabletheuseofmatrixvariablesinSpringMVC,wesettheenable-matrix-
variablesattributeofthe<mvc:annotation-driven>tagtotrue;wedidthisinstep6.
Finally,wewereabletoviewtheproductsbasedonthespecifiedcriteriainstep7onour
productlistingpage.
Understandingrequestparameters
MatrixvariablesandpathvariablesareagreatwayofbindingvariablesintheURL
requestpath.However,thereisonemorewaytobindvariablesintheHTTPrequest,not
onlyasapartoftheURLbutalsointhebodyoftheHTTPwebrequest,whicharetheso-
calledHTTPparameters.YoumighthaveheardabouttheGETorPOSTparameters.GET
parametershavebeenusedforyearsasastandardwaytobindvariablesintheURL,and
POSTparametersareusedtobindvariablesinthebodyoftheHTTPrequest.Wewill
learnaboutPOSTparametersinthenextchapterduringformsubmission.
Okay,nowlet’sseehowtoreadGETrequestparametersusingtheSpringMVCstyle.To
demonstratetheuseoftherequestparameter,let’saddaproductdetailspagetoour
application.
Timeforaction–addingtheproduct
detailspage
Sofarinourproductlistingpage,wehaveonlyshownproductinformationsuchasthe
product’sname,description,price,andavailableunitsinstock.However,wehaven’t
showninformationsuchasthemanufacturersname,category,productID,andsoon.
Let’screateaproductdetailspagedisplayingthisinformationasfollows:
1. OpentheProductControllerclassandaddonemorerequestmappingmethodas
follows:
@RequestMapping("/product")
publicStringgetProductById(@RequestParam("id")StringproductId,
Modelmodel){
model.addAttribute("product",
productService.getProductById(productId));
return"product";
}
2. AddonemoreJSPviewfilecalledproduct.jspunderthedirectory
src/main/webapp/WEB-INF/views/,andaddthefollowingcodesnippetintoitand
saveit:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-
1">
<linkrel="stylesheet"

href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<title>Products</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>Products</h1>
</div>
</div>
</section>
<sectionclass="container">
<divclass="row">
<divclass="col-md-5">
<h3>${product.name}</h3>
<p>${product.description}</p>
<p>
<strong>ItemCode:</strong><spanclass="labellabel-
warning">${product.productId}</span>
</p>
<p>
<strong>manufacturer</strong>:${product.manufacturer}
</p>
<p>
<strong>category</strong>:${product.category}
</p>
<p>
<strong>Availbleunitsinstock</strong>:
${product.unitsInStock}
</p>
<h4>${product.unitPrice}USD</h4>
<p>
<ahref="#"class="btnbtn-warningbtn-large"><span
class="glyphicon-shopping-cartglyphicon"></span>OrderNow
</a>
</p>
</div>
</div>
</section>
</body>
</html>
3. Now,runtheapplicationandentertheURL
http://localhost:8080/webstore/products/product?id=P1234;youwillseethe
productdetailspageasshowninthefollowingscreenshot:
Usageofrequestparametershowingproductdetailspage
Whatjusthappened?
Whatwedidinstep1isverysimilartowhatwedidinthegetProductsByCategory
methodofProductController.Wejustaddedaproductobjecttothemodelthatis
returnedbytheserviceobjectasfollows:
model.addAttribute("product",productService.getProductById(productId));
However,theimportantquestionhereis,whoisgivingthevalueoftheparameter
productId?Theanswerissimple,asyouguessed;sinceweannotatedtheparameter
productIdwiththe@RequestParam("id")annotation
(org.springframework.web.bind.annotation.RequestParam),SpringMVCwilltryto
readaGETrequestparameterwiththenameidfromtheURLandassignittothe
getProductByIdmethodparameter,productId.
The@RequestParamannotationalsofollowsthesameconventionforotherbinding
annotations;thatis,ifthenameoftheGETrequestparameterandthenameofthevariable
itisannotatedwitharethesame,thentherewillbenoneedtospecifythevalueattribute
inthe@RequestParamannotation.
Finally,instep6,weaddedonemoreviewfilecalledproduct.jspbecausewewanteda
detailedviewoftheproductsothatwecoulddisplayalltheinformationabouttheproduct.
Nothingfancyinthisproduct.jsp;asusual,wegetthevaluefromthemodelandshowit
withinHTMLtagsusingtheusualJSTLexpressionlanguagenotation${}asfollows:
<h3>${product.name}</h3>
<p>${product.description}</p>
......
WesawhowtoretrieveaGETrequestparameterfromtheURL,buthowdowepassmore
thanoneGETrequestparameterintheURL?Theansweristhatweneedtodelimiteach
parametervaluepairwithan&symbol;forexample,ifwewanttopasscategoryand
priceasGETrequestparametersinaURL,wehavetoformtheURLasfollows:
http://localhost:8080/WebStore/products/product?category=laptop&price=700
Similarly,tomaptheprecedingURLinarequestmappingmethod,ourrequestmapping
methodshouldhaveatleasttwoparameterswiththe@RequestParamannotation:
publicStringgetProducts(@RequestParamStringcategory,@RequestParam
Stringprice){
Popquiz–therequestparameter
Q1.WhichistheappropriaterequestURLforthefollowingrequestmappingmethod
signature?
@RequestMapping(value="/products",method=RequestMethod.GET)
publicStringproductDetails(@RequestParamStringrate,Modelmodel)
1. http://localhost:8080/webstore/products/rate=400
2. http://localhost:8080/webstore/products?rate=400
3. http://localhost:8080/webstore/products?rate/400
4. http://localhost:8080/webstore/products/rate=400
Timeforaction–implementingamaster
detailview
Amasterdetailviewisnothingbutthedisplayofveryimportantinformationonamaster
page.Onceweselectaniteminthemasterview,adetailedpageoftheselecteditemwill
beshowninthedetailviewpage.Let’sbuildamasterdetailviewforourproductlisting
pagesothatwhenweclickonanyproduct,weseethedetailedviewofthatproduct.
Wehavealreadyimplementedtheproductlistingpage
(http://localhost:8080/webshop/products)andproductdetailspage
(http://localhost:8080/webstore/products/product?id=P1234),sotheonlything
neededistoconnectthesetwoviewstomakeamasterdetailview.Performthefollowing
steps:
1. Openproducts.jsp;youcanfindproducts.jspundersrc/main/webapp/WEB-
INF/views/inyourprojectandaddthefollowingspringtaglibreferenceontopof
thefile:
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
2. AddthefollowinglinesaftertheAvailableunitsinstockparagraphtagin
products.jsp:
<p>
<ahref="<spring:urlvalue="/products/product?
id=${product.productId}"/>"class="btnbtn-primary">
<spanclass="glyphicon-info-signglyphicon"/></span>Details
</a>
</p>
3. Now,openproduct.jsp;youcanfindproduct.jspundersrc/main/webapp/WEB-
INF/views/inyourprojectandaddthefollowingspringtaglibreferenceontopof
thefile:
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
And,addthefollowinglinesjustbeforetheOrderNowlinkinproduct.jsp:
<ahref="<spring:urlvalue="/products"/>"class="btnbtn-default">
<spanclass="glyphicon-hand-leftglyphicon"></span>back
</a>
4. RuntheapplicationandentertheURL
http://localhost:8080/webstore/products;youwillbeabletoseeaproductlist
pagethathasaDetailsbuttonwitheveryproduct,asspecifiedinthefollowing
screenshot:
Themasterviewoftheproductlisting
5. Finally,clickonanyproduct’sDetailsbutton,andyouwillbeabletoseethedetail
viewwiththebackbuttonlinktotheproductlistingpage.
Whatjusthappened?
Whatwedidissimple.Instep2,weaddedahyperlinkusingthefollowingtagin
products.jsp:
<ahref="<spring:urlvalue="/products/product?id=${product.productId}"
/>"htmlEscape="true"/>"class="btnbtn-primary">
<spanclass="glyphicon-info-signglyphicon"/></span>Details
</a>
Notethehrefattributeofthe<a>tagasfollows,whichhasa<spring:url>tagasthe
value:
<spring:urlvalue="/products/product?id=${product.productId}"/>
This<spring:url>tagisusedtoconstructavalidSpringURL.Weneededthis
<spring:url>tobeusedinstep2;that’swhyweaddedareferencetothespringtag
libraryinstep1.Observethevalueattributeofthe<spring:url>tag;wecannotethatfor
theidURLparameter,weassignedtheexpression${product.productId}.So,while
renderingthislink,SpringMVCwillassignthecorrespondingproductIDinthat
expression.
Forexample,whilerenderingthelinkofthefirstproduct,SpringMVCwillassignthe
valueP1234fortheproductID.So,thefinalURLvaluewithin<spring:url>willbecome
/products/product?id=P1234,whichisnothingbuttherequestmappingpathofthe
productdetailspage.So,whenyouclickonthislink,youlandonthedetailspageofthat
product.
Similarly,weneedalinktotheproductlistingpagefromtheproductdetailspage;that’s
whyweaddedanotherlinkintheproduct.jsptaginstep4asfollows:
<ahref="<spring:urlvalue="/products"/>"class="btnbtn-default">
<spanclass="glyphicon-hand-leftglyphicon"></span>back
</a>
Notethatthespantagisjustforstylingthebuttonwiththeicon,soyouneedn’tmindit
thatmuch.Theonlyinterestingthingforusisthehrefattributeofthe<a>tag,whichhas
the<spring:url>tagwiththevalueattribute/productsonit.
Haveagohero–addingmultiplefilterstolist
products
ItisgoodthatwelearnedvarioustechniquestobindparameterswithURLs,suchasusing
pathvariables,matrixvariables,andGETparameters.Wesawhowtogetproductsofa
particularcategoryusingpathvariables,howtogetproductswithinaparticularprice
range,andfinally,wesawhowtogetaparticularproductbytheproductID.
Now,imaginethatyouwanttoapplymultiplecriteriatoviewadesiredproduct;for
example,whatifyouwanttoviewaproductthatfallsunderthetabletcategory,iswithin
thepricerangeof$200to$400,andhasbeenmanufacturedbyGoogle?
Toretrieveaproductthatcansatisfyallofthepreviouslymentionedcriteria,wecanform
aURLasfollows:
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?
manufacturer="Google"
Whydon’tyouwriteacorrespondingcontrollermethodtoservetheprecedingrequest
URL?Herearesomehintstoaccomplishtherequirement:
Createarepositorylayermethodtoreturnalltheproductsbasedonmanufacturer.
Forthis,addamethoddeclarationintheproductRepositoryinterfacetogetthe
productsbymanufacturerasfollows:
List<Product>getProductsByManufacturer(Stringmanufacturer);
AddanimplementationforthegetProductsByManufacturer()methodin
InMemoryProductRepository.ItislikethegetProductsByCategory()method;the
onlydifferenceisthatinsteadofthecategory,wefetchtheproductsbymanufacturer
name.
ExtendtheproductServiceinterfacewiththegetProductsByManufacturer()
methodandimplementthesamemethodintheproductServiceImplclass.
CreateonemorerequestmappingmethodcalledfilterProductsinthe
productControllerclasstomapthefollowingURL:
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?
manufacturer="Google"
RememberthatthisURLcontainsthematrixvariableslowandhightorepresentthe
pricerange,theGETparametermanufacturertoidentifythemanufacturer,and
finally,aURItemplatepathvariabletablettorepresentthecategory.
Usethesameviewfileproducts.jsptolistthefilteredproducts.
RememberthatgetProductsByCategoryfromproductServicereturnsproductsbasedon
category,thegetProductsBypriceFiltermethodreturnsproductswithinacertainprice
range,andfinally,ournewlyintroducedmethod,getProductsByManufacturer,returns
productsbelongingtoaparticularmanufacturer.Youhavetocombinethesethreemethod
resultsbeforeupdatingthemodelwiththeproductlistinthefilterProductscontroller
method.Youcanprobablyusejava.util.Settocombinetheresultsofthesethree
servicemethodstoavoidduplication.Goodluck!
Summary
Inthischapter,welearnedhowtodefineacontrollerandtheusageofthe@Controller
annotation.Afterthat,welearnedtheconceptofrelativerequestmapping,wherewesaw
howtodefinerequestmappingatthecontrollerlevelandunderstoodhowSpring
relativelymapsawebrequesttothecontrollerrequestmappingmethod.Wethenlearned
abouttheroleofacontrollerinSpringMVCandabouthowthedispatcherservletuses
handlermappingtofindouttheexacthandlermethods.Wealsosawvariousparameter
bindingtechniques,suchasURItemplatepatterns,matrixvariables,andHTTPGET
requestparameterstobindparameterswithURLs.Finally,wesawhowtoimplementa
masterdetailview.
Inthenextchapter,wearegoingtoexplorevariousSpringtagsthatareavailableinthe
springtaglibrary.Wewillalsolearnmoreaboutformprocessingandhowtobindform
datawiththeHTTPPOSTparameter.Getreadyforthenextchapter!
Chapter4.WorkingwithSpringTag
Libraries
Inpreviouschapters,welearnedhowtoputdataintothemodelfromthecontroller,but
wehaven’tseenhowtodothistheotherwayaround.Thismeansthatwehaven’tlearned
howtoputthedatafromtheviewintothemodel.InSpringMVC,theprocessofputtingan
HTMLformelement’svaluesintomodeldataiscalledformbinding.
SpringMVCprovidessomeJSPtaglibrariestomakeiteasiertobindformelementsto
modeldata.Springtaglibrariesalsosupportvariousothercommonfunctionalities,such
as,externalizingmessagesanderrorhandling.Inthischapter,wearegoingtolearnmore
abouthowtomakeuseofthesepredefinedtaglibrariesofSpring.
Afterfinishingthischapter,wewillhaveagoodideaaboutthefollowingtopics:
Servingandprocessingwebforms
Formbindingandwhitelisting
Springtaglibraries
Servingandprocessingforms
Springsupportsdifferentviewtechnologies,butifweareusingJSP-basedviews,wecan
makeuseoftheSpringtaglibrarytagstomakeupourJSPpages.Thesetagsprovide
manyuseful,commonfunctionalitiessuchasformbinding,evaluatingerrorsoutputting
internationalizedmessages,andsoon.Inordertousethesetags,wemustaddreferences
tothistaglibraryinourJSPpagesasfollows:
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"%>
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
Inallofourpreviouschapters’examples,wesawthatthedatatransfertookplacefrom
modeltoviewviathecontroller.Thefollowinglineisatypicalexampleofhowweput
dataintothemodelfromacontroller:
model.addAttribute(greeting,"Welcome")
SimilarlythenextlineshowshowweretrievethatdataintheviewusingtheJSTL
expression:
<p>${greeting}</p>
Note
JavaServerPagesStandardTagLibrary(JSTL)isalsoataglibraryprovidedby
Oracle.AnditisacollectionofusefulJSPtagsthatencapsulatesthecorefunctionality
commontomanyJSPpages.WecanaddareferencetotheJSTLtaglibraryinourJSP
pagesas<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>.
However,whatifwewanttoputdataintothemodelfromtheview?Howdoweretrieve
thatdatafromthecontroller?Forexample,considerascenariowhereanadminofour
storewantstoaddnewproductinformationinourstorebyfillingandsubmittingan
HTMLform.HowcanwecollectthevaluesfilledintheHTMLformelementsand
processitinthecontroller?ThisiswheretheSpringtaglibrarytagshelpustobindthe
HTMLtagelement’svaluestoaform-backingbeaninthemodel.Later,thecontrollercan
retrievetheform-backingbeanfromthemodelusingthe@ModelAttributeannotation
(org.springframework.web.bind.annotation.ModelAttribute).
Note
Form-backingbeans(sometimescalledformbeans)areusedtostoreformdata.Wecan
evenuseourdomainobjectsasformbeans;thisworkswellwhenthere’saclosematch
betweenthefieldsontheformandthepropertiesonourdomainobject.Anotherapproach
istocreateseparateclassesforformbeans,whicharesometimescalledDataTransfer
Objects(DTOs).
Timeforaction–servingandprocessing
forms
TheSpringtaglibraryprovidessomespecial<form>and<input>tagsthataremoreor
lesssimilartoHTMLformandinputtags,butithassomespecialattributestobindthe
formelementsdatawiththeform-backingbean.Let’screateaSpringwebforminour
applicationtoaddnewproductstoourproductlistbyperformingthefollowingsteps:
1. WeopenourProductRepositoryinterfaceandaddonemoremethoddeclarationin
itasfollows:
voidaddProduct(Productproduct);
2. WethenaddanimplementationforthismethodintheInMemoryProductRepository
classasfollows:
publicvoidaddProduct(Productproduct){
listOfProducts.add(product);
}
3. WeopenourProductServiceinterfaceandaddonemoremethoddeclarationinitas
follows:
voidaddProduct(Productproduct);
4. And,weaddanimplementationforthismethodintheProductServiceImplclassas
follows:
publicvoidaddProduct(Productproduct){
productRepository.addProduct(product);
}
5. WeopenourProductControllerclassandaddtwomorerequestmappingmethods
asfollows:
@RequestMapping(value="/add",method=RequestMethod.GET)
publicStringgetAddNewProductForm(Modelmodel){
ProductnewProduct=newProduct();
model.addAttribute("newProduct",newProduct);
return"addProduct";
}

@RequestMapping(value="/add",method=RequestMethod.POST)
publicStringprocessAddNewProductForm(@ModelAttribute("newProduct")
ProductnewProduct){
productService.addProduct(newProduct);
return"redirect:/products";
}
6. Finally,weaddonemoreJSPviewfilecalledaddProduct.jspunder
src/main/webapp/WEB-INF/views/andaddthefollowingtagreferencedeclaration
initastheveryfirstline:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"
%>
7. Now,weaddthefollowingcodesnippetunderthetagdeclarationlineandsave
addProduct.jsp(notethatIhaveskippedthe<form:input>bindingtagsforsomeof
thefieldsoftheproductdomainobject,butIstronglyencouragethatyouaddbinding
tagsfortheskippedfieldswhenyoutryoutthisexercise):
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-
1">
<link
rel="stylesheet"href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/boo
tstrap.min.css">
<title>Products</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>Products</h1>
<p>Addproducts</p>
</div>
</div>
</section>
<sectionclass="container">
<form:formmodelAttribute="newProduct"class="form-horizontal">
<fieldset>
<legend>Addnewproduct</legend>
<divclass="form-group">
<labelclass="control-labelcol-lg-2col-lg-2"
for="productId">ProductId</label>
<divclass="col-lg-10">
<form:inputid="productId"path="productId"type="text"
class="form:input-large"/>
</div>
</div>
<!--Similarlybind<form:input>tagfor
name,unitPrice,manufacturer,category,unitsInStockandunitsInOrder
fields-->
<divclass="form-group">
<labelclass="control-labelcol-lg-2"
for="description">Description</label>
<divclass="col-lg-10">
form:textareaid="description"path="description"rows=
"2"/>
</div>
</div>
<divclass="form-group">
<labelclass="control-labelcol-lg-2"
for="discontinued">Discontinued</label>
<divclass="col-lg-10">
<form:checkboxid="discontinued"path="discontinued"/>
</div>
</div>

<divclass="form-group">
<labelclass="control-labelcol-lg-2"
for="condition">Condition</label>
<divclass="col-lg-10">
<form:radiobuttonpath="condition"value="New"/>New
<form:radiobuttonpath="condition"value="Old"/>Old
<form:radiobuttonpath="condition"value="Refurbished"
/>Refurbished
</div>
</div>

<divclass="form-group">
<divclass="col-lg-offset-2col-lg-10">
<inputtype="submit"id="btnAdd"class="btnbtn-primary"
value="Add"/>
</div>
</div>
</fieldset>
</form:form>
</section>
</body>
</html>
8. Now,werunourapplicationandentertheURL
http://localhost:8080/webstore/products/add.Wewillbeabletoseeaweb
pagethatdisplaysawebformwherewecanaddtheproductinformationasshownin
thefollowingscreenshot:
Addtheproduct’swebform
9. Now,weenteralltheinformationrelatedtothenewproductthatwewanttoaddand
clickontheAddbutton;wewillseethenewproductaddedintheproductlisting
pageundertheURLhttp://localhost:8080/webstore/products.
Whatjusthappened?
Inthewholesequence,steps5and6areveryimportantstepsthatneedtobeobserved
carefully.Whateverismentionedpriortostep5isfamiliaraswehaveseenitinprevious
recipes;anyhow,Iwillgiveyouabriefnoteonwhatwehavedoneinsteps1to4.
Instep1,wecreatedamethoddeclarationaddProductinourProductRepository
interfacetoaddnewproducts.Instep2,weimplementedtheaddProductmethodinour
InMemoryProductRepositoryclass;theimplementationisjusttoupdatetheexisting
listOfProductsbyaddinganewproducttothelist.Steps3and4arejustaservicelayer
extensionforProductRepository.Instep3,wedeclaredasimilarmethod,addProduct,
inourProductServiceinterfaceandimplementeditinstep4toaddproductstothe
repositoryviatheproductRepositoryreference.
Okay,comingbacktotheimportantstep;wehavedonenothingbutaddedtworequest
mappingmethods,namely,getAddNewProductFormandprocessAddNewProductForm,in
step5asfollows:
@RequestMapping(value="/add",method=RequestMethod.GET)
publicStringgetAddNewProductForm(Modelmodel){
ProductnewProduct=newProduct();
model.addAttribute("newProduct",newProduct);
return"addProduct";
}

@RequestMapping(value="/add",method=RequestMethod.POST)
publicStringprocessAddNewProductForm(@ModelAttribute("newProduct")
ProductproductToBeAdded){
productService.addProduct(productToBeAdded);
return"redirect:/products";
}
Ifyouobservethesemethodscarefully,youwillnoticeapeculiarthing,whichisthatboth
themethodshavethesameURLmappingvalueintheir@RequestMappingannotation
(value="/add").So,ifweentertheURL
http://localhost:8080/webstore/products/addinthebrowser,whichmethodwill
SpringMVCmapthatrequestto?
Theanswerliesinthesecondattributeofthe@RequestMappingannotation(method=
RequestMethod.GETandmethod=RequestMethod.POST).Ifyouwillnoticeagain,even
thoughbothmethodshavethesameURLmapping,theydifferinrequestmethod.
So,whatishappeningbehindthescreenisthatwhenweentertheURL
http://localhost:8080/webstore/products/addinthebrowser,itisconsideredasa
GETrequest.So,SpringMVCmapsthisrequesttothegetAddNewProductFormmethod,
andwithinthismethod,wesimplyattachanewemptyProductdomainobjecttothe
modelundertheattributename,newProduct.
ProductnewProduct=newProduct();
model.addAttribute("newProduct",newProduct);
Sointheviewaddproduct.jsp,wecanaccessthismodelobject,newProduct.Before
jumpingintotheprocessAddNewProductFormmethod,let’sreviewtheaddproduct.jsp
viewfileforsometimesothatweareabletounderstandtheformprocessingflowwithout
confusion.Inaddproduct.jsp,wehavejustaddeda<form:form>tagfromtheSpringtag
libraryusingthefollowinglineofcode:
<form:formmodelAttribute="newProduct"class="form-horizontal">
Sincethisspecial<form:form>tagisacquiredfromtheSpringtaglibrary,weneedtoadd
areferencetothistaglibraryinourJSPfile.That’swhywehaveaddedthefollowingline
atthetopoftheaddProducts.jspfileinstep6:
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"%>
IntheSpring<form:form>tag,oneoftheimportantattributesismodelAttribute.Inour
case,weassignedthevaluenewProductasthevalueofmodelAttributeinthe
<form:form>tag.Ifyourecallcorrectly,youwillnoticethatthisvalueofmodelAttribute
andtheattributenameweusedtostorethenewProductobjectinthemodelfromour
getAddNewProductFormmethodarethesame.So,thenewProductobjectthatweattached
tothemodelinthecontrollermethod(getAddNewProductForm)isnowboundtotheform.
Thisobjectiscalledtheform-backingbeaninSpringMVC.
Okay,nownoticeeach<form:input>taginsidethe<form:form>tagshowninthe
followingcode.Youwillobservethatthereisacommonattributeineverytag.This
attributenameispath:
<form:inputid="productId"path="productId"type="text"class="form:input-
large"/>
Thepathattributejustindicatesthefieldnamethatisrelativetotheform-backingbean.
So,thevaluethatisenteredinthisinputboxatruntimewillbeboundtothe
correspondingfieldoftheformbean.
Okay,nowisthetimetocomebackandreviewourprocessAddNewProductFormmethod.
Whenwillthismethodbeinvoked?Thismethodwillbeinvokedoncewepressthesubmit
buttonofourform.Yes,sinceeveryformsubmissionisconsideredasaPOSTrequest,
thistimethebrowserwillsendaPOSTrequesttothesameURL,thatis,
http://localhost:8080/webstore/products/add.
So,thistime,theprocessAddNewProductFormmethodwillgetinvokedsinceitisaPOST
request.InsidetheprocessAddNewProductFormmethod,wesimplycalltheservice
methodaddProducttoaddthenewproducttotherepository,asfollows:
productService.addProduct(productToBeAdded);
However,theinterestingquestionhereis,howistheproductToBeAddedobjectpopulated
withthedatathatweenteredintheform?Theanswerlieswithinthe@ModelAttribute
annotation(org.springframework.web.bind.annotation.ModelAttribute).Notethe
methodsignatureoftheprocessAddNewProductFormmethodshowninthefollowingline
ofcode:
publicStringprocessAddNewProductForm(@ModelAttribute("newProduct")
ProductproductToBeAdded)
Here,ifyounoticethevalueattributeofthe@ModelAttributeannotation,youwill
observeapattern.Thevaluesofthe@ModelAttributeannotationandmodelAttribute
fromthe<form:form>tagarethesame.So,SpringMVCknowsthatitshouldassignthe
form-boundnewProductobjecttotheproductToBeAddedparameterofthe
processAddNewProductFormmethod.
The@ModelAttributeannotationisnotonlyusedtoretrieveanobjectfromamodel,but
ifwewantto,wecanevenuseittoaddobjectstothemodel.Forinstance,werewriteour
getAddNewProductFormmethodtosomethinglikethefollowingcodewiththeuseofthe
@ModelAttributeannotation:
@RequestMapping(value="/add",method=RequestMethod.GET)
publicStringgetAddNewProductForm(@ModelAttribute("newProduct")Product
newProduct){
return"addProduct";
}
Youcannoticethatwehaven’tcreatedanynewemptyProductdomainobjectand
attachedittothemodel.AllwehavedonewasaddedaparameterofthetypeProductand
annotateditwiththe@ModelAttributeannotationsothatSpringMVCwouldknowthatit
shouldcreateanobjectofProductandattachittothemodelunderthenamenewProduct.
OnemorethingthatneedstobeobservedintheprocessAddNewProductFormmethodis
thelogicalviewname,redirect:/products,thatitreturns.So,whatarewetryingtotell
SpringMVCbyreturningastringredirect:/products?Togettheanswer,observethe
logicalviewnamestringcarefully.Ifwesplitthisstringwiththe:(colon)symbol,we
willgettwoparts;thefirstpartistheprefixredirectandthesecondpartissomething
thatlookslikearequestpath,/products.So,insteadofreturningaviewname,wesimply
instructSpringtoissuearedirectrequesttotherequestpath,/products,whichisthe
requestpathforthelistmethodofourProductControllerclass.So,aftersubmittingthe
form,welisttheproductsusingthelistmethodofProductController.
Note
Asamatteroffact,whenwereturnanyrequestpathwiththeredirect:prefixfroma
requestmappingmethod,Springusesaspecialviewobject,RedirectView
(org.springframework.web.servlet.view.RedirectView),toissuearedirectcommand
behindthescreen.WewillseemoreaboutRedirectViewintheupcomingchapter.
Insteadoflandinginawebpageafterthesuccessfulsubmissionofawebform,weare
spawninganewrequesttotherequestpath/productswiththehelpofRedirectView.
ThispatterniscalledRedirectAfterPost,whichisacommonpatterntousewithweb-
basedforms.Weareusingthispatterntoavoiddoublesubmissionofthesameform;
sometimes,ifwepressthebrowsersrefreshbuttonorbackbuttonaftersubmittingthe
form,therearechancesthatthesameformwillberesubmitted.
Customizingdatabinding
Inthelastsection,wesawhowtobinddatasubmittedbyanHTMLformorbyquery
stringparameterstoaform-backingbean.Inordertodothebinding,SpringMVC
internallyusesaspecialbindingobjectcalledWebDataBinder
(org.springframework.web.bind.WebDataBinder).
TheWebDataBinderobjectextractsthedataoutoftheHttpServletRequestobject,
convertsittoaproperdataformat,loadsitintoaform-backingbean,andvalidatesit.To
customizethebehaviorofthedatabinding,wecaninitializeandconfigurethe
WebDataBinderobjectinourcontroller.The@InitBinderannotation
(org.springframework.web.bind.annotation.InitBinder)helpsusdothis.The
@InitBinderannotationdesignatesamethodtoinitializeWebDataBinder.
Let’sseeapracticalwayofcustomizingWebDataBinder.Sinceweareusingtheactual
domainobjectitselfastheform-backingbean,duringformsubmission,thereisachance
ofsecurityvulnerability.SinceSpringautomaticallybindsHTTPparameterstoformbean
properties,anattackercouldbindsuitablynamedHTTPparameterswithformproperties
thatweren’tintendedforbinding.Toaddressthisproblem,wecanexplicitlytellSpring
whichfieldsareallowedforformbinding.Technicallyspeaking,theprocessofexplicitly
specifyingtheallowedfieldsforformbindingiscalledwhitelistingformfieldsinSpring
MVC;wecandowhitelistingusingWebDataBinder.
Timeforaction–whitelistingformfields
Inthepreviousexercise,whileaddinganewproduct,weboundeveryfieldoftheProduct
domainintheform.However,itismeaninglesstospecifytheunitsInOrderand
discontinuedvaluesduringtheadditionofanewproductbecausenobodycanmakean
orderbeforeaddingtheproducttothestore,andsimilarly,thediscontinuedproducts
neednotbeaddedinourproductlist.So,weshouldnotallowthesefieldstobeboundto
theformbeanwhileaddinganewproducttoourstore.However,alltheotherfieldsofthe
Productdomainobjectneedtobebound.Let’sseehowtodothiswiththefollowing
steps:
1. WeopenourProductControllerclassandaddamethodasfollows:
@InitBinder
publicvoidinitialiseBinder(WebDataBinderbinder){
binder.setDisallowedFields("unitsInOrder","discontinued");
}
2. WethenaddanextraparameterofthetypeBindingResult
(org.springframework.validation.BindingResult)tothe
processAddNewProductFormmethodasfollows:
publicStringprocessAddNewProductForm(@ModelAttribute("newProduct")
ProductproductToBeAdded,BindingResultresult)
3. InthesameprocessAddNewProductFormmethod,weaddthefollowingconditionjust
beforethelinewherewesavedtheproductToBeAddedobject:
String[]suppressedFields=result.getSuppressedFields();
if(suppressedFields.length>0){
thrownewRuntimeException("Attemptingtobinddisallowedfields:"
+StringUtils.arrayToCommaDelimitedString(suppressedFields));
}
4. Now,werunourapplicationandentertheURL
http://localhost:8080/webstore/products/add;wewillbeabletoseeaweb
pagethatdisplaysawebformwherewecanaddnewproductinformation.Let’sfill
everyfield,particularlyUnitsinorderandDiscontinued.
5. Now,clickontheAddbutton.YouwillseeanHTTPStatus500errorontheweb
page,asshowninthefollowingscreenshot:
Addproductpageshowingerrorfordisallowedfields
6. Now,weopenaddProduct.jspfrom/webstore/src/main/webapp/WEB-INF/views/
inourprojectandremovetheinputtagsthatarerelatedtotheUnitsinorderand
Discontinuedfields.Basically,weneedtoremovethefollowingblockofcode:
<divclass="form-group">
<labelclass="control-labelcol-lg-2"for="unitsInOrder">UnitsIn
Order</label>
<divclass="col-lg-10">
<form:inputid="unitsInOrder"path="unitsInOrder"type="text"
class="form:input-large"/>
</div>
</div>
<divclass="form-group">
<labelclass="control-labelcol-lg-2"
for="discontinued">Discontinued</label>
<divclass="col-lg-10">
<form:checkboxid="discontinued"path="discontinued"/>
</div>
</div>
7. Now,werunourapplicationagainandentertheURL
http://localhost:8080/webstore/products/add.Wewillbeabletoseeaweb
pagethatdisplaysawebformwherewecanaddanewproduct,butthistime,
withouttheUnitsinorderandDiscontinuedfields.
8. Now,weenteralloftheinformationrelatedtothenewproductandclickontheAdd
button;wewillseethenewproductaddedintheproductlistingpageundertheURL
http://localhost:8080/webstore/products.
Whatjusthappened?
OurintentionwastoputsomerestrictionsonbindingtheHTTPparameterswiththeform-
backingbean.Aswealreadydiscussed,theautomaticbindingfeatureofSpringcouldlead
toapotentialsecurityvulnerability,incaseweusedthedomainobjectitselfastheform
bean.So,wehavetoexplicitlyspecifytoSpringMVCwhattheonlyallowedfieldsare.
That’swhatwedidinstep1.
The@InitBinderannotationdesignatesacontrollermethodasahookmethodtodosome
customconfigurationregardingdatabindingonWebDataBinder.And,WebDataBinderis
theonethatdoesthedatabindingatruntime,soweneedtospecifytoWebDataBinder
onlythefieldsallowedforbinding.IfyouobserveourinitialiseBindermethodfrom
ProductController,ithasaparametercalledbinder,whichisofthetype
WebDataBinder.WesimplycallthesetAllowedFieldsmethodonthebinderobjectand
passthefields’namesthatareallowedforbinding.SpringMVCcallsthismethodto
initializeWebDataBinderbeforebindingsinceithasthe@InitBinderannotation.
Note
TheWebDataBinderclassalsohasamethodcalledsetDisallowedFieldstostrictly
specifythedisallowedfieldsforbinding.Ifyouusethismethod,SpringMVCallowsany
HTTPrequestparameterstobebound,exceptthatthesefieldnamesarespecifiedinthe
setDisallowedFieldsmethod.
Okay,weconfiguredwhichfieldsareallowedforbinding,butweneedtoverifywhether
anyotherfieldsotherthantheonesallowedareboundwiththeform-backingbean.That’s
whatwedidinsteps2and3.
WechangedprocessAddNewProductFormbyaddingoneextraparametercalledresult,
whichisofthetypeBindingResult.SpringMVCwillfillthisobjectwiththeresultofthe
binding.Ifanyattemptismadetobindanythingotherthantheallowedfields,the
getSuppressedFieldscountoftheBindingResultobjectwillbegreaterthanzero.That’s
why,wecheckedsuppressedfieldcountandthrewRuntimeExceptionasfollows:
if(suppressedFields.length>0){
thrownewRuntimeException("Attemptingtobinddisallowedfields:"+
StringUtils.arrayToCommaDelimitedString(suppressedFields));
}
Wewantedtoensurethatourbindingconfigurationisworking;that’swhy,weranour
applicationwithoutchangingtheviewfileaddProduct.jspinstep4.Asexpected,wegot
theHTTPStatus500errorsayingAttemptingtobinddisallowedfieldswhenwe
submittedtheaddproductformwiththeunitsInOrderanddiscontinuedfieldsfilled.
Werealizedthatourbinderconfigurationisworking,sowechangedourviewfiletonot
bindthedisallowedfields.That’swhatwedidinstep6;wejustremovedtheinputfield
elementsthatarerelatedtothedisallowedfieldsfromtheaddProduct.jspfile.
Afterthis,ourpageforaddingnewproductsworksjustfine,asexpected.Incaseanyof
theoutsideattackerstrytotamperthePOSTrequestandattachaHTTPparameterwiththe
samefieldnameoftheform-backingbean,theywillgetRuntimeException.
Whitelistingisjustanexampleofhowwecancustomizethebindingwiththehelpof
WebDataBinder.However,usingWebDataBinder,wecandoothertypesofbinding
customizationsaswell.Forexample,WebDataBinderinternallyusesmany
PropertyEditor(java.beans.PropertyEditor)implementationstoconvertHTTP
requestparameterstothetargetfieldoftheform-backingbean.Wecanevenregisterthe
customPropertyEditorobjectswithWebDataBindertoconvertmorecomplexdatatypes.
Forinstance,takealookatthefollowingcodesnippetthatshowshowtoregisterthe
customPropertyEditorclasstoconvertaDatetype:
@InitBinder
publicvoidinitialiseBinder(WebDataBinderbinder){
DateFormatdateFormat=newSimpleDateFormat("MMMd,YYYY");
CustomDateEditororderDateEditor=newCustomDateEditor(dateFormat,
true);
binder.registerCustomEditor(Date.class,orderDateEditor);
}
TherearemanyadvancedconfigurationswecandowithWebDataBinderintermsofdata
binding,butforabeginnerlevel,wedon’tneedtogosodeep.
Externalizingtextmessages
Sofar,inallourviewfiles,wehardcodedtextvaluesforallofthelabels.Forinstance,
takeouraddProduct.jspfilefortheproductIDinputtag;wehavealabeltagwitha
hardcodedtextvalueasProductId,asfollows:
<labelclass="control-labelcol-lg-2col-lg-2"for="productId">Product
Id</label>
Externalizingthesetextsfromaviewfileintoapropertiesfilewillhelpushavesingle,
centralizedcontrolofallthelabelmessages,andmoreover,itwillhelpusmakeourweb
pagesreadyforinternationalization.Wewillseemoreaboutinternationalizationin
Chapter6,InterceptYourStorewithInterceptor,butinordertodointernationalization,we
needtoexternalizethelabelmessagesfirst.Sonow,wearegoingtoseeonlyhowto
externalizethelocale-sensitivetextmessagesfromourwebpage.
Timeforaction–externalizingmessages
Let’sseehowtoexternalizethelabeltextsinouraddProduct.jspfile:
1. WeopenouraddProduct.jspfileandaddthefollowingtaglibreferenceatthetop:
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
2. ChangetheproductID<label>tag’svalueas<spring:message
code="addProdcut.form.productId.label"/>,asshownasfollows:
<labelclass="control-labelcol-lg-2col-lg-2"for="productId">
<spring:messagecode="addProduct.form.productId.label"/></label>
3. Wecreateafilecalledmessages.propertiesunder/src/main/resourcesinour
projectandaddthefollowinglineinit:
addProduct.form.productId.label=NewProductID
4. Now,weopenourwebapplicationcontextconfigurationfileDispatcherServlet-
context.xmlfromsrc/main/webapp/WEB-INF/spring/webcontext/andaddthe
followingbeandefinitioninit:
<beanid="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
>
<propertyname="basename"value="messages"/>
</bean>
5. Now,werunourapplicationagainandentertheURL
http://localhost:8080/webstore/products/add.Wewillbeabletoseetheadd
productpagewiththeproductIDlabelNewProductID.
Whatjusthappened?
SpringMVChasaspecialatagcalled<spring:message>toexternalizetextsfromJSP
files.Inordertousethistag,weneedtoaddareferencetotheSpringtaglibrary,whichis
whatwedidinstep1.WejustaddedareferencetotheSpringtaglibraryinour
addProduct.jspfileasfollows:
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"%>
Instep2,weusedthistagtoexternalizethelabeltextoftheproductIdinputtag,as
follows:
<labelclass="control-labelcol-lg-2col-lg-2"for="productId">
<spring:messagecode="addProduct.form.productId.label"/></label>
Here,animportantthingthatneedstobenotedisthecodeattributeofthe
<spring:message>tagthatwehaveassignedthevalue
addProduct.form.productId.labelasthecodeforthis<spring:message>tag.This
codeattributeisakindofkey,andatruntime,Springwilltrytoreadthecorresponding
valueforthegivenkey(code)fromamessagesourcepropertyfile.
WesaidthatSpringwillreadthemessagevaluefromamessagesourcepropertyfile,so
weneedtocreatethatpropertyfile,whichiswhatwedidinstep3.Wejustcreateda
propertyfilewiththenamemessages.propertiesundertheresourcedirectory.Insidethis
file,weassignedthelabeltextvaluetothemessagetagcodeasfollows:
addProduct.form.productId.label=NewProductID
Notethatfordemonstrationpurposes,Ijustexternalizedasinglelabel,butatypicalweb
applicationwillhaveexternalizedmessagesalmostforallofthelabels.Inthatcase,the
messages.propertiesfilewillhavemanycode-valuepairentries.
Okay,wehavecreatedthemessagesourcepropertyfileandaddedthe<spring:message>
taginourJSPfile.However,toconnectthesetwo,weneedtocreateonemoreSpring
beaninourwebapplicationcontextforthe
org.springframework.context.support.ResourceBundleMessageSourceclasswiththe
namemessageSource.Wedidthisinstep4asfollows:
<beanid="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<propertyname="basename"value="messages"/>
</bean>
Oneimportantpropertythatneedstobenotedhereisthebasenameproperty.Weassigned
thevaluemessagesforthatproperty;ifyouremember,thisisthenameofthepropertyfile
thatwecreatedinstep3.
ThatisallthatwehavedonetoenabletheexternalizationofmessagesinaJSPfile.Now,
ifweruntheapplicationandopenuptheaddproductpage,wecanseethattheproductID
labelhasthesametextasthatassignedtothecodeaddProduct.form.productId.label
inthemessages.propertiesfile.
UsingSpringSecuritytags
Atthestartofthischapter,wesawhowtoserveandprocesswebforms.Inthatexercise,
wecreatedawebpagetoaddproducts.Anyonewithaccesstotheaddproductspagecan
addnewproductstoourwebstore.However,inatypicalwebstore,onlytheadministrator
canaddproducts.So,howdowerestrictotherusersfromaccessingtheaddproducts
page?TherecomesSpringSecuritytohelpus.
SpringSecurityisavasttopic,sowearenotgoingtoseeallofthecapabilitiesofSpring
Security;instead,weareonlygoingtoseehowtoaddbasicauthenticationtoourweb
pages.
Timeforaction–addingaloginpage
WearegoingtouseSpringSecurityfeaturestorestrictaccesstotheaddproductspage.
Onlyanauthorizeduserwithavalidusernameandpasswordwillbeabletoaccesstheadd
productspage.Let’sseehowwecandothisinSpringMVCwiththefollowingsteps:
1. Weopenpom.xml,whichcanbefoundundertheprojectrootfolderitself.
2. Wewillbeabletoseesometabsatthebottom,underthepom.xmlfile;weselectthe
DependenciestabandclickontheAddbuttonoftheDependenciessection.
3. ASelectDependencywindowwillappear;here,weenterGroupIdas
org.springframework.security,ArtifactIdasspring-security-config,Version
as3.1.4.RELEASE,andselectScopeascompileandclickontheOKbutton.
4. Similarly,weaddonemoredependencyGroupIdas
org.springframework.security,ArtifactIdasspring-security-web,Versionas
3.1.4.RELEASE,andselectScopeascompileandclickontheOKbutton.Andmost
importantly,wesavepom.xml.
5. Now,wegototheadjacenttab,whichistheDependencyHierarchytabinpom.xml.
WecanseetheResolvedDependenciessectionontheright,whichlistsallthe
resolveddependencyentries.
6. Wejustright-clickontheentrywiththenamespring-
asm:3.0.7.RELEASE[compile]fromtheResolvedDependencieslistandchoosethe
ExcludeMavenArtifact…optionandclickonOK.Then,wesavepom.xml.
7. Now,wecreateonemorecontrollerclasscalledLoginControllerunderthe
com.packt.webstore.controllerpackageinsrc/main/javaandaddthefollowing
codeintoit:
packagecom.packt.webstore.controller;
importorg.springframework.stereotype.Controller;
importorg.springframework.ui.Model;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RequestMethod;
@Controller
publicclassLoginController{
@RequestMapping(value="/login",method=RequestMethod.GET)
publicStringlogin(){
return"login";
}
@RequestMapping(value="/loginfailed",method=RequestMethod.GET)
publicStringloginerror(Modelmodel){
model.addAttribute("error","true");
return"login";
}
@RequestMapping(value="/logout",method=RequestMethod.GET)
publicStringlogout(Modelmodel){
return"login";
}
}
8. And,weaddonemoreJSPviewfilecalledlogin.jspundersrc/main/webapp/WEB-
INF/views/andaddthefollowingcodesnippetintoitandsaveit:
<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglibprefix="form"uri="http://www.springframework.org/tags/form"
%>
<%@taglibprefix="spring"uri="http://www.springframework.org/tags"
%>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html;charset=ISO-8859-
1">
<link
rel="stylesheet"href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/boo
tstrap.min.css">
<title>Products</title>
</head>
<body>
<section>
<divclass="jumbotron">
<divclass="container">
<h1>Products</h1>
<p>Addproducts</p>
</div>
</div>
</section>
<divclass="container">
<divclass="row">
<divclass="col-md-4col-md-offset-4">
<divclass="panelpanel-default">
<divclass="panel-heading">
<h3class="panel-title">Pleasesignin</h3>
</div>
<divclass="panel-body">
<c:iftest="${notemptyerror}">
<divclass="alertalert-danger">
<spring:message
code="AbstractUserDetailsAuthenticationProvider.
badCredentials"/><br/>
</div>
</c:if>
<formaction="<c:urlvalue="/j_spring_security_check">
</c:url>"method="post">
<fieldset>
<divclass="form-group">
<inputclass="form-control"placeholder="UserName"
name='j_username'type="text">
</div>
<divclass="form-group">
<inputclass="form-control"placeholder="Password"
name='j_password'type="password"value="">
</div>
<inputclass="btnbtn-lgbtn-successbtn-block"
type="submit"value="Login">
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
9. Now,weopenouraddProduct.jspfileandaddthefollowingcodetagwithinthe
jumbotrondivtag:
<ahref="<c:urlvalue="/j_spring_security_logout"/>"class="btnbtn-
dangerbtn-minipull-right">logout</a>
10. Then,weopenourmessagesourcefilemessages.propertiesfrom
/src/main/resourcesandaddthefollowinglineinit:
AbstractUserDetailsAuthenticationProvider.badCredentials=Theusername
orpasswordyouenteredisincorrect.
11. Now,wecreateonemorebeanconfigurationfilecalledsecurity-context.xml
undersrc/main/webapp/WEB-INF/spring/webcontextandaddthefollowing
contentintoitandsaveit:
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">

<security:httpauto-config="true">
<security:intercept-urlpattern="/products/add"access="ROLE_ADMIN"
/>

<security:form-loginlogin-page="/login"
default-target-url="/products/add"
authentication-failure-url="/loginfailed"/>
<security:logoutlogout-success-url="/logout"/>
</security:http>

<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:username="Admin"password="Admin123"
authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
12. Then,weaddthefollowingtagsinweb.xmlunderthe<web-app>tag:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/webcontext/security-context.xml
</param-value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
13. Now,wealsoaddthefollowingtagsinweb.xmlunderthe<web-app>tagandsaveit:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
14. WerunourapplicationandentertheURL
http://localhost:8080/webstore/products/add.Wewillbeabletoseealogin
page,asshowninthefollowingscreenshot:
Theloginpageshowinganerrormessageforinvalidcredentials
15. Now,weenterUserNameasAdminandPasswordasAdmin123andclickonthe
Loginbutton.Finally,wewillbeabletoseetheregularaddproductspagewitha
Logoutbutton.
Whatjusthappened?
Asusual,inordertouseSpringSecurityinourproject,weneedsomeSpringSecurity
relatedjars;fromsteps1to4,wejustaddedthosejarsasMavendependencies.However,
wedidsomethingunusualinsteps5and6.Weexcludedthespring-asmdependency
(spring-asm:3.0.7.RELEASE[compile])fromtheresolveddependencieslist.
FromtheSpring3.2versiononwards,thespring-asmmodulehadalreadybeenincluded
inthespring-coremodule,sothereisnoneedtohavespring-asmasaseparate
transitivedependency.Ifyouhaveskippedsteps5and6,youwillget
java.lang.IncompatibleClassChangeErrorwhenstartinguptheproject.
Instep7,wecreatedonemorecontroller(LoginController)tohandleallourlogin-
relatedwebrequeststhatcontainsimplythreerequestmappingmethodscorrespondingly
tohandlelogin,loginfailure,andlogoutrequests.Allthreemethodsreturnthesameview
name,outofwhichtheloginerrormethodsetsamodelvariableerrortotrueinthe
model.
Sinceinstep7,alltherequestmappingmethodsreturntheviewnamelogin,weneedto
createaviewfilelogin.jsp,whichiswhatwedidinstep8.
Thelogin.jspfilecontainsmanytagswithaBootstrap-styleclassappliedtoenhancethe
lookandfeeloftheloginform;wedon’tneedtoconcentrateonthesetags.However,
therearesomeimportanttagsouttherethatcanbeusedtounderstandtheflow;thefirst
oneisthe<c:if>tag,asshowninthefollowingcode:
<c:iftest="${notemptyerror}">
<divclass="alertalert-danger">
<spring:message
code="AbstractUserDetailsAuthenticationProvider.badCredentials"/>
</div>
</c:if>
The<c:if>tagisaspecialJSTLtagusedtocheckacondition;itismorelikeanif
conditionthatweuseinourprogramminglanguage.Usingthis<c:if>tag,wesimply
checkwhetherthemodelvariableerrorcontainsanyvalue.Ifthemodelvariableerroris
notempty,wesimplyshowanerrormessagewithinthedivtagusingthe
<spring:message>tag.
RememberthatfromtheExternalizingtextmessagesexercise,wealreadylearned
howtoexternalizemessages.Inthisrecipe,wesimplyusedthepredefinederrorkey,
AbstractUserDetailsAuthenticationProvider.badCredentials,ofSpringSecurityas
themessagekey.Sincewedidthis,wejustoverrodethedefaulterrormessageinstep10.
Okay,comingbacktostep8,whataretheotherimportanttagsinthelogin.jspfile?The
nextimportanttagistheformtag,whichrepresentstheloginform.Notetheaction
attributeoftheformtagshowninthefollowingcode:
<formaction="<c:urlvalue="/j_spring_security_check"></c:url>"
method="post">
Wesimplypostourloginformvalues,suchasusernameandpassword,totheSpring
SecurityauthenticationhandlerURL,whichis/j_spring_security_check.Here,the
special<c:url>JSTLtagisusedtoformattheURL.
WhilepostingtheusernameandpasswordtotheSpringSecurityauthenticationhandler,
Springexpectsthesevaluestobeboundunderthevariablenamesj_usernameand
j_passwordcorrespondingly.That’swhy,ifyounoticetheinputtagfortheusernameand
password,itcarriesthenameattributesasj_usernameandj_password,asfollows:
<inputclass="form-control"placeholder="UserName"name='j_username'
type="text">
<inputclass="form-control"placeholder="Password"name='j_password'
type="password"value="">
Similarly,Springhandlesthelogoutoperationunderthej_spring_security_logout
URL;that’swhy,instep9,weformedthelogoutlinkontheaddproductspageasfollows:
<ahref="<c:urlvalue="/j_spring_security_logout"/>"class="btnbtn-danger
btn-minipull-right">logout</a>
WearealmostdonewiththecodingtoincorporateSpringSecurityintoourproject,but
stillweneedtodosomemoreconfigurationtogetitupandrunningwiththebasic
authenticationfortheaddproductspage.Forthefirstconfiguration,weneedtodefineour
authenticationmanagerandspecifytheauthenticatedusersandrolestoSpringSecurity.
Wedidthiswiththehelpofasecuritycontextfile.
Asecuritycontextfileismoresimilartoawebapplicationcontextconfigurationfile.
Basedontheconfigurationandbeandefinitionfoundinthisfile,Springcreatesand
managesthenecessarybeansrelatedtoSpringSecurity.Wecreatedsuchasecurity
contextfileinstep11.Thefirstconfigurationtagthatisfoundinthissecuritycontextfile
(security-context.xml)is<security:http>,asfollows:
<security:httpauto-config="true">
<security:intercept-urlpattern="/products/add"access="ROLE_ADMIN"/>

<security:form-loginlogin-page="/login"
default-target-url="/products/add"
authentication-failure-url="/loginfailed"/>
<security:logoutlogout-success-url="/logout"/>
</security:http>
The<security:http>tagcontainsalotofinformation,andwewillseethemonebyone.
Thefirstconfigurationwithinthe<security:http>tagisasfollows:
<security:intercept-urlpattern="/products/add"access="ROLE_ADMIN"/>
ThisinstructsSpringtointercepteverywebrequestthatisreceivedbytherequestpath
/products/addandonlyallowsaccesstowhicheveruserhastheroleofROLE_ADMIN.If
yourecall,/products/addisnothingbuttherequestpathforouraddproductspage.
Thenextconfigurationwithinthe<security:http>tagisasfollows:
<security:form-loginlogin-page="/login"
default-target-url="/products/add"
authentication-failure-url="/loginfailed"/>
Here,thelogin-pageattributedenotestheURLthatitshouldforwardtherequestto,to
gettheloginform;rememberthatthisrequestpathshouldbethesameastherequest
mappingofthelogin()methodofLoginController.Also,default-target-urldenotes
thedefaultlandingpageafterasuccessfullogin,andthefinalattributeauthentication-
failure-urlindicatestheURLthattherequestneedstobeforwardedtointhecaseofa
loginfailure.
Thefinalconfiguration,<security:logoutlogout-success-url="/logout"/>,denotes
wheretherequestneedstobeforwardedafteralogout.Rememberthatthisalsocarriesthe
samerequestmappingvalue,whichisthevalueofthelogoutmethod,fromthe
LoginControllerclass.
Thenextconfigurationtaginthesecuritycontextfileisthe<security:authentication-
manager>tag;refertothefollowingcode:
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:username="Admin"password="Admin123"
authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
Theimportantinformationconfiguredundertheauthenticationmanageriswhotheusers
are,whattheircorrespondingpasswordis,andwhichrolestheyhave,asfollows:
<security:username="Admin"password="Admin123"authorities="ROLE_ADMIN"/>
TheprecedingpieceofconfigurationsaysthatitisauserwiththenameAdminandhasa
passwordAdmin123andaroleROLE_ADMIN.Wecanaddasmanyrolesaswewantby
separatingthemwithacomma.
Okay,wedefinedthesecurity-relatedconfigurationinthesecuritycontextfile,butSpring
shouldknowaboutthisfileandhavetoreadthisfilebeforebootingtheapplication.Then
onlywillitbeabletocreateandmanagethesecurity-relatedbeans.Howdoweinstruct
Springtopickupthisfile?Theansweristhesame:thecontextConfigLocationlocation
propertythatwehaveusedtolocatethewebapplicationcontextconfigurationfile.
However,thistime,weloadedthesecuritycontextfilethroughthe
ContextLoaderListenerclassandnotthroughthedispatcherservlet.That’swhy,we
initiatedContextLoaderListenerinweb.xmlandgavecontextConfigLocationviathe
<context-param>taginstep12,asfollows:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webcontext/security-context.xml</param-
value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Basedontheprecedingconfiguration,theContextLoaderListenerclasswillloadour
securitycontextfile(/WEB-INF/spring/webcontext/security-context.xml)intothe
SpringruntimesothatSpringcancreatethenecessarybeanswhilebootingthe
application.
Asafinalstep,weneedtoconfiguretheSpringSecurityfilterinourweb.xmlfilesothat
everywebrequestcanbeexaminedforuserauthentication.Thisiswhatweconfiguredin
step13,asfollows:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Afterfinishingallthesteps,ifweaccesstheURL
http://localhost:8080/WebStore/products/add,SpringMVCwillpromptusto
providetheusernameandpassword.Sincewehaveconfiguredanadminuserinstep11
withUserNameasAdminandPasswordasAdmin123,wehavetoprovidethese
credentialstoproceedtotheaddproductspage.
Summary
Atthestartofthischapter,wesawhowtoserveandprocessforms;welearnedhowto
bindformdatawithaform-backingbeanandreadthatbeaninthecontroller.Afterthat,
wewentalittledeeperintoformbeanbindingandconfiguredthebinderinourcontroller
towhitelistsomeofthePOSTparametersfrombeingboundtotheformbean.Wesaw
howtouseonemorespecialtag,<spring:message>,ofSpringtoexternalizemessagesin
aJSPfile.Finallywealsosawhowtoincorporatespringsecuritytodobasic
authenticationtoaccessproductaddpage.
Inthenextchapter,wewilllearnmoreaboutviewandviewresolvers.
Chapter5.WorkingwithViewResolver
Inthepreviouschapter,welearnedhowwecanusesomeoftheSpringtagsthatcanonly
beusedinJSPandJSTLviews.However,Springhasexcellentsupportforotherview
technologiesaswell,suchastheXMLview,JSONview,andsoon.SpringMVCmaintains
ahighlevelofdecouplingbetweentheviewandcontroller.Thecontrollerknowsnothing
aboutviewexcepttheviewname.Itistheresponsibilityoftheviewresolvertomapthe
correctviewforthegivenviewname.
Inthischapter,wewilltakeadeeperlookintoviewsandviewresolvers.Afterfinishing
thischapter,youwillhaveaclearideaaboutthefollowingtopics:
Viewsandresolvingviews
Staticviews
Themultipartviewresolver
Contentnegotiation
Thehandlerexceptionresolver
Resolvingviews
Aswealreadymentioned,SpringMVCdoesnotmakeanyassumptionaboutanyspecific
viewtechnology.AccordingtoSpringMVC,aviewisidentifiableasanimplementation
oftheorg.springframework.web.servlet.Viewinterface,shownasfollows:
publicinterfaceView{
StringgetContentType();
voidrender(Map<String,?>model,HttpServletRequestrequest,
HttpServletResponseresponse)throwsException;
}
TherendermethodfromtheSpringMVCViewinterfacedefinesthemainresponsibility
ofaviewobject.Theresponsibilityisthatitshouldrenderofpropercontentasaresponse
(javax.servlet.http.HttpServletResponse)basedonModelandrequest
(javax.servlet.http.HttpServletRequest).
BecauseofthesimplicityofSpringMVC’sViewinterface,wecanwriteourownview
implementationifwewant.However,SpringMVCprovidesmanyconvenientview
implementationsthatarereadyforusebysimplyconfiguringitinourwebapplication’s
contextconfigurationfile.
OnesuchviewisInternalResourceView
(org.springframework.web.servlet.view.InternalResourceView),whichrendersthe
responseasaJSPpage.Similarly,thereareotherviewimplementationssuchas
RedirectView,TilesView,FreeMarkerView,andVelocityView,whichareavailablefor
specificviewtechnologies.SpringMVCdoesnotencouragecouplingtheviewobject
withthecontrollerasitwillleadthecontrollermethodtotightlycouplewithonespecific
viewtechnology.However,ifyouwanttodoso,youcandosomethingsimilartowhatis
showninthefollowingcodesnippet:
@RequestMapping("/home")
publicModelAndViewgreeting(Map<String,Object>model){

model.put("greeting","WelcometoWebStore!");
model.put("tagline","Theoneandonlyamazingwebstore");

Viewview=newInternalResourceView("/WEB-INF/views/welcome.jsp");

returnnewModelAndView(view,model);
}
Intheprecedingcodehandlermethod,wehaven’treturnedanylogicalviewname;rather,
wedirectlyinstantiatedInternalResourceViewoutofwelcome.jspandcomposeditinto
theModelAndView(org.springframework.web.servlet.ModelAndView)object.The
precedingexampleisnotencouragedsinceithastightlycoupledthegreetinghandler
methodwithInternalResourceView.Instead,whatwecandoisreturnalogicalview
nameandconfigureanappropriateviewresolverofourchoiceinourwebapplication’s
contexttocreateaviewobject.
Springcomeswithquiteafewviewresolverstoresolvevarioustypesofviews.We
alreadylearnedhowwecanconfigureInternalResourceViewResolverasourview
resolvertoresolveJSPviewsinChapter2,SpringMVCArchitecture–ArchitectingYour
WebStore,andwealsolearnedhowInternalResourceViewResolverresolvesa
particularlogicalviewnameintoaview(seetheViewresolverssection,inChapter2,
SpringMVCArchitecture–ArchitectingYourWebStore).Anyhow,Iwillrepeatitbriefly
here.
InternalResourceViewResolverwillresolvetheactualview’sfilepathbyprepending
theconfiguredprefixvalueandappendingthesuffixvaluewiththelogicalviewname;the
logicalviewnameisthevalueusuallyreturnedbythecontrollermethod.So,the
controllermethoddidn’treturnanyactualview;itjustreturnedtheviewname.Itisthe
jobofInternalResourceViewResolvertoformthecorrectURLpathofactualJSPview
fileforInternalResourceView.
Theredirectview
Inawebapplication,URLredirectionorforwardingarethetechniquestomovevisitorsto
adifferentwebpagethantheonetheyrequest.Mostofthetime,thistechniqueisused
aftersubmittingawebformtoavoidresubmissionofthesameformduetotheeventof
pressingthebrowsersbackbuttonorrefreshbutton.SpringMVChasaspecialView
objectcalledRedirectviewtohandleredirectionandforwarding.TouseRedirectview
(org.springframework.web.servlet.view.Redirectview)withourcontroller,we
simplyneedtoreturnthetargetURLstringwiththeredirectionprefixfromthecontroller.
TherearetworedirectionprefixesavailableinSpringMVC,asshowninthefollowing
codesnippet:
returnredirect:/products/productDetail
And:
returnforward:/products/productDetail
Timeforaction–examiningRedirectView
Thoughbothredirectionandforwardingareusedtopresentadifferentwebpagethanthe
onerequested,thereisalittledifferencebetweenthem.Let’strytounderstandtheseby
examiningthem:
1. OpenourHomeControllerclassandaddonemorerequestmappingmethodas
follows:
@RequestMapping("/welcome/greeting")
publicStringgreeting(){
return"welcome";
}
2. Now,alterthereturnstatementoftheexistingwelcomerequestmappingmethod,
andsaveitasfollows:
return"forward:/welcome/greeting";
3. Now,runourapplicationandenterhttp://localhost:8080/webstore/.Youwillbe
abletoseeawelcomemessageonthewebpage.
4. Now,alterthereturnstatementoftheexistingwelcomerequestmappingmethod
againandsaveitasfollows:
return"redirect:/welcome/greeting";
5. Now,runourapplicationandenterhttp://localhost:8080/webstore/.Youwill
seeablankpagewithoutanywelcomemessage.
6. Finally,revertthereturnvalueofthewelcomemethodofHomeControllertothe
originalvalue,shownasfollows:
return"welcome";
Whatjusthappened?
So,whatwehavedemonstratedhereishowwecaninvoketheredirectviewfromthe
controllermethod.Instep1,wesimplycreatedarequestmappingmethodcalled
greetingforthewelcome/greetingrequestpath.Thismethodsimplyreturnsalogical
viewnameaswelcome.
Sincewereturnedthelogicalviewnameaswelcome,thewelcome.jspfilewillbe
renderedbyInternalResourceViewatruntime.Thewelcome.jspfileexpectstwomodel
attributes,namelygreetingandtagline,duringrendering.Instep2,wealteredthe
returnstatementoftheexitingrequestmappingmethodtoreturnaredirectedURL,as
follows:
@RequestMapping("/")
publicStringwelcome(Modelmodel){
model.addAttribute("greeting","WelcometoWebStore!");
model.addAttribute("tagline","Theoneandonlyamazingwebstore");
return"forward:/welcome/greeting";
}
Whatwehavedoneinstep2ismoreimportant;insteadofreturningalogicalviewname,
wesimplyreturntherequestpathvalueofthegreetinghandlermethodwiththe
forward:keywordprefixed.
ThemomentSpringMVCseesthis,itcanunderstandthatitisnotaregularlogicalview
name,soitwon’tsearchforanyviewfileunderthesrc/main/webapp/WEB-INF/views/
directory;rather,itwillconsiderthisrequestforittobeforwardedtoanotherrequest
mappingmethodbasedontherequestpathattachedaftertheforward:keyword.
Oneimportantthingtorememberhereisthattheforwardedrequestisstilltheactive
originalrequest,sowhatevervaluewehaveputinthemodelatthestartoftherequest
wouldstillbeavailable.ThisiswhywedidnotaddanyvaluetoModelinsidethe
greetingmethod.Wesimplyreturntheviewnameaswelcomeandthewelcome.jspfile
ontheassumptionthattherewillbemodelattributes,namelygreetingandtagline,
availableinthemodel.So,whenwefinallyrunourapplication,asmentionedinstep3,
eventhoughweissuedtherequesttotheURLhttp://localhost:8080/webstore/,the
RedirectViewwillforwardourrequestto
http://localhost:8080/webstore/welcome/greeting,andwewillabletoseethe
welcomemessageonthewebpage.
Againinstep4,wesimplychangedthereturnstatementofthewelcomemethodwiththe
redirect:prefix.Thistime,Springwillconsiderthisrequestasanewrequest,so
whatevervaluewehaveputinthemodel(insidethewelcomemethod)atthestartofthe
originalrequestwouldhavebeengone.Thisiswhyyousawanemptywelcomepagein
step6,sincethewelcome.jsppagecan’treadthegreetingandtaglinemodelattributes
fromthemodel.
So,basedonthisexercise,weunderstandthatRedirectViewwillgetintothepictureifwe
returnaredirectedURLwiththeappropriateprefixfromthecontrollermethod.
RedirectViewwillkeeptheoriginalrequestorspawnanewrequestbasedonredirection
orforwarding.
Popquiz–redirectview
Considerthefollowingcustomercontroller:
@Controller("/customers")
publicclassCustomerController{
@RequestMapping("/list")
publicStringlist(Modelmodel){
return"customers";
}
@RequestMapping("/process")
publicStringprocess(Modelmodel){
//return
}
}
Q1.IfIwanttogetredirectedtothelistmethodfromprocess,howshouldIformthe
returnstatementwithintheprocessmethod?
1. return"redirect:list";.
2. return"redirect:/list";.
3. return"redirect:customers/list";.
4. return"redirect:/customers/list";.
Servingstaticresources
Sofar,wehaveseenthateveryrequestgoesthroughthecontrollerandreturnsa
correspondingviewfilefortherequest;mostofthetime,theseviewfilescontaindynamic
content.Bydynamiccontent,Imeanthemodelvaluesthataredynamicallypopulatedin
theviewfileduringtherequestprocessing.Forexample,iftheviewfileisoftheJSPtype,
thenwepopulatemodelvaluesintheJSPfileusingtheJSPexpressionnotation,${}.
However,whatifwehavesomestaticcontentthatwewanttoservetotheclient?For
example,consideranimagethatisstaticcontent;wedon’twanttogothroughcontrollers
inordertoserve(fetch)animageasthereisnothingtoprocessorupdateanyvaluesinthe
model.Wesimplyneedtoreturntherequestedimage.
Let’ssaywehaveadirectory(/resources/images/)thatcontainssomeproductimages,
andwewanttoservetheseimagesuponrequest.Forexample,iftherequestedURLis
http://localhost:8080/webstore/resource/images/P1234.png,thenwewouldliketo
servetheimagewiththeP1234.pngname.Similarly,iftherequestedURLis
http://localhost:8080/webstore/resource/images/P1236.png,thenanimagewith
thenameP1236.pngneedstobeserved.
Timeforaction–servingstaticresources
Let’sseehowwecanservestaticimageswithSpringMVC:
1. Placesomeimagesunderthesrc/main/webapp/resources/images/directory;I
haveusedthreeproductimages,namelyP1234.png,P1235.png,andP1236.png.
2. Addthefollowingtaginourwebapplicationcontext’sconfiguration
DispatcherServlet-context.xmlfile:
<mvc:resourceslocation="/resources/"mapping="/resource/**"/>
3. Now,runourapplicationandenter
http://localhost:8080/webstore/resource/images/P1234.png(changethe
imagenameintheURLbasedontheimagesyouplacedinstep1).
4. Youarenowabletoviewtheimageyourequestedinthebrowser.
Whatjusthappened?
Whatjusthappenedwassimple;instep1,weplacedsomeimagefilesunderthe
src/main/webapp/resources/images/directory.Instep2,wejustaddedthe
<mvc:resources>taginthewebapplicationcontextconfigurationtotellSpringwhere
theseimagefilesarelocatedinourprojectsothatspringcanservethosefilesupon
request.Considerthefollowingcodesnippet:
<mvc:resourceslocation="/resources/"mapping="/resource/**"/>
Thelocationattributeofthe<mvc:resources>tagdefinesthebasedirectorylocationof
staticresourcesthatyouwanttoserve.Inourcase,wewanttoserveallimagesthatare
availableunderthesrc/main/webapp/resources/images/directory;youmaywonder
whywehavegivenonly/resources/asthelocationvalueinsteadof
src/main/webapp/resources/images/.Thisisbecauseweconsidertheresources
directoryasthebasedirectoryforallresources,wecanhavemultiplesubdirectoriesunder
resourcesdirectorytoputourimagesandotherstaticresourcefiles
Thesecondattribute,mapping,justindicatestherequestpaththatneedstobemappedto
thisresourcedirectory.Inourcase,wehaveassigned/resources/**asthemapping
value.So,ifanywebrequeststartswiththe/resourcerequestpath,thenitwillbe
mappedtotheresourcesdirectory,andthe/**symbolindicatestherecursivelookfor
anyresourcefilesunderneaththebaseresourcedirectory.
Thisiswhy,ifyounoticeinstep3,weformedtheURLas
http://localhost:8080/webstore/resource/images/P1234.png.So,whileservingthis
webrequest,SpringMVCwillconsider/resource/images/P1234.pngastherequest
path.So,itwilltrytomap/resourcetotheresourcebasedirectory,resources.Fromthis
directory,itwilltrytolookfortheremainingpathoftheURL,whichis
/images/P1234.png.Sincewehavetheimagesdirectoryundertheresourcesdirectory,
Springcaneasilylocatetheimagefilefromtheimagesdirectory.
Asamatteroffact,behindthescreen,SpringMVCuses
org.springframework.web.servlet.resource.ResourceHttpRequestHandlertoserve
theresourcesthatareconfiguredbythe<mvc:resources>tag.So,inourapplication,if
anyrequestcomeswiththerequestpath’s/resourceprefixinitsURL,thenSpringwill
lookintothelocationdirectorythatisconfiguredinthe<mvc:resources>tagandwill
returntherequestedfiletothebrowser.Remember,Springallowsyoutohostnotonly
images,butalsoanytypeofstaticfiles,suchasPDFs,Worddocuments,Excelsheets,and
sooninthisfashion.
Itisgoodthatweareabletoserveproductimageswithoutaddinganyextrarequest
mappingmethodsinthecontroller.
Popquiz–staticview
Considerthefollowingresourceconfiguration:
<mvc:resourceslocation="/pdf/"mapping="/resources/**"/>
Q1.Underthepdfdirectory,ifIhaveasubdirectorysuchasproduct/manuals/,which
containsa.pdffilecalledmanual-P1234.pdf,howcanIformtherequestpathtoaccess
that.pdffile?
1. /pdf/product/manuals/manual-P1234.pdf.
2. /resources/pdf/product/manuals/manual-P1234.pdf.
3. /product/manuals/manual-P1234.pdf.
4. /resource/pdf/product/manuals/manual-P1234.pdf.
Timeforaction–addingimagestothe
productdetailpage
Let’sextendthistechniquetoshowproductimagesinourproductlistingpageandinthe
productdetailpage.Performthefollowingsteps:
1. Openproducts.jsp;youcanfindproducts.jspunderthe/src/main/webapp/WEB-
INF/views/directoryinyourproject.Now,addthefollowing<img>tagafterthe
<divclass="thumbnail">tag:
<imgsrc="<c:urlvalue="/resource/images/${product.productId}.png">
</c:url>"alt="image"style="width:100%"/>
2. Similarly,openproduct.jspandaddthefollowing<img>tagafterthe<div
class="row">tag:
<divclass="col-md-5">
<imgsrc="<c:urlvalue="/resource/images/${product.productId}.png">
</c:url>"alt="image"style="width:100%"/>
</div>
3. Now,runourapplicationandenterhttp://localhost:8080/webstore/products.
Youwillbeabletoseetheproductlistpagewitheveryproductthathasaproduct
image,asshowninthefollowingfigure:
Productlistingswiththeimageattached
4. Now,clickontheDetailsbuttonofanyproduct,andyouwillbeabletoseethe
correspondingviewoftheproductdetailswiththeimageattachedtothedetailspage,
asfollows:
Theproductdetailpagewiththeimageattached
Whatjusthappened?
Whatwehavedoneissimple.Welearnedhowwecanservestaticresourcesandhowwe
canhostproductimages.Duringthisexercise,welearnedthatinourapplication,ifany
requestcomeswiththerequestpath’s/resourceprefix,itwouldgetmappedtothebase
resourcedirectory,andanyremainingURLpathwouldleadtothestaticfile.
Weleveragedthisfact,andformedtheimage’ssrcURLaccordingly;noticethesrc
attributeofthe<img>tagweaddedinstep1:
<imgsrc="<c:urlvalue="/resource/images/${product.productId}.png">
</c:url>"alt="image"style="width:100%"/>
Thesrcattributevaluethatweareforminginthepreceding<img>taghasanexpression
languagenotationtofetchtheproductID;aftergettingtheproductID,wesimply
concatenateittotheexistingvaluetoformavalidrequestpath,shownasfollows:
/resource/images/${product.productId}.png
Forexample,iftheproductIDisP1234,thenwewouldgetanimagerequestURLas
/resource/images/P1234.png,whichisnothingbutoneoftheimagefilenamesthatwe
havealreadyputupinthe/resources/imagesdirectory.So,Springcaneasilyreturnthe
imagefilethatweshowedusingthe<img>taginsteps1and2.
Themultipartrequestinaction
Intheprecedingexercise,welearnedhowwecanincorporatethestaticviewtoshow
productimagesintheproducts’detailspage.Wesimplyputsomeimagesinadirectoryin
theserverandperformedaconfiguration,andSpringMVCwasabletopickupthesefiles
duringtherenderingofthepagethathadtheproductdetails.Whatifweautomatethis
process?Imeaninsteadofputtingtheseimages,whatifweareabletouploadimagesto
theimagedirectory?
Howcanwedothis?Therecomesthemultipartrequest.Themultipartrequestisatypeof
HTTPrequestthatsendsthefileanddatatotheserver.SpringMVChasgoodsupportfor
amultipartrequest.Let’ssaywewanttouploadsomefilestotheserver.Toaccomplish
this,wewillhavetoformamultipartrequest.
Timeforaction–addingimagestothe
productpage
Let’saddtheimageuploadfacilitytoouraddproductspage:
1. Addabeandefinitioninourwebapplication’scontextconfigurationfile
(DispatcherServlet-context.xml)forCommonsMultipartResolver,asfollows:
<beanid="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolv
er">
<propertyname="maxUploadSize"value="10240000"/>
</bean>
2. Openpom.xml;youcanfindpom.xmlundertheprojectrootdirectoryitself.
3. Youwillbeabletoseesometabsatthebottomofthepom.xmlfile.Selectthe
DependenciestabandclickontheAddbuttonoftheDependenciessection.
4. ASelectDependencywindowwillappear;enterGroupIdascommons-fileupload,
ArtifactIdascommons-fileupload,Versionas1.2.2;selectScopeascompile;and
clickontheOKbutton.
5. Similarly,addonemoreGroupIddependencyasorg.apache.commons,ArtifactId
ascommons-io,Versionas1.3.2;selectScopeascompile;clickontheOKbutton;
andsavethepom.xmlfile.
6. Openourproduct’sdomainclass(Product.java)andaddareferenceto
org.springframework.web.multipart.MultipartFilewiththecorresponding
settersandgettersasfollows:
privateMultipartFileproductImage;
7. OpenaddProduct.jsp;youcanfindaddProduct.jspunderthe
/src/main/webapp/WEB-INF/views/directoryinyourproject.Addthefollowingset
oftagsafterthe<form:inputid="condition">taggroup:
<divclass="form-group">
<labelclass="control-labelcol-lg-2"for="productImage">
<spring:messagecode="addProdcut.form.productImage.label"/></label>
<divclass="col-lg-10">
<form:inputid="productImage"path="productImage"type="file"
class="form:input-large"/>
</div>
</div>
8. Addanentryinourmessagebundlesource(messages.properties)fortheproduct’s
imagelabel,asfollows:
addProdcut.form.productImage.label=ProductImagefile
9. Now,settheenctypeattributetomultipart/form-dataintheformtagasfollows
andsaveaddProduct.jsp:
<form:formmodelAttribute="newProduct"class="form-
horizontal"enctype="multipart/form-data">
10. OpenourProductController.javafileandmodifytheprocessAddNewProductForm
method’ssignaturebyaddinganextramethodparameteroftheHttpServletRequest
type(javax.servlet.http.HttpServletRequest);sobasically,your
processAddNewProductFormmethodsignatureshouldlooklikethefollowingcode
snippet:
publicStringprocessAddNewProductForm(@ModelAttribute("newProduct")
ProductnewProduct,BindingResultresult,HttpServletRequestrequest){
11. AddthefollowingcodesnippetinsidetheprocessAddNewProductFormmethodjust
beforeproductService.addProduct(newProduct);:
MultipartFileproductImage=productToBeAdded.getProductImage();
StringrootDirectory
=request.getSession().getServletContext().getRealPath("/");
if(productImage!=null&&!productImage.isEmpty()){
try{

productImage.transferTo(newFile(rootDirectory+"resources\\images\\"+pro
ductToBeAdded.getProductId()+".png"));
}catch(Exceptione){
thrownewRuntimeException("ProductImagesavingfailed",e);
}
}
12. WithintheinitialiseBindermethod,addtheproductImagefieldtothewhitelisting
setasfollows:
binder.setAllowedFields("productId","name","unitPrice","description","m
anufacturer","category","unitsInStock","productImage");
13. Now,runourapplicationandentertheURL
http://localhost:8080/webstore/products/add.Youwillbeabletoseeouradd
productspagewithanextrainputfieldtochooseafiletoupload.Justfillevery
informationasusualandmoreimportantly,chooseanimagefileofyourchoiceto
addanewimagefile,andclickontheAddbutton.Youwillthenbeabletoseethat
theimagehasbeenaddedtotheproductspageandtheproductdetailspage,asshown
inthefollowingscreenshot:
Addproductpagewithimageselectionoption
Whatjusthappened?
Spring’sCommonsMultipartResolver
(org.springframework.web.multipart.commons.CommonsMultipartResolver)class
determineswhetherthegivenrequestcontainsmultipartcontentornotandparsesthe
givenHTTPrequestintomultipartfilesandparameters.Thisiswhyweinitiatedthisclass
withinourservletcontextinstep1.ThroughthemaxUploadSizeproperty,wehaveseta
maximumof10240000bytesastheallowedfilesizetobeuploaded:
<bean
id="multipartResolver"class="org.springframework.web.multipart.commons.Comm
onsMultipartResolver">
<propertyname="maxUploadSize"value="10240000"/>
</bean>
Fromsteps2to5,weaddedsomeoftheorg.apache.commonslibrariesasourmaven
dependency.ThisisbecauseSpringusestheselibrariesinternallytosupportthefile
uploadingfeature.
Sincetheimagethatwewereuploadingbelongstoaproduct,itisbettertokeepthat
imageaspartoftheproductinformation;thisiswhyinstep6,weaddedareferenceto
MultipartFileinourdomainclass(Product.java)andaddedcorrespondingsettersand
getters.ThisMultipartFilereferenceholdstheactualproductimagefilethatwewere
uploading.
Wewanttoincorporatetheimageuploadingfacilityinouraddproductspage;thisiswhy,
intheaddProduct.jspviewfile,weaddedafileinputtagtochoosethedesiredimage,
shownasfollows:
<divclass="form-group">
<labelclass="control-labelcol-lg-2"for="productImage"><spring:message
code="addProdcut.form.productImage.label"/>
</label>
<divclass="col-lg-10">
<form:inputid="productImage"path="productImage"type="file"
class="form:input-large"/>
</div>
</div>
Intheprecedingsetoftag,theimportantoneisthe<form:input>tag.Ithasthetype
attributeasfilesothatitcanhavetheChooseFilebuttontodisplaythefilechooser
window.Asusual,wewantthisformfieldtobeboundwiththedomainobjectfield;thisis
whywehavesetthepathattributeasproductImage.Ifyouremembercorrectly,this
pathnameisnothingbutthesameMultipartFilereferencenamethatweaddedinstep6.
Asusual,wewanttoexternalizethelabelmessageforthisfileinputtagaswell,andthat’s
whyweaddedthe<spring:message>tag,andinstep8,weaddedthecorresponding
messageentryinthemessagesourcefile(messages.properties).
Sinceouraddproductformisnowcapableofsendingimagefilesaswellaspartofthe
request,weneedtoencodetherequestasamultipartrequest.Thisiswhy,instep9,we
addedtheenctypeattributetothe<form:form>tagandsetitsvalueasmultipart/form-
data.Theenctypeattributeindicateshowtheformdatashouldbeencodedwhenweare
submittingittotheserver.
Wewantedtosavetheimagefileintheserverunderthelocation’sresources/images
directory;thisdirectorystructurewouldbeavailabledirectlyundertherootdirectoryof
ourwebapplicationatruntime.So,inordertogettherootdirectoryofourweb
application,weneedHttpServletRequest.Seethefollowingcodesnippet:
StringrootDirectory=
request.getSession().getServletContext().getRealPath("/");
Thisiswhyweaddedanextramethodparametercalledrequestofthe
HttpServletRequesttypetoourprocessAddNewProductFormmethodinstep10.
Remember,SpringwillfillthisrequestparameterwiththeactualHTTPrequest.
Instep11,wesimplyreadtheimagefilefromthedomainobjectandwroteitintoanew
filewiththeproductIDasthename,asshowninthefollowingcodesnippet:
MultipartFileproductImage=productToBeAdded.getProductImage();
StringrootDirectory=
request.getSession().getServletContext().getRealPath("/");
if(productImage!=null&&!productImage.isEmpty()){
try{
productImage.transferTo(new
File(rootDirectory+"resources\\images\\"+
productToBeAdded.getProductId()+".png"));
}catch(Exceptione){
thrownewRuntimeException("ProductImagesavingfailed",e);
}
}
Remember,wepurposelysavetheimageswiththeproductIDnamebecausewehave
alreadydesignedourproducts(products.jsp)pageanddetail(product.jsp)page
accordinglyinordertodisplaytherightimagebasedontheproductID.
Asafinalstep,weaddedthenewlyintroducedproductImagefiletothewhitelistingsetin
thebinderconfigurationwithintheinitialiseBindermethod.
Now,ifyourunourapplicationandenter
http://localhost:8080/webstore/products/add,youwillbeabletoseeouradd
productspagewithanextrainputfieldtochoosethefiletoupload.
Haveagohero–uploadingproductusermanuals
totheserver
Itisnicethatwewereabletouploadtheproductimagetotheserverwhileaddinganew
product.Whydon’tyouextendthisfacilitytouploadaPDFfiletoserver?Forexample,
considerthateveryproducthasausermanualandyouwanttouploadtheseusermanuals
aswellwhileaddingaproduct.
HerearesomeofthethingsyoucandotouploadPDFfiles:
Createadirectorywiththepdfnameunderthesrc/main/webapp/resources/
directoryinyourproject.
AddonemoreMultipartFilereferenceinyourproductdomainclass
(Product.java)toholdthePDFfileandchangeProduct.javaaccordingly.
ExtendaddProduct.jsp.
ExtendProductController.javaaccordingly;don’tforgettoaddthenewlyadded
fieldtothewhitelist.
Sofinally,youwillbeabletoaccessthePDFunder
http://localhost:8080/webstore/resource/pdf/P1237.pdfifthenewlyadded
productidisP1237.Goodluck!
UsingContentNegotiatingViewResolver
Contentnegotiationisamechanismthatmakesitpossibletoserveadifferent
representationofthesameresource.Forexample,sofarwehavedisplayedourproduct
detailpageinaJSPrepresentation.Whatifwewanttorepresentthesamecontentinan
XMLformat,andsimilarly,whatifwewantthesamecontentinaJSONformat?There
comesSpringMVC’sContentNegotiatingViewResolver
(org.springframework.web.servlet.view.ContentNegotiatingViewResolver)tohelp
us.TheXMLandJSONformatsarepopulardatainterchangeformatsthatareusedinweb
servicecommunicationsheavily.So,usingContentNegotiatingViewResolver,wecan
incorporatemanyviewssuchasMappingJacksonJsonView(forJSON)and
MarshallingView(forXML)torepresentthesameproductinformationasthe
XML/JSONformat.
Timeforaction–configuring
ContentNegotiatingViewResolver
ContentNegotiatingViewResolverdoesnotresolveviewsitselfbutdelegatesthemto
otherviewresolversbasedontherequest.Now,let’saddthecontentnegotiationcapability
toourapplication:
1. Openpom.xml;youcanfindpom.xmlundertheprojectrootdirectoryitself.
2. Youwillbeabletoseesometabsatthebottomofpom.xmlfile.Selectthe
DependenciestabandclickontheAddbuttonoftheDependenciessection.
3. ASelectDependencywindowwillappear;enterGroupIdas
org.springframework,ArtifactIdasspring-oxm,Versionas4.0.3.RELEASE;
selectScopeascompile;andthenclickontheOKbutton.
4. Similarly,addonemoredependencyGroupIdasorg.codehaus.jackson,Artifact
Idasjackson-mapper-asl,Versionas1.9.10,andselectScopeascompile.Then,
clickontheOKbuttonandsavepom.xml.
5. AddthebeanconfigurationforContentNegotiatingViewResolverinourweb
application’scontextconfigurationfile,DispatcherServlet-context.xml,as
follows:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResol
ver">
<propertyname="defaultViews">
<list>
<refbean="jsonView"/>
<refbean="xmlView"/>
</list>
</property>
</bean>
6. Now,addthebeanconfigurationfortheJSONviewasfollows:
<beanid="jsonView"
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView
">
<propertyname="prettyPrint"value="true"/>
</bean>
7. Finally,addthebeanconfigurationfortheXMLviewasfollows:
<beanid="xmlView"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<beanclass="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<propertyname="classesToBeBound">
<list>
<value>com.packt.webstore.domain.Product</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
8. Openourproductdomainclass(Product.java),andaddthe@XmlRootElement
annotationatthetopoftheclass.
9. Similarly,addthe@XmlTransientannotationatthetopofthegetProductImage()
methodandaddanother@JsonIgnoreannotationontopoftheproudctImagefield.
10. Now,runourapplicationandenter
http://localhost:8080/webstore/products/product?id=P1234.Youwillnowbe
abletoviewthedetailpageoftheproductwiththeP1234ID.
11. NowchangetheURLwiththe.xmlextension
(http://localhost:8080/webstore/products/product.xml?id=P1234).Youwill
beabletoseethesamecontentintheXMLformat,asshowninthefollowing
screenshot:
TheproductdetailpagethatshowstheproductinformationintheXMLformat
12. Similarly,thistimechangetheURLwiththe.jsonextension
(http://localhost:8080/webstore/products/product.json?id=P1234).Youwill
beabletoseetheJSONrepresentationofthatcontentasshowninthefollowing
screenshot:
TheproductdetailpagethatshowstheproductinformationintheJSONformat
Whatjusthappened?
SincewewantanXMLrepresentationforourmodeldatatoconvertourmodelobjects
intoXML,weneedSpring’sobject/XMLmappingsupport.Thisiswhyweaddedthe
dependencyforspring-oxm.jarinsteps1to3.Thespring-oxmnotationwillhelpus
convertanXMLdocumenttoandfromaJavaobject.
Similarly,toconvertmodelobjectsintoJSON,SpringMVCwillusejackson-mapper-
asl.jar,soweneedthatJARinourprojectaswell.Instep4,wejustaddedthe
dependencyconfigurationforthatjar.
Ifyouremember,wehavealreadydefinedInternalResourceViewResolverinourweb
applicationcontextasourviewresolvertoresolveJSP-basedviews.However,thistime,
wewantaviewresolvertoresolveXMLandJSONviews.Thisiswhy,instep6and7,we
configuredMappingJacksonJsonView(forJSON)andMarshallingView(forXML)inour
webapplicationcontext.
AsIalreadymentioned,ContentNegotiatingViewResolverdoesnotresolveviewsitself.
Instead,itdelegatestootherviewsbasedontherequest,soweneedtointroduceother
viewstoContentNegotiatingViewResolver.Wedidthatinstep5throughthe
defaultViewspropertyinContentNegotiatingViewResolver.Notethatinthe
ContentNegotiatingViewResolverbeanconfiguration,wejustaddedthebeanreference
fortheJSONviewandXMLviewunderthedefaultViewsproperty:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
>
<propertyname="defaultViews">
<list>
<refbean="jsonView"/>
<refbean="xmlView"/>
</list>
</property>
</bean>
WeconfiguredbeanreferencesforjsonViewandxmlViewinside
ContentNegotiatingViewResolver.
ThexmlViewbeanconfiguration,especially,hasoneimportantpropertycalled
classesToBeBound,whichliststhedomainobjectsthatneedsXMLconversionduringthe
requestprocessing.SinceourproductdomainobjectneedstheXMLconversion,weadded
com.packt.webstore.domain.ProductinthelistofclassesToBeBound,shownas
follows:
<beanid="xmlView"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<beanclass="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<propertyname="classesToBeBound">
<list>
<value>
com.packt.webstore.domain.Product
</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
InordertoconverttoXML,weneedtogiveonemorehinttoMarshallingViewto
identifytherootXMLelementintheProductdomainobject.Thisiswhy,instep8,we
annotatedourclasswiththe@XmlRootElementannotation
(javax.xml.bind.annotation.XmlRootElement).
Instep9,weaddedthe@XmlTransientannotation
(javax.xml.bind.annotation.XmlTransient)ontopofthegetProductImage()method
andaddedanotherannotation,@JsonIgnore
(org.codehaus.jackson.annotate.JsonIgnore),ontopoftheproductImagefield.This
isbecausewedon’twanttorepresenttheproductimageaspartoftheXMLvieworJSON
view.Sincebothformatsarepurelytext-basedrepresentation,itisnotpossibleto
representimagesintexts.
Instep10,wesimplyaccessedourproductdetailpageinaregularwaybyfiringtheweb
requesthttp://localhost:8080/webstore/products/product?id=P1234fromthe
browser,andwewillbeabletoseethenormalJSPview,asexpected.
Instep11,wejustchangedtheURLslightlybyaddinga.xmlextensiontothe
http://localhost:8080/webstore/products/product.xml?id=P1234requestpath.
Thistime,wewillbeabletoseethesameproductinformationintheXMLformat.
Similarly,fortheJSONview,wechangedtheextensionbyadding.jsontothe
http://localhost:8080/webstore/products/product.json?id=P1234path,andwe
willbeabletoseetheJSONrepresentationofthesameproductinformation.
Workingwiththehandlerexception
resolver
SpringMVCprovidesseveralapproachestoexceptionhandling.InSpring,oneofthe
mainexceptionhandlingconstructsistheHandlerExceptionResolverinterface
(org.springframework.web.servlet.HandlerExceptionResolver).Anyobjectsthat
implementthisinterfacecanresolveexceptionsthatarethrownduringcontrollermapping
orexecution.TheHandlerExceptionResolverimplementersaretypicallyregisteredas
beansinthewebapplicationcontext.
SpringMVCcreatestwosuchHandlerExceptionResolverimplementationsbydefaultto
facilitateexceptionhandling:
ResponseStatusExceptionResolveriscreatedtosupportthe@ResponseStatus
annotation
ExceptionHandlerExceptionResolveriscreatedtosupportthe@ExceptionHandler
annotation
Timeforaction–addingtheresponse
statusexception
First,wewilllookatthe@ResponseStatusannotation
(org.springframework.web.bind.annotation.ResponseStatus).InChapter3,Control
YourStorewithControllers,wecreatedarequestmappingmethodtodisplayproductsby
categoryundertheURItemplate,
http://localhost:8080/webstore/products/{category}.Ifnoproductswerefound
underthegivencategory,wewouldshowanemptywebpage,whichisnotcorrect
semantically.WeshouldshowanHTTPstatuserrortoindicatethatnoproductsexist
underthegivencategory.Let’sseehowwecandothatwiththehelpofthe
@ResponseStatusannotation:
1. CreateaclasscalledNoProductsFoundUnderCategoryExceptionunderthe
com.packt.webstore.exceptionpackageinthesourcefolder,src/main/java.Now
addthefollowingcodeintoit:
packagecom.packt.webstore.exception;
importorg.springframework.http.HttpStatus;
importorg.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="Noproductsfound
underthiscategory")
publicclassNoProductsFoundUnderCategoryExceptionextends
RuntimeException{
privatestaticfinallongserialVersionUID=3935230281455340039L;
}
2. Now,openourProductControllerclassandmodifythegetProductsByCategory
methodasfollows:
@RequestMapping("/{category}")
publicStringgetProductsByCategory(Model
model,@PathVariable("category")Stringcategory){
List<Product>products
=productService.getProductsByCategory(category);
if(products==null||products.isEmpty()){
thrownewNoProductsFoundUnderCategoryException();
}
model.addAttribute("products",products);
return"products";
}
3. Nowrunourapplicationandenter
http://localhost:8080/webstore/products/HeadPhones.YouwillseeanHTTP
statuserrorthatsaysNoproductsfoundunderthiscategory,shownasfollows:
TheproductcategorypagethatshowsHTTPStatus404for“Noproductsfound
underthiscategory”
Whatjusthappened?
Instep1,wejustcreatedaruntimeexceptioncalled
NoProductsFoundUnderCategoryException