Spring框架学习第五天
1。SpringMVC具有如下特点。
是Spring框架的一部分,可以方便地利用Spring所提供的其他功能。
灵活性强,易于与其他框架集成。
提供了一个前端控制器DispatcherServlet,使开发人员无须额外开发控制器对象。
可自动绑定用户输入,并能正确的转换数据类型。
内置了常见的校验器,可以校验用户输入。如果校验不能通过,那么就会重定向到输入表单。
支持国际化。可以根据用户区域显示多国语言。
支持多种视图技术。它支持JSP、Velocity和FreeMarker等视图技术。
使用基于XML的配置文件,在编辑后,不需要重新编译应用程序。
实现如下
1。项目结构
2配置前端控制器
在web。xml中,配置SpringMVC的前端控制器DispatcherServlet。
lt;?xmlversion1。0encodingUTF8?
webappxmlns:xsihttp:www。w3。org2001XMLSchemainstance
xmlnshttp:java。sun。comxmlnsjavaee
xsi:schemaLocationhttp:java。sun。comxmlnsjavaee
http:java。sun。comxmlnsjavaeewebapp30。xsd
idWebAppIDversion3。0
springmvc
org。springframework。web。servlet。DispatcherServlet
contextConfigLocation
classpath:springmvcconfig。xml
initparam
1hrservlet
springmvc
servletmapping
webapp
3。创建Controller类
packagecom。itheima。controller;
importjavax。servlet。http。HttpServletRequest;
importjavax。servlet。http。HttpServletResponse;
importorg。springframework。web。servlet。ModelAndView;
importorg。springframework。web。servlet。mvc。Controller;
控制器类
publicclassFirstControllerimplementsController{
Override
publicModelAndViewhandleRequest(HttpServletRequestrequest,HttpServletResponseresponse){
创建ModelAndView对象
ModelAndViewmavnewModelAndView();
向模型对象中添加数据
mav。addObject(msg,这是我的第一个SpringMVC程序);
设置逻辑视图名
mav。setViewName(WEBINFjspfirst。jsp);
返回ModelAndView对象
returnmav;
}
}
handleRequest()是Controller接口的实现方法,FirstController类会调用该方法来处理请求,并返回一个包含视图名或包含视图名和模型的ModelAndView对象。本案例中,向模型对象中添加了一个名称为msg的字符串对象,并设置返回的视图路径为WEBINFjspfirst。jsp,这样,请求就会被转发到first。jsp页面
4。创建SpringMVC的配置文件,配置控制器映射信息
lt;?xmlversion1。0encodingUTF8?
beansxmlnshttp:www。springframework。orgschemabeans
xmlns:xsihttp:www。w3。org2001XMLSchemainstance
xsi:schemaLocationhttp:www。springframework。orgschemabeans
http:www。springframework。orgschemabeansspringbeans4。3。xsd
beannamefirstController
classcom。itheima。controller。FirstController
bean
classorg。springframework。web。servlet。handler。BeanNameUrlHandlerMapping
bean
classorg。springframework。web。servlet。mvc。SimpleControllerHandlerAdapter
bean
classorg。springframework。web。servlet。view。InternalResourceViewResolver
beans
首先定义了一个名称为firstController的Bean,该Bean会将控制器类FirstController映射到firstController请求中;然后配置了处理器映射器BeanNameUrlHandlerMapping和处理器适配器SimpleControllerHandlerAdapter,其中处理器映射器用于将处理器Bean中的的name(即url)进行处理器查找,而处理器适配器用于完成对FirstController处理器中handleRequest()方法的调用。最后配置了视图解析器InternalResourceViewResolver来解析结果视图,并将结果呈现给用户。
5。创建视图(View)页面
在WEBINF目录下,创建一个jsp文件夹,并在文件夹中创建一个页面文件first。jsp
6。启动项目即可。
2。SpringMVC的工作流程
SpringMVC程序的完整执行流程如下。
(1)用户通过浏览器向服务器发送请求,请求会被SpringMVC的前端控制器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。了解SpringMVC核心类的作用
DispatcherServlet
DispatcherServlet的全名是org。springframework。web。servlet。DispatcherServlet,它在程序中充当着前端控制器的角色。在使用时,只需将其配置在项目的web。xml文件中,其配置代码如下。
springmvc
org。springframework。web。servlet。DispatcherServlet
contextConfigLocationclasspath:springmvcconfig。xml
initparam
1hrservlet
springmvc
servletmapping
4。掌握SpringMVC常用注解的使用
在上述代码中,元素和元素都是可选的。如果元素的值为1,则在应用程序启动时会立即加载该Servlet;如果元素不存在,则应用程序会在第一个Servlet请求时加载该Servlet。如果元素存在并且通过其子元素配置了SpringMVC配置文件的路径,则应用程序在启动时会加载配置路径下的配置文件;如果没有通过元素配置,则应用程序会默认到WEBINF目录下寻找如下方式命名的配置文件。
servletNameservlet。xml
其中,servletName指的是部署在web。xml中的DispatcherServlet的名称,在上面web。xml中的配置代码中即为springmvc,而servlet。xml是配置文件名的固定写法,所以应用程序会在WEBINF下寻找springmvcservlet。xml。
Controller注解类型
org。springframework。stereotype。Controller注解类型用于指示Spring类的实例是一个控制器,其注解形式为Controller。该注解在使用时不需要再实现Controller接口,只需要将Controller注解加入到控制器类上,然后通过Spring的扫描机制找到标注了该注解的控制器即可。
Controller注解在控制器类中的使用示例如下。
packagecom。itheima。controller;
importorg。springframework。stereotype。Controller;
。。。
Controller
publicclassFirstController{
。
}
为了保证Spring能够找到控制器类,还需要在SpringMVC的配置文件中添加相应的扫描配置信息,具体如下。
(1)在配置文件的声明中引入springcontext。
(2)使用元素指定需要扫描的类包。
lt;?xmlversion1。0encodingUTF8?
beansxmlnshttp:www。springframework。orgschemabeans
xmlns:xsihttp:www。w3。org2001XMLSchemainstance
xmlns:contexthttp:www。springframework。orgschemacontext
xsi:schemaLocationhttp:www。springframework。orgschemabeans
http:www。springframework。orgschemabeansspringbeans4。3。xsd
http:www。springframework。orgschemacontext
http:www。springframework。orgschemacontextspringcontext4。3。xsd
beans
元素的属性basepackage指定了需要扫描的类包为com。itheima。controller。在运行时,该类包及其子包下所有标注了注解的类都会被Spring所处理。
与实现了Controller接口的方式相比,使用注解的方式显然更加简单。同时,Controller接口的实现类只能处理一个单一的请求动作,而基于注解的控制器可以同时处理多个请求动作,在使用上更加的灵活。因此,在实际开发中通常都会使用基于注解的形式。
使用注解方式时,程序的运行需要依赖Spring的AOP包,因此需要向lib目录中添加springaop4。3。6。RELEASE。jar,否则程序运行时会报错。
RequestMapping注解的使用
Spring通过Controller注解找到相应的控制器类后,还需要知道控制器内部对每一个请求是如何处理的,这就需要使用org。springframework。web。bind。annotation。RequestMapping注解类型。RequestMapping注解类型用于映射一个请求或一个方法,其注解形式为RequestMapping,可以使用该注解标注在一个方法或一个类上。
1标注在方法上
当标注在一个方法上时,该方法将成为一个请求处理方法,它会在程序接收到对应的URL请求时被调用。使用RequestMapping注解标注在方法上的示例如下。
packagecom。itheima。controller;
importorg。springframework。stereotype。Controller;
importorg。springframework。web。bind。annotation。RequestMapping;
。。。
Controller
publicclassFirstController{
RequestMapping(valuefirstController)
publicModelAndViewhandleRequest(HttpServletRequestrequest,HttpServletResponseresponse){
。。。returnmav;
}
}
2标注在类上
当标注在一个类上时,该类中的所有方法都将映射为相对于类级别的请求,表示该控制器所处理的所有请求都被映射到value属性值所指定的路径下。
packagecom。itheima。controller;
importorg。springframework。stereotype。Controller;
importorg。springframework。web。bind。annotation。RequestMapping;。。。
Controller
RequestMapping(valuehello)
publicclassFirstController{
RequestMapping(valuefirstController)
publicModelAndViewhandleRequest(HttpServletRequestrequest,HttpServletResponseresponse){。。。
returnmav;
}
}
组合注解
GetMapping:匹配GET方式的请求。
PostMapping:匹配POST方式的请求。
PutMapping:匹配PUT方式的请求。
DeleteMapping:匹配DELETE方式的请求。
PatchMapping:匹配PATCH方式的请求。
以GetMapping为例,该组合注解是RequestMapping(methodRequestMethod。GET)的缩写,它会将HTTPGET映射到特定的处理方法上
而使用新注解GetMapping后,可以省略method属性。
GetMapping(valueuser{id})
publicStringselectUserById(Stringid){
。。。
}
请求处理方法的参数类型和返回类型
在控制器类中,每一个请求处理方法都可以有多个不同类型的参数,以及一个多种类型的返回结果。例如在入门案例中,handleRequest()方法的参数就是对应请求的HttpServletRequest和HttpServletResponse两种参数类型。除此之外,还可以使用其他的参数类型,例如在请求处理方法中需要访问HttpSession对象,则可以添加HttpSession作为参数,Spring会将对象正确地传递给方法,其使用示例如下。
RequestMapping(valuefirstController)publicModelAndView(HttpSessionsession){
。。。returnmav;
}
需要注意的是,org。springframework。ui。Model类型不是一个ServletAPI类型,而是一个包含了Map对象的SpringMVC类型。如果方法中添加了Model参数,则每次调用该请求处理方法时,SpringMVC都会创建Model对象,并将其作为参数传递给方法。
在上述所列举的返回类型中,常见的返回类型是ModelAndView、String和void。其中ModelAndView类型中可以添加Model数据,并指定视图;String类型的返回值可以跳转视图,但不能携带数据;而void类型主要在异步请求时使用,它只返回数据,而不会跳转视图。
由于ModelAndView类型未能实现数据与视图之间的解耦,所以在企业开发时,方法的返回类型通常都会使用String。既然String类型的返回值不能携带数据,那么在方法中是如何将数据带入视图页面的呢?这就用到了上面所讲解的Model参数类型,通过该参数类型,即可添加需要在视图中显示的属性。
返回String类型方法的示例代码如下。
RequestMapping(valuefirstController)
publicStringhandleRequest(HttpServletRequestrequest,HttpServletResponseresponse,Modelmodel){
向模型对象中添加数据
model。addAttribute(msg,这是我的第一个SpringMVC程序);
返回视图页面
returnWEBINFjspfirst。jsp;
}
ViewResolver(视图解析器)
SpringMVC中的视图解析器负责解析视图,可以通过在配置文件中定义一个ViewResolver来配置视图解析器,其配置示例如下。
bean
在上述代码中,定义了一个id为viewResolver的视图解析器,并设置了视图的前缀和后缀属性。这样设置后,方法中所定义的view路径将可以简化。例如,入门案例中的逻辑视图名只需设置为first,而不再需要设置为WEBINFjspfirst。jsp,在访问时视图解析器会自动地增加前缀和后缀。
5。数据绑定
在执行程序时,SpringMVC会根据客户端请求参数的不同,将请求消息中的信息以一定的方式转换并绑定到控制器类的方法参数中。这种将请求消息数据与后台方法参数建立连接的过程就是SpringMVC中的数据绑定。
在数据绑定过程中,SpringMVC框架会通过数据绑定组件(DataBinder)将请求参数串的内容进行类型转换,然后将转换后的值赋给控制器类中方法的形参,这样后台方法就可以正确绑定并获取客户端请求携带的参数了。整个数据绑定的过程如图131所示。
绑定默认数据类型
常用的默认参数类型如下。
HttpServletRequest:通过request对象获取请求信息。
HttpServletResponse:通过response处理响应信息。
HttpSession:通过session对象得到session中存储的对象。
ModelModelMap:Model是一个接口,ModelMap是一个接口实现,作用是将model数据填充到request域。
以HttpServletRequest举例
以注解的形式定义一个Controller,在参数中使用HttpServletRequest,则可以取得Get请求的参数。
Controller
publicclassUserController{
RequestMapping(selectUser)
publicStringselectUser(HttpServletRequestrequest){
Stringidrequest。getParameter(id);
System。out。println(idid);
returnsuccess;
}
}
绑定简单数据类型
参数不用HttpServletRequest参数,而使用简单数据类型如int、String、Double等类型,一样可以取得Get请求的参数。
RequestMapping(selectUser)
publicStringselectUser(Integerid){
System。out。println(idid);returnsuccess;
}
需要注意的是,有时候前端请求中参数名和后台控制器类方法中的形参名不一样,这就会导致后台无法正确绑定并接收到前端请求的参数。为此,SpringMVC提供了RequestParam注解来进行间接数据绑定。
http:localhost:8080chapter13selectUser?userid1
RequestMapping(selectUser)
publicStringselectUser(RequestParam(valueuserid)Integerid){
System。out。println(idid);
returnsuccess;
}
绑定POJO类型
定义POJO,前端请求的参数名(本例中指form表单内各元素的name属性值)必须与要绑定的POJO类中的属性名一样,这样才会自动将请求数据绑定到POJO对象中,否则后台接收的参数值为null。
配置编码过滤器防止请求乱码。
为了防止前端传入的中文数据出现乱码问题,我们可以使用Spring提供的编码过滤器来统一编码。要使用编码过滤器,只需要在web。xml中添加如下代码。
CharacterEncodingFilter
org。springframework。web。filter。CharacterEncodingFilter
encoding
UTF8
initparam
filter
CharacterEncodingFilter
filtermapping
绑定包装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中包装一个集合属性