SpringMVC学习总结

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注解表名当前类是一个控制器类
@Controller
public 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格式返回
@ResponseBody
public 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中,却可以非常方便的获取请求参数,只需要在对应方法的参数列表中定义出来,即可获取,所见即所得!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值