简介
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。
配置项目
- 自动导入依赖
- 打开 File > Project Structure 对当前工程进行设置
- Facets > + > Web 选中工程 ok
设置 web.xml 位置与版本(3.1以上)
设置 页面存储位置 与 应用上下位地址
设置运行方式
点击右下角 Create Artifact 创建运行环境 点击 OK
在 src/main/webapp 下 创建 index.html body 写入 Hello Spring MVC
配置 Tomcat
找到 Tomcat Server -> local 设置 Tomcat 位置 模板 点击 OK 修改模板
- 再次点击 Add Configuration 这次点击 + 号,找到 Tomcat Server local 添加配置
选择 Deploment 点击 + 号 点击 Artifact 直接添加 当前 web exploded
下方设置路径
- 回到 Server 设置 update action 为 Update class and resources
- (重新运行后更新,只在 debug 模式下生效)
- 修改端口
设置阿里云仓库并添加依赖 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 包 与测试类
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!";
}
}
添加运行配置
选中所有未加入依赖的包 右键选择 Put into /WEB-INF/lib
点击 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 中
修改 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中允许跨域的三个标签: