1. SpringMVC介绍
1.1. SpringMVC是什么
SpringMVC是Spring组织下的一个表现层框架。和Struts2一样。它是Spring框架组织下的一部分。我们可以从Spring的整体结构中看得出来:
1.2. SpringMVC的作用
- 接收Web请求中的参数
- 把处理好的数据返回给页面
1.3. 为什么要学习SpringMVC
技术是要更新换代的,可以说Springmvc是对Struts2的技术更新,Struts2太老了,许多设计已经过时,效率不符合现在业务(互联网)的需要,而且SpringMVC与Spring是一家的,它们之间的衔接是无缝的,所以使用SpringMVC更方便和Spring进行整合。
更重要的一点是Struts2存在安全漏洞(比如...),之前的某些版本曾经造成过一些企业的损失,这也加速了Struts2的迅速老去。
那为什么之前还要学习Struts2呢?是因为今后工作中不一定都是从事新的系统开发,你有可能去维护一个已经上线的老系统,比如许多传统行业里面应用的系统Struts2的使用率仍然不小,因此从学习的角度Struts2也要学习掌握。
1.4. 了解SpringMVC的处理流程
要想引入SpringMVC做表现层开发,最基本的需要完成两件事:
1. 配置好前端控制器DispatcherServlet。
2. 开发后端控制器并在SpringMVC的配置文件中加入企业级的配置。
后端控制器一般需要开发人员去写代码处理业务逻辑以及操作数据库的地方...
2. SpringMVC环境搭建及入门程序
2.1. 软件环境
Jdk:jdk1.7.0_72
Eclipse:mars
Tomcat:apache-tomcat-7.0.53
Springmvc:4.1.3
说明:
在实际项目中团队的开发版本是有严格要求的,最新版本不代表是最好的,实际项目都选用最稳定的版本。
2.2. 环境搭建
2.2.1. 第一步:创建一个java web工程(UTF-8)并导入jar包
- 1. 创建一个java web工程
- 2. 导入jar包
在web工程中拷贝到lib文件夹下的jar包可以自动被导入工程
spring原生jar包:
Spring常用依赖jar包:
2.2.2. 第二步:配置前端控制器
【web.xml】配置文件是整个web请求的入口配置文件
<说明>
·前端控制器:
org.springframework.web.servlet.DispatcherServlet,它是SpringMVC接收web请求的第一入口,也是唯一入口。这是一个servlet对象,因此需要在web.xml中进行配置。
·<load-on-startup>标签:此项配置是控制当前servlet是否随tomcat启动而被加载
配置的值必须是整数
值 >= 0:表示当前servlet随着tomcat启动而被加载,值的大小表示加载的顺序,越小越优先
值 < 0:表示当前servlet不会随着tomcat启动而被加载,只有当它被使用的时候才加载。
DispatcherServlet启动后会立刻去找SpringMVC的配置文件,然后根据配置文件中的内容进行加载和扫描
·<init-param>标签:
用这个标签加载SpringMVC配置文件,意义就是在DispatcherServlet的初始化过程中加载SpringMVC的配置文件
<param-name>为【contextConfigLocation】
<param-value>为【classpath:SpringMVC配置文件的类的根目录下的相对路径】
·SpringMVC默认配置文件:
如果没有显示的配置SpringMVC的核心配置文件,SpringMVC会去[/WEB-INF/]下找默认的核心配置文件。默认核心配置文件的命名:servlet-name的值 + -servlet.xml。在实际工作中要知道:当发现web.xml没有配置核心配置文件时要知道去[/WEB-INF/]下找它的默认配置文件。
因为各种框架的默认配置文件的位置可能不同,所以企业很少采用默认的配置文件路径,因此我们需要统一规划配置文件的存放位置,通过手动配置完成配置文件的加载。
·常用URL样式:
[/*]: SpringMvc禁止使用,不支持。
[*.action]: 以.action为结尾的url地址请求可以进入DispatcherServlet, 不是以.action结尾的url请求,则放行所有资源文件后缀的url。
[/]: 所有url地址请求均可进入DispatcherServlet, 但只放行以.jsp为结尾的url,其他资源文件后缀的url都不放行(这个明天的RESTful的时候会具体用到, 今天先不讲)
资源文件请求url:
<link href="<%=basePath%>css/bootstrap.min.css" rel="stylesheet">
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>springmvc</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置springmvc前端控制器 --> <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> <!-- 配置DispacherServlet随tomcat启动而被加载 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 配置什么样的url路径可以进入DispatcherServlet --> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app> |
2.2.3. 第三步:创建springmvc核心配置文件
新建一个source folder: config
在config下创建一个xml文件: 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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> </beans> |
2.2.4. 第四步:启动tomcat测试环境
到此为止SpringMvc基本框架搭建完成,启动tomcat,日志中不报错,就说明环境搭建成功。
下面就是入门程序的开发。
2.3. 案例需求
2.3.1. 需求
使用SpringMVC实现商品列表的展示。
2.3.2. 需求分析
- 要展示全部商品列表,所以不需要参数,请求url: http://localhost:8080/<具体web应用的名字>/list.action
- 主要关注SpringMvc的入门程序,所以暂不考虑连接数据库等多余功能,在业务处理中只做假的模拟数据返回给页面。
2.4. 入门程序
2.4.1. 第一步:创建jsp页面
创建jsp页面的目录:
前端页面不是本课内容,参考: 参考资料\参考案例\jsp\itemList.jsp直接拷贝到工程jsp目录中。
问题:放在WebContent目录下和放到WEB-INFO目录下的区别?
WEB-INFO是受tomcat保护目录,它里面的文件只能由servlet去访问,不能通过url地址栏去请求访问。
WebContent下的文件可以直接通过url地址栏去访问,一般的欢迎页和静态资源文件都放在这里。
2.4.2. 第二步:创建和配置后端控制器(开发人员编写的控制器类)
创建包:
cn.itcast.controller用于存放后端控制器,cn.itcast.pojo用于存放保存返回数据的bean
创建后端控制器类:
<说明>
·@Controller:表明用这个注解修饰的类需要SpringMVC扫描成SpringMVC的组件(bean)。
|
package cn.itcast.controller; import org.springframework.stereotype.Controller; // 定义一个java类,@Controller注解标注在类定义的上方表明这个类需要SpringMVC扫描。 @Controller public class ItemsController { } |
在SpringMvc.xml中配置后端控制器类的扫描
<说明>
<context:component-scan base-package="要扫描的包路径" />
扫描指定包及子包下的@Controller、@Service、@Repository等注解修饰的java类。
他们三个都是@Conponent的子类注解
其中在SpringMVC配置文件中只扫描@Controller修饰的类所在的包,并将这些类注册为SpringMVC的组件。
其它注解修饰的类在Spring配置文件中配置注解扫描,并将扫描的注解下的类注册为Spring的组件。
|
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置SpringMVC下Controller类的扫描 --> <context:component-scan base-package="cn.itcast.controller" /> </beans> |
注意:
如果想扫描多个包,可以配置多个<context:component-scan base-package="指定的包名" />
2.4.3. 第三步:编写方法响应url请求
注解类型的Controller类中使用@RequestMapping注解修饰的方法响应url请求。一个url对应一个方法。不可能多个url同时对应一个方法,也不可能多个方法同时响应一个url请求。
<说明>
·@RequestMapping(“具体URL”):
指明这个方法响应的具体url是什么。这里面配置的url是工程名后的具体url,以【/】开头,如果不写【/】也可以,推荐写。
@RequestMapping(“具体URL”)和它修饰的方法就形成一对key/value,key就是URL,value就是由注解修饰的方法,它被包装在handler对象中(handler是SpringMVC内置的专门用来封装url请求响应方法的对象),最终再把这些key/value放到一个map对象中保存。
·Model:
模型对象,是SpringMVC默认支持的一种形参类型,
作用:负责将返回给页面的数据传递(赋值)给request对象(这个赋值的过程是SpringMVC底层做的,将我们开发人员自己赋给Model对象的属性名和值赋给request对象,这个详细过程不需要我们掌握它的详细逻辑,理解一下即可。)
这样JSP就可以用EL表达式从request对象中取得这个属性名所对应的数据了。
·记住:对于jsp永远都是从request对象中通过属性名取值。
|
package cn.itcast.controller; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import cn.itcast.pojo.Items; // 定义一个java类,@Controller注解标注在类定义的上方表明这个类需要SpringMVC扫描。 @Controller public class ItemsController { // 标注url到请求方法的key/value对应关系 @RequestMapping("/list") public String list(Model model) throws Exception { //商品列表(临时数据) List<Items> itemsList = new ArrayList<Items>(); Items items1 = new Items(); items1.setName("联想笔记本"); items1.setPrice(6000f); items1.setDetail("ThinkPad T430 联想笔记本电脑!"); Items items2 = new Items(); items2.setName("苹果手机"); items2.setPrice(5000f); items2.setDetail("iphone6苹果手机!"); itemsList.add(items1); itemsList.add(items2); // 1. 设置返回给页面的数据 // 第一个参数是属性名称, 第二个参数是属性值 model.addAttribute("itemsList", itemsList); // 2. 指定返回页面的地址 return "/WEB-INF/jsp/itemList.jsp"; } } |
返回的页面是否存在、是否正确都需要先判断一下,在SpringMVC中使用一个视图解析器的组件来做这些处理。
配置视图解析器:在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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置指定包下的组件扫描 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> </bean> </beans> |
|
2.4.4. 第四步:启动tomcat测试
访问地址: http://localhost:8080/springmvc/list.action
2.4.5. 第五步:优化方法的返回路径
上面直接返回jsp的路径倒是很直接,但是每个方法都返回一长串路径看着有点乱,而且每个方法返回的路径中【/WEB-INF/jsp/】和【.jsp】都是重复的,未免显得有些冗余。
能否将这些重复的部分提取出来放到SpringMVC的配置文件中呢?答案是肯定的——修改视图解析器的配置:
【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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置指定包下的组件扫描 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> |
|
说明:
- 作用:
用视图解析器中配置的前缀和后缀简化Controller类中的编码
2.代码的简化:
|
······ // 2. 指定返回页面的地址 return "itemList"; ······ |
3.逻辑视图名与视图文件物理路径
简化后Controller方法中返回的字符串叫做逻辑视图名。
视图文件物理路径=前缀 + 逻辑视图名 + 后缀。
SpringMVC能保证每次返回的字符串都会自动走视图解析器,然后按照上面的方式拼接,再进行后续处理。
2.5. 本节总结
本单元内容主要是搭建了一个SpringMVC开发环境并学习了它的入门程序。
这个开发环境只有SpringMVC,所以不是我们正式的环境,了解即可,不重要。
入门程序中学习到的两个注解@Controller和@RequestMapping用法以及返回数据和返回页面的处理方式要掌握。
3. SpringMVC框架
3.1. 框架结构(重点)
- 学习框架结构的目的: 开发不用, 但面试时会问到
- 框架结构详细内容:(面试题)
说明:前端控制器是接收web请求的入口,地位最重要。如果还要做其他具体的工作会使它的负担过于繁重,因此SpringMVC找来了四个帮手,叫做四个组件,来帮助前端控制器承担一些具体的工作,这样前端控制器就只发号司令做为集中控制调度中心,具体的工作交给四个组件来完成。
具体工作分为两部分:
- 处理请求:两个组件,一个来找Handler,一个来执行Handler
1) 处理器映射器负责找到URL对应的Handler对象
2) 处理器适配器负责执行找到的Handler对象。
2.返回结果:两个组件,一个来找页面,一个来执行页面渲染
1) 视图解析器负责找到要返回的页面
2) 视图对象负责渲染页面,渲染页面需要的数据由前端控制器传给它。
●啥是freemaker?
就是模版, 通过模版和数据生成输出的文本(HTML网页, 电子邮件等). 比如网易首页点击进入的一个html页面, 这些静态的html都是由freemarker生成的, 而struts2只支持jsp.
3.2. 框架流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
- 执行处理器(handler也叫后端控制器-->Service-->DAO)
- Handler执行完成返回ModelAndView
- HandlerAdapter将handler执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover根据handler中设置的页面信息解析成一个View视图对象并返回它.
10. DispatcherServlet调用View对象的接口方法对实际的视图文件(如: jsp文件)进行渲染(即将模型数据填充至视图文件中)
11. DispatcherServlet响应用户
3.3. 需要认识的SpringMVC组件
SpringMVC的整个控制层采用组件式的结构。
SpringMVC的组件有:
前端控制器DispatcherServlet、
处理器Handler(相对于前端控制器的后端控制器)、
处理器映射器HandlerMapping、
处理器适配器HandlerAdapter、
视图对象View、
视图解析器ViewResolver。
其中HandlerMapping、HandlerAdapter、ViewResolver是springmvc的三大核心组件,Handler涉及具体业务需要程序员实现,View由ViewResolver生成,负责渲染页面。
三大组件干的事情其实都可以集中交给DispatcherServlet来干,但都交给它会使它过于臃肿,处理效率会大大降低,因此分而治之才是上策。
3.3.1. DispatcherServlet:前端控制器
DispatcherServlet负责接收用户请求,是整个流程的控制中心,但它几乎不做任何具体的工作,只进行任务调度。具体的工作由具体的组件来完成。这就是组件式结构的优势,专项事情又专门的组件来做,这样能提高专项的处理能力同时集中调度的存在降低了组件之间的耦合性。
3.3.2. Handler:处理器
在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。
3.3.3. HandlerMapping: 处理器映射器
HandlerMapping负责为每个请求找到一个合适的处理器handler,其实简单来说就是维持了一个url到handler的映射Map。springmvc提供了不同的映射器,实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
比如注解方式的映射器会根据核心配置文件中配置的<context:component-scan base-package="包路径" />指定的包路径(包括子目录)进行扫描,找@Controller标注的Java类,该类中所有使用@RequestMapping修饰的方法都是一个handler对象,并根据@RequestMapping的值作为key,对应的方法的handler对象作为value,形成一个url到方法的k/v键值对映射。而且这种扫描只要在tomcat启动时做一次,不会影响系统的性能。
3.3.4. HandlerAdapter: 处理器适配器
- 什么是适配器:
2.适配器的作用:统一调用接口,好扩展。
3.Springmvc中的处理器适配器:
处理器适配器HandlerAdapter负责执行具体的处理器。
SpringMVC有多个适配器,当HandlerMapping找到了url对应的handler对象后,前端控制器会挑选一个能够执行这个handler的处理器适配器,然后给这个适配器发送指令,同时把这个handler对象传给这个适配器,让它执行handler,最终将handler的返回值和逻辑视图名字符串返回给前端控制器。
3.3.5. ViewResolver: 视图解析器
视图解析器(ViewResolver)负责解析出视图文件的物理路径,并根据这个路径生成视图View对象。
ViewResolver首先把逻辑视图名解析成实际的页面位置,再生成视图View对象并返回给前端控制器。
3.3.6. View:视图对象类型
- View视图对象
View对象负责渲染视图文件,将数据结果通过视图文件展示给用户。前端控制器调用View对象的接口方法render(),参数就是后台返回的数据,在render方法拿数据渲染视图文件生成返回给客户端的结果。
springmvc框架提供了很多的View类型,包括:jstlView、freemarkerView、pdfView等。
2.视图文件
视图文件可以是jsp、pdf、freemaker等,最常用的就是jsp。一般情况下需要通过页面jsp标签或页面模版将处理器返回的model数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
3.3.7. 组件总结
SpringMVC的三大组件(理解记忆):处理器映射器、处理器适配器、视图解析器
需要程序员编写代码的有:处理器(包括处理器、具体业务的service和dao)、视图文件(jsp)
3.4. SpringMvc三大组件的配置
Springmvc三大组件配置在核心配置文件中,springmvc支持组件免配置、显示配置和企业的配置方法
3.4.1. 组件的免配置
- 何为免配置:
即什么都不配。此时SpringMVC仍然可以正常运行,全凭它自己的DispatcherServlet.properties,会从中找到合适的组件去执行。这个属性文件的位置:
2.DispatcherServlet.properties的作用:
如果没有显示配置三大组件(其中一个或者全部),依靠这个属性文件中的默认配置组件,springmvc也能正确的执行。
3.上面的入门程序中自动选择的三大组件分别是:
a) 处理器映射器
b) 处理器适配器
c) 视图解析器
默认的视图解析器只有一个。
4.坏处:
每次请求都要去这里去找合适的组件,所以执行效率很低,因此什么都不配置是不可取的。需要我们显示配置来提高执行效率。
3.4.2. SpringMvc显式配置处理器映射器和处理器适配器
- 显式配置默认选择的处理器映射器和处理器适配器(旧版)
2.显式配置官方推荐的处理器映射器和处理器适配器(新版)
如果版本升级,会导致当前的版本也不是最新的
3.企业中的配置方法:注解驱动
作用:帮助我们去找并显式配置当前Spring版本的最新的注解形式的处理器映射器和处理器适配器
好处:简化配置,一劳永逸
4.面试题: springmvc是否要配置注解驱动和注解扫描? 有什么区别?
答:
都需要配置,两个东西的作用完全不一样,不要混淆视听。
注解驱动:作用就是替我们显式的配置当前spring版本下最新版本的注解形式的处理器映射器和处理器
适配器
注解扫描:扫描指定包及子包下的@Controller、@Service、@Repository等注解修饰的java类,其
中@Controller修饰的类注册为SpringMVC的组件(bean),其它注解修饰的类注册为Spring的组件(bean).
3.4.3. SpringMvc显式配置视图解析器
前面已经学过,此处只给出配置的例子。
3.4.4. 显示配置的意义
处理器映射器、适配器:提高执行效率
视图解析器(有前缀和后缀):简化编码
3.5. 本节重点
掌握:
SpringMVC的框架流程,能说出来从请求到返回页面的处理流程;
SpringMVC三大组件的最终形态的显示配置方法。
理解:
三大核心组件的功能。
了解:
Springmvc默认组件配置;
单独配置新版的处理器映射器和处理器适配器。
下面是完整的springmvc核心配置文件的配置: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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置指定包下的组件扫描 --> <!-- 作用:SpringMVC可以自动去扫描指定包以及子包下的java文件,如果扫描到有@Controller(控制层的类) @Service(业务层的类) @Repository(数据库访问层的类)这些注解修饰的类,则把这些类注册为 SpringMVC的组件 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 1. SpringMVC默认的三大组件选择(处理器映射器、处理器适配器、视图解析器) 如果没有显式地配置三大组件,SpringMVC也能正常执行,是因为会默认去找到SpringMVC的默认 属性文件DispatcherServlet.properties,从中找到合适的三大组件去执行。但这种方式在每次 请求的时候都会去找一遍,所以效率很低,因此采用默认的三大组件选择是不可取的。 我们应该显示的配置它们,这样可以提高系统的访问效率。 --> <!-- 2. 显示的配置处理器映射器和处理器适配器 --> <!-- 默认的注解形式的处理器映射器:老版本,不推荐使用 --> <!-- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> --> <!-- 默认的注解形式的处理器适配器:老版本,不推荐使用 --> <!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> --> <!-- 当前最新版本的注解形式的处理器映射器 --> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> --> <!-- 当前最新版本的注解形式的处理器适配器 --> <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> --> <!-- 3. 企业中配置注解形式的处理器映射器和处理器适配器的方法:注解驱动 --> <!-- 作用:显式地配置了当前Spring版本下最新的注解形式的处理器映射器和处理器适配器。由于它 没有和任何class关联,所以即使Spring版本升级,该项配置也不会发生任何改动,企业中 喜欢采用这种一劳永逸的方法。 --> <mvc:annotation-driven /> <!-- 配置视图解析器 --> <!-- 作用:利用显示配置视图解析器中的前缀和后缀可以简化Controller方法中的视图信息的设置,只需 在setViewName方法中设置逻辑视图名称(视图文件的名称,比如jsp文件)即可。每次视图解 析器都会自动的进行视图文件物理路径的拼接:前缀 + 逻辑视图名称 + 后缀。从而方便了我们的 编码工作。 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> |
4. SSM整合
4.1. SSM整合包含的框架
4.2. SSM整合思路
4.2.1. 整合思路的重要性
整合的步骤是固定的, 过程是可以复制的, 人家告诉我们怎么整合就怎么来做就可以了.
具体来说, 第一是你手头有现成的资料照着做即可; 第二如果你没有资料, 怎么办? 这时候如果能记住思路, 我们就可以上网去找资料. 但如果思路记不住就连资料怎么找都不知道了, 所以说思路是很重要的, 要记住.
4.2.2. 具体的整合思路(重点)
首先,先划分大层次,整合后分为三层:表现层 à 业务层 à 数据访问层,再加上web.xml这是整体的骨架;
其次,再逐层规划每一层具体要干什么。
ssm整合的思路如下:
Spring与MyBatis的整合在MyBatis第二天的时候已经学习过了,这里仍然沿用。SpringMVC与Spring又是一家的,所以它们之间是不需要整合配置的,即所谓的无缝整合,直接就可以用,只不过需要在web.xml中配置它们两个。具体规划如下:
SSM整合分三层:DAO层、Service层、Controller层
代码目录:
·DAO层:
pojo:pojo类
dao:映射文件、接口文件——Mybatis逆向工程自动生成,DAO通过SM整合jar包来扫描
·Service层:
service:service接口和实现类——利用@Service注解修饰,让spring来扫描(service目录)
·Controller层:
controller:Controller类及方法——利用@Controller注解修饰,让SpringMVC来扫描(controller目录)
配置目录:
·config:
MyBatisConfig.xml——MyBatis配置
ApplicationContext-dao.xml——数据源、连接池、会话工厂、mapper包扫描
ApplicationContext-service.xml——注解扫描(service层的组件扫描)、事务管理
(以上两个配置文件可以配置在一个文件中,这里为了体现分层的思路所以分开配置。)
SpringMVC.xml——注解扫描(Controller层的组件扫描)、注解驱动、视图解析器
web.xml
Spring监听(管理service层和dao层)、SpringMVC前端控制器(管理Controller层)
JSP:在【/WEB-INF/】创建jsp目录,存放jsp页面。
面试题:事务配置在哪一层?为什么?
事务配置在service层,因为service层控制的是业务,在一个service中有可能调用多个DAO中的方法进行一系列的操作,这些操作要么都成功,要么都失败。比如汇款,汇出操作成功了,但是存入给另一个人时发现卡被注销了,这个时候要整个业务回滚,否则钱就会丢失,所以必须在service层做事务控制。
注意:
不要纠结Controller层的类与Service层的类能否放到一个目录下。这个问题没有意义,因为分层的意思就是强制将它们分开,Controller层的目录就放Controller的类,Service层的目录就放Service的类,DAO层的目录就放Dao的类。
配置文件是否合并的问题,这个问题也不要纠结,看个人喜好,如果想让配置文件单一化,就可以把两个ApplicationContext文件合并,但SpringMVC.xml与ApplicationContext不要合并,因为前者是表现层由Spring的子集框架SpringMVC专门负责,后者是业务层以及DAO层由Spring本身自己负责。
4.3. 软件环境
Jdk: jdk1.7.0_72
Eclipse: mars
Tomcat: apache-tomcat-7.0.53
Springmvc: 4.1.3
MyBatis: mybatis-3.2.7
MySql: 5.1.28
SM整合包: 1.2.2
4.4. 数据库环境
使用【资料\参考案例\sql】下的创建库建表脚本【springmvc.sql】创建我们使用的数据库环境。
4.5. SSM整合步骤
4.5.1. 第一步: 新建一个web工程
4.5.2. 第二步: 导入jar包
将【ssm整合后jar全集】下的jar包拷贝到WebContent/WEB-INF/lib下, 会自动关联到工程中
4.5.3. 第三步: 创建目录结构
根据思路创建工程目录:
- 代码目录:
cn.itcast包下创建四个子包
controller: 存放cnotroller层的代码
service : 存放service层的代码
dao: 存放dao层的代码
pojo: 存放pojo的代码
2.配置文件目录:
选择工程右键创建source folder: config, 用于存放全部配置文件.
3.视图目录:
在WebContent/WEB-INF下创建jsp目录,用于存放jsp文件.
4.5.4. 第四步: 使用mybatis逆向工程生成代码
- 将【资料\MyBatis逆向工程】下的【MyBatisGeneration】工程导入eclipse。
2.修改配置文件符合当前的开发环境和目录结构。
a) 数据库名
b) Pojo包名
c) Mybatis映射文件的包名
d) Mybatis映射接口的包名(与c相等)
e) 需要生成代码的数据库表
3.注意:
a) 执行前要把原先旧的代码全部删除。
b) 执行完生成程序后第一次刷新的时候表现出来的包名不对,再刷新一次就好了。这是eclipse的一个bug。
4.将生成的代码拷贝到我们的工程中去。
4.5.5. 第五步: 创建DAO层配置文件
- 在【资料\参考案例\config】下是mybatis课程中sm整合的时候需要的配置文件,整体导入。
2.整理mybatis的配置文件:
a) MyBatisConfig.xml:清空<configuration>标签内全部的内容,保留一个空的配置文件是为了今后对mybatis的扩展。
b) ApplicationContext.xml:保留其中的属性文件、数据源(连接池)、会话工厂、动态代理包扫描的配置,其他的都删除。根据上面的思路它应该属于dao层的spring配置文件,改名为ApplicationContext-dao.xml
c) 其他配置文件保持不变。
3.修改后的配置文件:
【MyBatisConfig.xml】
|
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 类型别名的配置 --> <!-- <typeAliases> <typeAlias type="cn.itcast.pojo.UserModel" alias="UserModel"/> <package name="cn.itcast.pojo"/> </typeAliases> --> </configuration> |
【ApplicationContext-dao.xml】
|
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 1 属性文件的配置 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 2 数据源的配置 --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> </bean> <!-- 3 MyBatis的会话工厂的配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:MyBatisConfig.xml" /> <property name="dataSource" ref="dataSource" /> </bean> <!-- 4 动态代理包扫描的配置 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="cn.itcast.dao" /> </bean> </beans> |
4.5.6. 第六步: 创建Service层配置文件
创建【ApplicationContext-service.xml】,@Service注解组件的扫描和事务管理
ApplicationContext-service.xml】
|
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- service层的组件扫描 --> <context:component-scan base-package="cn.itcast.service" /> <!-- 事物管理配置 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 数据源 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 传播行为 --> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- 切面 --> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service.*.*(..))" /> </aop:config> </beans> |
4.5.7. 第七步: 创建SpringMvc.xml
创建【SpringMvc.xml】,配置@Controller注解组件扫描,注解驱动,视图解析器
配置文件:
【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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- controller层的组件扫描 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 配置注解驱动 --> <mvc:annotation-driven /> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> |
4.5.8. 第八步: 配置web.xml
配置spring的容器监听、springmvc前端控制器以及它可接收的url地址。
配置文件:
【web.xml】
|
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>ssm</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置spring的容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:ApplicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置springmvc的前端控制器--> <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> <!-- 标记是否在tomcat启动时就加载当前的servlet --> <load-on-startup>1</load-on-startup> </servlet> <!-- 配置springmvc前端控制器能够接收的url结尾格式 --> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app> |
4.5.9. 小结
本节的重点是要掌握整合的思路,有了思路就可以寻着线索进行整合了,不用死记具体的过程。
4.6. 整合后的案例程序
4.6.1. 需求
使用SSM从数据库查询数据, 实现真正的商品列表的展示.
4.6.2. 需求分析
- 沿用SpringMvc入门程序.
- 在此基础上完成service层的代码, 定义service接口和实现类, 并用@autowired自动注入DAO接口对象.
- 完善controller层代码, 用@autowired自动注入service接口对象.
4.6.3. 第一步: 创建service层的接口和实现类
- 定义ItemsService.java接口
- 定义ItemsServiceImpl.java实现类,实现这个接口
代码:
【ItemsService.java】
|
package cn.itcast.service; import java.util.List; import cn.itcast.pojo.Items; public interface ItemsService { public List<Items> findItemsList() throws Exception; } |
【ItemsServiceImpl.java】
|
package cn.itcast.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import cn.itcast.dao.ItemsMapper; import cn.itcast.pojo.Items; @Service public class ItemsServiceImpl implements ItemsService { @Autowired ItemsMapper itemsMapper; @Override public List<Items> findItemsList() throws Exception { // 通过自动生成的接口方法查询商品列表 List<Items> list = itemsMapper.selectByExample(null); return list; } } |
注意:selectByExample(null)只检索除了大对象数据类型之外的字段,但items表中有一个detail字段的类型是text,为了把它也检索出来可以使用selectByExampleWithBLOBs(null)这个方法。
|
package cn.itcast.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import cn.itcast.dao.ItemsMapper; import cn.itcast.pojo.Items; public class ItemsServiceImpl implements ItemsService { @Autowired ItemsMapper itemsMapper; @Override public List<Items> findItemsList() throws Exception { /* * 注意: * selectByExample只检索除了大对象数据类型之外的项目 * selectByExampleWithBLOBs检索包含大对象数据类型的项目 */ // 通过自动生成的接口方法查询商品列表 List<Items> list = itemsMapper.selectByExampleWithBLOBs(null); return list; } } |
4.6.4. 第二步: 完善Controller层代码
- 把入门程序中的【ItemsController.java】拷贝过来
- 修改里面的【lsit()】方法,调用service接口的方法完成查询。
代码:
【ItemsController.java】
|
package cn.itcast.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import cn.itcast.pojo.Items; import cn.itcast.service.ItemsService; @Controller public class ItemsController { @Autowired private ItemsService itemsService; @RequestMapping("/list") public ModelAndView list() throws Exception { List<Items> itemsList = itemsService.findItemsList(); // 1. 设置返回页面需要的数据 2. 指定返回页面的地址 ModelAndView modelAndView = new ModelAndView(); // 1. 设置返回页面需要的数据 modelAndView.addObject("itemList", itemsList); // 2. 指定返回页面的地址 modelAndView.setViewName("itemList"); return modelAndView; } } |
4.6.5. 第三步: 导入jsp
从【资料\参考案例\jsp】中导入【itemList.jsp】到工程的jsp目录下
4.6.6. 第三步: 把工程加入tomcat启动、测试
访问地址: http://localhost:8080/springmvc/list.action
数据库:
4.7. 本节重点
到本节为止,一个完整的ssm整合就完成了。我们从最初的springmvc入门程序,到认识三大核心组件,到最后ssm整合形成完整的web系统,这就是一个web系统的学习进化过程。
Spring MVC 入门程序默认配置 --> Spring MVC 三大核心组件显式配置 --> SSM整合完整的显式配置
大家重点掌握:
整合的分层思路以及各层代码的编写
大家主要了解:
SSM开发环境搭建,这个环境搭建不是大家掌握的重点,只是作为了解,基本会搭即可。
5. 参数绑定(重点)
Springmvc作为表现层框架,是连接页面和service层的桥梁,它负责所有请求的中转。怎么从请求中接收参数是重点,这也体现了我们刚开始说的Springmvc的第一个作用:“接收请求中的参数”。
接收的参数具体有哪些类型呢?6.1~6.5是绝大部分参数绑定的类型,还有两种第二天课程讲。
5.1. 简述参数绑定的类型
- 默认支持的参数类型:HttpServletRequest,HttpServletResponse,HttpSession,Model
- 简单类型:String,long,double,boolean,Integer, Long等
- POJO类型
- POJO的包装类型-QueryVo
- 自定义转换器Converter:适合参数在传入方法前做事前加工,比如不能自动完成的类型转换,去空格等。
5.2. 需求
前面我们做完了商品列表画面的展示,下面继续做修改页面和保存修改。
【修改页面】:在列表页面点击一条数据的【修改】,根据id查询这条数据的详细信息,然后显示在修改页面
【保存修改】:在修改页面修改信息,然后点【保存】,把信息存到数据库,保存成功迁移到success页面。(正常保存完应该返回列表页面,但我们先做的简单一点,就暂时迁移到success页面。)
下面我们就利用这个修改的业务需求来逐个演示各种参数绑定方法。
5.3. 业务实现的代码规划
·默认支持的参数类型实现【修改页面】显示;
·简单类型实现【保存修改】功能;
·POJO类型改进【保存修改】功能;
·针对日期类型,利用自定义转换器Converter实现字符串到日期类型转换,进一步完善【保存修改】功能;
·POJO的包装类型-QueryVo简单说明综合查询业务的综合查询条件的传递。
5.4. 默认支持的参数类型
5.4.1. 啥是默认支持的参数类型
所谓默认支持的参数类型就是传不传它们都会存在的参数,想用时就在Controller方法中定义即可,用哪个定义哪个,不用不定义。
默认参数有:
HttpServletRequest:通过request对象获取请求信息
HttpServletResponse:通过response处理响应信息
HttpSession:通过session对象得到session中存放的对象
Model:通过Model参数返回需要传递给页面的数据。
|
注意:如果使用Model参数给页面传值,那方法的返回值可以不使用ModelAndView对象而只返回一个逻辑视图名(String字符串),此时返回的字符串会走视图解析器解析生成View对象。 无论Springmvc怎样对结果和返回值进行处理封装,其本质都是使用Request对象向jsp传递数据。 |
5.4.2. 演示代码
- 【itemList.jsp】的【修改】:
2.【ItemsController.java】新定义一个方法
<说明>
·HttpServletRequest:
可以接收页面传递过来的参数。
·Model:前面讲过,略
|
/** * 演示默认支持的类型参数:HttpServletRequest、HttpServletResponse、HttpSession、Model * 默认支持的参数类型就是传不传它们都存在的参数,想用时就在Controller方法中定义即可, * 用哪个就定义哪个,不用就不定义。 */ @RequestMapping("/toEdit") public String itemEdit(HttpServletRequest request, Model model) throws Exception { // 取得页面传过来的主键id Integer id = Integer.valueOf(request.getParameter("id")); Items itemsResult = itemsService.getItemsDetailById(id); // 设置返回给页面的数据 model.addAttribute("item", itemsResult); // 返回页面的逻辑视图名 return "editItem"; } |
3.【ItemsService.java】新定义一个接口
|
public Items findItemsById(Integer id) throws Exception; |
4.【ItemsServiceImpl.java】实现上面的接口方法
|
public Items findItemsById(Integer id) throws Exception { Items items = itemsMapper.selectByPrimaryKey(id); return items; } |
|
5.访问【http://localhost:8080/ssm2/list.action】,点击【修改】
6.将返回页面的数据和返回页面的地址合体返回:
SpringMVC提供一种专门用于Handler返回结果的类:ModelAndView(模型和视图类)。它相当于把Model类和视图路径字符串合并在一起返回。
SpringMVC拿到这个类对象后仍然会调度视图解析器来解析这个视图文件路径,并把数据给刚由视图解析器生成的视图对象,由它执行页面的渲染。
改造上面的方法:
|
/** * 演示默认支持的类型参数:HttpServletRequest、HttpServletResponse、HttpSession、Model * 默认支持的参数类型就是传不传它们都存在的参数,想用时就在Controller方法中定义即可, * 用哪个就定义哪个,不用就不定义。 */ @RequestMapping("/toEdit") public ModelAndView itemEdit(HttpServletRequest request, Model model) throws Exception { // 取得页面传过来的主键id Integer id = Integer.valueOf(request.getParameter("id")); Items itemsResult = itemsService.getItemsDetailById(id);
ModelAndView modelAndView = new ModelAndView(); // 1. 设置返回页面需要的数据 // 第一个参数是属性名称, 第二个参数是属性值 modelAndView.addObject("item", itemsResult); // 2. 指定返回页面的地址 modelAndView.setViewName("editItem");
return modelAndView; } |
|
项目实在中经常使用的还是直接返回字符串的那种,这个返回ModelAndView的不太常用。
5.5. 简单类型
默认参数类型有一个缺点:用request.getParameter来取值可能需要额外的类型转换,从String转成其他类型。
Springmvc可不可以直接接收这些类型的参数呢?答案是可以的,即直接接收简单类型的参数。Springmvc不仅可以直接接收多个简单类型参数,还可以自动进行简单的类型转换。
5.5.1. 简单类型就是java的简单类型
例如:String、double、long、Integer、Boolean等。
5.5.2. 传参规范
页面上input框的name属性值必须等于controller方法中接收时的参数名称
5.5.3. 演示代码
- 从【资料\参考案例\jsp】中导入【editItem.jsp】到工程的jsp目录下。
- 【ItemsController.java】新定义一个方法
|
/** * 演示接收简单类型:String, Integer, Double, Boolean等 * 要求:页面上input框的name属性值必须等于controller方法中接收时的参数的变量名称 */ @RequestMapping("/itemUpdate") public String itemUpdate(Integer id, String name, Float price, String detail) throws Exception { Items items = new Items(); items.setId(id); items.setName(name); items.setPrice(price); items.setDetail(detail); itemsService.updateItems(items); return "success"; } |
|
3.【ItemsService.java】新定义一个接口
|
public void updateItems(Items items) throws Exception; |
4.【ItemsServiceImpl.java】实现上面的接口方法
|
public void updateItems(Items items) throws Exception { itemsMapper.updateByPrimaryKeySelective(items); } |
5.从【资料\参考案例\jsp】中导入【success.jsp】到工程的jsp目录下。
6.进入修改页面修改信息并保存。
5.5.4. 解决post提交乱码问题
web页面默认的编码是ISO8859-1,但这个编码不支持汉字,所以汉字参数传递过来会出现乱码。
post请求乱码的解决方法:在web.xml中加一个过滤器解决。
|
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> 。。。。 <!-- 配置解决post提交汉字乱码的过滤器 --> <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> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 。。。。 </web-app> |
5.5.5. 解决get提交乱码问题
对于get请求中文参数出现乱码解决方法有两个:
- 修改tomcat配置文件【server.xml】添加编码与工程编码一致,如下:(常用)
2.另外一种方法对参数进行重新编码:
5.6. POJO类型
实现对修改保存的改进,适应参数个数的变化,几十上百个参数时候是绝对不可能用简单类型传递参数的。
5.6.1. 传参规范
页面中input框的name属性值必须等于Controller方法接收时的POJO参数中的属性名称
5.6.2. 演示代码
【ItemsController.java】新定义一个保存更新的方法,将旧的注释掉
|
/** * 演示接收简单类型:String, Integer, Double, Boolean等 * 要求:页面上input框的name属性值必须等于controller方法中接收时的参数的变量名称 */ // @RequestMapping("/itemUpdate") // public String itemUpdate(Integer id, String name, Float price, String detail) // throws Exception { // Items items = new Items(); // items.setId(id); // items.setName(name); // items.setPrice(price); // items.setDetail(detail); // items.setCreatetime(new Date()); // itemsService.updateItems(items); // return "success"; // } /** * 演示接收POJO类型的参数 * 要求:页面上input框的name属性值必须等于pojo中的属性名称 * * @return * @throws Exception */ @RequestMapping("/itemUpdate") public String itemUpdate(Items items) throws Exception { itemsService.updateItems(items); return "success"; } |
5.7. POJO的包装类型-QueryVo
我们要想在列表页面加一个综合查询功能,查询条件可能有商品信息、用户信息、订单信息,因此我们需要一个QueryVo来包装这些查询信息。那如何传递包装的参数呢?
5.7.1. 传参规范
页面中input框的name属性值必须等于Controller方法接收时的Vo参数中的属性.属性.属性....,即各层的属性名要相等。
5.7.2. 演示代码
- 新定义【QueryVo.java】
|
package cn.itcast.pojo;
public class QueryVo {
// 用户对象 // ...... // 订单对象 // ...... // 商品对象 private Items items; public Items getItems() { return items; } public void setItems(Items items) { this.items = items; } } |
2.【itemList.jsp】中增加两个查询条件作为POJO的包装类型的示范说明:控件name属性的名称要符合要求。
|
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>查询商品列表</title> </head> <body> <form action="${pageContext.request.contextPath }/search.action" method="post"> 查询条件: <table width="100%" border=1> <tr> <td>商品名称: <input type="text" name="items.name"></td> <td>商品价格: <input type="text" name="items.price"></td> <td><input type="submit" value="查询"/></td> </tr> </table> 商品列表: <table width="100%" border=1> <tr> <td>商品名称</td> <td>商品价格</td> <td>生产日期</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${itemList }" var="item"> <tr> <td>${item.name }</td> <td>${item.price }</td> <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td> <td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/toEdit.action?id=${item.id}">修改</a></td> </tr> </c:forEach> </table> </form> </body> </html> |
|
3.【ItemsController.java】新定义一个方法,这里不做具体的查询过滤,我们主要学习的是参数的传递。
|
/** * 演示接收POJO的包装类型 - QueryVo * 要求: 页面上input框的name属性值必须等于POJO中属性.属性.属性..... * * @param vo * @return * @throws Exception */ @RequestMapping("/search") public String searchItems(QueryVo vo) throws Exception { System.out.println(vo); return "success"; } |
5.8. 自定义转换器Converter
前台传递的是一个时间格式的字符串,后台数据库存储的是一个日期类型的数据,需要转换,但自动转换会报错(可以试一试)。为了转换需要自定义转换器。
5.8.1. 自定义转换器的作用
参数传递到方法之前的统一加工处理。
应用:最多的应用就是复杂类型转换、再有就是去掉金钱中的千分符等。比如:在Springmvc中接收参数时可以自动进行简单类型的类型转换,但是像String转Date这种复杂的类型转换,Springmvc不能自动完成,所以需要手动编写Converter转换器,来进行类型转换。
5.8.2. 演示代码
- 将【editItem.jsp】中的【商品生产日期】项目的注释打开
- 自定义转换器Converter
Converter的包名可以随意,我们这里定义一个全局的String到Date的转换器。
都要继承【Converter<S, T>】接口,【S - source源的类型】,【T - target目标的类型】,我们这里的S是String,T是Date。
|
package cn.itcast.controller.converter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.core.convert.converter.Converter; /** * S - source源的类型 * T - target目标的类型 * @author Derek Sun */ public class CustomGlobalStrToDateConverter implements Converter<String, Date> { public Date convert(String source) { try { Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(source); return date; } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } } |
3.Converter的配置方式:
【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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- controller层的组件扫描 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 配置注解驱动 --> <!-- 配置加载converter转换器 --> <mvc:annotation-driven conversion-service="conversionService" /> <!-- 转换器配置 --> <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="cn.itcast.controller.converter.CustomGlobalStrToDateConverter"/> </set> </property> </bean> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> |
4.Converter的配置方式2(了解)
这种方式放到工程里不好用,就是用来理解Converter具体作用在处理器适配器上。
|
<?xmlversion="1.0"encoding="UTF-8"?> <beansxmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 扫描带Controller注解的类 --> <context:component-scanbase-package="cn.itcast.springmvc.controller"/> <!-- 转换器配置 --> <beanid="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <propertyname="converters"> <set> <beanclass="cn.itcast.springmvc.convert.DateConverter"/> </set> </property> </bean> <!-- 自定义webBinder --> <beanid="customBinder" class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer"> <propertyname="conversionService"ref="conversionService"/> </bean> <!--注解适配器 --> <beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <propertyname="webBindingInitializer"ref="customBinder"></property> </bean> <!-- 注解处理器映射器 --> <beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!-- 加载注解驱动 --> <!-- <mvc:annotation-driven/> --> <!-- 视图解析器 --> <beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"> <propertyname="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <!-- jsp前缀 --> <propertyname="prefix"value="/WEB-INF/jsp/"/> <!-- jsp后缀 --> <propertyname="suffix"value=".jsp"/> </bean> </beans> |
注意:此方法需要独立配置处理器映射器、适配器,不再使用<mvc:annotation-driven/>
5. 【ItemsController.java】
|
/** * 演示接收POJO类型的参数 * 要求:页面上input框的name属性值必须等于pojo中的属性名称 */ @RequestMapping("/itemUpdate") public String itemUpdate(Items items) throws Exception { itemsService.updateItems(items); return "success"; } |
再次启动运行。
5.仅仅是做一个日期类型的转化可以不用自定义转换器,还有一种更简单的做法:直接在pojo对应的日期属性变量上面加注解 @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss"),因此SpringMVC.xml恢复原来的配置
【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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置注解扫描 --> <context:component-scan base-package="cn.itcast.controller" /> <!-- 企业中配置处理器映射器和处理器适配器:注解驱动 --> <mvc:annotation-driven /> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans> |
【Items.java】在pojo中对应的日期属性变量上使用注解@DateTimeFormat
|
public class Items { 。。。。。。 @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date createtime; 。。。。。。 } |
启动测试,这样也是可以进行String到Date的类型转换的。
注意格式:【yyyy-MM-dd HH:mm:ss】
5.9. 本节重点
要想顺利的保证前台的数据传到后台,在使用SpringMVC框架的前提下就要遵守SpringMVC传参的规范,具体规范如下:
- 默认支持的参数类型:HttpServletRequest,HttpServletResponse,HttpSession,Model。用哪个就在方法的形参中定义哪个,不用的不定义。
- 简单类型:String,long,double,boolean,Integer等
要求:页面中input框的name属性值必须等于Controller方法接收时的参数名称。
适合单个或少数参数的请求
3.POJO类型
要求:页面中input框的name属性值必须等于Controller方法接收时的POJO参数中的属性名称。
适合更新、插入操作。
4.POJO的包装类型-QueryVo
要求: 页面中input框的name属性值必须等于Controller方法接收时的Vo参数中的属性.属性.属性....
适合综合查询。
5.自定义转换器Converter
作用:参数传递到方法之前的统一加工处理。
应用:复杂类型转换、去空格, 去钱的千分符等
6. Springmvc与Struts2区别
- 入口不同:
springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
2.请求的拦截级别:
Struts2是类级别的拦截,一个Action类对应一个request上下文;
SpringMVC是方法级别的拦截,一个Controller类的方法对应一个request上下文。
3.单例与多例:
Struts2是基于类开发,传递参数是通过Action类的属性,只能设计为多例。
Springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(默认是单例)。
4.接收参数和返回数据:
Struts接收的请求参数存放于Action的属性中,是诸多方法共享的,程序可读性差。Struts采用值栈存储请求和响应的数据,通过OGNL存取数据;值栈存储方式太过原始。
Springmvc通过参数解析器是将request请求内容解析并给方法形参赋值,即请求参数是方法之间独立的。Springmvc对数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques对象传输到页面。