ClickとS2の連携
ClickServletを拡張してS2Containerからページクラスを作成するサーブレットを作ってみました。ClickにはSpring用のサーブレットも用意されているのでそれを参考にしました。ちょっと長いですがソースを全文掲載しておきます。
package tk.sample; import java.lang.reflect.Field; import java.util.Map; import javax.servlet.GenericServlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.click.ClickServlet; import net.sf.click.Context; import net.sf.click.Page; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.SingletonS2ContainerFactory; import org.seasar.framework.util.StringUtil; /** * Provides Seasar2 (S2) integration <tt>S2ClickServlet</tt>. * <p/> * This specialized Click Servlet can inject S2 dependencies into * defined S2 Page component. If a requested Page is not configured * as a S2 component, then a plain new Page instance is created. * <p/> * You have to register Page classes to the dicon file * (the dicon file is the configuration file of Seasar2) like following: * <pre class="codeConfig"> * <components> * <component name="/index.htm" * class="examples.IndexPage" * instance="prototype" /> * </components> * </pre> * There are no needs to register Page classes to click.xml. * <p/> * <strong>Note:</strong> the instance attribute of component * in the dicon file have to be prototype or request. * * @author Naoki Takezoe */ public class S2ClickServlet extends ClickServlet { private static final long serialVersionUID = -1915099546074919781L; private S2Container container; public static final String CONFIG_PATH_KEY = "configPath"; /** * Initializes the Click servlet, the Velocity runtime and S2Container. * * @see GenericServlet#init() */ public void init() throws ServletException { super.init(); String configPath = null; ServletConfig servletConfig = getServletConfig(); if (servletConfig != null) { configPath = servletConfig.getInitParameter(CONFIG_PATH_KEY); } if (!StringUtil.isEmpty(configPath)) { SingletonS2ContainerFactory.setConfigPath(configPath); } SingletonS2ContainerFactory.setServletContext(getServletContext()); SingletonS2ContainerFactory.init(); container = SingletonS2ContainerFactory.getContainer(); } /** * Creates and initializes a new Page instance. * This method gets the Page instance from S2Container. * * @param request the servlet request * @param response the servlet response * @param isPost determines whether the request is a POST * @return a new Page instance for the given request */ protected Page createPage(HttpServletRequest request, HttpServletResponse response, boolean isPost) { Context context = new Context(getServletContext(), getServletConfig(), request, response, isPost, pageMaker); String path = context.getResourcePath(); if (request.getAttribute(FORWARD_PAGE) != null) { Page forwardPage = (Page) request.getAttribute(FORWARD_PAGE); forwardPage.setContext(context); request.removeAttribute(FORWARD_PAGE); return forwardPage; } Page page = null; if(container.hasComponentDef(path)){ page = (Page)container.getComponent(path); } else { page = super.createPage(request, response,isPost); } Object clickApp = getField(ClickServlet.class, this, "clickApp"); if(page.getFormat()==null){ try { Class formatClass = (Class)getField(clickApp.getClass(), clickApp, "formatClass"); page.setFormat(formatClass.newInstance()); } catch(Exception ex){ throw new RuntimeException(ex); } } if(page.getHeaders()==null){ page.setHeaders((Map)getField(clickApp.getClass(), clickApp, "commonHeaders")); } page.setPath(path); page.setContext(context); return page; } /** * This is the utility method to get the field using reflection. * * @param type The type that declares the field * @param obj The target object * @param fieldName the field name * @return the field object */ private Object getField(Class type, Object obj, String fieldName){ try { Field[] fields = type.getDeclaredFields(); for(int i=0;i<fields.length;i++){ if(fields[i].getName().equals(fieldName)){ fields[i].setAccessible(true); return fields[i].get(obj); } } } catch(Exception ex){ throw new RuntimeException(ex); } return null; } }
ダウンロードは以下のリンクからどうぞ。
- S2ClickServlet.java(1871)
このサーブレットを以下のような感じでweb.xmlに登録しておきます。サーブレットの初期化パラメータで設定ファイルを指定できるのはS2ContainerServletと同じです。指定しなければクラスパスルートのapp.diconを読み込みます。
<servlet> <servlet-name>click-servlet</servlet-name> <servlet-class>tk.sample.S2ClickServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>click-servlet</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping>
diconファイルには以下のようにページクラスを登録しておきます。
<component name="/index.htm" class="tk.sample.IndexPage" instance="prototype"/>
ページクラスのinstance属性はrequestまたはprototypeにしておく必要があります。Clickに付属している SpringClickServletとは違ってclick.xmlにはページクラスを登録しておく必要はありません(SpringClickServletはclick.xmlとSpringの設定ファイルの両方にページクラスを登録しておく必要があります)。