SpringMVC学习总结

来源:互联网 发布:linux上jsp页面跳转 编辑:程序博客网 时间:2024/05/19 17:51

SpringMVC学习总结


1 . MVC架构

MVC是一种架构模型,本身没有什么功能,只是让我们的项目结构更加合理,流程控制更加清晰,一般包含三个组件:

一、流程图

二、流程总结

  • Model(模型):数据模型,用于提供要展示的数据。一般包含数据和行为(也就是业务),在JavaWEB中,数据和业务往往是分离开的
  • View(视图):负责对模型数据进行展示,例如我们看到的网页。概念比较广泛,可以是:html、JSP、excel、Word、PDF、json、XML等
  • Controller(控制器):接收用户请求,委托给模型做处理,处理完毕返回数据,再交给视图做渲染,相当于调度员工作

2 . SpringMVC架构

一、流程图

二、流程总结

DisPatcherServlet:前端控制器

HandlerMapping:处理器映射

Handler:处理器

HandlerInterceptor:处理器拦截器

HandlerAdapter:处理器适配器

ModelAndView:模型和视图

Model:模型数据

View:视图名称,不是真正的视图对象

ViewResolver:视图解析器

  1. 用户发送请求到DisPatcherServlet
  2. DispatcherServlet通过HandlerMapping 寻找用户要请求的 Handler
  3. HandlerMapping返回执行链,包含两部分内容:HandlerHandlerInterceptor
  4. DisPatcherServlet通过HandlerAdapterHandler进行适配包装
  5. 调用包装后的Handler中的方法处理业务
  6. 处理业务完成,返回ModelAndView对象,包含两部分内容:ModelView
  7. DispatcherServlet获取处理得到的ModelAndView对象
  8. DispatcherServlet将视图名称交给ViewResolver查找视图
  9. ViewResolver返回真正的视图对象给DispatcherServlet
  10. DispatcherServletModel交给视图对象进行渲染
  11. 返回渲染后的视图
  12. 将最终的视图返回给用户,产生响应

3 . SpringMVC入门案例

第一步:在war工程的pom.xml文件中导入依赖

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>cn.itcast.springmvc</groupId>    <artifactId>springmvc-day03</artifactId>    <packaging>war</packaging>    <!-- 1. 导入父模块 -->    <parent>        <groupId>cn.itcast.parent</groupId>        <artifactId>itcast-parent</artifactId>        <version>1.0.0-SNAPSHOT</version>    </parent>    <!-- 2. 导入相关依赖 -->    <dependencies>        <!-- 2.1 SpringMVC -->        <dependency>            <groupId>org.springframework</groupId>            <artifactId>spring-webmvc</artifactId>        </dependency>        <!-- 2.2 JSP相关 -->        <dependency>            <groupId>jstl</groupId>            <artifactId>jstl</artifactId>        </dependency>        <dependency>            <groupId>javax.servlet</groupId>            <artifactId>servlet-api</artifactId>        </dependency>        <dependency>            <groupId>javax.servlet</groupId>            <artifactId>jsp-api</artifactId>        </dependency>        <!-- 2.3 日志 -->        <dependency>            <groupId>org.slf4j</groupId>            <artifactId>slf4j-log4j12</artifactId>        </dependency>    </dependencies>    <!-- 3. 配置插件 -->    <build>        <plugins>            <!-- 3.1 配置Tomcat插件 -->            <plugin>                <groupId>org.apache.tomcat.maven</groupId>                <artifactId>tomcat7-maven-plugin</artifactId>                <configuration>                    <!-- 端口信息 -->                    <port>8080</port>                    <!-- 项目路径 -->                    <path>/</path>                </configuration>            </plugin>        </plugins>    </build></project>

第二步:在WEB-INF目录下编写项目配置文件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="MyWebApp" version="2.5">    <!-- 配置欢迎页面 -->    <welcome-file-list>        <welcome-file>index.jsp</welcome-file>    </welcome-file-list>    <!-- 描述servlet的名称信息 -->    <display-name>springMVC</display-name>    <servlet>        <!-- 在web.xml(web程序的入口) 配置了DispatcherServlet,        并且指定所有以.do结尾的请求全部交给DispatcherServlet来处理-->        <servlet-name>springmvc</servlet-name>        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>        <servlet-name>springmvc</servlet-name>        <!-- 配置/*会拦截所有请求,包括静态页面 -->        <url-pattern>*.do</url-pattern>    </servlet-mapping></web-app>

第三步:在WEB-INF目录下创建springmvc-servlet.xml

springmvc-servlet.xml是SpringMVC项目的核心配置文件

<?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:p="http://www.springframework.org/schema/p"    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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <!-- 配置HandlerMapping -->    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>    <!-- 配置HandlerAdapter -->    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />    <!-- 配置Handler,一般以Controller后缀,指向自定义的那个Controller-->    <bean name="/hello.do" class="cn.itcast.controller.HelloController"/>    <!-- 视图解析器,这里是用内部资源视图解析器,其实就是指向项目中的jsp文件    Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" -> "/WEB-INF/jsp/test.jsp"  -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="prefix" value="/WEB-INF/views/"/>        <property name="suffix" value=".jsp"/>    </bean></beans>

第四步:编写Handler

Handler,具体的处理器,在SpringMVC中,一般是叫做Controller(控制器),我们可以自定义类,实现Controller接口,就称为控制器,代码如下所示:

package cn.itcast.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 HelloController implements Controller{    @Override    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {        ModelAndView mv = new ModelAndView("hello");        mv.addObject("msg","这是我的第一个springmvc程序");        return mv;    }}

第五步:定义视图

创建一个hello.jsp文件,符合上面的视图规则,所以要放到WEB-INF/views/下,代码如下

<%@ 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>${msg}</h1></body></html>

第六步:测试

将该工程的父模块工程使用 maven install 命令,打成jar包到仓库中,然后使用tomcat7:run命令执行该模块工程

测试结果OK!

第七步:优化配置

  1. 我们尝试省略HandlerMapping和HandlerAdapter的配置
  2. 重启Tomcat重试:发现依然没有问题

    原因:在spring-webmvc-4.1.3.RELEASE.jar –> org.springframework.web.servlet –> DispatcherServlet.properties文件中定义了很多默认配置,因此,一般我们只需要配置 Handler和视图解析器就够了

4 . SpringMVC注解案例

入门案例中,我们自定义控制器类的方式并不好,存在以下问题:

  1. 类必须实现Controller接口,不友好
  2. 每个类中只能有一个默认处理方法,只能处理一个用户请求
  3. 每个类需要在配置文件中进行配置,很麻烦

解决方案:在Spring2.5以后,就引入了注解方式的控制器定义方式,并且在Spring3.0以后引入了更多非常强大的注解帮我们进行参数注入

第一步:创建注解控制器

package cn.itcast.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;// 通过@Controller注解表名当前类是一个控制器类@Controllerpublic class AnnotationController {    // 通过@RequestMapping注解定义当前方法的映射路径,在浏览器中通过这个路径访问这个方法    @RequestMapping("/show1")    public ModelAndView show1(){        ModelAndView mv = new ModelAndView("hello");        mv.addObject("msg","这是使用注解的第一个SpringMVC程序!");        return mv;    }}

第二步:在springmvc-servlet.xml配置包扫描

要想使用SpringMVC的注解控制器,只需要在springmvc-servlet.xml文件中增加一个配置包扫描,代码如下所示:

<!-- 使用SpringMVC注解:直接配置包扫描,不需要Controller的Bean了 --><context:component-scan base-package="cn.itcast.controller"/>

第三步:测试

测试结果OK!

第四步:默认的配置问题及推荐方案

我们使用SpringMVC默认配置没有问题,完全可以使用。但是呢,有一些小问题存在:

  • 默认的HandlerMapping过时了,推荐我们使用RequestMappingHandlerMapping
  • 默认的HandlerAdapter过时了,推荐使用RequestMappingHandlerAdapter

所以,这里要玩注解方式,就不能使用默认配置,必须手动设置这两个推荐的HandlerMapping和HandlerAdapter

在springmvc-servlet.xml文件中增加两个bean节点,代码如下所示:

<!-- 配置注解方式的HandlerMapping和HandlerAdapter --><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/><bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>

第五步:注解驱动及原理

经过上面第四步的修改,我们的配置又变的很麻烦了。为了解决这个问题,其实在SpringMVC中,给我们提供了一种解决方案:只需要配置一个标签即可

在springmvc-servlet.xml文件中取消第四步配置的两个bean节点,增加一个开启注解驱动的节点,代码如下所示:

<!-- 开启注解驱动,就不要配置HandlerMapping和HandlerAdapter了 --><mvc:annotation-driven />

原因:在spring-webmvc-4.1.3.RELEASE.jar –> org.springframework.web.servlet.config –> AnnotationDrivenBeanDefinitionParser.class这个类中已经注册了2个HandlerMapping和3个HandlerAdapter

因此,当我们配置了注解驱动开关,那么注解驱动的类被加载后,会自动加载这几个HandlerMapping和HandlerAdapter,所以我们不需要配置了。
注解驱动相当于是原来默认配置的升级版!

因此,玩注解驱动的最终配置方式就是:

  1. 开启注解驱动
  2. 开启扫描包
  3. 配置内部资源解析器

最终的springmvc-servlet.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:p="http://www.springframework.org/schema/p"    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/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">    <!-- 开启注解包扫描 -->    <context:component-scan base-package="cn.itcast.controller"/>    <!-- 开启注解驱动 -->    <mvc:annotation-driven />    <!-- 配置视图解析器 -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="prefix" value="/WEB-INF/views/"/>        <property name="suffix" value=".jsp"/>    </bean></beans>

注意:上面的最终配置只针对注解方式有效

5 . RequestMapping请求映射方式

第一种:标准映射

规则:

  1. @RequestMapping可以设置在类上,也可以设置在方法上
  2. 请求的映射规则是:类上的RequestMapping + 方法上的RequestMapping
  3. 如果没有写 / ,SpringMVC会自动补全
  4. 类上的RequestMapping可以省略,这时直接用方法的RequestMapping访问
  5. 路径不可重复

第二种:Ant风格映射

Ant风格,其实就是通配符映射,有以下三种方式:

  1. ? 匹配任何单”字符”
    • 匹配0或者任意数量的”字符”
  2. ** 匹配0或者更多的”目录”

第三种:占位符映射

@RequestMapping(value=”/users/{userId}”) :

其中{userId}占位符,请求的 URL 可以是 “/users/123456”或“/users/abcd”

通过@PathVariable 可以提取 URI 模板模式中的{userId}中的userId变量

演示代码如下:

// 演示占位符路径映射@RequestMapping("/show4/{userId}")public ModelAndView show4(@PathVariable("userId") Integer userId) {    ModelAndView mv = new ModelAndView("hello");    mv.addObject("msg", "占位符:" + userId);    return mv;}

第四种:请求方式限定

我们可以通过@RequestMapping注解中的 method属性来限定客户端的请求方式,method属性可以接收的是一个枚举数组

限定post请求方式代码演示如下:

// 演示请求方式的限定@RequestMapping(value = "/only/post", method={RequestMethod.POST})public ModelAndView show5() {    ModelAndView mv = new ModelAndView("hello");    mv.addObject("msg", "请求方式限定,只允许post请求方式访问");    return mv;}

第四种:请求参数限定

我们还可以通过@RequestMapping注解的params属性来对请求的参数进行限定

需求如下:

  1. 限定必须携带参数userid
  2. 限定不能携带参数name
  3. 限定必须携带参数age但是不能等于18
  4. 限定必须携带参数nickname但是必须是lisi

代码演示如下:

// 演示请求参数的限定@RequestMapping(value = "/query", params = { "userid", "!name", "age!=18", "nickname=lisi" })public ModelAndView show6(Integer userid, String name, Integer age, String nickname) {    ModelAndView mv = new ModelAndView("hello");    mv.addObject("msg",            "请求参数限定,您输入的userId:" + userid + "--name:" + name + "--age:" + age + "--nickname" + nickname);    return mv;}

6 . 视图解析

一、什么是视图解析?

视图就是展示给用户看的结果。可以是很多形式,例如:html、JSP、excel表单、Word文档、PDF文档、JSON数据、freemarker模板视图等等。
我们目前比较常用的就是JSP视图了。

二、传统JSP和JSTL视图

我们所使用的InternalResourceViewResolver解析器,默认支持JSP视图,而JSP中最常用的莫过于JSTL标签库了

1.导入JSTL标签库依赖如下:

<dependency>    <groupId>jstl</groupId>    <artifactId>jstl</artifactId></dependency>

2.编写用户的控制器代码如下:

package cn.itcast.controller;import java.util.ArrayList;import java.util.List;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;import cn.itcast.mybatis.pojo.User;@Controller@RequestMapping("user")public class UserController {    @RequestMapping("list")    public ModelAndView getUserList(){        // 创建模型和视图对象        ModelAndView mv = new ModelAndView("user");        // 创建一个集合对象        List<User> users = new ArrayList<User>();        for (Long i = 1L; i <= 10L; i++) {            User user = new User();            user.setId(i);            user.setuserName("lisi" + i);            user.setName("lisi" + (11 - i));            user.setAge(18);            users.add(user);        }        mv.addObject("users",users);        return mv;    }}

3.编写用户视图代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%><%@ 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><style type="text/css">    table {border-collapse: collapse;}      table, th, td {border: 1px solid green;padding: 10px}</style></head><body>    <table>        <tr>            <th>ID</th>            <th>UserName</th>            <th>Name</th>            <th>Age</th>        </tr>        <c:forEach items="${users }" var="user">            <tr>                <td>${user.id }</td>                <td>${user.userName }</td>                <td>${user.name }</td>                <td>${user.age }</td>            </tr>        </c:forEach>    </table></body></html>

4.测试

测试结果OK!

三、JSON视图

在实际开发中,我们经常需要以JSON的格式进行数据的传输,所以在SpringMVC中提供了一种非常便捷的方式来返回一个JSON视图

第一步:引入依赖

SpringMVC的JSON功能,底层依赖的是Jackson这个JSON工具,引入依赖代码如下所示:

<!-- Jackson Json处理工具包 --><dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-databind</artifactId></dependency>

第二步:定义需要访问的Controller

代码如下所示:

// 演示:返回JSON视图@RequestMapping("/ajaxlist")// 这里没有返回ModelAndView,而是通过ResponseBody注解声明,返回的是JSON视图// SpringMVC会自动的把返回值,本例中的是List<User>转为JSON格式返回@ResponseBodypublic List<User> getAjaxUserList(){    // 创建一个集合对象    List<User> users = new ArrayList<User>();    for (Long i = 1L; i <= 10L; i++) {        User user = new User();        user.setId(i);        user.setuserName("lisi" + i);        user.setName("lisi" + (11 - i));        user.setAge(18);        users.add(user);    }    return users;}

第三步:测试

测试结果OK!

第四步:分析原理

  1. 当SpringMVC读取到方法上的@ResponseBody注解时,就知道该方法不再使用默认的视图解析器解析视图,而是直接把结果写到响应体中,这样就需要对结果进行转换
  2. SpringMVC会从框架中查找有没有定义MessageConvertor(消息转换器),通过消息转换器转换结果,返回对应视图
  3. 在SpringMVC的注解驱动类中,会进行默认的消息转换器注册,因为我们引入了jacksonJson包,所以会注册JSON的消息转换器
    注解驱动类中的代码:在AnnotationDrivenBeanDefinitionParser.class中关键点代码如下所示:
    if (jackson2Present) {        RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2HttpMessageConverter.class, source);        GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);        jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);        messageConverters.add(jacksonConverterDef);    }

4 因为只有JSON消息转换器可以对Java对象序列化,因此这里默认用了JSON转换

第五步:问题:如果有多个消息转换的依赖被引入,那么就会注册多个消息转换器:例如JSON、XML等等,此时会用哪个转换器?

答案:此时会根据请求头中的accept来判断返回什么类型数据

四、直接返回视图名称

有时候,我们并不需要返回数据模型,而仅仅是访问某个JSP页面。如果是传统做法,你要创建一个ModelAndView对象,并且返回。很麻烦。

所以,SpringMVC允许直接返回一个String数据,作为视图名称。不需要数据模型,演示代码如下:

// 演示:直接返回视图名称,不需要数据模型@RequestMapping("/index")public String index(){    // 如果只是访问一个页面,就不需要创建ModelAndView对象,直接返回一个字符串    // 这个字符串就会作为视图的名称,从而去访问对应的页面    return "index";}

编写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>欢迎光临首页</h1></body></html>

也可以把视图与模型分离。在参数中注入Model对象:

// 把视图与模型分离。在参数中注入Model对象@RequestMapping("/index2")// 直接返回视图,而不需要model中的数据public String index2(Model model){    model.addAttribute("msg","我试试Model好不好用");    return "hello";}

五、重定向和转发

在SpringMVC中,如果要实现重定向或转发,也非常简单,只需要在返回的字符串前以下面的格式做前缀即可:

redirect:/hello.do 重定向到hello.do

forward:/hello.do 转发到hello.do

注意:后面必须跟上URL路径而非视图名

演示代码如下所示:

// 演示重定向@RequestMapping("/demo1")// 直接返回视图,而不需要model中的数据public String demo1(){    // 返回值以redirect开头,但是后面必须跟上URL路径而非视图名    return "redirect:/user/index.do";}// 演示转发@RequestMapping("/demo2")// 直接返回视图,而不需要model中的数据public String demo2(){    // 返回值以redirect开头,但是后面必须跟上URL路径而非视图名    return "forward:/user/index.do";}

注意:返回ModelAndView,或者没有写redirect和forward时,默认都属于转发

六、不返回视图

有的时候,我们接收一个请求,处理后并不打算给页面返回任何数据,只是返回成功的状态码即可,演示代码如下:

// 演示不返回视图@RequestMapping("/demo3")@ResponseStatus(HttpStatus.OK)// 如果写void,表示不返回模型和视图,那么就需要加ResponseStatus,返回一个响应的状态码public void demo3() {    System.out.println("你好,我收到了你的请求,但是什么也不想做");}

7 . 请求参数绑定和获取

struts2获取参数的弊端:

获取页面参数,是javaee必不可少的一个环节,在struts中,是通过action定义属性,或者modle的方式进行数据绑定和获取,需要提供setter和getter方法,略显麻烦

SpringMVC获取参数的优点:

在SpringMVC中,却可以非常方便的获取请求参数,只需要在对应方法的参数列表中定义出来,即可获取,所见即所得!

原创粉丝点击