MVC:模型(dao、service) 视图(jsp) 控制器(servlet)
什么是MVC?
- MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
- 是将业务逻辑、数据、显示分离的方法来组织代码。
- MVC主要作用是降低了视图与业务逻辑间的双向耦合
- MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在不同的差异。
面试题
假设:你的项目的架构是设计好的?还是演进的?
- Alibaba PHP
- 随着用户大 java
- 王坚 去IOE MySQL
- MySQL:MySQL —> AliSQL、AliRedis
- All in one —> 微服务
1、回顾Servlet
导入依赖
见项目 D:\IntelliJ IDEA workSpace\Maven\javaEE\SpringMVC\spring-01-servlet
MVC框架要做哪些事情
- 将url映射到java类或者java类的方法
- 封装用户提交的数据
- 处理请求 — 调用相关的业务处理 — 封装相应数据
- 将相应的数据进行渲染 .jsp / html 等表示层数据
说明:
常见的服务器MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framwork、JSF;常见前端MVC架构:vue、angularjs、react、backbone;由于MVC演化出了另外一些模式,如:MVP、MVVM等等……
2、初识SpringMVC
Spring MVC 是 Spring Framework 的一部分,是基于Java实现MVC的轻量级web框架。
为什么要学习Spring MVC呢?
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定大于配置
- 功能强大:RESTful风格、数据验证、格式化、本地化、主题等
- 简介灵活
2.1、中心控制器
Spring 的 web 框架围绕 DispatcherServlet 设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring2.5 开始,使用Java 5 或者以上版本的用户可以采用基于注解的 controller 声明方式。
Spring MVC 框架像许多其他MVC框架一样,以请求为驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet(它继承自HttpServlet基类)。
DispatcherServlet:也可以叫做前端控制器


DispatcherServlet执行流程:
- DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DIspatcherServlet 接收请求并拦截请求。
- 我们假设请求的 url 为:http://localhost:8080/SpringMVC/hello
- 如上 url 可以拆分成三部分
- http://localhost:8080 服务器域名
- SpringMVC 部署在服务器上的 web 站点
- hello 表示控制器
- 通过分析,如上url 表示为:请求位于服务器 localhost://8080 上的 SpringMVC 站点 的hello 控制器。
- HandlerMapper 为处理器映射。DispatcherServlet 调用HandlerMapper,Handler Mapping根据请求 url 查找Handler
- HandlerExecution 表示具体的 Handler,其主要作用是根据 url 查找控制器,如上 url 被查找控制器为:hello
- HandlerExecution 将解析后的信息传递给 DispatcherServlet,如解析控制器映射等。
- HandlerAdapter 表示处理器适配器,其按照特性的规则去执行 Handler。
- Handler 让具体的Controller 执行。
- Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
- HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
- DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
- 视图解析器将解析的逻辑视图名传给DispatcherServlet。
- DispacherServlet 根据视图解析器解析的视图结果,调用具体的视图。
- 渲染数据,将最终视图呈现给用户。
实线是SpringMVC帮我们的操作,虚线是我们自己明面上的操作。
2.2、HelloSpringMVC原理

首先配置web.xml配置文件 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
<servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--DispatcherServlet要绑定SpringMVC(说是SpringMVC,其实本质还是Spring)的配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!--启动级别:1(服务器一启动,我就启动)--><load-on-startup>1</load-on-startup>
<servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern>
2. 因为web.xml中初始化参数绑定了 springmvc-servlet.xml,所以配置 springmvc-servlet.xml
```xml
<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:模板引擎:Thymeleaf、Freemarker...-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--因为BeanNameUrlHandlerMapping是根据bean的id名来找映射路径,所以我们需要在这里配置一个对应的bean-->
<bean id="/hello" class="com.jungle.controller.HelloController"/>
</beans>
- 编写Controller ```java package com.jungle.controller;
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 HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView();
// 业务代码
String str = "Hello SpringMVC!";
mv.addObject("msg", str);
// 视图跳转
mv.setViewName("test");
return mv;
}
}
4. 编写视图层
```html
<%--
Created by IntelliJ IDEA.
User: PC
Date: 2022-03-02
Time: 0:58
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
2.2.1、可能遇到的问题:
- 查看控制台输出,看一下是不是缺少了什么 jar 包
- 如果 jar 包存在,显示无法输出,就在IDEA的项目发布中,添加 lib 依赖
- 重启Tomcat即可解决!


- 可能存在静态资源过滤的问题,这个问题在pom.xml导入静态资源过滤就行了。
2.3、使用注解开发HelloSpringMVC
- 配置web.xml
这一块web.xml的配置是死的
<?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">
<!--配置DispatcherServlet:这个是SpringMVC的核心;叫请求分发器或者,前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定SpringMVC(说是SpringMVC,其实本质还是Spring)的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别:1(服务器一启动,我就启动)-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置springmvc-servlet.xml 【这一块的代码也是死的】 ```xml <?xml version=”1.0” encoding=”UTF8”?>

3. 编写controller
```java
package com.jungle.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
// 向模型中添加属性msg,可以在jsp页面中被取出然后渲染
model.addAttribute("msg", "Hello SpringMVC Annotation");
// 会被视图解析器解析成 WEB-INF/jsp/hello.jsp
return "hello";
}
}
- 编写视图层
<%-- Created by IntelliJ IDEA. User: PC Date: 2022-03-02 Time: 17:35 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
步骤:
- 新建一个项目
- 导入相关jar 包
- 编写web.xml,注册 DispatcherServlet
- 编写springmvc 配置文件
- 接下来就是去创建对应的控制类,controller
- 最后完善前端视图和 controller 之间的对应
- 测试运行调试
使用 SpringMVC 必须配置的三大件:
- 处理器映射
- 处理器适配器
- 视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的 xml 配置。
2.4、小结
controller层实现Controller的方式是一种比较老的方法,尽量不用。而且它还有一个缺点,就是一个类只能实现一个bean,这样效率太低了,并且每次写完一个controller,都要去springmvc-servlet.xml 配置一个bean。太麻烦!
@Controller 注解一个类:代表这个类会被Spring接管,被这个注解的类,中的所有方法,如果返回值是String,并且有具体的页面可以跳转,那么就会被视图解析器解析;
我们可以将多个请求指向一个视图,但页面结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱耦合关系。、
3、RestFul风格
优点:简洁、高效、安全
原来的风格:localhost:8080/method?add=1 & name=
Restful风格:localhost:8080/method/add/1/2/3
概念:
RestFul 就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,基于这个风格设计的软件可以更简介,更有层次,更易于实现缓存等机制。


学习测试:
新建一个类RestFulController
@Controller public class RestFulController { }在SpringMVC中可以使用 @PathVariable 注解,让方法的值对应绑定到一个URL模板变量上。 ```java package com.jungle.controller;
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class RestFulController { // 映射访问路径 @RequestMapping(“/commit/{p1}/{p2}”) public String index(@PathVariable int p1, @PathVariable int p2, Model model){ int result = p1 + p2; // SpringMVC会自动实例化一个Model对象用于向视图中传值 model.addAttribute(“msg”, “结果为:” + result); // 返回视图位置 return “test”; } }
3. 通过不同去请求方式来实现不同的效果
```java
@Controller
public class RestFulController {
// 映射访问路径 源码默认使用 value 或者 path
@RequestMapping(value = "/commit/{p1}/{p2}", method = RequestMethod.GET)
public String index(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1 + p2;
// SpringMVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果为:" + result);
// 返回视图位置
return "test";
}
}
小结:
SpringMVC的@RequestMapping 注解能够处理 HTTP 请求的方法,比如 GET,PUT,POST,DELETE 以及 PATCH。
所有的地址栏请求默认都会时 HTTP GET 类型的。
方法级别的注解变体有如下几个:组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMappint
@PatchMapping
例如:
@Controller
public class RestFulController {
@GetMapping(value = "/commit/{p1}/{p2}")
public String index(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1 + p2;
// SpringMVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果为:" + result);
// 返回视图位置
return "test";
}
@PostMapping(value = "/commit/{p1}/{p2}")
public String index2(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1 + p2;
// SpringMVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", "结果为:" + result);
// 返回视图位置
return "test";
}
}
4、转发和重定向
SpringMVC:结果跳转方式
- 转发
- 重定向
4.1、ModelAndView
设置ModelAndVIew对象,根据View的名字,和视图解析器跳到指定的页面
页面:{视图解析器前缀} + viewName + {视图解析器后缀}
<!--视图解析器:模板引擎:Thymeleaf、Freemarker...-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
对应的controller类
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
// 业务代码
String str = "Hello SpringMVC!";
mv.addObject("msg", str);
// 视图跳转
mv.setViewName("test");
return mv;
}
}
4.2、ServletAPI
通过设置ServletAPI,不需要视图解析器
- 通过HttpServletResponse进行输出
- 通过HttpServletResponse实现重定向
- 通过HttpServletResponse实现转发
之前JavaWeb实现转发和重定向
4.3、SpringMVC
在不配置视图解析器的情况下:
转发
@Controller public class ModelTest1 { @RequestMapping("/m1/t1") public String test1(Model model){ model.addAttribute("msg", "ModelTest1"); return "forward:/WEB-INF/jsp/test.jsp"; // 如果是/WEN-INF/jsp/test.jsp,那么默认的也是转发 } }重定向
@Controller public class ModelTest1 { @RequestMapping("/m1/t1") public String test1(Model model){ return "redirect:/index.jsp"; } }
配置了视图解析器:
@Controller
public class ModelTest1 {
// 1. 转发
@RequestMapping("/m1/t1")
public String test1(Model model){
model.addAttribute("msg", "ModelTest1");
return "test";
}
// 2. 重定向
@RequestMapping("/m1/t2")
public String test1(Model model){
return "redirect:/index.jsp";
}
}
5、SpringMVC数据处理
5.1、接收请求参数
- 提交的域名称和处理方法的参数名一致
提交数据:http://localhost:8080/hello?name=kuangshen
处理方法:
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "hello";
}
后台输出:kuangshen
- 提交的域名称和处理方法的参数名不一样
提交数据:http://localhost:8080/hello?usernName=kuangshen
处理方法:
@RequestMapping("/hello")
public String hello(@RequestParam("userName")String name){
System.out.println(name);
return "hello";
}
后台输出:kuangshen
- 提交的是一个对象
要求提交的表单域和对象的属性名一致,参数使用对象即可
实体类
public class User{ private int id; private String name; private int age; // 构造 // get/set // toString() }提交数据:http://localhost:8080/mvc04/user?name=kuangshen%id=1&age=15
- 处理方法:
后台输出:User(id=1, name=qinjiang, age=15);@RequestMapping("/user") public String user(User user){ System.out.println(user); return "hello"; }
说明:如果使用对象的话,前端传递的参数名和对象的属性名必须一致,否则返回null。
5.2、数据显示到前端
第一种:通过 ModelAndVIew
我们一直都是如此,就不必多说了。
第二种:通过ModelMap
第三种:通过Map

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

6.1、什么是JSON
- JSON(JavaScript Object Notation, JS对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立编程语言的文本格式来存储和表示数据
- 简洁和清晰的层次结构使得JSON称为理想的数据交换语言。
- 易于人阅读和编写,同时也易于及其解析和生成,并有效地提升网络传输效率。
在JavaScript语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过JSON来表示。例如字符串、数字、对象、数组等。看看JSON的要求和语法格式:
- 对象表示为键值对,数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
JSON键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键值对组合中的键名卸载前面并用双引号 ""包裹,使用冒号 :c分隔,然后及接着值:
{"name" : "Jungle"}
{"age" : "3"}
{"sex" : "man"}
JSON初体验
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSON测试</title>
<script type="text/javascript">
// 编写一个JavaScript对象 ES6
let user = {
name : "Jungle",
age : 3,
sex : "男"
};
// 将js对象转换为Json对象
let json = JSON.stringify(user);
console.log(json);
console.log("==================");
// 将Json对象转换为JavaScript对象
let parse = JSON.parse(json);
console.log(parse);
</script>
</head>
<body>
</body>
</html>
6.2、Jackson使用
- Jackson应该是目前比较好的json解析工具了
- 当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
- 我们这里使用 Jackson,使用它需要导入它的 jar 包;
导入jar包
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.1</version> </dependency>编写web.xml和springmvc-servlet.xml 配置文件
编写实体类 User
编写controller
在不用 jackson 的情况下,直接返回一个 toStirng() 也可以将字符串返回到前端
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody // 添加了这个注解,类就不会走视图解析器,会直接返回一个字符串
public String json1(){
// 创建一个对象
User user = new User("Jungle01", "20", "男");
return user.toString();
}
}

使用 jackson
@Controller
public class UserController {
@RequestMapping("/j1")
@ResponseBody // 添加了这个注解,类就不会走视图解析器,会直接返回一个字符串
public String json1() throws JsonProcessingException {
// jackson, ObjectMapper方法
ObjectMapper mapper = new ObjectMapper();
// 创建一个对象
User user = new User("Jungle01", "20", "男");
String s = mapper.writeValueAsString(user); // 需要抛出一个异常
return s;
}
}

但还是有乱码的情况
手动解决乱码:@RequestMapping ( value = “/j1”, produces = “application/json;charset=utf-8” )
上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置同一指定,这样就不用每次都去处理了!
我们可以在 SpringMVC 的配置文件上添加一段消息 StringHttpMessageConverter 转换配置!
springmvc-servlet.xml
<!--JSON乱码问题配置(这段代码是死的)-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
6.2.2、@RestController
@RestController == @Controller + @ResponseBody
区别:
- @RestController 不会走视图解析器,直接返回 JSON 字符串(前后端分离)
- @Controller 会走视图解析器。
//@Controller @RestController // 不走视图解析器,直接返回JSON字符串 public class UserController { @RequestMapping("j1") // @ResponseBody // 添加了这个注解,类就不会走视图解析器,会直接返回一个字符串 public String json1() throws JsonProcessingException { // jackson, ObjectMapper方法 ObjectMapper mapper = new ObjectMapper(); // 创建一个对象 User user = new User("Jungle01", "20", "男"); String s = mapper.writeValueAsString(user); // 需要抛出一个异常 return s; } }
如果返回的是多个对象,那么用List封装
// 如果返回的多个对象怎么办?用List
@RequestMapping("j2")
public String json2() throws JsonProcessingException {
List<User> list = new ArrayList();
// 创建一个对象
User user1 = new User("Jungle01", "20", "男");
User user2 = new User("Jungle02", "20", "男");
User user3 = new User("Jungle03", "20", "男");
User user4 = new User("Jungle04", "20", "男");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
return new ObjectMapper().writeValueAsString(list); // 需要抛出一个异常
}

输出时间对象:
// 输出时间对象
@RequestMapping("j3")
public String json3() throws JsonProcessingException {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return new ObjectMapper().writeValueAsString(sdf.format(date)); // 需要抛出一个异常
}

通过 jackson ,屏蔽java代码原本默认使用时间戳输出的方式
// 输出时间对象
@RequestMapping("j3")
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
// 不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// 自定义日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mapper.setDateFormat(sdf);
Date date = new Date();
// 这个时候输出的就不是时间戳的格式了
return mapper.writeValueAsString(date); // 需要抛出一个异常
}
6.2.3、提取工具类
JsonUtils 工具类
public class JsonUtils {
public static String getJson(Object object){
return getJson(object, "yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object, String dateFormat){
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
// 提取了工具类之后,使用更加方法
@RequestMapping("j4")
public String json4() {
Date date = new Date();
// 自定义时间格式
return JsonUtils.getJson(date, "yyyy-MM-dd HH:mm:ss");
}
提取公共类和方法的复用,这是一种编码思想,大量出现在源码中。值得学习!!
6.3、fastJson
fastjson.jar 是阿里开发的一款专门用于 Java 开发的包,可以方便的实现 json 对象与 JavaBean 对象的转换,实现 JavaBean 对象与 json 字符串的转换,实现 json 对象与 json 字符串的转换。实现 json 转换的方法很多,最后的实现结果都是一样的。
fastjson 的 pom.xml 依赖
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>

// 使用fastjson
@RequestMapping("j5")
public String json5() {
List<User> list = new ArrayList();
// 创建一个对象
User user1 = new User("Jungle01", "20", "男");
User user2 = new User("Jungle02", "20", "男");
User user3 = new User("Jungle03", "20", "男");
User user4 = new User("Jungle04", "20", "男");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
String jsonString = JSON.toJSONString(list);
return jsonString;
}
7、AJAX
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
- AJAX 是一种无需在重新加载整个网页的情况下,能够更新部分网页的技术
- AJAX 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的 web 应用程序的技术

7.1、关于 / 和 /*
URL匹配注意事项
Servlet对URL的匹配既不是Ant风格,也不是Regex。特殊符号只有单个的,且使用位置有强约束,切忌*想当然的随意拼凑。
举例两种典型的错误理解,应该能帮助到你:
- /api/.jsp:该urlPatterns是非法的,启动时会报错“IllegalArgumentException: servlet映射中的[/api/.jsp]无效”。原因为:
- 若当路径匹配,/*后面不能再有任何东西
- 若当后缀名匹配,*.必须是最前面
/api//demo:这个urlPatterns是合法的。只不过它属于精确匹配,也就是说别看它中间有,仍旧有且仅能匹配/api/*/demo这个请求路径
匹配顺序
有时候一个URL会被多个urlPatterns所匹配,这时谁优先呢?
Servlet同样遵循“国际惯例”:越精确越优先,越模糊越靠后。站在pattern模式的角度换句话讲就是:范围越小越优先,范围越大越靠后。
因此Servlet四种匹配方式顺序按范围从小到大(优先级从高到底)排序为:精确匹配 > 路径匹配 > 后缀名匹配 > 缺省匹配。/和/*的区别
终于,来到了今天的主菜。
从上至下的阅读到这里,再看这个问题,是不是觉得答案已经浮出水面?那么,最后我还是来总结一下它俩的异同点:
相同点
绝大部分场景下具有相同的表现:匹配所有。
不同点
就是由于它们的相同点(如此相似),所以才让我们难以区分。
关于/:servlet中特殊的匹配模式(用在Filter中无效),
- 因为是缺省匹配代表匹配所有路径,所以只可能存在一个实例(若存在多个就覆盖)
- 优先级最低(兜底),这是和/*的最大区别。它不会覆盖任何其它的url-pattern,只会覆盖Servlet容器(如Tomcat)内建的DefaultServlet
关于/*:
- 属于4中匹配模式中的路径匹配,可用于Servlet和Filter
优先级很高(仅次于精确匹配)。所以它会覆盖所有的后缀名匹配,从而很容易引起404问题,所以这种模式的“伤害性”是非常强的,一般有且仅用在Filter上
DispatcherServlet不拦截.jsp请求根因分析
/只能用于Servlet上,/*一般只用于Filter上。
大家熟悉的Spring MVC的DispatcherServlet的匹配路径默认就是/,它会拦截各种各样的请求,诸如下面这种请求都会拦截:/api/demo1
- /html/demo1.html
- /static/main.js
但是,它不会拦截/api/demo1.jsp这种以.jsp结尾的请求。据此现象就出现了:/不拦.jsp请求而/拦截(/的范围比/大)这种“错误”言论。
下面告诉你此现象的根因:Servlet容器(如Tomcat)内置有专门匹配.jsp这种请求的Servlet处理器,如下图所示:

而后缀名匹配优先级高于缺省匹配,所以.jsp结尾的请求不会被DispatcherServlet所“截胡”而是交给了JspServlet处理。
7.2、AJAX理解

AJAX是实现前后端分离里面最重要的一门技术(请求类型xhr)。作为一个java后端程序员,需要掌握的有:
Jquery.ajax(...)
部分参数:
url: 请求地址
data: 要发送的数据
success: 成功之后执行的回调函数(全局)
error: 失败之后执行的回调函数(全局)
AJAX理解:
举个例子:实现一个失去焦点后浏览器响应一个请求。
在前端,我们通过js实现一个失去焦点的触发事件,然后这个事件通过 ajax.post()方法,一般我们填上三个参数,url、data、success,将url请求给到后台,以往的 a 标签都是通过url请求给到后台,然后后台去做一些转发或者重定向操作,但是这样会使得整个网页刷新,这不是我们想要的效果。这个时候就需要用到ajax技术,我们将url给到后台,后台只返回我们需要的数据,而没有去刷新整个页面。这个将后台的控制权给到了前端的过程就叫做AJAX技术。
- 【狂神说Java SpringMVC 24、Ajax初体验】
- 【狂神说Java SpringMVC 25、Ajax异步加载数据】
- 【狂神说Java SpringMVC 26、Ajax验证用户名体验】
8、拦截器
概述
SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用
过滤器
- servlet 规范中的一部分,任何 java web 工程都可以使用
- 在 url-pattern 中配置了 /* 之后,可以对所有要访问的资源进行拦截
拦截器
- 拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,如果访问的是 jsp/html/css/image/js 是不会进行拦截的
自定义拦截器
如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口
全在代码里:D:\IntelliJ IDEA workSpace\Maven\javaEE\SpringMVC\springmvc-07-interceptor
9、文件上传和下载
准备工作
文件上传是项目开发中最常见的功能之一,springMVC 可以很好的支持文件上传,但是 SpringMVC 上下文中默认没有装配 MultipartResolver,因此默认情况下不能处理文件上传工作。如果想使用 Spring 的文件上传功能,则需要在上下文中装配 MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单的 enctype 属性做个详细的说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
- multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
- text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
- 导包
代码全在:D:\IntelliJ IDEA workSpace\Maven\javaEE\SpringMVC\springmvc-08-file 中<!--文件上传--> <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>
