SpringMVC之使用SpringMVC获取参数与返回数据

举报
未见花闻 发表于 2022/11/30 21:35:51 2022/11/30
【摘要】 ⭐️前面的话⭐️本篇文章将介绍SpringMVC的概念,SpringMVC项目的创建,如何使用SpringMVC实现前端参数的获取与后端参数的返回等内容。 1.Spring MVC概述 1.1什么是Spring MVC? 1.1.1官方定义官方是这样给出解释的:Spring Web MVC is the original web framework built on the Servlet ...

⭐️前面的话⭐️

本篇文章将介绍SpringMVC的概念,SpringMVC项目的创建,如何使用SpringMVC实现前端参数的获取与后端参数的返回等内容。

1.Spring MVC概述

1.1什么是Spring MVC?

1.1.1官方定义

官方是这样给出解释的:

Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,” comes from the name of its source module (spring-webmvc), but it is more commonly known as “Spring MVC”.
Parallel to Spring Web MVC, Spring Framework 5.0 introduced a reactive-stack web framework whose name, “Spring WebFlux,” is also based on its source module (spring-webflux).

我们简单翻译一下:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring Framework 中。正式名称“Spring Web MVC”来自其源模块的名称(spring-webmvc),但更常见的是“Spring MVC”。
与 Spring Web MVC 并行,Spring Framework 5.0 引入了一个响应式堆栈 Web 框架,其名称“Spring WebFlux”也是基于其源模块 ( spring-webflux)。

嗯,我没怎么看懂,其实Spring MVC就是一个Web项目,我们简单从官方给出的定义中提炼一些东西:

  • SpringMVC全名叫做Spring Web MVC。
  • SpringMVC项目基于Servlet API构建,所以之前Servlet那一套操作,SpringMVC也支持。
  • SpringMVC项目相比于Spring项目多了Web模块。

在了解SpringMVC之前,我们先来了解一下MVC,什么是MVC呢?

1.1.2MVC与SpringMVC

MVC是Model View Controller的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。

1.1.2
Model+View+Controller就是一个项目,或者是一个软件。

Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的,这里的View指的是服务器视图(如JSP),而不是前端(客户端)的视图。
Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。

MVC与Spring MVC之间的区别?
MVC是设计思想,Spring MVC是一种具体的实现。
Spring MVC是一种基于MVC设计模式和Servlet API实现的Web项目,而SpringMVC是Spring框架中的一个Web模块,它是随着Spring诞生而存在的一个框架。

1.2Spring MVC的优势

现在绝大部分的Java项目都是基于Spring(或Spring Boot)的,而 Spring的核心就是Spring MVC。也就是说 Spring MVC是 Spring 框架的核心模块,而 Spring Boot是 Spring 的脚手架,因此我们可以推断出,现在市面上绝大部分的Java项目基本上都是Spring MVC项目,这也是我们要学Spring MVC的原因。

我们学习SpringMVC项目,有三个目的:

  • 能够用户(浏览器)与程序链接起来。
  • 能够获取到用户端传来的数据。
  • 能够对用户传来的数据进行处理,并返回数据给用户端。

2.SpringMVC项目的创建与使用

2.1创建SpringMVC项目

首先,我们需要新建SpringBoot项目。

1
2

一定要添加Web模块,因为它使用的就是SpringMVC的依赖。
3
最后在给项目设置个路径和名字就可以了。

2.2设置路由

设置路由可以实现程序与用户之间的映射,而设置路由可以使用@RequestMapping注解实现,需要实现路由访问,必须使用@Controller将对象储存到Spring。

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

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

    @ResponseBody
    @RequestMapping("/hello")
    public String sayHi() {
        return "hello";
    }
}

其中,访问方法所返回数据或页面的url为http://IP:端口号/类上的路由地址/方法上加的路由地址,这样就能访问到每个方法所返回的页面或者数据了,类上也可以不设置路由地址,这样直接拿方法的路由地址作为一级目录直接访问就可以了。
由于历史原因,方法返回默认是一个静态页面,如果要设置返回一个页面数据,需要搭配使用 @ResponseBody注解。

启动程序,我们去浏览器通过访问./user/hello地址能否获取到hello
1
关于@ResponseBody注解,你也可以使用在类上,这样类里面所有的方法都会默认放回的是页面数据,而不是一个静态页面。

@RequestMapping注解不仅支持GET方式请求方式也支持POST等其他请求方式。并且默认情况下,同时支持多种请求方式,如果想要仅支持一种请求方式,我们需要做一些配置。

我们需要设置@RequestMapping的method属性为RequestMethod.xxx,RequestMethod其实是一个枚举,里面储存了多种的请求方式。
777

@Controller
@ResponseBody
@Slf4j
@RequestMapping("/user")
public class UserController {
    @RequestMapping(method = RequestMethod.POST, value = "/onlypost")
    public String func1() {
        return "post";
    }
}

我们使用postman构造GET与POST请求看看能不能进行处理。

首先我们来试一试GET请求,
1111
通过抓包,返回给用户的结果是405,出错了,这就表示该方法不支持GET请求,我们再来试一试POST请求。

2222
构造POST请求:
3333
返回结果:
4444
返回了一个post数据,与我们预期相同,所以像上面那样进行配置,可以使一个方法只支持GET或POST一种请求格式。

当然还有另外的方法,如果只支持POST请求,我们还可以使用@PostMapping注解来实现。

    @PostMapping("/hello2")
    public String func2() {
        return "hello2";
    }

7777

8888

同理,如果支持GET请求我们也可以使用@GetMapping注解来进行实现。

2.3获取参数

在MVC项目中,因为SpringMVC是基于Servlet的,所以使用Servlet那一套操作也是可以的,只不过有点繁琐,Spring有更方便获取参数的方式。

2.3.1获取一个参数

假设有一个类UserInfo,客户会传一个用户ID到后端,我们需要返回一个UserInfo对象。

@Data
public class UserInfo {
    private Integer id;
    private String name;
    private String password;
}

根据ID查询UserInfo对象,为了方便,我们不使用数据库进行查询了,直接构造相应ID的对象,返回即可,能够模拟数据的传入与传出是重点。

    @RequestMapping("/getuserbyid")
    public UserInfo getUserById(Integer id) {
        //不查询数据库,这个方法目的意在接收前端一个参数返回一个数据
        //所以我们直接构造一个对应id的Userinfo对象即可
        UserInfo userInfo = new UserInfo();
        userInfo.setId(id);
        userInfo.setName("张三");
        userInfo.setPassword("12345678");
        return userInfo;
    }

我们通过postman来构造一个id参数,并获取到一个UserInfo对象。

获取一个参数
我们直接在方法中加上一个形参,然后会自动根据形参的名字以前端传来参数的key进行匹配,如果能够对应,后端就能成功接收参数,这比Servlet方便不少。

除此之外,Spring会根据响应的返回值,决定返回数据的类型,比如你返回一个对象或Map,就会返回一个json格式的数据,你返回一个页面,那它返回的就是页面类型的数据。

2.3.2获取多个参数

我们会了获取一个参数,那么获取多个参数同样也不在话下,我们可以给方法设置多个参数,也可以设置一个对象参数直接获取多个前端传来的参数。

比如,一个登录的逻辑,需要用户传来账户名与密码,我们就不实现一个登录逻辑了,我们直接将获取到的账户名与密码作为响应返回出去,毕竟我们的重点是多个参数的获取。

    @RequestMapping("/login") 
    public String login(String name, String password) {
        return "用户名:" + name + "密码:" + password;
    }

我们从前端传入同名的键值对,后端就能够自动获取到。
9999
当然,我们也可以使用对象来进行接收前端的参数,后端会根据key与对象中的属性名自动地进行匹配。

    @RequestMapping("/object")
    public String getObject(UserInfo userInfo) {
        return userInfo.toString();
    }

UserInfo中的属性有id,name和password,我们直接从前端传递三个对应名称的键值对,就可以自动被UserInfo对象获取。

1010

除此之外,我们还可以接收form表单的形式的参数,不过得是POST请求方式,使用GET请求不能获取到参数,毕竟GET方式是使用查询字符串传递参数。
1111
如果想要获取json对象这种类型的参数,现在是做不到的,需要使用@RequestBody修饰方法参数才行,后面再说。
2222

2.3.3参数重命名@RequestParam

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个time给后端,而后端又是有createtime字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用@RequestParam来重命名前后端的参数值。

其中@RequestParam里面的参数为前端传来的参数名字,它可以自动匹配到所对象后端的形参中。

    @RequestMapping("/rename")
    public String getNameAndPass(@RequestParam("name") String username, @RequestParam("pass") String password) {
        return "用户名:" + username + "密码:" + password;
    }

3
并且使用@RequestParam注解修饰的参数,默认情况下,参数是必传,如果不传或少传就会报错。
4
这是因为@RequestParam注解里面还有一个属性required,默认情况下为true,这个属性的意思是是否是必须参数,所以参数重命名后,重命名的参数默认情况下不能缺少,如果不想将参数设置成必须,但是想重命名,那么就需要额外设置required属性为false

    @RequestMapping("/rename")
    public String getNameAndPass(@RequestParam(name = "name", required = false) String username, @RequestParam(name = "pass", required = false) String password) {
        return "用户名:" + username + "密码:" + password;
    }

8989

2.3.4获取json字符串

前面我们已经介绍了获取一个和多个参数,但是我们发现无法获取到json格式的参数,如果我们想要获取json格式的参数,需要使用@RequestBody注解修饰参数才行。

    @RequestMapping("/object")
    public String getObject(@RequestBody UserInfo userInfo) {
        return userInfo.toString();
    }

像上面这样,我们能够获取到json格式的参数了。
99999
这样设置后,就不能接收form表单格式的数据了。

2.3.5获取URL中的参数

这里所说的从URL获取参数,不是获取查询字符串部分的参数,而是直接拿URL地址中的参数,简单来说,就是从URL中?前面的字段中获取参数。

24254
比如,在有一些游戏网站中,有类似与王者营地这一种游戏工具软件或网页,它们的网址就可能直接将角色名作为URL地址的一部分,比如http(s)://dota2.uuu9.com/角色名

这样做的好处,就是在浏览器搜索的时候,优先级比较高,有利于提高曝光度。

获取方法:使用特定URL格式和在参数前加上注解@PathVariable

    @RequestMapping("/hero/{id}/{name}")
    public String geuURL(@PathVariable Integer id, @PathVariable String name) {
        return "id:" + id + "  name:" + name;
    }

我们访问http://127.0.0.1:8080/user/hero/2333/辉夜网页就能够获取到如下内容:
2333
其中hero表示二级目录地址,后面使用{}的就表示参数。
具体

2.3.6上传文件

文件的上传,我们需要使用到 @RequestPart注解和MultipartFile,我们写方法形参定义的时候,需要一个MultipartFile变量来接收前端传递的文件参数,并设置@RequestPart的属性来表示接收前端参数的名字。

    //上传文件
    @RequestMapping("/upimg")
    public boolean updateImg(Integer id, @RequestPart("img") MultipartFile file) {
        boolean result = false;
        try {
            //将图片保存
            file.transferTo(new File("D:\\Doc\\img.png"));
            result = true;
        } catch (IOException e) {
            log.error("图片上传失败!" + e.getMessage());
        }
        return result;
    }

我们使用postman构造一个请求,给服务器端发送一个图片,我们来看看目标目录下是否有我们上传的文件。
res
目标目录:
ok
但是,在实际开发当中,保存的文件路径并没有写死,并且在开发时是一个运行环境,在生产上线时是另外一个环境,所以最好的方式就是将保存的图片路径放在配置文件当中,然后读取配置环境中的保存图片路径即可,并且设置多种环境所需的配置文件,这样当环境改变时,我们仅需要改动配置文件就可以了,而代码一行都不用变。

一般情况下,我们最少准备3个配置文件,一个是默认的配置文件,即名为applicationymlproperties格式文件,其余的就是不同环境下不同的配置文件,配置文件名有规定,那就是application-xxx,后面那个xxx我们自定义,前面的一坨是固定写法,如开发环境的配置文件可以是application-dev.yml,生产环境的配置文件可以是application-prod.yml

1233
我们可以在主配置文件application.yml中来配置配置文件的运行平台

# 设置配置文件的运行平台
spring:
  profiles:
    active: xxx
    # 如运行application-dev配置文件 即active: dev

然后,在各个环境下的配置文件中,配置不同的参数,如在开发配置文件中配置图片保存路径:

# 文件保存路径
img:
  path: D:/Doc/

最后,在主配置文件运行开发环境下的配置文件,就可以了。

下面我们来实现一个小案例,就是实现一下头像的修改功能,那这个功能的实现有三步:
第一步,配置保存的路径,并获取
第二步,设置不会重名的图片名称(UUID)
第三步,获取图片格式,得到文件的格式
第四步,将随机UUID与图片格式拼接得到完整的图片文件名
第五步,储存图片

对于不重名文件名的设定,我们可以使用UUID,UUID可以自动生成一个唯一的标识序列,当然你也可以使用id,只不过使用id据局限性较大,相比于UUID,因为id只能使用一次嘛,用完了就没有了,当然你也可以使用添加一些特定前后缀来使他唯一,但总的来说UUID更通用。

//获取配置文件的保存路径
    @Value("${img.path}")
    private String path;

    //上传文件
    @RequestMapping("/upimg")
    public boolean updateImg(Integer id, @RequestPart("img") MultipartFile file) {
        boolean result = false;

        //得到原图片名称
        String fixName = file.getOriginalFilename();
        //得到图片后缀
        String fixType = fixName.substring(fixName.lastIndexOf("."));
        //生成不重名的文件名
        fixName = UUID.randomUUID().toString() + fixType;
        try {
            //将图片保存
            file.transferTo(new File(path + fixName));
            result = true;
        } catch (IOException e) {
            log.error("图片上传失败!" + e.getMessage());
        }
        return result;
    }

cg

2.3.7获取Cookie/Header

这几个参数呢,一般用户是不会传递这些的,基本上都是浏览器发送过来的,其中Cookie与Session用在登录验证,Header用的比较多的就是获取用户的浏览器的一些基本信息了。

我们知道SpringMVC是基于Servlet的,因此Servlet那一套在这里也是可行的,在MVC中,方法中的HttpServletRequest 与HttpServletResponse参数默认是隐藏的,如果想要使用,显示地声明后就能使用了。

    //mvc是基于Servlet,方式1使用Servlet那一套获取
    @RequestMapping("/servlet")
    public void get(HttpServletRequest req, HttpServletResponse resp) {
    }

用法与之前使用Servlet方式一模一样。

使用Servlet方式获取Cookie:

    @RequestMapping("/cookie")
    public void getCookie(HttpServletRequest req) {
        //获取请求中全部的cookie
        Cookie[] cookies = req.getCookies();
        for (Cookie x : cookies) {
            log.info("CookieKey:" + x.getName() + "   CookieValue:" + x.getValue());
        }
    }

为了防止空指针异常,我先在浏览器随便加上一些Cookie。

1

下面我们刷新网页,看看控制台是否有输出我们所传的Cookie。
2
发现有记录,说明我们成功获取到了Cookie。

简洁地获取Cookie,使用@CookieValue注解

    @RequestMapping("/cookie2")
    public String getCookie2(@CookieValue("1212") String cookie) {
        return "CookieValue:" + cookie;
    }

本来前面我们随机设置了一个cookie,即1212:3554,@CookieValue所传参数为你需要获取cookie的key,使用该注解修饰一个变量,变量里面就会自动获取对应的value值。

3
如果需要多个Cookie值,就写多个@CookieValue修饰变量就行。

使用Servlet获取Header

    @RequestMapping("/getua")
    public String getUA(HttpServletRequest req) {
        return "用户浏览设备信息:" + req.getHeader("User-Agent");
    }

4
更简单地获取Header,使用@RequestHeader

和前面使用注解@CookieValue用法类似,也是设置一个key来获取对应的value。

    @RequestMapping("/getua2")
    public String getUA2(@RequestHeader("User-Agent") String ua) {
        return "用户浏览设备信息:" + ua;
    }

5

2.3.8存储和获取Session

在登录逻辑中,我们需要存储Session对象,这一步存储操作,SpringMVC与Servlet操作是一样的,获取方式则有两种方式。

存储Session对象:

    @RequestMapping("/setsession")
    public boolean setSession(HttpServletRequest req) {
        boolean result = false;
        //1.获取Session,boolean参数表示不存在Session时是否新建,登录的时候是需要新建的
        HttpSession session = req.getSession(true);
        //2.设置Session里面的内容
        session.setAttribute("User对象", "一个对象");
        result = true;
        return result;
    }

当新建一个Session对象后,后端会返回一个Cookie给前端,根据这个Cookie下次验证的时候就能自动登录,不用再次输入账号密码登录了。
6
使用Servlet模式获取Session:

    @RequestMapping("/getsession")
    public String getSession(HttpServletRequest req) {
        String result = "";
        //1.获取Session
        HttpSession session = req.getSession(false);
        //2.验证
        if (session != null && session.getAttribute("User对象") != null) {
            result = (String) session.getAttribute("User对象");
        }
        return result;
    }

下面我们开始执行该代码,注意访问getsession之前一定要先访问setsession,不然页面就说明都没有。

8
更加简洁获取Session,使用@SessionAttribute
该注解有两个属性,value表示需要获取Session对象里面内容的key值,还有一个require表示修饰的参数是否必须,一般需要设置为false,如果设置成true,没有获取到对应的value就会返回一个400的页面。

    @RequestMapping("/getsession2")
    public String getSession2(@SessionAttribute(value = "User对象", required = false) String session) {
        return session;
    }

运行结果

2.4返回数据

2.4.1返回普通的text文本

由于历史原因,在方法中返回的数据默认是一个静态页面,如果没有找到这个静态页面,就会显示404,。

@Controller
public class TestController {

    @RequestMapping("/sayhi")
    public String sayHi() {
        return "hello";
    }
}

页面访问结果:

333
我们可以写一个简单的静态页面,放入static目录,来验证一下是否能够获取到。
444

@Controller
public class TestController {
    @RequestMapping("/sayhi")
    public String sayHi() {
        return "hello.html";
    }
}

访问页面结果:

555

如果想要返回一个数据,则需要使用注解@ResponseBody修饰对应的方法或者修饰类才能实现。

@Controller
public class TestController {
    @RequestMapping("/sayhi")
    @ResponseBody
    public String sayHi() {
        return "hello.html";
    }
}

666

关于@ResponseBody注解:

  • 当@ResponseBody修饰类时,被修饰类里面的所有方法都会返回一个非静态页面数据。
  • 当@ResponseBody修饰方法时,被修饰的方法返回的是一个非静态页面的数据。

或者使用@RestController注解修饰类,其实就是一个组合注解,是@Controller与@ResponseBody注解的组合。

@RestController
public class TestController {
    @RequestMapping("/sayhi")
    public String sayHi() {
        return "hello.html";
    }
}

访问页面结果:

777

小案例,实现一个加法计数器,前端页面就随便写写,不使用CSS了,我们目的是练习返回后端数据。

<!doctype html>
<html lang="en"> <head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initialscale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>计算器示例</title>
</head> 
<body>
<form action="calc">
    <h1>计算器</h1>
    数字1<input name="num1" type="text"><br>
    数字2<input name="num2" type="text"><br>
    <input type="submit" value=" 点击相加 ">
</form>
</body>
</html>

后端处理代码,返回一个结果:

@RestController
public class CalcController {

    @RequestMapping("/calc")
    public String calc(Integer num1, Integer num2) {
        return "<h2>" + (num1+num2) + "</h2>";
    }
}

前端输入数据:
464
后端返回结果:
2344
我们还可以在后端做非空验证,和添加一个返回原页面的按钮或标签。

@RestController
public class CalcController {

    @RequestMapping("/calc")
    public String calc(Integer num1, Integer num2) {
        if (num1 == null || num2 == null) return "<h2>参数错误!</h2><a href='javascript:history.go(-1)'>返回</a>";
        return "<h2>" + (num1+num2) + "</h2><a href='javascript:history.go(-1)'>返回</a>";
    }
}

效果:

3556

2.4.2返回JSON对象

下面来介绍如何返回一个JSON对象,在Spring中很简单,之间返回一个HashMap<String, Object>对象即可,Spring会自动处理成JSON对象。

下面我们通过一个登录小案例来进行演示:

前端代码如下,使用ajax构造post请求,传递账号与密码参数。如果你想要传递一个JSON对象字符串,则需要设置ajax对象参数中的contentType : "application/json; charset=utf8",最好先将对象转换成JSON字符串,即使用JSON.stringify方法。

前端做的事大致是发送含有账号与密码参数的请求,等待后端验证是否登录成功,如果不成功说明登录失败的理由。

<!doctype html>
<html lang="en"> <head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="jquery.min.js"></script>
    <title>login</title>
    <script>
        function mysub() {
            //使用jQuery获取表单提交的数据
            let username = jQuery("#username");
            let password = jQuery("#password");
            //验证是否为空字符串或者是空格字符串,trim能够去除字符串两边的空格
            if (jQuery.trim(username.val()) === "") {
                alert("用户名不能为空!");
                //将光标定位到当前输入框最前面
                username.focus();
                return;
            }
            if (jQuery.trim(password.val()) === "") {
                alert("密码不能为空!");
                //将光标定位到当前输入框最前面
                password.focus();
                return;
            }
            let user = {
                "username" : username.val(),
                "password" : password.val()
            }
            //$是通用符,当有其他的API也使用$时就会出问题,因此建议使用jQuery原名
            jQuery.ajax({
                url: "user/login",
                type: "post",
                //需要传递json格式数据,参考注释中的代码,直接写默认是x-www=form-urlencoded格式
                // contentType : "application/json; charset=utf8",
                // data: JSON.stringify(user),
                data: user,
                success: function (body) {
                    alert(body.msg);
                }
            });
        }
    </script>
</head>
<body>
<div style="text-align: center;">
    <h1>登录</h1>
    用户:<input id="username">
    <br>
    密码:<input id="password" type="password">
    <br>
    <input type="button" value=" 提交 " onclick="mysub()"
           style="margin-top: 20px;margin-left: 50px;">
</div>
</body>
</html>

在后端,我们首先需要接收账号与密码参数,然后对这些参数进行确认,为了方便起见,我们将账号与密码写死,即账号是admin密码是admin才能登录成功。

我们返回一个json格式的数据给前端,里面包含状态state,是否登录成功ok,具体原因msg,我们经过一系列验证,将这三种参数以键值对的形式储存到哈希表中返回即可。

//存在父路径user
    @RequestMapping("/login")
    public HashMap<String, Object> login(@RequestParam(value = "username", required = false) String name, String password) {
        HashMap<String, Object> res = new HashMap<>();
        //假设用户只有admin,密码也是admin
        //状态码
        int state = 200;
        //是否登录成功
        boolean ok = false;
        //原因
        String msg = "未知错误!";
        //对密码进行验证
        if (StringUtils.hasLength(name) && StringUtils.hasLength(password)) {
            //账号与密码均不为空
            if (name.equals("admin") && password.equals("admin")) {
                //验证通过
                ok = true;
                msg = "登录成功!";
            } else {
                //账号或密码错误
                msg = "账号或密码错误!";
            }
        }
        res.put("state", state);
        res.put("ok", ok);
        res.put("msg", msg);
        //spring中返回map会自动转换成json格式
        return res;
    }

实现效果:

登录

2.4.4实现请求转发与重定向

请求转发是服务器端的行为,是服务器去拿到数据发送给浏览器,相当于张三找李四借钱,但李四没钱,于是李四让张三喝杯茶,自己去找王五借了钱然后在借给张三。

请求转发实现方式1:

    @RequestMapping("/fw")
    public String myForward() {
        //转发html静态页面
        return "forward:/hello.html";
    }

这种方式其实forward:/是可以省略的,因为我们知道默认情况下,返回的就是一个静态页面。

1
请求转发实现方式2:

    @RequestMapping("/fw2")
    public void myForward2(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("hello.html").forward(req, resp);
    }

效果是一样的:
2

请求重定向其实是浏览器的行为,因为服务端只是发送一个重定向响应,告诉浏览器要去访问哪个地方,浏览器收到服务器的重定向响应后,就会去访问目标地址,所以请求重定向是浏览器的行为,相当于张三找李四借钱,但李四没钱,于是李四告诉张三它没有钱,要它去找王五借钱。

请求重定向的实现方式1: 与请求转发类似,只不过将forward改为redirect

    @RequestMapping("/rd")
    public String myRedirect() {
        return "redirect:/hello.html";
    }

效果图:
我们从rd跳转到hello.html页面了。
redirect

请求重定向的实现方式2:

    @RequestMapping("/rd2")
    public void myRedirect2(HttpServletResponse resp) throws IOException {
        resp.sendRedirect("hello.html");
    }

效果也是一样的:
243

请求转发forward与请求重定向redirect之间的区别:

  • 定义不同:请求转发发生在服务端程序内部,当服务器端收到一个客户端的请求之后,会先将请求,转发给目标地址,再将目标地址返回的结果转发给客户端;请求重定向指的是服务器端接收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头中记录了,客户端需要再次发送请求(重定向)的 URL 地址,客户端再收到了地址之后,会将请求发送到新的地址上,这就是请求重定向。
  • 请求方不同:请求转发是服务器端的行为,是服务器提出请求去获取资源,而请求重定向是客户端的行为,服务器只是告诉服务器去哪里拿资源,实际上是客户端提出请求去获取资源。
  • 数据共享不同,请求转发是服务器端实现的,所以整个执行流程中,客户端(浏览器端)只需要发送一次请求,因此整个交互过程中使用的都是同一个 Request 请求对象和一个 Response 响应对象,所以整个请求过程中,请求和返回的数据是共享的;而请求重定向客户端发送两次完全不同的请求,所以两次请求中的数据是不同的。
  • 请求转发是服务器端代为请求,再将结果返回给客户端的,所以整个请求的过程中 URL 地址是不变的;而请求重定向是服务器端告诉客户端去另外一个地方,于是客户端会再次发送一个请求,因此客户端最终访问的URL会发生变化,不是最初的那个URL。
  • 代码实现是不同的,上面我们也演示了,它们的代码实现是不同的,尽管类似,但是还是有区别。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。