配套视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
1.SpringMVC的引言
为了使Spring可插入的MVC架构,SpringFrameWork在Spring基础上开发SpringMVC框架,从而在使用Spring进行WEB开发时可以选择使用Spring的SpringMVC框架作为web开发的控制器框架。
2.为什么是SpringMVC?
-
可以和spring框架无缝整合
-
运行效率高于struts2框架
-
注解式开发更高效
3.SpringMVC的特点
SpringMVC 轻量级,典型MVC框架,在整个MVC架构中充当控制器框架,相对于之前学习的struts2框架,SpringMVC运行更快,其注解式开发更高效灵活。
4.SpringMVC与Struts2运行流程对比
5.第一个环境搭建
配套视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
新建Maven-webapp项目,添加java、resources目录以及test路径下java、resources目录
5.1 引入相关依赖
<!--spring核心及相关依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--springmvc核心依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--servlet-api--> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!--jstl--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>
5.2 编写springmvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--开启注解扫描--> <context:component-scan base-package="com.study.controller"/> <!-- <!–注册处理器映射器–>--> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>--> <!-- <!–注册处理器适配器–>--> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>--> <!--【推荐使用】注册处理器映射器、注册处理器适配器,完成参数类型转转、跳转、响应处理...--> <mvc:annotation-driven/> <!--注册视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--注入前缀和后缀:前缀和后缀固定写死,制可以根据项目页面目录动态变化--> <property name="prefix" value="/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
5.3 配置web.xml中springmvc相关参数
<!--配置springmvc核心servlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--配置springmvc配置文件位置--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!--拦截所有请求交给springmvc处理,注意此处是/而不是/*--> <url-pattern>/</url-pattern> </servlet-mapping>
注意: 这里还要加载springmvc配置文件位置,通过在servlet写init-param标签,还是contextConfigLocation属性,value用来加载springmvc配置文件。
5.4 创建控制器
package com.study.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @ClassName HelloController * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/20 16:01 * @Version 1.0 */ @Controller @RequestMapping("/hello") public class HelloController { /** * @RequestMapping 修饰范围: 用在 类上 和 方法上 * 1.用在方法上用来给当前方法加入指定的请求路径 相当于之前struts2中action标签的name属性 * 2.用在类上用来给类中所有方法加入一个统一请求路径在方法访问之前需要加入类上@requestMapping的路径 * 相当于之前struts2中package标签的namespace属性 * 注意: 一旦类上和方法上同时加入@requestMapping访问时必须 * /项目名/类上@requestMapping的路径/访问方法上@requestMapping的路径 */ //访问路径:http://localhost:8888/springmvc01/hello/find @RequestMapping(value = "/find") public String find(){ //1.收集数据 //2.调用业务方法 System.out.println("调用了find方法"); //3.处理响应 return "index";//页面逻辑名 对应 index.jsp } //访问路径:http://localhost:8888/springmvc01/hello/save @RequestMapping(value = "/save") public String save(){ //1.收集数据 //2.调用业务方法 System.out.println("调用了save方法"); //3.处理响应 return "index";//页面逻辑名 对应 index.jsp } }
-
@Controller
: 该注解用来在类上标识这是一个控制器组件类,并创建这个类实例 -
@RequestMapping
:-
修饰范围 : 用在方法或者类上
-
注解作用: 用来指定类以及类中方法的请求路径
-
注解详解 :
-
用在类上相当于struts2中namespace在访问类中方法必须先加入这个路径
-
用在方法上相当于action标签的name属性用来表示访问这个方法的路径
-
-
5.5 部署项目在tomcat服务器上进行测试
启动项目进行测试:
D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\catalina.bat run [2022-04-20 04:42:56,645] Artifact springmvc01:war exploded: Waiting for server connection to start artifact deployment... Using CATALINA_BASE: "C:\Users\cjn\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\Unnamed_springmvc01" Using CATALINA_HOME: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78" Using CATALINA_TMPDIR: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\temp" Using JRE_HOME: "D:\Software_Development\JDK" Using CLASSPATH: "D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\bootstrap.jar;D:\Software_Development\IDEA_code\apache-tomcat-8.5.78\bin\tomcat-juli.jar" Using CATALINA_OPTS: "" ...... Connected to server [2022-04-20 04:42:58,218] Artifact springmvc01:war exploded: Artifact is being deployed, please wait... ...... [2022-04-20 04:42:59,430] Artifact springmvc01:war exploded: Artifact is deployed successfully [2022-04-20 04:42:59,430] Artifact springmvc01:war exploded: Deploy took 1,212 milliseconds ... 调用了find方法 调用了save方法
访问路径 :
http://localhost:8888/springmvc01/hello/find
或
http://localhost:8888/springmvc01/hello/save
与此同时,控制台输出“调用了xxx方法”
5.6 编程步骤总结
6.SpringMVC中跳转方式
配套视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
6.1 跳转方式
-
说明 : 跳转方式有两种,一种是forward,一种是redirect。
-
forward跳转,一次请求,地址栏不变
-
redirect跳转,多次请求,地址栏改变
-
# 1.Controller跳转到JSP forward跳转到页面: 默认就是forward跳转 语法: return "页面逻辑名" 例如: return "index"; redirect跳转到页面: 使用springmvc提供redirect:关键字进行重定向页面跳转 语法: return "redirect: 跳转页面逻辑名" 例如: return "redirect:/index.jsp" 注意: 使用redirect跳转页面不会经过视图解析器 # 2.Controller跳转到Controller forward跳转到Controller: 使用springmvc提供的关键字forward: 语法: forward:/跳转类上@requestMapping的值/跳转方法上@RequestMapping的值 redirect:跳转到Controller: 使用springmvc提供关键字redirect: 语法: redirect:/跳转类上@requestMapping的值/跳转方法上@RequestMapping的值
6.2 编写代码启动tomcat服务器进行测试
package com.study.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * @ClassName ForwardAndRedirectController * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/21 10:57 * @Version 1.0 */ @Controller @RequestMapping("forwardAndRedirect") public class ForwardAndRedirectController { /** * @MethodName test * @Description 测试forward跳转到页面 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:03 */ @RequestMapping("test") public String test(){ System.out.println("测试forward跳转到页面"); return "index"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test * 输出结果分析: * 不写时默认forward跳转,即从controller跳转到页面 * 地址栏:不变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test * jsp页面:index.jsp(即原始默认输出Hello World!的页面) * 控制台输出:测试forward跳转到页面 */ } /** * @MethodName test1 * @Description 测试redirect跳转到页面 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:04 */ @RequestMapping("test1") public String test1(){ System.out.println("测试redirect跳转到页面"); return "redirect:/index.jsp"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test1 * 输出结果分析: * 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/index.jsp * jsp页面:index.jsp * 控制台输出:测试redirect跳转到页面 */ } /** * @MethodName test2 * @Description 测试forward跳转到相同controller类中的不同方法 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:11 */ @RequestMapping("test2") public String test2(){ System.out.println("测试forward跳转到相同controller类中的不同方法"); return "forward:/forwardAndRedirect/test"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test2 * 输出结果分析: * 地址栏:不改变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test2 * jsp页面:index.jsp * 控制台输出:测试forward跳转到相同controller类中的不同方法 * 测试forward跳转到页面 */ } /** * @MethodName test3 * @Description 测试redirect跳转到相同controller类中的不同方法 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:15 */ @RequestMapping("test3") public String test3(){ System.out.println("测试redirect跳转到相同controller类中的不同方法"); return "redirect:/forwardAndRedirect/test"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test3 * 输出结果分析: * 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/forwardAndRedirect/test * jsp页面:index.jsp * 控制台输出:测试redirect跳转到相同controller类中的不同方法 * 测试forward跳转到页面 */ } /** * @MethodName test4 * @Description 测试forward跳转到不同controller类中的不同方法 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:18 */ @RequestMapping("test4") public String test4(){ System.out.println("测试forward跳转到不同controller类中的不同方法"); return "forward:/hello/find"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test4 * 输出结果分析: * 地址栏:不改变,仍为 http://localhost:8888/springmvc01/forwardAndRedirect/test4 * jsp页面:index.jsp * 控制台输出:测试forward跳转到不同controller类中的不同方法 * 调用了find方法 */ } /** * @MethodName test5 * @Description 测试redirect跳转到不同controller类中的不同方法 * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 11:24 */ @RequestMapping("test5") public String test5(){ System.out.println("测试redirect跳转到不同controller类中的不同方法"); return "redirect:/hello/find"; /** * 访问路径:http://localhost:8888/springmvc01/forwardAndRedirect/test5 * 输出结果分析: * 地址栏:经redirect改变一次,变为 http://localhost:8888/springmvc01/hello/find * jsp页面:index.jsp * 控制台输出:测试redirect跳转到不同controller类中的不同方法 * 调用了find方法 */ } }
6.3 跳转方式总结
或
7. SpringMVC中参数接收
配套视频:
【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
-
接收参数语法说明:springmvc中使用控制器方法参数来收集客户端的请求参数,因此在接收请求参数时直接在需要的控制器方法中声明即可,springmvc可以自动根据指定类型完成类型的转换操作。
7.1 接收零散类型参数
如: 八种基本类型 + String + 日期类型
a.前台传递参数
# GET 方式传递参数 http://localhost:8080/springmvc_day1/param/test?name=zhangsan&age=19&sex=true&salary=11.11&bir=2012/12/12 # POST 方式传递参数 <h1>测试参数接收</h1> <form action="${pageContext.request.contextPath}/param/test" method="post"> 用户名: <input type="text" name="name"/> <br> 年龄: <input type="text" name="age"/> <br> 性别: <input type="text" name="sex"> <br> 工资: <input type="text" name="salary"> <br> 生日: <input type="text" name="bir"> <br> <input type="submit" value="提交"/> </form>
b.后台控制器接收
@Controller @RequestMapping("/param") public class ParamController { @RequestMapping("/test") public String test(String name, Integer age, Boolean sex,Double salary,Date bir){ System.out.println("姓名: "+name); System.out.println("年龄: "+age); System.out.println("性别: "+sex); System.out.println("工资: "+salary); System.out.println("生日: "+bir); return "index"; } }
注意:springmvc在接收日期类型参数时日期格式必须为yyyy/MM/dd HH:mm:ss
7.2 接收对象类型参数
a.前台传递参数
# GET 方式请求参数传递 http://localhost:8080/springmvc_day1/param/test1?name=zhangsan&age=19&sex=true&salary=11.11&bir=2012/12/12 # POST 方式请求参数传递 <h1>测试对象类型参数接收</h1> <form action="${pageContext.request.contextPath}/param/test1" method="post"> 用户名: <input type="text" name="name"/> <br> 年龄: <input type="text" name="age"/> <br> 性别: <input type="text" name="sex"> <br> 工资: <input type="text" name="salary"> <br> 生日: <input type="text" name="bir"> <br> <input type="submit" value="提交"/> </form>
注意:在接收对象类型参数时和struts2接收不同,springmvc直接根据传递参数名与对象中属性名一致自动封装对象
b.后台控制器接收
// 1.定义对象 public class User { private String name; private Integer age; private Double salary; private Boolean sex; private Date bir; } // 2.控制器中接收 @RequestMapping("/test1") public String test1(User user){ System.out.println("接收的对象: "+user); return "index"; }
7.3 接收数组类型参数
a.前台传递参数
# GET 方式请求参数传递 http://localhost:8080/springmvc_day1/param/test2?names=zhangsan&names=lisi&names=wangwu # POST 方式请求参数传递 <h1>测试对象类型参数接收</h1> <form action="${pageContext.request.contextPath}/param/test2" method="post"> 爱好: <br> 看书: <input type="checkbox" name="names"/> 看电视:<input type="checkbox" name="names"/> 吃饭: <input type="checkbox" name="names"/> 玩游戏: <input type="checkbox" name="names"/> <input type="submit" value="提交"/> </form>
b.后台控制器接收
@RequestMapping("/test2") public String test2(String[] names){ for (String name : names) { System.out.println(name); } return "index"; }
注意:接收数组类型数据时前台传递多个key一致自动放入同一个数组中
7.4 接收集合类型参数
说明:springmvc不支持直接将接收集合声明为控制器方法参数进行接收,如果要接收集合类型参数必须使用对象封装要接收接收类型才可以
a.前台传递参数
# GET 方式请求参数传递 http://localhost:8080/springmvc_day1/param/test3?lists=zhangsan&lists=lisi&lists=wangwu # POST 方式请求参数传递 <h1>测试对象类型参数接收</h1> <form action="${pageContext.request.contextPath}/param/test3" method="post"> 爱好: <br> 看书: <input type="checkbox" name="lists"/> 看电视:<input type="checkbox" name="lists"/> 吃饭: <input type="checkbox" name="lists"/> 玩游戏: <input type="checkbox" name="lists"/> <input type="submit" value="提交"/> </form>
b.后台控制器接收
// 1.封装接收集合类型对象---->在spring mvc中用来接收集合类型参数 public class CollectionVO { private List<String> lists; public List<String> getLists() { return lists; } public void setLists(List<String> lists) { this.lists = lists; } } // 2.控制器中接收集合类型参数 @RequestMapping("/test3") public String test3(CollectionVO collectionVO){ collectionVO.getLists().forEach(name-> System.out.println(name)); return "index"; }
7.5 代码实测
User
package com.study.entity; import java.util.Date; /** * @ClassName User * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/21 15:37 * @Version 1.0 */ public class User { private String name; private Integer age; private Boolean sex; private Double salary; private Date bir; public User() { } public User(String name, Integer age, Boolean sex, Double salary, Date bir) { this.name = name; this.age = age; this.sex = sex; this.salary = salary; this.bir = bir; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getSex() { return sex; } public void setSex(Boolean sex) { this.sex = sex; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Date getBir() { return bir; } public void setBir(Date bir) { this.bir = bir; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", sex=" + sex + ", salary=" + salary + ", bir=" + bir + '}'; } }
CollectionVO
package com.study.vo; import com.study.entity.User; import java.util.List; import java.util.Map; /** * @ClassName CollectionVO * @Description 自定义VO对象 * @Author Jiangnan Cui * @Date 2022/4/21 15:38 * @Version 1.0 */ public class CollectionVO { private List<String> lists; private Map<String,String> maps; public List<String> getLists() { return lists; } public void setLists(List<String> lists) { this.lists = lists; } public Map<String, String> getMaps() { return maps; } public void setMaps(Map<String, String> maps) { this.maps = maps; } }
ParamController
package com.study.controller; import com.study.entity.User; import com.study.vo.CollectionVO; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Date; /** * @ClassName ParamController * @Description TODO * @Author Jiangnan Cui * @Date 2022/4/21 15:36 * @Version 1.0 */ @Controller @RequestMapping("param") public class ParamController { /** * @MethodName test * @Description 用来测试零散类型参数接收 * @param: name * @param: age * @param: sex * @param: salary * @param: bir * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 15:44 */ @RequestMapping("test") public String test(String name, Integer age, Boolean sex, Double salary, Date bir){ System.out.println("用来测试零散类型参数接收"); System.out.println("name = " + name); System.out.println("age = " + age); System.out.println("sex = " + sex); System.out.println("salary = " + salary); System.out.println("bir = " + bir); return "index"; /** * 访问路径:http://localhost:8888/springmvc01/param/test?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56 * 输出结果: * 用来测试零散类型参数接收 * name = 张三 * age = 20 * sex = true * salary = 1234.5 * bir = Sat Dec 12 12:34:56 CST 2020 * * 注意: * 日期默认格式:yyyy/MM/dd HH:mm:ss */ } /** * @MethodName test1 * @Description 用来测试对象类型的参数接收 * @param: user * @param: name * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 15:50 */ @RequestMapping("test1") public String test1(User user,String name){ System.out.println("用来测试对象类型的参数接收"); System.out.println("user = " + user); System.out.println("name = " + name); return "index"; /** * 访问路径:http://localhost:8888/springmvc01/param/test1?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56 * 输出结果: * 用来测试对象类型的参数接收 * user = User{name='张三', age=20, sex=true, salary=1234.5, bir=Sat Dec 12 12:34:56 CST 2020} * name = 张三 * * 注意: * 此处的User中的name属性和变量name都会赋值 * * 总结: * 接收对象类型: 也是直接将要接收对象作为控制器方法参数声明 * 注意:springmvc封装对象时直接根据传递参数key与对象中属性名一致自动封装对象 * url提交: http://localhost:8888/springmvc01/param/test1?name=张三&age=20&sex=true&salary=1234.5&bir=2020/12/12 12:34:56 * form表单提交: * input name="id" * input name="name" * input name="age" * .... */ } /** * @MethodName test2 * @Description 用来测试数组类型的参数接收 * @param: collectionVO * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 15:55 */ @RequestMapping("test2") public String test2(String[] arrays){ System.out.println("用来测试数组类型的参数接收"); for (String array : arrays) { System.out.println("array = " + array); } return "index"; /** * 访问路径:http://localhost:8888/springmvc01/param/test2?arrays=吃饭&arrays=睡觉&arrays=打豆豆 * 输出结果: * 用来测试数组类型的参数接收 * arrays = 吃饭 * arrays = 睡觉 * arrays = 打豆豆 * * 总结: * 接收数组: 将要接收数组类型直接声明为方法的形参即可 * 注意: 保证请求参数多个参数key与声明数组变量名一致,springmvc会自动放入同一个数组中 * url提交: http://localhost:8888/springmvc01/param/test2?arrays=吃饭&arrays=睡觉&arrays=打豆豆 * form表单提交中多用于checkbox * input type="checkbox" name="arrays" value="卖吃饭" * input type="checkbox" name="arrays" value="睡觉" * input type="checkbox" name="qqs" value="打豆豆" * .... */ } /** * @MethodName test3 * @Description 用来测试list集合类型参数接收 * @param: collectionVO * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 16:08 */ @RequestMapping("test3") public String test3(CollectionVO collectionVO){ System.out.println("用来测试list集合类型参数接收"); collectionVO.getLists().forEach(list -> System.out.println("list = " + list)); return "index"; /** * 访问路径:http://localhost:8888/springmvc01/param/test3?lists=吃饭&lists=睡觉&lists=打豆豆 * 注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值 * 输出结果: * 用来测试list集合类型参数接收 * list = 吃饭 * list = 睡觉 * list = 打豆豆 * * 总结: * springmvc不能直接通过形参列表方式收集集合类型参数 * 如果要接收集合类型的参数必须将集合放入对象中接收才可以,推荐放入vo对象中接收集合类型,即新创建vo包,包中自定义集合 * vo = value object 值对象 */ } /** * @MethodName test4 * @Description 用来测试map集合类型参数接收 * @param: collectionVO * @return: java.lang.String * @Author Jiangnan Cui * @Date 2022/4/21 16:21 */ @RequestMapping("test4") public String test4(CollectionVO collectionVO){ System.out.println("用来测试map集合类型参数接收"); collectionVO.getMaps().forEach((k,v)-> System.out.println("k=" + k+",v="+v)); return "index"; /** * 访问路径:http://localhost:8888/springmvc01/param/test4?maps[1]=吃饭&maps[2]=睡觉&maps[3]=打豆豆 * 注意:在url中对参数进行赋值的时候要给CollectionVO中的集合赋值而不是collectionVO赋值 * 输出结果: * 用来测试map集合类型参数接收 * k= 1,v= 吃饭 * k= 2,v= 睡觉 * k= 3,v= 打豆豆 */ } }
如果map传递参数时出现400错误,如下所示:
解决方案:
如果测试时出现HTTP状态 400-错误的请求,是因为日志显示请求地址中包含了不合法字符. tomcat高版本严格按照RFC 3986规范解析地址。该规范只允许包含a-z A-Z 0-9 - _ . ~ 以及所有保留字符 ! * ’ ( ) ; : @ & = + $ , / ? # [ ] 解决方案:在使用的tomcat文件夹中找到conf,打开后对server.xml进行编辑,在 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/> 后面加上relaxedPathChars="|{}[],%" relaxedQueryChars="|{}[],%",其余不用修改,即: <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" relaxedPathChars="|{}[],%" relaxedQueryChars="|{}[],%"/> 保存后,重启tomcat即可解决。 参考链接:https://blog.51cto.com/u_15196075/2765608
7.6 接收参数中文乱码解决方案
配套视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
param.jsp
<%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <!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"> <title>测试参数接收</title> </head> <body> <h1>测试对象和零散类型参数接收</h1> <form action="${pageContext.request.contextPath}/param/test1" method="post"> 用户姓名:<input type="text" name="name"><br> 用户年龄:<input type="text" name="age"><br> 用户性别:<input type="text" name="sex"><br> 用户收入:<input type="text" name="salary"><br> 用户生日:<input type="text" name="bir"><br> <input type="submit" value="提交"> </form> </body> </html>
测试路径:http://localhost:8888/springmvc01/param.jsp
测试结果:
1.英文状态 用来测试对象类型的参数接收 user = User{name='xiaosan', age=20, sex=false, salary=1000.0, bir=Mon Dec 12 00:00:00 CST 2022} name = xiaosan 2.中文状态 用来测试对象类型的参数接收 user = User{name='?°?è??', age=22, sex=true, salary=800.0, bir=Thu Mar 15 00:00:00 CST 2018} name = ?°?è??
注意:在使用springmvc接收客户端的请求参数的过程中有时会出现中文乱码问题,这是因为springmvc并没有对对象请求参数进行编码控制,如果需要控制需要自行指定。
# 1.针对于GET方式中文乱码解决方案: <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/> # 2.针对POST方式中文乱码解决方案: web.xml中配置字符Filter <!--配置post请求方式中文乱码的Filter--> <filter> <filter-name>charset</filter-name> <!--自定义的Filter--> <!-- <filter-class>com.study.filter.CharacterEncodingFilter</filter-class>--> <!--spring框架提供的Filter--> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>charset</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
自定义编码Filter
package com.study.filter; import javax.servlet.*; import java.io.IOException; /** * @ClassName CharacterEncodingFilter * @Description 自定义编码Filter * @Author Jiangnan Cui * @Date 2022/4/22 15:51 * @Version 1.0 */ public class CharacterEncodingFilter implements Filter { private String encoding; @Override public void init(FilterConfig filterConfig) throws ServletException { this.encoding = filterConfig.getInitParameter("encoding"); System.out.println(encoding); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding(encoding); servletResponse.setCharacterEncoding(encoding); filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
总结:
7.7 总结
8.SpringMVC中数据传递机制
配套视频:【编程不良人】继spring之后快速入门springmvc,面对SpringMVC不用慌_哔哩哔哩_bilibili
8.1 数据传递机制
# 1.数据怎么存 Servlet 作用域 Struts2 作用域 SpringMVC 作用域 # 2.数据怎么取 Servlet EL表达式 Struts2 EL表达式 SpringMVC EL表达式 # 3.数据怎么展示 Servlet JSTL标签 Struts2 JSTl标签 SpringMVC JSTL标签
8.2 使用forward跳转传递数据
# 1.使用servlet中原始的request作用域传递数据 request.setAttribute("key",value); # 2.使用是springmvc中封装的Model和ModelMap对象(底层对request作用域封装) model.addAttribute(key,value); modelMap.addAttribute(key,value);
8.3 使用Redirect跳转传递数据
# 1.使用地址栏进行数据传递 url?name=zhangsan&age=21 # 2.使用session作用域 session.setAttribute(key,value); session.getAttribute(key);
8.4 代码测试
AttributeController
package com.study.controller; import com.study.entity.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Arrays; import java.util.Date; import java.util.List; /** * @ClassName AttributeController * @Description 用来测试SpringMVC中的数据传递机制 * @Author Jiangnan Cui * @Date 2022/4/22 20:40 * @Version 1.0 */ @Controller @RequestMapping("attribute") public class AttributeController { /** * 使用forward跳转页面数据传递 * 1.传递零散类型数据 * 2.传递对象类型数据 * 3.传递集合类型数据 * * 可以使用request对象进行数据传递,也可以使用model对象进行数据传递,其底层封装的也是request对象 */ @RequestMapping("test") public String test(Model model,HttpServletRequest request, HttpServletResponse response){ //1.收集参数 //2.调用业务方法 //传递零散类型数据 String name = "小崔"; //request.setAttribute("name",name); model.addAttribute("name",name); //传递对象类型数据 User user = new User("光头强",50,true,12.12,new Date()); //request.setAttribute("user",user); model.addAttribute("user",user); //传递集合类型数据 User user1 = new User("熊大",30,true,6.06,new Date()); User user2 = new User("熊二",20,true,3.03,new Date()); List<User> users = Arrays.asList(user1, user2); //request.setAttribute("users",users); model.addAttribute("users",users); return "attribute"; } /** * 使用redirect跳转传递数据 * 传递数据的方式有2种: * 1.地址栏?拼接数据 * 2.session对象 */ @RequestMapping("test1") public String test1(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException { //1.收集数据 //2.调用业务 String name = "小猫"; User user = new User("小猪", 3, false, 0.1234, new Date()); User user1 = new User("小狗", 4, false, 1.2345, new Date()); User user2 = new User("小兔", 5, false, 2.3456, new Date()); List<User> users = Arrays.asList(user1, user2); request.getSession().setAttribute("user",user); request.getSession().setAttribute("users",users); //3.流程跳转 return "redirect:/attribute.jsp?name=" + URLEncoder.encode(name,"UTF-8"); } }
attribute.jsp
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@page contentType="text/html; UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <!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"> <title>测试数据传递</title> </head> <body> <h1>用来测试request作用域传递数据</h1> 获取request作用域数据:${requestScope.name}<br> 获取request作用域数据:${name}<br> <hr color="red"> name:${requestScope.user.name}<br> age:${requestScope.user.age}<br> sex:${requestScope.user.sex}<br> salary:${requestScope.user.salary}<br> bir:<fmt:formatDate value="${requestScope.user.bir}" pattern="yyyy-MM-dd"/></h3> <hr> <c:forEach items="${requestScope.users}" var="user"> name:${user.name}<br> age: ${user.age}<br> sex: ${user.sex}<br> salary: ${user.salary}<br> bir: <fmt:formatDate value="${user.bir}"/><br> <hr> </c:forEach> <br> <h1>测试使用redirect跳转传递数据</h1> 获取地址栏数据:${param.name}<br> <hr color="red"> name: ${sessionScope.user.name}<br> age: ${sessionScope.user.age}<br> sex: ${sessionScope.user.sex}<br> salary: ${sessionScope.user.salary}<br> bir: ${sessionScope.user.bir}<br> <hr> <c:forEach items="${sessionScope.users}" var="user"> name:${user.name}<br> age: ${user.age}<br> sex: ${user.sex}<br> salary: ${user.salary}<br> bir: <fmt:formatDate value="${user.bir}"/><br> <hr> </c:forEach> </body> </html>
测试结果:
(1)http://localhost:8888/springmvc01/attribute/test
(2)http://localhost:8888/springmvc01/attribute/test1
8.5 总结
9.SpringMVC处理静态资源拦截
# 1.处理静态资源拦截 # 问题:当web.xml中配置为"/"时,会拦截项目静态资源 <mvc:default-servlet-handler/>