sábado, 31 de agosto de 2013

Spring MVC

 - Spring MVC  

     - Flow of a requiest in Spring MVC
         - Request to DispacherServlet(the front controller)
             - HandlerMapping
             - Model and logical view name
                 - Controller (return to DispacherServlet)
             - ViewResolver
             - View
     - Setting up Spring MVC
         - Configure the web.xml
             The Servlet
             <servlet>
                 <servlet-name>spitter</servlet-name>
                 <servlet-class>
                     org.springframework.web.servlet.DispatcherServlet
                 </servlet-class>
                 <load-on-startup>1</load-on-startup>
             </servlet>
             The Mapping
             <servlet-mapping>
                 <servlet-name>spitter</servlet-name>
                 <url-pattern>/</url-pattern> Will handle all request including request from static content.
             </servlet-mapping>
         - Configure the Spring Configuration (ex: project-servelt.xml)
             <?xml version="1.0"encoding="UTF-8"?>
             <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:mvc="http://www.springframework.org/schema/mvc"
                 xsi:schemaLocation="http://www.springframework.org/schema/mvc
                 http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
                 http://www.springframework.org/schema/beans
                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
                 <mvc:resourcesmapping="/resources/**" location="/resources/"/> Handle request for static resources
             </beans>
     - Writing Controller
         - Handler Mapping - DispatcherServlet decide which controller to dispach a request to.
             BeanNameUrlHandlerMapping
                 Maps controlers to URL that are based on the controller's BEAN name
             ControllerBeanNameHandlerMapping
                 Similar than above. Names don't requires to follow URL conventions
             ControllerClassNameHandlerMapping
                 Maps controlers to URL that are based on the controller's CLASS name as the basis of URL
             DefaultAnnotationHandlerMapping
                 Maps request to controller and controller methods that are annotated with @RequestMapping
             SimpleUrlHandlerMapping
                 Maps controllers to URL using a property collection defined in the Spring application context.
             If no handler mapping is found, uses BeanNameUrlHandlerMapping and DefaultAnnotationHandlerMapping
         - To use DefaultAnnotationHandlerMapping, include in app-servlet.xml:
             <mvc:annotation-driven/>  It includes:
                 validation support
                 message conversion
                 field formating
         Controller Example
             @Controller                <---- Declare the Controller
             public class HomeController{
                 public static final int DEFAULT_SPITTLES_PER_PAGE=25;
                 private SpitterService spitterService;
                 @Inject                        <---- Inject the bean of service
                 public HomeController(SpitterService spitterService){
                     this.spitterService=spitterService;
                 }
                 @RequestMapping({"/","/home"})    <------ Handle request for home page
                 public String showHomePage(Map<String,Object> model){ <---- Model is just a Map
                     List<Spitter> list = spitterService.getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE);
                     model.put("spittles", list); <------- Data into model
                     return"home";            <---- Return view name
                 }
             }
             - To recognise the @Controller <context:component-scanbase-package="com.habuma.spitter.mvc"/> should be included in app-servlet.xml
         - Testing the controller
             public classHomeControllerTest{
             @Test
             public void shouldDisplayRecentSpittles(){
                 List<Spittle>expectedSpittles =    asList(newSpittle(),newSpittle(),newSpittle());
                 SpitterService spitterService= mock(SpitterService.class);
                 when(spitterService.getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE)).thenReturn(expectedSpittles);
                 HomeControllercontroller= new HomeController(spitterService);
                 HashMap<String,Object> model=new HashMap<String,Object>();
                 String viewName=controller.showHomePage(model);
                 assertEquals("home",viewName);
                 assertSame(expectedSpittles,model.get("spittles"));
                 verify(spitterService).getRecentSpittles(DEFAULT_SPITTLES_PER_PAGE);
             }
         - Resolving Internal views
             Relating to rendering output to the user.
             Can use JSP, Velocity, FreeMarker.
             There are many View resolver implementations
                 BeanNameViewResolver, ContentNegotiatingViewResolver, FreeMarkerViewResolver, InternalResourceViewResolver, JasperReportsViewResolver, ResourceBundleViewResolver, TilesViewResolver, UrlBasedViewResolver, VelocityLayoutViewResolver, VelocityViewResolver, XmlViewResolver
             - InternalResolverViewResolver.
                 Convention-over-configuration approach
                 In app-servlet.xml
                     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                         *****
                         <propertyname="prefix"value="/WEB-INF/views/"/>
                         <propertyname="suffix"value=".jsp"/>
                     </bean>
                     Configure that al JSP will be inside /WEB-INF/views folder and will have .jsp as sufix.
                 DispatchServlet ask InternalResourceViewResolver to resolv a view.
                 InternalResourceViewResolver creates a InternalResourceView(the View) which dispatches the request to the JSP for rendering.
                 If the jsp users JSTL, we should replace InternalResourceView with JstlView by setting the viewClass property inside the block above
                     ***** <propertyname="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
                     It exposes JSTL-specific request attributes so that we can use the internationalization
         - Resolving tiles view
             Templating framework for laying out of a piece of pages as fragments to make on e page.
             Register TilesViewResourver in app-servlet.xml
                 <bean class="org.springframework.web.servlet.view.tiles2.TilesViewResolver"/>
             View resolver attempts to find views that are Tiles templates.
             Also add TilesConfigurer in app-servlet.xml
             <bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
                 <property name="definitions">
                     <list>
                         <value>/WEB-INF/views.xml</value>   <---- Where tiles are configured
                     </list>
                 </property>
             </bean>
             <tiles-definitions>
                 <definition name="template" template="/WEB-INF/views/main_template.jsp">
                     <put-attributename="top" value="/WEB-INF/views/tiles/spittleForm.jsp"/>
                     <put-attributename="side" value="/WEB-INF/views/tiles/signinsignup.jsp"/>
                 </definition>
                 <definition name="home" extends="template">
                     <put-attributename="content"value="/WEB-INF/views/home.jsp"/>
                 </definition>
             </tiles-definitions>
         - Defining a page
             <%@ taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%>
             <%@ taglibprefix="s"uri="http://www.springframework.org/tags"%>
             <%@ taglibprefix="t"uri="http://tiles.apache.org/tags-tiles"%>
             <%@ taglibprefix="fmt"uri="http://java.sun.com/jsp/jstl/fmt"%>
             <div>
                 <c:forEach var="spittle"items="${spittles}">
                     <s:urlvalue="/spitters/{spitterName}" var="spitter_url">
                         <s:param name="spitterName"    value="${spittle.spitter.username}"/>
                     </s:url>
                 </c:forEach>
             </div>
     - Handling controller input
         How to deal with a set of parameters.
         To link: http://localhost:8080/spitter/spittles?spitter=habuma
         @Controller
         @RequestMapping("/spitter")            <--- Root URL path
         public class SpitterController{
             private final SpitterService spitterService;
             @Inject
             public SpitterController(SpitterService spitterService){
                 this.spitterService=spitterService;
             }
             @RequestMapping(value="/spittles",method=GET)        <--- Handle Get Requests for /spitterSpittlers
             public String listSpittlesForSpitter(    @RequestParam("spitter") String username, Model model){ <--- The request param
                 Spitterspitter=spitterService.getSpitter(username);
                 model.addAttribute(spitter);                <---- Fill model
                 model.addAttribute(spitterService.getSpittlesForSpitter(username));
                 return "spittles/list";
             }
         }
         - Model model is just likely a Map<String,Object> with some methods: addAttribute(similar to Map.put)
     - Processing Form
         Two operations:
             Display the form
             Process the form submition
         Displaying the form
         First call the controlller
             @RequestMapping(method=RequestMethod.GET,params="new") <--- only handle this GET if pass the param new.
             public String createSpitterProfile(Model model){
                 model.addAttribute(new Spitter());  <---- Create a empty object
                 return "spitters/edit";             <---- Forward to a page
             }
         ex of call:
             http://localhost:8080/Spitter/spitters?new
         - Defining the form view
             Tiles template
                 <definitionname="spitters/edit"extends="template">
                     <put-attributename="content" value="/WEB-INF/views/spitters/edit.jsp"/>
                 </definition>
             - Write the jsp
         - Processing the Form - How to handle the form
             @RequestMapping(method=RequestMethod.POST)
             public String addSpitterFromForm(@ValidSpitter spitter, BindingResult bindingResult){
                 if(bindingResult.hasErrors()){            <--- Check validation
                     return"spitters/edit";
                 }
                 spitterService.saveSpitter(spitter);  <---- Call the service to save object
                 return "redirect:/spitters/"+spitter.getUsername(); <--- Redirect to a specific page
             }
         - Handling requests with path variable
             - http://localhost:8080/Spitter//spitters/{username}
             @RequestMapping(value="/{username}",method=RequestMethod.GET)  <------ value indicates how the link should be called
             public String showSpitterProfile(@PathVariable String username, Model model){  <---- username again indicating the path{username}
                 model.addAttribute(spitterService.getSpitter(username));
                 return "spitters/view";
             }
         - Validating Input
             Use @Valid annotation
         - Show errors in JSP
             <%@ taglibprefix="sf"uri="http://www.springframework.org/tags/form"%>
             <sf:errors path="fullName"cssClass="error"/>
         <%@ taglibprefix="sf"uri="http://www.springframework.org/tags/form"%>
             <sf:form method="POST"modelAttribute="spitter" enctype="multipart/form-data">
                 <fieldset>
                     <th><sf:label path="fullName">Fullname:</sf:label></th>
                     <td><sf:input path="fullName"size="15"/><br/>
                     <sf:errors path="fullName"cssClass="error"/>
                     <th><sf:label path="username">Username:</sf:label></th>
                     <td><sf:input path="username"size="15"maxlength="15"/>
                     <small id="username_msg">Nospaces,please.</small><br/>
                     <sf:errors path="username"cssClass="error"/>
                 </fieldset>
             </sf:form>
     Upload File
         <sf:form method="POST" modelAttribute="spitter" enctype="multipart/form-data">
         multipart/form-data makes each field be submitted as a distinct part of the POST
         <tr>
             <th><labelfor="image">Profileimage:</label></th>
             <td><inputname="image"type="file"/>
         </tr>
         Receiving the file
             @RequestMapping(method=RequestMethod.POST)
             public String addSpitterFromForm(@Valid Spitter spitter, Binding Result bindingResult,
                                             @RequestParam(value="image",required=false)    MultipartFile image){
                 if(bindingResult.hasErrors()){
                     return"spitters/edit";
                 }
                 spitterService.saveSpitter(spitter);
                 try {
                     if(!image.isEmpty()){
                         validateImage(image);
                         saveImage(spitter.getId()+".jpg",image);//
                     }
                 } catch(ImageUploadExceptione){
                     bindingResult.reject(e.getMessage());
                     return"spitters/edit";
                 }
                 return "redirect:/spitters/"+spitter.getUsername();
             }
             private void validateImage(MultipartFile image){
                 if(!image.getContentType().equals("image/jpeg")){ <--- To guarantee that the file is a jpeg
                 thrownew ImageUploadException("OnlyJPGimagesaccepted");
                 }
             }
         To upload file, spring should be configured
             <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
                 p:maxUploadSize="500000"/>
             DispatcherServlet will look for multipartResolver id. DispatcherServlet doesn't know how to deal with multipart form data.
 - Spring MVC + Jquery + AJAX
     - Maven
         jackson <--- Responsible for marshall to JSON
     - in dispatcher-servlet.xml
         <context:component-scan base-package "br.com.packageRoma"/>  <---- Defines which package to look for annotations
         <mvc:annotation-driven>                <--- Shows Spring to use annotation
     - Controller
         public class TestController {
             @RequestMapping(value="/action.htm",method=RequestMethod.POST)
             public @ResponseBody Test method(HttpServletRequest request, HttpServletResponse response) throws Exception
             {
                 Test test = new Test()
                 return test;        <---- Jackson do the marshall to JSON
             }
         }
         or
         public @ResponseBody User addUser(@ModelAttribute(value="user") User user, BindingResult result ){
             String text;
             if(!result.hasErrors()){
                 userList.add(user);
                 text = "User inserted";
             }else{    
                 text = "Couldn't insert user";
             }
             return user;
         }
     - The jsp
         <script type="text/javascript" language="javascript" src="URL/jquery"></script>
         <script type="text/javascript">
             function testCallAjax(){
                 $.ajax({
                     type: "post",
                     url: "http://localhost:8080/TestSpring/test/test.htm",
                     cache: false,                
                     data:'firstName=' + $("#firstName").val() + "&lastName=" + $("#lastName").val() + "&email=" + $("#email").val(),
                     success: function(response){
                         $('#result').html(""); <--- Clean the div that will be renderized
                         var obj = JSON.parse(response);
                         $('#result').html("First Name:- " + obj.firstName +"</br>Last Name:- " + obj.lastName);
                     },
                     error: function(){                        
                         alert('Error while request..');
                     }
                 });
             }
         </script>
         ....
         <form name="testForm" method="post">    
             <table>
                 <tr><td><input type="text" name="firstName" id="firstName" value=""></td></tr>
                 <tr><td><input type="text" name="lastName" id="lastName" value=""></td></tr>
                 <tr><td ><input type="button" value="Ajax Submit" onclick="testCallAjax();"></td></tr>
             </table>
         </form>
         <div id="result"></div> <----- div that will be renderized.
 - Spring Web Flow
     Framework that enables development of elements following a prescribed flow.
     It separes the definition of an applications's flow from the classes and views that implement the flow's behavior.
     - Install (maven)
         <dependency>
             <groupId>org.springframework.webflow</groupId>
             <artifactId>spring-webflow</artifactId>
             <version>2.3.2.RELEASE</version>
         </dependency>

Nenhum comentário:

Postar um comentário