初识SpringMVC

2023年 9月 17日 70.1k 0

 前言🍭

❤️❤️❤️Spring专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️

Spring + Spring MVC + MyBatis专栏

前篇我们讲了Spring日志,知道了日志的作用,日志怎么用以及通过lombok去进行更简单的日志输出,然后我们就基本讲完了Spring 相关知识,现在进入SpringMVC的学习。

一、什么是SpringMVC🍭

官方对于 Spring MVC 的描述是这样的:

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".

Spring Web MVC是基于Servlet API的原始Web框架,从一开始就包含在Spring框架中。其正式名称“Spring Web MVC”来自其源模块(Spring -webmvc)的名称,但更常见的名称是“Spring MVC”。

Spring Web MVC :: Spring Framework

从上述官方定义的描述我们可以提取两个关键信息:

  • Spring MVC 是⼀个 Web 框架。
  • Spring MVC 是基于 Servlet API 构建的。
  • 然而要真正的理解什么是 Spring MVC?我们首先要搞清楚什么是 MVC?

    1、什么是MVC?🍉

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

    image.png

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

    2、MVC 和 Spring MVC 的关系🍉

    Spring MVC是基于MVC模式的Java Web开发框架,是Spring框架的一部分。Spring MVC提供了一种结构良好的开发模式,使得开发人员能够更好地组织和管理代码。它使用了MVC的概念,将应用程序的逻辑分离为模型、视图和控制器,并提供了一些额外的功能,如请求处理、表单验证、数据绑定等。是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架,当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求。

    因此,可以说Spring MVC是基于MVC模式的一种实现方式,它将MVC的概念应用于Web开发,并提供了一些与Web开发相关的功能和特性。

    二、为什么要学 Spring MVC?🍭

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

    SpringMVC的优点:🍓

  • 轻量级:Spring MVC是一个轻量级的框架,它只提供了基本的Web开发功能,没有过多的冗余功能,使得应用程序的开发和部署更加高效。

  • 灵活性:Spring MVC采用了基于注解的配置方式,使得开发者可以更灵活地定义控制器、请求映射和视图解析等,极大地简化了开发过程。

  • 松耦合:Spring MVC采用了MVC设计模式,将应用程序的不同层次分离开来,使得各个模块之间的耦合度降低,提高了代码的可维护性和可测试性。

  • 可扩展性:Spring MVC提供了丰富的扩展点和插件机制,开发者可以根据自己的需求进行扩展和定制,满足各种复杂的业务需求。

  • 高度集成:Spring MVC与Spring框架紧密集成,可以很容易地与其他Spring组件(如Spring Boot、Spring Security等)进行集成,提供了更完整的解决方案。

  • 强大的视图解析能力:Spring MVC提供了多种视图解析器,支持多种视图技术(如JSP、Thymeleaf、Freemarker等),使得开发者可以根据自己的喜好选择合适的视图技术。

  • 易于测试:Spring MVC采用了面向接口的编程方式,使得控制器和服务层的代码可以很容易地进行单元测试,提高了代码的质量和稳定性。

  • 在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架,如下图所示:

    image.png

    简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项目的基础,我们以后创建的所有 Spring、Spring Boot 项目基本都是基于 Spring MVC 的。

    三、怎么学 Spring MVC?🍭

    学习 Spring MVC 我们只需要掌握以下 3 个功能:

  • 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调用到我们的 Spring 程序。
  • 获取参数的功能:用户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
  • 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。
  • 对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC。

    1、Spring MVC 创建和连接🍉

    Spring MVC 项目创建和 Spring Boot 创建项目相同(Spring MVC 使用 Spring Boot 的方式创建), 在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。 在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作用。

    Ⅰ、创建SpringMVC项目🍓

  • 使用Maven方式传统的创建SpringMVC(不过这已经是过时的方法)。
  • 使用Spring Boot添加Spring Web模块(Spring MVC)。
  • 创建步骤:

    image.png

    image.png

    创建之后,初始化完成:

    image.png

    接下来,创建⼀个 TextController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
     
    @Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面
    @RequestMapping("/text")//路由注册
    public class TextController {
        
        @RequestMapping("/hi")//路由注册
        public String sayHi(){
            return "Hi,Spring MVC";
        }
    }
    

    运行起来:

    image.png

    也可以使用@RestController代替@Controller+@ResponseBody

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    @RequestMapping("/text")//路由注册
    public class TextController {
     
        @RequestMapping("/hi")//路由注册
        public String sayHi(){
            return "Hi,Spring MVC";
        }
    }
    

    Ⅱ、@RequestMapping 注解介绍🍓

    @RequestMapping 是 Spring Web 应用程序中最常被用到的注解之⼀,它是用来注册接口的路由映射的。

    路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类的某个方法的过程。

    @RequestMapping 即可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类 + 方法。

    @RequestMapping 也可以直接修饰方法,代码实现如下:

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    /*@RequestMapping("/text")//路由注册*/
    public class TextController {
     
        @RequestMapping("/hi")//路由注册
        public String sayHi(){
            return "Hi,Spring MVC";
        }
    }
    

    代码运行:

    image.png

    Ⅲ、@RequestMapping 是 post 还是 get 请求?🍓

    我们先在浏览器看一下这是post请求还是get请求?

    image.png

    可以看到这是get请求。

    下面使用 PostMan 测试⼀下,默认情况下使用注解 @RequestMapping 是否可以接收 GET 或 POST 请求?

    我们测试之后发现在现在版本的@RequestMapping 既支持GET方式的请求有支持PSOT方式的请求。

    GET:

    image.png

    POST:

    image.png

    GET方法和POST方法有什么区别🍒

    下面这篇文章讲解的十分详细了:

    面试突击71:GET 和 POST 有什么区别? - 掘金 (juejin.cn)

    指定 GET/POST 方法类型🍒

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.bind.annotation.RestController;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    /*@RequestMapping("/text")//路由注册*/
    public class TextController {
     
        @RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册
        public String sayHi(){
            return "Hi,Spring MVC";
        }
    }
    

    我们打开浏览器发现报错了,难道代码有问题?我们使用Postman看看

    image.png

    GET:

    image.png

    使用GET请求仍然报405,使用POST请求试试,发现可以访问:

    image.png

    这是因为我们设置了方法为POST,即只能使用POST请求去访问。我们的浏览器之前已经看了。它是GET请求。

    Ⅳ、@GetMapping 和 PostMapping🍓

    get 请求的 3 种写法:🍒

    // 写法1
    @RequestMapping("/hi")
    // 写法2
    @RequestMapping(value = "/hi",method = RequestMethod.GET)
    // 写法3
    @GetMapping("/hi")
    

    post 请求的 2 种写法:🍒

    // 写法1
    @RequestMapping(value = "/hi",method = RequestMethod.POST)
    // 写法2
    @PostMapping("/hi")
    

    2、获取参数🍉

    Ⅰ、传递单个/多个参数🍓

    在 Spring MVC 中可以直接用方法中的参数来实现传参,比如以下代码:

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    /*@RequestMapping("/text")//路由注册*/
    public class TextController {
     
        /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
        /*@PostMapping("/hi")*/
        @GetMapping("/hi")
        public String sayHi(String name){
            return "Hi"+name;
        }
    }
    

    不加参数,直接输出null

    image.png

    添加name参数,输出:Hi 张三

    image.png

    浏览器也是一样:

    image.png

    如果我们参数名错误(不同)则传递不成功:

    image.png

    如果我们传递了多个参数,其中有所需要的(参数名字相同),那它会自动匹配:

    image.png

    多个参数也是一样传递,而且我们通过上面,也发现了参数的顺序并不影响参数的传递。 

    总结说明:当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置 是不影响后端获取参数的结果

    Ⅱ、传递对象🍓

    当参数个数过多时,可以进行传递对象,将参数封装成一个类。

    Person对象

    package com.example.mvcdemo.controller;
     
    import lombok.Data;
    @Data
    public class Person {
        private int id;
        private String name;
        private String password;
    }
    

    TextController

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    /*@RequestMapping("/text")//路由注册*/
    public class TextController {
     
        /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
        /*@PostMapping("/hi")*/
        @GetMapping("/hi1")
        public String sayHi1(Person p){
            return "Hi "+p.getId()+" "+p.getName()+" "+p.getPassword();
        }
    }
    

    运行代码+传递参数:

    image.png

    注意事项🍒

    在Spring Boot(Spring MVC)中传参一定要是包装类型,而非基础类型。

    package com.example.mvcdemo.controller;
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
     
    /*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
    @ResponseBody//告诉程序我返回的是一个数据而非页面*/
    @RestController//@Controller+@ResponseBody
    /*@RequestMapping("/text")//路由注册*/
    public class TextController {
     
        /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
        /*@PostMapping("/hi")*/
        @GetMapping("/num")
        public String sayHi2(int num){
            return "num="+num;
        }
    }
    

    我们先正常传递参数:

    image.png

    但是如果我们忘记传递或是没有传递(前后端工作人员沟通不及时时),则会报错,而且这是非常严重的。

    image.png

    这个时候就很莫名其妙,也找不到错误。

    如果我们将int换成它的包装类时:

    正常传递参数可以正常显示:

    image.png

    没有传递参数时它则会显示null,这就会很明显发现错误的来源。

    image.png

    所以注意:参数类型应该设置为包装类

    Ⅲ、后端参数重命名(后端参数映射)🍓

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

    具体示例如下,后端实现代码:

    @RequestMapping("/m4")
    public Object method_4(@RequestParam("time") String createtime) {
            System.out.println("时间:" + createtime);
            return "Hi "+createtime;
        }
    

    代码运行:

    image.png

    这就说明参数的重命名生效了。

     还有需要注意的是使用了@RequestParam(),则这个参数是必须要传递的,我们可以看@RequestParam()源码:

    image.png

    没有传递参数时:

    image.png

    所以当这个重命名参数是非必传参数时,我们可以设置@RequestParam 中的required=false 来避免不传递时报错

    @RequestMapping("/m4")
    public Object method_4(@RequestParam(value = "time", required = false) String createtime) {
            System.out.println("时间:" + createtime);
            return "Hi "+createtime;
        }+ createtime);
    

    Ⅳ、@RequestBody 接收JSON对象🍓

    我们先来试试看接受对象的是否可以接收JSON对象:

    @GetMapping("/hi1")
        public String sayHi1(@RequestBody Person p){
            return p.toString();
        }
    

    使用Postman 传递JSON对象

    image.png

    传递的是 0 null null ,就发现传递不了。那我们传递JSON对象时应该任何传递?

    使用@RequestBody 注解。

        @PostMapping("/hi1")
        public String sayHi1(@RequestBody Person p){
            return "Hi "+p.getId()+" "+p.getName()+" "+p.getPassword();
        }
    

    不过当@RequestBody传递JSON格式对象时需要配合PostMapping一起使用,因为@RequestBody传递JSON格式对象时是Post类型传参。

    Postman:

    image.png

    Ⅴ、获取URL中参数@PathVariable🍓

    后端实现代码:

    @PostMapping("/m6/{name}/{password}")
        public Object method_6(@PathVariable String name, @PathVariable String password) {
            return "name:" + name+" password:" + password;
        }
    

    image.png

    这样写就很简洁,SEO(Search Engine Optimization 是指搜索引擎优化)效果很好。

    注意事项:@PostMapping("/m6/{name}/{password}") 中的 {password} 参数不能省略。

    这是因为在Spring的路径映射中使用了占位符(即{})来表示可变的路径段。

    /m6/{name}/{password}中的{name}和{password}都是路径变量,它们需要被具体的值替代才能匹配相应的请求路径。

    参数的位置和个数都必须保持一致。

    Ⅵ、上传文件@RequestPart🍓

    @RequestMapping("/m9")
        public String upFile(@RequestPart("myfile") MultipartFile file) throws IOException {
            // ⽂件保存地址
            String filePath = "C:\Users\lin\Pictures\JiangHai\11.png";
            // 保存⽂件
            file.transferTo(new File(filePath));
            return filePath + " 上传成功.";
        }
    

    文件夹什么都没有:

    image.png

    使用Postman进行上传文件:

    image.png

    随便选择一张图片(文件名为myFile)

    image.png

    上传成功:

    image.png

    我们也可以打开这张图片

    image.png

    但是我们发现我们把路径定死了,这在实际开发中是不可能的,那我们现在来写一个最终版的文件上传:

    @RequestMapping("/upfile")
        public String myUpFile(@RequestPart("myupfile") MultipartFile file) throws IOException {
            //根目录
            String path ="C:\Users\lin\Pictures\JiangHai\";
            //根目录+唯一文件名(进行随机取名)
            path+=UUID.randomUUID().toString();
            //根目录+唯一文件名+文件的后缀 ex: aaa.aaa.png
            path+=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
                file.transferTo(new File(path));
                return path + " 上传成功";
        }
    

    再随便上传一张图片

    image.png

    image.png

    我们也可以上传一个.txt文件:

    image.png

    上传成功:

    image.png

    注意:字段myfile允许的最大大小为1048576字节(即上传的文件是有大小限制的)

    image.png

    Ⅶ、获取Cookie/Session/header🍓

    获取 Request 和 Response 对象 🍒

    //Spring MVC(Spring Web) 内置了HttpServletRequest 和 HttpServletResponse
        @RequestMapping("/getparam")
        public String param10(HttpServletRequest request) {
            return request.getParameter("name");
        }
    

    通过获取Request对象获取参数:

    image.png

    获取Cookie🍒

    @RequestMapping("/getck")
        public String getCookie( HttpServletRequest request) {
            // 获取所有 cookie 信息
            Cookie[] cookies = request.getCookies();
            for(Cookie item:cookies){
                log.error(item.getName()+" "+item.getValue());
                //log的使用需要添加@Slf4j注解
            }
            return "get cookie!";
        }
    

    打开浏览器开发人员工具(F12) ,手动添加结果Cookie:

    image.png

    浏览器访问 localhost:8080/getck

    控制台就会将我们的Cookie打印出来:

    image.png

    上面我们是获取全部Cookie,我们也可以去获取指定的Cookie:

    @RequestMapping("/getck2")
        public String getCookie2(@CookieValue("zhangsan") String val) {
            return "Cookie Value: "+val;
        }
    

    image.png

    明明你在请求时没有加Cookie,为什么可以拿到呢?这是因为浏览器,浏览器自己实现了这个机制,浏览器会在你每一次访问网站时,将这个网站的所以Cookie传送给你的后端。

    可以看下面:

    image.png

    为什么浏览器会去实现这个机制呢?

    是因为HTTP协议是一种无状态协议,服务器无法知道用户之前的状态信息。

    为了解决这个问题,Web应用使用了Cookie机制来跟踪和记录用户的状态。当用户首次访问一个网站时,服务器会在响应中设置一个或多个Cookie,并将它们发送到用户的浏览器。浏览器会将这些Cookie保存起来。

    随后,当用户再次访问同一网站时,浏览器会将之前保存的Cookie附加到请求中,然后发送给服务器。这样,服务器可以通过读取Cookie中的信息来识别并恢复用户的状态,例如登录信息、用户偏好等。

    因此,浏览器在每次访问网站时将所有与该网站相关的Cookie传送给后端,以便服务器能够根据这些Cookie识别用户并提供相应的服务。

    需要注意的是,浏览器会根据Cookie的设置规则来决定是否发送Cookie,例如Cookie的过期时间、域名限制等。

    简洁获取 Header—@RequestHeader🍒

    @RequestMapping("/header")
    public String header(@RequestHeader("User-Agent") String userAgent) {
         return "userAgent:"+userAgent;
    }
    

    浏览器:

    image.png

    Session 存储和获取🍒

    Session 存储和 Servlet 类似,是使⽤ HttpServletRequest 中获取的,如下代码所示

    @RequestMapping("/setsess")
        public String setsess(HttpServletRequest request) {
            // 获取 HttpSession 对象,参数设置为 true 表示如果没有 session 对象就创建⼀个session
            HttpSession session = request.getSession(true);
            if(session!=null){
                session.setAttribute("username","username");
            }
            return "session 存储成功";
        }
    

    读Session①

    //读Session1
        @RequestMapping("/getsess")
        public String sess(HttpServletRequest request) {
            // 如果 session 不存在,不会⾃动创建
            HttpSession session = request.getSession(false);
            String username = "暂⽆";
            if(session!=null && session.getAttribute("username")!=null){
                username = (String) session.getAttribute("username");
                return (String)session.getAttribute("username");
            }
            return "暂无Session信息!";
        }
    

    读Session②(更简洁的方式)

    //读Session2
        @RequestMapping("/getsess2")
        public String sess2(@SessionAttribute(value = "username",required = false)
                            String username) {
            return "username:"+username;
        }
    

    我们先去读Session,可以发现浏览器显示:暂无Session信息!

    image.png

    然后我们去存储Session:

    image.png

    再去读取Session就有了:

    image.png

    当然Session是默认存在内存中的,如果当我们程序重新启动时,就没了,这是因为内存中的数据不具有持久性,无法跨越程序重启的边界。

    3、返回数据🍉

    Ⅰ、返回静态页面🍓

    创建前端页面 hello.html

    image.png

    
    
    
        
        
        
        hello,spring mvc
        
    
    
    Hello,Spring MVC.
    
    
    

    创建控制器 RespController:

    package com.example.mvcdemo.controller;
     
     
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
     
    @Controller
    @RequestMapping("/resp")
    public class RespController {
        @RequestMapping("/hi")
        public String sayHi(String name){
            return "/hello.html";
        }
    }
    

    image.png

    Ⅱ、返回text/html🍓

    如果我们加上@ResponseBody,则显示:

    image.png

    Ⅲ、返回 JSON 对象🍓

    @ResponseBody
        @RequestMapping("/m8")
        public HashMap method_8() {
            HashMap map = new HashMap();
            map.put("Java", "Java Value");
            map.put("MySQL", "MySQL Value");
            map.put("Redis", "Redis Value");
            return map;
        }
    

    当你使用字典(键值对)类型时,Spring MVC会自动将其转换成JSON对象

    image.png

    Ⅳ、请求转发或请求重定向🍓

    forward VS redirect

    return 不但可以返回⼀个视图,还可以实现跳转,跳转的方式有两种:

    • forward :请求转发;
    • redirect:请求重定向。

    请求转发和重定向的使用对比:

    // 请求重定向
    @RequestMapping("/hello")
    public String hello(){
         return "redirect:/hello.html";
    }
    // 请求转发
    @RequestMapping("/hello2")
    public String hello2(){
         return "forward:/hello.html";
    }
    

    forward(请求转发)和 redirect(请求重定向)的区别,举例来说,例如,你告诉你妈妈,你想吃辣条,如果你妈妈,说好,我帮你去买,这就是 forward 请求转发;如果你妈妈让你自己去买,那么就是请求 redirect 重定向。

    “转发”和“重定向”理解:在中国官⽅发布的内容越少事也越大, “转发”和“重定向”也是⼀样:字越少,责任越大 。转发是服务器帮转的,而重定向是让浏览器重新请求另⼀个地址。

    forward 和 redirect 具体区别如下:

  • 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
  • 请求重定向地址发⽣变化,请求转发地址不发⽣变化。
  • 请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。
  • 请求转发如果资源和转发的页面不在⼀个目录下,会导致外部资源不可访问 。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论