Spring MVC初体验

Spring MVC介绍

什么是Spring MVC

  • Spring MVC是Spring体系的轻量级Web MVC框架
  • Spring MVC的核心Controller控制器,用于处理请求,产生响应
  • Spring MVC基于Spring IOC容器运行,所有对象被IOC管理

Spring 5.x 版本变化

  • Spring 5.x最低要求JDK8与J2EE(Servlet 3.1/Tomcat 8.5)
  • Spring 5.x支持JDK8/9,可以使用新特性
  • Spring 5.x最重要的新特性支持响应式编程

spring MVC官网介绍

创建Maven WebApp

  1. 创建webapp目录

选中项目根目录,File => Project Structure => Facets => add => Web => 填写配置 => OK
=> 自动创建src/main/webapp目录
image.png

  1. 配置Template的Local Tomcat Server

Edit Configurations => Templates => Tomcat Server
#Application server中是Tomcat的存放路径
image.png

MAC安装Tomcat

  1. 使用Template的Local Tomcat Server

Edit Configurations => add => 选择Tomcat Server / local
image.png
image.png

Spring MVC环境配置

  1. Maven依赖spring-webmvc

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.song</groupId>
  7. <artifactId>spring_mvc_first</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <!-- 引入阿里云镜像仓库 -->
  10. <repositories>
  11. <repository>
  12. <id>aliyun</id>
  13. <name>aliyun</name>
  14. <url>https://maven.aliyun.com/repository/public</url>
  15. </repository>
  16. </repositories>
  17. <dependencies>
  18. <dependency>
  19. <groupId>org.springframework</groupId>
  20. <artifactId>spring-webmvc</artifactId>
  21. <version>5.1.9.RELEASE</version>
  22. </dependency>
  23. </dependencies>
  24. </project>
  1. web.xml配置DispatcherServlet

src/main/webapp/WEB_INF/web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  5. version="3.1">
  6. <!-- DispatchServlet -->
  7. <!--
  8. DispatchServletSpring MVC最核心的对象
  9. DispatchServlet用于拦截Http请求,
  10. 并根据请求的URL调用与之对应的Controller方法,来完成HTTP请求的处理
  11. -->
  12. <servlet>
  13. <servlet-name>springmvc</servlet-name>
  14. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  15. <!-- applicationContext.xml -->
  16. <init-param>
  17. <param-name>contextConfigLocation</param-name>
  18. <param-value>classpath:applicationContext.xml</param-value>
  19. </init-param>
  20. <!-- Web应用启动时自动创建Spring IOC容器,并初始化DispatcherServlet -->
  21. <load-on-startup>0</load-on-startup>
  22. </servlet>
  23. <servlet-mapping>
  24. <servlet-name>springmvc</servlet-name>
  25. <!-- "/"代表拦截所有请求 -->
  26. <url-pattern>/</url-pattern>
  27. </servlet-mapping>
  28. </web-app>

src/main/resources/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mv="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 标签作用
    在Spring IOC初始化过程中,自动创建并管理com.song.springmvc及子包中
    拥有以下注解的对象.
    @Repository
    @Service
    @Controller
    @Component
    -->
    <context:component-scan base-package="com.song.springmvc"></context:component-scan>

    <!--启用Spring MVC的注解开发模式-->
    <mvc:annotation-driven/>

    <!-- 将图片/JS/CSS等静态资源排除在外,可提高执行效率 -->
    <mvc:default-servlet-handler/>
</beans>
  1. 添加依赖到发布目录

虽然在pom.xml中增加了springmvc依赖,但是默认情况下这些依赖不会自动增加到发布的目录(WEB-INF)中,所以需要手动指向到WEB-INF中
操作:Edit Configurations => Deployment => edit => 选择以下依赖包 => 右键选择”Put into/WEB-INF/lib”
image.png

  1. 测试

src/main/java/com.song.springmvc.controller

package com.song.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {
    @GetMapping("/t")   // localhost:8080/t
    @ResponseBody       // 直接向响应输出字符串数据,不跳转页面
    public String test(){
        return "SUCCESS";
    }
}

结果:localhost:8080/t页面显示”SUCCESS”

总结:
在以前开发的时候,都使用servlet进行web请求的处理,但是servlet在很多时候并不好用,而Spring MVC简化了web处理过程。
在以上例子中,可以把TestController当初原有servlet的替代品,不需要引人servlet的请求响应对象,只需要添加对应的注解就可以了。

image.png

MVC数据绑定

URL Mapping(URL映射)

URL Mapping概念:

  • URL Mapping指将URL与Controller方法绑定
  • 通过将URL与方法绑定,SpringMVC便可通过Tomcat对外暴露服务

URL Mapping注解:

一般放在类中,用于设置地址前缀

import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;

@Controller @RequestMapping(“/um”) public class URLMappingController { @GetMapping(“/get”) @ResponseBody public String getMapping() { return “This is get method”; }

@PostMapping("/post")
@ResponseBody
public String postMapping() {
    return "This is post method";
}

}


<a name="5btS7"></a>
#### Controller方法参数接受参数
src/main/com/song/springmvc/controller<br />#@RequestParam,可以解决参数名不一致的问题(下划线和驼峰的适配)
```java
package com.song.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/um")
public class URLMappingController {
    @GetMapping("/get")
    @ResponseBody
    public String getMapping(@RequestParam("manager_name") String managerName) {
        System.out.println("managerName:" + managerName);
        return "This is get method";
    }

    @PostMapping("/post")
    @ResponseBody
    public String postMapping(String username, Long password) {
        System.out.println(username + ":" + password);
        return "This is post method";
    }
}

Controller实体对象接受参数

src/main/java/com/song/springmvc/entity/User.java

package com.song.springmvc.entity;

public class User {
    private String username;
    private Long password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getPassword() {
        return password;
    }

    public void setPassword(Long password) {
        this.password = password;
    }
}
package com.song.springmvc.controller;

import com.song.springmvc.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("/um")
public class URLMappingController {

    @PostMapping("/post2")
    @ResponseBody
    public String postMapping2(User user){
        System.out.println(user.getUsername() + ":" + user.getPassword());
        return "This is post method";
    }
}

接受表单复合数据

  • @RequestParam,可以指定默认值
  • List和Map接受参数,必须用@RequestParam修饰
  • 建议使用List接受复合数据,而Map无法接受复合数据 ```java package com.imooc.springmvc.controller;

import com.imooc.springmvc.entity.Form; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; import java.util.Map;

@Controller public class FormController { // @PostMapping(“/apply”) @ResponseBody public String apply(@RequestParam(value = “n”,defaultValue = “ANON”) String name, String course, Integer[] purpose){ System.out.println(name); System.out.println(course); for (Integer p : purpose) { System.out.println(p); } return “SUCCESS”; }

// @PostMapping(“/apply”) @ResponseBody public String apply(String name, String course, @RequestParam List purpose){ System.out.println(name); System.out.println(course); for (Integer p : purpose) { System.out.println(p); } return “SUCCESS”; }

// @PostMapping(“/apply”) @ResponseBody public String apply(Form form){ return “SUCCESS”; } @PostMapping(“/apply”) @ResponseBody public String apply(@RequestParam Map map){ System.out.println(map); return “SUCCESS”; } }


<a name="tij8b"></a>
#### 关联对象赋值
前端传递参数:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/330066/1590391587128-27cf3588-7268-410d-ab4a-01108bc720a8.png#align=left&display=inline&height=125&margin=%5Bobject%20Object%5D&name=image.png&originHeight=250&originWidth=1298&size=324337&status=done&style=none&width=649)<br />后端接受对象:<br />delivery是Form对象中的一个关联对象,Spring MVC会自动赋值<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/330066/1590391612667-bb9572fa-4edd-4c35-a379-ffdd0a69a6da.png#align=left&display=inline&height=248&margin=%5Bobject%20Object%5D&name=image.png&originHeight=496&originWidth=990&size=237764&status=done&style=none&width=495)

<a name="NJx1Y"></a>
#### 日期类型转换

1. 利用@DateTimeFormat注解

方法参数接受
```java
    @PostMapping("/p1")
    @ResponseBody
    public String postMapping1(User user , String username ,@DateTimeFormat(pattern = "yyyy-MM-dd") Date createTime){
        System.out.println(user.getUsername() + ":" + user.getPassword());
        return "<h1>这是Post响应</h1>";
    }

实体对象接受

package com.imooc.springmvc.entity;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Date;

public class User {

    private String username;
    private Long password;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createTime;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Long getPassword() {
        return password;
    }

    public void setPassword(Long password) {
        this.password = password;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}
  1. 全局日期转换器

每个地方都用日期注解去转换会很麻烦,我们就可以设置一个全局日期转换器来解决这个问题
#全局日期转换器和日期注解转换只能两者选一个

src/main/java/com/song/springmvc/converter/MyDateConverter.java

package com.imooc.springmvc.converter;

import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyDateConverter implements Converter<String, Date> {
    public Date convert(String s) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        <!-- 如果有多中日期格式,这里需要处理一下 -->
        <!-- 比如如果长度是8为的话,就采用yyyyMMdd的形式等 -->
        try {
            Date d = sdf.parse(s);
            return d;
        } catch (ParseException e) {
            return null;
        }
    }
}

src/main/resources/applicationContext.xml

    <!--启用Spring MVC的注解开发模式-->
    <mvc:annotation-driven conversion-service="conversionService"/>

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.imooc.springmvc.converter.MyDateConverter"/>
            </set>
        </property>
    </bean>

中文乱码问题解决

Web应用的中文乱码由来

  • Tomcat默认使用字符集ISO-8859-1,属于西欧字符集
  • 解决乱码的核心思路是将ISO-8859-1转换为UTF-8
  • Controller中请求与相应都需要设置UTF-8字符集

中文乱码的配置

  • Get请求乱码:tomcat的server.xml增加URIEncoding属性

tomcat/conf/server.xml

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8" />

tomcat8.0以后的版本可以不用设置,因为默认就是UTF-8

  • Post请求乱码:web.xml配置CharacterEncodingFilter

webapp/WEB-INF/web.xml

    <filter>
        <filter-name>characterFilter</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>characterFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • Response响应乱码:Spring配置StringHttpMessageConverter

src/main/resources/applicationContext.xml

    <!--启用Spring MVC的注解开发模式-->
    <mvc:annotation-driven conversion-service="conversionService">
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <!-- response.setContentType("text/html;charset=utf-8") -->
                        <value>text/plain;charset=utf-8</value>
                        <value>text/html;charset=utf-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

响应输出

ResponseBody - 产生响应文本

ModelAndView - 利用模板引擎渲染输出

  • ModelAndView对象是指”模型(数据)与视图(界面)”对象
  • 通过ModelAndView可将包含数据对象与模板引擎进行绑定
  • SpringMVC默认的Vive是JSP,也可以配置其他模板引擎
    @GetMapping("/view")
      public ModelAndView showView(Integer userId){
    //        ModelAndView mav = new ModelAndView("redirect:/view.jsp");
          ModelAndView mav = new ModelAndView();
          mav.setViewName("/um/view.jsp");
          User user = new User();
          if(userId == 1){
              user.setUsername("lily");
          }else if(userId == 2){
              user.setUsername("smith");
          }else if(userId == 3){
              user.setUsername("lina");
          }
          mav.addObject("u" , user);
          return mav;
      }
      //String与ModelMap
      //Controller方法返回String的情况
      //1. 方法被@ResponseBody描述,SpringMVC直接响应String字符串本身
      //2. 方法不存在@ResponseBody,则SpringMVC处理String指代的视图(页面)
      @GetMapping("/xxxx")
    //    @ResponseBody
      public String showView1(Integer userId , ModelMap modelMap){
          String view = "/um/view.jsp";
          User user = new User();
          if(userId == 1){
              user.setUsername("lily");
          }else if(userId == 2){
              user.setUsername("smith");
          }else if(userId == 3){
              user.setUsername("lina");
          }
          modelMap.addAttribute("u", user);
          return view;
      }
    

ModelAndView对象核心用法

。。。省略。。。

Spring MVC整合FreeMarker

。。。省略。。。