接收表单复合数据
说明:
(1) 本篇博客的内容:接收复合数据:如下,form表单中的【您的学习目的】,我们可以选择多项,对于这样的复合数据,【Spring MVC】如何接收,就是本篇博客的主要内容;
零:本篇博客内容;
说明:
(1) 可以使用数据或者List接收【复合数据】;
(2) 如果某个参数没有被传递的时候,我们不希望这个参数是null,我们可以使用@RequestParam为这个参数设置默认值;
(3) 使用Map对象一次性接收(请求中的)所有参数:这是一种常见但又容易出错的点;
(1)pom.xml:
说明:
(1) 没什么好说的,就是设置了一些国内仓库;引入了【Spring-webmvc】的依赖;
说明:
(1) form.html就是一个如下图所示的前端文件:
(2) 其中form表单的提交地址【form action=“./apply” method=“post”】中的【./】是指当前路径:
为此就需要介绍下,URI相对路径与绝对路径;
● URI是统一资源定位符,是URL的子集;(即去掉URL中的主机和端口,剩下的就是URI);
● 绝对路径和相对路径如下图:很容易理解啦;
● 在开发时,使用【相对路径】更方便些;
(注):当我们一个IDEA,打开过多个不同的web应用时,我们可以多个不同的Tomcat服务器,然后根据情况为当前工程选择合适的Tomcat服务器!
(1) 配置多个Tomcat服务器,隐约感觉到肯定有很多坑,比如多个服务器的端口尽量不要重复;这些坑需要自己以后慢慢踩、慢慢填;
二: 正式阐述&演示;
1.Example一:使用数组接收【复合数据】;
(2)启动Tomcat服务器,观察效果;
2.Example二:使用@RequestParam为参数设置默认值;
(2)启动Tomcat,观察效果;
3.Example三:使用List接收【复合数据】;
● 随着编程的深入,会发现在很多情况下,数组不咋好用,数组用的也越来越少了;因为,在Java中,提供了更有效的管理方式:集合;
●【Spring MVC】也默认支持,使用List接收和保存【复合数据】;
(2)启动Tomcat,观察效果;
说明:【使用数组接收复合数据】和【使用List接收复合数据】没有本质区别;
●【1.Example一:使用数组接收【复合数据】;】和【3.Example三:使用List接收【复合数据】;】,二者没有本质区别,只是一个数据的载体是数组,一个数据的载体是ArrayList;
● 更多是因为List对象有更多的方法,我们操作起来更方便;
● 在日常开发中,建议使用List接收复合数据;
3.1.Example三(附):使用【JavaBean】接收请求参数时,依旧可以使用List接收【复合数据】;
这儿其实就是【Controller接收请求:使用【Java Bean】接收】中的内容,只不过这个【JavaBean】中使用了List接收请求中的复合数据而已;
(3)启动Tomcat,观察效果;
【JavaBean中有List类型的属性,然后再用这个JavaBean去接收“包含复合数据”的请求参数】,这个开发技巧挺好用的,在实际开发中,一定要知道有这个开发技巧;
4.Example四:使用Map一次性接收(请求中的)所有参数
● 在实际开发中,也有很多人习惯【使用Map接收前端的表单数据】;这自然是没问题的,【Spring MVC】也支持;
● 但是,在接收【复合数据】时,Map有天生的缺陷;
同样,和List一样,使用Map接收数据的时,也需要使用@RequestParam注解;
(2)启动Tomcat,观察效果;
(3)建议:如果【表单不包含复合数据】,可以使用Map去收;如果【表单包含复合数据】,一定不要使用Map去接收,否则数据会丢失;
关联对象赋值
说明:
(1) 本篇博客必要性说明:
● 【关联对象】以前遇到过多次,就是指在一个对象中引用了另外一个对象;
● 我们需要对这个被引用对象进行赋值,这个操作就是【关联对象赋值】,这也是本篇博客的重点;
(2) 在实际开发中:
● 对于一个结构复杂的表单,不应该傻乎乎的只用一个JavaBean去接收;而是,应该根据面向对象设计原则,使用多个对象去对应表单中不同的数据;然后,后端通过【对象关联】的方式,把这些数据组织起来;
● 为此,在后端接受前端表单数据的时候,就涉及到了【关联对象赋值】;
● 而本篇博客的内容,就是为了说明这个问题的;同时,本篇博客的内容,在日常开发中是非常常见的;
(3) 从程序员的角度来说,实现【对象关联赋值】的步骤很简单,但能感受到背后【Spring MVC】做了支撑。
零:实际案例引入;
1.复杂表单案例说明;【只使用一个JavaBean去接收表单】不太好;
● 自然,对于这份表单,可以创建一个对象,来包含其中所有的属性,然后再使用前面介绍的【Spring MVC】为其赋值;但是,这样做并不好,因为这份表单包含了两类信息,【注册信息】和【个人身份信息】;
2.【使用“关联对象”的方式去接收表单】更好;关联对象赋值的步骤;
如果严格按照【面向对象设计原则】的话,对这个表单接收时,首先应该创建两个类; 需要注意,在User类中,需要实例化IDcard;
然后,在前端的form表单中,设置一下输入项的属性名;
一:演示如下
说明:
(1) form.html改动说明;
(2) 修改后,form.html效果;
2.然后,为了应对前端表单的变化,增加Delivery实体类,去对应接收【收货人信息】;
6.启动Tomcat,观察效果;
日期类型转换
说明:
(1) 本篇博客必要性说明:
● 世界各地,日期的表达方式存在差异;欧美常采用【月、日、年】的方式;中国常采用【年、月、日】的方式;
● 正是由于这种差异,我们在开发中,需要根据系统的实际需求,采用合适的日期格式进行处理;
●【 如何接收程序中(尤其是前端的输入)的日期数据、并将其转换为日期对象】,就是本篇博客的重点;
(2) 本篇博客包含【@DateTimeFormat注解的使用】和【Converter转换器类的使用和配置】两部分;
零:日期问题的引入:如果我们不设置,其自己无法完成String和Data的转换;
(1) 增加一个日期;
(2) 启动Tomcat,观察效果;
一:后端通过【方法参数】接收前端参数
使用形如【@DateTimeFormat(pattern = “yyyy-MM-dd”)】的注解,解决日期转换问题;
(1) 在方法参数
使用【@DateTimeFormat(pattern = “yyyy-MM-dd”) 】注解;
(2) 启动Tomcat,观察效果;
二:后端通过【JavaBean】接收前端参数
也可使用形如【@DateTimeFormat(pattern = “yyyy-MM-dd”)】的注解,解决日期抓换问题;
(1)在类属性上
使用【@DateTimeFormat(pattern = “yyyy-MM-dd”) 】注解;
(2)启动Tomcat,观察效果;
注:但是,使用注解比较麻烦;使用【日期转换器】更好;
● 使用【@DateTimeFormat(pattern = “yyyy-MM-dd”) 】注解,是很简单的;
● 但是,使用注解开发,也有不方便的地方;设想一下,对于一个大型的系统中,会有很多地方都需要进行Date日期类型的转换,难道对于每个地方我们都要手动增加【@DateTimeFormat(pattern = “yyyy-MM-dd”) 】注解吗?这样做太麻烦了;
● 为此,可以引入“全局的默认时间转换器”,即可以设置全局的默认时间格式;
三:编写【Converter日期转换器】;(本篇博客核心!!!)
(1)编写Converter日期转换器类;
MyDateConverter类:
说明:
但是,至此,MyDateConverter类只是一个标准的Java类,Spring MVC还不知道这个类的存在;为此就需要在applicationContext.xml配置文件中进行设置,让Spring MVC知道MyDateConverter类是一个转化器类,并且让其起作用;
(2)在applicationContext.xml中配置转换器类;
说明:
(3)测试一下;
这儿我们用get方法测试一下,在方法参数中增加一个【Date类型的createTime】;
启动Tomcat,观察效果;
(4)日期转换器类似乎可以这样理解:
●
上面我们编写了MyDateConverter日期转换器类,这个转换器在泛型中已经定义了<String,Date>,即是把String类型转为Date类型;
● 然后,经过我们在applicationContext.xml中配置转换器类后,Spring
MVC就会知道,以后只要是把String类型的数据转换为Date类型数据时,就去找MyDateConverter类;
● 上面的理解很粗糙,但似乎目前只能这样说服自己;也能感受到在背后,Spring MVC做了强大的支撑;
● 在实际中,如果即使用了【@DateTimeFormat注解】,又编写了【日期转换器类】时,是以【转换器类】为准的;
● Spring MVC的强制要求:一旦增加了【日期转换器类】,那么优先去使用【转换器类】来处理日期类型的转换工作,【@DateTimeFormat注解】就会被忽略掉;
● 所以,在实际开发中,一种比较好的开发方式是:【@DateTimeFormat注解】和【日期转换器类】,只能二者选其一;要么使用【@DateTimeFormat注解】对所有的日期类型加以转换,要么使用【日期转换器类】,全局统一转换;
● 但是,在一个大型系统中,往往会出现这种情况:99%的情况下,前端输入的日期格式是形如【2020-05-04】的格式,此时我们的转换器类是没问题的:
但是,保不齐,该大型系统中某些地方日期的输入格式是形如【20200504】的格式,那么为此,我们就需要修改下MyDateConverter日期转换器类了:根据实际的业务逻辑,在MyDateConverter类中,增加对不同情况的判断和分别处理就行了;
中文乱码问题解决
说明:
(1) 本篇博客必要性说明:默认情况下,Spring MVC对中文的支持度不高,很多时候会出现中文乱码的情况;本篇博客就是介绍中文乱码问题的解决策略;
(2) 本篇博客内容虽多,但实操起来并不复杂,需要时,及时查阅即可;
零:中文乱码简述;
(1) 中文乱码问题由来和解决思路;
(0) 前面在介绍Servlet的时候,就接触过中文乱码的问题;
(1) 中文乱码根源是字符集的问题;
● 计算机要识别某种自然语言,就必须依赖于字符集,不同的字符集使用不同的编码方式;字符集就像是一个【专为计算机使用的字典】,计算机通过特定的字符集把【指令】准换为【特定的字符】;
● Tomcat早期的版本中,使用ISO-8859-1字符集;这个字符集是西欧字符集,包含了英文字母、拉丁字母、数字、标准符号等;ISO-8859-1不支持中文;所以,使用ISO-8859-1字符集处理中文时,会出现乱码问题;
(2) 解决策略;
● 核心策略就是把ISO-8859-1编码方式,转换为UTF-8的编码方式;
● UTF-8(Universal Character Set/Unicode Transformation Format)就是Unicode码的8位交换集格式;
● Unicode字符集,包含了世界上已知的各种语言,所以UTF-8自然支持中文;
(3) 在开发中,请求和响应都需要设置UTF-8;
(2)具体的解决策略;
(0) 基本上,在任何一个项目中,都需要设置以下三步;
(1) 首先,解决get请求的乱码:需要在Tomcat的server.xml中增加URIEncoding属性,配置UTF-8;
(2) 然后,解决post请求的乱码:在web.xml中配置CharacterEncodingFilter过滤器,通过Spring提供的这个过滤器,来解决post请求中的中文乱码问题;
(3) 最后,解决响应的乱码:在Spring的配置文件applicationContext.xml中配置StringHTTPMessageConverter这个转换器;
一:解决【get请求的中文乱码】
设置Tomcat配置文件server.xml中的URIEncoding属性,配置UTF-8;
(1)需要配置Tomcat的server.xml配置文件中的URIEncoding;
(2)启动Tomcat,观察效果;
二:解决【post请求的中文乱码】
在web.xml中配置CharacterEncodingFilter过滤器;
(0)没有设置前,Post请求乱码演示:启动Tomcat,效果如下:
对于Spring MVC,为了解决post请求的中文乱码问题,目前广泛采用的方法是【增加一个过滤器,转换字符集】;
(1)Spring MVC中配置过滤器;(核心内容!!!)
在web.xml中配置字符集过滤器:
说明:
(1) 只是这儿Spring MVC已经帮我们写好了过滤器类,我们拿来用就行了;
(2)设置后,Post请求乱码演示:启动Tomcat,效果如下:
三:解决【响应的中文乱码】
在applicationContext.xml中配置StringHttpMessageConverter这个转换器;
(0)没有设置前,响应的中文乱码演示:启动Tomcat,效果如下:
对于Spring MVC,为了解决响应的中文乱码问题,目前广泛采用的方法是【在Spring的配置文件applicationContext.xml中配置StringHTTPMessageConverter这个转换器】;
(1)在Spring的配置文件applicationContext.xml中配置
StringHTTPMessageConverter这个转换器;(核心内容!!!)
applicationContext.xml:
说明:
(1) 配置了哪些内容:
(2) 配置内容说明:
(3) 可以看到,这儿的套路,和以前在Controller中使用如
【response.setContentType(“text/html;charset=utf-8”)】原理是一样的;只是,这儿我们是在配置文件中配置的,而这会让程序更加灵活和易于维护;
(2)设置后,响应的中文乱码演示
启动Tomcat,效果如下:
响应输出结果
说明:
(1) 本篇博客必要性说明:
● 在前面几篇博客中,介绍的都是【请求】的内容;即【后端的Controller如何设置url映射】、【后端的Controller如何接收前端请求的数据】等;
● 本篇博客就介绍响应的相关内容,即【后端给前端的响应,是如何输出结果的】;
(2)
本篇博客涉及到了JSP的一些内容,如有需要可以快速参考【(4)JavaWeb基础(网页搭建与JavaWeb基础)】中的相关内容;
(3)本篇博客的内容:
● 简单介绍了@ResponseBody,具体ResponseBody在实际开发中常用的场景,有待积累和总结;
● 引入了ModelAndView对象,有关该对象的详细内容,会在下篇博客中介绍;
一:响应产生结果的两种方式
简介;(@ResponseBody注解,ModelAndView对象)
说明:
(1) 第一种:@ResponseBody:在Controller的方法上,使用@ResponseBody注解,直接产生响应文本;前面接触过很多次,如下图;
(2) 第二种:ModelAndView:
● 但有的时候,【响应中只包含文本,即浏览器只显示一个文本】是不够的;
● 后端在处理请求后,往往需要跳转到一个新的页面,然后这个新的页面获取响应中的数据并展示(这个页面也称作View视图),为此就需要【响应包含一些比较复杂的、有组织的数据】;
● 在Spring MVC中,可以利用【ModelAndView对象】(承载数据),再结合【模板引擎】(JSP或FreeMarker等),在前端生成对应的页面;
二:第一种方式:@ResponseBody注解;
1.@ResponseBody简介;
说明:
(1) Controller方法直接return一个字符串,这个返回的字符串就是单纯给前端浏览器显示的,不涉及任何模板引擎的内容;
(2) 在实际开发中,Controller方法return的字符串,一般是JSON格式的字符串;
(3) ●在【中文乱码问题】知道,StringHTTPMessageConverter是Spring MVC定义的一个转换器,这个转换器的作用是解决响应中的中文乱码;
● 响应中的文本信息(字符串、JSON、XML等)都会 StringHttpMessageConverter的配置所影响;
● 自然,Controller方法return的字符串,会被StringHttpMessageConverter所影响;
2.@ResponseBody演示;返回的HTML字符串,会被浏览器解释、渲染,然后显示;
启动Tomcat,观察效果;
说明:
(1) 在实际开发中,后端一般不返回HTML片段;因为,这种方式太笨了;尤其对于复杂的页面,这样做的工作量太大了;
(2) 在实际工作中,一般采用的策略:【后端产生数据】+【前端的模板引擎】,得到最终的前端页面;
注:虽然,目前看来@ResponseBody在【显示前端页面】上不太适合;但,@ResponseBody还是有很多适用的场景的;
三:第二种方式:ModelAndView对象;
1.ModelAndView对象简介;
说明:
(1) ModelAndView:通过名字可知,是Model和View的意思;
(2) ModelAndView对象的目的,就是将【数据对象】和【模板引擎】进行绑定;
(3) Spring MVC默认的模板引擎是JSP;自然,也可以通过配置,使用FreeMarker等其他模板引擎;
2.ModelAndView的一个入门案例;
通过一个简单的入门案例,演示通过ModelAndView如何实现【页面的跳转】和【使用JSP显示后端产生的数据】;
(1)最简单的一个案例:后端没有传递数据:仅仅演示一下页面的跳转;
首先,在URLMappingController中定义一个后端的方法;
然后,编写要跳转到的前端页面view.jsp;
启动Tomcat,观察效果;
说明:
(1) 上面的案例,只是演示了一下【使用ModelAndView对象方式的时候,如何实现页面的跳转】,并没有传递数据。而在实际开发中,一般后端会传递数据的。
(2) 稍微复杂的一个案例:后端传递了数据;
首先,在URLMappingController中,编写一个有传递数据的方法;
然后, 在前端的view.jsp中接收后端传过来的数据;
启动Tomcat,观察效果;
说明:
(1) 有关JSP的EL表达式等内容,
如有需要可以快速参考【JavaWeb基础】中的相关内容;
(2) 上面的案例可以看到:
● 【数据:是后端Controller动态产生的】,【界面:是由JSP动态渲染的】;
● 上面的案例也体现了MVC的设计理念:视图和模型解耦;
● 而在Spring MVC中,就通过ModelAndView对象,来实现【视图和模型的解耦】,即【“数据产生的过程”和“界面展现的过程”,实现了解耦】;(已经知道,在没有Spring MVC的时候,我们一般把数据放在Servlet/Session/Context对象中;而这儿,我们把数据放在了ModelAndView对象中,可以感受到Spring MVC作了封装~~)
● 即在Spring MVC中,通过ModelAndView对象,就能很好的贯彻【MVC的设计理念】;
ModelAndView对象
说明:
(1) 本篇博客内容:
● 已知,在Spring MVC中,要想跳转页面,需要使用ModelAndView对象,来实现【数据和页面的绑定】;
● 本篇博客,就是介绍ModelAndView对象的详细内容;
● 其中包括【ModelAndView对象的setViewName()方法】,【绝对路径和相对路径】;
● 最后提到了扩展内容:【String和ModelMap】替代【ModelAndView】;
一:ModelAndView简介;
已知,在Spring MVC中,要想跳转页面,需要使用ModelAndView对象,来实现【数据和页面的绑定】;
说明:
(1) ModelAndView的addObject()方法:
● 该方法用于设置【前端页面要显示的数据是什么】;
● 该方法的参数:可以是任何一个有效的Java对象;
● 该方法默认把对象,存放在当前请求中的;
(2) ModelAndView对象在进行页面跳转的时候,默认使用【请求转发】的方式来实现;即底层使用了forward;
(3) ModelAndView对象,如果想通过【响应重定向】来实现页面跳转,那么就需要额外增加【redirect:】;
(4) 请求转发和响应重定向的内容,如有需要可以快速参考【JavaWeb基础]】专栏中的内容;
二:在进行页面跳转的时候,ModelAndView对象默认使用
【请求转发】的方式来实现页面跳转;可以增加【redirect:】,来使用【页面重定向】的方式实现页面跳转;
1. ModelAndView对象默认使用【请求转发】的方式来实现页面跳转;(使用的场景比较多)
说明:
(1) ModelAndView对象默认的【请求转发】的方式,也是常用的方式;
(2)【请求转发】的时候,Controller和view.jsp可以共享同一个请求对象,而这也方便Controller向view.jsp传递数据;
2. 可以增加【redirect:】,来使用【页面重定向】的方式实现页面跳转;(使用的场景相对少)
说明:
(1) 通过上面的案例,可以看到【页面重定向】会导致(原请求中的)数据的丢失;
(2.1) 因此引出的一个问题:既然【页面重定向】有这么个不给力的地方,那么【页面重定向】的使用场景有哪些?:
(2.2) 感觉(2.1)的水还是有点深的,目前见过的例子比较少,似乎不能很好的hold住;慢慢积累和总结吧。
三:也可以使用ModelAndView对象的【setViewName(“/view.jsp”)】方法来确定跳转的页面;
四:ModelAndView对象跳转页面时:【绝对路径】和【相对路径】;
1.原先使用如【mav.setViewName(“/view.jsp”);】时,前面有【/】:这是绝对路径;(推荐使用)
2.如果【mav.setViewName(“view.jsp”);】时,前面没有【/】:这是相对路径;(不推荐使用)
说明:
(1.1) 这种不带【/】前缀,相对路径的使用方式,在实际开发中还是很可能遇到的(你可能有一个喜欢使用这种方式的同事);
(1.2) 但是不建议在开发中使用这种方式:
(2) 在实际开发中,推荐使用绝对路径的方式;
五:扩展:使用【String和ModelMap】替代【ModelAndView】;
如下代码中的showView1()方法:就可以使用【String和ModelMap】来替代【ModelAndView】:
说明:
(1) showView1()方法和showView()方法,效果是一样的;
(2) showView1()方法分析;
(3) 通过showView1()方法,能够感觉到;【String和ModelMap】就是把【ModelAndView对象】拆分成了两个不同的部分,分别存储:
(4) 在实际开发中,这种【String和ModelMap】的方式,也是比较常见的;
甚至有的项目中,会发现【Controller中的方法返回值都是String,而不是ModelAndView】,也就是这个Controller中使用的全部是【String和ModelMap】的方式,没有使用【ModelAndView】的方式;
(5) 当【Controller的方法,返回值是String】,即使用【String和ModelMap】这种方式时,存在两种情况:
● 情况一:方法使用了@ResponseBody注解:这种也是没有接触【ModelAndView】之前,见到过的形式;
● 情况二:方法没有使用@ResponseBody注解:
(6) 有的场景下,ModelMap不是必需的:对于那些不需要向前端传递数据的情况,是可以不使用ModelMap的;
Spring MVC整合FreeMarker
说明:
(1) 有关FreeMarker的内容,如有需要可以快速参考【常用功能与过滤器、监听器、FreeMarker】中的内容;
(2) 本篇博客内容:
● Spring MVC默认使用JSP作为模板引擎,但又因为FreeMarker比JSP好用;所以本篇博客就介绍【Spring MVC整合FreeMarker】;
● 本篇博客仅仅说明了【Spring MVC整合FreeMarker】;
(3) 本篇博客又提到了那个容易忘记的点:我们引入新的依赖后,需要及时把这个依赖添加到发布中去;
一:【Spring MVC整合FreeMarker】步骤;
第一步:在Maven的pom.xml中引入【FreeMarker的依赖】和【spring-context-support】;
第二步:在applicationContext.xml中配置:通知Spring MVC【我们要使用FreeMarker模板引擎】;
说明:
(1) 这儿设置UTF-8编码方式是:在【Controller发过来的数据】和【FreeMarker模板引擎】渲染完成后,向客户端浏览器返回响应时,响应体中使用的字符串集编码是UTF-8;
(2) 经过上面的设置以后,Spring MVC就启用了FreeMarker,Spring
MVC已经知道了FreeMarker的存在;但是还不够,我们还需要对FreeMarker本身进行参数设置;
第三步:在applicationContext.xml中配置:配置FreeMarker参数;
说明:
(1) 这儿设置的UTF-8编码方式是:在【Controller发过来的数据】和【FreeMarker模板引擎】渲染的过程中,所有的字符按UTF-8字符集进行编码;
二:【Spring MVC整合FreeMarker】演示
第一步:在Maven的pom.xml中引入【FreeMarker的依赖】和【spring-context-support】;
pom.xml:
说明:
第二步:在applicationContext.xml中配置:通知Spring MVC【我们要使用FreeMarker模板引擎】;
第三步:在applicationContext.xml中配置:配置FreeMarker参数;
三:【在Spring MVC中实际使用FreeMarker】测试;
1.创建FreeMarkerController,test.ftl:用于演示;
FreeMarkerController:
说明:
(1) 关于跳转的进一步说明;
(2) 有关FreeMarker的内容,如有需要可以快速参考【常用功能与过滤器、监听器、FreeMarker】中的内容;
此时,还不能直接运行;还是那个容易忘记的点:我们引入新的依赖后,需要及时把这个依赖添加到发布中去;
如有需要可以参考:附加:IDEA的Artifacts;(这篇博客,以后有了更深的理解时,随时补充……)
2.容易忘记的一个点:将新引入的依赖,添加到发布中去;
说明:
(1) 上面的步骤虽然与【附加:IDEA的Artifacts】中的存在差异,但经过实测,其本质是一样的,殊途同归。
3.启动Tomcat,观察效果;
这样就说明,在我们的Spring MVC项目中,FreeMarker整合成功了,可以愉快的开始后续的开发了。