SpringMVC

开始啦,这是SpringMVC框架的学习博客内容,最近高强度更新,我的学习压力也很大

首先先区分两个东西,MVCSpringMVC

  • MVC是一种设计模式,Model-View-Controller的缩写,模型-视图-控制器
  • SpringMVC是Spring框架中的一个模块,是基于MVC设计模式实现的Web框架

三层架构&MVC

三层架构是指将应用程序分为表示层(Presentation Layer)、业务逻辑层(Business Logic Layer)和数据访问层(Data Access Layer)三部分。每一层都有其特定的职责和功能。

我们这样搞简直是强迫症福音,可以将每个部分负责的功能都老老实实的分离开来,互不干扰,每个部分都有自己的职责和功能。

  • 表现层:web层,用来与客户端进行数据交互,表现层一般会采用MVC的设计模型。
  • 业务层:处理具体业务逻辑的
  • 持久层:用来操作数据库

MVC全称Model View Controller,是一种设计创建Web应用程序的模式。这三个单词分别代表Web应用程序的三个部分:
Model(模型):指数据模型。用于存储数据以及处理用户请求的业务逻辑。在Web应用中,JavaBean对象,用来进行数据封装
View(视图):用于展示模型中的数据的,一般为jsp或html文件。
Controller(控制器):用来接受用户的请求。

SpringMVC

SpringMVC是一个基于MVC模式的轻量级Web框架,是Spring框架的一个模块,和Spring可以直接整合使用。
SpringMVC代替了Servlet技术,它通过一套注解,让一个简单的Java类成为处理请求的控制器,而无须实现任何接口。

天啊是SpringMVC大人,它的出现解决了Servlet的问题,简化了开发流程,提高了开发效率。
但是我选择等待SpringBoot大人,那位大人更加强大。

SpringMVC的优点

  • 基于MVC模式,结构清晰,易于维护
  • 松耦合,高内聚
  • 支持RESTful风格的URL

    • RESTful风格表达起来是这样的:他把URL的路径部分作为资源的标识符,把HTTP方法作为对资源的操作。
      1
      2
      3
      4
      GET /users/123
      POST /users
      PUT /users/123
      DELETE /users/123
  • 支持自定义的视图解析器

  • 支持自定义的参数绑定
  • 支持自定义的异常处理
  • 支持自定义的拦截器
  • 支持自定义的类型转换器

SpringMVC的使用

为了和后面的Springboot做出区分展示,我们采用JSP作为视图技术,JSP相对落后很多,现已经不太是主流开发,所以这里只是提一句

提示下,后续会用到大量的注解,如果对注解用途不清楚的话建议查看这里

1). 导入SpringMVC的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!--spring核心依赖-->
<dependency>
<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.1.6.RELEASE</version>

</dependency>

<!--spring整合web的依赖-->
<dependency>
<groupId>org.springframework</groupId>

<artifactId>spring-web</artifactId>

<version>5.1.6.RELEASE</version>

</dependency>

<!--spring整合webmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

<version>5.1.6.RELEASE</version>

</dependency>

<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>

<artifactId>javax.servlet-api</artifactId>

<version>3.1.0</version>

<scope>provided</scope>

</dependency>

<!-- jsp -->
<dependency>
<groupId>javax.servlet.jsp</groupId>

<artifactId>javax.servlet.jsp-api</artifactId>

<version>2.3.1</version>

<scope>provided</scope>

</dependency>

2). 配置SpringMVC的DispatcherServlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<!-- springMVC的前端控制器
springMVC的前端控制器,本质是一个servlet,接受所有请求
由它调用其他的组件处理用户请求,DispatcherServlet的存在降低了组件之间的耦合度
-->
<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:springmvc.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<!-- 设置servlet拦截的请求路径
/ 表示拦截所有请求,包括静态资源
/* 表示拦截所有请求,不包括静态资源
-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

</web-app>


3).src/resources资源目录下创建springMVC配置文件springmvc.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- context:component-scan 自动组件扫描
base-package 指定扫描的基础包,把基础包下其子包下的类所有加了注解的类,自动扫描进IOC容器
-->
<context:component-scan base-package="com.iweb"/>

<!-- 视图解析器
视图解析器的作用是,根据控制器返回的视图名,找到对应的视图对象
视图对象的作用是,渲染模型数据,生成最终的视图
将prefix+视图名称+后缀 确定最终要跳转的页面 例如 /sucess.jsp
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
</bean>

<!-- 开启springmvc框架的注解支持 -->
<mvc:annotation-driven/>

</beans>


4).编写hello.jsp,路径为webapp/WEB-INF/hello.jsp
1
2
3
4
5
6
7
8
<html>
<body>
<h2>SpringMVC hello!!!</h2>

</body>

</html>


5).编写controller类和方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.iweb.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

// 用于标识控制层 使用改注解需要开启springMVC的注解扫描
@Controller
public class HelloController {


@RequestMapping(value = "/hello",method = RequestMethod.GET)// 用于标识请求映射 表示当前方法处理的是get请求
// value属性表示请求的路径,method属性表示请求的方法类型
public String sayHello(){
System.out.println("hello world");
return "hello";
}
}

RequestMapping注解
RequestMapping注解可以作用在方法或类上
● 作用在类上:第一级访问目录
● 作用在方法上:第二级访问目录
1.name属性:该映射的引用名称
2.value/path属性:含义相同,都是设置请求路径
3.method属性:用于设置请求方式,默认是GET,
4.param属性:设置请求必须包含指定的参数,才能执行

6).部署项目
将项目部署到tomcat中,启动tomcat,在浏览器中输入http://localhost:8080/hello,即可访问到hello.jsp页面

案例执行过程分析

执行流程
1.当启动tomcat服务器的时候,会创建DispatcherServlet,就会加载springmvc.xml配置文件
2.开启了注解扫描,那么HelloController对象就会被创建
3.当发送请求,请求会先到达DispatcherServlet核心控制器,根据配置的@RequestMapper注解找到执行的具体方法
4.根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
5.tomcat服务器渲染页面,做出响应

SpringMVC处理响应

SpringMVC提供了处理响应的方式有:返回字符串,请求转发,ModelAndView,Request域设置数据,返回Model,回写字符串,回写对象/集合信息,简化注解

返回字符串
SpringMVC的视图解析器将返回的字符串转换为视图(页面)
视图解析器会根据处理器返回的字符串与xml中配置的前缀和后缀进行组合,最后组合成视图的访问路径即/WEB-INF/views/view.jsp

1
2
3
4
5
6
7
8
9
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hello")
public String hello(){
System.out.println("hello world");
return "hello";
}
}

请求转发
请求转发是指,服务器收到请求后,从一个资源跳转到另一个资源的过程
请求转发的过程中,浏览器地址栏的URL不会发生变化
请求转发的过程中,只能转发到当前应用的资源
请求转发的过程中,只能转发到当前应用的资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hello")//此处为转到的路径地址
public String hello(){
System.out.println("hello world");
return "hello";
}
@RequestMapping("/forward")
public String forward(){
System.out.println("forward");
return "forward:/user/hello";
}
}

ModelAndView
ModelAndView是SpringMVC提供的一个类,用于封装模型数据和视图信息
1
2
3
4
5
6
7
8
9
10
@RequestMapping("/method3")
public ModelAndView method3(){
// 创建ModelAndView对象
ModelAndView mv=new ModelAndView();
// 设置要跳转的视图
mv.setViewName("view");
// 设置视图中添加的数据
mv.addObject("title","modelAndView");
return mv;
}

视图中读取数据,使用EL表达式即可完成数据的读取
1
2
3
4
5
6
7
8
9
10
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false"%>
<html>
<body>
<h2>view--->${title}</h2>

</body>

</html>


Request域设置数据
使用原生的HttpServletRequest
一般情况下,在springMVC中都有对servlet原生对象的方法的替换,推荐使用SpringMVC的方式替代servlet原生对象。
1
2
3
4
5
6
// 向方法内注入request对象,并向域对象中添加数据即可
@RequestMapping("method4")
public String method4(HttpServletRequest request){
request.setAttribute("title","request...");
return "view";
}

返回Model
model对象也可以在跳转页面的时候传递数据
1
2
3
4
5
@RequestMapping("method5")
public String method5(Model model){
model.addAttribute("name","helloModel");
return "hello";
}

回写字符串
有时候我们不需要跳转页面,也不需要发数据,我们只是希望浏览器能够渲染数据,这时候我们可以使用HttpServetResponse向浏览器输出数据。

1
2
3
4
5
6
@RequestMapping("method6")
public void method6(HttpServletResponse response) throws Exception{
// 设置响应头,防止中文乱码
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("你好,springMVC!!!");
}

使用spring提供的注解
1
2
3
4
5
6
7
8
9
/**
* @ResponseBody的作用就是当前方法的返回值会绑定到响应体中
* 可以应用在方法上,也可以应用在类上,使用该注册后不会在经过视图解析器
*/
@RequestMapping(value = "/method7",produces ={"text/html;charset=utf-8"} )
@ResponseBody
public String method7(){
return "hello";
}

回写对象/集合信息
在回写对象或者集合时一般都是转成JSON格式数据,生成JSON数据的工具有很多种,常见的fastJson,但是Spring默认采用的Jackjson工具完成JSON数据的响应。

首先,我们在使用@ResponseBody注解时,需要在springmvc.xml配置文件中配置jackjson的相关配置

添加依赖

1
2
3
4
5
6
7
8
9
10
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>

<artifactId>jackson-databind</artifactId>

<version>2.13.3</version>

</dependency>


springmvc.xml配置响应结果转换器
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 配置响应结果转换器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<!-- 自定义配置 -->
<property name="messageConverters">
<list>
<!-- 将响应结果转换为JSON格式数据 -->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>

</property>

</bean>

实体类编写
1
2
3
4
5
6
7
public class UserInfo {

private String name;
private int age;
private String sex;
// 省略get/set方法
}

控制器编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 @RequestMapping("/method8")
@ResponseBody
public UserInfo method8(){
UserInfo user=new UserInfo("张三",18,"男");
return user;
}

@RequestMapping("/method9")
@ResponseBody
public List<UserInfo> method9(){
List<UserInfo> users=new ArrayList<UserInfo>();
Collections.addAll(users,new UserInfo("张三",19,"男"),
new UserInfo("李四",20,"男"),
new UserInfo("王武",21,"男"));
return users;
}

简化注解
1
2
3
4
5
6
7
8
/**
@RestController 该注解是类级别的注解,应用之后相当于使用了
@Controller&@ResponseBody两个借助,减少@ResponseBody注解的使用次数
**/
@RestController
public class HelloController {

}

SpringMVC获取请求参数


施工中……