SpringMVC(一)基本原理、使用、参数接收

MVC模式

MVC指的是模型(model)-视图(view)-控制器(controller)模型,是一种用于设计创建Web应用程序表现层的模式。可以将业务逻辑、数据、界面显示代码分离开来。

image.png
  • 三层架构-mvc


    image.png

SpringMVC

SpringMVC是Spring产品对MVC模式的一种具体实现,属于轻量级的WEB框架,可以通过一套注解,让一个简单的Java类称为控制器。而无须实现任何接口,同时还支持restful风格


image.png

SpringMVC主要工作的组件有:

  • 前端控制器
  • 处理器映射器
  • 处理器适配器

SpringMVC入门案例

  • 加入坐标
 <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>

        </dependency>


    </dependencies>
  • SpringMVC配置文件 spring-mvc.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.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--    配置注解扫描-->
    <context:component-scan base-package="com.itheima.controller"/>
    <!--    配置组件-->
    <!--    配置处理器映射器和处理器适配器-->
    <mvc:annotation-driven/>
    <!--    配置视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
</beans>
  • web.xml
<?xml version="1.0" encoding="utf-8"?>
<web-app version="3.0"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--        配置参数-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!--        除了jsp不拦截-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • 后端controller
@Controller
public class HelloController {
    @RequestMapping("/helloServlet/demo1")
    public String demo1() {
        System.out.println("hello1");
        return "/success.jsp";
    }
}
  • 请求页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/helloServlet/demo1">入门案例</a>

</body>
</html>
  • 响应页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
Success
</body>
</html>

SpringMVC原理

image.png
  • 当用户通过浏览器发送一个请求会被前端控制器DispatcherServlet接收
  • DispathcerServlet接收请求后会调用处理器映射器HandlerMapper
  • HandlerMapper会找到具体的处理器链返回给DispatcherServlet
  • DispatcherServlet会根据收到返回的处理器链调用处理器适配器HandlerAdapter
  • HandlerAdapter经过适配后会调用具体的Controller
  • Controller执行完成后会返回一个执行结果
  • HandlerAdapter将Handler的结果ModelAndView对象返还给DispatcherServlet
  • DispatcherServlet将ModelAndView对象传给视图解析器ViewReslover
  • ViewReslover解析后得到具体的View,并返回给DispatcherServlet
  • DispatcherServlet根据ViewReslover返回的View进行视图渲染。将模型数据填充到视图中
  • DispathcerServlet会将渲染后的视图响应给浏览器

SpringMVC三大组件

  • 处理器映射器 HandlerMapper

根据请求中的URL寻找对应的处理方法

  • 处理器适配器

真正的去调用处理方法

  • 视图解析器

将逻辑视图转化成物理视图

配置视图解析器

 <!--    配置视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        配置前缀-->
        <property name="prefix" value="/"/>
<!--        配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

RequestMapping

RequestMapping用于建立请求URL和处理方法之间的对应关系,可以通过它的属性对请求做出各种限制

  • value:用于限制请求URL(和path作用一样),可以传递多个url @RequestMapping(value={url1,url2})
  • method:用于限制请求类型 get post 支持多个,如果不写表示不做限制
  • Params:用于限制请求参数的条件 用于限制必传参数,支持数组
@RequestMapping("/helloServlet/demo1")
    public String demo1() {
        System.out.println("hello1");
        return "success";
    }

此注解可以标注在方法上,也可以标注在类上,标注在类上代表类中的所有方法都可以共用一段URL

限制请求路径(value path)

  • 前台页面
<a href="${pageContext.request.contextPath}/helloServlet/demo2">指定请求路径</a>

  • 后台
@RequestMapping("/helloServlet/demo2")
    public String demo2() {
        System.out.println("指定请求路径为:/helloServlet/demo2");
        return "success";
    }

限制请求类型(method)

限制只能是post方式请求,如果不是指定的请求方式 将会抛出405异常

  • 页面
<form action="helloServlet/demo3" method="post">
    <input type="submit" value="限制请求方式">
</form>
  • 后台
 @RequestMapping(value = "/helloServlet/demo3",method = RequestMethod.POST)
    public String demo3() {
        System.out.println("限制请求类型");
        return "success";
    }

限制请求参数(params)

  • 页面
 <a href="${pageContext.request.contextPath}/helloServlet/demo4?name=zs">指定请求的参数</a>

  • 后台

表示必须传递name参数

 @RequestMapping(value = "/helloServlet/demo4", params = "name")
    public String demo4() {
        return "success";
    }

接收请求参数

在SpringMVC中可以使用多种类型来接收前端传入的参数

简单类型

基本类型、基本类型的包装类、字符串类型

只需要保证前端传递的参数名称跟方法的形参名称一致就好

  • 页面
<a href="${pageContext.request.contextPath}/helloServlet/demo5?name=zs&age=18">接收简单类型参数</a>

  • 后台
@RequestMapping(value = "/helloServlet/demo5")
    public String demo5(String name, Integer age) {
        System.out.println("name = " + name);
        System.out.println("age = " + age);
        return "success";
    }

对象类型

只要保证前端传递的参数名称和pojo的属性名称(set方法)一致

  • 前台
<a href="${pageContext.request.contextPath}/helloServlet/demo6?name=ss&age=20">接收对象类型</a>

  • 后台
 @RequestMapping("/helloServlet/demo6")
    public String demo6(User user) {
        System.out.println("user = " + user);
        return "success";
    }

数组类型

需要保证前端传递的参数名称和方法中的数组形参名称一致

  • 页面
<a href="${pageContext.request.contextPath}/helloServlet/demo7?username=zz&username=zz2&username=zz3">传递数组类型</a>

  • 后台
   @RequestMapping("/helloServlet/demo7")
    public String demo7(String[] username) {
        for (String s : username) {
            System.out.println(s);
        }
        return "success";
    }

集合类型

获取集合类型的参数时,需要提供一个pojo对象,SpringMVC会将集合包装到pojo对象中

  • 页面
<form action="${pageContext.request.contextPath}/helloServlet/demo8" method="post">
    第一个user.name <input type="text" name="users[0].name"/><br/>
    第一个user.age <input type="text" name="users[0].age"/><br/>
    第二个user.name <input type="text" name="users[1].name"/><br/>
    第二个user.age <input type="text" name="users[1].age"/><br/>
    第三个user.name <input type="text" name="users[2].name"/><br/>
    第三个user.age <input type="text" name="users[2].age"/><br/>
    <input type="submit" value="传递集合"/>
</form>
  • 封装vo对象
public class Vo {
    private List<User> users;
    private Map<String, String> map;

    @Override
    public String toString() {
        return "Vo{" +
                "users=" + users +
                ", map=" + map +
                '}';
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }
}
  • 后台controller
 @RequestMapping("/helloServlet/demo8")
    public String demo8(Vo vo) {
        List<User> users = vo.getUsers();
        users.stream().forEach(user -> System.out.println(user));
        return "success";
    }

日期类型

对于一些常见的类型,SpringMVC是内置了类型转换器,也就是说在内置中存在一个类型转换器,可以自动转换基本类型,但是对于一些类型的参数,无法完成类型转换。这时候就必须自定义类型转换器了

  • 页面
  • 自定义时间类型转换器

    自定义类型转换器需要实现Converter<S,D>接口

    • S:代表需要转换的源Source类型
    • D:代表转换后的目标类型
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        return new SimpleDateFormat("yyyy-MM-dd").parse(s);
    }
}
  • 配置类型转换器 spring-mvc.xml

将自定义的类型转换器注册SpringMVC的转换服务,并且将服务注册到注解驱动上

 <mvc:annotation-driven conversion-service="conversionService2"/>
    <!--    配置视图解析器-->
    <!--    配置自定义类型转换器-->
    <bean id="conversionService2" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <!--                指定自定义类型转换器-->
                <bean class="com.itheima.converters.DateConverter"/>
            </set>
        </property>
    </bean>
  • 后台
  @RequestMapping("/helloServlet/demo9")
    public String demo9(Date date) {
        System.out.println(date);
        return "success";
    }

文件类型(文件上传)

  • 配置文件上传用的坐标
<dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
  • 配置文件上传解析器

    <!--    配置文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5242880"/>
    </bean>
    
  • 页面

    • post提交
    • 多部分表单 part-form
    • type=file
<%--文件上传--%>
<form action="${pageContext.request.contextPath}/helloServlet/demo10" method="post"
      enctype="multipart/form-data"
>
    <input type="file" name="upFile"/><br/>
    <input type="submit" value="上传">
</form>
  • 后台
@RequestMapping("/helloServlet/demo10")
public String demo10(MultipartFile upFile) throws IOException {
    //获取名字 重新命名
    String newFileName = UUID.randomUUID() + upFile.getOriginalFilename();
    String saveFilePath = "/Users/wangxin/Documents/temp";
    File uploadFile = new File(saveFilePath, newFileName);
    //接收上传文件
    upFile.transferTo(uploadFile);
    return "success";
}

多文件上传

  • 页面

多文件上传 需要在<input type="file">标签中添加multiple属性

多文件上传:
<form method="post" action="${pageContext.request.contextPath}/helloServlet/demo11" enctype="multipart/form-data">
    <input type="file" multiple/>
    <input type="submit" value="提交">
</form>
  • 后台 多文件上传 后台需要接收MultiPartFile数组
@RequestMapping("helloServlet/demo11")
public String demo11(MultipartFile[] upFiles) throws IOException {
    String saveFilePath = "/Users/wangxin/Documents/temp";

    for (MultipartFile file : upFiles) {
        String newFileName = UUID.randomUUID() + file.getOriginalFilename();
        File uploadFile = new File(saveFilePath, newFileName);
        //文件上传
        file.transferTo(uploadFile);
    }
    System.out.println("文件上传完毕");
    return "success";
}
文件上传原理

在前端控制器(DispatcherServlet)有一个属性叫做multipartResolver,它对应着一个文件上传解析器

当SpringMVC启动的时候,它就会在容器中寻找是否有一个id位multipartResolver的bean,如果有那么会将文件上传的文件交给指定的文件解析器来做。

当DispathcerServlet调用controller方法的时候就可以将MultipartFile作为参数传进去了

在Controller中就可以操作MultiPartFIle对象进行文件的操作

接收参数的处理

中文乱码

SpringMVC在使用POST提交请求时,对于中文参数会存在乱码问题,我们可以使用SpringMVC提供的中文乱码过滤器

  • 前端

通过form表单的post请求提交中文

<%--提交中文乱码--%>
<br/>
<form action="${pageContext.request.contextPath}/helloServlet/demo12" method="post">
    姓名:<input type="text" name="username"/>
</form>

  • 配置 编码过滤器
    <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 后台

  • @RequestMapping("/helloServlet/demo12")
    public String demo12(String username) {
        System.out.println("接收到的参数:" + username);
        return "success";
    }
    
@RequestParam

@RequestParam标注在方法参数之前,用于对传入的参数做一些限制,支持三个属性:

  • Value:用于指定前端传入的参数名称
  • required:用于指定此参数是否必传,默认是true
  • defaultValue:当参数为非必传参数设置一个默认值
  • 前台
<a href="${pageContext.request.contextPath}/helloServlet/demo13?username=达到">前端参数对应</a>

  • 后台
 @RequestMapping("/helloServlet/demo13")
    public String demo13(@RequestParam("username") String name) {
        System.out.println(name);
        return "success";
    }

接收请求头信息

接收请求头,使用

  • @RequestHeader 前端控制器会将所有的请求头封装成一个Map结构传递过来
  • @RequestHeader("key") 接收指定的请求头
  • @CookieValue("key") 接收一个Cookie中的值
@RequestMapping("/helloServlet/demo14")
    public String demo14(
            @RequestHeader Map<String, String> headMap,
            @RequestHeader("cookie") String cookieKey,
            @CookieValue("JSESSIONID") String jSessionId
    ) {
        System.out.println(headMap);
        System.out.println(cookieKey);
        System.out.println(jSessionId);
        return "success";
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270