1 : 配置Struts2
1)把struts.xml放在src文件夹下,项目编译完成时,会自动放到web-inf的class下。
2)把jar包放到web-inf的lib下面。
3)把struts的内容copy到web.xml下面 。
2.web.xml下面的<filter-mapping>下的<url-mapping>永远都写成/*
3.如果我们想看struts里面封装类的源码,却只能看到反编译之后的内容,怎么办呢?
找到对应的jar文件,右键 ...external Folder
有的时候我们也需要看它的doc文档,也是通过上面的类似的操作,这样就可以直接在eclipse里面查看说明内容。
找到类,按F1 。之后就可以直接看类的api文档。。\
Eclipse中 :添加struts2 source
我一般是这样添加的
1、将源包跟jar包都放到lib中
2、选中一个使用jar包中的方法,比如ActionSupport,然后在eclipse中按快捷键F3 java API - F1
3、由于没有导入源文件,所以在打开的文件中会出现 change attached source的按钮
4、点击这个按钮,在打开的对话框中选择 点击 external file..
5、选择源包即可。
当然以上你的保证src包是和导入的jar包相比配的。
说明下我导入的是webwork-2.2.7.jar 及 webwork-src-2.2.7.jar
4.怎样让eclipse给出xml文档提示呢? (定义文档dtd位置)
找到struts2 - core .jar,解压开,找到struts-2.dtd文件
顺序 : window - perference - xml catalog(可以手动搜索) - add - 上面dtd文件
5.之所以这些框架开始感觉麻烦,还不如直接访问,是因为易于以后的扩展(设计模式一般都是简单问题复杂化)。
struts就是把请求和展现(最后的结果)分开。
6.nameSpace :
<struts>
<constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/front">
<action name="index">
<result>/Namespace.jsp</result> <rusult name = "success">里面为success的话就可以不写
</action>
</package> name="front" 用来区分重名的情况 namespace必须斜杠开头 一般都以模块命名
</struts>
namespace决定了action的访问路径,默认为"",可以接收所有路径的action
namespace可以写为/,或者/xxx,或者/xxx/yyy,对应的action访问路径为/index.action,
/xxx/index.action,或者/xxx/yyy/index.action.<br/>
namespace最好也用模块来进行命名
namespace不写 或者为空 不管怎么访问都能访问到。如下:
<package name="main" extends="struts-default" namespace="">
<action name="index">
<result>/Namespace.jsp</result>
</action>
</package>
找不到的都到里面找 。
7. <constant name="struts.devMode" value="true" />
<package name="front" extends="struts-default" namespace="/">
<action name="index" class="com.bjsxt.struts2.front.action.IndexAction1">
<result name="success">/ActionIntroduction.jsp</result>
</action>
</package>
当我们action不配class时 ,是默认的class,即ActionSupport 。 import com.opensymphony.xwork2.ActionSupport 。
真正开发只用 ActionSupport 。 继承ActionSupport 。
8 .路径问题的说明 :
当找不到对应的namespace路径时,会访问web.xml里面的默认路径。
相对路径 : 查找同目录上一层目录 : ../ 上两层目录 .. .. /
1)
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%> localhost 8080 项目名 namespace
2)
myEclipse可以加上 <base href="<%=basePath%>" /> 就是所有的路径默认加上namespace的路径。
struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。(在jsp中用request.getContextRoot方式来拿到webapp的路径)
或者使用myeclipse经常用的,指定basePath。
9. method 动态方法调用 (DMI)
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" extends="struts-default" namespace="/user">
<action name="userAdd" class="com.bjsxt.struts2.user.action.UserAction" method="add">
<result>/user_add_success.jsp</result>
</action>
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>/user_add_success.jsp</result>
</action> 用这种 ,用动态的。
</package>
</struts>
Action执行的时候并不一定要执行execute方法<br />
可以在配置文件中配置Action的时候用method=来指定执行哪个方法
也可以在url地址中动态指定(动态方法调用DMI)(推荐)<br />
<a href="<%=context %>/user/userAdd">添加用户</a>
<br />
<a href="<%=context %>/user/user!add">添加用户</a>
<br />
前者会产生太多的action,所以不推荐使用
10 。ActionWildcard :通配符。 视频14
<struts>
<constant name="struts.devMode" value="true" />
<package name="actions" extends="struts-default" namespace="/actions">
<action name="Student*" class="com.bjsxt.struts2.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
</action>
*为通配符 , {1} ,就是*代表的内容 。 用这种的 。
<action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}">
<result>/{1}_{2}_success.jsp</result>
<!-- {0}_success.jsp -->
</action>
</package>
</struts> 精简化 :项目中约定优于配置 。
当有几个action都匹配时,struts会匹配最精确的 。如果*都能配置 ,就会按照顺序 。
11.用action属性接受参数 :<a href="user/user!add?name=a&age=8"> name 、age必须在action里面是成员变量,提供get、set方法,类型自动转换。
12.用DomainModel接受参数(域模型) 真正纯在的实体概念:<a href="user/user!add?user.name=a&user.age=8">添加用户</a>
DTO :比如说,密码确认。 视频16 。
public class UserDTO {
private String name;
private String password;
private String confirmingPassword;
}
13. ModelDriven 不常用 : MVC思想 ,这里面user被认为是一个model,必须new一个user 。
public class UserAction extends ActionSupport implements ModelDriven<User>{
private User user = new User();
public String add() {
System.out.println("name=" + user.getName());
System.out.println("age=" + user.getAge());
return SUCCESS;
}
@Override
public User getModel() {
return user;
}
}
14. 版本的中文问题 : 在struts里面加上 <constant name="struts.i18n.encoding" value="GBK" /> <!-- internationalization -->
去哪里查struts的文档呢? :官网啊~~~
struts2 2.1.6有bug解决不了中文问题 ,只能在web.xml里面配 ,或者在spring的filter里面配置。
web.xml 配置 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>改成struts2的2.1.7的配置
15. 简单数据验证 : 视频19 ,项目11 。 <%@taglib uri="/struts-tags" prefix="s" %>
jsp页面最后写了<s:debug></s:debug> 会在页面出现很多链接 。
栈 :先进后出 堆 :先进先出 。
ognl表达式 : <s:property value="errors.name[0]"/> 取属性 ,得到结果 “name is error”,debug里面value Stack Contents能看到可以取的属性 。
key的value 是一个数组。
<s:property value="errors"/> 得到的结果是 "name = name is error "
<body>
User Add Error!
<s:fielderror fieldName="name" theme="simple"/> <!-- 默认是xhtml-->
<br />
<s:property value="errors.name[0]"/>
<s:debug></s:debug>
</body>两种error方法 ,第二种好,可以改css,第一种封装好了 。
16.Struts访问web元素 : 视频21
一个form里的4个button通过不同的action提交方式 :
<form name="f" action="" method="post">
用户名:<input type="text" name="name"/>
密码:<input type="text" name="password"/>
<br />
<input type="button" value="submit1" οnclick="javascript:document.f.action='login/login1';document.f.submit();" />
<input type="button" value="submit2" οnclick="javascript:document.f.action='login/login2';document.f.submit();" />
<input type="button" value="submit3" οnclick="javascript:document.f.action='login/login3';document.f.submit();" />
<input type="button" value="submit4" οnclick="javascript:document.f.action='login/login4';document.f.submit();" />
</form>
只用IOC :
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware {
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
//DI dependency injection
//IoC inverse of control
public String execute() {
request.put("r1", "r1");
session.put("s1", "s1");
application.put("a1", "a1");
return SUCCESS;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
页面部分 (取值)
<s:property value="#request.r1"/> | <%=request.getAttribute("r1") %> <br />
<s:property value="#session.s1"/> | <%=session.getAttribute("s1") %> <br />
<s:property value="#application.a1"/> | <%=application.getAttribute("a1") %> <br />
<s:property value="#attr.a1"/><br />
<s:property value="#attr.s1"/><br />
<s:property value="#attr.r1"/><br />
}
17 .
<struts>
<constant name="struts.devMode" value="true" />
<include file="login.xml" />
</struts> 直接把login.xml包进来 。 意义在于 ,项目组中不同的模块包含进来,公用模块写在struts.xml里面
18.default action : 项目14 视频24
<default-action-ref name="index"></default-action-ref> 项目名字后面没有或者加其他的都跳到index的action
19 . result的配置 : type跳转的方式
<struts>
<constant name="struts.devMode" value="true" />
<package name="resultTypes" namespace="/r" extends="struts-default">
<action name="r1">
<result type="dispatcher">/r1.jsp</result> 只能跳转到视图 服务器端跳转
</action>
<action name="r2">
<result type="redirect">/r2.jsp</result> 只能跳转到视图 客户端跳转
</action>
<action name="r3">
<result type="chain">r1</result> 跳转到action 访问同一个包或者另外一个包的action 类似于forward
<!--<result type="chain">p2/r1</result> --> 另一个包p 都不要加斜杠
</action>
上面不行的时候用下面的:
<action name="r4">
<result type="redirectAction">r2</result> 跳转到action
</action>
</package>
</struts>
2)Global_Result 全局结果集 视频30 项目16
想用另外一个包里面的result :用extends
<package name="admin" namespace="/admin" extends="user"> extends
<action name="admin" class="com.bjsxt.struts2.user.action.AdminAction">
<result>/admin.jsp</result>
</action>
</package>
20.动态结果集 : 视频31
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result>${r}</result>
</action>
</package> struts里面的ognl表达式 不是el表达式
</struts>
public String execute() throws Exception {
if(type == 1) r="/user_success.jsp";
else if (type == 2) r="/user_error.jsp";
return "success";
}
21.带参数的结果集 : 项目18 视频32 只有在redirect情况下才要传参数 ,forward不要。
一次request只有一次值栈 ,forward共享同一个值栈 。
向结果传参数
<ol>
<li><a href="user/user?type=1">传参数</a></li>
</ol> index.jsp
<struts>
<constant name="struts.devMode" value="true" />
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="com.bjsxt.struts2.user.action.UserAction">
<result type="redirect">/user_success.jsp?t=${type}</result>
</action>
</package>
</struts>
<body>
User Success!
from valuestack: <s:property value="t"/><br/> 因为不是forward ,所以这样取不到值的 。不在值栈里面,因为user_success
只有jsp,没有从action类中取值,没有action user_success。所以只能<s:property value="#parameters.t"/>这样取值。
from actioncontext: <s:property value="#parameters.t"/>
<s:debug></s:debug>
</body>
22.OGNL (Object Graph Navigation Language) 表达式 : 视频 36-43 项目19 重要!
不是标签 是标签里面的value
user.xxx只有传 ,才会构造 。 想初始化domain model ,可以自己new ,也可以传参数值,
但这时 domain Model必须有一个参数空的构造方法 。
get/set生成的位置不对,怎么办 ? -> 右键source - sort member - sort all member .
<body>
<ol>
<li>访问值栈中的action的普通属性: username = <s:property value="username"/> </li>
<li>访问值栈中对象的普通属性(get set方法):<s:property value="user.age"/> | <s:property value="user['age']"/> | <s:property value="user[\"age\"]"/> | wrong: <%--<s:property value="user[age]"/>--%></li>
<li>访问值栈中对象的普通属性(get set方法): <s:property value="cat.friend.name"/></li>
<li>访问值栈中对象的普通方法:<s:property value="password.length()"/></li>
<li>访问值栈中对象的普通方法:<s:property value="cat.miaomiao()" /></li>
<li>访问值栈中action的普通方法:<s:property value="m()" /></li>
<hr />
<li>访问静态方法:<s:property value="@com.bjsxt.struts2.ognl.S@s()"/></li>
<li>访问静态属性:<s:property value="@com.bjsxt.struts2.ognl.S@STR"/></li>
<li>访问Math类的静态方法:<s:property value="@@max(2,3)" /></li>
<hr />
<li>访问普通类的构造方法:<s:property value="new com.bjsxt.struts2.ognl.User(8)"/></li>
<hr />
<li>访问List:<s:property value="users"/></li>
<li>访问List中某个元素:<s:property value="users[1]"/></li>
<li>访问List中元素某个属性的集合:<s:property value="users.{age}"/></li>
<li>访问List中元素某个属性的集合中的特定值:<s:property value="users.{age}[0]"/> | <s:property value="users[0].age"/></li>
<li>访问Set:<s:property value="dogs"/></li>
<li>访问Set中某个元素:<s:property value="dogs[1]"/></li>
<li>访问Map:<s:property value="dogMap"/></li>
<li>访问Map中某个元素:<s:property value="dogMap.dog101"/> | <s:property value="dogMap['dog101']"/> | <s:property value="dogMap[\"dog101\"]"/></li>
<li>访问Map中所有的key:<s:property value="dogMap.keys"/></li>
<li>访问Map中所有的value:<s:property value="dogMap.values"/></li>
<li>访问容器的大小:<s:property value="dogMap.size()"/> | <s:property value="users.size"/> </li>
<hr />
<li>投影(过滤):<s:property value="users.{?#this.age==1}[0]"/></li> 过滤
<li>投影:<s:property value="users.{^#this.age>1}.{age}"/></li> ^ 表示第一个
<li>投影:<s:property value="users.{$#this.age>1}.{age}"/></li>
<li>投影:<s:property value="users.{$#this.age>1}.{age} == null"/></li>
<hr />
<li>[]:<s:property value="[0"/></li> 在debug模式上方的stack 栈里面 从上往下全部取出来 。
<li>[]:<s:property value="[0].username"/></li>
</ol>
<s:debug></s:debug>
</body>
访问集合 :视频 40 toString也在里面 。set里面没有顺序 ,所以去set里面的第几个取不到。
23 .struts 标签: 视频 44 - 52 重要 ! 项目20
要想把一个object转换成一个字符串 就在双引号里面加单引号
<li>property: <s:property value="username"/> </li>
<li>property 取值为字符串: <s:property value="'username'"/> </li>
<li>property 设定默认值: <s:property value="admin" default="管理员"/> </li> 取不到用默认值 取到用admin
<li>property 设定HTML: <s:property value="'<hr/>'" escape="false"/> </li> escape默认为true 不会转换html 打印出<hr/>
<li>set 设定adminName值(默认为request 和 ActionContext): <s:set var="adminName" value="username" /></li>
<li>set 从request取值: <s:property value="#request.adminName" /></li>
<li>set 从ActionContext取值: <s:property value="#adminName" /></li>
<%--<li>set 设定范围: <s:set name="adminPassword" value="password" scope="page"/></li>
<li>set 从相应范围取值: <%=pageContext.getAttribute("adminPassword") %></li>
--%>
<li>set 设定var,范围为ActionContext: <s:set var="adminPassword" value="password" scope="session"/></li>
<li>set 使用#取值: <s:property value="#adminPassword"/> </li>
<li>set 从相应范围取值: <s:property value="#session.adminPassword"/> </li>
Chr />
<%--<li>push:<s:set name="myDog" value="new com.bjsxt.struts2.ognl.Dog('oudy')"></s:set></li>
<li>
push:<s:push value="#myDog">
<s:property value="name"/>
</s:push>
</li>
<li>push: <s:property value="name"/></li>
--%>
<hr />
<li>bean 定义bean,并使用param来设定新的属性值:
<s:bean name="com.bjsxt.struts2.tags.Dog" >
<s:param name="name" value="'pp'"></s:param>
<s:property value="name"/> 必须在bean标签里面访问 var是可以在bean外面访问的 因为放到了actioncontext里面
</s:bean>
</li>
<li>bean 查看debug情况:
<s:bean name="com.bjsxt.struts2.tags.Dog" var="myDog">
<s:param name="name" value="'oudy'"></s:param> 注意双引号里面的单引号
</s:bean>
拿出值:
<s:property value="#myDog.name"/>
</li>
<hr />
完全可以不用 ,因为struts里面的include中文出来比较麻烦 ,用jsp中的两种include
<li>include _include1.html 包含静态英文文件
<s:include value="/_include1.html"></s:include>
</li>
<li>include _include2.html 包含静态中文文件
<s:include value="/_include2.html"></s:include>
</li>
<li>include _include1.html 包含静态英文文件,说明%用法
<s:set var="incPage" value="%{'/_include1.html'}" />
<s:include value="%{#incPage}"></s:include> 说明%用法
</li>
总结 :$#%的区别 :
a)$用于i18n和struts配置文件
b)#取得ActionContext的值
c)%将原本的文本属性解析为ognl,对于本来就是ogni的属性不起作用(但是也可以加上),有的value的属性的string,加上%就变成ognl.
i ,参考<s:property 和 <s:include
# 1.用于actionContext 取值 () 2. url传入的值, 用#取值 3.%{#include}
24 .控制标签 :
<li>if elseif else:
age = <s:property value="#parameters.age[0]" /> <br />
<s:set var="age" value="#parameters.age[0]" />
<s:if test="#age < 0">wrong age!</s:if>
<s:elseif test="#parameters.age[0] < 20">too young!</s:elseif> //age是一个集合 必须加数组下标。
<s:else>yeah!</s:else><br />
<s:if test="#parameters.aaa == null">null</s:if>
</li>
<hr />
<li>遍历集合:<br />
<s:iterator value="{1, 2, 3}" >
<s:property/> | 自动拿元素
</s:iterator>
</li>
<li>自定义变量:<br />
<s:iterator value="{'aaa', 'bbb', 'ccc'}" var="x">
<s:property value="#x.toUpperCase()"/> |
</s:iterator>
</li>
<li>使用status:<br />
<s:iterator value="{'aaa', 'bbb', 'ccc'}" status="status"> 记录当前的状态
<s:property/> |
遍历过的元素总数:<s:property value="#status.count"/> |
遍历过的元素索引:<s:property value="#status.index"/> |
当前是偶数?:<s:property value="#status.even"/> |
当前是奇数?:<s:property value="#status.odd"/> |
是第一个元素吗?:<s:property value="#status.first"/> |
是最后一个元素吗?:<s:property value="#status.last"/>
<br />
</s:iterator>
</li>
<li>
<s:iterator value="#{1:'a', 2:'b', 3:'c'}" > 定义map的时候要加#
<s:property value="key"/> | <s:property value="value"/> <br />
</s:iterator>
</li>
<li>
<s:iterator value="#{1:'a', 2:'b', 3:'c'}" var="x">
<s:property value="#x.key"/> | <s:property value="#x.value"/> <br />
</s:iterator>
</li>
<li>
<s:fielderror fieldName="fielderror.test"theme="simple"></s:fielderror>
</li>
截元素:从第三个 截13个 。
<s:subset source = "myList" count = "13" start = "3">]
<s:iterator>
<s:propery/>
</s:subset>
<struts>
theme :
<constant name="struts.devMode" value="true" />
<constant name="struts.ui.theme" value="css_xhtml" />
<package name="theme" extends="struts-default">
<action name="theme" class="com.bjsxt.struts2.theme.ThemeAction">
<result>/theme.jsp</result>
</action>
</package>
</struts>
25. 视频52 改变struts2的默认的filedError的theme 的几种方法 .
项目2100 1、2、3、4
只有fiedError会比较麻烦,其他标签struts2不会对它添加其他的属性 。
26. <package name="front" namespace="/" extends="struts-default" >
<default-action-ref name="index"/> <!-- bug!!! -->
<action name="index" class="com.bjsxt.bbs2009.action.CategoryAction" method="list">
<result>/index.jsp</result>
</action>
</package>
27.声明式的异常处理 : 项目30-07 视频66
public List<Category> list() throws SQLException {
Connection conn = DB.createConn();
String sql = "select * from _category_";
PreparedStatement ps = DB.prepare(conn, sql);
List<Category> categories = new ArrayList<Category>();
try {
ResultSet rs = ps.executeQuery();
Category c = null;
while(rs.next()) {
c = new Category();
c.setId(rs.getInt("id"));
c.setName(rs.getString("name"));
c.setDescription(rs.getString("description"));
categories.add(c);
}
} catch (SQLException e) {
e.printStackTrace();
throw(e); //throw(e) ;
}
DB.close(ps);
DB.close(conn);
return categories;
}
Struts里面配置异常信息 :
<action name="*-*" class="com.bjsxt.bbs2009.action.{1}Action" method="{2}">
<result>/admin/{1}-{2}.jsp</result>
<result name="input">/admin/{1}-{2}.jsp</result>
<exception-mapping result="error" exception="java.sql.SQLException" />
<result name="error">/error.jsp</result> //有异常的时候,跳到匹配的result 。
</action>
2)可以为所有action配置一个统一的异常 :视频66,
其它包继承此包,这样出异常统一跳到"/admin/error.jsp
<constant name="struts.devMode" value="true"></constant>
<package name="bbs2009_default" extends="struts-default">
<global-results>
<result name="error">/admin/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
</global-exception-mappings>
</package>
28.国际化 :视频69 项目3100 ResourceBundle这个类
public class Test {
public static void main(String[] args) {
ResourceBundle res = ResourceBundle.getBundle("app", Locale.CHINA);
System.out.println(res.getString("welcome.msg" ));
}
}
app_zh_CN.properties
app_en_US.properties
转换工具 :PropertiesEditor 插件
features plugin覆盖到myeclipse中的eclipse目录里。
29 . Struts2 I18N action级别I18N问题 : 视频71 : 项目 32
<constant name="struts.custom.i18n.resources" value="bbs2009"></constant> bbs2009为properties默认前缀名
<body>
<form action="admin/Login-login" method="post">
<s:property value="getText('login.username')"/> <input name="username" />
<s:property value="getText('login.password')"/><input name="password" type="password" />
<input type="submit" value="<s:property value="getText('login.login')"/>" />
</form>
<s:debug></s:debug>
<a href="admin/lang?request_locale=en_US">en</a>
<a href="admin/lang?request_locale=zh_CN">cn</a>
</body>
第二种: 出来资源文件中的参数 视频72 项目32
<body>
<s:text name="welcome.msg">
<s:param value="username"></s:param>
</s:text>
</body>
welcome.msg=welcome:{0}可以
中英文切换 视频73 项目 32
<constant name="struts.custom.i18n.resources" value="bbs2009"></constant>
http://localhost:8080/struts2_3200_BBS2009_08_I18N/admin/lang?request_locale=en_US
http://localhost:8080/struts2_3200_BBS2009_08_I18N/admin/lang?request_locale=zh_CN 后面传参必须这么写(request_locale=zh_CN), 就是这样解析的
30.源码解析 : 视频 75 项目 36
31.防止重复提交 :
<action name="user" class="com.bjsxt.action.UserAction">
<result>/addOK.jsp</result>
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="token"></interceptor-ref>//防止重复提交
<result name="invalid.token">/error.jsp</result> //重复提交的错误结果页面(“严谨做重复的事”)
</action>
32.拦截器:视频76-79
http默认传String类型
关键问题是字符串转其他类型 :比如说Date 视频80 项目37
<body>
name:<s:property value="name"/><br/>
age:<s:property value="age"/><br/>
date:<s:property value="d"/><br/>
<s:date name="d" format="yyyy/MM/dd HH:mm:ss"/><br/> //时间的专门表达式
<s:property value="interests"/><br/>
<s:property value="users"/><br/>
<s:property value="p"/><br/>
<s:property value="ps"/><br/>
points:<s:property value="points"/><br/>
</body>
关于Point类的转换 视频 81- 82 项目37