参考视频:SpringMVC教程,SpringMVC从零到精通,老杜SpringMVC,动力节点SpringMVC
0. 思考 假设有这样一个请求:
http://localhost:8080/springmvc/register?name=muyoukule&password=123&email=muyoukule@example.com
在SpringMVC中应该如何获取请求提交的数据呢?
在SpringMVC中又应该如何获取请求头信息呢?
在SpringMVC中又应该如何获取客户端提交的Cookie数据呢?
1. 环境准备 1、创建模块,添加依赖
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?xml version="1.0" encoding="UTF-8" ?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > com.muyoukule</groupId > <artifactId > springmvc-004</artifactId > <version > 1.0-SNAPSHOT</version > <packaging > war</packaging > <properties > <maven.compiler.source > 17</maven.compiler.source > <maven.compiler.target > 17</maven.compiler.target > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > </properties > <dependencies > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 6.1.4</version > </dependency > <dependency > <groupId > ch.qos.logback</groupId > <artifactId > logback-classic</artifactId > <version > 1.5.3</version > </dependency > <dependency > <groupId > jakarta.servlet</groupId > <artifactId > jakarta.servlet-api</artifactId > <version > 6.0.0</version > <scope > provided</scope > </dependency > <dependency > <groupId > org.thymeleaf</groupId > <artifactId > thymeleaf-spring6</artifactId > <version > 3.1.2.RELEASE</version > </dependency > </dependencies > </project >
2、添加web支持
3、编写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 <?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns ="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version ="4.0" > <servlet > <servlet-name > springmvc</servlet-name > <servlet-class > org.springframework.web.servlet.DispatcherServlet</servlet-class > <init-param > <param-name > contextConfigLocation</param-name > <param-value > classpath:springmvc.xml</param-value > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > springmvc</servlet-name > <url-pattern > /</url-pattern > </servlet-mapping > </web-app >
4、创建UserController
1 2 3 4 5 6 7 @Controller public class UserController { @RequestMapping("/") public String toRegisterPage () { return "register" ; } }
5、编写springmvc.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 31 32 33 34 35 36 <?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 https://www.springframework.org/schema/context/spring-context.xsd" > <context:component-scan base-package ="com.muyoukule.controller" /> <bean id ="thymeleafViewResolver" class ="org.thymeleaf.spring6.view.ThymeleafViewResolver" > <property name ="characterEncoding" value ="UTF-8" /> <property name ="order" value ="1" /> <property name ="templateEngine" > <bean class ="org.thymeleaf.spring6.SpringTemplateEngine" > <property name ="templateResolver" > <bean class ="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver" > <property name ="prefix" value ="/WEB-INF/templates/" /> <property name ="suffix" value =".html" /> <property name ="templateMode" value ="HTML" /> <property name ="characterEncoding" value ="UTF-8" /> </bean > </property > </bean > </property > </bean > </beans >
6、编写register.html文件
在WEB-INF目录下新建templates
目录,在templates目录中新建register.html文件:
1 2 3 4 5 6 7 8 9 10 11 <!DOCTYPE html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="UTF-8" > <title > 用户注册</title > </head > <body > <h3 > 用户注册</h3 > <hr > </body > </html >
7、部署测试
2. 使用原生的Servlet API进行获取 原生的Servlet API指的是:HttpServletRequest
在SpringMVC当中,一个Controller类中的方法参数上如果有HttpServletRequest
,SpringMVC会自动将当前请求对象
传递给这个参数,因此我们可以通过这个参数来获取请求提交的数据。
测试
1、在 register.html 中准备一个注册的表单:
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 <!DOCTYPE html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="UTF-8" > <title > 用户注册</title > </head > <body > <h3 > 用户注册</h3 > <hr > <form th:action ="@{/register}" method ="post" > 用户名:<input type ="text" name ="username" > <br > 密码:<input type ="password" name ="password" > <br > 性别: 男 <input type ="radio" name ="sex" value ="1" > 女 <input type ="radio" name ="sex" value ="0" > <br > 爱好: 抽烟 <input type ="checkbox" name ="hobby" value ="smoke" > 喝酒 <input type ="checkbox" name ="hobby" value ="drink" > 烫头 <input type ="checkbox" name ="hobby" value ="perm" > <br > 简介:<textarea rows ="10" cols ="60" name ="intro" > </textarea > <br > <input type ="submit" value ="注册" > </form > </body > </html >
2、先测试这个页面是否可以正常打开,是否可以正常提交数据:
3、点击注册:F12的方式查看是否提交了数据:
通过测试得知:可以正常提交数据。
4、接下来在控制器添加一个方法来处理这个注册的请求:
1 2 3 4 5 6 7 8 9 10 11 @PostMapping(value="/register") public String register (HttpServletRequest request) { String username = request.getParameter("username" ); String password = request.getParameter("password" ); String sex = request.getParameter("sex" ); String[] hobbies = request.getParameterValues("hobby" ); String intro = request.getParameter("intro" ); System.out.println(username + "," + password + "," + sex + "," + Arrays.toString(hobbies) + "," + intro); return "success" ; }
5、提供视图页面:
1 2 3 4 5 6 7 8 9 10 <!DOCTYPE html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <head > <meta charset ="UTF-8" > <title > 注册成功</title > </head > <body > <h1 > 注册成功</h1 > </body > </html >
6、测试:
7、控制台打印:
1 muyoukule,123,1,[smoke, drink, perm],66666666
这样通过Servlet原生的API获取到提交的数据。但是这种方式不建议使用,因为方法的参数依赖Servlet原生API,Controller的测试将不能单独测试,必须依赖WEB服务器才能测试。另外,换句话说,如果在SpringMVC中使用了原生的Servlet,你为什么还要用SpringMVC框架呢🙄!!!!!
3. 使用@RequestParam注解标注 3.1 @RequestParam注解的基本使用 @RequestParam
注解作用:将请求参数
与方法上的形参
映射
1、修改register方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @PostMapping(value = "/register") public String register ( @RequestParam(value="username") String a, @RequestParam(value="password") String b, @RequestParam(value="sex") String c, @RequestParam(value="hobby") String[] d, @RequestParam(name="intro") String e) { System.out.println(a); System.out.println(b); System.out.println(c); System.out.println(Arrays.toString(d)); System.out.println(e); return "success" ; }
PS:对于@RequestParam
注解来说,属性有value
和name
,这两个属性的作用相同,都是用来指定提交数据的name。
1 2 3 4 5 @AliasFor("name") String value () default "" ; @AliasFor("value") String name () default "" ;
例如:发送请求时提交的数据是:name1=value1&name2=value2
,则这个注解应该这样写:@RequestParam(value="name1"),@RequestParam(value="name2")
2、启动服务器测试:
3、控制台打印:
1 2 3 4 5 muyoukule002 123 1 [smoke, drink] muyoukule666
PS: @RequestParam(value="name1")
中value一定要与前端传过来的参数相同,否则会出错。 😨
例如:前端传过来的参数为username
,而后端接收参数时写的是@RequestParam(value="uname")
,就会出现如下错误:
3.1.1 @PathVariable注解 在SpringMVC当中,如果请求的URL使用的是RESTFul风格的,那么这个数据应该在java程序中如何获取呢?使用占位符方式。
1 2 3 4 5 6 7 8 9 @RequestMapping(value = "/login/{a}/{b}") public String testRESTFulURL ( @PathVariable("a") String username, @PathVariable("b") String password) { System.out.println("用户名:" + username + ",密码:" + password); return "ok" ; }
@PathVariable
这个注解是可以省略的,如果请求的URL参数的名字和形参的name相同 ,则 @PathVariable
可以省略。
但有一个前提:如果你采用的是Spring6+版本,你需要在pom.xml文件中指定编译参数-parameter
,配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.12.1</version > <configuration > <source > 17</source > <target > 17</target > <compilerArgs > <arg > -parameters</arg > </compilerArgs > </configuration > </plugin > </plugins > </build >
PS:如果你使用的是Spring5的版本,以上的配置是不需要的。 😁
3.2 @RequestParam注解的required属性 1 boolean required () default true ;
required
属性用来设置该方法参数是否为必须的。
默认情况下,这个参数为 true
,表示方法参数是必需的。如果请求中缺少对应的参数,则会抛出异常。
可以将其设置为false
,false表示不是必须的,如果请求中缺少对应的参数,则方法的参数为null
。
测试
1、修改register方法,添加一个 age 形参,没有指定 required 属性时,默认是true,表示必需的
1 2 @RequestParam(name = "age") String age
2、启动服务器,但前端表单中没有填写年龄age的输入框 ,我们来看报错信息:
错误信息告诉我们:参数age是必需的。没有提供这个请求参数,HTTP状态码 400
3、如果将 required
属性设置为 false。则该参数则不是必须的,如果请求参数仍然未提供时,我们来看结果:
1 2 3 4 5 @RequestParam(name = "age", required = false) String ageSystem.out.println("age====>" + age);
4、启动服务器,填写信息后成功 跳转到注册成功页面,控制台打印:
1 2 3 4 5 6 muyoukule 123 1 [smoke, drink] muyoukule66666 age====>null
通过测试得知,如果一个参数被设置为不是必需的
,当没有提交对应的请求参数时,形参默认值null
。
当然,如果请求参数中提供了age,则age为真实提交的数据(PS:未填写信息会返回给后端一个空字符串""
)
1、给register.html添加如下输入框:
1 年龄:<input type ="number" name ="age" > <br >
2、重新启动服务器,填写所有信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 2 3 4 5 6 muyoukule 123 1 [smoke, drink, perm] 4245 age====>18
3.3 @RequestParam注解的defaultValue属性 defaultValue属性用来设置形参的默认值,当没有提供对应的请求参数
或者请求参数的值是空字符串""
的时候,方法的形参会采用默认值。
测试
1、给age形参的@RequestParam
注解添加一个defaultValue = "18"
属性
1 @RequestParam(name = "age", required = false,defaultValue = "18") String age
2、当前端表单中没有填写年龄age的输入框 ,用户正常填写其他信息,点击注册后成功跳转到注册成功界面,控制台打印:
1 2 3 4 5 6 muyoukule003 123 1 [smoke, drink, perm] muyoukule003 age====>18
3、给register.html添加如下输入框:
1 年龄:<input type ="number" name ="age" > <br >
4、重新启动服务器
4.1. 当前端页面用户未填写age(提交的age是空字符串""
)的时候,点击注册后成功跳转到注册成功界面,控制台打印:
1 2 3 4 5 6 muyoukule004 123 1 [smoke, drink, perm] muyoukule004 age====>18
4.2. 当前端提交的age不是空字符串的时候:
填写信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 2 3 4 5 6 muyoukule005 123 1 [smoke, drink, perm] muyoukule005 age====>81
4. 依靠控制器方法上的形参名来接收 @RequestParam
这个注解是可以省略的,如果方法形参的名字和提交数据时的name相同,则 @RequestParam
可以省略。
但有一个前提:如果你采用的是Spring6+版本,你需要在pom.xml文件中指定编译参数-parameter
,配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.12.1</version > <configuration > <source > 17</source > <target > 17</target > <compilerArgs > <arg > -parameters</arg > </compilerArgs > </configuration > </plugin > </plugins > </build >
PS:如果你使用的是Spring5的版本,以上的配置是不需要的。 😁
Controller中的方法只需要这样写:形参的名字必须和提交的数据的name一致!!!!!
1 2 3 4 5 @PostMapping(value="/register") public String register (String username, String password, String sex, String[] hobby, String intro) { System.out.println(username + "," + password + "," + sex + "," + Arrays.toString(hobby) + "," + intro); return "success" ; }
测试结果:
填写信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 muyoukule006,123,1,[smoke],muyoukule006
如果形参名和提交的数据的name不一致:
例如前端传过来的参数为username
,而后端接收参数时写的是String umane
,就会出现uname
值为null
的情况:
1 null,123,1,[smoke],muyoukule007
另外,对于提交的hobby数据,也可以采用String来接收,不一定使用数组方式:
1 2 3 4 5 @PostMapping(value="/register") public String register (String username, String password, String sex, String hobby, String intro) { System.out.println(username + "," + password + "," + sex + "," + hobby + "," + intro); return "success" ; }
测试结果:
1 muyoukule008,123,1,smoke,drink,perm,muyoukule008
根据输出结果可以看到多个hobby是采用 ,
进行连接的。
5. 使用POJO类/JavaBean接收请求参数 以上方式大家可以看到,当提交的数据非常多时,方法的形参个数会非常多,这不是很好的设计。在SpringMVC中也可以使用 POJO类/JavaBean
来接收请求参数。不过有一个非常重要的要求:POJO类的属性名
必须和 请求参数的参数名
保持一致!! 😁
测试
1、提供以下的JavaBean:
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 package com.muyoukule.pojo;import java.util.Arrays;public class User { private Long id; private String username; private String password; private String sex; private String[] hobby; private String intro; public User () { } public User (Long id, String username, String password, String sex, String[] hobby, String intro) { this .id = id; this .username = username; this .password = password; this .sex = sex; this .hobby = hobby; this .intro = intro; } public Long getId () { return id; } public void setId (Long id) { this .id = id; } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } public String getSex () { return sex; } public void setSex (String sex) { this .sex = sex; } public String[] getHobby() { return hobby; } public void setHobby (String[] hobby) { this .hobby = hobby; } public String getIntro () { return intro; } public void setIntro (String intro) { this .intro = intro; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", sex='" + sex + '\'' + ", hobby=" + Arrays.toString(hobby) + ", intro='" + intro + '\'' + '}' ; } }
2、在控制器方法的形参位置上使用javabean来接收请求参数:
1 2 3 4 5 @PostMapping("/register") public String register (User user) { System.out.println(user); return "success" ; }
3、执行结果:
4、填写信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 User{id=null, username='muyoukule', password='123', sex='1', hobby=[smoke, perm], intro='muyoukulehaoshuaia'}
底层的实现原理:反射机制。先获取请求参数的名字,因为请求参数的名字就是JavaBean的属性名,通过这种方式给对应的属性赋值 。
测试一下:当JavaBean的属性名和请求参数的参数名不一致时,会出现什么问题?
PS:getter和setter的方法名不修改,只修改属性名 😃
1、修改属性名
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package com.muyoukule.pojo;import java.util.Arrays;public class User { private Long id; private String uname; private String upwd; private String usex; private String[] uhobby; private String uintro; public User () { } public User (Long id, String username, String password, String sex, String[] hobby, String intro) { this .id = id; this .uname = username; this .upwd = password; this .usex = sex; this .uhobby = hobby; this .uintro = intro; } public Long getId () { return id; } public void setId (Long id) { this .id = id; } public String getUsername () { return uname; } public void setUsername (String username) { this .uname = username; } public String getPassword () { return upwd; } public void setPassword (String password) { this .upwd = password; } public String getSex () { return usex; } public void setSex (String sex) { this .usex = sex; } public String[] getHobby() { return uhobby; } public void setHobby (String[] hobby) { this .uhobby = hobby; } public String getIntro () { return uintro; } public void setIntro (String intro) { this .uintro = intro; } @Override public String toString () { return "User{" + "id=" + id + ", username='" + uname + '\'' + ", password='" + upwd + '\'' + ", sex='" + usex + '\'' + ", hobby=" + Arrays.toString(uhobby) + ", intro='" + uintro + '\'' + '}' ; } }
2、测试,填写和上面相同的信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 User{id=null, username='muyoukule', password='123', sex='1', hobby=[smoke, perm], intro='muyoukulehaoshuaia'}
通过测试,我们得知:请求参数名
可以和 JavaBean的属性名
不一致。
1、我们继续将其中一个属性的setter和getter方法名修改一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public String getUname () { return uname; } public void setUname (String uname) { this .uname = uname; }
2、再次测试,填写和上面相同的信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 User{id=null, username='null', password='123', sex='1', hobby=[smoke, perm], intro='muyoukulehaoshuaia'}
通过测试可以看到:username属性没有赋上值。可见请求参数是否可以赋值到JavaBean对应的属性上,不是取决于属性名,而是setter方法名 。
该注解的作用是:将 请求头信息
映射到 方法的形参上
。
和@RequestParam
注解功能相似,@RequestParam
注解的作用:将请求参数
映射到方法的形参
上。
当然,对于@RequestHeader
注解来说,也有三个属性:value、required、defaultValue,和@RequestParam
一样,这里就不再赘述。
测试
1、编写register方法
1 2 3 4 5 6 7 8 @PostMapping("/register") public String register (User user, @RequestHeader(value = "Referer", required = false, defaultValue = "") String referer) { System.out.println(user); System.out.println(referer); return "success" ; }
2、填写信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 2 User{id=null, username='muyoukule', password='123', sex='1', hobby=[smoke, drink, perm], intro='muyoukulehaoshuaia'} http://localhost:8080/springmvc/
7. @CookieValue注解 该注解的作用:将 请求提交的Cookie数据
映射到 方法形参
上
同样是有三个属性:value、required、defaultValue
测试
1、前端页面中编写发送cookie的代码:
1 2 3 4 5 6 7 <script type ="text/javascript" > function sendCookie ( ) { document .cookie = "id=123456789; expires=Thu, 18 Dec 2025 12:00:00 UTC; path=/" ; document .location = "/springmvc/register" ; } </script > <button onclick ="sendCookie()" > 向服务器端发送Cookie</button >
2、后端UserController代码:
1 2 3 4 5 6 7 8 9 10 11 @GetMapping("/register") public String register (User user, @RequestHeader(value = "Referer", required = false, defaultValue = "") String referer, @CookieValue(value = "id", required = false, defaultValue = "2222222222") String id) { System.out.println(user); System.out.println(referer); System.out.println(id); return "success" ; }
3、启动服务器打开页面,直接点击向 服务器端发送Cookie
按钮测试,控制台打印:
1 2 3 User{id=null, username='null', password='null', sex='null', hobby=null, intro='null'} http://localhost:8080/springmvc/ 123456789
8. 请求的中文乱码问题 8.1 get请求乱码 get请求数据在URI后面提交,这个乱码问题怎么解决呢?
解决办法是找到CATALINA_HOME/config/server.xml
文件,找到其中配置端口号的标签<Connector>
,在该标签中添加 URIEncoding="UTF-8"
但是对于高版本的Tomcat服务器来说,是不需要设置的,例如Tomcat10,Tomcat9,有如下的默认配置,在默认情况下URIEncoding使用的就是UTF-8
的编码方式。
但对于低版本的Tomcat服务器,例如:Tomcat8。URIEncoding的默认配置是ISO-8859-1
,因此在Tomcat8中需要手动配置server.xml文件:
在 conf
目录下打开 server.xml
文件,配置如下:
测试默认情况下,Tomcat10是否已经解决了get请求乱码问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <form th:action ="@{/register}" method ="get" > 用户名:<input type ="text" name ="username" > <br > 密码:<input type ="password" name ="password" > <br > 性别: 男 <input type ="radio" name ="sex" value ="1" > 女 <input type ="radio" name ="sex" value ="0" > <br > 爱好: 抽烟 <input type ="checkbox" name ="hobby" value ="smoke" > 喝酒 <input type ="checkbox" name ="hobby" value ="drink" > 烫头 <input type ="checkbox" name ="hobby" value ="perm" > <br > 简介:<textarea rows ="10" cols ="60" name ="intro" > </textarea > <br > <input type ="submit" value ="注册" > </form >
注意,以上表单已经修改为get
请求了。
1 2 3 4 5 @GetMapping("/register") public String register (User user) { System.out.println(user); return "success" ; }
测试结果:
控制台打印:
1 User{id=null, username='木又枯了', password='123', sex='1', hobby=[smoke, drink, perm], intro='木又枯了太酷了!'}
8.2 post请求乱码 post请求是解决请求体的中文乱码问题。解决办法大家都知道:
1 request.setCharacterEncoding("UTF-8" );
同样,对于高版本的Tomcat10 服务器来说,针对请求体中的字符编码也是配置好的,默认也是采用了UTF-8,中文乱码问题也解决了,在这个文件中配置的:apache-tomcat-10.1.19\conf\web.xml
配置内容如下:
通过以上配置可以看到,Tomcat10对请求和响应都设置了默认的字符编码方式为UTF-8
。
PS:Tomcat9以及之前的版本,以上的配置是没有的。
测试针对Tomcat10,SpringMVC会不会有乱码问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <form th:action ="@{/register}" method ="post" > 用户名:<input type ="text" name ="username" > <br > 密码:<input type ="password" name ="password" > <br > 性别: 男 <input type ="radio" name ="sex" value ="1" > 女 <input type ="radio" name ="sex" value ="0" > <br > 爱好: 抽烟 <input type ="checkbox" name ="hobby" value ="smoke" > 喝酒 <input type ="checkbox" name ="hobby" value ="drink" > 烫头 <input type ="checkbox" name ="hobby" value ="perm" > <br > 简介:<textarea rows ="10" cols ="60" name ="intro" > </textarea > <br > <input type ="submit" value ="注册" > </form >
PS:以上表单已经修改为post请求
1 2 3 4 5 @PostMapping("/register") public String register (User user) { System.out.println(user); return "success" ; }
测试结果:
1 User{id=null, username='木又枯了', password='123', sex='1', hobby=[smoke, drink, perm], intro='木又枯了太酷啦!!'}
通过测试可以看到在Tomcat10当中,默认SpringMVC,发送POST请求,是不会出现乱码问题的。
模拟乱码
如果不是Tomcat10,则会出现乱码问题,我们来模拟一下乱码的产生,将apache-tomcat-10.1.19\conf\web.xml
文件中的UTF-8
配置修改为ISO-8859-1
:
1 2 3 <request-character-encoding > ISO-8859-1</request-character-encoding > <response-character-encoding > ISO-8859-1</response-character-encoding >
一定要重启Tomcat10 ,新的配置才能生效,来测试一下是否存在乱码:
1 User{id=null, username='??¨?????????', password='123', sex='1', hobby=[smoke, drink, perm], intro='??¨??????????¤?é?·?????????'}
那么,在SpringMVC中如何解决请求体的中文乱码问题呢?
当然,还是使用request.setCharacterEncoding("UTF-8")
,使用它有一个前提条件,要想解决请求体乱码问题,以上代码必须在 request.getParameter("username")
执行之前执行才有效。
也就是说以上代码如果放在Controller的相关方法中执行是无效的,因为Controller的方法在执行之前 DispatcherServlet已经调用了 request.getParameter("username")
方法。因此在Controller方法中使用request.setCharacterEncoding("UTF-8")
无效。
我们来测试一下(PS:注意表单为post请求):
1 2 3 4 5 6 @PostMapping("/register") public String register (User user, HttpServletRequest request) throws UnsupportedEncodingException { request.setCharacterEncoding("UTF-8" ); System.out.println(user); return "success" ; }
测试结果:
1 User{id=null, username='??¨?????????', password='123', sex='1', hobby=[smoke, drink, perm], intro='??¨??????????¤?é?·?????????'}
通过测试可以看到:在Controller当中调用 request.setCharacterEncoding("UTF-8")
是无法解决POST乱码问题的。
那怎么办呢?怎么样才能在DispatcherServlet之前执行 request.setCharacterEncoding("UTF-8")
呢?
没错,我相信大家想到了:过滤器Filter。过滤器Filter可以在Servlet执行之前执行。有人又说了:监听器不行吗?不行。因为我们需要对每一次请求解决乱码,而监听器只在服务器启动阶段执行一次。因此这里解决每一次请求的乱码问题,应该使用过滤器Filter。
1、编写过滤器CharacterEncodingFilter
1 2 3 4 5 6 7 8 9 10 11 public class CharacterEncodingFilter implements Filter { @Override public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8" ); response.setContentType("text/html;charset=UTF-8" ); chain.doFilter(request, response); } }
2、在web.xml里配置过滤器
1 2 3 4 5 6 7 8 9 <filter > <filter-name > characterEncodingFilter</filter-name > <filter-class > com.muyoukule.filter.CharacterEncodingFilter</filter-class > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
3、编写方法
1 2 3 4 5 @PostMapping("/register") public String register (User user) { System.out.println(user); return "success" ; }
4、启动服务器,填写信息后点击注册成功 跳转到注册成功页面,控制台打印:
1 User{id=null, username='木又枯了', password='123', sex='1', hobby=[smoke, drink, perm], intro='木又枯了太酷啦!!!'}
SpringMVC框架内置字符编码过滤器CharacterEncodingFilter
除此以外,SpringMVC框架内置了字符编码过滤器,叫做 CharacterEncodingFilter
,我们直接配置好即可使用。
CharacterEncodingFilter
中最核心的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String encoding = getEncoding(); if (encoding != null ) { if (isForceRequestEncoding() || request.getCharacterEncoding() == null ) { request.setCharacterEncoding(encoding); } if (isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); }
分析以上核心方法得知该过滤器对请求和响应都设置了字符编码方式。
当 强行使用请求字符编码方式为true
时,或者 请求对象的字符编码方式为null
时,设置请求的字符编码方式。
当 强行使用响应字符编码方式为true
时,设置响应的字符编码方式。
根据以上代码,可以得出以下配置信息,在web.xml文件中对过滤器进行如下配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <filter > <filter-name > characterEncodingFilter</filter-name > <filter-class > org.springframework.web.filter.CharacterEncodingFilter</filter-class > <init-param > <param-name > encoding</param-name > <param-value > UTF-8</param-value > </init-param > <init-param > <param-name > forceRequestEncoding</param-name > <param-value > true</param-value > </init-param > <init-param > <param-name > forceResponseEncoding</param-name > <param-value > true</param-value > </init-param > </filter > <filter-mapping > <filter-name > characterEncodingFilter</filter-name > <url-pattern > /*</url-pattern > </filter-mapping >
重启Tomcat10,看看乱码是否能够解决?
1 User{id=null, username='木又枯了', password='123', sex='1', hobby=[smoke, drink, perm], intro='木又枯了太酷啦!!'}
PS:针对于我们当前的Tomcat10的配置 来说,它有默认的字符集ISO-8859-1
,因此以下在web.xml文件中的配置是不能缺少的:
1 2 3 4 <init-param > <param-name > forceRequestEncoding</param-name > <param-value > true</param-value > </init-param >
如果缺少它,仍然是会存在乱码问题的。自行测试一下!!!!