SpringMvc


1. Web 开发的发展

1.1 model1 的开发方式

统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来进行处理

image-20210308143854691

出现的弊端:

  • JSP 和 Java Bean 之间严重耦合,Java 代码和 HTML 代码也耦合在了一起

  • 要求开发者不仅要掌握 Java ,还要有高超的前端水平

  • 前端和后端相互依赖,前端需要等待后端完成,后端也依赖前端完成,才能进行有效的测试

  • 代码难以复用


1.2 model2 的开发方式

Servlet + JSP + Java Bean

image-20210308144038275

首先用户的请求会到达 Servlet,然后根据请求调用相应的 Java Bean,并把所有的显示结果交给 JSP 去完成,这样的模式我们就称为 MVC 模式。

  • M 代表 模型(Model)

    模型是什么呢? 模型就是数据,就是 dao,bean

  • V 代表 视图(View)

    视图是什么呢? 就是网页,JSP,用来展示模型中的数据

  • C 代表 控制器(controller)

    控制器是什么? 控制器的作用就是把不同的数据(Model),显示在不同的视图(View)上,Servlet 扮演的就是这样的角色。


2. Spring MVC 框架介绍

SpringMVC 是类似于 Struts2 的一个 MVC 框架,在实际开发中,接收浏览器的请求响应,对数据进行处理,然后返回页面进行显示,但是上手难度却比 Struts2 简单多了。而且由于 Struts2 所暴露出来的安全问题,SpringMVC 已经成为了大多数企业优先选择的框架。

  • 特点:
    • 结构松散,几乎可以在 Spring MVC 中使用各类视图
    • 松耦合,各个模块分离
    • 与 Spring 无缝集成

3. SpringMvc的执行流程

传统的 JavaWeb 开发

一个请求资源路径(url) 对应一个控制器(Controller),每次请求之后都会自动根据所请求的资源找到对应的 Servlet 类,执行相应的业务。

SpringMVC 开发

前后端不分离

SpringMVC 底层有一个核心对象:DispatcherServlet 前端控制器(分发器),使用了 SpringMVC 框架之后,所有的请求都会执行 DispatcherServlet 这个对象,不再去直接执行对应的 Controller,而是先通过 DispatcherServlet 前端控制器找到该请求路径(URL) 对应的控制器,前端控制器再去调用该控制器执行具体业务。

image-20210309195355880
  1. 一个请求匹配前端控制器 DispatcherServlet 的请求映射路径(在 web.xml 中指定),WEB 容器将该请求转交给 DispatcherServlet 处理
  2. DispatcherServlet 接收到请求后,解析URL,将根据请求信息交给处理器映射器 (HandlerMapping)
  3. HandlerMapping 根据用户的url请求 查找匹配该 url 的 Handler,并返回一个执行链
  4. DispatcherServlet 再请求处理器适配器(HandlerAdapter) 调用相应的 Handler 进行处理并返回 ModelAndView 给 DispatcherServlet
  5. DispatcherServlet 将 ModelAndView 请求 ViewReslover(视图解析器)解析,返回具体 View
  6. DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)
  7. DispatcherServlet 将页面响应给用户

注意:

  • 在前端浏览器上第一次请求我们的 DispatchServlet 前端控制器(核心组件),会创建该 DispatchServlet 对象的实例,再执行 DispatchServlet 中的 init() 方法 , 从 spring 容器中按照类型注入来获取 DispatchServlet 中的属性对应的组件来进行依赖注入 !!!
  • 如果不是第一次请求的话,各大组件依赖注入完毕,直接执行 doService() 方法来完成后续操作!!!
  • SpringMVC 底层也有自己的一个容器:WebXmlApplicationContext ,和 spring 的 ApplicationContext 容器是父子关系,SpringMVC 的容器是继承了 Spring 容器的,spring 容器是父容器,springmvc 容器是子容器!!!
  • springmvc 在需要使用到某个功能组件的时候,先去自己的 WebXmlApplicationContext 容器中去找,如果没有则去 spring 容器中去找
  • springmvc 可以获取 spring 容器中的 bean,而 spring 则无法获取 springmvc 容器中的 bean !!!!
  • 一般的话像 Controller 层对象一般都是存放在 springmvc 的容器中来共 springmvc 中的处理器适配器去调用!!!
  • Service 层 和 Dao 层对象,一般则是放在 spring 容器中,因为像一些事务的处理和 mybatis 核心对象的生成不是加上注解之后就会立即生效,而是先生成代理对象,一般这些代理对象一般都在 spring 容器中注册!!!

前后端分离

使用 @ResponseBody 来把数据写入到响应体中。所以不需要进行页面的跳转。

  1. 用户发起请求被 DispatchServlet 所处理

  2. DispatchServlet 通过 HandlerMapping 根据具体的请求查找能处理这个请求的 Handler。(HandlerMapping 主要是处理请求和Handler方法的映射关系的)

  3. HandlerMapping 返回一个能够处理请求的执行链给 DispatchServlet,这个链中除了包含 Handler 方法也包含拦截器。

  4. DispatchServlet 拿着执行链去找 HandlerAdapter 执行链中的方法。

  5. HandlerAdater 会去执行对应的 Handler 方法,把数据处理转换成合适的类型,然后作为方法参数传入

  6. Handler 方法执行完后的返回值会被 HandlerAdapter 转换成 ModelAndView 类型。由于使用了 @ResponseBody 注解,返回的ModelAndView 会为 null,并且 HandlerAdapter 会把方法返回值放到响应体中。(HandlerAdater 主要进行 Handler 方法参数和返回值的处理。)

  7. 返回 ModelAndView 给 DispatchServlet。

  8. 因为返回的 ModelAndView 为null,所以不用去解析视图解析和其后面的操作


4. 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
<!--只需要引入这一个依赖即可,因为这个依赖包含  beans  core  context   web ..-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>

<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>

创建 Spring 与 SpringMvc 配置文件

  • applicationContext.xml
  • spring-mvc.xml

修改web.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
<web-app>
<!--Spring的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!-- 监听tomcat的启动,在启动时初始化容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!--配置springmvc的前端控制器-->

<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:spring-mvc.xml</param-value>
</init-param>
<!--大于0:代表tomcat启动时加载这个Servlet,小于等于0:代表第一次访问时加载这个Servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

编写spring的applicationContext.xml配置文件

1
2
3
4
5
6
7
8
9
10
11
<?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"
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">
<!--配置注解扫描器-->
<context:component-scan base-package="com.xzy.spring"/>
</beans>

编写springmvc配置文件 spring-mvc.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
<?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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置前端控制器(在web.xml中配置)-->

<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
<!--必须配置处理器的包扫描路径,如果想要去掉applicationContext中的这个注解,就要把这个扫描路径配置成父类的-->
<context:component-scan base-package="com.xzy.spring.controller"/>
</beans>

编写处理器(Controller)

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
package com.xzy.spring.controller;

import com.xzy.spring.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;

@GetMapping("/login")
public ModelAndView login() {
userService.login();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/login.jsp");
Map map = new HashMap();
map.put("name", "admin");
map.put("age", 20);
modelAndView.addObject(map);
return modelAndView;
}
}

编写视图

1
2
3
4
5
6
7
8
9
10
11
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Title</title>
</head>
<body>
登录视图${requestScope.user}
<%= request.getAttribute("user")%>
</body>
</html>

5. 浏览器访问

http://localhost:8080/user/login.do

DispatcherServlet会接收到这个请求,并且去掉.do去到相应的处理器


6. SpringMvc接收客户端的请求参数

http://localhost:8080/user/login.do?username=admin&password=admin123

6.1 通过servlet原始的api接收参数(了解)

1
2
3
4
@RequestMapping("/login")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
}

6.2 通过springmvc自带的功能完成参数的接收(重要)

1
2
3
4
5
6
7
@RequestMapping("/login")
public ModelAndView login(@RequestParam("username") String uname, @RequestParam("password") String upassword,@RequestParam("loves") List<String> loves) {
System.out.println(uname);
System.out.println(upassword);
ModelAndView modelAndView = new ModelAndView();
return modelAndView;
}

但是我们如果接收很多的参数每个参数都需要添加@RequestParam注解,这样就显得很繁琐,我们可以省略@RequestParam注解,那么就需要让我们形参的名称请求的参数的名称一致;

eg:

1
2
3
4
5
6
7
@RequestMapping("/login")
public ModelAndView login(String username,String password) {
System.out.println(username);
System.out.println(password);
ModelAndView modelAndView = new ModelAndView();
return modelAndView;
}

6.3 接收参数使用实体类来进行接收

注意: 实体类必须是一个标准的JavaBean(setter方法);

1
2
3
4
5
@PostMapping(value = "/login.do")
public ModelAndView login(User user) {
System.out.println(user.getName());
System.out.println(user.getAge());
}

6.4 获取Rest请求风格的参数(路径参数) ==讲到这了==

什么是RestFul?

RESTFUL是一种网络应用程序的设计风格和开发方式;

Post

Put

Get

Delete

1
2
3
4
5
6
7
8
9
10
11
12
13
查询:
GET /user/selectUser?id=10 #传统方式
GET /user/10 #RestFul的方式

删除:
POST /user/deleteUser?id=10 #传统方式
DELETE /user/10 #RestFul的方式

修改:
POST /user/updateUser?id=10 #传统方式
xxxxxx
PUT /user/10 #RestFul的方式
xxxx

请求url:

POST: http://localhost:8080/user

DELET:http://localhost:8080/user/10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 添加用户
*/
@PostMapping()
public void add(String name) {
System.out.println("添加用户:name=" + name);
}


/**
* 添加用户
*/
@DeleteMapping("/{id}")
public void del(@PathVariable("id") String id) {
System.out.println("删除:id=" + id);
}

@PathVariable注解不能省略;


6.5 获取请求实体的内容

image-20210311203740472

1
2
3
4
5
6
7
8
//需要添加 <mvc:annotation-driven/> 高级功能支持
@PostMapping(value = "/login")
public ModelAndView login(@RequestBody User user) {
System.out.println(user);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("index.jsp");
return modelAndView;
}

注意

  • 导入依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.0</version>
    </dependency>
  • spring-mvc.xml配置高级注解功能的支持

    1
    2
    <!--@RequestBody注解必须得配置这一项-->
    <mvc:annotation-driven/>

    此注解需要配置在之前


7. SpringMvc的响应处理

7.1 方法的返回值为void

1
2
3
4
5
@PostMapping(value = "/login")
public void login(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.setAttribute("username", "admin678");
request.getRequestDispatcher("/index01.jsp").forward(request, response);
}

7.2 方法的返回值为String类型

1
2
3
4
5
6
@PostMapping(value = "/login")
public String login(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {
//这个model里面的数据会被携带到视图中去
model.addAttribute("username", "admin234");
return "/index01.jsp";
}

7.3 方法的返回值为ModelAndView

1
2
3
4
5
6
7
@PostMapping(value = "/login")
public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws IOException {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/index01.jsp");
modelAndView.addObject("username", "admin");
return modelAndView;
}

8. mvc:annotation-driven

我们如果使用springmvc的基础功能比如:@Controller @RequestMapping @RequestParam,是不需要添加 mvc:annotation-driven的支持,但是我们如果要使用高级功能,例如: @RequestBody @ResponseBody这一些高级功能注解就需要添加mvc:annotation-driven的支持了;

我们要在 spring-mvc.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
<?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:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--高级功能注解的扩展支持(一定要放在其他配置的最前面,要不然不生效)-->
<mvc:annotation-driven/>

<!--注册处理器映射器-->
<bean name="requestMappingHandlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>

<!--注册处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>

<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>

<!--开启Springmvc的注解扫描,主要扫描处理器的注解 @Controller @RequestMapping @GetMapping @PostMapping-->
<context:component-scan base-package="com.xzy.goods.controller"></context:component-scan>
</beans>

mvc:annotation-driven一定要放在其他注解之前,要不然不会生效;


9. @ReponseBody 注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--返回的对象转换成json字符串必须导入jackson的依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.0</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.0</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>

@ReponseBody@Controller进行结合使用,可以直接返回 json 对象给客户端

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
package com.xzy.goods.controller;

import com.xzy.goods.entity.User;
import com.xzy.goods.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/user")
public class UserController {

@Autowired
UserService userService;

@PostMapping(value = "/login")
@ResponseBody
public User login(@RequestBody User user) {
System.out.println(user);
user.setId(1001);
return user;// 返回一个对象,在springmvc的底层会把对象自动转换为json字符串进行返回,还自动添加了 Content-Type: application/json
}
}

但是我们如果在每个方法上面都添加 ReponseBody 注解实在太繁琐了,所以 Spring 给我们提供了一种非常好的解决方案: @RestController

通过源码可知:

image-20210311220719635@RestController =@Controller+ @ResponseBody


10. SpringMvc的请求转发与请求重定向

10.1 传统的Servlet的方式

请求转发:

1
2
3
//请求转发
request.setAttribute("orderNum", "7823432");
request.getRequestDispatcher("/orderList.jsp").forward(request, response);

请求重定向:

1
2
//传统方式的请求重定向
response.sendRedirect("/orderList.jsp");

10.2 SpringMvc提供的方式

请求转发:

1
2
3
4
5
6
7
8
@GetMapping("/findById")
/**
* 方法的返回值为String类型,返回的是视图逻辑名称
*/
public String findById(Model model) throws ServletException, IOException {
model.addAttribute("orderNum", 220);
return "/orderList.jsp";
}

请求重定向:

1
2
3
4
5
public String findById(Model model) throws ServletException, IOException {
//重定向时会把orderNum以参数的形式携带在url中
model.addAttribute("orderNum", 220);
return "redirect:/orderList.jsp";
}

11. Springmvc中的拦截器

SpringMVC 中的Interceptor 拦截器是有相当重要的,它的主要作用是拦截用户的请求并进行相应的处理;

定义拦截器可以通过两种方式:

  • 通过实现 HandlerInterceptor 接口或继承 HandlerInterceptor 接口的实现类来定义;
  • 通过实现 WebRequestInterceptor 接口或继承 WebRequestInterceptor 接口的实现类来定义。

编写拦截器

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
package com.xzy.goods.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyAllRequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyAllRequestInterceptor...请求处理之前....");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyAllRequestInterceptor...请求处理之后......");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyAllRequestInterceptor...视图渲染结束之后");
}
}

拦截器的定义中实现了 HandlerInterceptor 接口,并实现了接口中的 3 个方法。

  • preHandle 方法:该方法在控制器的处理请求方法前执行,其返回值表示是否中断后续操作,返回 true 表示继续向下执行,返回 false 表示中断后续操作。
  • postHandle 方法:该方法在控制器的处理请求方法调用之后、解析视图之前执行,可以通过此方法对请求域中的模型和视图做进一步的修改。
  • afterCompletion 方法:该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

注册拦截器

1
2
3
4
5
6
7
8
9
10
<mvc:interceptors>
<!--配置全局拦截器,拦截所有请求-->
<bean class="com.xzy.goods.interceptor.MyAllRequestInterceptor"></bean>

<!--配置某个请求的拦截器,可以使用/**通配符-->
<mvc:interceptor>
<mvc:mapping path="/user/findById.do"/>
<bean class="com.xzy.goods.interceptor.Interceptor01"></bean>
</mvc:interceptor>
</mvc:interceptors>

拦截器与过滤器的区别

过滤器是原生的servlet中提供的过滤请求的一种机制

拦截器是SpringMvc中基于Aop的一种过滤handler的一种机制

在纯Servlet开发中不能直接使用拦截器,拦截器只能在SpringMvc中使用,

在SpringMvc中是直接可以使用过滤器的


12. SpringMvc 请求参数限定

1
2
3
4
5
@RequestMapping("/findById")
public User findById(@RequestParam(name = "id",required = false,defaultValue = "110") Integer id) {
User user = new User(id, "admin", "admin123");
return user;
}

required: 默认为true,也就是说发送的请求必须要传递这个参数,不传递就会报错,我们想要不传递也不报错就要设置为false

defaultValue: 不传递时的默认值,一般与 required = false来进行结合使用;


13. SpringMvc接收数组参数

1
2
3
4
5
6
7
8
9
10
/**
* 接收数组参数,前端访问的格式: /user/u3.do?loves=java&loves=python
* @param loves
* @return
*/
@GetMapping("/u3")
public String u3(String[] loves) {
System.out.println(Arrays.toString(loves));
return "/login.jsp";
}

14. 跨域问题

一个域的三要素:

  • 协议
  • 主机/域名
  • 端口

默认浏览器中不支持后台的ajax跨域访问的;处于安全因素考虑的

浏览器对于 javascript 的同源策略的限制,例如 http://a.cn 下面的 js 不能调用 http://b.cn 中的 js 对象或数据(因为 http://a.cnhttp://b.cn 是不同域)

同源策略会阻止一个域的 JavaScript 脚本和另一个域的内容进行交互

跨域问题的解决方案:

  • 前端解决(通过代理的方式解决,不推荐)

  • 后端解决(真正意义上解决了跨域问题)

  • CORS 方案,就是通过服务器设置响应头来实现跨域

    CORS才是解决跨域的真正解决方案。

前端需要做什么?

无需做任何事情,正常发送 Ajax 请求即可。

后端需要做什么?

需要加响应头 。或者使用第三方模块 cors 。

WebConfig 配置类解决跨域问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
//设置允许跨域的路径
registry.addMapping("/**")
//设置允许跨域请求的域名
.allowedOriginPatterns("*")
//是否允许cookie
.allowCredentials(true)
//设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
//设置允许的header属性
.allowedHeaders("*")
//跨域允许时间
.maxAge(3600);
}
}

文章作者: Yang Shiyu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yang Shiyu !
  目录