SpringMVC学习笔记_01

1、JAVAEE体系结构

  • JAVAEE体系结构图如下所示:

2、什么是springmvc?

  • 什么是mvc?
    • Model1
    • Model2
  • SpringMVC是什么?
    • SpringMVC是一个web层mvc框架,类似struts2。
  • SpringMVC和Spring?
    • Springmvc是Spring的组成部分。
  • SpringMVC执行流程(运行原理)
    • 回忆Struts2执行流程:
      • 前端控制器:StrutsPrepareAndExcuteFilter拦截请求(控制层):拦截请求,转发请求
      • 寻找Action执行,处理请求数据
      • ActionMapping去寻找执行类Action --> UserAction
      • 找到ActionProxy:StrutsActionProxy extends DefaultActionProxy
      • 通过代理类ActionProxy根据struts.xml寻找到真正的执行类Action
    • SpringMVC执行流程(运行原理),如下图所示:

3、springmvc第一个程序案例

3.1、不使用jsp视图解析器+使用jsp视图解析器

(1)使用eclipse,创建一个动态的web工程
  其中Dynamic web module version版本选择 2.5,这样兼容性好一些;
  Default output folder设置为 WebRoot\WEB-INF\classes
  Content directory设置为 WebRoot
  更改JRE System Library[J2SE-1.5]为 JRE System Library[jre1.7.0_80]
  删掉没用的库:EAR Libraries
  增加服务器运行环境库 Server Runtime,不然jsp文件会报错。


  创建完项目后,将整个项目的编码改为UTF-8。
  操作步骤:选中项目右键 --> Properties --> Resource --> Text file encoding --> Other中选择UTF-8。

  对于动态的java web项目,为了工程目录结构的清爽,我们将引入的jar包放到“Web App Libraries”中,可以通过“小三角”选择是否“Show 'Referenced Libraries' Node ”进行调节。
  对于普通的java项目,为了工程目录结构的清爽,我们将引入的jar包放到“Referenced Libraries”中,可以通过“小三角”选择是否“Show 'Referenced Libraries' Node ”进行调节。

(2)导入springmvc的jar包
  本案例共16个jar,如下图所示:

(3)在web.xml配置前端控制器:DispatcherServlet(入口)

    <!-- 配置前端控制器:DispatcherServlet -->
    <servlet >
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

  我们还需要配置springmvc.xml文件的初始化参数,如下图所示:

(4)配置springmvc.xml
  参考文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
    <!-- 配置处理器映射器,springmvc默认的处理器映射器 -->
    <!-- BeanNameUrlHandlerMapping:根据bean(自定义的Controller)的name属性的url去寻找执行类Handler(Action)即Controller -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

    <!-- 配置处理器适配器,负责执行Controller,也是springmvc默认的处理器适配器 -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

    <!-- 配置自定义的Controller:UserController -->
    <bean name="/hello.do" class="com.itheima.controller.UserController"></bean>

    <!-- 配置jsp视图解析器,InternalResourceViewResolver负责解析出真正的逻辑视图 -->
    <!-- 后台返回逻辑视图:index,jsp视图解析器解析出真正的物理视图:前缀+逻辑视图+后缀 ==>/WEB-INF/jsps/index.jsp -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

(5)自定义Controller(相当于Struts2里面的Action)

public class UserController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 接收请求,接收参数,验证参数,处理请求
        // 封装参数,调用业务方法,返回处理结果数据ModelAndView

        // 演示案例中我们只模拟下而已:向前台返回数据
        ModelAndView mv = new ModelAndView();
        mv.addObject("hello", "like xiaoyi");

        // 指定跳转的视图
        // 返回真实的物理视图,省略了8、9步
        // mv.setViewName("/WEB-INF/jsps/index.jsp");
        // 返回逻辑视图
        mv.setViewName("index");

        return mv;
    }
}

(6)定义视图页面
  根据视图解析路径:WEB-INF/jsps/index.jsp

<body>
    <h1>${hello}</h1>
</body>

(7)浏览器访问
  访问地址:http://localhost:8080/day63_SpringMVC_01/hello.do

4、根据程序分析springmvc执行流程(画图)

  • 该图同SpringMVC执行流程图(运行原理)

5、处理器映射器

5.1、配置默认处理器映射器(BeanNameUrlHandlerMapping)

功能:寻找Controller
   根据url请求去匹配bean的name属性url,从而获取Controller

5.2、配置集中处理器映射器(SimpleHandlerMapping)

功能:寻找Controller
   根据浏览器url匹配简单url的key,key通过Controller的id找到Controller

5.3、配置类名处理器映射器(ClassNameHandlerMapping)

功能:寻找Controller
   直接根据类名(UserController),类名.do来访问,类名首字母小写

  • 3个处理器映射器可以共存。均可以访问成功。

6、处理器适配器

6.1、配置默认处理器适配器(SimpleControllerHandlerAdapt)

功能:执行Controller
   负责执行实现了Controller接口的后端控制器,例如:UserController,调用Controller里面的方法,返回ModelAndView。


默认处理器适配器源码分析,如下图所示:

6.2、配置请求处理器适配器(HttpRequestHandlerAdapter)

功能:执行Controller
   负责执行实现了HttpRequestHandler接口的后端控制器。


演示过程:
  自定义实现了接口HttpRequestHandler的实现类HttpController,如下图所示:

  在springmvc.xml中配置自定义的bean,即自定义的HttpController,如下图所示:

  上面的这种方式无限接近servlet的开发。
  • 2个处理器适配器可以共存。

7、命令控制器

7.1、Controller简介

1、收集、验证请求参数并绑定到命令对象;
2、将命令对象交给业务对象,由业务对象处理并返回模型数据;
3、返回ModelAndView(Model部分是业务对象返回的模型数据,视图部分是逻辑视图名)。

  • 普通控制器(继承接口Controller,继承接口HttpRequestHandler)
  • 命令控制器(继承抽象类AbstractCommandController)
    • 例子:跳转到添加页面,进行页面跳转,参数提交get请求或者post请求
  • 参数控制器(类ParameterizableViewController)

Springmvc通过命令设计模式接受页面参数。

7.2、演示:自定义命令控制器

示例如下:
(1)自定义命令控制器

package com.itheima.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;

import com.itheima.domain.User;

// 从页面接收参数,封装到JavaBean中,本例中的JavaBean是User
@SuppressWarnings("deprecation")
public class CommandController extends AbstractCommandController {

    // 指定把页面传过来的参数封装到对象,使用命令设计模式
    public CommandController() {
        this.setCommandClass(User.class);
    }

    @Override
    protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command,
            BindException errors) throws Exception {
        // 参数被封装进命令对象,这个过程很复杂,我们暂时不用管它,只要知道它使用的是命令设计模式即可

        // 把命令对象强转成User对象
        User user = (User) command;
        // 设置Model的数据,值可以是任意pojo
        ModelAndView mv = new ModelAndView();
        mv.addObject("user", user);
        // 指定返回页面
        mv.setViewName("index");

        return mv;
    }
}

(2)定义javaBean

package com.itheima.domain;

import java.util.Date;

public class User {

    private Integer id;
    private String username;
    private String age;
    private Date birthday;
    private String address;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

(3)封装参数页面
  文件位置:/day63_SpringMVC_01/WebRoot/WEB-INF/jsps/add.jsp
add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/command.do" method="post">
        姓名:<input type="text" name="username" id="username"><br>
        年龄:<input type="text" name="age" id="age"><br>
        生日:<input type="text" name="birthday" id="birthday"><br>
        地址:<input type="text" name="address" id="address"><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

(4)获取参数页面
  文件位置:/day63_SpringMVC_01/WebRoot/WEB-INF/jsps/index.jsp
index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>${user.username}---${user.age}---${user.birthday}---${user.address}</h1>
</body>
</html>

(5)跳转到add页面
  由于add页面在WEB-INF下面不能直接访问,需要通过Controller来访问。

package com.itheima.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class ToAddController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 跳转到add页面
        ModelAndView mv = new ModelAndView();
        mv.setViewName("add");

        return mv;
    }
}

(6)在springmvc.xml中配置bean

    <!-- 配置自定义的CommandController:CommandController -->
    <bean name="/command.do" class="com.itheima.controller.CommandController"></bean>

    <!-- 配置自定义的ToAddController:ToAddController -->
    <bean name="/toAdd.do" class="com.itheima.controller.ToAddController"></bean>

7.3、中文乱码解决

(1)解决get请求乱码
  配置tomcat的编码,如下图所示:


(2)解决post请求乱码
  在web.xml中,配置spring编码过滤器,如下所示:
    <!-- 配置spring编码过滤器 -->
    <filter>
        <filter-name>characterEcoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEcoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

7.4、时间类型转换

  在CommandController类中重写initBinder()方法,示例代码如下:

// 从页面接收参数,封装到JavaBean中,本例中的JavaBean是User
@SuppressWarnings("deprecation")
public class CommandController extends AbstractCommandController {

    // 指定把页面传过来的参数封装到对象,使用命令设计模式
    public CommandController() {
        this.setCommandClass(User.class);
    }

    @Override
    protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception {
        // 参数被封装进命令对象,这个过程很复杂,我们暂时不用管它,只要知道它使用的是命令设计模式即可

        // 把命令对象强转成User对象
        User user = (User) command;
        // 设置Model的数据,值可以是任意pojo
        ModelAndView mv = new ModelAndView();
        mv.addObject("user", user);
        // 指定返回页面
        mv.setViewName("index");

        return mv;
    }

    @Override
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        String str = request.getParameter("birthday");
        if (str.contains("/")) {
            binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy/MM/dd"), true));
        } else {
            binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
        }
    }
}

7.5、参数控制器ParameterizableViewController

  在springmvc.xml中配置参数控制器

  • 注意:使用参数控制器:不用自己定义Controller了,可以直接使用toIndex.do进行访问。

8、注解开发

8.1、注解开发第一个入门程序

  • 步骤如下:
    • 创建一个动态的web工程,导入jar文件
    • 配置web.xml
    • 配置springmvc.xml文件:配置处理器映射器、配置处理器适配器、配置jsp视图解析器
    • 自定义Controller类,使用注解开发:添加,返回到成功页面进行回显,点击修改回到添加页面,初步理解参数传递。

(1)创建一个动态的web工程,导入jar文件
  详细过程同3、springmvc第一个程序案例
(2)配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>day63_SpringMVC_01</display-name>
    <!-- 配置spring编码过滤器 -->
    <filter>
        <filter-name>characterEcoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEcoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置前端控制器:DispatcherServlet -->
    <servlet >
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 隐式默认加载springmvc.xml文件,该文件需要满足2个规范:
                命名规范:servlet-name-servlet.xml => springmvc-servlet.xml
                路径规范:该文件必须放在WEB-INF目录下面
        -->
        <!-- 显示配置加载springmvc.xml文件,即配置springmvc.xml文件的初始化参数 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

(3)配置springmvc.xml文件
  配置扫描,把Controller交给spring管理、配置处理器映射器、配置处理器适配器、配置jsp视图解析器

<?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"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
    <!-- 配置扫描,把Controller交给spring管理 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!-- 配置注解的处理器映射器,作用:寻找执行类Controller -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>

    <!-- 配置注解的处理器适配器,作用:调用Controller方法,执行Controller -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>

    <!-- 配置jsp视图解析器,InternalResourceViewResolver负责解析出真正的逻辑视图 -->
    <!-- 后台返回逻辑视图:index,jsp视图解析器解析出真正的物理视图:前缀+逻辑视图+后缀 ==>/WEB-INF/jsps/index.jsp -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsps/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

(4)自定义Controller类

@Controller // 相当于<bean id="userController" class="com.itheima.controller.UserController">,即相当于创建了一个UserController对象
@RequestMapping("/user")
public class UserController {
    // 请求映射注解
    @RequestMapping("hello") // 相当于访问/hello.do
    public String myHello() {
        // 表示springmvc返回了一个逻辑视图hello.jsp
        return "hello";
    }
}

(5)定义hello页面
  根据视图解析,需要在WEB-INF下面定义jsps文件夹,在里面定义一个hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>欢迎访问SpringMVC</h1>
</body>
</html>

(6)访问地址:http://localhost:8080/day63_SpringMVC_02/user/hello.do

8.2、注解开发流程图

注解开发流程图如下:

8.3、RequestMapping

功能:请求映射

几种写法:
    @RequestMapping("hello") -- 这种方式可以匹配任何的扩展名
    @RequestMapping("/hello.do")
    @RequestMapping(value="/hello.do")
    @RequestMapping(value="/hello.do",method=RequestMethod.GET)
    @RequestMapping(value="/hello.do",method=RequestMethod.POST)
    @RequestMapping(value="/hello.do", method={RequestMethod.GET,RequestMethod.POST})

  浏览器直接访问、a标签都是get请求。
  表单提交(指定post)、ajax指定post提交。
  如果是get请求,写成了post浏览器会报405错误,如下图所示:

8.4、RequestMapping的根路径

@RequestMapping("/user")
public class UserController {
    @RequestMapping("save")
    public String save() {
    }
    @RequestMapping("update")
    public String update() {
    }
    @RequestMapping("find")
    public String find() {
    }
}
访问地址:http://localhost:8080/项目名/user/save.do

@RequestMapping("/items")
public class  ItemsController {
    @RequestMapping("save")
    public String save() {
    }
    @RequestMapping("update")
    public String update() {
    }
    @RequestMapping("find")
    public String find() {
    }
访问地址:http://localhost:8080/项目名/items/save.do

演示:自定义根路径

@Controller // 相当于<bean id="userController" class="com.itheima.controller.UserController">,即相当于创建了一个UserController对象
@RequestMapping("/user")
public class UserController {
    // 请求映射注解
    @RequestMapping("hello") // 相当于访问/hello.do
    // @RequestMapping(value="/hello.do",method=RequestMethod.POST)
    public String myHello() {
        // 表示springmvc返回了一个逻辑视图hello.jsp
        return "hello";
    }
}

访问地址:http://localhost:8080/day63_SpringMVC_02/user/hello.do

8.5、RequestParam

  value:参数名字,即入参的请求参数名字,如value="studentid"表示请求的参数区中的名字为studentid的参数的值将传入。
  required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码。
  defaultValue:默认值,表示如果请求中没有同名参数时的默认值
示例如下:

public String userList(@RequestParam(defaultValue="2",value="group",required=true) String groupid) {
}
    1、形参名称为groupid,但是这里使用value="group"限定参数名为group,所以页面传递参数的名必须为group。
    2、这里通过required=true限定groupid参数为必需传递,如果不传递则报400错误,由于使用了defaultvalue="2"默认值,即使不传group参数它的值仍为"2"。
    3、所以页面不传递group也不会报错,如果去掉defaultvalue="2"且定义required=true,则如果页面不传递group就会报错。

示例如下图所示:


  @RequestParam的作用:给传递的参数起别名。

9、封装参数

  • springmvc没有成员变量,那页面提交过来的参数该如何接收和进行传递呢?
  • 答:把需要传递的参数对象放入方法里面,当你请求这个方法,向这个方法传递参数的时候,这个方法里面的对象会自动被创建,需要的参数会自动被封装到方法的对象里面。

分析接受参数类型:

基本类型
    int、String等基本类型。
Pojo类型
包装类型
集合类型

Springmvc默认支持类型:
    HttpSession、HttpRequstServlet、Model等等。

Struts2参数封装:基于属性驱动封装。
Springmvc参数封装:基于方法进行封装。

9.1、封装int类型参数

  • 页面传递的参数都是字符串。

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveInt.do" method="post">
        ID:<input type="text" name="id" id="id"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收int类型参数 
    @RequestMapping("recieveInt")
    public String recieveInt(Integer id) {
        System.out.println(id);
        return "success";
    }
  • 特别注意:标签input的name的属性值id要与方法的形式参数名称id相同。

9.2、封装String类型参数

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveString.do" method="post">
        姓名:<input type="text" name="username" id="username"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收String类型参数 
    @RequestMapping("recieveString")
    public String recieveString(String username) {
        System.out.println(username);
        return "success";
    }

9.3、封装数组类型参数

  • 分析:封装数组是批量删除时使用,使用checkbox复选框,其value属性必须有值。

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveArray.do" method="post">
        ID:<input type="checkbox" name="ids" value="1" id="ids"><br>
        ID:<input type="checkbox" name="ids" value="2" id="ids"><br>
        ID:<input type="checkbox" name="ids" value="3" id="ids"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收数组类型参数 
    @RequestMapping("recieveArray")
    public String recieveArray(Integer[] ids) {
        System.out.println(ids);
        return "success";
    }

9.4、封装pojo类型参数

创建一个pojo类:

public class User {

    private Integer id;
    private String username;
    private String age;
    private Date birthday;
    private String address;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", age=" + age + ", birthday=" + birthday + ", address="
                + address + "]";
    }
}

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveUser.do" method="post">
        姓名:<input type="text" name="username" id="username"><br>
        年龄:<input type="text" name="age" id="age"><br>
        生日:<input type="text" name="birthday" id="birthday"><br>
        地址:<input type="text" name="address" id="address"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收pojo类型参数 
    @RequestMapping("recieveUser")
    public String recieveString(User user) {
        System.out.println(user);
        return "success";
    }

9.4、封装包装类型参数

创建一个包装类:

public class UserCustom {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveUserCustom.do" method="post">
        姓名:<input type="text" name="user.username" id="username"><br>
        年龄:<input type="text" name="user.age" id="age"><br>
        生日:<input type="text" name="user.birthday" id="birthday"><br>
        地址:<input type="text" name="user.address" id="address"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收包装类型参数 
    @RequestMapping("recieveUserCustom")
    public String recieveUserCustom(UserCustom userCustom) {
        System.out.println(userCustom);
        return "success";
    }

9.5、封装集合类型参数

9.5.1、封装List集合类型参数

  • 注意:不能直接传递集合类型,需要把集合类型封装到包装类中。

我们先把List集合封装到包装类中。即:在包装类中定义List集合。提供getter和setter方法。

    private List<User> userList;

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveList.do" method="post">
        姓名:<input type="text" name="userList[0].username" id="username"><br>
        年龄:<input type="text" name="userList[0].age" id="age"><br>

        姓名:<input type="text" name="userList[1].username" id="username"><br>
        年龄:<input type="text" name="userList[1].age" id="age"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收List结合类型参数 
    @RequestMapping("recieveList")
    public String recieveList(UserCustom userCustom) {
        System.out.println(userCustom);
        return "success";
    }

9.5.2、封装Map集合类型参数

我们先把Map集合封装到包装类中。即:在包装类中定义Map集合。提供getter和setter方法。

    private Map<String, Object> maps = new HashMap<String, Object>();

    public Map<String, Object> getMaps() {
        return maps;
    }

    public void setMaps(Map<String, Object> maps) {
        this.maps = maps;
    }

页面的代码:

    <hr size="12" color="blue">
    <form action="${pageContext.request.contextPath}/user/recieveMap.do" method="post">
        姓名:<input type="text" name="mps['username']" id="username"><br>
        年龄:<input type="text" name="mps['age']" id="age"><br>
        <input type="submit" value="提交">
    </form>

接受参数的方法:

    // 接收Map结合类型参数 
    @RequestMapping("recieveMap")
    public String recieveMap(UserCustom userCustom) {
        System.out.println(userCustom);
        return "success";
    }

9.6、思考:有了struts2,为什么还需要sprigmvc呢?

  • 实现机制:
    • struts2 底层是基于`过滤器`实现的。过滤器的底层是servlet。
    • springmvc 底层基于`servlet`实现。servlet比过滤器快。
  • 运行速度:
    • struts2 是`多例`
      • 一个请求来了以后,struts2创建多少个对象?如下:
      • ActionContext、ValueStack、UserAction、ActionSuport、ModelDriven等等。
      • UserAction里面属性:User对象,userList集合对象等。属于成员变量,存活时间长。
    • springmvc 是`单例`,因为是基于servlet的,servlet是单例的。
      • 一个请求来了以后,springmvc 创建多少个对象?如下:
      • Controller等等。
      • 方法的参数属于局部变量,存活时间短。
  • 参数封装来分析:
    • struts 基于`属性驱动`进行封装。
    • springmvc 基于`方法`进行封装,粒度更细。

10、页面回显

  • springmvc使用Model对象进行页面数据回显,Model对象相当于javaweb时所学的application对象(应用域对象),所以Model对象中的数据可以通过EL表达式进行获取。
  • 有了Model对象,才可以向对象中放值,那么Model对象该如何创建呢?
    • 答:`springmvc中放到方法里面的对象会自动被创建`,那么我们就把Model对象放到方法里面。

10.1、查询所有

页面的代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%--引入jstl标签 --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <table border="1" style="color: blue">
        <tr>
            <td>姓名</td>
            <td>年龄</td>
            <td>生日</td>
            <td>地址</td>
            <td>操作</td>
        <tr/>
        <c:forEach items="${userList}" var="user">
            <tr>
                <td>${user.username}</td>
                <td>${user.age}</td>
                <td>${user.birthday}</td>
                <td>${user.address}</td>
                <td>
                    <href="${pageContext.request.contextPath}/user/updateById.do?id${user.id}">修改</a>
                </td>
            <tr/>        
        </c:forEach>
    </table>
</body>
</html>

接受参数的方法:

    // 查询所有
    @RequestMapping("listAll")
    public String listAll(Model model) {
        // 由于演示我们没有查询数据库,所以下面我们模拟几条数据
        List<User> userList = new ArrayList<User>();

        User user1 = new User();
        user1.setId(1);
        user1.setUsername("晓艺");
        user1.setAge("26");
        user1.setAddress("物资学院");
        user1.setBirthday(new Date());

        User user2 = new User();
        user2.setId(2);
        user2.setUsername("黑泽");
        user2.setAge("26");
        user2.setAddress("青年路");
        user2.setBirthday(new Date());

        User user3 = new User();
        user3.setId(3);
        user3.setUsername("奇遇");
        user3.setAge("28");
        user3.setAddress("物资学院");
        user3.setBirthday(new Date());

        userList.add(user1);
        userList.add(user2);
        userList.add(user3);

        // Model相当于application域对象
        model.addAttribute("userList", userList);

        return "list";  
    }

浏览器显示效果:

11、URL模版映射

  • URL模版映射主要是为了实现请求Restfull软件架构设计模式
  • Restfull软件架构设计模式使得请求更简洁、更安全,方便于搜索引擎收录。

11.1、普通模式修改

页面的代码:

    <td>
        <href="${pageContext.request.contextPath}/user/updateByIdNormal.do?id=${user.id}">修改</a>
    </td>

接受参数的方法:

    // 普通模式修改
    @RequestMapping("updateByIdNormal")
    public String updateByIdNormal(Integer id) {
        System.out.println(id);
        return "redirect:listAll.do";
    }

访问的地址为:http://localhost:8080/day63_SpringMVC_02/user/updateByIdNormal.do?id=1

11.2、Restfull风格设计模式修改

(1)初始Restfull风格设计模式修改
页面的代码:

    <td>
        <href="${pageContext.request.contextPath}/user/updateByIdRestfull/${user.id}.do">修改</a> <!-- 把参数放在了请求的里面了 -->
    </td>

接受参数的方法:

    // 初始Restfull模式修改
    @RequestMapping("updateByIdRestfull/{id}")
    public String updateByIdRestfull(@PathVariable Integer id) {
        System.out.println(id);
        return "redirect:/user/listAll.do"; // 请求重定向
    }

访问的地址为:http://localhost:8080/day63_SpringMVC_02/user/updateByIdRestfull/1.do

(2)最终Restfull风格设计模式修改
  约定:在web.xml配置拦截方式:在rest目录下所有请求都被拦截,servlet可以拦截目录。
web.xml中配置代码如下:

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

页面的代码:

    <td>
        <href="${pageContext.request.contextPath}/rest/user/updateByIdRestfull/${user.id}">修改</a> 
    </td>

接受参数的方法:

    // 最终Restfull模式修改
    @RequestMapping("updateByIdRestfull/{id}")
    public String updateByIdRestfull(@PathVariable Integer id) {
        System.out.println(id);
        return "redirect:/user/listAll.do"; // 请求重定向
    }

访问的地址为:http://localhost:8080/day63_SpringMVC_02/rest/user/updateByIdRestfull/1
其中:
  {id}:表示匹配接受页面url路径中的参数
  @PathVariable:表示{id}里面参数注入后面参数id里面
  url模版映射需要@RequestMapping和@PathVariable结合使用。
画图理解URL模版映射,如下图所示:

11.3、在线安装eclipse提示插件--Spring tools suite

步骤:Help --> Eclipse Marketplace… --> 在Find中输入Spring tools suite,点击安装即可。
安装成功后的截图如下:

12、转发和重定向

12.1、转发

  • 本类中进行转发:本类中方法与方法之间进行forward
    • 关键字:forward
    • 转发方式一:return "forward:listAll.do";
    • 转发方式二:return "/user/forward:listAll.do";
    • 注意:`user根路径前面必须有/。`
  • 跨类进行转发:
    • 转发方式:return "forward:/items/listAll.do";

测试代码如下:

    // 测试forward
    @RequestMapping("forward")
    public String forward() {
        // return "forward:listAll.do"; // 本类中转发方式一
        // return "/user/forward:listAll.do"; // 本类中转发方式二
        return "forward:/items/listAll.do"; // 跨类进行转发
    }

12.2、重定向

  • 本类中进行重定向:本类中方法与方法之间进行redirect
    • 关键字:redirect
    • 重定向方式一:return "redirect:listAll.do";
    • 重定向方式二:return "redirect:/user/listAll.do";
  • 跨类进行重定向:
    • 重定向方式:return "redirect:/items/listAll.do";

测试代码如下:

    // 测试redirect
    @RequestMapping("redirect")
    public String redirect() {
        // return "redirect:listAll.do"; // 本类中重定向方式一
        // return "/user/redirect:listAll.do"; // 本类中重定向方式二
        return "redirect:/items/listAll.do"; // 跨类进行重定向
    }

13、标签< mvc:annotation-driven />的使用

详解如下:

标签<mvc:annotation-driven /> 表示默认创建处理器映射器RequestMappingHandlerMapping、处理器映射器RequestMappingHandlerAdapter,还表示默认启动json格式数据的支持。

所以在springmvc.xml中就不要再配置处理器映射器和处理器映射器了。
只需要配置这一句就可以了。

14、RequestBody 和 ResponseBody

  • @RequestBody 和 @ResponseBody,这两个注解主要是为了提供对json格式数据的支持。
  • @RequestBody的作用:把前台页面请求的json格式数据直接封装成JavaBean,使用ajax进行数据传递。
  • @ResponseBody的作用:在后台,把JavaBean强制转换成json格式数据返回给前台页面。

这两个注解不能直接使用,需要依赖两个Jackson的jar包。

(1)先导入Jackson的jar包


(2)在springmvc.xml中配置json格式转换
注意:我们也可以直接使用<mvc:annotation-driven />,因为该标签默认启动json格式数据的支持。
    <!-- 配置注解的处理器适配器,作用:调用Controller方法,执行Controller -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <!-- 配置对json格式数据的支持 -->
        <property name="messageConverters">
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
        </property>
    </bean> 

(3)请求json格式数据,返回json格式数据
(4)请求pojo格式数据,返回json格式数据
/day63_SpringMVC_02/WebRoot/WEB-INF/jsps/requestjson.jsp
前台代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<!-- 引入jquery.js的支持 -->
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.js"></script>
</head>
<body>
    <input type="button" value="请求是json格式数据,返回是json格式数据" onclick="requestJson();">
    <br>
    <input type="button" value="请求是pojo格式数据,返回是json格式数据" onclick="requestPojo();">
    <script type="text/javascript">
        function requestJson() {
            // 演示:构造一个json格式数据
            var jsonObj = JSON.stringify({'username':'晓艺','age':'26','address':'物资学院'}); // stringify的作用:把json格式的数据数强转成json对象
            // 发送ajax请求
            $.ajax({
                type:'post',
                url:'${pageContext.request.contextPath}/user/requestJson.do',
                contentType:'application/json;charset=UTF-8', // 默认: "application/x-www-form-urlencoded"
                data:jsonObj,
                success:function(data) { // 回调函数
                    alert(data);
                }
            });
        }
        function requestPojo() {
            // 演示:构造一个pojo格式数据
            var pojoObj = 'username=黑泽&age=26&address=青年路';
            // 发送ajax请求
            $.ajax({
                type:'post',
                url:'${pageContext.request.contextPath}/user/requestPojo.do',
                data:pojoObj,
                success:function(data) { // 回调函数
                    alert(data);
                }
            });         
        }
    </script>
</body>
</html>

后台代码:

    // 跳转方法,跳转到requestjson.jsp页面
    @RequestMapping("toJson")
    public String tiJson() {
        return "requestjson";
    }

    // 接收json格式数据,使用 @RequestBody 把json格式数据封装进JavaBean对象中(本例中是User对象)
    // 返回json对象,使用 @ResponseBody 把User对象转换成json对象
    @RequestMapping("requestJson")
    public @ResponseBody User requestJson(@RequestBody User user) {
        System.out.println(user);

        return user;
    }

    // 接收pojo格式数据
    // 返回json对象,使用@ResponseBody 把User对象转换成json对象
    @RequestMapping("requestPojo")
    public @ResponseBody User requestPojo(User user) {
        System.out.println(user);

        return user;
    }

posted on 2018-12-04 22:21  pony1223  阅读(661)  评论(1编辑  收藏  举报

导航