第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

06-01 1688阅读

✨前言:传参和状态管理,看似简单其实门道不少

在 Web 开发中,前端和后端最核心的交流方式就是“传参”,而“传参”除了涉及如何写代码获取参数,还藏着很多开发者容易忽略的细节:

  • 为什么 URL 带了中文,后端拿到是乱码?

  • @PathVariable 和 @RequestParam 到底怎么选?

  • 前端传 数据(#),后端拿不到值怎么办?

  • 用户登录后,我要怎么“记住”他?

  • Cookie 和 Session 有啥区别,怎么用才优雅?

    这些问题都是你在 Spring MVC 实战中一定会遇到的!本篇内容就是为了解决这些“看起来简单,实际容易踩坑”的问题。


    📌 本期我们将系统讲解以下几个关键点:

    1. 多种传参方式(GET、POST、Path、JSON)

    2. 中文、空格、特殊字符(# % & +)等处理方式

    3. 如何在 Spring MVC 中正确获取和管理 Cookie/Session

    不仅让你学会“怎么用”,还帮你彻底搞懂“为什么这样用”。


    📎 适合人群:

    • 初学 Spring MVC 的小伙伴

    • 使用前后端分离开发时遇到参数/状态问题的开发者

    • 想彻底理解请求细节、编码和状态管理原理的同学、

       第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)


      🧭 第一章:Spring MVC 中的多种数据传参方式

      前后端交互的核心是“请求—响应”,而传参方式直接决定了后端能否正确拿到前端发送的数据。Spring MVC 支持多种传参方式,每种方式都各有使用场景和注意事项。



      🔹 1.1 Query 参数(GET 请求)

      在 Web 开发中,最常见的请求类型之一就是 GET 请求,用于向后端“索取资源”。GET 请求通常会将参数拼接在 URL 的末尾,形式如下:

      /search?keyword=java&page=1
      

      这类参数就叫做 Query 参数,也称为 URL 查询参数。


      ✅ 使用 @RequestParam 获取参数

      Spring MVC 中可以使用 @RequestParam 注解来接收 GET 请求的参数。

      @GetMapping("/search")
      public String search(@RequestParam("keyword") String keyword,
                           @RequestParam("page") int page) {
          System.out.println("搜索关键词:" + keyword + ",页码:" + page);
          return "searchResult";
      }
      

      如果你访问:

      http://localhost:8080/search?keyword=springmvc&page=2
      

      控制台输出将会是:

      搜索关键词:springmvc,页码:2
      

      🛠️ 默认值 & 是否必传配置

      有些参数可能不是必传的。比如分页的 page 参数,默认展示第一页。这时候可以设置参数为可选,并给一个默认值:

      @GetMapping("/search")
      public String search(@RequestParam(defaultValue = "spring") String keyword,
                           @RequestParam(required = false, defaultValue = "1") int page) {
          System.out.println("搜索关键词:" + keyword + ",页码:" + page);
          return "searchResult";
      }
      
      解释:
      • required = false:表示这个参数不是必须要传的。

      • defaultValue = "...":如果参数没有传,则使用默认值。


        🔍 小细节提示:

        • @RequestParam 不区分 GET/POST,本质上是从参数中提取数据。

        • 如果你传的是数组/列表,可以直接使用 List 或 String[] 接收。

          @GetMapping("/tags")
          public String tags(@RequestParam List tag) {
              // /tags?tag=java&tag=spring&tag=web
              System.out.println(tag); // [java, spring, web]
              return "tagList";
          }
          

          🔹 1.2 传递参数(POST 请求)

          ✅传递单个参数

          接收单个参数,在SpringMVC中直接⽤⽅法中的参数就可以,⽐如以下代码:

          @RequestMapping("/user")
          public class user {
              @RequestMapping("/m1")
              public String m1(String name) {
                  return "接受参数name"+ name;
              }
          }

           咱们使⽤浏览器发送请求并传参

          http://127.0.0.1:8080/user/m1?name=spring

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          可以看到,后端程序正确拿到了name参数的值.

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          SpringMVC会根据⽅法的参数名,找到对应的参数,赋值给⽅法

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          如果参数不⼀致,是获取不到参数的.

          ⽐如请求URL:http://127.0.0.1:8080/user/m1?name1=spring

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          注意事项 

          使⽤基本类型来接收参数时,参数必须传(除boolean类型),否则会报500错误 类型不匹配时,会报400错误 

           @RequestMapping("/age")
              public String age(int age) {
                  return "接受的数字为age "+ age;
              }

          1. 正常传递参数

          http://127.0.0.1:8080/user/age?age=1

          浏览器响应情况:

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          通过Fiddler观察请求和响应,HTTP响应状态码为200,Content-Type 为text/html

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          2. 不传递age参数

          http://127.0.0.1:8080/user/age

          浏览器响应情况:

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          通过Fiddler观察请求和响应,HTTP响应状态码为500

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          3. 传递参数类型不匹配

          http://127.0.0.1:8080/user/age?age=abc

          浏览器响应情况:

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          通过Fiddler观察请求和响应, HTTP响应状态码为400

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          对于包装类型,如果不传对应参数,Spring接收到的数据则为null 

          所以企业开发中,对于参数可能为空的数据,建议使⽤包装类型

          ✅传递多个参数

          和接收单个参数⼀样,直接使⽤⽅法的参数接收即可.使⽤多个形参.

          @RequestMapping("/m2")
              public String m2(String name,String password) {
                  return "返回的参数 + name" + name +" password" + password;
              }

          使⽤浏览器发送请求并传参:http://127.0.0.1:8080/user/m2?name=zhangsan&password=123456

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          可以看到,后端程序正确拿到了name和password参数的值

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

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

          ⽐如访问:http://127.0.0.1:8080/user/m2?password=123456&name=zhangsan

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          ✅传递对象

          如果参数⽐较多时,⽅法声明就需要有很多形参.并且后续每次新增⼀个参数,也需要修改⽅法声明. 我们不妨把这些参数封装为⼀个对象. 

          SpringMVC也可以⾃动实现对象参数的赋值

           @RequestMapping("/m3")
              public String m3(Info info) {
                  return  info.toString();
              }
          package com.example.demo;
          public class Info {
              private String user;
              public String getPassword() {
                  return password;
              }
              @Override
              public String toString() {
                  return "Info{" +
                          "user='" + user + '\'' +
                          ", password='" + password + '\'' +
                          ", age=" + age +
                          '}';
              }
              public void setPassword(String password) {
                  this.password = password;
              }
              public String getUser() {
                  return user;
              }
              public void setUser(String user) {
                  this.user = user;
              }
              public int getAge() {
                  return age;
              }
              public void setAge(int age) {
                  this.age = age;
              }
              private String password;
              private int age;
          }
          

          使⽤浏览器发送请求并传参: http://127.0.0.1:8080/user/m3?age=5&name=zhangsan&password=123456

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          可以看到,后端程序正确拿到了Info对象⾥各个属性的值

          ✅传递数组

          SpringMVC可以⾃动绑定数组参数的赋值 

          后端实现代码:

          @RequestMapping("/m5")
          public String method5(String[] arrayParam) {
           return Arrays.toString(arrayParam);
          }
          

          使⽤浏览器发送请求并传参:

          数组参数:请求参数名与形参数组名称相同且请求参数为多个,后端定义数组类型形参即可接收参数

          http://127.0.0.1:8080/param/m5?arrayParam=zhangsan&arrayParam=lisi&arrayParam=wangwu

          或者使⽤http://127.0.0.1:8080/param/m6?listParam=zhangsan%2clisi%2cwangwu

          浏览器响应结果:

          第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)

          ✅传递集合 

          集合参数:和数组类似,同⼀个请求参数名有为多个,且需要使⽤@RequestParam 绑定参数关系 

          默认情况下,请求中参数名相同的多个值,是封装到数组.如果要封装到集合,要使⽤ @RequestParam 绑定参数关系

          请求⽅式和数组类似:

          浏览器传参:

          ⽅式⼀:http://127.0.0.1:8080/param/m6?listParam=zhangsan&listParam=lisi&listParam=wangwu

          ⽅式⼆:http://127.0.0.1:8080/param/m6?listParam=zhangsan%2clisi%2cwangwu

          %2c是逗号的转义编码,解码后的url为:http://127.0.0.1:8080/param/m6?listParam=zhangsan,lisi,wangwu

          后端接收代码:

          @RequestMapping("/m6")
          public String method6(@RequestParam List listParam){
           return "size:"+listParam.size() + ",listParam:"+listParam;
          }
          

          ✅传递JSON数据

          好的,这里我们来专门总结一下如何在 Spring MVC 中传递 JSON 数据(即:前端 → 后端)以及后端如何正确解析这些 JSON 请求。非常适合初学者掌握前后端分离接口开发的基础。


          在前后端分离开发中,前端通常使用 fetch、axios、jQuery.ajax 等方式向后端发送 JSON 数据,而不是传统的表单提交。Spring MVC 提供了强大的机制来处理这些 JSON 请求。


          1.2.1  前端如何发送 JSON 数据
          使用 fetch 示例(原生 JS):
          fetch("/api/user", {
            method: "POST",
            headers: {
              "Content-Type": "application/json"
            },
            body: JSON.stringify({
              username: "jack",
              password: "123456"
            })
          });
          
          使用 axios 示例:
          axios.post("/api/user", {
            username: "jack",
            password: "123456"
          });
          

          关键点:

          • 必须设置请求头 Content-Type: application/json

          • body 或 data 是一个 JSON 对象(会被序列化成字符串)


            1.2.2  后端 Spring MVC 接收 JSON 数据

            后端通过 @RequestBody 注解来接收请求体中的 JSON 数据,并将其绑定到一个 Java 对象。

            示例 Controller:
            @RestController
            @RequestMapping("/api")
            public class UserController {
                @PostMapping("/user")
                public String createUser(@RequestBody User user) {
                    System.out.println("用户名:" + user.getUsername());
                    System.out.println("密码:" + user.getPassword());
                    return "用户创建成功";
                }
            }
            
            示例实体类:
            public class User {
                private String username;
                private String password;
                // Getter & Setter
            }
            

            ⚠️ 注意:使用 @RequestBody 表示数据是从 请求体中提取 的,不能再用来接收 URL 参数或表单字段。


            1.2.3  常见问题排查
            问题可能原因
            接收不到数据前端请求头没设置 Content-Type: application/json
            报错 HttpMessageNotReadableException请求体不是合法 JSON 或字段不匹配
            校验不生效忘了加 @Valid 或 @Validated
            返回乱码没设置响应编码或响应类型

            1.2.4  结合参数校验(推荐)

            可以在实体类中添加注解如 @NotBlank、@Size,然后在 Controller 中使用 @Valid 自动进行参数校验:

            @PostMapping("/user")
            public String createUser(@Valid @RequestBody User user, BindingResult result) {
                if (result.hasErrors()) {
                    return "参数错误:" + result.getFieldError().getDefaultMessage();
                }
                return "用户创建成功";
            }
            

            1.2.5  返回 JSON 数据给前端

            可以直接返回一个对象,Spring 会自动将其转为 JSON(前提是使用了 @RestController 或方法上加了 @ResponseBody):

            @PostMapping("/user")
            public User createUser(@RequestBody User user) {
                user.setUsername(user.getUsername().toUpperCase());
                return user;
            }
            


            1.2.6 JSON字符串 和 Java对象的互相转换(Jackson)

            Spring MVC(尤其是 Spring Boot)默认集成了 Jackson 作为 JSON 解析器,支持 Java 对象和 JSON 字符串之间的自动转换。


            1.2.6.1 Java 对象 ➡️ JSON 字符串

            使用 ObjectMapper(Jackson 提供)进行对象序列化:

            import com.fasterxml.jackson.databind.ObjectMapper;
            public class JsonDemo {
                public static void main(String[] args) throws Exception {
                    User user = new User();
                    user.setUsername("Alice");
                    user.setPassword("123456");
                    ObjectMapper mapper = new ObjectMapper();
                    String json = mapper.writeValueAsString(user);
                    System.out.println("JSON 字符串:" + json);
                }
            }
            
            🧾 输出示例:
            {"username":"Alice","password":"123456"}
            

            1.2.6.2 JSON 字符串 ➡️ Java 对象

            使用 ObjectMapper.readValue() 将 JSON 字符串反序列化成 Java 对象:

            String json = "{\"username\":\"Bob\",\"password\":\"654321\"}";
            User user = mapper.readValue(json, User.class);
            System.out.println("用户名:" + user.getUsername());
            

            1.2.6.3 List / Map 类型转换
            JSON 数组转为 List:
            String json = "[{\"username\":\"Tom\"},{\"username\":\"Jerry\"}]";
            List users = mapper.readValue(json, new TypeReference() {});
            
            JSON 对象转为 Map:
            String json = "{\"id\":1,\"name\":\"Java\"}";
            Map map = mapper.readValue(json, new TypeReference() {});
            

            1.2.6.4 自定义 ObjectMapper(可选)

            你可以自定义 ObjectMapper 来格式化输出、修改时间格式、字段命名等:

            @Bean
            public ObjectMapper objectMapper() {
                ObjectMapper mapper = new ObjectMapper();
                mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
                return mapper;
            }
            

            🔚 总结
            操作工具注解
            前端发送 JSONfetch / axios设置 Content-Type: application/json
            后端接收 JSONSpring MVC@RequestBody
            参数校验JSR-303@Valid + BindingResult
            返回 JSONSpring Boot / MVC@ResponseBody 或 @RestController
            类型方法
            Java ➡️ JSONmapper.writeValueAsString(obj)
            JSON ➡️ Javamapper.readValue(json, Class.class)
            自动处理使用 @RequestBody / @ResponseBody
            常用库Jackson(Spring 默认)、Gson、Fastjson(需手动集成)

            🔹 1.3 路径参数(REST 风格)

            随着 RESTful API 的流行,很多接口不再使用传统的 Query 参数来传值,而是将参数嵌入在 URL 路径中,以表达资源之间的关系:

            GET /user/1001
            GET /order/1001/items/5001
            

            Spring MVC 通过 @PathVariable 注解,可以轻松提取路径中的动态参数。


            ✅ 使用 @PathVariable 获取单个参数

            @GetMapping("/user/{id}")
            public String getUser(@PathVariable("id") Long userId) {
                System.out.println("获取用户ID:" + userId);
                return "userDetail";
            }
            
            ✨ 说明:
            • {id} 是路径中的占位符,实际访问时用具体数字或字符串替代。

            • @PathVariable("id") 中的 "id" 要和 URL 中的 {id} 一致。

            • 如果参数名和占位符相同,可以简写为:

              @GetMapping("/user/{id}")
              public String getUser(@PathVariable Long id) {
                  return "userDetail";
              }
              

              ✅ 绑定多个路径参数

              当路径中包含多个动态段时,可以绑定多个参数:

              @GetMapping("/order/{userId}/item/{itemId}")
              public String getOrderItem(@PathVariable Long userId,
                                         @PathVariable Long itemId) {
                  System.out.println("用户ID:" + userId + ",商品ID:" + itemId);
                  return "orderItemDetail";
              }
              

              访问 URL 示例:

              /order/2001/item/888
              

              控制台输出:

              用户ID:2001,商品ID:888
              

              🔍 常见用法拓展:

              ✅ 路径参数 + Query 参数组合使用:
              @GetMapping("/product/{id}")
              public String getProduct(@PathVariable Long id,
                                       @RequestParam(defaultValue = "1") int page) {
                  // 访问 /product/10?page=2
                  System.out.println("商品ID:" + id + ",评论页码:" + page);
                  return "productDetail";
              }
              

              🧱 小结:

              特性@PathVariable
              来源URL 路径
              类型支持数字、字符串、UUID 等
              常用于RESTful 风格接口
              可与其他注解混用✅ 支持与 @RequestParam、@RequestBody 一起使用


              🔹1.4 文件上传:使用 @RequestPart 接收文件 & JSON

              在实际开发中,经常会遇到这样的需求:前端上传一个文件,同时还需要提交一些 JSON 格式的表单数据。这时候,我们就可以使用:

              • @RequestPart 接收 Multipart 表单中的文件和 JSON 字段

              • MultipartFile 类型接收上传的文件


                ✅ 示例:上传头像 + 用户资料

                前端发送一个包含文件和 JSON 的 multipart 请求(Content-Type: multipart/form-data)

                💡 控制器:
                @RestController
                @RequestMapping("/api")
                public class UploadController {
                    @PostMapping("/upload")
                    public String uploadUserInfo(@RequestPart("file") MultipartFile file,
                                                 @RequestPart("user") User user) throws IOException {
                        System.out.println("接收到用户:" + user.getUsername());
                        System.out.println("上传文件名:" + file.getOriginalFilename());
                        return "上传成功";
                    }
                }
                
                🧾 示例实体类:
                public class User {
                    private String username;
                    private String email;
                    // Getter & Setter
                }
                

                ✅ 前端请求示例(使用 JavaScript + fetch + FormData):

                const formData = new FormData();
                formData.append("file", document.querySelector("#fileInput").files[0]);
                formData.append("user", new Blob([
                  JSON.stringify({
                    username: "alice",
                    email: "alice@example.com"
                  })
                ], { type: "application/json" }));
                fetch("/api/upload", {
                  method: "POST",
                  body: formData
                });
                

                ✅ 请求格式说明

                • file 是文件上传字段,对应 MultipartFile

                • user 是一个 JSON 字符串包装成的 Blob,对应 @RequestPart("user") 自动反序列化为 Java 对象

                • 请求头 不需要设置 Content-Type,浏览器会自动生成 multipart/form-data 并带上 boundary。


                  ✅ 注意事项

                  问题说明
                  JSON 必须为 Blob 类型如果直接 append JSON 字符串,会作为普通字段而不是 part
                  不可使用 @RequestParam 接 JSON@RequestParam 只能接简单类型或文件,无法处理复杂 JSON
                  请求方式必须是 multipart/form-data否则文件不会被正确识别

                  ✅ 配置文件大小限制(Spring Boot 示例)

                  在 application.properties 或 application.yml 中设置上传限制:

                  spring.servlet.multipart.max-file-size=10MB
                  spring.servlet.multipart.max-request-size=20MB
                  

                  🧱 小结

                  内容注解类型
                  文件上传@RequestPart("file")MultipartFile
                  JSON 数据@RequestPart("user")Java 对象
                  普通字段@RequestParam("name")String / 基本类型
                  请求类型multipart/form-data浏览器自动生成

                  👣 到此,我们已经覆盖了多种常见的数据传参方式:

                  • Query 参数:使用 @RequestParam 从 URL 中获取查询参数。

                  • 表单参数:通过 @ModelAttribute 获取表单数据,并结合 BindingResult 进行校验。

                  • 路径参数:使用 @PathVariable 从 URL 路径中提取参数。

                  • JSON 请求体:通过 @RequestBody 获取前端传来的 JSON 数据,并可与数据校验结合使用。

                    第二章:特殊字符处理 & 编码问题解析

                    当然可以!这是 2.1 常见特殊字符 的详细讲解,适用于博客中“Spring MVC 数据传参中的特殊字符处理”章节 ✅


                    🔹 2.1 常见特殊字符解析(中文、空格、#、% 等)

                    在使用 Spring MVC 开发 Web 接口时,我们经常会通过 URL 传递参数,例如:

                    http://localhost:8080/search?name=张三#abc
                    

                    但是,如果参数中包含 中文、空格、#、%、&、= 等特殊字符,就可能出现参数截断、乱码、无法接收等问题。了解这些字符在 URL 中的表现和解决方法非常关键。


                    ✅ 一、特殊字符的常见类型

                    字符描述问题
                    中文非 ASCII 字符会出现乱码
                    空格空白字符会变成 + 或 %20
                    #锚点符号浏览器不传给服务器
                    %转义符号开头若不正确使用会解析失败
                    &参数分隔符用于多个参数
                    =参数赋值符号不能出现在值中
                    ?查询字符串开始只能出现一次

                    ✅ 二、示例问题分析

                    请求示例:
                    /search?name=张三#abc
                    
                    实际情况:
                    • 浏览器会 截断 # 后的内容,它认为 #abc 是页面锚点,不会发送到后端。

                    • 后端接收到的请求其实是:

                      /search?name=张三
                      
                    • 如果没编码,Spring MVC 控制器中打印参数会变成乱码(如 张三)


                      ✅ 三、如何解决?

                      1. 对 URL 进行 URL 编码(encode)
                      • 使用前端 JS 或其他工具对参数进行编码:

                        const name = encodeURIComponent("张三#abc");
                        // 结果:%E5%BC%A0%E4%B8%89%23abc
                        
                        • 发送请求时变成:

                          /search?name=%E5%BC%A0%E4%B8%89%23abc
                          
                          • 后端接收到参数后自动解码

                            2. Spring MVC 端设置编码(避免乱码)
                            • 如果是 Spring Boot,在 application.properties 中添加:

                              spring.http.encoding.enabled=true
                              spring.http.encoding.charset=UTF-8
                              spring.http.encoding.force=true
                              
                              3. 使用过滤器统一设置编码(传统 Spring MVC)
                              public class EncodingFilter implements Filter {
                                  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                                      throws IOException, ServletException {
                                      request.setCharacterEncoding("UTF-8");
                                      response.setCharacterEncoding("UTF-8");
                                      chain.doFilter(request, response);
                                  }
                              }
                              

                              ✅ 四、常见特殊字符编码表

                              字符编码
                              空格%20 或 +
                              中文%E5%BC%A0%E4%B8%89(张三)
                              #%23
                              %%25
                              &%26
                              =%3D

                              ✅ 五、后端示例(使用 @RequestParam 接收参数)

                              @GetMapping("/search")
                              public String search(@RequestParam("name") String name) {
                                  System.out.println("接收到参数 name = " + name);
                                  return "ok";
                              }
                              

                              若前端发送的是未经编码的中文或特殊字符,控制器可能会收到乱码或不完整内容。通过前端 encodeURIComponent() 编码 + 后端统一 UTF-8 解码即可避免这些问题。


                              ✅ 六、测试建议

                              测试内容预期结果
                              /search?name=张三后端接收到 “张三”
                              /search?name=张三#abc实际只收到 “张三”
                              /search?name=%E5%BC%A0%E4%B8%89%23abc后端接收到 “张三#abc”


                              🔹2.2 GET 请求中的编码问题解析(%20、+、%23 的区别)

                              在 Web 开发中,GET 请求的参数直接拼接在 URL 中。当 URL 包含中文、空格或特殊字符时,浏览器和服务器之间的编码解码处理就变得非常关键。


                              ✅ 一、浏览器对 URL 的自动编码行为

                              浏览器会自动对 URL 中 非 ASCII 字符 和 部分特殊字符 进行编码,例如:

                              /search?keyword=Java 编码
                              

                              浏览器实际发送请求时,会自动将其编码为:

                              /search?keyword=Java%20%E7%BC%96%E7%A0%81
                              
                              • 中文“编码” → %E7%BC%96%E7%A0%81

                              • 空格 → %20(或有些场景中为 +)


                                ✅ 二、Spring MVC 如何解析这些编码

                                Spring MVC 默认使用 UTF-8 对 URL 进行解码(如果配置正确),即:

                                @GetMapping("/search")
                                public String search(@RequestParam String keyword) {
                                    System.out.println("关键词:" + keyword);
                                    return "ok";
                                }
                                

                                请求 /search?keyword=Java%20%E7%BC%96%E7%A0%81

                                后端接收到的参数会被正确解析为:

                                Java 编码
                                

                                ✅ 所以只要前端编码正确,Spring 后端是可以自动解析的。


                                ✅ 三、重点区别:%20 vs + vs %23

                                表达形式代表含义用途说明
                                %20空格(编码)URL 中最标准的空格编码方式
                                +空格(表单风格)仅适用于 application/x-www-form-urlencoded 表单编码
                                %23# 字符本身因为 # 是锚点标记,需转义才能被服务器接收到
                                示例解析:
                                • /search?kw=A%20B → A B ✅

                                • /search?kw=A+B → A B ✅(但依赖解码器行为)

                                • /search?kw=A%2BB → A+B ✅(如果真要传 + 本身)

                                • /search?kw=A#B → 浏览器只会发送 A,不会包含 #B

                                • /search?kw=A%23B → 后端会收到 A#B


                                  ✅ 四、如何避免乱码和错误

                                  场景建议处理
                                  中文参数使用 encodeURIComponent 编码
                                  空格推荐使用 %20 而非 +(更标准)
                                  # 符号必须编码为 %23
                                  后端乱码确保 Spring Boot 配置了 UTF-8 解码(默认已支持)

                                  Spring Boot 配置参考:

                                  spring.servlet.encoding.charset=UTF-8
                                  spring.servlet.encoding.enabled=true
                                  spring.servlet.encoding.force=true
                                  

                                  ✅ 五、简单测试表格

                                  原始字符URL 编码解码结果(Spring)
                                  空格%20空格
                                  空格+空格(表单风格)
                                  +%2B+
                                  #%23#
                                  中文“张三”%E5%BC%A0%E4%B8%89张三

                                  🧪 示例 Controller 方法(用于调试测试):
                                  @GetMapping("/test")
                                  public String test(@RequestParam String value) {
                                      return "收到参数:" + value;
                                  }
                                  

                                  可以测试这些 URL:

                                  /test?value=A%20B
                                  /test?value=A+B
                                  /test?value=A%2BB
                                  /test?value=A%23B
                                  


                                  ✅六 URL 编码常见字符对照表(开发必备小抄)

                                  字符原文

                                  编码后

                                  解码结果

                                  说明
                                  空格(半角)%20空格推荐使用 %20 表示空格
                                  空格(表单场景)+空格仅在 x-www-form-urlencoded 中解析为空格
                                  加号 +%2B+若想传“+”本身,必须使用 %2B
                                  井号 #%23#避免被浏览器视为锚点
                                  中文 “张三”%E5%BC%A0%E4%B8%89张三需要 UTF-8 编码
                                  百分号 %%25%编码开头符号自身的转义
                                  与号 &%26&避免作为参数分隔符
                                  等号 =%3D=避免参数赋值误解析

                                  ✅ 建议用 encodeURIComponent() 对所有参数值进行编码,避免问题。


                                  🔸 前端 JS 测试代码(复制即可用)

                                  这是一个简单的前端测试页面,能快速测试各种字符编码的行为:

                                  
                                  
                                    
                                    GET 编码测试
                                  
                                  
                                    

                                  GET 参数编码测试

                                  测试请求

                                  function sendRequest() { const raw = document.getElementById("input").value; const encoded = encodeURIComponent(raw); const url = `/test?value=${encoded}`; fetch(url) .then(res => res.text()) .then(res => { document.getElementById("result").innerText = "服务端返回: " + res; }); }

                                  🔸 Spring Boot Controller 示例代码(配合前端测试)
                                  @RestController
                                  public class EncodingTestController {
                                      @GetMapping("/test")
                                      public String test(@RequestParam String value) {
                                          return "服务端收到参数:" + value;
                                      }
                                  }
                                  

                                  🔸 实际测试示例
                                  输入实际请求 URL后端收到
                                  张三/test?value=%E5%BC%A0%E4%B8%89张三
                                  A B/test?value=A%20BA B
                                  A+B/test?value=A%2BBA+B
                                  A#B/test?value=A%23BA#B
                                  %25/test?value=%2525%25

                                  ✅ 小贴士
                                  • 永远不要手动拼接 URL 参数,使用 encodeURIComponent()

                                  • 浏览器不会发送 # 后的内容,必须提前编码为 %23

                                  • 表单提交推荐用 POST,GET 仅用于短、简单的查询参数



                                    🔸 2.3 POST 请求中的编码设置(CharacterEncodingFilter 全解析)

                                    虽然 GET 请求中浏览器会自动进行 URL 编码,但在 POST 请求中,请求体的数据编码依赖客户端和服务端的配置是否匹配,否则会出现中文乱码等问题。


                                    ✅ 一、为什么 POST 请求容易出现编码问题?

                                    • GET 请求参数放在 URL 中,浏览器会自动进行 UTF-8 编码。

                                    • POST 请求的参数通常放在 请求体 body 中,如表单数据、JSON 数据等。

                                    • 若服务端未正确设置编码方式,则无法按预期解析参数,例如表单提交中文可能乱码。


                                      ✅ 二、传统 Spring MVC 中的解决方案:CharacterEncodingFilter

                                      在不使用 Spring Boot 的老项目中,开发者必须手动配置字符编码过滤器 CharacterEncodingFilter,否则 Spring MVC 默认使用 ISO-8859-1 解码表单参数,导致乱码。

                                      示例配置方式(web.xml):
                                        encodingFilter
                                        org.springframework.web.filter.CharacterEncodingFilter
                                        
                                          encoding
                                          UTF-8
                                        
                                        
                                          forceEncoding
                                          true
                                        
                                      
                                      
                                        encodingFilter
                                        /*
                                      
                                      

                                      或使用 Java Config:

                                      @Bean
                                      public FilterRegistrationBean characterEncodingFilter() {
                                          CharacterEncodingFilter filter = new CharacterEncodingFilter();
                                          filter.setEncoding("UTF-8");
                                          filter.setForceEncoding(true);
                                          FilterRegistrationBean bean = new FilterRegistrationBean(filter);
                                          bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
                                          return bean;
                                      }
                                      

                                      ✅ 三、Spring Boot 的自动配置(默认已支持)

                                      Spring Boot 已经默认为你配置好了 CharacterEncodingFilter,你只需确保配置项存在即可:

                                      application.properties 中配置:
                                      spring.servlet.encoding.enabled=true
                                      spring.servlet.encoding.charset=UTF-8
                                      spring.servlet.encoding.force=true
                                      

                                      这些配置会自动启用 CharacterEncodingFilter,确保所有请求(包括 POST 表单)都使用 UTF-8 编码。


                                      ✅ 四、实测对比如下:

                                      场景是否乱码原因
                                      Spring MVC 未配置编码❌乱码默认使用 ISO-8859-1 解码
                                      手动添加 CharacterEncodingFilter✅正常统一使用 UTF-8
                                      Spring Boot 默认配置✅正常自动注入编码过滤器
                                      Spring Boot 配置关闭 encoding.enabled=false❌乱码无过滤器生效

                                      ✅ 五、编码生效的两个关键点

                                      条件说明
                                      CharacterEncodingFilter.forceEncoding=true强制使用你设置的编码解析请求体
                                      客户端 Content-Type 正确表单应为 application/x-www-form-urlencoded; charset=UTF-8,JSON 为 application/json; charset=UTF-8

                                      ✅ 六、示例控制器验证 POST 编码

                                      @PostMapping("/submit")
                                      public String submit(@RequestParam String name) {
                                          System.out.println("接收到 name = " + name);
                                          return "ok";
                                      }
                                      

                                      使用表单或 Postman 发送中文数据,可以观察是否成功接收。


                                      ✅ 总结一句话:

                                      GET 编码靠浏览器自动,POST 编码必须服务端主动设定;用 Spring Boot 就别怕,它自动帮你搞定!



                                      📷 POST 中文乱码演示(Postman 测试案例)

                                      我们用一个简单的 Spring MVC 控制器来测试:

                                      ✅ 控制器代码

                                      @RestController
                                      public class PostTestController {
                                          @PostMapping("/submit")
                                          public String submit(@RequestParam String name) {
                                              System.out.println("收到参数 name = " + name);
                                              return "服务器已收到:" + name;
                                          }
                                      }
                                      

                                      📤 测试用例 1:无编码过滤器(或未设置 forceEncoding)

                                      💬 Postman 请求设置:
                                      • 请求方式:POST

                                      • 请求地址:http://localhost:8080/submit

                                      • 类型:x-www-form-urlencoded

                                      • 参数:name=张三

                                      • Headers:未设置 charset

                                        ⚠️ 后台打印:
                                        收到参数 name = ???
                                        

                                        👉 出现乱码!因为 Spring 默认解码方式是 ISO-8859-1。


                                        📤 测试用例 2:配置 CharacterEncodingFilter + UTF-8

                                        ✅ Spring Boot 自动配置(或你手动加上):
                                        spring.servlet.encoding.charset=UTF-8
                                        spring.servlet.encoding.enabled=true
                                        spring.servlet.encoding.force=true
                                        
                                        💬 Postman 请求相同,但 header 手动添加:
                                        Content-Type: application/x-www-form-urlencoded; charset=UTF-8
                                        
                                        ✅ 后台打印:
                                        收到参数 name = 张三
                                        

                                        成功 ✅


                                        🔸 2.4 遇到乱码怎么办?全流程排查 + 解决方案 ✅

                                        乱码问题在 Web 开发中常见,尤其是在多语言环境、前后端交互复杂时。这里为你总结一份统一编码 + 排查方案清单,帮助你快速定位与解决乱码。

                                        第三期:深入理解 Spring Web MVC [特殊字符](数据传参+ 特殊字符处理 + 编码问题解析)


                                        ✅ 一、配置统一的字符编码过滤器(服务端核心)

                                        在 Spring 项目中,CharacterEncodingFilter 是解决乱码的关键组件。

                                        💡 Spring Boot 自动配置(推荐):
                                        spring.servlet.encoding.charset=UTF-8
                                        spring.servlet.encoding.enabled=true
                                        spring.servlet.encoding.force=true
                                        

                                        ✔ 适用于 GET、POST、文件上传等请求

                                        🧰 非 Spring Boot 项目(传统配置):
                                        @Bean
                                        public FilterRegistrationBean characterEncodingFilter() {
                                            CharacterEncodingFilter filter = new CharacterEncodingFilter();
                                            filter.setEncoding("UTF-8");
                                            filter.setForceEncoding(true);
                                            return new FilterRegistrationBean(filter);
                                        }
                                        

                                        ✅ 二、IDE 配置统一编码(避免开发阶段引入乱码)

                                        IDE 设置不对,直接导致 .java 或 .html 文件保存就是乱码!

                                        🌟 IntelliJ IDEA 设置 UTF-8:
                                        1. File -> Settings -> Editor -> File Encodings

                                        2. 设置以下内容为 UTF-8:

                                          • Global Encoding

                                          • Project Encoding

                                          • Default encoding for properties files

                                          • Transparent native-to-ascii conversion ✔


                                        ✅ 三、页面文件声明编码(前端页面不能少)

                                        对于 Thymeleaf / JSP 等后端渲染页面:

                                        HTML 示例:
                                         
                                        
                                        JSP 页面开头:
                                         
                                        

                                        ✅ 四、客户端请求编码设置(特别是 POST)

                                        表单提交(需带 charset):
                                         
                                        
                                        Postman 请求 Header 添加:
                                        Content-Type: application/x-www-form-urlencoded; charset=UTF-8
                                        

                                        或 JSON:

                                        Content-Type: application/json; charset=UTF-8
                                        

                                        ✅ 五、数据库连接设置编码(从根上解决保存乱码)

                                        MySQL 示例:

                                        jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
                                        

                                        characterEncoding=utf8 一定不要忘!


                                        🧭 六、乱码排查流程图(逻辑全链路)

                                        [客户端输入]
                                              ↓
                                        [前端页面编码] 
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码