[TOC]

简介

MVC 是一种架构模式,模型,视图,控制器。
控制器接收视图中所传入的数据,根据数据调用后端的业务逻辑得到结果,再通过控制器返回视图。
视图和控制器没有直接的连接关系,一切都是通过控制器连接和返回。
Servlet 就是用于开发控制器的技术
Spring MVC 要比 Servlet 开发更高效。
Spring MVC 基于 Spring IOC 容器运行,所有对象被 IOC 管理。

版本

Spring版本: 5.x
最低要求: JDK8 与 J2EE 7(Servlet3.1+、Tomcat 8.5+)
支持: JDK8+,响应式编程(一种编程理念或风格,专注于构建对事件做出响应的应用程序)

IDE:IDEA

返回 Hello World

创建工程

  • Create New Project
  • 选择 Maven,JDK1.8以上版本 点击Next
  • GroupId:com.xxx ArtifactId: hello-springmvc Next
  • 默认会去掉 - 加上,点击 finish。

配置项目

  • 自动导入依赖

image.png

  • 打开 File > Project Structure 对当前工程进行设置

image.png

  • Facets > + > Web 选中工程 ok

image.png

设置 web.xml 位置与版本(3.1以上)

image.png

设置 页面存储位置 与 应用上下位地址

image.png

设置运行方式

  • 点击右下角 Create Artifact 创建运行环境 点击 OK

  • 在 src/main/webapp 下 创建 index.html body 写入 Hello Spring MVC

配置 Tomcat

image.png
找到 Tomcat Server -> local 设置 Tomcat 位置 模板 点击 OK 修改模板
image.png

  • 再次点击 Add Configuration 这次点击 + 号,找到 Tomcat Server local 添加配置
  • 选择 Deploment 点击 + 号 点击 Artifact 直接添加 当前 web exploded

    image.png

  • 下方设置路径

image.png

  • 回到 Server 设置 update action 为 Update class and resources
  • (重新运行后更新,只在 debug 模式下生效)

image.png

  • 修改端口

image.png

设置阿里云仓库并添加依赖 Spring-webmvc

在pom.xml 配置 maven 仓库为阿里云仓库
配置 spring-webmvc 依赖

<repositories>
  <repository>
    <id>aliyun</id>
    <name>aliyun</name>
    <url>https://maven.aliyun.com/repository/public</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.9.RELEASE</version>
  </dependency>
</dependencies>

web.xml 配置 DispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <!--DispatchServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <!--
        DispatchServlet 是 Spring MVC 最核心的对象
        DispatchServlet 用于拦截 Http 请求,
        并根据请求的 URL 调用阈值对应的 Controller 方法,来完成 HTTP 请求的处理
        -->
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--applicationContext.xml 配置上下文文件配置 路径
                    在 resources 目录下创建同名文件 applicationContext.xml
                -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <!--
            在 Web 应用启动时自动创建 Spring IOC 容器(所有的 JavaBean 都会被 IOC 管理)
            并初始化 DispatchServlet
            (若不设置,以上工作会在第一次接收访问 url 时执行)
        -->
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!-- "/" 代表拦截所有请求    -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

配置 applicationContext 的 mvc 标记

<?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.ylq.springmvc 及子包中拥有以下注解的对象
    @Repository    注解 DAO 类
    @Service       注解 Service 类
    @Controller    注解 Controller 类
    @Component     注解无法确定类型的类
    -->
    <context:component-scan base-package="com.ylq.springmvc"></context:component-scan>
    <!--启用 Spring MVC 注解开发模式-->
    <mvc:annotation-driven/>
    <!--将图片 JS/CSS 等静态资源排除在外,可提高执行效率-->
    <mvc:default-servlet-handler/>
</beans>

开发 Controller 控制器

在 java 目录下 创建 与 base-package 值相同的包路径,之下创建 controller 包 与测试类
image.png

package com.ylq.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")
    @ResponseBody  // 直接向响应输出字符串数据,不跳转页面
    public String test() {
        return "Hello Spring MVC!";
    }
}

添加运行配置
image.png
image.png
选中所有未加入依赖的包 右键选择 Put into /WEB-INF/lib
image.png

点击 debug按钮 会自动打开
浏览器输入 http://localhost:8080/t
即可看到返回。

中文乱码问题

Tomcat 默认字符集 ISO-8859-1,不支持中文,需转换为 UTF-8

Get 请求乱码

Tomcat 8以后的版本不需要此设置
Tomcat 中的 conf/server.xml增加 URIEncoding 属性

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

Post 请求乱码

项目中的 web.xml 配置 CharacterEncodingFilter

<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 在 applicationContext.xml 配置 StringHttpMessageConverter

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

ModelAndView 数据模板引擎绑定

Spring MVC 默认的 View 是 JSP,也可以配置其他模板引擎

方法返回对象为 ModelAndView 类型

@Controller
public class TestController {
    @GetMapping("view")
    public ModelAndView showView() {
        ModelAndView mav = new ModelAndView("/view.jsp");
        mav.addObject("username", "Lily");
        return mav;
    }
}
<h1>Hello ${username}</h1>

整合 Freemarker

修改 pom.xml 引入依赖

<dependency>
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>2.3.29</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <!--这里的版本号要和 spring-webmvc 的版本号保持一致-->
  <version>5.1.9.RELEASE</version>
</dependency>

IDEA 不会把依赖的 jar 包自动发布,编辑 Deployment 配置备选依赖添加入 lib 中
image.png
修改 applicationContext.xml 启用模板引擎,配置参数

<bean id="ViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
  <!--设置响应请求时的编码-->
  <property name="contentType" value="text/html;charset=utf-8"/>
  <!--扩展名,同事代码设置模板文件时无需加.ftl 后缀了-->
  <property name="suffix" value=".ftl"/>
</bean>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <!--模板文件存放地址 Tomcat 无法直接解析 Freemarker 模板引擎,
        为了保证模板安全,要把文件放在外侧无法直接访问的 /WEB-INF/ 里-->
  <property name="templateLoaderPath" value="/WEB-INF/ftl"/>
  <property name="freemarkerSettings">
    <props>
      <!--设置渲染模板时的编码-->
      <prop key="defaultEncoding">UTF-8</prop>
    </props>
  </property>
</bean>

Restful

原则

1、网络上的所有事物都被抽象为资源;
2、每个资源都有一个唯一的资源标识符;
3、同一个资源具有多种表现形式(xml,json等);
4、对资源的各种操作不会改变资源标识符;
5、所有的操作都是无状态的。

URL设计

客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源

GET    xx.com/authors/1  根据用户id查询用户数据
POST   xx.com/authors  新增用户
PUT    xx.com/authors/1  修改用户信息
DELETE xx.com/authors/1  删除用户信息

除了第一级,其他级别都用查询字符串表达

GET /authors/12?categories=2

查询已发布的文章

GET /articles?published=true

RestController 注解与路径变量

在 Controller 类上使用 RestController 注解 代替 Controller 注解,就不需要在每个路由方法上增加 ResponseBody 注解
路径变量的使用:

@RestController
@RequestMapping("/rest")
public class RestfulController {
    @GetMapping("/users/{uid}")
    public String showJson(@PathVariable("uid") Integer uid) {
        return "{\"message\": \"返回" + uid + "查询结果\"}";
    }
}

支持所有请求方式

由于历史原因,SpringMVC 原有代码不支持除 GET 与 POST 以外的请求方式,
需要在 web.xml 中添加表单内容过滤器

<filter>
  <filter-name>formContentFilter</filter-name>
  <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>formContentFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

添加之后就可以获取其他请求方式的数据

JSON 序列化(jackson)

添加 Jackson 的依赖,然后把依赖加入发布目录

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <!--核心包,不能独立运行-->
  <artifactId>jackson-core</artifactId>
  <!--需使用 2.9 以后的版本,否则会有安全风险-->
  <version>2.9.9</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <!--数据绑定包,版本号需与核心包相同-->
  <artifactId>jackson-databind</artifactId>
  <version>2.9.9</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <!--注解包-->
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.9</version>
</dependency>

在 RestController 里的方法,如果返回的是实体类,jackson 会自动序列化
需要注意的是如果是时间格式,默认输出时间戳。
可以在实体类里使用 JsonFormat 注解设置格式 和时区

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date birthday;

浏览器跨域访问

原因是浏览器的同源策略:组织从一个域加载的脚本去获取了另一个域上的资源
只要协议,域名,端口有任何一个不同,都被当做是不同的域
跨域被阻止是浏览器 console 会输出 …No ‘Access-Control-Allow-Origin’ …

HTML中允许跨域的三个标签:
Spring MVC Hello World - 图17