760 likes | 1.06k Views
Spring Web MVC. Ievads. Spring i r atklāta koda Java/J2EE aplikāciju ietvars Viens no interesantākiem komponentiem ir Spring Web MVC. Web aplik āciju uzdevumi. Svarīgie uzdevumi, kuri ir jāatrisina izstrādājot web aplikāciju : Stāvokļu pārvaldība (s tate management )
E N D
Ievads • Spring iratklāta koda Java/J2EE aplikāciju ietvars • Viens no interesantākiem komponentiem ir Spring Web MVC
Web aplikāciju uzdevumi • Svarīgie uzdevumi, kuri ir jāatrisina izstrādājot web aplikāciju: • Stāvokļu pārvaldība (state management) • Darba plūsma (workflow) • Validācija • Spring web ietvars ir uzprojektēts, lai palīdzet izstrādātājiem risināt šīs problēmas
Model-View-Controller Pattern • Model-View-Controller (MVC) ir arhitektūras paraugs (aprakstīts 1979. gadā, Smalltalk valodā) • Pamata mērķis: atdalīt datus (Model) no lietotāja interfeisa (View) • MVC atrisina problēmu ieviešot starpnieka komponenti - kontrolieri (Controller)
Model-View-Controller Pattern • Model - Represents enterprise data and the business rules. • View - Renders the contents of a model. Accesses enterprise data through the model and specifies how that data should be presented. • Controller - Translates interactions with the view (button clicks, menu selections) into actions to be performed by the model (activating processes, changing the state of the model).
Spring MVC • Spring MVC sastāv no vairākiem komponentiem, starp kuriem notiek sadarbība apstrādājot klienta pieprasījumu
Pieprasījuma dzīves cikls (1) • Klients sūta pieprasījumu, kurš tiek nodots DispatcherServlet komponentam • Visi pieprasījumi vienmēr tiek nodoti vienam servletam, kuru sauc par priekšējo kontrolieri (front controller)
Pieprasījuma dzīves cikls (2) • Komponents, kurš atbild par pieprasījuma apstrādi ir Controller • Lai nolemt kuram kontrolierim atdot pieprasījumu, DispatcherController izmanto HandlerMapping komponentus • HandlerMapping: URL piesaistīšana kontrolieriem
Pieprasījuma dzīves cikls (3-4) • Kad DispatcherServlet nolemj par kontroliera objektu, tad parsūta tam pieprasījumu, lai kontrolieris izpilda biznesa loģiku • Pēc darba pabeigšanas Controller atgriež ModelAndView objektu • ModelAndView satur View objektu vai skata loģisko vārdu
Pieprasījuma dzīves cikls (5) • Ja ModelAndView objekts satur skata loģisko vārdu, tad DispatcherServlet izmanto ViewResolver komponenti • ViewResolver atrod atbilstošu View objektu, lai attēlot atbildi klientam
Pieprasījuma dzīves cikls (6) • Visbeidzot, DispatcherServlet atdod pieprasījumu tam View objektam, uz kuru norāda ModelAndView • View objekts ir atbildīgs par pieprasījuma atbildes atgriešanu un parādīšanu klientam
Front Controller • At the heart of Spring MVC is DispatcherServlet, a servlet that functions as front controller • A front controller is a common web-application pattern where a single servlet delegates responsibility for a request to other components of an application to perform the actual processing
DispatcherServletconfig • Jākonfigurē web aplikācijasweb.xml failā: <servlet> <servlet-name>training</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> • Nākamais solis ir nodefinēt servlet mapping: <servlet-mapping> <servlet-name>training</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
DispatcherServletcontext • WebApplicationContext tiek ielādēts no faila: • training-servlet.xml • kurš atrodas direktorijā WEB-INF (līdzīgi web.xml failam) • Ir iespējams arī sadalīt • konfigurāciju starp • vairākiem failiem
Vienkāršas Web lapas izveidošana • Nepieciešamie soļi, lai izveidot web lapu ar Spring MVC: • Uzrakstīt kontroliera klasi, kas izpildīs biznesa loģiku • Iekonfigurēt kontrolieri DispatcherServlet konteksta konfigurācijas failā (training-servlet.xml) • Iekonfigurēt view resolver, kurš piesaistīs kontrolieri pie JSP • Uzrakstīt JSP, kas attēlos lapu klientam
Kontroliera izveidošana public class HomeController implements Controller { public ModelAndViewhandleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView("home", "message", greeting); } private String greeting; public void setGreeting(String greeting) { this.greeting = greeting; } } • Nodarbojas ar pieprasījuma apstrādāšanu • Pamata metodes signatūra ir līdzīga servleta service() metodei • Atgriež ModelAndView objektu
Kontroliera konfigurēšana • Kontrolieri ir jāieraksta DispatcherServlet konteksta konfigurācijas failā: <bean name="/home.htm" class="com.springinaction.training.mvc.HomeController"> <property name="greeting"> <value>Welcome to Spring Training!</value> </property> </bean> • The default handler mapping is BeanNameUrlHandlerMapping, which uses the base name as the URL pattern • When a request comes with a URL that ends with “/home.htm”, DispatcherServlet will dispatch the request to HomeController
View Resolver deklarēšana • View resolver darbs ir pēc skata loģiska vārda (kurš ir atgriezts ModelAndView objektā) atrast pašu skatu • Viens no variantiem ir izmantot skata vārdu kā JSP faila vārdu: <bean id="viewResolver" class="org.springframework.web. servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> “home” /WEB-INF/jsp/home.jsp
JSP izveidošana • Pēdējais kas palika – izveidot pašu JSP <html> <head><title>Spring Training, Inc.</title></head> <body> <h2>${message}</h2> </body> </html> • Failu ir jānosauc par “home.jsp” un ir jānoliek zem /WEB-INF/jsp/ direktorijas
HandlerMapping • Tipiski piesaista specifisku kontrolieri pie URL adreses parauga • Spring piedāvā četras noderīgas HandlerMapping implementācijas • BeanNameUrlHandlerMapping • SimpleUrlHandlerMapping • CommonsPathMapHandlerMapping
BeanNameUrlHandlerMapping • Piesaista URL adresi pie kontroliera, kurš ir reģistrēts konfigurācijas failā ar tādu pašu vārdu • e.g. /simple.htm maps to a bean named “/simple.htm” • Ir jāizmanto name atribūtu, jo “/” nav atļauts XML atribūtā id <bean class="org.springframework.web.servlet. handler.BeanNameUrlHandlerMapping"/> <bean name="/simple.htm" class="com.mvc.web.SimpleController"> . . . </bean>
SimpleUrlHandlerMapping • Pats vispārīgs veids kā piesaistītpieprasījuma URLus kontrolieriem • Tiek konfigurēts kāsaraksts no name/value pāriem (URL/kontrolieru vārds) <bean id="simpleUrlMapping" class="org.springframework.web .servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/listCourses.htm">listCoursesController</prop> <prop key="/register.htm">registerStudentController</prop> <prop key="/displayCourse.htm">displayCourseController</prop> </props> </property> </bean>
CommonsPathMapHandlerMapping • Considers source-level metadata placed in a controller’s source code to determine the URL mapping • Need to set up build to include the Commons Attributes compiler so that the attributes will be compiled into application code <bean id="urlMapping" class="org.springframework.web. servlet.handler.metadata.CommonsPathMapHandlerMapping"/> /** @@org.springframework.web.servlet. handler.commonsattributes.PathMap( "/displayCourse.htm") */ public class DisplayCourseController extends AbstractCommandController { … }
Multiple handler mappings • Ir iespējams deklarēt vairākus handler mappings vienā aplikācijā • Handler mapping klases implementē Spring’a Ordered interfeisu • Var uzstādīt order īpašību, lai norādīt izpildes kārtību attiecībā uz citiem handler mapping komponentiem
Multiple handler mappings <bean id="beanNameUrlMapping"class="org.springframework.web. servlet.handler.BeanNameUrlHandlerMapping"> <property name="order"><value>1</value></property> </bean> <bean id="simpleUrlMapping" class="org.springframework.web. servlet.handler.SimpleUrlHandlerMapping"> <property name="order"><value>0</value></property> <property name="mappings"> … </property> </bean>
Kontrolieri • JaDispatcherServletir Spring MVC sirds, tad kontrolieri ir smadzenes
Kontrolieru hierarhija • Spring piedāvā bagātu kontrolieru hierarhiju • Hierarhijas virsotnē atrodas Controller interfeiss • Parasti ir jāizmanto kādu no implementācijas apakšklasēm
AbstractController • Pats vienkāršākais kontrolieris public class SampleController extends AbstractController { public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception { return new ModelAndView( "hello“, “message”, "Hello World!"); } }
ModelAndViewobjekts • Iekapsulē skatu un modeļa datus, kurus skats attēlos • Modelis ir realizēts kā java.util.Map • Ērts konstruktors viena modeļa objekta gadījumam: ModelAndView( String viewName, String modelName, Object modelObject)
ModelAndViewobjekts • Ir iespējams arī pievienot modelim vairākus objektus: public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mav = new ModelAndView(“welcome"); mav.addObject("message1", “Welcome!"); mav.addObject("message2", "Nice to see you!"); return mav; }
Parametru apstrāde • Web pieprasījums bieži satur vienu vai vairākus parametrus <form action="/login" method="POST"> Login: <input id=“login" name="login"/> Password: <input id="password" name="password" type="password"/> <input type="submit" value="Login"/> </form> Kādā veidā varētu piekļūt parametriem kontroliera kodā???
Risinājums • Varētu izmantot AbstractControllerun nolasīt parametrus no HttpServletRequest public ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response) throws Exception { String login = request.getParameter("login"); String pass = request.getParameter("password"); . . . } Spring piedāvā ērtāku iespēju!
AbstractCommandController • Automātiski ieraksta parametrus speciālajā komandas objektā (command object) • Ir iespēja pievienot validatoru, lai nodrošināt to, ka parametri ir pareizi • Galvenā izpildes metode: handle( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
AbstractCommandController public class DisplayCourseController extends AbstractCommandController { public DisplayCourseController() { setCommandClass(DisplayCourseCommand.class); } protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { DisplayCourseCommand displayCommand = (DisplayCourseCommand) command; Course course = courseService.getCourse(displayCommand.getId()); return new ModelAndView("courseDetail", "course", course); }
Command Object • A command object is a bean that is meant to hold request parameters for easyaccess public class DisplayCourseCommand { private Integer id; public void setId(Integer id) { this.id = id; } public Integer getId() { return id; } } • Spring will attempt to match any parameters passed in the request to properties in the command object
Formu apstrāde • Tipiska web aplikācija satur vismaz vienu formu • Lietotājs aizpilda formu un aizsūta to • Dati tiek nosūtīti serverim • Kad datu apstrāde ir pabeigta, tad lietotājs saņem vienu no variantiem: • Lapa ar veiksmīgas izpildes paziņojumu • Formas lapa ar kļūdu paziņojumiem Kādā veidā varētu to realizēt???
Risinājums • IzmantotAbstractControllerformas attēlošanai • Izmantot AbstractCommandControllerformas apstrādei • Trūkums: vajag uzturēt divus dažādus kontrolierus, kuri kopā nodarbojas ar viena uzdevuma risināšanu
SimpleFormController • Formu kontroliera funkcionalitāte: • Attēlo formu uz HTTP GET pieprasījuma • Apstrādā formu uz HTTP POST pieprasījuma • Ja notiek kļūda, tad atkārtoti parāda formu public class RegisterStudentController extends SimpleFormController { public RegisterStudentController() { setCommandClass(Student.class); } protected voiddoSubmitAction(Object command) throws Exception { Student student = (Student) command; studentService.enrollStudent(student); } }
SimpleFormControllerconfig • Kontrolieris ir uzprojektēts tādā veidā, lai pēc iespējas vairāk atdalīt skatu detaļas no kontroliera koda <bean id="registerStudentController" class="com.springinaction. training.mvc.RegisterStudentController"> <property name="formView"> <value>newStudentForm</value> </property> <property name="successView"> <value>studentWelcome</value> </property> . . . </bean> HTTP GET • Ja ir nepieciešams aizsūtīt datus skatam, tad vajag izmantot onSubmit() metodi
Formu validācija • Viens no svarīgiem uzdevumiem ir formas datu validācija • Par validāciju atbild sekojošais interfeiss public interface Validator { void validate(Object obj, Errors errors); boolean supports(Class clazz); } • Implementējot šī interfeisa validate() metodi vajag pārbaudīt objekta atribūtu vērtības un noraidīt nepareizas vērtības izmantojot Errors objektu
Validatora reģistrēšana • Validatoru vajag piesaistīt kontrolierim konfigurācijas failā <bean id="registerStudentController" class="com.springinaction.training.mvc. RegisterStudentController"> … <property name="validator"> <bean class="com.springinaction.training. mvc.StudentValidator"/> </property> </bean>
Wizard (daudzekrānu) formas • Uzdevums – realizēt aptaujas formu ar 40 jautājumiem Kādā veidā varētu to realizēt??? • Variants – izmantot SimpleFormController, izvietot visus jautājumus vienā lapā • Bet tas nav ērti lietotājam!
Wizard formas • Spring piedāvā kontrolieri, kas atbild par secīgu virzīšanos cauri vairākām lapām AbstractWizardFormController • Līdzīgs parastai formai, bet ir iespējams validēt datus pa daļām (katrā ekrānā savu daļu) • Formas apstrāde parasti notek pašās beigās • Ir iespēja visu procesu atcelt (cancel) jebkurā brīdī
Wizard formas kontrolieris public class FeedbackWizardController extends AbstractWizardFormController { public FeedbackWizardController() { setCommandClass(FeedbackSurvey.class); } protected ModelAndView processFinish( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception { FeedbackSurvey feedback = (FeedbackSurvey) command; feedbackService.submitFeedback(feedback); return new ModelAndView("thankyou"); }
Wizard formas konfigurēšana • Formas kontroliera konfigurēšana <bean id="feedbackController" class="com.springinaction. training.mvc.MyWizardController"> <property name="pages"> <list> <value>general</value> <value>instructor</value> <value>course</value> </list> </property> </bean> • Šeit tiek definētas visas lapas
Wizard formas lapas • Pa lapām var pārvietoties ierakstot pieprasījumā parametru ar vārdu "_targetX", kur X ir lapas numurs <form method="POST" action="feedback.htm"> … <input type="submit" value="Back" name="_target1"> <input type="submit" value="Next" name="_target3"> </form>
Wizard formas finish/cancel • Formas pabeigšana - tiks izsaukta metode processFinish() <input type="submit" value="Finish" name="_finish"> • Formas atcelšana - tiks izsaukta metode processCancel() <input type="submit" value="Cancel" name="_cancel">