马士兵老师Struts2学习笔记
1、namespace = "" 处理的是找不到对应的namespace的所有情况
比如有一个package, namespace = "/top" result为/index.jsp
有一个package, namespace = "" result为/index.jsp
如果我敲/bottom/index.jsp,没有对应的namespace, 那么为namespace =""的package就来处理这个action,
在它的result里找有没有index.jsp,如果还没有就报错
2、tomcat处理地址的过程:
eg, http://localhost:8080/MyStrcuts/HelloWorld/HelloWorld.jsp;
看有没有filter过滤,于是发现struts2,于是交给它处理,找不到再返回来
3、action里有指定class的情况:
eg, <action name="test" class="com.zaq.mystructs.IndexAction">
<result>
/hello.jsp
</result>
</action>
省略了class, 它默认的class是ActionSupport.class, 这个class的execute就返回了"success"
4、java三种写action的方法:
直接在class中写String xxx()方法
实现Action接口
继承自ActionSupport类 (推荐)
5、匹配URL的三种方法:
1、常规通过action result 指定具体的class,(method),和result地址
2、使用!感叹号的形式:
eg. <action name="user" class="com.zaq.mystructs.User">
<result>
/User.jsp
</result>
</action>
而User.class里有一个add的方法,返回success
那么可以这么写:http://localhost:8080/WebApp/package_namespace/user!add来访问这个方法
好处是不用写多个Action来分别指定执行的method, 动态选择method来执行
注意要加上:<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
还要加上<global-allowed-methods>regex:.*</global-allowed-methods>
3、通配符的方法,要求约定好形式:
<action name="*_*" class="com.zaq.mystructs.{1}" method="{2}">
<result name="{2}">
/{1}_{2}.jsp
</result>
</action>
可以这么写:
http://localhost:8080/WebApp/package_namespace/User_Login来访问, 那么{1}就代表User,{2}代表Login,
访问的是mystructs.User下Login方法(返回String login),接收返回值"login"后跳转到User_Login.jsp
很无敌
这样就可以类似http://localhost:8080/WebApp/package_namespace/User_Register来同样操作,
只要在User里加一个Register()即可;很灵活
6、利用Action的属性接受参数:
在User里指定字段name, age, 写setter,getter,然后:
http://localhost:8080/WebApp/package_namespace/User_Login?name=zaq&age=20
这样默认调用了setter, 可以直接使用name,age字段,连new User()都不用
7、利用DomainModel接收参数:
如果字段有很多,6比较麻烦,此时可以这么写:
在UserMgr中直接定义User user这个对象字段, 只写getUser(),setUser()然后:
http://localhost:8080/WebApp/package_namespace/User_Login?user.name=zaq&user.age=20
这样默认先set好一个User, 再给UserMgr;
8、利用ModelDriven接收参数
实现ModelDriven<User>的接口,重写getModel()方法,然后return user;
这里可以省略user的getter和setter,取而代之的是写User user = new User();
没错一定要new一个
9、中文编码:
默认就是UTF-8 配置的方法就是struts.i18n.encoding=UTF-8
10、数据验证:
通过valueStack 和 fieldError:
后台在拿到参数后,进行业务逻辑判断,调用addFieldError来设置错误的键值对;
eg if(name != 'admin'){
this.addFieldError("login", "not admin");
}
result配置到前台,通过定义structs的标签:
<%@taglib uri = "/struts-tags" prefix="s"%>
就可以拿数据:
<s:property value="name"/> //"AL"
<s: property value="fieldErrors.login[0]" /> //"not admin"
注意:
1、后台设置错误键值对可以多设几个:
eg:this.addFieldError("login", "not admin");
this.addFieldError("login", "length too long");
这样在前台拿的时候可以依次:
<s: property value="fieldErrors.login[0]" /> //"not admin"
<s: property value="fieldErrors.login[1]" /> //"length too long"
2、加入<s:debug/>标签可以在前台调出valueStack 和 ContextStack 的信息
里面包含了property的键值对,可以参考stack来写vaule;
比如,fieldErrors.login[0]代表:
在VauleStack中, fieldErrors是一个Key, 对应的Value是一个Map,
取出其中Key为login的Value, 再取出Value的第一个元素[0]
11、获得Web元素:Request, Session, Application (依赖容器/IoC)
方法一:利用Map容器:
Map request;
Map session;
Map application;
构造方法里:
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
execute()的时候:
//进行业务逻辑操作
request.put("name", name);
session.put("name",name);
application.put("name", name);
前台:因为找的是context, 所以要加#, 在debug里也能看的
<s:property value = "#request.name"/>
<s:property value = "#session.name"/>
<s:property value = "#application.name"/>
方法二: IoC 控制反转 常用!
使用接口,RequestAware,SessionAware, ApplicationAware
实现方法 setRequest(Map<String, Object> request), setSession(Map<String, Object> session), setApplication(Map<String, Object> application);
this.request = request;
this.session = session;
this.application = application;
与方法一不一样的是不用自己去getContext().getXXX;
12、模块包含
在pacakge里可以直接<include file=""/> 来原封不动引入配置
13、default模式
加入<default-action-ref name="index"/>
表示如果namespace下找不到对应的action,就转到index这个action
注意这个标签一定要加在<global-allowed-methods>前面 否则报错
而且这个package里不要有通配符的使用, 否则好像也会报错
14、结果集的跳转(4个):
1、dispatcher (默认的)
服务器端跳转到jsp
2、redirect
重定向到jsp, 客户端跳转,url地址跟着变的
3、chain:
跳转到action 不同包下的action要通过<param>标签指定namespace 和 actionName 来跳转
4、redirectAction:
客户端跳转Action, url地址跟着变
客户端跳转就是重新发起一个request, valueStack也是新的, 而服务器端跳转一直是同一个request, 共享同一个valueStack
15、globalResult:
全局结果集, 定义在package里:
例如:
<global-results>
<result name="mainpage">/mainpage.jsp</result>
</global-results>
代表这个package里任何一个action返回mainpage都会往这个result里走
如果别的包也要这个全局的result, 在自己的package里extend = "那个包名" 就好
16、动态结果集:
在class里指定结果集:
eg:
test.java的execute()里,写 r = "mainpage.jsp";
那么result里写${r}即可
17、调用参数:
通常发生在要Redirect的时候,此时不共享同一个valueStack
例如:test.java:
name = AL;
action:
class = test.java
result:
type="redirect" -> /test.jsp?newName=${name}
test.jsp:
<s:property value ="newName"/> ❌ 不能从valueStack里拿了,因为不是同一个valueStack,而且你url里的参数又没传到新的值栈里
<s:property value = "#parameters.newName"/> ✔ 可以从actionContext里的patameters里取值。
18、OGNL:
1、只有传值,才会构造,用.来一层一层深入,必须保留无参构造函数
2、访问普通方法:<s:property value="login()"/>
<s:property value="userInfo.update()"/>
<s:property value="name.length()"/> //相当于string.length();
访问成员变量:
<s:property value="name"/>
<s:property value="userInfo.phonne"/>
访问静态成员变量:
<s:property value="@com.zaq.test@STATIC_STRING"/> //test.class里的一个静态成员STATIC_STRING
<s:property value="@com.zaq.test@static_method()"/> //test.class里的一个静态方法static_method()
注意必须要加上<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
3、访问容器:
<s:property value="list[0]"/>
<s:property value="list[1]"/>
<s:property value="array[1]"/>
<s:property value="map.somekey"/>
<s:property value="set"/>
//由于set内部元素排列是无序的,
所以带下标访问是没有意义的,只能整体拿出来
对于Map,还有:
<s:property value="map.size()"/>
<s:property value="map.size"/> //同上
<s:property value="map.keys"/>
<s:property value="map.values"/>
对于list:
<s:property value="list.{name}"/> 把元素中属性为name的值都拿出来
4、投影/过滤 ?#,^#,$#
eg:
<s:property value="list.{?#this.age>20}"/>
取出list中元素属性age>20的
this表示当前list代表的对象
<s:property value="list.{^#this.age>20}"/>
与正则表达式相似,取出第一个满足条件的(得到的是集合,取其中元素可以加上[0])
<s:property value="list.{$#this.age>20}"/>
与正则表达式相似,取出最后一个满足条件的(得到的是集合,取其中元素可以加上[0])
5、[]访问值栈
可以直接这么写:
<s:property value="[i]"/>
代表访问值栈从栈第i个元素(也就是栈顶)往下取所有的栈元素,是一个集合
而不是第i个栈元素的意思
valueStack可以有多个栈元素呀,
也就是有多个action呀,
也就是chain的时候呀
19、tag:
1、property: (value的类型是Object!)
<s:property value="name"/> 拿值栈里叫name的,是OGNL表达式
<s:property value="'name'"/>
这里拿出来的是字符串name,而非OGNL表达式,不是去取key=name的值
<s:property value="admin" default="zaq"/>
valueStack里没有admin, 这就用default的值
<s:property value="'<br>'" escapeHtml="true"/> //代表直接展现字符串<br>
<s:property value="'<br>'" escapeHtml="false"/>
//代表展现html的元素<br>,也就是打印了一个换行
2、set: (value的类型也是Object!)
<s:set var="name" value="'zaq'"/> //注意啊注意啊一定要加''不然这是OGNL表达式 不是字符串啊啊啊
定义变量name = zaq, 默认的scope是action-->放在actionContext,和request
取值:
<s:property value="#name"/>
<s:property value="#request.name"/>
都可以
<s:set var="name" value="'zaq'" scope = "session"/>
定义变量name = zaq, 放在actionContext的session里
取值:
<s:property value="#session.name"/>
<s:set var="name" value="'zaq'" scope = "request"/>
定义变量name = zaq, 放在actionContext的request里
取值:
<s:property value="#request.name"/>
3、include
尽量别用,因为如果包含的文件有中文字符会不显示,很麻烦
<s:include value="/index.jsp"/>
4、%{}
代表将内容转换为OGNL表达式
比如:
<s:set var="incPage" value="'/index.jsp'"/>
<s:include value="#incPage"/>
没用,因为他把value翻译为字符串了
得这么写:表示这是OGNL表达式,你给我取incPage它的value
<s:include value="%{#incPage}"/>
5、ifelse
eg:
url: xxxxx.jsp?age=30
<s:if test="#parameters.age[0]>20">too old</s:if>
<s:elseif test="#parameters.age[0]>20">too young</s:elseif>
<s:else>too young</s:else>
记得这里age要加[],因为可能传多个age
6、iterator
<s:iterator value="{1,2,3}">
<s:property/>
</s:iterator>
输出每个元素
<s:iterator value="{1,2,3}" var="ele">
<s:property value="#ele"/>
</s:iterator>
输出每个元素
<s:iterator value="#{'a','b','c'}" status="status">
<s:property value="#status.count"/> //当前遍历的次数1,2,3
<s:property value="#status.index"/> //索引:0,1,2
<s:property value="#status.odd"/> //是否为奇数
<s:property value="#status.even"/> //是否为偶数
<s:property value="#status.last"/> //是否是最后一个
<s:property value="#status.first"/> //是否是第一个
</s:iterator>
//定义map:
<s:iterator value="#{1:'a',2:'bb',3:'ccc'}">
<s:iterator value="key"/>
<s:iterator value="value"/>
</s:iterator>
7、theme
比较复杂,繁琐,用的少,simple什么的,知道了解即可
20、声明异常处理:
当action处理方法时抛出了异常:通过throws XXXException来通知struts我这会抛异常
1、局部异常处理:
<action name="exceptionAction" class="com.zaq.mystructs.user.ExceptionAction">
//有异常时设置返回值,在这里部署一下就好
<exception-mapping exception="java.io.FileNotFoundException" result="error"/>
<result name="error">
/error.jsp
</result>
<result name="success">
/index.jsp
</result>
</action>
2、全局的异常处理:
定义一个包,继承struts-default,在让别的包继承这个包就行,这里result写在map前
<package name="gloablExc" extends="struts-default">
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception="java.io.FileNotFoundException" result="error"/>
</global-exception-mappings>
</package>
21、拦截器:
struts的拦截器实现原理:类似设计模式里的责任链:
从过滤doFilter开始一步步跟:
StrutsPrepareAndExecuteFilter.doFilter()->Dispatcher.serviceAction()
->StrutsActionProxy.execute()->DefaultActionInvocation.invoke()
可以发现在invoke里通过迭代拦截器,执行interceptor.intercept()方法,
而intercept()方法中又调用invoke(),再接着迭代下一个interceptor,
于是一直到最后一个intercept()后,没用下一个interceptor了,
开始原路返回:return到上一个intercept()的invoke()后的内容,
执行完这个intecept()再一层一层返回,这样就形成一个责任链。
最后执行invokeActionOnly() ,然后executeResult()
22、类型转换:
再url里传参数时,int,String会自动转换,而容器:
list<String>/set<String>/String[]/ :这样传递:list=a&list=b;
//必须指定泛型
map<String,String>:
map['a'] = 'good'&map['b']='justsoso' & map['c']=bad
打印直接写<s:property vaule="xxx"/>
日期类型Date:
打印这么写:
<s:date name="d" format="YYYY/mm/dd"/>与SimpleDateFormat那个类一样
Object类型:
可以自定义类型转换:
写一个自定义的类,继承自DefaultTypeConverter,重写convertValue()方法:
public class MyConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Map context, Object value, Class toType) {
if (toType == com.zaq.bean.User.class) {
//这个setter,getter要写好,除非是public的字段
User u = new User();
String[] values = (String[]) value; //传递的参数可能不止一个
int id = Integer.parseInt(values[0].split(",")[0]); //这里只对第一个进行类型转换
int age= Integer.parseInt(values[0].split(",")[1]);
u.id = id;
u.age = age;
return u;
}
return super.convertValue(context, value, toType); //要加上
}
}
局部的:
ActionName-conversion.properties
写:p = com.zaq.mystruts.myConverter
全局的:
xwork-conversion.properties
写 com.zaq.bean.User.u = com.zaq.mystruts.myConverter
就行
如此一来:url可以这么敲:.../?u=10001,18
方便很多hhh
struts还有validation框架等等,需要时再学也是可以的
马士兵老师Struts2学习笔记相关推荐
- Java高并发编程 (马士兵老师视频)笔记(一)同步器
本篇主要总结同步器的相关例子:包括synchronized.volatile.原子变量类(AtomicXxx).CountDownLatch.ReentrantLock和ThreadLocal.还涉及 ...
- 马士兵坦克大战学习笔记(一)
java初学者对于马士兵坦克大战的个人学习笔记及代码问题总结(第一阶段), 1.系统自动初始化了Graphics g参数 2.设计原则:高内聚,低耦合: 一个模块中的各元素之间的紧密程度越高,内聚性越 ...
- Java高并发编程 (马士兵老师视频)笔记(二)并发容器
本篇主要总结了:线程安全的单例模式和并发容器.其中并发容器包含:ConcurrentHashMap.ConcurrentSkipListMap.CopyOnWriteArrayList和队列相关的内部 ...
- 马士兵hibernate(原始笔记)
马士兵hibernate(原始笔记) 课程内容 1 HelloWorld a) Xml b) annotation 2 Hibernate原理模拟 - 什么是O/R Mapping以及为什么要有O/R ...
- [原创 - 尚学堂科技 - 马士兵老师]
JAVA自学之路 一:学会选择 [转载请注明出处:http://www.bjsxt.com/zixue/zixuezhilu_1.html] 为了就业,不少同学参加各种各样的培训. 决心做软件的,大多 ...
- 马士兵python_马士兵:python学习(一)
python学习 一. 输出函数print(P6) 1. 输出数字和字符串 print(520) print(52.01) print("hello world") print(h ...
- [转]尚学堂科技 - 马士兵老师-JAVA自学之路
[原创 - 尚学堂科技 - 马士兵老师] JAVA自学之路 一:学会选择 [转载请注明出处:http://www.bjsxt.com/zixue/zixuezhilu_1.html] 为了就业,不少同 ...
- 2022年了Java架构师怎样进阶,马士兵老师给你答案
苦于网络上充斥的各种java知识,多半是互相抄袭,导致很多后来者在学习java知识中味同嚼蜡,今天给大家推荐马士兵老师分享的进阶成为java架构师所必须掌握的核心知识点. 废话少说,直接上正题 1.多 ...
- 马士兵老师的Java自学之路(转长篇!!)
作者:马士兵老师 JAVA自学之路 一:学会选择为了就业,不少同学参加各种各样的培训. 决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机.嵌入式.游戏.3G.测试等.那么究竟应该 ...
- 马士兵老师经典J2SE中的经典语录
最近的软考内容主要为马士兵老师讲的J2SE,老师讲的不只是知识,还有学习的经验,对生活的感悟,对我们的一些忠告,所以还是很喜欢看的.下边记录了一些让我感触很深的话,随着视频的进度,我会不断更新上的. ...
最新文章
- 再见了,公司的“烂系统”
- C++ 私有构造函数的作用
- cmf php,cmf公共函数解析-common.php
- how to extend odata service
- GMIC来了 HTC VIVE细化VR梦
- 2017.9.22 middle 失败总结
- java跟setattribute,java 中的request.setAttribute和session.setAttribute的区别
- java获取当前年月日历_转:JavaCalendar获取年、月、日、时间
- 世界各国英文简写一览表
- 计算机基础——4.1 数字通信入门
- HCIP 数通资料下载 肖哥视频
- CSMA/CD与CSMA/CA的区别
- 全国计算机一级证书重点知识,全国计算机一级
- Linux基础第一课——基础知识了解
- 宇宙最全面试题目实录(二)
- 【信息技术】【2004.05】双耳语音识别研究:声与电的听觉
- 设备功耗计算专题《测试仪器使用篇,EFM32GG-STK3700使用教程》
- ESP32(arduino)和声音传感器数据采集并实现连接WiFi进行MQTT通信
- 笔记:机器学习——吴恩达 第九周
- 数据分析案例——客户流失分析与预测
热门文章
- php time()的用法,PHP timezone_name_from_abbr() 函数用法及示例
- 用C语言程序进行比赛日程排列
- Paper reading (三十一):Personalized Nutrition by Prediction of Glycemic Responses(overview)
- Oracle细节,plsql语法大全
- rtl8201以太网卡调试
- 教你如何写原创歌词和卖你的原创歌曲
- 实现一个多线程安全的单向有序链表,add单个结点、与其他链表合并
- 设计心理学2-与复杂共处【读书笔记】
- UNI-APP_uni-app uni.getUserProfile微信授权,微信授权信息显示微信用户解决
- VirtualBox升级VirtualBox Guest Additions增强功能