stripes actionresolve(一)
3.5 ActionResolverを解析stripesのライフサイクルを理解し、構成可能なコンポーネントを構成することによってどのように組み合わせるか、interceptorを通じてこれらのコンポーネントを直列に接続する方法についても理解しました.各ステップの各コンポーネントが何をしているかを理解する必要があります.まず、ActionResolver、つまりstripesがurl pathを介して対応するactionにマッピングされる方法について理解します.DispatcherServiceletの最初のライフステージはresolveActionBean(ctx)です.この方法の主体は:DispatcherHelper.JAva:
上の最も重要な部分は
ActionBean bean = StripesFilter.getConfiguration()
.getActionResolver().getActionBean(context);
これは
configuration
構成またはデフォルトの
ActionResolver
.
Stripes
デフォルトは
NameBasedActionResolver
;
継承
AnnotatedClassActionResolver
.その本質は採用である
annotation
を選択します.カスタマイズ
ActionResolver
を選択します.
AnnotatedClassActionResolver
.によって
ActionResolver
構成可能なコンポーネントです.
stripes
起動時に生成されます
ActionResolver
のサブクラスのインスタンスを実行します.
init(Configuraton)
方法.
まず見てみましょう
NameBasedActionResolver
.getActionBean(context)
ああ、この方法は
AnnotatedClassActionResolver
;
そのOverride親の同名メソッド.親クラスの同名メソッドを先に実行し、異常(すなわち対応するactionbeanが見つからない)が発生した場合、最適なjspファイルがあるかどうかを探す機能です.例えばuser.を要求するアクション、userを探します.jspとか.
この方法は簡単です.urlBindingのような適切なjspページを見つけるのはView Accountです.action ViewAccount.jsp viewAccount.jsp、view_account.jspは、その後、3つのjspファイルが存在しないことを確認し、存在する場合は最初にjspファイルが存在することを取得します.
今戻る
handleActionBeanNotFound
を選択します.
Resolution
あ、じゃあ、次は上のプログラムを統一するために、これを使います.
Resolution
生成
DefaultViewActionBean(view);
イベントメソッドを解析するときに、
annotion
見つからない場合は、戻りタイプを探します.
Resolution
の非抽象的な方法同名の方法.イベントの処理方法には一般的にパラメータはありません.
これで
actionResolver
パスに対応する
actionbean
クラスは、クラスとイベントの処理方法の関係を初期化します.
public static Resolution resolveActionBean(final ExecutionContext ctx) throws Exception {
return ctx.wrap( new Interceptor() {
public Resolution intercept(ExecutionContext ctx) throws Exception {
// Look up the ActionBean and set it on the context
ActionBeanContext context = ctx.getActionBeanContext();
ActionBean bean = StripesFilter.getConfiguration()
.getActionResolver().getActionBean(context);
// actionbean ExcuteContext 。
ctx.setActionBean(bean);
// actionbean request actionBean , // actionbean
HttpServletRequest request = context.getRequest(); request.setAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN, bean);
return null; } }); }
上の最も重要な部分は
ActionBean bean = StripesFilter.getConfiguration()
.getActionResolver().getActionBean(context);
これは
configuration
構成またはデフォルトの
ActionResolver
.
Stripes
デフォルトは
NameBasedActionResolver
;
継承
AnnotatedClassActionResolver
.その本質は採用である
annotation
を選択します.カスタマイズ
ActionResolver
を選択します.
AnnotatedClassActionResolver
.によって
ActionResolver
構成可能なコンポーネントです.
stripes
起動時に生成されます
ActionResolver
のサブクラスのインスタンスを実行します.
init(Configuraton)
方法.
まず見てみましょう
NameBasedActionResolver
.getActionBean(context)
ああ、この方法は
AnnotatedClassActionResolver
;
public ActionBean getActionBean(ActionBeanContext context) throws StripesServletException {
HttpServletRequest request = context.getRequest();
String path = getRequestedPath(request);
// getActionBean(context, path) , 、、//NameBasedActionResolver, , 。
ActionBean bean = getActionBean(context, path);
// actionbean request __stripes_resolved_action。
request.setAttribute(RESOLVED_ACTION, getUrlBindingFromPath(path));
return bean;
}
@Override public ActionBean getActionBean(ActionBeanContext
context, String urlBinding) throws StripesServletException {
try { return super.getActionBean(context, urlBinding); }
catch (StripesServletException sse) {
ActionBean bean = handleActionBeanNotFound(context, urlBinding);
if (bean != null) { bean.setContext(context);
return bean; }
else { throw sse; } } }
そのOverride親の同名メソッド.親クラスの同名メソッドを先に実行し、異常(すなわち対応するactionbeanが見つからない)が発生した場合、最適なjspファイルがあるかどうかを探す機能です.例えばuser.を要求するアクション、userを探します.jspとか.
protected ActionBean handleActionBeanNotFound(ActionBeanContext context, String urlBinding) {
ActionBean bean = null;
Resolution view = findView(urlBinding);
if (view != null) {
log.debug("Could not find an ActionBean bound to '", urlBinding, "', but found a view ","at '", view, "'. Forwarding the user there instead.");
bean = new DefaultViewActionBean(view); }
return bean; }
findView(urlBinding):
protected Resolution findView(String urlBinding) {
int lastPeriod = urlBinding.lastIndexOf('.');
String path = urlBinding.substring(0, urlBinding.lastIndexOf("/") + 1);
String name = (lastPeriod >= path.length()) ? urlBinding.substring(path.length(), lastPeriod) : urlBinding.substring(path.length());
ServletContext ctx = StripesFilter.getConfiguration().getBootstrapPropertyResolver().getFilterConfig().getServletContext();
try {
// This will try /account/ViewAccount.jsp
String jsp = path + name + ".jsp";
if (ctx.getResource(jsp) != null) {
return new ForwardResolution(jsp); }
// This will try /account/viewAccount.jsp
name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
jsp = path + name + ".jsp";
if (ctx.getResource(jsp) != null) {
return new ForwardResolution(jsp); }
// And finally this will try /account/view_account.jsp
StringBuilder builder = new StringBuilder();
for (int i=0; i<name.length(); ++i) {
char ch = name.charAt(i);
if (Character.isUpperCase(ch)) {
builder.append("_");
builder.append(Character.toLowerCase(ch));
}
else { builder.append(ch); } }
jsp = path + builder.toString() + ".jsp";
if (ctx.getResource(jsp) != null) {
return new ForwardResolution(jsp); } return null;
} catch (MalformedURLException mue) {
return null; } }}
この方法は簡単です.urlBindingのような適切なjspページを見つけるのはView Accountです.action ViewAccount.jsp viewAccount.jsp、view_account.jspは、その後、3つのjspファイルが存在しないことを確認し、存在する場合は最初にjspファイルが存在することを取得します.
今戻る
handleActionBeanNotFound
を選択します.
Resolution
あ、じゃあ、次は上のプログラムを統一するために、これを使います.
Resolution
生成
DefaultViewActionBean(view);
class DefaultViewActionBean implements ActionBean {
private ActionBeanContext context;
private Resolution view;
public DefaultViewActionBean(Resolution view) { this.view = view; }
public void setContext(ActionBeanContext context) { this.context = context; }
public ActionBeanContext getContext() { return this.context; }
public Resolution view() { return view; }}
このactionbeanは簡単です.DefaultView(Resolution view){this.view=view;}この方法.これは主に全体のコードと統一するためです.次にgetActionBean(ActionBeanContext,String)に戻ってみましょう.public ActionBean getActionBean(ActionBeanContext context, String path)
throws StripesServletException {
String urlBinding = getUrlBindingFromPath(path);
Class<? extends ActionBean> beanClass = this.formBeans.get(urlBinding);
ActionBean bean;
if (beanClass == null) {
throw new StripesServletException(“emit”); }
try { HttpServletRequest request = context.getRequest();
if (beanClass.isAnnotationPresent(SessionScope.class)) {
bean = (ActionBean) request.getSession().getAttribute(path);
if (bean == null) {
bean = makeNewActionBean(beanClass, context);
equest.getSession().setAttribute(path, bean); }
bean.setContext(context); }
else {
bean = (ActionBean) request.getAttribute(path);
if (bean == null) {
bean = makeNewActionBean(beanClass, context);
bean.setContext(context);
request.setAttribute(path, bean); } }
return bean; }
catch (Exception e) { 。。。。。 } }
このコードはまず経路からurlBindingを見つけ、urlBindingから対応するactionbeanを見つけます.この2つは後で分析して、まず下のコードを見て、以下は簡単で、コードからactionbeanは@SessionScopeを通じてsessionの中で保存することができることを見ることができます.一般的にrequestに保存されています.プログラマを呼び出すことで実現されるbean.setContext(context);コンテキストをactionbeanに渡す.次にactionbeanのインスタンスをrequest(session)のpathプロパティに配置します.上記の質問に戻り、urlBinding=getUrlBindingFromPath(path):String getUrlBindingFromPath(String path) {
String binding = null;
while (binding == null && path != null) {
if (this.formBeans.containsKey(path)) {
binding = path; } else {
int lastSlash = path.lastIndexOf("/");
if (lastSlash > 0) {
path = path.substring(0, lastSlash); }
else { path = null; } } }
return binding; }
この問題を解決する前に、pathがどのようなフォーマットで、どのように来たのかを知らなければなりません.Pathは、getActionBean(ActionBeanContext context)のHttpServertRequest request=contextである.getRequest(); String path = getRequestedPath(request);得られた:: protected String getRequestedPath(HttpServletRequest request) { String servletPath = null, pathInfo = null;
if (request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH) != null) { servletPath = (String) request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH);
pathInfo = (String) request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH_INFO); }
else { servletPath = request.getServletPath();
pathInfo = request.getPathInfo();
}
return (servletPath == null ? "" : servletPath) + (pathInfo == null ? "" : pathInfo); }
servlet仕様では、urlパスを3つの部分requestURI=contextPath+servletPath+pathInfoにする.contextPathは私たちのアプリケーションシステムの名前です.例えば、第2章の例はregisterです.上のプログラムは、ルートディレクトリを取得した後のURLアドレス部分です.例えば、/user/register.action/view.私たちはこのような構造であることを知っていて、上のプログラムがthisからであることを理解するのは難しくありません.formBeansの検索は/user/registerと一致していますか?Action/view同じkey.ないなら見てみろActionこれは同じです.なければ/userと同じkeyを見ます.これ以上ないのはnullです.この方法と上記の方法ではthisが現れます.formBeans、これは何ですか.mapは間違っていません.rivate Map<String,Class<? extends ActionBean>> formBeans =
new HashMap<String,Class<? extends ActionBean>>();
AnnotatedClassActionResolver , formBeans init(Configuration) 。 AnnotatedClassActionResolver init() , : NameBasedActionResolver , init(Configuration), NameBasedActionResolver init() 。
@Override
public void init(Configuration configuration) throws Exception {
super.init(configuration);
addActionBean(DefaultViewActionBean.class);
}
AnnotatedClassActionResolver。 DefaultViewActionBean bean。 jsp 。 。
public void init(Configuration configuration) throws Exception {
is.configuration = configuration;
Set<Class<? extends ActionBean>> beans = findClasses(ActionBean.class);
ActionClassCache.init(beans);
for (Class<? extends ActionBean> clazz : beans) {
addActionBean(clazz); }
}
この方法では、すべてのactionbeanを見つけてからキャッシュに保存します.その後、各beanをそれぞれ処理する.protected <T> Set<Class<? extends T>> findClasses(Class<T> parentType) {
ResolverUtil<T> resolver = new ResolverUtil<T>();
resolver.setPackageFilters(getPackageFilters());
resolver.setLocationFilters(getUrlFilters());
if (!resolver.loadImplementationsFromContextClassloader(parentType)) {
ServletContext context = this.configuration.getBootstrapPropertyResolver()
.getFilterConfig().getServletContext();
resolver.loadImplementationsFromServletContext(parentType, context);
}
return resolver.getClasses();
actionbean 。Stripes1.5 。 , addActionBean(clazz); actionbean urlbinging this. formBeans 。
protected void addActionBean(Class<? extends ActionBean> clazz) {
// actionbean @ UrlBinding(“/user/register.action”) /user/register.action
String binding = getUrlBinding(clazz);
// Only process the class if it's properly annotated
if (binding != null) {
this.formBeans.put(binding, clazz);
// Construct the mapping of event->method for the class
Map<String, Method> classMappings = new HashMap<String, Method>();
processMethods(clazz, classMappings);
// Put the event->method mapping for the class into the set of mappings
this.eventMappings.put(clazz, classMappings);
// Print out the event mappings nicely
for (Map.Entry<String,Method> entry : classMappings.entrySet()) {
String event = entry.getKey();
Method handler = entry.getValue();
boolean isDefault = DEFAULT_HANDLER_KEY.equals(event);
log.debug("Bound: ", clazz.getSimpleName(), ".", handler.getName(), "() ==> ",
binding, isDefault ? "" : "?" + event);
}
}
}
: formBeans、eventMappings,formBeans urlbinging actionbean 。eventMappings actionbean 。 , (urlbinging) , actionbean 。Actionbean @UrlBinding , , actonresolver 。 String binding = getUrlBinding(clazz) 。
@Override
public String getUrlBinding(Class<? extends ActionBean> clazz) {
String binding = super. annotation ;
// If there's no annotated binding, and the class is concrete
if (binding == null && !Modifier.isAbstract(clazz.getModifiers())) { binding = getUrlBinding(clazz.getName()); }
return binding; }
getUrlBinding getUrlBinding(clazz) 。 actionbean urlbing 。getUrlBinding(String name) :
protected String getUrlBinding(String name) {
// Chop off the packages up until (and including) any base package
for (String base : getBasePackages()) {
int i = name.indexOf("." + base + ".");
if (i != -1) {
name = name.substring(i + base.length() + 1);}
else if (name.startsWith(base + ".")) {
name = name.substring(base.length());} }
// If it ends in Action or Bean (or ActionBean) take that off
if (name.endsWith("Bean")) {
name = name.substring(0, name.length() - 4); }
if (name.endsWith("Action")) {
name = name.substring(0, name.length() - 6); }
// Replace periods with slashes and make sure it starts with one
name = name.replace('.', '/');
if (!name.startsWith("/")) {
name = "/" + name; }
// Lastly add the suffix
name += getBindingSuffix();
return name;
}
getUrlBinding(String name) , com.morik.action.RegisterAction RegisterActionBean, Register.action.
actionbean 。 processMethods(clazz, classMappings); actionbean 。
protected void processMethods(Class clazz, Map<String,Method> classMappings) {
// Do the super class first if there is one
Class superclass = clazz.getSuperclass();
if (superclass != null) {
processMethods(superclass, classMappings);
}
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if ( Modifier.isPublic(method.getModifiers()) ) {
String eventName = getHandledEvent(method);
DefaultHandler defaultMapping = method.getAnnotation(DefaultHandler.class);
if (eventName != null) {
classMappings.put(eventName, method);
}
if (defaultMapping != null) {
// Makes sure we catch the default handler
classMappings.put(DEFAULT_HANDLER_KEY, method);
}
}
}
}
, actionbean @DefaultHandler DefaultHandler 。 ,
public String getHandledEvent(Method handler) {
String name = super.getHandledEvent(handler);
if ( name == null && !Modifier.isAbstract(handler.getModifiers())
&&R esolution.class.isAssignableFrom(handler.getReturnType()) ) { name = handler.getName(); }
return name; }
イベントメソッドを解析するときに、
annotion
見つからない場合は、戻りタイプを探します.
Resolution
の非抽象的な方法同名の方法.イベントの処理方法には一般的にパラメータはありません.
これで
actionResolver
パスに対応する
actionbean
クラスは、クラスとイベントの処理方法の関係を初期化します.