课程地位
就业技能结构图
本门课程目标
课程项目展示
· “房屋出租系统”演示
·
相关课程回顾
预习检查
· 根据你的理解,谈谈什么是框架?
· 框架能给我们带来什么好处?
· 举两个框架的例子。
本章任务
本章目标
· 知道使用框架技术的好处
· 掌握MVC控制器实现原理
· 了解常用Java框架的应用优势
为什么需要框架技术
· “框架技术”帮我们更快更好地构建程序:
· 是一个应用程序的半成品
· 提供可重用的公共结构
· 按一定规则组织的一组组件
· 优势:
· 不用再考虑公共问题
· 专心在业务实现上
· 结构统一,易于学习、维护
· 新手也可写出好程序
概念辨析
· 技术、组件、框架和系统
Java流行框架
· 大名鼎鼎的SSH
回顾:三层结构
三层结构在Java中的应用
课程安排
回顾:MVC设计模式
自定义MVC框架
· 问题:实现自定义MVC框架
· 目的:
· 规范Java Web应用开发
· 实现MVC模式(保证视图与模型分离)
· 实现:
· 结构、控制流程与核心组件(Action和Controller)
实现加法器
使用框架的优点
· 这个框架给开发带来了什么好处?
· JSP页面中没有业务逻辑代码,业务和展示彻底分开
· 用户操作抽象成了Action,程序逻辑更清晰
· 整个系统通过统一的入口(Controller Servlet)访问
基于框架开发
· 如何基于这个框架开发用户登录功能?
· 需求描述:
· 输入用户名为“aptech”,密码为“accp5.0”则登录成功;
否则登录失败
· 登录成功转发到my.jsp,登录失败返回index.jsp继续登录
基于框架开发:开发登录功能
这个框架还可以怎样改进?
· 自定义MVC框架的缺点
· 在增加功能时,需要修改Controller Servlet
· AddAction.java 的execute方法中直接引用页面物理路径, 修改页面文件名时需要修改代码
· Struts是一个成熟的MVC实现
· 第一个开源的Java Web框架
· Java Web框架的事实标准
· 利于快速开发稳健的Web应用
总结
· 什么是框架?
· 使用框架有什么好处?
· 什么是MVC模式?
· 使用MVC模式有什么好处?
· 在Java Web开发中,MVC模式中M、V、C都是如何实现的?
· 如何基于自定义MVC框架实现“查询所有用户” 的功能?
1. 下载使用Struts2
下载地址:<http://struts2.apache.org/download>
2.导入包,一般通过增加User library实现。
右键项目名--->propertise--->User librarys--->Userlibrarys--->New--->AddJARs 如果要导出就选export,下次直接import
也可以放在web-inf中,可以跟项目,但是不能以列表的形式保存。
现在需要的是八个包。commons-io-2.0.1.jar,commons-lang-2.5.jar,commons-fileupload-1.2.2.jar,javassist-3.11.0.GA.jar,ognl-3.0.1.jar,struts-core-1.3.10.jar,xwork-core-2.2.3.jar,freemarker-2.3.16.jar
3.过滤器
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
特别注意复制绝对路径的时候要去掉文件类型
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.导入struts标签库
<%@ taglib uri="/struts-tags" prefix="s" %>
对应struts-core-1.3.10.jar中的META-INF中的struts-tags.tld的URL
5.struts框架配置文件,文件名struts.xml,如果要引用是使用classes下的,但是src目录下的文件会产生一模一样的文件到classes,所以也可以直接放到src目录下
配置文件命名mess_en_US.properties,mess_zh_CN.properties,中间是字符编码,例如_zh_CN是中文,浏览器的字符编码进行效果查看。
<struts>
//使用配置文件,value和配置文件的前缀对应。name是强制规定的struts.custom.i18n.resources
<constant name="struts.custom.i18n.resources" value="mess"></constant>
//pageage只是做区分的,可以随便命名,大项目可以有多个package,名字不可以一样。namespcae是命名空间,也就是前缀。最好继承struts-default
<package name="default" namespace="/abc" extends="struts-default">
//name是servlet名字,class是完整的包名加类名,可以有多个action处理请求。
<action name="login" class="action.LoginAction">
//对应servlet中execute中的返回值。默认是request方式,如果要responce方式,就要把类型改成redirect
<result name="succ">/succ.jsp</result>
<result name="fail" type="redirect">/fail.jsp</result>
</action>
</package>
</struts>
6.在struts框架下写类
页面有几个参数需要接收就设几个属性。一般要继承ActionSupport类,重写execute方法,如果不用继承就直接写execute方法。默认是对request对象进行操作。el表达式中的${message }!等价于${requestScope.message }!
7.使用简单的struts标签
产生表单
//action和配置文件的actionname一至,如果package中的namespace不是所有路径,还要加上namespace
<s:form action="/login">
//文本框,name是控件名,key是配置文件中的key。
<s:textfield name="loginname" key="uname"></s:textfield>
<s:password name="loginpass" key="upass"></s:password>
<s:submit key="btn"></s:submit>
</s:form>
//输出标签,对应配置文件中的key,二进制输出。
<s:property value="%{getText('logintitle')}"/>
//只能在request中才可以,读取serlvet属性。
<s:property value="loginname"/>
8.增加提示信息
windows--->properties--->搜索栏输入catalog--->add
location对应struts-2.2.3\lib\struts2-core-2.2.3下的struts-2.1.7.dtd,例如E:\createprogram\struts-2.2.3\lib\struts2-core-2.2.3\struts-2.1.7.dtd
key type是uri
key是struts中的http://struts.apache.org/dtds/struts-2.1.7.dtd
<!DOCTYPE struts PUBLIC
"-//ApacheSoftware Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
9新建struts.xml文件。
右键src--->New--->XML(Advanced)--->去掉x-body标签
也可直接建file文件,后缀xml
一、 回顾MVC设计模式
二、 下载使用Struts2
a) 下载地址:<http://struts2.apache.org/download>
b) 了解文件结构:
i. apps:示例应用
ii. docs:API相关文档
iii. lib:核心类库
iv. src:源代码
c) 在项目中配置Struts2
i. 复制jar文件 commons-io ,commons-fileupload , commons-lang , javassist , core , freemarker , xwork
ii. 配置web.xml (配置核心过滤器)
三、 简单登录处理
i. jsp页面使用struts2标签结合资源文件
ii. 配置struts.xml (资源文件常量)
iii. 创建LoginAction类
四、 Struts2执行流程
五、 Struts2常量配置
a) 参考struts.properties文件
六、 实现Action
a) 编写一个普通Java类,定义属性用于封装HTTP请求中的参数(get/set)
b) 编写请求执行方法 execute
c) 了解Action接口和ActionSupport基类
d) Action访问ServletAPI
i. 使用ActionContext类:常用方法 put,get/setApplication, 静态getContext, getParameters, get/setSession,
ii. 使用ServletActionContext工具类:常用方法getPageContex, getRequest, getResponse, getServletContext
e) 配置Action
i. package :name,extends,namespace
ii. action : name,class,result子节点
目录
处理action请求: 1
普通Action请求: 1
DMI(Dynamic Method Invocation),动态方法调用 2
指定method属性及使用通配符 3
配置处理结果 9
普通配置Action视图资源 9
Action属性值决定物理视图资源 9
使用Struts2标签 10
控制标签 10
if/else if/else标签 10
iterator标签 11
append标签 13
generator标签 14
merge标签 15
subset标签 16
表单标签 17
checkboxlist标签 17
doubleSelect标签 18
optiontransferselect标签 21
select标签 22
radio标签 22
非表单标签 23
actionerror/actionmessage标签 23
处理action请求:
普通Action请求:
<package/>节点如不配置namespace属性,即该包使用默认的命名空间。
*****
当某个包指定了命名空间后,该包下所有的Action处理的URL应该是命名空间+Action名。
如果请求为/barspace/bar.action,系统首先查找/barspace命名空间里名为bar的Action,如果在该命名空间里找到对应的Action,则使用该Action处理用户请求:否则,系统将默认命名空间中查找名为bar的Action,如果找到对应的Action,则使用该Action处理用户请求;如果两个命名空间里都找不到bar的Action,则系统出现错误。
*****
PS:namespace=”/” 代表根命名空间,并不代表默认命名空间, 不配置或配置成namespace=”” 则代表默认命名空间。
DMI(Dynamic Method Invocation),动态方法调用
动态方法调用是指表单元素的action并不是直接等于某个Action的名字,而是以如下形式来指定表单的action属性
<! – action属性为actionName!methodName的形式,其中ActionName指定提交到哪个Action,而methodName指定提交到指定方法-- >
action = “ActionName!methodName”
//该路径指向namespace为/zhaojing Action名为login 方法名为doLogin
<s:form action="/zhaojing/login!doLogin"method="post">
PS:使用动态方法调用前必须设置Struts2允许动态方法调用,开启系统的动态方法调用是通过设置struts.enable.DynamicMethodInvocation常量完成的,设置该常量的值为true,将开启动态方法调用。(默认为true)
指定method属性及使用通配符
如果在配置<action />元素时,可以为它指定method属性,则可以让Action调用指定方法、而不是execute方法来处理用户请求。
struts.xml
<action name="login"class="struts.action.LoginAction" method="login">
<resultname="welcome">/welcome.jsp</result>
<resultname="login">/login.jsp</result>
<resultname="input">/login.jsp</result>
</action>
<actionname="reg" class="struts.action.LoginAction"method="reg">
<resultname="success">/reg_success.jsp</result>
<resultname="input">/login.jsp</result>
</action>
页面配置:
function doSubmit(url){
var f=document.forms[0];
f.action =f.action+url;
}
<s:form action="/zj/" method="post">
<s:textfieldname="uname" label="uname"></s:textfield>
<s:passwordname="upass" label="upass"></s:password>
<s:submitvalue="login"onclick="doSubmit('login')"></s:submit>
<s:submitvalue="reg" onclick="doSubmit('reg')"></s:submit>
</s:form>
*****
为了解决action定义冗余问题,struts2还允许使用通配符的方式。
在配置<action .. />元素时,允许在指定name属性时使用字符串(即用* 代表一个或多个任意字符),接下来就可以在class、method属性及<result .. />子元素中使用{N}的形式来代表前面第N个星号( * )所匹配的子串。
*****
struts.xml :
<action name="*Action_*"class="struts.action.LoginAction" method="{1}">
<resultname="success">/{2}_success.jsp</result>
<resultname="login">/login.jsp</result>
</action>
页面:
<SCRIPT type="text/javascript">
functiondoSubmit(url,tag){
var f=document.forms[0];
f.action =f.action+url+"_"+tag;
}
</SCRIPT>
<s:form action="/zj/" method="post">
<s:textfieldname="uname" label="uname"></s:textfield>
<s:passwordname="upass" label="upass"></s:password>
<s:submitvalue="login"onclick="doSubmit('loginAction','log')"></s:submit>
<s:submitvalue="reg" onclick="doSubmit('regAction','reg')"></s:submit>
</s:form>
除以上之外,当<action ../>元素的name属性使用了* 之后,<action/>元素的class属性也可以使用{N}表达式,即Struts2允许将一系列的Action类配置成一个<action/>元素,相当于一个<action/>元素配置了多个逻辑Action
struts.xml配置:
<action name="*Action_*"class="struts.action.{1}Action" method="{2}">
<resultname="success">/{2}_success.jsp</result>
<resultname="login">/login.jsp</result>
<resultname="hello">/index.jsp</result>
<resultname="input">/login.jsp</result>
</action>
页面配置:
function doSubmit(url,tag){
var f=document.forms[0];
f.action =f.action+url+"Action_"+tag;
}
<s:form action="/zj/" method="post">
<s:textfieldname="uname" label="uname"></s:textfield>
<s:passwordname="upass" label="upass"></s:password>
<s:submitvalue="login"onclick="doSubmit('Login','login')"></s:submit>
<s:submitvalue="reg"onclick="doSubmit('Login','reg')"></s:submit>
<s:submitvalue="hello"onclick="doSubmit('HelloWorld','')"></s:submit>
</s:form>
PS:如第二个*代表要执行的方法,如参数值为空则执行execute方法,否则执行与值同名的相对应方法
实际上,Struts2不仅允许在class属性、name属性中使用表达式,还可以在<result/>节点中使用{N}表达式。下面的配置提供了一个通用Action,该Action可以配置成如下形式:
<action name="*">
<result>/{1}.jsp</result>
</action>
通过这种方式,可以避免让浏览者直接访问系统的jsp页面,而是让struts2框架来管理所有用户请求。
*****
当用户请求匹配多个Action时,请求的处理。
假设有URL为abcAction.action的请求,在struts.xml文件中配置了如下三个Action,它们的Action值分别为:abcAction,*Action和*,则这个请求将被名为abcAction的Action处理。
如有defAction.action的请求,同样配置的三个action是abcAction,*Action和*,则这个请求显然不会被name为abcAction的Action处理,剩下的匹配的*Action和*,哪一个action配置在前则由哪一个action处理用户请求。
*****
PS:因为除非请求的URL与Action的name属性绝对相同,否则将按先后顺序来决定由哪个Action来处理用户请求。因此,我们应该将name=”*”的Action配置在最后,否则Struts2将使用该Action来处理所有请求。
配置处理结果
普通配置Action视图资源
<action/>节点会根据所调用方法的返回字符串来查找<result/>子节点中name属性相对应的值,从而进行转发。
//如方法返回值为login则进入/login.jsp(重定向),返回 hello 则进入/index.jsp页面(转发)
<result name="login" type=”redirect”>/login.jsp</result>
<result name="hello">/index.jsp</result>
//如没有指定任何name属性值,则name属性采用默认值:success;系统会将<result></result>中间的字符串当成实际视图资源;如没有指定type 属性则使用dispatcher;
<result>/thank_you.jsp</result>
Action属性值决定物理视图资源
<result name="success"type="redirect">/success.jsp?username=${uname}</result>
对于上面表达式的语法,要求在对应的Action实例里应该包含uname属性,否则${uname}表达式值为null.
<result name="success"type="redirect">/success.jsp?username=${user.uname}</result>
上面配置要求Action中属性user并且user中包含有属性uname
使用Struts2标签
控制标签
Struts2的非UI标签包括控制标签和数据标签,主要用于完成流程控制。控制标签可以完成流程控制,如分支、循环等。
控制标签:
if 、elseIf/elseif 、else 、append 、generator 、iterator 、merge 、sort 、subset
if/else if/else标签
这三个标签都是用于进行分支控制的,它们都用于根据一个boolean表达式的值,来决定是否计算、输出标签体的内容
<s:set name="age" value="30"></s:set>
<s:iftest="#age>60">
老年人
</s:if>
<s:elseiftest="#age>35">
中年人
</s:elseif>
<s:elseiftest="#age>15">
青年人
</s:elseif>
<s:else>
少年
</s:else>
iterator标签
主要用于对集合进行迭代,这里的集合包含List,Set和数组,也可以对Map集合进行迭代输出。
<s:iterator value="{'Struts','Spring','Hibernate'}"id="str"
status="i">
<s:if test="#i.index == 2">
当前下标为 : ${i.index}
</s:if>
<s:propertyvalue="str"/><br>
</s:iterator>
PS:status属性每次迭代时都会有一个IteratorStatus实例,该实例包含如下几个方法。
int getCount();返回当前迭代了几个元素
int getIndex();返回当前迭代元素的索引
Boolean isEven();返回当前元素顺序是否是偶数
Boolean isFirst();返回当前元素是否是第一个元素
Boolean isLast();返回当前元素是否是最后一个元素
Boolean isOdd();返回当前元素顺序是否是奇数
*****
<s:iterator value="{'Struts','Spring','Hibernate','dwr'}"id="str"
status="i">
<font <s:iftest="#i.odd">color="red"</s:if>>
<s:propertyvalue="str"/>
</font>
<br>
</s:iterator>
通过status的方法来控制样式显示
*****
append标签
append标签用于将多个对象集合拼接起来,组成一个新的集合。
<s:append var="newList" id="news">
<s:paramvalue="{'struts','spring'}"></s:param>
<s:paramvalue="{'hibernate','dwr'}"></s:param>
</s:append>
<s:iteratorvalue="#news" id="str"
status="i">
<font <s:iftest="#i.odd">color="red"</s:if>>
<s:propertyvalue="str"/>
</font>
<br>
</s:iterator>
*****
append标签不仅能将多个list拼接起来,也能将map与list进行拼接
<s:append var="newList" id="news">
<s:paramvalue="#{'st':'Struts','sp':'Spring'}"></s:param>
<s:paramvalue="#{'hibernate','dwr'}"></s:param>
</s:append>
<s:iteratorvalue="#news" id="str"
status="i">
<font <s:iftest="#i.odd">color="red"</s:if>>
Key:<s:propertyvalue="key"/> Value:<s:propertyvalue="value"/>
</font>
<br>
</s:iterator>
generator标签
使用generator标签可以将指定字符串按分隔分隔成多个子串,临时生成的子串数据可以用iterator标签进行输出。类似于String对象的split()方法
<s:generator separator=","val="'struts,spring,hibernate,dwr'" var="strs">
<s:iterator>
<s:property/>
</s:iterator>
</s:generator>
但此种写法generator标签一结束,集合将不可用.但可以通过定义var属性或id属性来保存集合 : 定义成var 可将集合设置成request范围内的属性。 count 设置集合可保留几个元素
<s:generator separator=","val="'struts,spring,hibernate,dwr'" var="strs">
</s:generator>
<s:iteratorvalue="strs" id="str">
<s:propertyvalue="str"/>
</s:iterator>
merge标签
类似于append标签,也是用于将多个集合拼接成一个集合,但它采用的方式与append有所区别。
如有三个集合元素,分别使用append和merge方式进行拼接,产生的新集合顺序为:
使用append
集合 1 元素 1
集合 1 元素 2
集合 2 元素 1
集合 2 元素 2
集合 3 元素 1
集合 3 元素 2
使用merge
集合 1 元素 1
集合 2 元素 1
集合 3 元素 1
集合 1 元素 2
集合 2 元素 2
集合 3 元素 2
subset标签
subset标签用于取得集合的子集。
<s:subset source="{'struts','spring','hibernate','dwr'}"start="1" count="2">
<s:iterator>
<s:property/>
</s:iterator>
</s:subset>
从下标1开始取元素,取2个长度。页面输出的结果为spring hibernate
表单标签
checkboxlist标签
可以一次创建多个复选框,用于同时生成多个<input type=”checkbox” />的HTML标签。它根据list属性指定的集合来生成多个复选框,因为,使用该标签需指定一个list属性。还有两个常用属性listKey(做为复选框的value) listValue(属性做为复选框的标签)
<s:checkboxlist name="ckl1" label="请选择你最喜欢的图书"
labelposition="top"list="{'Hello','SSH'}">
</s:checkboxlist>
<br/>
<s:checkboxlistname="ckl2" label="请选择你要的出版日期"
list="#{'疯狂的java讲义':'2008年9月','轻量级javaEE企业应用实战':'2010年8月'}"
listKey="key"listValue="value" >
</s:checkboxlist>
<br/>
<s:beanname="struts.bean.BookService" id="bs"></s:bean>
<s:checkboxlist name="ckl3"list="#bs.bookList" label="请选择你喜欢的图书"
labelposition="top"
listKey="author"listValue="bookName"></s:checkboxlist>
doubleSelect标签
会生成一个级联列表框(生成两个下拉列表框),当选择第一个的下拉列表时,第二个下拉列表框的内容会随之改变
常用属性:list,listKey,listValue ;doubleList,doubleListKey,doubleListValue,doubleName
<s:doubleselect label="请选择喜欢的图书" labelposition="top" name="author"
doubleList="top== '李刚'?{'struts2指南','轻量级JavaEE应用'}:{'javaScript'}"
list="{'李刚','David'}"doubleName="book"></s:doubleselect>
</s:form>
PS:使用doubleselect标签时,必须放在<s:form/>标签中使用,且必须为该<s:form/>标签指定action属性。除此之外,还应该在struts.xml文件中增加如下一段:
<actionname="*">
<result>/{1}.jsp</result>
</action>
*****
在默认情况下,第一个下拉列表只支持两项,如果第一个下拉列表框包含三个或更多的值,这里的list和doubleList属性值便不能这样设定
<s:set name="bs" value="#{'李刚':{'疯狂java讲义','轻量级java实战'}
,'David':{'javaScript'},'Johnson':{'J2EEDevelopment'}}"></s:set>
<s:doubleselectlabel="请选择喜欢的图书" name="author"doubleList="#bs[top]"
list="#bs.keySet()"
doubleName="book">
</s:doubleselect>
实现从数据库读取QX、JD数据的动态级联
配置一个匹配的Action[将qx和jd读取保存到集合]
public String execute() {
BookService bs = newBookService();
Map<Integer,List<Jd>>jdmap=new HashMap<Integer,List<Jd>>();
List<Qx> qxlist=bs.getQx();
ServletActionContext.getRequest().setAttribute("qxlist",qxlist);
for (Qx qx : qxlist) {
jdmap.put(qx.getQxid(),bs.getJdByQxid(qx.getQxid()));
}
ServletActionContext.getRequest().setAttribute("jdmap",jdmap);
return"success";
}
页面显示:[top指第一个下拉列表项]
<s:doubleselect name="qxlist" doubleList="#request.jdmap.get(top.qxid)"
list="#request.qxlist"listKey="qxid" listValue="qx"
doubleName="jds"doubleListKey="jdid"doubleListValue="jd"></s:doubleselect>
</s:form>
optiontransferselect标签
生成两个列表选择框,并生成系列的按钮用于控制各选项在两个下拉列表之间的移动。
常用属性:addAllToLeftLable ; addAllToRightLable ; addToLeftLable ; addToRightLable ;allowAddAllToLeft ; allAddAllToRight ; allowAddToLeft ; allowAddToRight ;leftTitle ; rightTitle ; allowselectAll ; selectAllLabel ; doubleList ;doubleListKey ; doubleName ; doubleValue ; doubleMultiple ; list ; listKey ;listValue ; name ; value ; multiple
<s:optiontransferselect name="cb"doubleList="#bs.booksRight"
list="#bs.booksLeft"doubleName="fb" addAllToLeftLabel="全部左移"
addAllToRightLabel="全部右移" allowAddAllToLeft="true"allowAddAllToRight="true"
allowAddToLeft="true"allowAddToRight="true" addToLeftLabel="<=="
addToRightLabel="==>"listKey="author" listValue="bookName"
doubleListKey="author"doubleListValue="bookName">
</s:optiontransferselect>
select标签
用于生成一个下拉列表框,使用该标签必须指定list属性,系统会使用list属性指定的集合来生成下拉列表框的选项。这个list属性指定的集合,既可以是普通集合,也可以是Map集合,还可以是元素对象集合。
<s:bean name="struts.bean.BookService"id="bs"></s:bean>
<s:selectlist="#bs.bookList" name="book"
listKey="author"listValue="bookName" label="选择图书"></s:select>
radio标签
与checkboxlist标签的用法几乎完全相同,唯一不同的是checkboxlist生成多个复选框,而radio生成多个单选框
<s:radio list="#bs.bookList" listKey="author"listValue="bookName"
label="选择图书"labelposition="top" name="books" value="'李刚'"></s:radio>
非表单标签
actionerror/actionmessage标签
这两个标签用法完全一样,作用也几乎完全一样,都是负责输出Action实例里封装的信息:区别是actionerror标签负责输出Action实例的getActionErrors()方法的返回值,而actionmessage标签负责输出getActionMessage()方法的返回值。
action中的配置
super.addActionError("第一个错误信息");
super.addActionError("第二个错误信息");
super.addActionMessage("第一个信息");
super.addActionMessage("第二个信息");
页面:
<s:actionerror/>
<s:actionmessage/>
显示效果:
• 第一个错误信息
• 第二个错误信息
o 第一个信息
o 第二个信息