自分のmvc-1の開発に着手します.初歩的なコントロール層を実現して、各種の配置と資源の獲得を実現します.


mvcフレームの一番基本的な機能はジャンプです.struts 2は注釈+xmlの配置ジャンプをサポートしています.個人的には注釈でジャンプを配置するのはいい方法ではないと思います.見たところ簡単なようですが、actionが多いと探しにくいです.また、配置情報をクラスの中に入れるのは実際にはデカップリングの理念とは違っています.ですから、ここでジャンプ層をxml配置に設計して、他の層を注解するように設計したいです.
ジャンプの設定に必要な知識は反射、xml読み取りです.反射は動的組み立ての基礎を実現するものであり、それは私たちのプログラムをよりダイナミックにし、拡張可能にし、ほぼすべての流行のフレームワークはそれをベースに実現されます.xml読み取りは基本的にdom 4 jで行われます.
mvcジャンプを実現する過程:xml名前空間、アクションクラス、要求のaction方法とジャンプのページを設定し、formに要求を提出した後、センターServletによって処理され、要求の経路を解析し、xml構成の各種情報に基づいて、ターゲットアクション類の処理方法を反射し、xml構成のターゲットジャンプページに従ってジャンプします.
だから、私達が抽出した核心の配置はあります.
1,namcespace:名前空間、モジュールによって異なるnamespaceがあります.
2,name:formリクエストの名前.
3,method:nameに対応するアクションの処理方法名は、反射的に呼び出されます.
4,class:アクションクラスの全パスは、センターServletで反射生成するために使用されます.
5,reult子ラベル:アクション処理後のジャンプページ、ジャンプ先はforwardまたはredirectです.
私たちはwebプロジェクトを新設し、MVCと名づけました.
次にServletを新たに作って、MainServletと名づけて、センタープロセッサ用に作ります.
srcディレクトリの下で新しいcontrol.xmlをジャンププロファイルとして作成します.control.xmlは以下の通りです.

xml version ="1.0" encoding= "UTF-8" ?>
< actions>

test/test1.action


class= "com.test.action.TestAction" >
success.jsp
error.jsp
action>

class= "com.test.action.TestAction" >
success.jsp
error.jsp
action>

class= "com.test.action.TestAction" >
success.jsp
error.jsp
action>


actions>

web.xmlを設定して、すべてのactionの最後の要求をブロックさせます.私の構成は以下の通りです.


mainservlet
org.love.servlet.MainServlet



control action , src control.xml

CONTROL_CONFIG
classpath:control.xml




ENCODING
UTF-8





mainservlet
*.action


なぜCONTROLをCONFIG配合
classipath:control.xmlは、異なる経路のファイルをよりよく読み込むためです.
このように、すべてのactionの要求は、MainServletというセンタープロセッサに入り、設定ファイルを一括して入力し、servlet初期化(init()方法は、最初の要求時に呼び出しされる.
)段階でプロファイル情報を読み出し、キャッシュします.
一般的には、リソース管理クラスは、単一の例として設計することができますが、アプリケーションの必要性を満たすために、メモリを節約し、コードがより明確に見えるので、私はここで新しいControlXml類を作成し、専用のcontrol.xmlファイルを読み込むために使用します.
このようなことを実現する前に、プロファイルの各要素を異なるjavabeanに対応させる必要があります.クラスの対応は以下の通りです.
[img]http://dl.iteye.com/upload/picture/pic/122768/d009cc6a-66b4-3e7b-95a2-caf8653629e5.gif[img]
NamespaceはアクションVoリストを持ち、アクションVoはResultリストを持ち、ControlXmlはNamespaceのmap構造を持っていればいいです.
ControlXMLコードは以下の通りです.

package org.love.servlet.util;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.love.converter.DateConverter;
import org.love.converter.FileConverter;
import org.love.converter.IntegerConverter;
import org.love.converter.TypeConverter;

/**
* xml
*
* @author Administrator
*
*/
public class ControlXML {

public final static String CONTROL_CONFIG = "control.xml";

private static ControlXML controlXml = new ControlXML();

private Map namespaces = new HashMap();

private Map convertMap= new HashMap();

private Map globalResults= new HashMap();

public Map getGlobalResults() {
return globalResults;
}

private ControlXML() {
/*convertMap.put("java.util.Date", new DateConverter());
convertMap.put("java.lang.Integer", new IntegerConverter());
convertMap.put("org.love.po.FilePo", new FileConverter());*/
}

public static ControlXML getInstance() {
return controlXml;
}

public void readXml(String xmlurl) throws DocumentException, InstantiationException, IllegalAccessException, ClassNotFoundException {
/* xml */
SAXReader reader = new SAXReader();
Document document = reader.read( new File(xmlurl));
Element rootElement = document.getRootElement();

/* namespace ( result ) start */
List namespaces_list = rootElement.elements("namespace" );
for (Element namespace : namespaces_list) {
/* action */
Map actions = new HashMap();

/* action ( result ) start */
List actions_list = namespace.elements("action" );
for (Iterator it = actions_list.iterator(); it.hasNext();) {
Element action = (Element) it.next();
ActionVo avo = new ActionVo();
avo.setName(action.attributeValue( "name"));
avo.setMethod(action.attributeValue( "method"));
avo.setClassName(action.attributeValue( "class"));

List avo_results = action.elements("result" );
Map list_result = new HashMap();
for (Element result : avo_results) {
Result rs = new Result();
rs.setName(result.attributeValue( "name"));
rs.setType(result.attributeValue( "type"));
rs.setUrltext(result.getText().trim());
list_result.put(rs.getName(),rs);
}
avo.setResults(list_result);
actions.put(avo.getName(), avo);
}
/* action ( result ) end */

namespaces.put(namespace.attributeValue( "name"), new Namespace(
namespace.attributeValue( "name"), actions));
}
/* namespace ( result ) end */

/* converter start*/
/*List converter_list = rootElement.elements("converter");
for(Element convertElement:converter_list){
String type=convertElement.attributeValue("type");
String handle=convertElement.attributeValue("handle");
TypeConverter tc=(TypeConverter)(Class.forName(handle).newInstance());
convertMap.put(type,tc);
}*/
/* converter end*/

/* global-results start*/
List global_results_list = rootElement.elements("global-results");
if(global_results_list!=null && global_results_list.size()>0){
Element global_results=global_results_list.get(0);
List results=global_results.elements("result");
for(Element result:results){
Result rs = new Result();
rs.setName(result.attributeValue("name"));
rs.setType(result.attributeValue("type"));
rs.setUrltext(result.getText().trim());
globalResults.put(rs.getName(),rs);
}
}


/* global-results end*/

/* */

}

public ActionVo getAction(String namespacename, String actionname) {
if ( namespaces == null || namespaces.isEmpty()) {
throw new RuntimeException( " readXml(xml) " );
}
Namespace ns = namespaces.get(namespacename);
ActionVo avo = null;
if (ns != null) {
avo=ns.getListActions().get(actionname);
}

return avo;
}



public Map getConvertMap() {
return convertMap;
}

}

コードの中のコメントの部分は後で詳しく説明しますが、コードの構造がはっきりしていれば、添削が簡単です.
以下はMainServletの方法で読み取りできます.コアコードは以下の通りです.

ControlXML controlXml = ControlXML.getInstance();
String control_config = sc.getInitParameter("CONTROL_CONFIG" );

if (control_config == null || control_config.trim().equals("" )) {
control_config = Thread.currentThread().getContextClassLoader()
.getResource(ControlXML. CONTROL_CONFIG).getFile();
} else if (control_config.startsWith("classpath:" )) {
control_config = control_config.split(":" )[1];
control_config = Thread.currentThread().getContextClassLoader()
.getResource(control_config).getFile();
} else {
control_config = sc.getServletContext().getRealPath("WEB-INF" )
+File. separator+ control_config;
}
try {
controlXml.readXml(control_config);
} catch (Exception e) {
e.printStackTrace();
}

control.xmlは必ずしもsrcの下に置くとは限らないし、web-infの下にあるかもしれないので、ここでは何回かの判断をする必要があります.
以上はすべての解析作業です.次のステップはMainServletを作成して、各種の要求を処理します.
解析要求の核心作業はこのステップに分けられます.
1,レクリエーションからnamespace,actionを解析します.
2,このNamcespaction情報は、リソースクラスのControlXmlを構成して得られ、アクションの例が生成される.
3,対応するアクション方法を実行し、このアクション構成に値するレスポンスに従って、ページにジャンプする.
以下のように実現します

String requestURI = request.getRequestURI();
// "/" , url,
if (requestURI.endsWith("/" )) {
requestURI = requestURI.substring(0, requestURI.length() - 1);
}
String namespace = requestURI.substring(0, requestURI.lastIndexOf("/" ));
String actionname = requestURI.substring(
requestURI.lastIndexOf( "/") + 1, requestURI.lastIndexOf("." ));
相応のアクションを得る

ControlXML controlXml = ControlXML.getInstance();
ActionVo avo = controlXml.getAction(namespace, actionname);
Object action = InvocakeHelp.newInstance(avo.getClassName(), null);
アクションの方法を反射して呼び出し、文字列を返します.

Object actionValue=InvocakeHelp.invokeMethod(action,avo.getMethod(),null);


globalResult Result, action result
Result result = controlXml.getGlobalResults().get(actionValue);
if(result== null){
result = avo.getResults().get(actionValue);
}


//
if ("redirect" .equals(result.getType())) {
response.sendRedirect(request.getContextPath() + "/"
+ result.getUrltext());
} else {
request.getRequestDispatcher( "/" + result.getUrltext()).forward(
request, response);
}

InvocakeHelp , ,


public static Object newInstance(String className, Object[] args) {
try {
Class newClass = Class. forName(className);
if (args == null || args. length == 0) {
return newClass.newInstance();
} else {
Class[] argsClasses = new Class[args.length];
for ( int i = 0; i < args. length; i++) {
argsClasses[i] = args[i].getClass();
}
Constructor cons = newClass.getConstructor(argsClasses);
return cons.newInstance(args);
}

} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}

public static Object invokeMethod(Object owner, String methodName,
Object[] args) {
Class ownerClass = owner.getClass();
Class[] argsClass = null;
if (args != null && args. length != 0) {
argsClass = new Class[args. length];
for ( int i = 0; i < args. length; i++) {
argsClass[i] = args[i].getClass();
}
}
try {
Method method = ownerClass.getMethod(methodName, argsClass);
return method.invoke(owner, args);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}

return null;
}

/**
* set
*
* @param obj
* @param fieldName
* @param value
* @param fieldType
*/
public static void callSetMethod(Object owner, String fieldName,
Object value) {
String setName = "set" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Class ownerClass = owner.getClass();
try {
Field field=ownerClass.getField(fieldName);
Method method = ownerClass.getMethod(setName,field.getType());
method.invoke(owner,value);
} catch (Exception e) {
e.printStackTrace();
}


}


大体の機能がありますが、テストしてもいいですか?自分のアクションにはレクリエーションという資源がないようです.
今は二つの方法があります.
1、インターフェースを実現する(または引き継ぎ)
2,APIは得られます
第二の方式は確かにいいと言われています.デカップルしているからと言って、必ずしもそうではないと思います.私たちはいかなる枠組みの目標をしても、結合を解くためには使いません.
実はstruts 2にも似たような問題がありました.解決方法の一つは資源インターフェースを実現することです.
Servlet Request Awarehuインターフェースは、requestを取得することができますが、他にも彼の兄弟などServlet Resonse Aware、Session Aware、Servlet ContactAware、それぞれreponse、session、servlet Contawareを得ることができます.
まず私たちが作成します
Contect Actionインターフェースのコードは以下の通りです.

/**
* action , ,
* @author duyf
*
*/
public interface ContextAction {
public void setRequest(HttpServletRequest request);
public void setResponse(HttpServletResponse response);
public void setSession(HttpSession session);
public void setServletContext(ServletContext context);
}

MainServletを呼び出し、actionオブジェクトを取得した後、設定コードを追加します.

if (!(action instanceof ContextAction)) {
throw new RuntimeException( " ContextAction " );
}
ContextAction ca = (ContextAction) action;
ca.setRequest(request);
ca.setResponse(response);
ca.setSession(request.getSession());
ca.setServletContext( servletContext);

テストアクションを呼び出して、HttpServletRequestなどの各種リソースオブジェクトを宣言し、インターフェースを実現し、リソースを受信します.コアコードは以下の通りです.

protected HttpServletRequest request ;
protected HttpServletResponse response ;
protected HttpSession session;
protected ServletContext servletContext;

public void setRequest(HttpServletRequest request) {
this. request = request;
}

public void setResponse(HttpServletResponse response) {
this. response = response;
}

public void setServletContext(ServletContext context) {
this. servletContext = context;
}

public void setSession(HttpSession session) {
this. session = session;
}

.有木さんはこれから各actionには業務と関係のないコードがあります.だから、普通のやり方はBaseAction類を作って、Contect Actionインターフェースを実現して、その後あなたのアクションをBaseActionに引き継がせて、冗長コードを排除しました.これはjavaモードでよく使われるデフォルトモードです.
APIがウェブリソースを獲得する前に、tomcatがどのように要求に応答しているかをよく考えてみます.
tomcatを要求する時に、tomcatはスレッド池からアイドルスレッドを割り当ててこの要求に対して、データの包装を経て、初めてMainServletを実行する時に、init方法を実行し(一回実行します)、その後すべての要求は同じMainSerServletオブジェクトを実行します.このようにすれば、Servletスレッドの安全問題を引き起こしやすくなります.だから、どの場所でも正確に要求リソースを得るために、ThreadLocalを採用して記憶しています.ThreadLocalは本質的には現在のスレッドと値のキーです.だから、現在のいつでもこのオブジェクトにアクセスすると、マルチスレッド変数の干渉を排除できます.
実現方法は比較的簡単です.

public class ActionContext {

public final static String HTTPREQUEST = "httprequest";
public final static String HTTPRESPONSE = "httpresponse";
private static ThreadLocal threadLocal = new ThreadLocal();

public static ActionContext getContext() {
return (ActionContext) threadLocal.get();
}

public static void setContext(ActionContext context) {
threadLocal.set(context);
}

public static HttpServletRequest getRequest() {
return (HttpServletRequest) getContext().get(HTTPREQUEST);
}

public static HttpServletResponse getResponse() {
return (HttpServletResponse) getContext().get(HTTPRESPONSE);
}



public ActionContext() {

}

public ActionContext(Map context) {
this. context = context;
}

/* start */
private Map context = new HashMap();

/* end */

/* start */
public Object get(String key) {
return context.get(key);
}

public Object put(String key, Object value) {
return context.put(key, value);
}
/* end */
}

ここにはrequestとレスポンスだけが格納されています.国際情報、コンテナ情報、またはアクションのコンテキスト情報なども自分で保存できます.
もう一回説明したのはrequestとreponseはスレッドの安全ですが、継承または参参などの方法でどこでもrequestリソースが得られます.threadLocalを使うのが一番いいです.
コール方式は以下の通りです.(ソースコードと照合してください.)

// Action Context
Map contextMap= new HashMap();
contextMap.put(ActionContext. HTTPREQUEST, request);
contextMap.put(ActionContext. HTTPRESPONSE,response);
ActionContext. setContext(new ActionContext(contextMap));

ThreadLocal , , , finally :
finally{
//
ActionContext. setContext(null);
}

今後は、任意の要求範囲において、アクションContect.get Request()とアクションContect.gets Resonse()を介して要求リソースまたは応答を得ることができる.
これで私たちの基本的な構成のジャンプが完了しました.自分でテストしてもいいです.
Byトビの転載について説明してください.
騰訊微博:[url]http://t.qq.com/duyunfeiRoom[/url]
新浪微博:[url]http://weibo.com/u/1766094735[/url]
原文の住所:[url]http://duyunfei.iteye.com/blog/1773693[/url]