- 定義配置文件dtd
<!-- 示例 -->
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT myMvc (actions)>
<!ELEMENT actions (action*)>
<!ELEMENT action (result*)>
<!ATTLIST action
name CDATA #REQUIRED
class CDATA #REQUIRED>
<!ELEMENT result (#PCDATA)>
<!ATTLIST result
name CDATA #IMPLIED
redirect (true|false) "false"> - 定義配置文件
<!-- 創建一個使用剛創建的dtd的配置文件 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE myMvc PUBLIC "-//UNKOWN/" "mymvc.dtd"><!--此處引用上面的自定義dtd-->
<myMvc>
<actions>
<action name="login" class="cn.stanley.action.LoginAction">
<result name="success">pages/success.jsp</result>
<result name="input">pages/login.jsp</result>
</action>
<action name="regist" class="cn.stanley.action.LoginAction">
<result name="success">pages/success.jsp</result>
<result name="input">pages/login.jsp</result>
</action>
</actions>
</myMvc> - 創建 請求——操作 映射類
/**
* 映射 響應結果與視圖之間的關係
*/
public class ResultMapping {
private String name;
private boolean redirect;
private String path;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isRedirect() {
return redirect;
}
public void setRedirect(boolean redirect) {
this.redirect = redirect;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public ResultMapping(){}
public ResultMapping(String name, boolean redirect, String path) {
super();
this.name = name;
this.redirect = redirect;
this.path = path;
}
}/**
* 映射 請求與處理請求方法之間的關聯
*/
public class ActionMapping {
private String name;
private String className;
private Map<String,ResultMapping> resultMap=new HashMap<String, ResultMapping>(0);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Map<String, ResultMapping> getResultMap() {
return resultMap;
}
public void setResultMap(Map<String, ResultMapping> resultMap) {
this.resultMap = resultMap;
}
public ActionMapping(String name, String className) {
super();
this.name = name;
this.className = className;
}
public ActionMapping(){}
public void addResult(ResultMapping result){
this.resultMap.put(result.getName(), result);
}
} - 創建 配置文件解析類,解析配置文件並生成 請求——操作的映射對象
/**
* 解析配置文件生成相就的映射對象 ,並管理
*/
public class ActionMappingManager {
private Map<String, ActionMapping> actionMappings =new HashMap<String, ActionMapping>();
public ActionMappingManager(String[] configFileNames) {
for (String configFileName : configFileNames) {
try {
init(configFileName);
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("rawtypes")
public void init(String configFileName)throws DocumentException {
// dom4j 解析器
SAXReader reader = new SAXReader();
// 設置 dtd 解析器 此片因爲是自定義dtd,所以寫了一個FindDTD類設定dtd
reader.setEntityResolver(new FindDTD());
//讀取根節點
Document document = reader.read(DocumentException.class
.getResourceAsStream("/" + configFileName));
//子節點集合
List nodes = document.getRootElement().element("actions")
.elements("action");
//遍楞子節集合
for (Iterator iterator = nodes.iterator();iterator.hasNext();) {
Element node = (Element) iterator.next();
ActionMapping acm = new ActionMapping( node.attributeValue("name"),node.attribute("class").getValue());
// 遍歷 result
for (Iterator it2 = node.elements("result").iterator(); it2.hasNext();) {
Element ele = (Element) it2.next();
String name = ele.attributeValue("name");
boolean redirect =Boolean.valueOf(ele.attributeValue("redirect"));
String path = ele.getText();
acm.addResult(new ResultMapping(name, redirect, path));
}
actionMappings.put(acm.getName(), acm);
}
}
/**
* 根據 請求中的 actionName 取 ActionMapping
*
* @param actionName
* @return
* @throws Exception
*/
public ActionMapping getActionMapping(String actionName) {
if (null == actionName || actionName.isEmpty()) {
return null;
}
ActionMapping mapping = actionMappings.get(actionName);
if (mapping == null) {
throw new RuntimeException("不存在此mapping:" +actionName);
}
return mapping;
}
}/**
* 自定義DTE 解析器,因爲是自定義DTD,web容器會默認在bin目錄下找,
* 而指定相對路徑與絕對路徑都不能正確獲取,所以得自定義
*/
public class FindDTD implements EntityResolver {
@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
//自已的dtd所在的位置
String path = "mymvcframework/" +systemId.substring(systemId.lastIndexOf("/")+1);
InputStream in=this.getClass().getClassLoader()
.getResourceAsStream(path);
InputSource so=new InputSource(in);
return so;
}
} - 定義 action 接口
/**
* Action 接口
* @author Administrator
*
*/
public interface Action {
/**
* 執行 業務與 數據 訪問操作
* @param req
* @param res
* @return
* @throws Exception
*/
String execute(HttpServletRequest req, HttpServletResponse res)
throws Exception;
} - 創建 controller
/**
* 這是整個mvc框加的核心
*/
public class ActionFilter implements Filter {
/**
* actionMappingManager 實例
*/
private ActionMappingManager mappingManage;
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
//請求類型轉換
HttpServletRequest hreq = (HttpServletRequest) req;
HttpServletResponse hres = (HttpServletResponse) res;
//獲取 動作映射
ActionMapping aMapping=null;
try {
aMapping = getActionMapping(hreq, hres);
} catch (Exception e1) {
throw new RuntimeException(e1);
}
if (null == aMapping) {
throw new RuntimeException("資源不存在");
}
//創建 動作對象 並執行
Action action = ActionFactory.createAction(aMapping.getClassName());
String resultName = null;
try {
resultName = action.execute(hreq, hres);
} catch (Exception e) {
e.printStackTrace();
}
if (resultName == null) {
throw new RuntimeException("結果視圖不存在");
}
//取出 結果映射
ResultMapping result = aMapping. getResultMap().get(resultName);
//判斷 結果映射 晌應方式
if (result.isRedirect()) { //重定向
hres.sendRedirect(result.getPath());
} else { //轉發
req.getRequestDispatcher(result.getPath())
.forward(req, res);
}
}
/**
* 初始化操作 :: 讀取web.xml 中的 初始參數配置 ,* 創建 ActionMappingManager 類
*/
@Override
public void init(FilterConfig config) throws ServletException {
//獲取配置參數 config
String conStr=config.getInitParameter("config");
//配置的文件名數組
String[] configFileNames=null;
if(conStr==null|| conStr.isEmpty()){
}else{
configFileNames=conStr.split(",");
}
// 創建 actionMappingManager 類
this.mappingManage=new ActionMappingManager(configFileNames);
}
/**
* 獲取動作
* @param req
* @param res
* @return
* @throws Exception
*/
private ActionMapping getActionMapping(HttpServletRequest req,
HttpServletResponse res) throws Exception {
//獲取 uri
String url = req.getRequestURI();
//獲取應用名
String contextPath = req.getContextPath();
//獲取 *.action...
String actionPath = url.substring(contextPath.length());
//獲取 *.action 中 的 * 部分
String actionName = actionPath
.substring(1, actionPath.lastIndexOf("."));
// 返加 actionMapping
return mappingManage.getActionMapping(actionName);
}
}/**
* 此處用一個返射工廠來創建Action實例
*/
public class ActionManager {
public static Action createAction(String className){
try {
return (Action) Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
} - 將控制器配置到 web.xml中
3、模型的可移植性。因爲模型是獨立於視圖的,所以可以把一個模型獨立地移植到新的平臺工作。需要做的只是在新平臺上對視圖和控制器進行新的修改。
1、增加了系統結構和實現的複雜性。對於簡單的界面,嚴格遵循MVC,使模型、視圖與控制器分離,會增加結構的複雜性,並可能產生過多的更新操作,降低運行效率。
2、視圖與控制器間的過於緊密的連接。視圖與控制器是相互分離,但確實聯繫緊密的部件,視圖沒有控制器的存在,其應用是很有限的,反之亦然,這樣就妨礙了他們的獨立重用。
3、視圖對模型數據的低效率訪問。依據模型操作接口的不同,視圖可能需要多次調用才能獲得足夠的顯示數據。對未變化數據的不必要的頻繁訪問,也將損害操作性能。