1:struts是将请求和视图分开。
2:这里我下载的是struts 2.3.29,下面有一个blank.war关于struts.xml和web.xml的配置直接在里面找就行了。
3:若要使在myeclipse中出现xml文件提示,window->preference->XML catalog->add,选择url,这里url写的是http://struts.apache.org/dtds/struts-2.3.dtd,location写struts2-core-2.3.29目录下的struts-2.3.dtd所在位置,如图:
这样就会有提示了。
4:关于将包要自己手动从别的文件夹下复制到tomcat webapp下的项目lib中去了,这样有点麻烦,将所需要的包复制到myeclipse的web项目的lib下面,这样发布的时候会自动发布到tomcat下。
5:<constant name="struts.devMode" value="true" />属性是让项目处于开发者模式,更改之后就不用每次都重新启动tomcat了。
6:输入地址:http://localhost:8080/mashibingStruts/hello 后所发生的事情
客户端输入url地址,发送请求,通过http协议发送给tomcat,tomcat通过url地址中的mashibingStruts知道了是要处理这个web application,然后参考这个web application中的web.xml文件,发现里面有一个filter--struts2,这个filter会过滤所有的url地址,然后将这个请求交给org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter来处理。这个类会根据请求的后半部分在struts.xml中来查询package,<package name="default" namespace="/" extends="struts-default">,然后在这个package中查询有没有hello这个action,查到这个action之后再进行接下来的处理,最后将页面反馈给客户端。
7:namespace一般以"/"开头
namespace可以为空,意味着这个package会处理其他所有package处理不了的action。如果这个package也处理不了,就会报错了。
如果直接访问http://localhost:8080/mashibingStruts/,那么就会交给web.xml中的<welcome-file>index.jsp</welcome-file>去处理了。
8:action中的class什么都不写的时候是默认调用ActionSupport的execute方法.
实现ActionSupport接口而不实现Action接口,因为ActionSupport已经为我们实现了Action,而且封装了很多好的方法可以直接调用。
9:struts2中的路径问题是根据action的路径,而不是jsp路径来决定,所以尽量不要使用相对路径,而使用绝对路径。
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
10:Action执行的时候并不一定要执行execute方法,可以再配置文件中配置Action的时候用method=来指定执行哪个方法,也可以在url地址中动态指定(DMI)(推荐),因为前者会产生太多的action。
11:使用通配符可以将配置降到最低,但是一定要遵循“约定优于配置”的原则。
12:当struts2的url传参出现中文乱码时,server.xml文件中的<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" />修改成:<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="utf-8" />即可。但是如果仅仅改的是tomcat中的server.xml不行,因为myeclipse重启的时候会用configuration files中的配置文件将其覆盖,所以应该改configuration files中的server.xml文件。
13:当数据校验时,struts2可以在action中使用addFieldError()方法,将错误信息放到valueStack中,然后用ognl表达式读出来。
访问web元素,向request.session等注入值时
1、可以实现RequestAware,SessionAware接口,实现其中的set方法。(IOC注入思想)
Struts在实例化一个Action实例时,如果发现它实现了相应的Aware接口,会把相应的资源通过Aware接口方法注射进去。这种方式也可以叫做注射方式(IoC方式)。
Servlet API中常用对象application、request、response、Session对应的Aware接口分别为ServletContextAware、ServletRequestAware、ServletResponseAware、SessionAware。实现了这4种接口,能够感知到这些对象
org.apache.struts2.interceptor.ServletConfigInterceptor 这个拦截器会在值执行Action之前,看该Action是否实现了Aware接口,如果实现了aware接口,就会像相应的servlet对象注入进来
public String intercept(ActionInvocation invocation) throws Exception {
final Object action = invocation.getAction();
//获得ActionContext,通过ActionContext注入内置对象
final ActionContext context = invocation.getInvocationContext();
if (action instanceof ServletRequestAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
((ServletRequestAware) action).setServletRequest(request);
}
if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
((ServletResponseAware) action).setServletResponse(response);
}
if (action instanceof ParameterAware) {
((ParameterAware) action).setParameters((Map)context.getParameters());
}
if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}
if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}
if (action instanceof RequestAware) {
((RequestAware) action).setRequest((Map) context.get("request"));
}
if (action instanceof PrincipalAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
if(request != null) {
// We are in servtlet environment, so principal information resides in HttpServletRequest
((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
if (action instanceof ServletContextAware) {
ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);
((ServletContextAware) action).setServletContext(servletContext);
}
return invocation.invoke();
}
2、可以用ServletActionContext.getRequest();来获取HttpServletRequest。然后通过HttpServletRequest来获取HttpSession等。
3、可以用actionContext.get("request");来获取HttpServletRequest,actionContext.getContext.getSession();来获取session等。
struts2 doFilter拦截器工作原理时序图:
struts2 关于ActionContext和值栈相关源码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
prepare.setEncodingAndLocale(request, response);
//创建ActionContext对象
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request, response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
execute.executeAction(request, response, mapping);
}
}
} finally {
prepare.cleanupRequest(request);
}
}
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
//创建值栈对象
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
//把后面的Map赋值到值栈的Map中
stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
//把值栈中的Map存储到ActionContext中一份
ctx = new ActionContext(stack.getContext());
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
ActionMapping mapping) {
//封装了传入的内置对象
Map requestMap = new RequestMap(request);
Map params = new HashMap(request.getParameterMap());
Map session = new SessionMap(request);
Map application = new ApplicationMap(servletContext);
//把相应的Map和传入的内置对象交给了createContextMap方法
Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response);
return extraContext;
}
public HashMap<String,Object> createContextMap(Map requestMap,
Map parameterMap,
Map sessionMap,
Map applicationMap,
HttpServletRequest request,
HttpServletResponse response) {
//声明的大Map对象,存储了所有的小Map和JSP内置对象,此大Map返回
HashMap<String,Object> extraContext = new HashMap<String,Object>();
extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
extraContext.put(ActionContext.LOCALE, locale);
extraContext.put(StrutsStatics.HTTP_REQUEST, request);
extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);
return extraContext;
}
14:当用了struts2标签的时候<%@taglib prefix="s"uri="/struts-tags"%>,web.xml要改成下面的形式:
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>