SpringMVC

SpringMVC是目前主流的实现MVC设计模式的框架,是Spring框架的一个分支产品,以SpringIoC容器为基础,并且利用容器的特性来简化它的配置,SpringMVC相当于Spring的一个子模块,可以很好的和Spring结合起来进行开发,是JavaWeb开发者必须掌握的框架

什么是MVC

  1. 将应用程序分为Controller, Model, View三层, Controller接收客户端请求,调用Model生成业务数据,传递给View.
  2. SpringMVC就是对这套流程的封装,屏蔽了许多底层代码,开放出接口,让开发者可以更加轻松,便捷的完成基于MVC模式的Web开发.

Spring MVC的核心组件

1 DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥.

2 Handler: 处理器,完成具体的业务逻辑,相当于Servlet或Action

3 HandlerMapping: DispatherServlet 接收到请求之后,通过HandlerMapping将不同的请求映射到不同的Handler

4 HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口

5 HandlerExecutionChain:处理器执行链.包括两部分内容:Handler 和HandlerInterceptor(系统会有一个默认的HandlerInterceptor ,如果需要额外设置拦截,可以添加拦截器)

6 HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作,包括表单数据的验证,数据类型的转换,将表单数据封装到JavaBean等,这些操作都是由HandlerApater来完成,开发者只需要将注意力集中到业务逻辑的处理上,DispatcherServlet通过HandlerAdapter执行不同的Handler

7 ModelAndView:装载了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet

8 ViewResolver:视图解析器,DispatherServlet通过它将逻辑视图解析为物理视图,最终将渲染结果响应给客户端

Spring MVC基本工作流程

1 客户端请求被DispatcherServlet接受

2 根据HandlerMapping映射到Handler

3 生成Handler和HandlerInterceptor

4 Handler和H按到了人Interceptor以HandlerExcutionChain的形式一并返回给 DispatcherServlet

5 DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑处理

6 Handler返回一个ModelAndView给DispatcherServlet

7 DispatcherServlet将获取的ModelAndView对象传给ViewResolver视图解析器,将逻辑视图解析为物理视图View

8 ViewResolver返回一个View给DispatcherServlet

9 DispatcherServlet根据View进行视图渲染(将模型数据Model填充到试图View中)

10 DispatcherServlet将渲染完的视图传递给客户端

Spring MVC流程非常复杂,实际开发中很简单,因为大部分组件不需要开发者创建管理,只需要通过配置文件的方式完成配置即可,真正需要开发者进行处理的只有Handler和View

一, 如何使用?

1 创建Maven工程, pom.xml

  1. 添加Spring MVC依赖
  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework</groupId>
  4. <artifactId>spring-webmvc</artifactId>
  5. <version>5.0.11.RELEASE</version>
  6. </dependency>
  7. </dependencies>

2 在web.xml中配置DispatcherServlet

  1. <!DOCTYPE web-app PUBLIC
  2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
  4. <web-app>
  5. <display-name>Archetype Created Web Application</display-name>
  6. <servlet>
  7. <servlet-name>dispatcherServlet</servlet-name>
  8. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  9. <init-param>
  10. <param-name>contextConfigLocation</param-name>
  11. <param-value>classpath:springmvc.xml</param-value>
  12. </init-param>
  13. </servlet>
  14. <servlet-mapping>
  15. <servlet-name>dispatcherServlet</servlet-name>
  16. <url-pattern>/</url-pattern>
  17. </servlet-mapping>
  18. </web-app>

3 springmvc.xml

  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/mvc
  8. http://www.springframework.org/schema/mvc/spring-mvc.xsd
  9. http://www.springframework.org/schema/context
  10. http://www.springframework.org/schema/context/spring-context.xsd
  11. http://www.springframework.org/schema/aop
  12. http://www.springframework.org/schema/aop/spring-aop.xsd
  13. ">
  14. <!-- -->
  15. <!--自动扫描 -->
  16. <context:component-scan base-package="com.wwjapex"></context:component-scan>
  17. <!--视图解析器 -->
  18. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  19. <property name="prefix" value="/"></property>
  20. <property name="suffix" value=".jsp"></property>
  21. </bean>
  22. </beans>

4 创建Handler

  1. package com.wwjapex.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. public class HelloHandler {
  6. @RequestMapping("/index")
  7. public String index(){
  8. System.out.println("执行了index");
  9. return "index";
  10. }
  11. }

二 Spring MVC注解

1 @RequestMapping

  1. Spring MVC通过@RequestMapping注解将URL请求与业务方法进行映射,在Handler的类定义处以及方法定义处都可以添加[@RequestMapping ](/RequestMapping ) , 在类的定义处添加,就相当于客户端多了一层访问路径.

2 @Controller

  1. [@Controller ](/Controller ) 在类的定义处添加,将该类交给IoC容器来管理(结合springmvc.xml中的自动扫描配置使用),同时使其成为一个控制器,可以接收客户端请求
  1. package com.wwjapex.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. @RequestMapping("/hello")
  6. public class HelloHandler {
  7. @RequestMapping("/index")
  8. public String index(){
  9. System.out.println("执行了index");
  10. return "index";
  11. }
  12. }

3 @RequestMapping相关参数

  1. (1), **value** :指定URL请求的实际地址,也是@RequestMapping的默认值.
  1. @RequestMapping("/index")
  2. public String index(){
  3. System.out.println("执行了index");
  4. return "index";
  5. }
  1. 等于
  1. @RequestMapping(value="/index")

(2) method : 指定请求的method类型, GET , POST , PUT , DELET .

  1. @RequestMapping(value = "/index",method = RequestMethod.GET)
  2. public String index(){
  3. System.out.println("执行了index");
  4. return "index";
  5. }

上述代码表示index方法只能接受GET请求

(3) params : 指定请求中必须包含某些参数,否则无法调用方法

  1. @RequestMapping(value = "/index",method = RequestMethod.GET, params = {"name","id=1"})
  2. public String index(String name){ //形参
  3. System.out.println("用户名:"+name);
  4. System.out.println("执行了index");
  5. return "index";
  6. }

上述代码表示请求中必须包含name和id两个参数,同时id 的值必须是1 .

参数绑定

关于参数绑定,在形参列表中通过添加@RequestParam注解完成HTTP请求参数业务方法形参的映射

  1. @RequestMapping(value = "/index",method = RequestMethod.GET, params = {"name","id=1"})
  2. public String index(@RequestParam("name") String str, @RequestParam("id") int inx){
  3. //当参数名字和形参名字不同时,需要添加@RequestParam注解
  4. System.out.println("用户名:"+str);
  5. System.out.println("id:"+inx);
  6. System.out.println("执行了index");
  7. return "index";
  8. }

上述代码表示将请求的参数name和id分别付给形参str 和 age ,同时自动完成了数据类型转换,将”1”转为了int类型,再付给age,这些工作都是由HandlerAdapter来完成的

Spring MVC也支持RESTful风格的URL.

传统类型: http//localhost:8080/hello/index?name=”吴文杰”&id=1

REST: http://localhost:8080/hello/index/"吴文杰"/1

  1. @RequestMapping("/rest/{name}/{id=10}")
  2. public String rest(@PathVariable("name") String name, @PathVariable("id=10") int id){
  3. System.out.println(name+id);
  4. return "index";
  5. }

REST结构下,必须要通过 @PathVariable () 注解 完成请求参数与形参的映射

映射cookie

Spring MVC通过映射可以直接在业务方法中获取Cookie的值

  1. @RequestMapping("/cookie")
  2. public String cookie(@CookieValue(value ="JSESSIONID" ) String sessionid){
  3. System.out.println(sessionid);
  4. return "index";
  5. }

使用JavaBean绑定参数

Spring MVC会根据请求参数名和JavaBean属性名进行自动匹配,自动为对象填充属性值,同时支持及联属性

register.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. <form action="/hello/save" method="post">
  8. 用户id:<input type="text" name="id"/><br>
  9. 用户名:<input type="text" name="name"/><br>
  10. 用户地址:<input type="text" name="address.value"/><br>
  11. <input type="submit" value="注册">
  12. </form>
  13. </body>
  14. </html>

User

  1. @Data
  2. public class User {
  3. private long id;
  4. private String name;
  5. private Address address;
  6. }

Address

  1. @Data
  2. public class Address {
  3. private String value;
  4. }

Handler

  1. @RequestMapping(value = "/save",method = RequestMethod.POST)
  2. public String save(User user){
  3. System.out.println(user);
  4. return "index";
  5. }

中文乱码 web.xml

如果出现中文乱码的情况,需要在web.xml中添加Spring MVC自带的过滤器即可

  1. <filter>
  2. <filter-name>encodingFilter</filter-name>
  3. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  4. <init-param>
  5. <param-name>encoding</param-name>
  6. <param-value>utf-8</param-value>
  7. </init-param>
  8. </filter>
  9. <filter-mapping>
  10. <filter-name>encodingFilter</filter-name>
  11. <url-pattern>/*</url-pattern>
  12. </filter-mapping>

JSP页面的转发和重定向:

Spring MVC默认是以转发的形式来响应jsp,

1,转发
@RequestMapping("/forward")
public String forward(){
    return "forward:/index.jsp";
    //return "index";
}
2,重定向
@RequestMapping("/redirect")    //重定向
public String redirect(){
    return "redirect:/index.jsp";
}

三 Spring MVC数据绑定

数据绑定:在后端的业务方法中直接获取客户端HTTP请求中的参数,将请求参数映射到业务方法的形参中,    Spring MVC中数据绑定的工作是由HandlerAdapter来完成的

1 基本数据类型

@RequestMapping("/baseType")
@ResponseBody  //直接将数据返回客户端
public String baseType(int id){
    return id+"";
}
[@ResponseBody ](/ResponseBody )    表示Spring MVC会直接将业务方法的返回值响应给客户端,如果不加@ResponseBody注解,Spring MVC会将业务方法的返回值传递给DispatcherServlet, 再由DispathcerServlet调用ViewResolver对返回值进行解析,映射到一个JSP资源. 

基本数据类型不能接受null值

2 包装类

    @RequestMapping("/packageType")
    @ResponseBody
    public String packageType(@RequestParam(value = "num" ,required = false, defaultValue = "0") Integer id){
        return id+"";
    }
包装类可以接受null, 当HTTP请求没有参数时, 使用包装类定义形参的数据类型, 程序不会抛出异常.

@RequestParam

value = "num"     :将HTTP请求中名为num的参数赋给形参id

requried    :设置num是否为必填项,true表示必填,false表示非必填,可省略.

defaultValue="0"    :如果HTTP请求中没有num参数,默认值为0.

3 数组

@RestController//表示当前controller里的值都是默认以rest形式返回,不会去解析
@RequestMapping("/data")
public class DataBinHandler {

    @RequestMapping("/array")
    public String array(@RequestParam("name") String[] name)    {    String str = Arrays.toString(name);
        return str+"";
    }
}

@RestController表示该控制器会直接将业务方法的返回值响应给客户端,不进行视图解析

@Controller表示该控制器的每一个业务方法的返回值都会交给视图解析器进行解析,如果只需要将数据响应给后端,而不需要视图解析,则需要在对应的业务方法定义处添加@ResponseBody

@Controller
@RequestMapping("/data")
public class DataBinHandler {
    @RequestMapping("/array")
    @ResponseBody
    public String array(@RequestParam("name") String[] name){
        String str = Arrays.toString(name);
        return str+"";
    }

}

等同于

@RestController
@RequestMapping("/data")
public class DataBinHandler {
    @RequestMapping("/array")
    public String array(@RequestParam("name") String[] name)    {    String str = Arrays.toString(name);
        return str+"";
    }
}

4 List集合

Spring MVC不支持List类型的直接转换, 需要对List集合进行包装

集合封装类

@Data
public class UserList {
    private List<User> users;
}

JSP文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/data/list" method="post">
        用户1编号: <input type="text" name="users[0].id"/><br>
        用户1名称: <input type="text" name="users[0].name"/><br>
        用户2编号: <input type="text" name="users[1].id"/><br>
        用户2名称: <input type="text" name="users[1].name"/><br>
        用户3编号: <input type="text" name="users[2].id"/><br>
        用户3名称: <input type="text" name="users[2].name"/><br>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

业务方法

@RequestMapping("/list")
public String list(UserList userList){
    StringBuffer str =new StringBuffer();
    for (User user:userList.getUsers()){
        str.append(user);
    }
    return str.toString();
}

处理@ResponseBody 中文乱码

如果出现中文乱码,需要在springmvc.xml中配置消息转换器

<mvc:annotation-driven>
    <!--消息转换器 -->
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

5 Map

自定义封装类

@Data
public class UserMap {
    private Map<String,User> users;
}

业务方法

@RequestMapping("/map")
public String map(UserMap userMap){
    StringBuffer str = new StringBuffer();
    for (String key:userMap.getUsers().keySet()){
        User user = userMap.getUsers().get(key);
        str.append(user);
    }
    return str.toString();
}

JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/data/map" method="post">
        用户1编号: <input type="text" name="users['a'].id"/><br>
        用户1名称: <input type="text" name="users['a'].name"/><br>
        用户2编号: <input type="text" name="users['b'].id"/><br>
        用户2名称: <input type="text" name="users['b'].name"/><br>
        用户3编号: <input type="text" name="users['c'].id"/><br>
        用户3名称: <input type="text" name="users['c'].name"/><br>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

6 JSON

客户端发送JSON格式的数据, 直接通过Spring MVC绑定到业务方法的形参中.

1