Spring4MVC(一)参数封装和请求映射

1、SpringMVC简介

       SpringMVC是web前端最主流的MVC框架之一;SpringMVC3.0后全面超越struts2,成为最优秀的MVC框架。SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,而无需实现任何接口。SpringMVC支持REST风格的URL请求;采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。

2、SpringMVC入门程序HelloWorld

步骤:

1、创建普通的动态web工程;

2、导入jar包

3、web.xml文件配置DispatcherServlet

4、创建springmvc.xml配置文件,配置包扫描和视图解析器

5、创建控制器类,类上添加注解@Controller

6、创建处理器方法,方法上添加@RequestMapping,指定请求的路径

7、页面上面创建<a>标签,配置href的值未@RequestMapping配置的值。

2.1 IDEA创建动态web(普通web工程,非maven)工程

1、File——》new——》project——》Java Enterprise——》Web Application;

2、点击下一步,选择项目存放位置,定义好项目名,一直finish即可。

3、在WEB-INF下面,创建classes和lib文件夹,名字不可改

4、在File中找到Project Structure,点击Modules ,选择Paths,选中Use module compile output path,把路径改成刚刚创建的classes文件夹;

apply后再点旁边的Dependencies,点击"+"号,选择1 JARs or directories ,选择你刚刚创建的lib文件夹,OK——》选中jar Directory。

5、回到主界面后,点击Run ,选择Edit Configurations,看tomcat已经有啦,这是java Enterprise的好处啦,点击Deployment

6、点击下面的图标就可以运行了

然后自动就会在浏览器上面打开首页,看到效果了。

2.2 加入jar到刚才创建的lib中

添加jar包到lib之后,要执行下面的操作:

2.2 修改web.xml,添加DispatcherServlet配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置 DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置 DispatcherServlet 的一个初始化参数: 配置 SpringMVC 配置文件的位置和名称 -->
        <!--
            实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.
            默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml
        -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--在web服务器启动的时候就加载这个servlet,否则会在第一次请求的时候再加载,效率慢-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--拦截路径,拦截所有路径-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

2.3 创建配置文件springmvc.xml

在类路径下,创建springmvc.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: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">

    <!-- 配置扫描的包 -->
    <context:component-scan base-package="com.springmvc"></context:component-scan>

    <!-- 配置视图解析器: 如何把 handler 方法返回值解析为实际的物理视图 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

2.4 创建包,创建类HelloWorld

package com.springmvc;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloWorld {

    @RequestMapping("helloworld")
    public String hello(){
        System.out.println("Hello World...");
        return "success";
    }
}

注意:类上添加了@Controller注解,方法hello上面添加了@RequestMapping注解,并且配置了请求路径:helloworld。

2.5 修改首页index.jsp,创建success.jsp页面

index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>首页</title>
  </head>
  <body>
  <a href="helloworld">点击跳转到success页面</a>
  </body>
</html>

在WEB-INF下面创建jsp目录,然后创建success.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>成功页面</title>
  </head>
  <body>
  success page
  </body>
</html>

2.6 启动,访问,点击查看效果

3、请求映射和参数封装

3.1 @RequestMapping注解

       该注解可以使用到类上和方法上,DispatcherServlet拦截请求之后,就会通过控制器的@RequestMapping提供的信息确定请求的处理方法。如果类上定义了该注解,那么类中所有的方法的请求路径上都要加上类上的路径:比如类上配置了@RequestMapping("demo"),处理器方法上配置了@RequestMapping("/hello")(这个 hello 前面的 斜杠/ 可有可无),那么请求路径就是:demo/hello。

       我们上面配置的是@RequestMapping注解的value属性,其实他还有其他几个属性:method、params,headers。

       method可以指定该方法接受的请求方式,比如GET和POST,如果指定了method属性,那么在前台页面就只能使用对应的请求方式了。但是如果没有指定method,那么GET和POST请求都是可以的。method的属性值在枚举类RequestMethod中定义。

       paramsheaders指定了前端必须要传的参数和请求头,可以更加精确的确定请求;

       params的例子:params = {"username","age!=100"}表示前台一定要包含参数username和age,但是age不能等于100,否则请求失败(404)。

      headers的例子:headers = {"Accept-Language=zh-CN,zh;q=0.9"},表示请求头中一定要包含Content-Language并且值只能是zh-CN。

       @RequestMapping的请求路径还支持Ant风格的URL,Ant风格的地址支持下面三种匹配符::匹配文件名中的一个字符;*:匹配文件名中的任意字符;**:匹配多层路径。

3.2 @PathVariable注解

       @PathVariable用来绑定URL中的占位符。带占位符的URL是Spring3.0新增的功能,通过注解@PathVariable可以将URL中的占位符绑定到处理器方法的参数中,但是URL路径中占位符的值一定要和@PathVariable的value属性名称是一样的,例如:

@RequestMapping(value = "testPathVariable/{name}")
    public String testMethod(@PathVariable("name") String myName){
        System.out.println("我是。。。。"+myName);
        return SUCCESS;
    }

两个都是name,这样的话String myName的名称可以随便取。

3.3 SpringMVC如何支持PUT和DELETE请求

       浏览器form表单只支持GET和POST请求,而PUT和DELETE请求并不支持。Spring3.0添加了一个过滤器(org.springframework.web.filter.HiddenHttpMethodFilter),可以将这些请求转换为标准的Http方法,使得可以支持GET、POST、PUT和DELETE请求。

步骤如下:

1、配置HiddenHttpMethodFilter

 <!--配置org.springframework.web.filter.HiddenHttpMethodFilter
        作用:可以将POST请求转换为 PUT和DELETE请求
     -->
    <filter>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2、发送的是POST请求

3、需要在发送post请求时,携带一个 name="_method"  value="PUT"("DELETE")的隐藏域。

3.4 @RequestParam注解绑定请求参数

       @RequestParam(value = "name"):可以把url路径中 ? 后面的参数绑定到方法的参数中,name和url路径中?后面的参数名名称要一致。这样的话,方法的形参名称就可以随便命名了。如果不@RequestParam或者说@RequestParam不知道value,那么只要方法的形参名和url的?后面的参数名相同,也可以把请求参数的值绑定到形参中。

如果请求路径是:<a href="springmvc/testMethod?name=111&pwd=110&qq=100">testMethod</a>

那么后台方法可以是:

@RequestMapping(value = "testRequestParam")
    public String testMethod(@RequestParam(value = "name") String name,@RequestParam(value = "pwd") String pwd){
        System.out.println("name:"+name+",pwd:"+pwd);
        return SUCCESS;
    }

也可以是:

public String testMethod(String name,String pwd){
        System.out.println("name:"+name+",pwd:"+pwd);
        return SUCCESS;
    }

@RequestParam还可以设置属性:@RequestParam(value = "name",required = true,defaultValue = "qqqq") ,即设置该参数是否必须传,是否设定默认值。

3.5 @RequestHeader注解

@RequestHeader可以用来获取请求头的值,例如:
@RequestMapping(value = "testRequestHeader")
    public String testRequestHeader(@RequestHeader(value = "Accept-Language") String head){
        System.out.println("请求头  :"+head);
        return SUCCESS;
    }

他和@RequestParam一样还有required和defaultValue属性。 

3.6 @CookieValue注解

可以用在方法形参前面,映射一个Cookie值:还有required和defaultValue属性。

@RequestMapping(value = "testCookieValue")
    public String testCookieValue(@CookieValue(value = "JSESSIONID") String sessionId){
        System.out.println("CookieValue  :"+sessionId);
        return SUCCESS;
    }

3.7、POJO对象绑定请求参数的值

       上面第三点,都是讲的单个参数的传递和接收,在开发中,很多时候需要提交表单或者传递很多的参数,如果每个参数都需要在方法中指定一个形参的话,那么就会显得方法很臃肿了。所以,可以使用POJO对象来绑定请求参数,只要保证请求的参数名和POJO的属性名是一一对应的就行了,并且,还支持级联属性的绑定。

3.7.1 创建两个POJO

public class Department {
    private Integer id;
    private String deptName;
//get/set方法以及toString方法
}

public class User {
    private Integer id;
    private String name;
    private Integer age;
    private Department department;
//get/set方法以及toString方法
}

3.7.2 场景处理器方法

@RequestMapping(value = "testPojo")
    public String testPojo( User user){
        System.out.println("pojo  :"+user);
        return SUCCESS;
    }

3.7.3 前端代码

<a href="springmvc/testPojo?id=1&name=tom&age=12&department.deptName=jishu&department.id=1001">testPojo</a>

后台打印:

pojo  :User{id=1, name='tom', age='12', department=Department{id=1001, deptName='jishu'}}

当然,实际开发中,如果是POJO接收的话,一般情况下是form表单进行提交的,不会是一个<a>标签。

3.8、使用Servlet原生的API作为形参

        MVC 的 Handler 方法可以接受以下ServletAPI 类型的参数:HttpServletRequest、HttpServletResponse 、HttpSession 、java.security.Principal 、Locale、InputStream、OutputStream 、Reader、Writer(HttpServletResponse.getWriter()) 这些可以直接在处理器的方法形参上引入即可。

@RequestMapping(value = "testServletApi")
    public void testServletApi(HttpServletRequest request, HttpServletResponse response, Writer writer) throws IOException {
        System.out.println(request+"===="+response);
        writer.write("servlet api test");
    }

4、处理模型数据

Spring MVC 提供了以下几种途径输出模型数据: 
      ModelAndView:处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据;
      Map 及 Model:入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
      @SessionAttributes:将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性;
      @ModelAttribute:方法入参标注该注解后,入参的对象就会放到数据模型中。

4.1 ModelAndView

控制器处理方法的返回值如果为 ModelAndView,则其既包含视图信息,也包含模型数据信息。
      添加模型数据的方法:
              MoelAndView addObject(String attributeName, Object  attributeValue)
              ModelAndView addAllObject(Map<String, ?> modelMap)
       设置视图的方法:
              void setView(View view)
              void setViewName(String viewName)

@RequestMapping(value = "testModelAndView")
    public ModelAndView testModelAndView() throws IOException {
        //创建 ModelAndView 对象并设置视图名称
        ModelAndView modelAndView = new ModelAndView(SUCCESS);
        //添加模型数据
        modelAndView.addObject("time",new Date());
        modelAndView.addObject("usernames", Arrays.asList("tom","jack","bob"));
        return modelAndView;
    }

前台页面的请求和取值:

<a href="springmvc/testModelAndView">testModelAndView</a>


   times:${requestScope.time}
  <br/>

  usernames:${requestScope.usernames}

4.2 Map及Model

Spring MVC 在内部使用了一个org.springframework.ui.Model 接口存储模型数据;
具体步骤:
       Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
       如果方法的入参为 Map 或 Model类型,Spring MVC 会将隐含模型的引用传递给这些入参。在方法体内,开发者可以
通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据。

@RequestMapping(value = "testMapAndModel")
    public String testMapAndModel(Map<String,Object> map, Model model) throws IOException {

        //添加模型数据
        map.put("time",new Date());
        model.addAttribute("usernames", Arrays.asList("tom","jack","bob"));
        return SUCCESS;
    }

4.3 @SessionAttributes

       若希望在多个请求之间共用某个模型属性数据,则可以在控制器类(该注解只能在类上使用)上标注一个 @SessionAttributes,Spring MVC 就会将在模型中对应的属性暂存到 HttpSession 中。
       @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中;
       @SessionAttributes(types=User.class): 会将隐含模型中所有类型为 User.class 的属性添加到会话中。
       @SessionAttributes(value={“user1”, “user2”}) :会将模型中属性名为 user1和user2 的属性方法HttpSession中;
       @SessionAttributes(types={User.class, Dept.class}) 
       @SessionAttributes(value={“user1”, “user2”}, types={Dept.class})

@SessionAttributes(value = {"department"},types = {String.class,Date.class})
@RequestMapping("springmvc")
@Controller
public class SpringMvcTest {

    private static final String SUCCESS = "success";

    @RequestMapping(value = "testSessionAttribute")
    public String testSessionAttribute(Map<String,Object> map, Model model) throws IOException {
        Department department = new Department();
        department.setId(1001);
        department.setDeptName("jishubu");
        //添加模型数据
        map.put("department",department);
        map.put("time",new Date());
        model.addAttribute("password", "123456");
        return SUCCESS;
    }
}

页面取值:

request times:${requestScope.time}
  <br/>

  request usernames:${requestScope.password}
  <br/>
  request department:${requestScope.department}
  <br/>

  下面的数据是从session域中获取:
  <br/>
  session times:${sessionScope.time}
  <br/>

  session usernames:${sessionScope.password}
  <br/>
  session department:${sessionScope.department}
  <br/>

页面效果:

request times:Fri Feb 28 09:47:00 CST 2020 
request usernames:123456 
request department:Department{id=1001, deptName='jishubu'} 
下面的数据是从session域中获取: 
session times:Fri Feb 28 09:47:00 CST 2020 
session usernames:123456 
session department:Department{id=1001, deptName='jishubu'} 

4.4 @ModelAttribute

       在方法定义上使用 @ModelAttribute 注解:Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了@ModelAttribute 的方法。

       在方法的入参前使用 @ModelAttribute 注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数绑定到对象中,再传入入参,将方法入参对象添加到模型中;

后台代码:

@ModelAttribute
    public void getUser(@RequestParam(value="id",required=false) Integer id,
                        Map<String, Object> map) throws IOException {
         if(id!=null){
             //模拟从数据库,根据id获取一个对象
             User user = new User();
             user.setId(1000);
             user.setAge(12);
             user.setName("jack");
             System.out.println("从数据库根据id查询到的User:"+user);

             //map.put("user",user);
             //对应 testModelAttribute的@ModelAttribute("myuser") 
             map.put("myuser",user);
         }
    }

    @RequestMapping(value = "testModelAttribute")
    //public String testModelAttribute(User user) {
    public String testModelAttribute(@ModelAttribute("myuser") User user) {
        System.out.println("修改User:"+user);
        return SUCCESS;
    }

前台表单:因为不能修改年龄,所以前台表单没有age

<form action="springmvc/testModelAttribute" method="post">
    id:<input type="text" name="id" value="1000">
    name:<input type="text" name="name" value="jack">
    <input type="submit" value="提交"/>
  </form>

执行流程:
     * 1. 执行 @ModelAttribute 注解修饰的方法,从数据库中取出对象,把对象放入到了 Map 中,键为:user
     * 2. SpringMVC 从 Map 中取出 User 对象,并把表单的请求参数赋给该 User 对象的对应属性.
     * 3. SpringMVC 把上述对象传入目标方法的参数(testModelAttribute(User user))


     * 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用! 
     * 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
            * 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中。
            * 2). SpringMVC 会一 value 为 key,POJO 类型的对象为 value,存入到 request 中。

注意:由@SessionAttributes引发的异常

org.springframework.web.HttpSessionRequiredException:
Session attribute 'user' required - not found in session

       如果在处理类定义处标注了@SessionAttributes(“xxx”),则尝试从会话中获取该属性,并将其赋给该入参,然后再用
请求消息填充该入参对象。如果在会话中找不到对应的属性,则抛出 HttpSessionRequiredException 异常

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值