SpringMVC

一、MVC 概述

1.1.什么是 MVC

  • MVC是模型(Model)、视图(View)、 控制器(Controller)的简写, 是一种软件设计规范。
  • 是将业务逻辑、数据、显示分离的方法来组织代码。
  • MVC主要作用是降低了视图与业务逻辑间的双向偶合。
  • MVC不是一种设计模式,MVC是-种架构模式。当然不同的MVC存在差异。
  • Model (模型) :数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在-般都分离开来: Value Object (数据Dao)和服务层(行为Service) 。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
  • View (视图) :负责进行模型的展示,-般就是我们见到的用户界面,客户想看到的东西。
  • Controller (控制器) :接收用户请求,委托给模型进行处理(状态改变), 处理完毕后把返回的
    模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

Model1时代

Model 1 时代

Model2

Model 2 时代

1.2.导入依赖

pom.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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.cying.study</groupId>
<artifactId>SpringMVC</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
</project>

1.3.特点

  • 轻量级,简单易学
  • 高效,基于请求响应的 MVC 框架
  • Spring 兼容性好,无缝结合
  • 约定优于配置
  • 功能强大: RESTful、数据验证、格式化、本地化、主题等
  • 简洁灵活

1.4.中心控制器

  • Springweb 框架围绕 DispatcherServlet 设计。DispatcherServlet 的作用是将请求分发到不同的处理器。从 Spring 2.5 开始,使用 Java 5 或者以上版本的用户可以采用基于注解的 controller声明方式。

1.5.原理

  • 当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。

yuanli

yuanli2

1.6.执行流程分析

  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
  • HandlerMapping为处理器映射。DispatcherServlet调用HandlerMappingHandlerMapping根据请求url查找Handler
  • HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为: hello
  • HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
  • Handler让具体的Controller执行。
  • Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView
  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
  • 视图解析器将解析的逻辑视图名传给DispatcherServlet
  • DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
  • 最终视图呈现给用户。

二、具体实现

在 web.xml 注册 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
<?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_4_0.xsd"
version="4.0">

<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>

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

</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

</web-app>

在 resources 新建 springmvc-servlet.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
<?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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="包路径"/>

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>

</beans>

2.1.原始方法实现

springmvc-serlvet.xml 配置 Spring Bean`,指向实体类

1
<bean class="实体类全路径" id="/外界访问路径"/>

书写实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstTest implements Controller {

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
//ModelAndView 模型和视图
ModelAndView mv = new ModelAndView();
System.out.println("Do");

//封装对象,放在ModelAndView中。Model
mv.addObject("msg","HelloSpringMVC!");
//封装要跳转的视图,放在ModelAndView中
mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
return mv;
}

}

2.2.注解方式实现

**修改 `springmvc-servlet.xml **

1
2
3
4
5
6
7
8
9
10
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

改为:

<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />

<!-- 支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。-->
<mvc:annotation-driven />

书写实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/HelloController")
public class HelloController {

//真实访问地址 : 项目名/HelloController/hello
@RequestMapping("/hello")
public String sayHello(Model model){
//向模型中添加属性msg与值,可以在JSP页面中取出并渲染
model.addAttribute("msg","hello,SpringMVC");
//web-inf/jsp/hello.jsp
return "hello";
}
}

三、数据处理

3.1.处理提交数据

3.1.1.提交时的 url 和参数名一样时

1
http://localhost/url?name=xx&age=xx
1
2
3
4
5
@RequestMapping("/url")
public String hello(String name, int age){
System.out.println(name + age);
return "hello";
}

3.1.2.提交时的 url 和参数名不一样时

1
http://localhost/url?name=xx
1
2
3
4
5
@RequestMapping("/url")
public String hello(@RequestParam("name") String Username){
System.out.println(Username);
return "hello";
}

3.1.3.提交一个对象

1
2
3
4
5
6
7
8
9
10
@Data
@AllArgsConstructor
@NoArgsConstructor

public class User {

private String name;
private int age;

}
1
http://localhost/url?name=xx&age=xx
1
2
3
4
5
@RequestMapping("/url")
public String user(User user){
System.out.println(user);
return "hello";
}

3.2.数据显示到前端

3.2.1.ModelAndView

1
2
3
4
5
6
7
8
9
10
public class Controller implements Controller {

public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//返回一个模型视图对象
ModelAndView mv = new ModelAndView();
mv.addObject("msg","value");
mv.setViewName("test");
return mv;
}
}

3.2.2.ModelMap

1
2
3
4
5
6
7
8
@RequestMapping("/url")
public String hello(@RequestParam("username") String name, ModelMap model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("name",name);
System.out.println(name);
return "hello";
}

3.2.3.Model

1
2
3
4
5
6
7
8
@RequestMapping("/url")
public String hello(@RequestParam("username") String name, Model model){
//封装要显示到视图中的数据
//相当于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}

3.2.4.对比

  • Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
  • ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
  • ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。

3.2.5.过滤器解决乱码

web.xml 配置

1
2
3
4
5
6
7
8
9
10
11
12
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

四、RestFul

4.1.概念

  • Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

4.2.功能

  • 资源:互联网所有的事物都可以被抽象为资源
  • 资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
  • 分别对应 添加、 删除、修改、查询。

4.3.映射访问路径

1
2
3
4
5
6
7
8
9
10
@RequestMapping("/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable String p2, Model model){

String result = p1+p2;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果:"+result);
//返回视图位置
return "test";

}

4.4.RequestMapping

1
2
3
4
5
6
7
8
@RequestMapping(value = "/url",method = {RequestMethod.POST})	
@PostMapping
// 两种都是 Post 方法,独立使用


@RequestMapping(value = "/url",method = {RequestMethod.GET})
@GetMapping
// 两种都是 Get 方法,独立使用

五、拦截器

书写拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

//在请求处理的方法之前执行
//如果返回true执行下一个拦截器
//如果返回false就不执行下一个拦截器
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("------------处理前------------");
return true;
}

//在请求处理方法执行之后执行
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("------------处理后------------");
}

//在dispatcherServlet处理后执行,做清理工作.
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("------------清理------------");
}
}

springmvc-servlet.xml 中配置

1
2
3
4
5
6
7
8
9
10
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<!--bean配置的就是拦截器-->
<bean class="拦截器全路径"/>
</mvc:interceptor>
</mvc:interceptors>

六、文件

6.1.上传

pom.xml 导入依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>

springmvc-servlet.xml 中配置 Java Bean

1
2
3
4
5
6
7
8
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和请求页面的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>

书写实体类

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
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {

//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();

//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);

//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);

InputStream is = file.getInputStream(); //文件输入流
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流

//读取写出
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}

6.2.下载

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
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基础语法.jpg";

//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();

byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}

Ajax

1
jQuery.ajax(...)
  • url:请求地址
  • type:请求方式,
  • GET、POST(1.9.0之后用method)
  • headers:请求头
  • data:要发送的数据
  • contentType:即将发送信息至服务器的内容编码类型(默认: “application/x-www-form-urlencoded; charset=UTF-8”)
  • async:是否异步
  • timeout:设置请求超时时间(毫秒)
  • beforeSend:发送请求前执行的函数(全局)
  • complete:完成之后执行的回调函数(全局)
  • success:成功之后执行的回调函数(全局)
  • error:失败之后执行的回调函数(全局)
  • accepts:通过请求头发送给服务器,告诉服务器当前客户端课接受的数据类型
  • dataType:将服务器端返回的数据转换成指定类型
    • “xml”: 将服务器端返回的内容转换成xml格式
    • “text”: 将服务器端返回的内容转换成普通文本格式
    • “html”: 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
    • “script”: 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
    • “json”: 将服务器端返回的内容转换成相应的JavaScript对象
    • “jsonp”: JSONP 格式使用 JSONP 形式调用函数时,如 “myurl?callback=?” jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
  • 在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!