Struts 2工作流程
[align=left][font=宋体]在前面[/font][font=宋体],已经介绍了[/font][font=Times New Roman]MVC[/font][font=宋体]设计思想和[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架的实现。而[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架本身大致可以分为[/font][font=Times New Roman]3[/font][font=宋体]个部分:核心控制器[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体]、业务控制器[/font][font=Times New Roman]Action[/font][font=宋体]和用户实现的企业业务逻辑组件。[/font][/align][align=left][/align][align=left][size=3][font=宋体]核心控制器[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体]是[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架的基础,包含了框架内部的控制流程和处理机制。业务控制器[/font][font=Times New Roman]Action[/font][font=宋体]和业务逻辑组件是需要用户来自己实现的。用户在开发[/font][font=Times New Roman]Action[/font][font=宋体]和业务逻辑组件的同时,还需要编写相关的配置文件,供核心控制器[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体]来使用。[/font][/size][/align][align=left][size=3][font=Times New Roman]Struts 2[/font][font=宋体]的工作流程相对于[/font][font=Times New Roman]Struts 1[/font][font=宋体]要简单,与[/font][font=Times New Roman]WebWork[/font][font=宋体]框架基本相同,所以说[/font][font=Times New Roman]Struts 2[/font][font=宋体]是[/font][font=Times New Roman]WebWork[/font][font=宋体]的升级版本。[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架按照模块来划分,可以分为[/font][font=Times New Roman]Servlet Filters[/font][font=宋体]、[/font][font=Times New Roman]Struts[/font][font=宋体]核心模块、拦截器和用户实现部分。[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架结构图如图[/font][font=Times New Roman]3.1[/font][font=宋体]所示。[/font][/size][/align][align=left][size=3]
[img]http://www.rsky.com.cn/Article/UploadFiles/200809/20080904122509618.jpg[/img][/size][size=3][/align][/size][align=left][font=宋体]图[/font][font=Times New Roman]3.1
Struts 2[/font][font=宋体]框架结构图[/font][/align][align=left][size=3][font=宋体]一个请求在[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架中的处理大概分为以下几个步骤。[/font][/size][/align][align=left][font=Times New Roman][size=3] [/size][/font][size=3][font=宋体]客户端提交一个([/font][font=Times New Roman]HttpServletRequest[/font][font=宋体])请求,如上文在浏览器中输入[/font][font=Times New Roman]http://localhost: 8080/bookcode/ch2/Reg.action[/font][font=宋体]就是提交一个([/font][font=Times New Roman]HttpServletRequest[/font][font=宋体])请求。[/font][/size][/align][align=left][font=Times New Roman][size=3] [/size][/font][size=3][font=宋体]请求被提交到一系列(主要是[/font][font=Times New Roman]3[/font][font=宋体]层)的过滤器([/font][font=Times New Roman]Filter[/font][font=宋体]),如([/font][font=Times New Roman]ActionContextCleanUp[/font][font=宋体]、其他过滤器([/font][font=Times New Roman]SiteMesh[/font][font=宋体]等)、[/font][font=Times New Roman] FilterDispatcher[/font][font=宋体])。注意:这里是有顺序的,先[/font][font=Times New Roman]ActionContext CleanUp[/font][font=宋体],再其他过滤器([/font][font=Times New Roman]Othter Filters[/font][font=宋体]、[/font][font=Times New Roman]SiteMesh[/font][font=宋体]等),最后到[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体]。[/font][/size][/align][align=left][font=Times New Roman][size=5pt]
[/size][size=3]FilterDispatcher[/size][/font][size=3][font=宋体]是控制器的核心,就是[/font][font=Times New Roman]MVC[/font][font=宋体]的[/font][font=Times New Roman]Struts 2[/font][font=宋体]实现中控制层([/font][font=Times New Roman]Controller[/font][font=宋体])的核心。[/font][/size][/align][align=left]
[font=Times New Roman][size=5pt]
[/size][size=3]FilterDispatcher[/size][/font][size=3][font=宋体]询问[/font][font=Times New Roman]ActionMapper[/font][font=宋体]是否需要调用某个[/font][font=Times New Roman]Action[/font][font=宋体]来处理这个([/font][font=Times New Roman]HttpServlet Request[/font][font=宋体])请求,如果[/font][font=Times New Roman]ActionMapper[/font][font=宋体]决定需要调用某个[/font][font=Times New Roman]Action[/font][font=宋体],[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体]则把请求的处理交给[/font][font=Times New Roman]ActionProxy[/font][font=宋体]。[/font][/size][/align][align=left]
[font=Times New Roman][size=5pt]
[/size][size=3]ActionProxy[/size][/font][size=3][font=宋体]通过[/font][font=Times New Roman]Configuration Manager[/font][font=宋体]([/font][font=Times New Roman]struts.xml[/font][font=宋体])询问框架的配置文件,找到需要调用的[/font][font=Times New Roman]Action[/font][font=宋体]类。例如,用户注册示例将找到[/font][font=Times New Roman]UserReg[/font][font=宋体]类。[/font][/size][/align][align=left]
[font=Times New Roman][size=5pt]
[/size][size=3]ActionProxy[/size][/font][size=3][font=宋体]创建一个[/font][font=Times New Roman]ActionInvocation[/font][font=宋体]实例,同时[/font][font=Times New Roman]ActionInvocation[/font][font=宋体]通过代理模式调用[/font][font=Times New Roman]Action[/font][font=宋体]。但在调用之前,[/font][font=Times New Roman]ActionInvocation[/font][font=宋体]会根据配置加载[/font][font=Times New Roman]Action[/font][font=宋体]相关的所有[/font][font=Times New Roman]Interceptor[/font][font=宋体](拦截器)。[/font][/size][/align][align=left][font=Times New Roman][size=3] [/size][/font][size=3][font=宋体]一旦[/font][font=Times New Roman]Action[/font][font=宋体]执行完毕,[/font][font=Times New Roman]ActionInvocation[/font][font=宋体]负责根据[/font][font=Times New Roman]struts.xml[/font][font=宋体]中的配置找到对应的返回结果[/font][font=Times New Roman]result[/font][font=宋体]。[/font][/size][/align][align=left][size=3][font=Times New Roman]Struts 2[/font][font=宋体]的核心控制器是[/font][font=Times New Roman]FilterDispatcher[/font][font=宋体],有[/font][font=Times New Roman]3[/font][font=宋体]个重要的方法:[/font][font=Times New Roman]destroy()[/font][font=宋体]、[/font][font=Times New Roman]doFilter()[/font][font=宋体]和[/font][font=Times New Roman]Init()[/font][font=宋体],可以在[/font][font=Times New Roman]Struts 2[/font][font=宋体]的下载文件夹中找到源代码,如代码[/font][font=Times New Roman]3.1[/font][font=宋体]所示。[/font][/size][/align][align=left][size=3][font=黑体][b]代码[/b][/font][b]3.1
[/b][font=黑体][b]核心控制器[/b][/font]FilterDispatcher[b][/b][/size][/align][align=left][size=2][font=Courier New]public class FilterDispatcher implements StrutsStatics, Filter {[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]定义一个[/font][font=Courier New]Log[/font][font=宋体]实例[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]private static final Log LOG = LogFactory.getLog(FilterDispatcher.class);[/font][/size][/align][align=left][size=2][font=Courier New]… ...[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]存放属性文件中的[/font][font=Courier New].STRUTS_I18N_ENCODING[/font][font=宋体]值[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]
private static String encoding;[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]定义[/font][font=Courier New]ActionMapper[/font][font=宋体]实例[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]
private static ActionMapper actionMapper;[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]定义[/font][font=Courier New]FilterConfig[/font][font=宋体]实例[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]
private FilterConfig filterConfig;[/font][/size][/align][align=left][size=2][font=Courier New]
protected Dispatcher dispatcher;[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]创建一个默认的[/font][font=Courier New]dispatcher[/font][font=宋体],初始化[/font][font=Courier New]filter[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]设置默认的[/font][font=Courier New]packages
*[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]
public void init(FilterConfig filterConfig) throws ServletException {[/font][/size][/align][align=left][size=2][font=Courier New]
this.filterConfig = filterConfig;[/font][/size][/align][align=left][size=2][font=Courier New]
dispatcher = createDispatcher(filterConfig);[/font][/size][/align][align=left][size=2][font=Courier New]
dispatcher.init();[/font][/size][/align][align=left][size=2][font=Courier New]
String param = filterConfig.getInitParameter("packages");[/font][/size][/align][align=left][size=2][font=Courier New]
String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";[/font][/size][/align][align=left][size=2][font=Courier New]
if (param != null) {[/font][/size][/align][align=left][size=2][font=Courier New]
packages = param + " " + packages;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
this.pathPrefixes = parse(packages);[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]销毁[/font][font=Courier New]filter[/font][font=宋体]方法[/font][/size][/align][align=left][size=2][font=Courier New]
public void destroy() {[/font][/size][/align][align=left][size=2][font=Courier New]
if (dispatcher == null) {[/font][/size][/align][align=left][size=2][font=Courier New]
LOG.warn("something is seriously wrong, Dispatcher is not initialized (null) ");[/font][/size][/align][align=left][size=2][font=Courier New]
} else {[/font][/size][/align][align=left][size=2][font=Courier New]
dispatcher.cleanup();[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]处理一个[/font][font=Courier New]Action[/font][font=宋体]或者资源请求[/font][/size][/align][align=left][size=2][font=Courier New]
* <p/>[/font][/size][/align][align=left][size=2][font=Courier New]
* filter[/font][font=宋体]尝试将请求同[/font][font=Courier New]action mapping[/font][font=宋体]相匹配[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]如果找到,将执行[/font][font=Courier New]dispatcher[/font][font=宋体]的[/font][font=Courier New]serviceAction[/font][font=宋体]方法[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]如果[/font][font=Courier New]Action[/font][font=宋体]处理失败[/font][font=Courier New], doFilter[/font][font=宋体]将建立一个异常[/font][/size][/align][align=left][size=2][font=Courier New]
* <p/>[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]如果请求静态资源[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]资源将被直接复制给[/font][font=Courier New] response[/font][/size][/align][align=left][size=2][font=Courier New]
* <p/>[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]如果找不到匹配[/font][font=Courier New]Action [/font][font=宋体]或者静态资源,则直接跳出[/font][/size][/align][align=left][size=2][font=Courier New]
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {[/font][/size][/align][align=left][size=2][font=Courier New]
HttpServletRequest request = (HttpServletRequest) req;[/font][/size][/align][align=left][size=2][font=Courier New]
HttpServletResponse response = (HttpServletResponse) res;[/font][/size][/align][align=left][size=2][font=Courier New]
ServletContext servletContext = getServletContext();[/font][/size][/align][align=left][size=2][font=Courier New]
String timerKey = "FilterDispatcher_doFilter: ";[/font][/size][/align][align=left][size=2][font=Courier New]
try {[/font][/size][/align][align=left][size=2][font=Courier New]
UtilTimerStack.push(timerKey);[/font][/size][/align][align=left][size=2][font=Courier New]
request = prepareDispatcherAndWrapRequest(request, response);[/font][/size][/align][align=left][size=2][font=Courier New]
ActionMapping mapping;[/font][/size][/align][align=left][size=2][font=Courier New]
try {[/font][/size][/align][align=left][size=2][font=Courier New]
mapping=actionMapper.getMapping(request, dispatcher.getConfigurationManager());[/font][/size][/align][align=left][size=2][font=Courier New]
} catch (Exception ex) {[/font][/size][/align][align=left][size=2][font=Courier New]
LOG.error("error getting ActionMapping", ex);[/font][/size][/align][align=left][size=2][font=Courier New]
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);[/font][/size][/align][align=left][size=2][font=Courier New]
return;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
if (mapping == null) {[/font][/size][/align][align=left][size=2][font=Courier New]
String resourcePath = RequestUtils.getServletPath(request);[/font][/size][/align][align=left][size=2][font=Courier New]
if ("".equals(resourcePath) && null != request.getPathInfo()) {[/font][/size][/align][align=left][size=2][font=Courier New]
resourcePath = request.getPathInfo();[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
if (serveStatic && resourcePath.startsWith("/struts")) {[/font][/size][/align][align=left][size=2][font=Courier New]
String name = resourcePath.substring("/struts".length());[/font][/size][/align][align=left][size=2][font=Courier New]
findStaticResource(name, request, response);[/font][/size][/align][align=left][size=2][font=Courier New]
} else {[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]为一个普通的[/font][font=Courier New]request, [/font][font=宋体]则通过[/font][/size][/align][align=left][size=2][font=Courier New]
chain.doFilter(request, response);[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
return;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]/**[/font][/size][/align][align=left][size=2][font=Courier New]*[/font][font=宋体]这个方法询问[/font][font=Courier New]ActionMapper[/font][font=宋体]是否需要调用某个[/font][font=Courier New]Action[/font][font=宋体]来处理这个([/font][font=Courier New]request[/font][font=宋体])请求,[/font][/size][/align][align=left][size=2][font=Courier New]*[/font][font=宋体]如果[/font][font=Courier New]ActionMapper[/font][font=宋体]决定需要调用某个[/font][font=Courier New]Action[/font][font=宋体],[/font][/size][/align][align=left][size=2][font=Courier New]*FilterDispatcher[/font][font=宋体]则把请求的处理交给[/font][font=Courier New]ActionProxy[/font][/size][/align][align=left][size=2][font=Courier New]
dispatcher.serviceAction(request, response, servletContext, mapping);[/font][/size][/align][align=left][size=2][font=Courier New]
} finally {[/font][/size][/align][align=left][size=2][font=Courier New]
try {[/font][/size][/align][align=left][size=2][font=Courier New]
ActionContextCleanUp.cleanUp(req);[/font][/size][/align][align=left][size=2][font=Courier New]
} finally {[/font][/size][/align][align=left][size=2][font=Courier New]
UtilTimerStack.pop(timerKey);[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]}[/font][/size][/align][align=left][size=2][font=Courier New]… …[/font][/size][/align][align=left][size=2][font=Courier New]}[/font][/size][/align][align=left][size=3][font=宋体]在[/font][font=Times New Roman]doFilter()[/font][font=宋体]方法中,将调用[/font][font=Times New Roman]dispatcher.serviceAction[/font][font=宋体],该方法如果找到相应的[/font][font=Times New Roman]Action[/font][font=宋体],将把用户请求交给[/font][font=Times New Roman]ActionProxy[/font][font=宋体]。[/font][font=Times New Roman]serviceAction()[/font][font=宋体]代码在[/font][font=Times New Roman]Dispatcher.java[/font][font=宋体]中,如代码[/font][font=Times New Roman]3.2[/font][font=宋体]所示。[/font][/size][/align] [align=left][size=3][font=黑体]代码[/font]3.2
Dispatcher[font=黑体]类[/font][/size][/align][align=left][size=2][font=Courier New]public class Dispatcher {[/font][/size][/align][align=left][size=2][font=Courier New]...[/font][/size][/align][align=left][size=2][font=Courier New]/**[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]为[/font][font=Courier New]mapping[/font][font=宋体]加载类,并调用相应的方法或者直接返回[/font][font=Courier New]result[/font][/size][/align][align=left][size=2][font=Courier New]
* <p/>[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]根据用户请求的参数,建立[/font][font=Courier New]Action[/font][font=宋体]上下文[/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]根据指定的[/font][font=Courier New]Action’[/font][font=宋体]名称和包空间名称,加载一个[/font][font=Courier New]Action[/font][font=宋体]代理[/font][font=Courier New] <tt>ActionProxy</tt> [/font][/size][/align][align=left][size=2][font=Courier New]
* [/font][font=宋体]然后[/font][font=Courier New]Action[/font][font=宋体]的相应方法将被执行,[/font][/size][/align][align=left][size=2][font=Courier New]
*/[/font][/size][/align][align=left][size=2][font=Courier New]
[b]public[/b] [b]void[/b] serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) [b]throws[/b] ServletException {[/font][/size][/align][align=left][size=2][font=Courier New]
Map<String, Object> extraContext = createContextMap(request, response, mapping, context);[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]如果存在一个值栈,则建立一个新的并复制以备[/font][font=Courier New]Action[/font][font=宋体]使用[/font][/size][/align][align=left][size=2][font=Courier New]
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);[/font][/size][/align][align=left][size=2][font=Courier New]
[b]if[/b] (stack!= [b]null[/b]) {[/font][/size][/align][align=left][size=2][font=Courier New]
extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
String timerKey = "Handling request from Dispatcher";[/font][/size][/align][align=left][size=2][font=Courier New]
[b]try[/b] {[/font][/size][/align][align=left][size=2][font=Courier New]
UtilTimerStack.push(timerKey);[/font][/size][/align][align=left][size=2][font=Courier New]
String namespace = mapping.getNamespace();[/font][/size][/align][align=left][size=2][font=Courier New]
String name = mapping.getName();[/font][/size][/align][align=left][size=2][font=Courier New]
String method = mapping.getMethod();[/font][/size][/align][align=left][size=2][font=Courier New]
Configuration config = configurationManager.getConfiguration();[/font][/size][/align][align=left][size=2][font=Courier New]
//FilterDispatcher[/font][font=宋体]把请求的处理交给[/font][font=Courier New]ActionProxy[/font][/size][/align][align=left][size=2][font=Courier New]
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.[b]class[/b]).createActionProxy(namespace, name, extraContext, [b]true[/b], [b]false[/b]);[/font][/size][/align][align=left][size=2][font=Courier New]
proxy.setMethod(method);[/font][/size][/align][align=left][size=2][font=Courier New]
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());[/font][/size][/align][align=left][size=2][font=Courier New]
//ActionMapping [/font][font=宋体]直接返回一个[/font][font=Courier New]result[/font][/size][/align][align=left][size=2][font=Courier New]
[b]if[/b] (mapping.getResult() != [b]null[/b]) {[/font][/size][/align][align=left][size=2][font=Courier New]
Result result = mapping.getResult();[/font][/size][/align][align=left][size=2][font=Courier New]
result.execute(proxy.getInvocation());[/font][/size][/align][align=left][size=2][font=Courier New]
} [b]else[/b] {[/font][/size][/align][align=left][size=2][font=Courier New]
proxy.execute();[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
[b]if[/b] (stack != [b]null[/b]) {[/font][/size][/align][align=left][size=2][font=Courier New]
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
} [b]catch[/b] (ConfigurationException e) {[/font][/size][/align][align=left][size=2][font=Courier New]
LOG.error("Could not find action or result", e);[/font][/size][/align][align=left][size=2][font=Courier New]
sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);[/font][/size][/align][align=left][size=2][font=Courier New]
} [b]catch[/b] (Exception e) {[/font][/size][/align][align=left][size=2][font=Courier New]
[b]throw[/b] [b]new[/b] ServletException(e);[/font][/size][/align][align=left][size=2][font=Courier New]
} [b]finally[/b] {[/font][/size][/align][align=left][size=2][font=Courier New]
UtilTimerStack.pop(timerKey);[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]…[/font][/size][/align][align=left][size=2][font=宋体]}[/font][/size][/align][align=left][size=3][font=宋体]从上面代码中可以看出来,[/font][font=Times New Roman]Struts 2[/font][font=宋体]用于处理用户请求的[/font][font=Times New Roman]Action[/font][font=宋体]实例,并不是用户实现的业务控制器,而是[/font][font=Times New Roman]Action[/font][font=宋体]代理。关于[/font][font=Times New Roman]Action[/font][font=宋体]代理相关内容,读者可以参考拦截器章节的介绍。[/font][/size][/align][align=left][size=3][/size][font=宋体][size=11pt]★[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=黑体][size=11pt]提示[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=宋体][size=11pt]★[/size][/font][size=11pt][/size][/align][align=left][size=3][font=Times New Roman][font=方正楷体简体]前面一直在说[/font]Action[font=方正楷体简体]可以是一个普通的[/font]Java[font=方正楷体简体]类,与[/font]Servlet API[font=方正楷体简体]完全分离,但是为了实现业务逻辑,[/font]Action[font=方正楷体简体]需要使用[/font]HttpServletRequest[font=方正楷体简体]内容。[/font][/font][/size][/align][align=left][size=12.0pt][font=Times New Roman][size=3] [/size][/font][/size][/align][align=left][size=3][font=Times New Roman]Struts 2[/font][font=宋体]设计的精巧之处就是使用了[/font][font=Times New Roman]Action[/font][font=宋体]代理,[/font][font=Times New Roman]Action[/font][font=宋体]代理可以根据系统的配置,加载一系列的拦截器,由拦截器将[/font][font=Times New Roman]HttpServletRequest[/font][font=宋体]参数解析出来,传入[/font][font=Times New Roman]Action[/font][font=宋体]。同样,[/font][font=Times New Roman]Action[/font][font=宋体]处理的结果也是通过拦截器传入[/font][font=Times New Roman]HttpServletResponse[/font][font=宋体],然后由[/font][font=Times New Roman]HttpServletRequest[/font][font=宋体]传给用户。[/font][/size][/align][align=left][size=3][font=宋体]其实,该处理过程是典型的[/font][font=Times New Roman]AOP[/font][font=宋体](面向切面编程)的方式,读者可以在后面详细了解到。[/font][font=Times New Roman]Struts 2[/font][font=宋体]处理过程模型如图[/font][font=Times New Roman]3.2[/font][font=宋体]所示。[/font][/size][/align][align=left][size=3]
[img]http://www.rsky.com.cn/Article/UploadFiles/200809/20080904122510954.jpg[/img][/size][size=3][/align][/size][align=left][font=宋体]图[/font][font=Times New Roman]3.2
Struts 2[/font][font=宋体]处理过程模型[/font][/align][align=left][font=宋体][size=11pt]★[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=黑体][size=11pt]说明[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=宋体][size=11pt]★[/size][/font][size=11pt][/size][/align][align=left][size=3][font=Times New Roman][font=方正楷体简体]拦截器是[/font]Struts 2[font=方正楷体简体]框架的核心,通过拦截器,实现了[/font]AOP[font=方正楷体简体](面向切面编程)。使用拦截器,可以简化[/font]Web[font=方正楷体简体]开发中的某些应用,例如,权限拦截器可以简化[/font]Web[font=方正楷体简体]应用中的权限检查。[/font][/font][/size][/align][align=left]
[/align][font=宋体][align=left][size=3][font=宋体]业务控制器[/font][font=Times New Roman]Action[/font][font=宋体]是由开发者自己编写实现的,[/font][font=Times New Roman]Action[/font][font=宋体]类可以是一个简单的[/font][font=Times New Roman]Java[/font][font=宋体]类,与[/font][font=Times New Roman]Servlet API[/font][font=宋体]完全分离。[/font][font=Times New Roman]Action[/font][font=宋体]一般都有一个[/font][font=Times New Roman]execute()[/font][font=宋体]方法,也可以定义其他业务控制方法,详细内容将在后面介绍。[/font][/size][/align][align=left][size=3][font=Times New Roman]Action[/font][font=宋体]的[/font][font=Times New Roman]execute()[/font][font=宋体]返回一个[/font][font=Times New Roman]String[/font][font=宋体]类型值,这与[/font][font=Times New Roman]Struts 1[/font][font=宋体]返回的[/font][font=Times New Roman]ActionForward[/font][font=宋体]相比,简单易懂。[/font][font=Times New Roman]Struts 2[/font][font=宋体]提供了一个[/font][font=Times New Roman]ActionSupport[/font][font=宋体]工具类,该类实现了[/font][font=Times New Roman]Action[/font][font=宋体]接口和[/font][font=Times New Roman]validate()[/font][font=宋体]方法,一般开发者编写[/font][font=Times New Roman]Action[/font][font=宋体]可以直接继承[/font][font=Times New Roman]ActionSupport[/font][font=宋体]类。编写[/font][font=Times New Roman]Action[/font][font=宋体]类后,开发者还必须在配置文件中配置[/font][font=Times New Roman]Action[/font][font=宋体]。一个[/font][font=Times New Roman]Action[/font][font=宋体]的配置应该包含下面几个元素:[/font][/size][/align][align=left][size=3]—[/size]
[size=3][font=宋体]该[/font][font=Times New Roman]Action[/font][font=宋体]的[/font][font=Times New Roman]name[/font][font=宋体],即用户请求所指向的[/font][font=Times New Roman]URL[/font][font=宋体]。[/font][/size][/align][align=left][size=3]—[/size]
[size=3][font=Times New Roman]Action[/font][font=宋体]所对应的[/font][font=Times New Roman]class[/font][font=宋体]元素,对应[/font][font=Times New Roman]Action[/font][font=宋体]类的位置。[/font][/size][/align][align=left][size=3]—[/size]
[size=3][font=宋体]指定[/font][font=Times New Roman]result[/font][font=宋体]逻辑名称和实际资源的定位。[/font][/size][/align][align=left][size=3][font=Times New Roman]Action[/font][font=宋体]是业务控制器,笔者建议在编写[/font][font=Times New Roman]Action[/font][font=宋体]的时候,尽量避免将业务逻辑放到其中,尽量减少[/font][font=Times New Roman]Action[/font][font=宋体]与业务逻辑模块或者组件的耦合程度。[/font][/size][/align][align=left][size=3]
[/size] [/align][size=3][font=宋体][align=left][size=3][font=宋体]业务模型组件可以是实现业务逻辑的模块,可以是[/font][font=Times New Roman]EJB[/font][font=宋体]、[/font][font=Times New Roman]POJO[/font][font=宋体]或者[/font][font=Times New Roman]JavaBean[/font][font=宋体],在实际开发中,对业务模型组件的区分和定义也是比较模糊的,实际上也超出了[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架的范围。不同的开发者或者团队,都有自己的方式来实现业务逻辑模块,[/font][font=Times New Roman]Struts 2[/font][font=宋体]框架的目的就是使用[/font][font=Times New Roman]Action[/font][font=宋体]来调用业务逻辑模块。例如一个银行存款的业务逻辑模块,如代码[/font][font=Times New Roman]3.3[/font][font=宋体]所示。[/font][/size][/align][align=left][size=3][font=黑体]代码[/font]3.3
[font=黑体]模拟一个银行业务的实现模块[/font][/size][/align][align=left][size=2][font=Courier New]package ch3;[/font][/size][/align][align=left][size=2][font=Courier New]public class Bank {[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]定义银行账户[/font][/size][/align][align=left][size=2][font=Courier New]
private String accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]定义操作金额[/font][/size][/align][align=left][size=2][font=Courier New]
private double money;[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]属性的[/font][font=Courier New]getter[/font][font=宋体]和[/font][font=Courier New]setter[/font][font=宋体]方法[/font][/size][/align][align=left][size=2][font=Courier New]
public String getAccounts() {[/font][/size][/align][align=left][size=2][font=Courier New]
return accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
public void setAccounts(String accounts) {[/font][/size][/align][align=left][size=2][font=Courier New]
this.accounts = accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
public double getMoney() {[/font][/size][/align][align=left][size=2][font=Courier New]
return money;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
public void setMoney(double money) {[/font][/size][/align][align=left][size=2][font=Courier New]
this.money = money;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]模拟银行存款方法[/font][/size][/align][align=left][size=2][font=Courier New]
public boolean saving(String accounts, double money) {[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]调用[/font][font=Courier New]DAO[/font][font=宋体]等模块读写数据库[/font][/size][/align][align=left][size=2][font=Courier New]
return dosomeing();[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][font=Courier New][size=2] [/size][/font][/align][align=left][size=2][font=Courier New]}[/font][/size][/align][align=left][size=3][font=宋体]上面实例在实际开发中没有任何意义,这里只是作为业务逻辑模块来说明,在执行[/font][font=Times New Roman]saving(String accounts,double money)[/font][font=宋体]方法时,可以调用相应的数据库访问其他组件,来实现存款操作。使用[/font][font=Times New Roman]Action[/font][font=宋体]调用该业务逻辑组件可以在[/font][font=Times New Roman]execute()[/font][font=宋体]方法中实现,如代码[/font][font=Times New Roman]3.4[/font][font=宋体]所示。[/font][/size][/align][/font][/size][/font] [align=left][size=3][font=黑体]代码[/font]3.4
[font=黑体]业务控制器[/font]Bank_Saving_Action[/size][/align][align=left][size=2][font=Courier New]package ch3;[/font][/size][/align][align=left][size=2][font=Courier New]import java.util.Map;[/font][/size][/align][align=left][size=2][font=Courier New]import com.opensymphony.xwork2.ActionContext;[/font][/size][/align][align=left][size=2][font=Courier New]import com.opensymphony.xwork2.ActionSupport;[/font][/size][/align][align=left][font=Courier New][size=2] [/size][/font][/align][align=left][size=2][font=Courier New]public class Bank_Saving_Action extends ActionSupport {[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]定义银行账户[/font][/size][/align][align=left][size=2][font=Courier New]
private String accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]定义操作金额[/font][/size][/align][align=left][size=2][font=Courier New]
private double money;[/font][/size][/align][align=left][size=2][font=Courier New]
[/font][/size][/align][align=left][size=2][font=Courier New]
public String execute() throws Exception {[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]创建[/font][font=Courier New]Bank[/font][font=宋体]实例[/font][/size][/align][align=left][size=2][font=Courier New]
Bank bk=new Bank();[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]调用存款方法[/font][/size][/align][align=left][size=2][font=Courier New]
if (bk.saving(accounts, money)){[/font][/size][/align][align=left][size=2][font=Courier New]
return SUCCESS;[/font][/size][/align][align=left][size=2][font=Courier New]
}else{[/font][/size][/align][align=left][size=2][font=Courier New]
return ERROR;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=2][font=Courier New]}[/font][/size][/align][align=left][size=2][font=Courier New]
//[/font][font=宋体]属性的[/font][font=Courier New]getter[/font][font=宋体]和[/font][font=Courier New]setter[/font][font=宋体]方法[/font][/size][/align][align=left][size=2][font=Courier New]
public String getAccounts() {[/font][/size][/align][align=left][size=2][font=Courier New]
return accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][font=Courier New][size=2] [/size][/font][/align][align=left][size=2][font=Courier New]
public void setAccounts(String accounts) {[/font][/size][/align][align=left][size=2][font=Courier New]
this.accounts = accounts;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][font=Courier New][size=2] [/size][/font][/align][align=left][size=2][font=Courier New]
public double getMoney() {[/font][/size][/align][align=left][size=2][font=Courier New]
return money;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][font=Courier New][size=2] [/size][/font][/align][align=left][size=2][font=Courier New]
public void setMoney(double money) {[/font][/size][/align][align=left][size=2][font=Courier New]
this.money = money;[/font][/size][/align][align=left][size=2][font=Courier New]
}[/font][/size][/align][align=left][size=3][font=Times New Roman]Bank_Saving_Action[/font][font=宋体]演示了对银行存款业务逻辑组件的调用,这里是通过在[/font][font=Times New Roman]Action[/font][font=宋体]中创建业务逻辑组件实例的方式实现的。在实际开发中,可以使用静态工厂获得业务逻辑组件的实例或者使用[/font][font=Times New Roman]IoC[/font][font=宋体]容器来管理。[/font][font=Times New Roman]Action[/font][font=宋体]中不实现任何业务逻辑,只是负责组织调度业务逻辑组件。调用关系如图[/font][font=Times New Roman]3.3[/font][font=宋体]所示。[/font][/size][/align][align=left][size=3]
[img]http://www.rsky.com.cn/Article/UploadFiles/200809/20080904122510473.jpg[/img][/size][size=3][/align][/size][align=left][font=宋体]图[/font][font=Times New Roman]3.3
[/font][font=宋体]调用业务逻辑组件[/font][/align][align=left][font=宋体][size=11pt]★[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=黑体][size=11pt]说明[/size][/font][size=11pt][font=Times New Roman] [/font][/size][font=宋体][size=11pt]★[/size][/font][size=11pt][/size][/align][align=left][size=3][font=Times New Roman][font=方正楷体简体]业务控制器[/font]Action[font=方正楷体简体]一般情况下不是直接创建业务逻辑组件实例,而是使用工厂模式或者是从[/font]Spring[font=方正楷体简体]容器中获得业务逻辑组件实例,这样可以提高系统的性能。[/font][/font][/size][/align][align=left][size=3][font=Times New Roman]
[/font][/size] [/align][size=3][font=Times New Roman][font=方正楷体简体][align=left][size=3][font=Times New Roman]Struts 1[/font][font=宋体]只能支持[/font][font=Times New Roman]JSP[/font][font=宋体]作为视图资源,而[/font][font=Times New Roman]Struts 2[/font][font=宋体]的进步之处就是可以使用其他视图技术,如[/font][font=Times New Roman]FreeMarker[/font][font=宋体]、[/font][font=Times New Roman]Velocity[/font][font=宋体]等。通过前面的学习和示例,读者会知道[/font][font=Times New Roman]Action[/font][font=宋体]的返回结果只是一个简单的字符串,也就是一个逻辑上的视图名称,要与实际视图资源对应,必须通过配置文件来实现。[/font][/size][/align][align=left][size=3][font=宋体]在[/font][font=Times New Roman]struts.xml[/font][font=宋体]配置文件中,每一个[/font][font=Times New Roman]Aciton[/font][font=宋体]定义都有[/font][font=Times New Roman]name[/font][font=宋体]和[/font][font=Times New Roman]class[/font][font=宋体]属性,同时还要指定[/font][font=Times New Roman]result[/font][font=宋体]元素。[/font][font=Times New Roman]result[/font][font=宋体]元素指定了逻辑视图名称和实际视图的对应关系。每个[/font][font=Times New Roman]result[/font][font=宋体]都有一个[/font][font=Times New Roman]type[/font][font=宋体]属性,前面介绍的[/font][font=Times New Roman]struts.xml[/font][font=宋体]中并没有显式指定[/font][font=Times New Roman]type[/font][font=宋体]值,即使用了默认的[/font][font=Times New Roman]type[/font][font=宋体]类型:[/font][font=Times New Roman]dispatcher[/font][font=宋体],该结果类型支持[/font][font=Times New Roman]JSP[/font][font=宋体]所谓视图资源。[/font][/size][/align][align=left][size=3][font=宋体]对于[/font][font=Times New Roman]Struts 2[/font][font=宋体]的视图技术和[/font][font=Times New Roman]result[/font][font=宋体]返回类型,后面将详细介绍。总结[/font][font=Times New Roman]Strurs 2[/font][font=宋体]的框架工作流程,发现与[/font][font=Times New Roman]WebWork[/font][font=宋体]基本相同,可以参考第[/font][font=Times New Roman]1[/font][font=宋体]章关于[/font][font=Times New Roman]WebWork[/font][font=宋体]框架的介绍和流程图(如图[/font][font=Times New Roman]1.8[/font][font=宋体]所示)。[/font][/size][/align][/font][/font][/size]
页:
[1]