Struts2 学习笔记(马士兵)
structs2学习笔记
实验软件下载
- 下载struts2.1.6 http://struts.apache.org/download.cgi#struts217
(选择下载full distribution) - 下载myeclipse,http://www.myeclipseide.com
- 下载tomcat,http://tomcat.apache.org
- 下载xwork,http://www.opensymphony.com/xwork (要注意的是下载与struts2.1.6的对应版本,即2.1.2)
- 解压struts2.1.6,假设解压后位于d:\struts2目录
- 安装MyEclipse,任何版本都可以
- 假设你已经安装好jdk和tomcat了,如d:\tomcat
- 建立项目
安装与设置
HelloWorld
a) 打开eclipse
b) 新建项目
c) 选择myeclipse-java enterprise projects-web project
d) 项目名称:struts2_0100_introduction
e) 选择java ee 5.0
- 设定server
a) window – preferences – myeclipse – servers – tomcat – 6.x
b) 选择tomcat home directory
c) 选择enable
d) finish
- 设定jdk环境
a) window – preferences – java – installed jres
b) 如果没有对应的JDK(不是JRE),选择add
c) 选择standard VM -> next
d) 选择JDK对应的Directory
e) 将刚刚设定的JDK设为默认
- 建立第一个struts2.1的程序
a) 找到struts目录下对应的apps目录
b) 解压struts2-blank-2.1.6.war
c) Copy对应的lib的jar文件,需要除junit和spring-test之外的所有文件,其中commons-io的jar包会在文件上传和下载时需要,其他为必须
d) Copy对应的struts.xml到src目录,在package explorer视图进行操作
e) 注释掉struts.xml的多余内容
f) 建立HelloStruts2_1.jsp文件
g) *修改jsp文件的默认编码属性window-preferences-web-jspfiles-设为Chinese,National Standard
h) 在struts.xml中照原配置进行对应的配置
i) 修改对应的web.xml,建立struts2的filter(参考struts自带的项目)
- 运行项目
a) 可以首先部署到tomcat上项目
b) 也可以项目右键debug as – myeclipse server app,选择刚刚建立好的server
- 其他
a) 学习建立struts的dev-mode,好处在于我们修改了配置文件的时候能够自动热替换
b) 建立jar文件对应的源码D:/share/tools/struts-2.1.6/src/core/src/main/java,以及xwork对应的源码,以及对应的javadoc location,(更好的方式是建立自己的user-library)
c) 浏览struts的目录
d) 认识eclipse jee的项目部署目录,认识如何修改webapp的context-root,项目copy改名后可能会出现的问题
e) package explorer – 建立jar的源文件和目标关联,navigator – 观察所有的内容
f) 认识Action的后缀名,在struts2默认中,带不带action都可以
常见问题:
- struts.xml不自动提示
a) window – preferences – 搜索 catalog – add
b) 选择key type为URI
c) key: http://struts.apache.org/dtds/struts-2.0.dtd
d) location: 对应的dtd文件,位于struts-core包中,解压开,指定相应位置,如:D:\share\0750_Struts2.1.6\soft \struts-2.1.6\lib\struts2-core-2.1.6\struts-2.0.dtd
- 导入示例项目
a) 注意JDK的版本,应该是JDK6,否则会出class version的问题
b) 如果总是项目出问题,可以重建项目,单独拷文件
c) 还有一种情况是项目右键,properties – java – compiler 选择6.0
d) 另外,在tomcat配置中也要使用jdk6
- devMode设为true就会出问题空指针问题
a) tomcat路径带了空格
- 在使用ActionContext.getContext().get(“request”)取不到对象,为null值
a) web.xml不要使用2.0的filter,用新的
- 在action的试验中,遇到一个奇怪的bug
a) 用default-action-ref指定一个action
b) 用*_*映射
c) 在地址栏中访问一个不存在的action,如adfsdfsfs
d) 结果居然会映射到*_*上
e) 如果换成*__*就没问题了
f) 靠,只能认为是bug
g) 下次用*-*,不用*_*
学习方法说明
- 先阅读老师的代码
- 再建立自己的项目进行动手学习
- 实现一个Action的最常用方式:从ActionSupport继承(action的class不指定时,默认为该类)
Action
Struts1中用户访问一个action只创建一次,而struts2在每次访问时都会创建一个action(不存在线程同步)
Path问题:相对地址是根据地址栏中的url来定位,并不是根据jsp文件路径来确定,统一使用绝对路径。(myeclipse中的base标签)
- DMI动态方法调用 !
访问url:ActionName!Action中的方法;
- 通配符配置 * {1} {2} …
a) *_*
{1}对应第一个*
约定由于配置
- 接收参数的方法(一般用属性或者DomainModel(如user类)来接收)
属性传递:调用action中的set和get方法进行传递参数和接受参数
DomainModel传递:url中使用model.para形式传递参数
ModelDriven传递:getModel()方法,url中不用带model.para
- 简单参数验证addFieldError方法
a) 一般不使用Struts2的UI标签
b) <s:debug></s:debug>显示stackContext(actionContext是一个ThreadLocal对象)
在<s:property/>中value=“#request”访问其中的内容
- 访问Web元素
(Map类型的request,session,application,
真实类型的HttpServletRequest,HttpSession,ServletContext)
a) Map类型
- i. IoC:实现RequestAware接口
- ii. 依赖Struts2容器
b) 原始类型
- i. IoC:实现HttpServletRequestAware接口
- ii. 依赖Struts2容器
- 包含文件配置
- 默认action处理
- 常用四种类型:一次request只有一个值栈
Result
a) dispatcher(默认):服务器跳转,利用服务器跳转(forward)到页面(jsp等)
b) redirect:客户端跳转(url会改变)
c) chain:服务器端跳转,跳转到一个action
d) redirectAction:客户端跳转
- 全局结果集
a) global-results(包内) | extends(继承其他包的result)
- 动态结果(了解)
a) 在action中保存一个属性变量,存储具体的结果location;在配置文件用${变量}来访问值栈
- 传递参数
a) 客户端跳转才需要传递
b) ${}表达式(不是EL)取action的valuestack;
OGNL
- 1. <s:property value=”ognl表达式” /> 访问值栈(value->Object)
- Object Graph Navigation Language 对象.方法/属性
- 想初始化domain model,可以自己new,也可以传参数值,但这时候需要保持参数为空的构造方法
- 其他参考ognl.jsp [0]:从action栈的栈顶开始的对象集合
<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].username"/></li>
- 5. 什么时候在stack中会有两个Action?chain
- 通用标签:
Struts-Tags
a) property
b) set 设置变量,放到actioncontext中
- i. 默认为action scope,会将值放入request和ActionContext中
- ii. page、request、session、application
c) bean
d) include(对中文文件支持有问题,不建议使用,如需包含,改用jsp包含)
e) param
f) debug
- 控制标签
a) if elseif else
b) iterator
- i. collections map enumeration iterator array
c) subset
- UI标签
a) theme
- i. simple xhtml(默认) css_xhtml ajax
- AJAX标签
a) 补充
- $ # %的区别
a) $用于i18n和struts配置文件
b) #取得ActionContext的值
c) %将原本的文本属性解析为ognl,对于本来就是ognl的属性不起作用
- i. 参考<s:property 和 <s:include
- css(覆盖struts2原来的css)
- 覆盖单个文件
- 定义自己的theme
- 实战:freemarker语言
定义自己的theme
a) 把所有主题定义为simple
b) fielderror特殊处理
c) 自己控制其他标签的展现
作业
- 读doc文档:struts-tags
- 设计约定(编码规定)
a) 原则:简单就是美
b) 库名:项目名
c) 表的命名:_Model名
d) 字段:保持和属性名一致(尽量不要起名和数据库命名冲突)
e) 用层来划分包com.bjsxt.bbs.action model(bean) service dto(vo)
f) Action XXXXAction
g) *-* struts2配置文件、jsp命名规则
h) / namespace命名
i) /admin
j) package “action” adminAction
项目开发顺序-以BBS2009的名义
- 建立界面原型
- 建立Struts.xml
a) 确定namespace
b) 确定package
c) 确定Action的名称,空的方法
d) 确定Result
e) 将界面原型页面进行修改,匹配现有设置
f) 测试
g) 做好规划!!!!!
- 建立数据库(或者实体类)
- 建立Model层
- 建立Service层(后面讲了Hibernate后再完善)
a) 此时可以使用JUnit进行单元测试了
- 着手开发
- 在Actoin中进行异常映射 <exception-mapping>
- 在package中进行全局异常映射
- 使用继承共用异常映射
- Struts2中异常处理由拦截器实现(观察struts-default.xml)
声明式异常处理
a) 实际上Struts2的大多数功能都由拦截器实现
I18N
- I18N原理
a) ResourceBundle和Locale的概念
b) 资源文件
c) native2ascii
- Struts的资源文件
a) Action – Package – App级
b) 一般只用APP
- i. struts.xml custom.i18n
c) PropertiesEditor插件
- i. 解压
- ii. features plugin 覆盖到myeclipse中的eclipse目录里
d) 动态语言切换
- i. request_locale=en_US
- Struts架构图
Struts拦截器以及源码解析
a) 见文档
- Struts执行过程分析
- Interceptor拦截器过程模拟
- 定义自己的拦截器
a) acegi – spring security
- 使用token拦截器控制重复提交(很少用)
- 类型转换
a) 默认转换(url中参数转换为list,set,map等等)
- i. 日期处理
b) 写自己的转换器:
public class MyPointConverter extends DefaultTypeConverter{
@Override
public Object convertValue(Object value, Class toType) {
if(toType == Point.class) {
Point p = new Point();
String[] strs = (String[])value;
String[] xy = strs[0].split(",");
p.x = Integer.parseInt(xy[0]);
p.y = Integer.parseInt(xy[1]);
return p;
}
if(toType == String.class) {
return value.toString();
}
return super.convertValue(value, toType);
}
}
public class MyPointConverter extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
Point p = new Point();
String[] strs = (String[])values;
String[] xy = strs[0].split(",");
p.x = Integer.parseInt(xy[0]);
p.y = Integer.parseInt(xy[1]);
return p;
}
@Override
public String convertToString(Map context, Object o) {
// TODO Auto-generated method stub
return o.toString();
}
}
c) 三种注册方式:
-
i.
局部:XXXAction-conversion.properties
- p(属性名称) = converter
- ii. 全局:xwork-conversion.properties
- com.xxx.XXX(类名)= converter
- iii. Annotation
d) 如果遇到非常麻烦的映射转换
- i. request.setAttribute();
- ii. session
- Lambda表达式
- 验证框架
- UI标签
- 类型转换中的异常处理
- 上传与下载文件
- 6. Struts2注解
- Action
补充视频中讲解的内容
Struts2总结
a) namespace(掌握)
b) path(掌握)
c) DMI(掌握)
d) wildcard(掌握)
e) 接收参数(掌握前两种)
f) 访问request等(掌握Map IOC方式)
g) 简单数据验证(掌握addFieldError和<s:fieldError)
- Result
a) 结果类型(掌握四种,重点两种)
b) 全局结果(掌握)
c) 动态结果(了解)
- OGNL表达式(精通)
a) # % $
- Struts标签
a) 掌握常用的
- 声明式异常处理(了解)
- I18N(了解)
- CRUD的过程(最重要是设计与规划)(精通)
- Interceptor的原理(掌握)
- 类型转换(掌握默认,了解自定义)