首页 > 代码库 > springMVC-入门

springMVC-入门

springMVC(替代struts)(就是通过配置servlet,使普通的类通过注释被扫描变成控制器)的基本使用方法

    1.加入对应的jar包
        commons-logging-1.2.jar
        spring-aop-4.0.0.RELEASE.jar
        spring-beans-4.0.0.RELEASE.jar
        spring-context-4.0.0.RELEASE.jar
        spring-core-4.0.0.RELEASE.jar
        spring-expression-4.0.0.RELEASE.jar
        spring-web-4.0.0.RELEASE.jar
        spring-webmvc-4.0.0.RELEASE.jar
        
    2.在web.xml中直接alt+/,选择#dispatcherservlet
        <servlet>
            <servlet-name>springDispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 
                <init-param>也可以不配置,那么将使用默认的路径,为/WEB-INF/<servlet-name>-servlet.xml
             -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <!-- spring配置文件的位置 -->
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
            <!-- 代表在web应用初始化时创建servlet -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springDispatcherServlet</servlet-name>
            <!-- 
                开头的/代表web应用的根目录
                该servlet处理的请求
                会使用servletPath,即/nihao来匹配
                
                /*和/都是匹配所有请求,
                    > /是缺省匹配,优先级最低,也是默认的匹配项
                    > /*是路径匹配,优先级高于扩展名匹配仅次于精准匹配,会覆盖掉优先级低的匹配
                        若使用/*会覆盖默认的缺省匹配,那么在刚开始请求index.jsp页面时就匹配了,但找不到对应的响应所以会报404
             -->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
        
    3.可以看出springMVC是使用了servlet,这是与struts的区别
    
    4.在spring配置文件中
            <context:component-scan base-package="handlers"></context:component-scan>
    
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <!-- 
                    prefix的value中开头的/代表web应用根目录。
                    若写了开头的/
                        >那么响应的页面会是正常的/springMVC-helloworld/WEB-INF/view/success.jsp
                    若不写开头的/
                        >@RequestMapping("/QQ")加在类前了,那么响应的页面是/springMVC-helloworld/QQ/WEB-INF/view/success.jsp
                        >@RequestMapping("/QQ")没有加在类前,那么还是正常的/springMVC-helloworld/WEB-INF/view/success.jsp
                 -->
                <property name="prefix" value="http://www.mamicode.com/WEB-INF/view/"></property>
                <property name="suffix" value="http://www.mamicode.com/.jsp"></property>
            </bean>
            
    5.编写控制类handler(就是普通的类,通过注释成为了控制器,类似与Action类)
        @RequestMapping("/QQ")
        @Controller
        public class myHandler {
            /**
             * @RequestMapping 中value代表会响应的contextPath
             * 根据spring中的配置,会到prefix+returnValue+suffix。即WEB-INF/view/success.jsp
             * 
             * 
             * nihao和/nihao其实是一样的,响应是随机选一个,但在初始化时就确定响应哪一个方法了
             * 
             * @RequestMapping("/QQ") 若写在类上面,则请求映射信息变为/QQ/nihao
             * */
        //    @RequestMapping(value="http://www.mamicode.com/nihao")
        //    public String hello2(){
        //        System.out.println("To Success2");
        //        return "success2";
        //    }
            @RequestMapping(value="http://www.mamicode.com/nihao")
            public String hello(){
                System.out.println("To Success");
                return "success";
            }
        }
1.@RequestMapping(value="http://www.mamicode.com/nihao"),其中的value支持ant风格匹配
    Ant风格 资源地址支持 源地址支持 3?匹文件名中一个字
    *匹文件名中任意字
    **匹多层路径
    /user/*/createUser: 匹配/user/aaa/createUser、/user/bbb/createUser  URL
    /user/**/createUser: 匹配/user/createUser、/user/aaa/bbb/createUser  URL
    /user/createUser??: 匹配/user/createUseraa、/user/createUserbb  URL

2.@PathVariable注解:用于得到URL中的值信息。
    在请求映射中添加占位符,在方法形参前加@PathVariable(value="id")注解就可以得到id
        @RequestMapping("/**/testVariable/{id}")
        public String testPathVariable(@PathVariable(value="http://www.mamicode.com/id") int id){}
        
3.REST风格:表现层状态转化
    REST风格的增删改查,分别对应POST,DELETE,PUT,GET请求
    
4.如何使用PUT,DELETE请求
    1.先在web.xml中配置HiddenHttpMethodFilter拦截器
    2.必须是POST请求
    3.且携带参数_method,它的值就是发出请求的方式
    例:
        <form action="QQ/order/1" method="post">
            <input type="hidden" name="_method" value="http://www.mamicode.com/put">
            <input type="submit" value="http://www.mamicode.com/更新">
        </form>
        <form action="QQ/order/1" method="post">
            <input type="hidden" name="_method" value="http://www.mamicode.com/delete">
            <input type="submit" value="http://www.mamicode.com/删除">
        </form>

5.@RequestParam注解(放在形参之前):获取请求的参数,放入形参中
    @RequestParam(value="username",required=true,defaultValue="http://www.mamicode.com/ji")
    value="username":请求参数的名字
    required=true:是否必须携带该请求参数
    defaultValue="ji":(一旦设置了defaultValue,required就失效了)当请求不带有该参数时就将其设置为ji
                        注意:testRequestParam和testRequestParam?username不一样
                            前者username为ji,是为不带;后者username为"",是为带了
                            testRequestParam?username&age : username为""。age为null,所以age不能为int而是Integer

6.@CookieValue,@RequestHeader和@RequestParam使用方法相同

7.Pojo作为参数
    可以直接将请求的参数封装到方法的形参对象中,而且在表单上可以写级联属性,不需要配置什么
    该形参是自定义的普通的java类(Pojo),其中的属性名和表单上<input>的name属性相同

8.Servlet原生的API作为参数
    可以直接在方法的形参中写Servlet原生的类对象在方法中使用
    支持写ServletRequest,ServletResponse,HttpSession,Principal,Locale,
    InputStream,Reader,OutputStream,Writer。
    原理如下:
            if (ServletRequest.class.isAssignableFrom(parameterType) ||
                    MultipartRequest.class.isAssignableFrom(parameterType)) {
                Object nativeRequest = webRequest.getNativeRequest(parameterType);
                if (nativeRequest == null) {
                    throw new IllegalStateException(
                            "Current request is not of type [" + parameterType.getName() + "]: " + request);
                }
                return nativeRequest;
            }
            else if (ServletResponse.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                Object nativeResponse = webRequest.getNativeResponse(parameterType);
                if (nativeResponse == null) {
                    throw new IllegalStateException(
                            "Current response is not of type [" + parameterType.getName() + "]: " + response);
                }
                return nativeResponse;
            }
            else if (HttpSession.class.isAssignableFrom(parameterType)) {
                return request.getSession();
            }
            else if (Principal.class.isAssignableFrom(parameterType)) {
                return request.getUserPrincipal();
            }
            else if (Locale.class.equals(parameterType)) {
                return RequestContextUtils.getLocale(request);
            }
            else if (InputStream.class.isAssignableFrom(parameterType)) {
                return request.getInputStream();
            }
            else if (Reader.class.isAssignableFrom(parameterType)) {
                return request.getReader();
            }
            else if (OutputStream.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getOutputStream();
            }
            else if (Writer.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getWriter();
            }

9.ModelAndView的使用(是一种向域对象中添加属性的方式)
    实际上,目标方法返回的字符串最终是被封装成了一个ModelAndView对象。也可以直接返回一个ModelAndView对象。
    原来返回的字符串被封装在modelAndView作为view的部分存在;addObject添加的对象作为model部分存在。
    model部分在页面上作为request的属性存在。
        @RequestMapping("/testModelAndView")
        public ModelAndView testModelAndView(){
            String viewName = "success";
            ModelAndView modelAndView = new ModelAndView(viewName);
            modelAndView.addObject("time", new Date());//此处添加的对象在requestScope的域中
            return modelAndView;
        }
        
10.使用Map,ModelMap,Model作为目标方法的形参
    则这些形参中添加的对象 在页面上作为request的属性存在。
        @RequestMapping("/testMap")
        public String testMap(Map<String,Object> names,ModelMap time,Model add,HttpServletRequest request){
            names.put("names", Arrays.asList("Ji","Yun","Fei"));
            time.put("time", new Date());
            add.addAttribute("add", new Address("HeNan", "JiaoZuo"));
            request.setAttribute("age", 12);
            return "success";
        }        
    <!-- 
        href中的开头的/代表站点的根目录。不写则代表当前文件所在目录
        所以此强求为http://localhost:8080/springMVC-helloworld/QQ/nihao
     -->
    <a href="QQ/nihao">To Success</a>
    <!-- 以下这种方式若什么都不输入就提交和 QQ/testRequestParam?username&age GET请求相同 -->
    <form action="QQ/testRequestParam" method="post">
        <input type="hidden" name="_method" value="get">
        <input type="text" name="username">
        <input type="text" name="age">
        <input type="submit" value="TestReuqestParam">
    </form>

Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 
            <init-param>也可以不配置,那么将使用默认的路径,为/WEB-INF/<servlet-name>-servlet.xml
         -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- spring配置文件的位置 -->
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- 代表在web应用初始化时创建servlet -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <!-- 
            开头的/代表web应用的根目录
            该servlet处理的请求
            会使用servletPath,即/nihao来匹配
            
            /*和/都是匹配所有请求,
                > /是缺省匹配,优先级最低,也是默认的匹配项
                > /*是路径匹配,优先级高于扩展名匹配仅次于精准匹配,会覆盖掉优先级低的匹配
                    若使用/*会覆盖默认的缺省匹配,那么在刚开始请求index.jsp页面时就匹配了,但找不到对应的响应所以会报404
         -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <filter>
        <filter-name>MethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
</web-app>

spring配置文件

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

    
    <context:component-scan base-package="handlers"></context:component-scan>
    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 
            prefix的value中开头的/代表web应用根目录。
            若写了开头的/
                >那么响应的页面会是正常的/springMVC-helloworld/WEB-INF/view/success.jsp
            若不写开头的/
                >@RequestMapping("/QQ")加在类前了,那么响应的页面是/springMVC-helloworld/QQ/WEB-INF/view/success.jsp
                >@RequestMapping("/QQ")没有加在类前,那么还是正常的/springMVC-helloworld/WEB-INF/view/success.jsp
         -->
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    
</beans>

控制器MyHandler.java

package handlers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@RequestMapping("/QQ")
@Controller
public class MyHandler {
    /**
     * @RequestMapping 中value代表会响应的contextPath
     * 根据spring中的配置,会到prefix+returnValue+suffix。即WEB-INF/view/success.jsp
     * 
     * 
     * nihao和/nihao其实是一样的,响应是随机选一个,但在初始化时就确定响应哪一个方法了
     * 
     * @RequestMapping("/QQ") 若写在类上面,则请求映射信息变为/QQ/nihao
     * */
//    @RequestMapping(value="http://www.mamicode.com/nihao")
//    public String hello2(){
//        System.out.println("To Success2");
//        return "success2";
//    }
    @RequestMapping(value="http://www.mamicode.com/nihao")
    public String hello(){
        System.out.println("To Success");
        return "success";
    }
    /**
     * 此外RequestMapping注释还可以使请求更加精准,例如
     * 
     * method=RequestMethod.POST,只映射post方式的testRequestMapping请求
     * 
     * params={"username=ji","age!=10","!password"}:只映射参数符合条件的请求.
     *         有username且=ji,有age且!=10",没有password
     * 
     * headers={""},对请求的头的要求,书写方式和params方式类似
     * */
    @RequestMapping(value="/testRequestMapping",method=RequestMethod.POST,
            params={"username=ji","age!=10","!password"})
    public String testRequestMapping(){
        System.out.println("To Success");
        return "success";
    }
    
    @RequestMapping("/**/testVariable/{id}")
    public String testPathVariable(@PathVariable(value="http://www.mamicode.com/id") int id){
        System.out.println("PathVariable"+id);
        return "success";
    }
    
    @RequestMapping(value="/**/order/{id}",method=RequestMethod.GET)
    public String testMethodFilterGET(@PathVariable(value="http://www.mamicode.com/id") int id){
        System.out.println("GET"+id);
        return "success";
    }
    @RequestMapping(value="/**/order",method=RequestMethod.POST)
    public String testMethodFilterPOST(){
        System.out.println("POST");
        return "success";
    }
    @RequestMapping(value="/**/order/{id}",method=RequestMethod.PUT)
    public String testMethodFilterPUT(@PathVariable(value="http://www.mamicode.com/id") int id){
        System.out.println("PUT"+id);
        return "success";
    }
    @RequestMapping(value="/**/order/{id}",method=RequestMethod.DELETE)
    public String testMethodFilterDELETE(@PathVariable(value="http://www.mamicode.com/id") int id){
        System.out.println("DELETE"+id);
        return "success";
    }
    
    @RequestMapping(value="/testRequestParam",method=RequestMethod.GET)
    public String testRequestParam(@RequestParam(value="http://www.mamicode.com/username",required=true,defaultValue="http://www.mamicode.com/ji") String username,
            @RequestParam(value="age",required=false,defaultValue="http://www.mamicode.com/0") Integer age){
        System.out.println(username+":"+age);
        return "success";
    }
}

控制器2MyHandler.java

package handlers;

import java.util.Arrays;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import model.Address;
import model.User;

@Controller
public class MyHandler2 {
    
    @RequestMapping("/testMap")
    public String testMap(Map<String,Object> names,ModelMap time,Model add,HttpServletRequest request){
        names.put("names", Arrays.asList("Ji","Yun","Fei"));
        time.put("time", new Date());
        add.addAttribute("add", new Address("HeNan", "JiaoZuo"));
        request.setAttribute("age", 12);
        return "success";
    }
    
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        String viewName = "success";
        ModelAndView modelAndView = new ModelAndView(viewName);
        modelAndView.addObject("time", new Date());//此处添加的对象在requestScope的域中
        return modelAndView;
    }
    
    @RequestMapping("testCookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID")String jsessionid){
        System.out.println(jsessionid);
        return "success";
    }
    
    /**
     * 可以直接将请求的参数封装到方法的形参对象中,而且在表单上可以写级联属性,不需要配置什么
     * 该形参是自定义的普通的java类(Pojo),其中的属性名和表单上<input>的name属性相同
     * */
    @RequestMapping("testPojo")
    public String testPojo(User user,HttpServletRequest req){
        System.out.println(user);
        System.out.println(req);
        return "success";
    }
    
}

 

springMVC-入门