??xml version="1.0" encoding="utf-8" standalone="yes"?>
需要在webE序的lib目录下粘贴jstl.jar和standard.jar(如果只用el表达式,不用拯q两个jar)
注意Qjstl必须在能够支持j2ee1.4/servlet2.4/jsp2.0版本上的容器才能q行?br />
c开头的核心库,fmt开头的为格式化库,fn开头的为函数库Qsql开头的为操作SQL库,x开头的操纵XML
核心?br />
<c:out/>输出标签
examples:
<c:out value="${hello}"/>
如果需要再scope里取?在value内必Lel表达式或jsp脚本,否则把引号内容按字W串输出
<c:out value="abc"/>输出abc?br />
如果只是以上业务的话Q推荐用el表达式取|更加z?br />
<c:out value="${abc}" default="123"/>
如果abc在scope内ƈ不存在的话,可以加入default属性规定默认?
<c:out value="${cz}" escapeXml="false"/>
如果x字符串按HTML格式输出Q需加入escapeXml="false"?br />
此处推荐使用el表达式,el自动按HTML格式输出?/p>
<c:set><c:remove>讑ր|U除标签
examples:
<c:set value="123" var="temp"/>
temp:${temp}
<c:remove var="temp"/>
temp:${temp}
var指定变量名?/p>
<c:if><c:if/>判断标签
examples:
<c:if test="${v1 lt v2}" var="v">
v1于v2
${v }
</c:if>
var标签指定变量q接收test内判断的?/p>
<c:choose>条g分支标签
examples:
<c:choose>
<c:when test="${v1<v2}">
v1于v2
</c:when>
<c:otherwise>
v1大于v2
</c:otherwise>
</c:choose>
使用choose标签有两炚w要注?br />
1?lt;c:choose>标签不能单独出现
2?lt;c:otherwise>标签不能出现?lt;c:when>标签之前,</c:when>可以有多?/p>
<c:forEach>循环标签
examples:
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.name}</td>
<td>${user.age}</td>
<td>${user.group.name}</td>
</tr>
</c:forEach>
items属性指定集合数l,var属性指定@环取出的每一的变量?变量var是存攑֜scope范围内的
所以需要用el表达式取出?/p>
<c:forEach>循环标签各项属性说?br />
varStatus属?获取循环中var的状态?br />
<c:forEach items="${userList}" var="user" varStatus="vs">
vs.count取出当前是@环的W几?vs.step获取循环的步?
<c:forEach items="${userList}" var="user" begin="2" end="8" step=2>
循环从集合的W二开始,循环到第八项Q@环步长ؓ2
循环取出map
example:
<c:forEach items="${map}" var="m">
${m.key }=${m.value }<br>
</c:forEach>
${m.key }输出键,${m.value }输出?/p>
<c:forTokens>支持分隔W的循环标签
example:
<c:forTokens items="${tok}" delims="," var="v">
${v }<br>
</c:forTokens>
其他属性与<c:forEach>标签功能相同,需要注意的是delims=","Q它指定了以什么做为分隔符q行分割?br />
request内设|?1,2,3,4,5",此@环的输出效果如下:
1
2
3
4
5
<c:import>导入标签
example:
<c:import url="http://127.0.0.1/struts_taglib"></c:import>
此标{作用相当于jsp:include标签的作用,当前面包含url里的面?/p>
<c:redirect>重定向标{?/span>
example:
<c:redirect url="http://127.0.0.1/struts_taglib"></c:redirect>
直接重定向至url指定地址
EL表达?br />
el表达式的使用Ҏ$和{}
examples:
取出普通字W串
${hello} 在request范围内寻扑ֱ性名为hello的属性,q打印输出在面?br />
作用{同?lt;bean:write>标签
如果为在表达式中制定scope,它的搜烦序为pageScope~applicationScope.
取出l构
${user.name }
?q行DQ也叫存取器。和struts?lt;bean:write>标签的用方式非常类?/p>
取出map
${mapValue.key1 }
mapValue为scope中的属性名,key1为map中的Key倹{?/p>
取出字符串数l?br />
${strArray[1] }
取出数组用[]和下标进行导?/p>
取出对象数组
${users[2].name }
取出数组用[]和下标进行导?/p>
取出List
userList[3]:${userList[3].name }
取出数组用[]和下标进行导?/p>
el对运符的支?br />
1+2=${1+2 }
+-*/%cM
el判断是否为空
${empty value}
empty为关键字 value为key
在el表达式中制定scope的用方?br />
example:
${requestScope.hello } 在request范围内寻找hello
首先要确定的是Servlet臛_至终只有一个对象以及init()Ҏ会在ServletW一ơ加载时被执行一ơ也是唯
一的一ơ,所以Servlet的初始化工作一般在init()Ҏq行
一、解析ModuleConfig
ModuleConfig装了struts-config的所有配|信?br />
actionConfigs(ActionMapping)/actionConfigList 、exceptions 、formBeans(ActionForm)、forwards
(ActionForward)、messageResources、plugIns{?br />
// 初始化ModuleConfig配置工厂
initModuleConfigFactory();
// 由配|工厂实例化一个ModuleConfig的对?
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleConfig(String prefix, String paths)Ҏ做了一下事?br />
1?ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
q成的配置工厂生成一个工厂实?br />
2、ModuleConfig config = factoryObject.createModuleConfig(prefix);
创徏ModuleConfig实例createModuleConfig()Ҏ会有DefaultModuleConfigFactory 执行
q是在配|文件中指定的工厂类
Ҏ内部new 出ModuleConfig对象
在ModuleConfig构造方法内对以下参数进行了初始?br />
到此config构造完?br />
Digester digester = initConfigDigester();
initConfigDigester()Ҏd解析struts文g的解析规?/p>
3、@环struts配置文gq把所有标{ְ装ؓ相应对象填充到config对象相应的map集合中中
List urls = splitAndResolvePaths(paths);
URL url;
for (Iterator i = urls.iterator(); i.hasNext();) {
url = (URL) i.next();
digester.push(config);
this.parseModuleConfigFile(digester, url);
}
最后getServletContext().setAttribute(Globals.MODULE_KEY
+ config.getPrefix(), config);
把ModuleConfig讑օServletContext?br />
xconfig初始化工作全部完?/p>
struts每个模块都对应一个ModuleConfig对象个,在initҎ内被初始化,内部装了模块xml?/p>
件中的配|?/p>
二、struts核心cRequestProcessorc解?/span>
ActionServlet做ؓ前端控制器当有请求被接收Ӟ会调用process(request, response)Ҏ
1、ModuleConfig config = getModuleConfig(request);
通过Servlet上下文找到ModuleConfig对象
2、RequestProcessor processor = getProcessorForModule(config);
通过Servlet上下文找到RequestProcessor对象 --所以RequestProcessorcM是单例的
if (processor == null) {
processor = getRequestProcessor(config);
}
如果为空 也就说明是服务器端第一ơ接收客L的接收请?br />
那么执行getRequestProcessor(config)Ҏ生成RequestProcessorq设入ServletContext?br />
此方法ؓ同步ҎQ借此我猜此Ҏ为生成RequestProcessor的唯一Ҏ
Ҏ内部对RequestProcessor调用了init()ҎQ进行了RequestProcessor的初始化q设入ServletContext
里?br />
Z么RequestProcessor要做成单例,原因是RequestProcessorcd部有
HashMap actions = new HashMap();
q样一个集合封装了所有的控制器?br />
q样的设计是面向对象的。当ActionServlet接收到请求时它需要对h分发到相应控制器?br />
此时它获取中央控制器Q而这个中央控制器内部拥有所有控制器的引用?br />
/*
q里我的疑惑是ؓ什么要通过反射生成RequestProcessorQ此cdƈ没有l承实现M接口或类?br />
processҎ最后调用了RequestProcessor的process()Ҏ。此Ҏ为RequestProcessor的核心方?br />
*/原因l过学习发现RequestProcessorq不是单例的Q而实际因为struts的多模块应用模式Q导?/p>
RequestProcessorcL多例?/p>
三、解析RequestProcessorcL心方法process
1?String path = processPath(request, response);
截取客户端请求字W串相当?lt;action>标签的path属?br />
2、ActionMapping mapping = processMapping(request, response, path);
获取控制器相对的ActionMapping 对象
processMapping(request, response, path)
1、ActionMapping mapping =
(ActionMapping) moduleConfig.findActionConfig(path);
Ҏ内部调用了moduleConfig.findActionConfig(path);
ModuleConfig对象前面已做q解析,在findActionConfigҎ内部已path属性做为Key|直接
到ActionConfigHashMap集合内寻找ActionMappingQ原因见一.3
2.if (mapping != null) {
request.setAttribute(Globals.MAPPING_KEY, mapping);
return (mapping);
}
如果扑ֈmapping那么攑օrequest中,q返?br />
3?ActionConfig[] configs = moduleConfig.findActionConfigs();
for (int i = 0; i < configs.length; i++) {
if (configs[i].getUnknown()) {
mapping = (ActionMapping) configs[i];
request.setAttribute(Globals.MAPPING_KEY, mapping);
return (mapping);
}
}
//ActionMapping说明Q和Action的unknow属性有?br />
3、if (mapping == null) {
return;
}
定w处理Q说明客Lh的path路径q没有被配置
4、ActionForm form = processActionForm(request, response, mapping);
processActionForm(request, response, mapping);
1、ActionForm instance =
RequestUtils.createActionForm(request, mapping, moduleConfig,
servlet);
1、String name = mapping.getName();
获得mapping name属性也是映射的相对ActionForm的name
2、FormBeanConfig config = moduleConfig.findFormBeanConfig(name);
已name做ؓKey值在~存的HashMap内获取相?FormBeanConfig)对象
<!--对这里的一些承关pd下说?br />
struts Configcȝ基类 BaseConfig
ForwardConfig从BaseConfigl承
FormBeanConfig从BaseConfigl承
ActionConfig从BaseConfigl承
ActionMapping从ActionConfigl承
-->
3、if (config == null) {
log.warn("No FormBeanConfig found under '" + name + "'");
return (null);
}
如果为空也就说明q没有配|相对ActionFormQ而这是合法的所以返回空
4、ActionForm instance =
lookupActionForm(request, attribute, mapping.getScope());
此方法试囑֜request,session内寻找ActionForm
5、if ((instance != null) && config.canReuse(instance)) {
return (instance);
}
如果扑ֈ那么q回
6、return createActionForm(config, servlet);
如果没有扑ֈ则进行创?Ҏ传递了configQ因为config内封装了formbean标签的所
有配|信息。方法可以根据类名进行反生成对象?br />
2、if ("request".equals(mapping.getScope())) {
request.setAttribute(mapping.getAttribute(), instance);
} else {
HttpSession session = request.getSession();
session.setAttribute(mapping.getAttribute(), instance);
}
Ҏ配置信息Q把ActionForm讑օ相应作用域内
此方法作用就是获取ActionForm
5、processPopulate(request, response, form, mapping);
此方法用于做ActionForm的数据收集工?br />
1、form.reset(mapping, request);
此方法用于做数据重置Q程序员可以重写此方?br />
2、RequestUtils.populate(form, mapping.getPrefix(), mapping.getSuffix(),
request);
调用工具c进行数据收?br />
1、if ((contentType != null)
&& (contentType.startsWith("multipart/form-data"))
&& (method.equalsIgnoreCase("POST"))) {
判断是否是数据上?br />
2、if (!isMultipart) {
names = request.getParameterNames();
}
如果不是获取request里所有参数参数名?br />
3?while (names.hasMoreElements()) {
String name = (String) names.nextElement(); //循环获取参数?br />
String stripped = name;
Object parameterValue = null;
...
if (isMultipart) {
parameterValue = multipartParameters.get(name);
parameterValue = rationalizeMultipleFileProperty(bean, name,
parameterValue);
} else { //不是上传 则获取此参数名的所有参数?br />
parameterValue = request.getParameterValues(name);
}
if (!(stripped.startsWith("org.apache.struts."))) {
properties.put(stripped, parameterValue);
}
}
Ҏ最后把参数名做为Key,所对应的所有参数值做为键值放入hashmap?br />
5、BeanUtils.populate(bean, properties);
q三方工具cL据ActionForm以及所有参数名参数D行数据收?br />
3、if (!processValidate(request, response, form, mapping)) {
return;
}
q行数据验证Q方法内部会调用ActionForm的validateҎQ程序员可以重写此方?br />
6、Action action = processActionCreate(request, response, mapping);
获取控制?br />
1、方法首先获取Action的类?br />
2、然后此Ҏ对actionsq行了同步处理,原因RequestProcessor是多例的Qactions是一个成
员变量,~存了所有action?br /> 3、instance = (Action) actions.get(className);
if (instance != null) {
if (log.isTraceEnabled()) {
log.trace(" Returning existing Action instance");
}
return (instance);
}
试图在集合内取出action,如果不ؓI?则返回。此时说明此Action已被执行q?br />
4、instance = (Action) RequestUtils.applicationInstance(className);
如果没有反射创徏Action引用?br />
5、actions.put(className, instance);
最后把action攑օ集合Qƈq回?br />
7、ActionForward forward =
processActionPerform(request, response, action, form, mapping);
此方法内部调用Action的execteҎQ获取{向类?/p>
<!--说明cȝl关p?br />
在他的父c里?HashMap forwards = new HashMap();q样一个集?br />
q里的类l织关系是这LQActionMapping从ActionConfigl承Q?br />
ActionConfig拥有forwards 集合Q?br />
而ModuleConfig内部拥有ActionConfig集合,
q和struts-config标签的组l关pL完全cM?
ModuleConfig模块配置cd应一个struts配置文gQ?br />
ActionConfig控制器配|类对应一个Action标签Q?br />
ForwardConfig转向配置cd应Forward标签Q?br />
而ModuleConfig在ActionServlet初始化时被加载?br />
q里可以看出大师对类的组l的合理Q每个标{N有相应的cR?br />
-->
lg所qͼ׃forward标签属于ActionMapping标签所以在E序里,能用findForward()Ҏ扑ֈ
ActionForward.
而在ActionConfig内部有这样一个方法addForwardConfig(ForwardConfig config)Q它已ForwardConfig ?/p>
name属性做为Key,ForwardConfig cd例做为值添加入~存中?br /> q也是Z么我们可以在findForward()Ҏ内通过传name属性获取相应的ActionForward实例?/p>
8、processForwardConfig(request, response, forward);
在processҎ的最后调用了processForwardConfig()Ҏ。完成{向操作?br />
在这个方法内部,他根据Redirect()是否讄为true选择是进行{发还是重定向。如果没有设|,默认是进
行{发?br />
说明Q?br />
此篇学习W记是阅读学堂王勇老师struts视频的读后感吧,当时弟刚学习strutsQ也是个j2ee的新人就斗胆写了q篇源码的分析,今天发上来ƈ未做M删减Q错误是隑օ的,q希望各位大NLQ多多指正,不吝赐教Q!
最后感谢由L感谢王勇老师Q感谢尚学堂Q!
<bean:write>标签
相当于jsp标签 <%= %> jsp内置对象out.println()Ҏ 做输Z?br />
在相应scope内设|??lt;bean:write>标签取出?br />
examples:
取出普通字W串
<bean:write name="hello"/>
name属性也是在上一面setAttribute()的key?/p>
以HTML文本形式做输?br />
<bean:write name="hello" filter="false"/>
filter="false"文本按HTML形式取出
格式化日期Ş式输?br />
<bean:write name="date" format="yyyy-mm-dd HH:mm:ss"/>
format属性内讄日期昄的格?/p>
格式化数?br />
<bean:write name="num" format="###,###.0000"/>
format属性内讄数字昄的格?nbsp; 数字昄格式API在java.text.DecimalFormat?/p>
对象l构输出
对象普通属性输?br />
<bean:write name="user" property="name"/>
property="name",引号内设|属性名Q需要符合javaBean规范
对象l构属性输?br />
<bean:write name="user" property="group.name"/>
property="group.name"Q?q行D扑ֈl构相应属?
<logic:empty><logic:notEmpty><logic:present><logic:notPresent>标签
q些标签主要用于q行属性状态的判断
examples:
null值判断ؓ不存?br />
不存在同样判断ؓ为空
I字W串判断为空Q空集合判断为空
<logic:terate>q代标签
<logic:iterate id="u" name="userList">
</logic:iterate>
寚w合进行P代,循环取出值放在变量u?br />
examples: