Spring框架学习第五天
1.Spring MVC具有如下特点。
· 是Spring框架的一部分,可以方便地利用Spring所提供的其他功能。
· 灵活性强,易于与其他框架集成。
· 提供了一个前端控制器DispatcherServlet,使开发人员无须额外开发控制器对象。
· 可自动绑定用户输入,并能正确的转换数据类型。
· 内置了常见的校验器,可以校验用户输入。如果校验不能通过,那么就会重定向到输入表单。
· 支持国际化。可以根据用户区域显示多国语言。
· 支持多种视图技术。它支持JSP、Velocity和FreeMarker等视图技术。
· 使用基于XML的配置文件,在编辑后,不需要重新编译应用程序。
实现如下——
1.项目结构
2配置前端控制器
在web.xml中,配置Spring MVC的前端控制器DispatcherServlet。
<?xml version="1.0" encoding="UTF-8"?>
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc-config.xml
1
springmvc
/
3.创建Controller类
package com.itheima.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
/**
* 控制器类
*/
public class FirstController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
// 创建ModelAndView对象
ModelAndView mav = new ModelAndView();
// 向模型对象中添加数据
mav.addObject("msg", "这是我的第一个Spring MVC程序");
// 设置逻辑视图名
mav.setViewName("/WEB-INF/jsp/first.jsp");
// 返回ModelAndView对象
return mav;
}
}
handleRequest()是Controller接口的实现方法,FirstController类会调用该方法来处理请求,并返回一个包含视图名或包含视图名和模型的ModelAndView对象。本案例中,向模型对象中添加了一个名称为msg的字符串对象,并设置返回的视图路径为"/WEB-INF/jsp/first.jsp",这样,请求就会被转发到first.jsp页面
4.创建Spring MVC的配置文件,配置控制器映射信息
<?xml version="1.0" encoding="UTF-8"?>
首先定义了一个名称为"/firstController"的Bean,该Bean会将控制器类FirstController映射到"/firstController"请求中;然后配置了处理器映射器BeanNameUrlHandlerMapping和处理器适配器SimpleControllerHandlerAdapter,其中处理器映射器用于将处理器Bean中的的name(即url)进行处理器查找,而处理器适配器用于完成对FirstController处理器中handleRequest()方法的调用。最后配置了视图解析器InternalResourceViewResolver来解析结果视图,并将结果呈现给用户。
5.创建视图(View)页面
在WEB-INF目录下,创建一个jsp文件夹,并在文件夹中创建一个页面文件first.jsp
6.启动项目即可。
2.Spring MVC的工作流程
Spring MVC程序的完整执行流程如下。
(1)用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet所拦截。
(2)DispatcherServlet拦截到请求后,会调用HandlerMapping处理器映射器。
(3)处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
(4)DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器)。
(5)HandlerAdapter会调用并执行Handler(处理器),这里的处理器指的就是程序中编写的Controller类,也被称之为后端控制器。
(6)Controller执行完成后,会返回一个ModelAndView对象,该对象中会包含视图名或包含模型和视图名。
(7)HandlerAdapter将ModelAndView对象返回给DispatcherServlet。
(8)DispatcherServlet会根据ModelAndView对象选择一个合适的ViewReslover(视图解析器)。
(9)ViewReslover解析后,会向DispatcherServlet中返回具体的View(视图)。
(10)DispatcherServlet对View进行渲染(即将模型数据填充至视图中)。
(11)视图渲染结果会返回给客户端浏览器显示。
在上述执行过程中,DispatcherServlet、HandlerMapping、HandlerAdapter和ViewResolver对象的工作是在框架内部执行的,开发人员并不需要关心这些对象内部的实现过程,只需要配置前端控制器(DispatcherServlet),完成Controller中的业务处理,并在视图中(View)中展示相应信息即可。
3.了解Spring MVC核心类的作用
DispatcherServlet
DispatcherServlet的全名是org.springframework.web.servlet.DispatcherServlet,它在程序中充当着前端控制器的角色。在使用时,只需将其配置在项目的web.xml文件中,其配置代码如下。
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation classpath:springmvc-config.xml
1
springmvc /
4.掌握Spring MVC常用注解的使用
在上述代码中,元素和元素都是可选的。如果元素的值为1,则在应用程序启动时会立即加载该Servlet;如果元素不存在,则应用程序会在第一个Servlet请求时加载该Servlet。如果元素存在并且通过其子元素配置了Spring MVC配置文件的路径,则应用程序在启动时会加载配置路径下的配置文件;如果没有通过元素配置,则应用程序会默认到WEB-INF目录下寻找如下方式命名的配置文件。
servletName-servlet.xml
其中,servletName指的是部署在web.xml中的DispatcherServlet的名称,在上面web.xml中的配置代码中即为springmvc,而-servlet.xml是配置文件名的固定写法,所以应用程序会在WEB-INF下寻找springmvc-servlet.xml。
Controller注解类型
org.springframework.stereotype.Controller注解类型用于指示Spring类的实例是一个控制器,其注解形式为@Controller。该注解在使用时不需要再实现Controller接口,只需要将@Controller注解加入到控制器类上,然后通过Spring的扫描机制找到标注了该注解的控制器即可。
@Controller注解在控制器类中的使用示例如下。
package com.itheima.controller;
import org.springframework.stereotype.Controller;
...
@Controller
public class FirstController{
.
}
为了保证Spring能够找到控制器类,还需要在Spring MVC的配置文件中添加相应的扫描配置信息,具体如下。
(1)在配置文件的声明中引入spring-context。
(2)使用元素指定需要扫描的类包。
<? xml version="1.0" encoding="UTF-8"? >
元素的属性base-package指定了需要扫描的类包为com.itheima.controller。在运行时,该类包及其子包下所有标注了注解的类都会被Spring所处理。
与实现了Controller接口的方式相比,使用注解的方式显然更加简单。同时,Controller接口的实现类只能处理一个单一的请求动作,而基于注解的控制器可以同时处理多个请求动作,在使用上更加的灵活。因此,在实际开发中通常都会使用基于注解的形式。
使用注解方式时,程序的运行需要依赖Spring的AOP包,因此需要向lib目录中添加spring-aop-4.3.6.RELEASE.jar,否则程序运行时会报错。
@RequestMapping注解的使用
Spring通过@Controller注解找到相应的控制器类后,还需要知道控制器内部对每一个请求是如何处理的,这就需要使用org.springframework.web.bind.annotation.RequestMapping注解类型。RequestMapping注解类型用于映射一个请求或一个方法,其注解形式为@RequestMapping,可以使用该注解标注在一个方法或一个类上。
1.标注在方法上
当标注在一个方法上时,该方法将成为一个请求处理方法,它会在程序接收到对应的URL请求时被调用。使用@RequestMapping注解标注在方法上的示例如下。
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
...
@Controller
public class FirstController{
@RequestMapping(value="/firstController")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
... return mav;
}
}
2.标注在类上
当标注在一个类上时,该类中的所有方法都将映射为相对于类级别的请求,表示该控制器所处理的所有请求都被映射到value属性值所指定的路径下。
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; ...
@Controller
@RequestMapping(value="/hello")
public class FirstController{
@RequestMapping(value="/firstController")
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response){ ...
return mav;
}
}
组合注解
· @GetMapping:匹配GET方式的请求。
· @PostMapping:匹配POST方式的请求。
· @PutMapping:匹配PUT方式的请求。
· @DeleteMapping:匹配DELETE方式的请求。
· @PatchMapping:匹配PATCH方式的请求。
以@GetMapping为例,该组合注解是@RequestMapping(method =RequestMethod.GET)的缩写,它会将HTTP GET映射到特定的处理方法上
而使用新注解@GetMapping后,可以省略method属性。
@GetMapping(value="/user/{id}")
public String selectUserById(String id){
...
}
请求处理方法的参数类型和返回类型
在控制器类中,每一个请求处理方法都可以有多个不同类型的参数,以及一个多种类型的返回结果。例如在入门案例中,handleRequest()方法的参数就是对应请求的HttpServletRequest和HttpServletResponse两种参数类型。除此之外,还可以使用其他的参数类型,例如在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确地传递给方法,其使用示例如下。
@RequestMapping(value="/firstController") public ModelAndView (HttpSession session){
... return mav;
}
需要注意的是,org.springframework.ui.Model类型不是一个Servlet API类型,而是一个包含了Map对象的Spring MVC类型。如果方法中添加了Model参数,则每次调用该请求处理方法时,Spring MVC都会创建Model对象,并将其作为参数传递给方法。
在上述所列举的返回类型中,常见的返回类型是ModelAndView、String和void。其中ModelAndView类型中可以添加Model数据,并指定视图;String类型的返回值可以跳转视图,但不能携带数据;而void类型主要在异步请求时使用,它只返回数据,而不会跳转视图。
由于ModelAndView类型未能实现数据与视图之间的解耦,所以在企业开发时,方法的返回类型通常都会使用String。既然String类型的返回值不能携带数据,那么在方法中是如何将数据带入视图页面的呢?这就用到了上面所讲解的Model参数类型,通过该参数类型,即可添加需要在视图中显示的属性。
返回String类型方法的示例代码如下。
@RequestMapping(value="/firstController")
public String handleRequest(HttpServletRequest request, HttpServletResponse response, Model model) {
// 向模型对象中添加数据
model.addAttribute("msg", "这是我的第一个Spring MVC程序");
// 返回视图页面
return "/WEB-INF/jsp/first.jsp";
}
ViewResolver(视图解析器)
Spring MVC中的视图解析器负责解析视图,可以通过在配置文件中定义一个ViewResolver来配置视图解析器,其配置示例如下。
在上述代码中,定义了一个id为viewResolver的视图解析器,并设置了视图的前缀和后缀属性。这样设置后,方法中所定义的view路径将可以简化。例如,入门案例中的逻辑视图名只需设置为"first",而不再需要设置为"/WEB-INF/jsp/first.jsp",在访问时视图解析器会自动地增加前缀和后缀。
5.数据绑定
在执行程序时,Spring MVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中。这种将请求消息数据与后台方法参数建立连接的过程就是Spring MVC中的数据绑定。
在数据绑定过程中,Spring MVC框架会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数了。整个数据绑定的过程如图13-1所示。
绑定默认数据类型
常用的默认参数类型如下。
· HttpServletRequest:通过request对象获取请求信息。
· HttpServletResponse:通过response处理响应信息。
· HttpSession:通过session对象得到session中存储的对象。
· Model/ModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域。
以HttpServletRequest举例——
以注解的形式定义一个Controller,在参数中使用HttpServletRequest,则可以取得Get请求的参数。
@Controller
public class UserController {
@RequestMapping("/selectUser")
public String selectUser(HttpServletRequest request) {
String id = request.getParameter("id");
System.out.println("id="+id);
return "success";
}
}
绑定简单数据类型
参数不用HttpServletRequest参数,而使用简单数据类型如int、String、Double等类型,一样可以取得Get请求的参数。
@RequestMapping("/selectUser")
public String selectUser(Integer id) {
System.out.println("id="+id); return "success";
}
需要注意的是,有时候前端请求中参数名和后台控制器类方法中的形参名不一样,这就会导致后台无法正确绑定并接收到前端请求的参数。为此,Spring MVC提供了@RequestParam注解来进行间接数据绑定。
http://localhost:8080/chapter13/selectUser?user_id=1
@RequestMapping("/selectUser")
public String selectUser(@RequestParam(value="user_id")Integer id) {
System.out.println("id="+id);
return "success";
}
绑定POJO类型
定义POJO,前端请求的参数名(本例中指form表单内各元素的name属性值)必须与要绑定的POJO类中的属性名一样,这样才会自动将请求数据绑定到POJO对象中,否则后台接收的参数值为null.
配置编码过滤器防止请求乱码。
为了防止前端传入的中文数据出现乱码问题,我们可以使用Spring提供的编码过滤器来统一编码。要使用编码过滤器,只需要在web.xml中添加如下代码。
CharacterEncodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
CharacterEncodingFilter
/*
绑定包装POJO
所谓的包装POJO,就是在一个POJO中包含另一个简单POJO。例如,在订单对象中包含用户对象。这样在使用时,就可以通过订单查询到用户信息。
在使用包装POJO类型数据绑定时,前端请求的参数名编写必须符合以下两种情况。
① 如果查询条件参数是包装类的直接基本属性,则参数名直接用对应的属性名,如上面代码中的ordersId。
② 如果查询条件参数是包装类中POJO的子属性,则参数名必须为【对象.属性】,其中【对象】要和包装POJO中的对象属性名称一致,【属性】要和包装POJO中的对象子属性一致,如上述代码中的user.username。
自定义数据绑定
在一般情况下,使用基本数据类型和POJO类型的参数数据已经能够满足需求,然而有些特殊类型的参数是无法在后台进行直接转换的,例如日期数据就需要开发者自定义转换器(Converter)或格式化(Formatter)来进行数据绑定。
除了使用Converter进行转换外,我们还可以使用Formatter来进行类型转换。Formatter与Converter的作用相同,只是Formatter的源类型必须是一个String类型,而Converter可以是任意类型。
复杂数据绑定
绑定数组
前端的列表定义好name属性,name属性和请求的参数要相等,则可以在请求中绑定数组类型。
绑定集合
在使用集合数据绑定时,后台方法中不支持直接使用集合形参进行数据绑定,所以需要使用包装POJO作为形参,然后在包装POJO中包装一个集合属性
汉滨县河小乡镇有大能量县河美地,青山环抱,清溪缓流。夏日,这里的游客络绎不绝,有竹排戏水有美味辣子鸡有红色印记牛蹄岭。干群有目共睹,县河镇各项事业蒸蒸而上蓬勃发展,无处不渗透着大与小这种最简单也最复杂的
糖尿病患者食用植物油是否可以不用限量?可以敞开吃?吃动物油不好,植物油是不是可以多吃一些呢?尤其是橄榄油等优质的植物油,是不是可以不限量,敞开了吃。最近,在我的评论区经常能碰到糖友们问这类问题。其实不然,无论是植物油还是动物油,在
黑科技频现中国移动元宇宙比特景观亮相MWC20232023世界移动通信大会(MWC)正在巴塞罗那如火如荼地进行,科技创新成果不断涌现。中国移动董事长杨杰首次以比特数智人的方式参加大会,并依托于中国移动5G算力网络实时渲染等超前数智
中国造船如何真正成为世界第一造船界曾流行这么一句话想要更多订单,就来中国船厂,要想入行赚钱,请到隔壁韩国去。衡量一个国家的造船规模和实力,常用到三大造船指标造船完工量新接订单量手持订单量。2010年,以载重吨
走进区域看发展四川省首个空港型综合保税区下月完工来源红星新闻网成都天府国际机场如一扇大门,开启人流资金信息的高速流动,将推动地区产业升级和经济发展。2月27日,走进区域看发展川渝奋楫谱新篇网上主题宣传采访团来到成都天府国际空港综
继续干,继续冲从今天的盘面看,A股跌多涨少,大多数跌幅在百分之3内,而且今天的北上资金流出了19亿多,可以看出美联储的加息的影响还是在可控内。两会快召开了,目前大盘应该会维稳为主。还是维持推荐原
关于人工智能,半年前曾让半个投资圈惊出一身冷汗的往事丨行业观察文Ben编辑石亚琼2022年7月12日一早,不少投资人被朋友圈刷屏的一段视频惊出了一身冷汗,视频是一段面试过程,面试对象是前一天刚刚在红杉中国低调上岗的数字虚拟员工Hng。Hng应
全国人大代表钟铮建议支持新型储能发展完善容量电费机制北京问答全国人大代表美的集团副总裁兼CFO钟铮将在今年两会提出六项建议,其中包括支持新型储能产业高质量发展的建议。钟铮2月28日向第一财经记者表示,完善新型储能产业的容量电费政策辅助服务机
兵分7路发起总攻,普京欲建新秩序,中国也对美霸权发起抨击俄军兵分7路发起总攻,美西方已经有专家警告,俄罗斯不会接受失败。俄乌冲突的后果正逐渐显现,全球新秩序或许在普京的主导下实现,中国也有了新动作。据相关媒体人27日透露,日前,俄军方面
不代言日本品牌,不用日本货不去日本,这8位中国明星痛怼日本人任何一个中国人提起日本,都会燃起爱国情怀。毕竟曾经那段惨痛屈辱的历史值得每个中国人铭记,而有些明星更是用自己的实际行动表达了自己的爱国,让日本人恨的咬牙切齿。他们都是谁呢,今天我们
中国球迷的至暗时刻中国足球是真的没人了!!!75到80初是中国足球百年辉煌的高峰在我的记忆中,97国家队应该是历史最强的,可惜带队的是我只负自己该负的责任的戚务生中国足球曾经在亚洲足坛是耀眼的存在,当时范志毅时候那支国家队搁