談起MVC設計模式,不得不說說struts。作爲經典的SSH框架之一的struts以獨具匠心的攔截器和公用servlet設計樣式讓人耳目一新,今天我要和大家一起探討的是關於以公共、唯一的servlet爲基礎,多個操作action爲核心的MVC設計框架。
下面是我模擬struts的運行原理寫的一個程序,希望對大家有用!
首先跟大家分享框架結構圖:
第一步,容器管理的框架ActionServlet初始化獲取ActionConfig.xml配置文件
第二步,創建ActionMappingManager映射文件管理器,將配置信息以ActionMapping的格式保存在ActionMappingManager裏
第三步,ActionServlet獲取*.jsp文件的提交,到ActionMappingManager裏面查找相對應的ActionMapping
第四步,通過ActionManager實例化Action對象
第五步,調用該對象進行邏輯處理,並返回Action
第六步,操作完畢後返回ActionServlet,再跳轉到響應的*.jsp
看完結構圖,由我帶大家瀏覽一下設計流程:
1、首先創建一個Web Project
2、然後需要導入一個解析XML文件的jar包dom4j-1.6.1.jar
3、需要在src下寫一個名叫ActionConfig.dtd文件,這個文件用於規範ActionConfig.XML配置文件
<!ELEMENT ActionConfig (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">
4、下面就開始寫各個類
a、統一的ActionServlet類
package com.huan.frame;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ActionServlet extends HttpServlet {
private ActionMappingManager manager;
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
String configStr = config.getInitParameter("config");
String[] files;
//判斷是否配置初始化參數
if(configStr == null || configStr.isEmpty())
files = new String[]{"ActionConfig.xml"};
else
files = configStr.split(",");
System.out.println("映射管理器運行");
manager = new ActionMappingManager(files);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
try {
ActionMapping mapping = getActionMapping(request);
if(mapping == null)
throw new Exception("doPost裏mapping沒有值!");
ActionSuport action = ActionManager.createAction(mapping.getClassName());
if(action == null)
throw new Exception("doPost裏action對象未生成!");
String isSuceess = action.execute(request, response);
System.out.println(mapping.getResult(isSuceess).getPath());
if(mapping.getResult(isSuceess).isRedirect())
response.sendRedirect(mapping.getResult(isSuceess).getPath());
else
request.getRequestDispatcher(mapping.getResult(isSuceess).getPath()).forward(request, response);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public ActionMapping getActionMapping(HttpServletRequest request){
//獲取請求的uri
String uri = request.getRequestURI();
//獲取上下文路徑
String contextPath = request.getContextPath();
//截取上下文路徑以後的部分
String actionPath = uri.substring(contextPath.length());
//獲取action名稱
String actionName = actionPath.substring(1,actionPath.lastIndexOf('.')).trim();
return manager.getActionMappingByName(actionName);
}
}
b、規範接口ActionSuport類
package com.huan.frame;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public interface ActionSuport {
//action需要實現的接口
public String execute(HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException;
}
c、映射文件ActionMapping類和返回結果Result類
package com.huan.frame;
import java.util.*;
public class ActionMapping {
private String name;
private String className;
private Map<String,Result> results = new HashMap<String,Result>();
public ActionMapping() {
super();
}
public ActionMapping(String name, String className,
Map<String, Result> results) {
super();
this.name = name;
this.className = className;
this.results = results;
}
public void addResult(String key,Result value){
results.put(key, value);
}
public Result getResult(String name){
return results.get(name);
}
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, Result> getResults() {
return results;
}
public void setResults(Map<String, Result> results) {
this.results = results;
}
}
package com.huan.frame;
public class Result {
private String name;
private boolean isRedirect;
private String path;
public Result() {
super();
}
public Result(String name, boolean isRedirect, String path) {
super();
this.name = name;
this.isRedirect = isRedirect;
this.path = path;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isRedirect() {
return isRedirect;
}
public void setRedirect(boolean isRedirect) {
this.isRedirect = isRedirect;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
d、映射文件實例化ActionManager類
package com.huan.frame;
public class ActionManager {
public static ActionSuport createAction(String className){
try {
return (ActionSuport)Class.forName(className).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
e、映射文件管理器ActionMappingManager類
package com.huan.frame;
import java.io.*;
import java.util.*;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
public class ActionMappingManager {
private static Map<String,ActionMapping> actionMappings = new HashMap<String,ActionMapping>();
public ActionMappingManager(String[] files){
try {
if(files == null || files.length == 0)
throw new Exception("配置文件爲空!");
for (String file : files) {
read(file);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void read(String file){
try {
if(file == null || file.isEmpty())
throw new Exception("文件不能爲空!");
//加上“/”和文件名,系統將在src下面找該文件
InputStream is = getClass().getResourceAsStream("/" + file);
if(is == null) throw new Exception("沒有找到" + file + "文件!");
Document doc = new SAXReader().read(is);
if(doc == null) throw new Exception("文件解析失敗!");
Element root = doc.getRootElement();
Iterator<Element> actionsIt = root.elementIterator("actions");
Element actions = actionsIt.next();
Iterator<Element> actionIt = actions.elementIterator("action");
ActionMapping mapping = null;
Element node = null;
Iterator<Element> resultIt = null;
String resultStr,redirectStr,pathStr;
Result result;
System.out.println("進入讀取循環");
while(actionIt.hasNext()){
node = actionIt.next();
mapping = new ActionMapping();
mapping.setName(node.attributeValue("name"));
mapping.setClassName(node.attributeValue("class"));
resultIt = node.elementIterator("result");
System.out.println("action循環");
while(resultIt.hasNext()){
node = resultIt.next();
resultStr = node.attributeValue("name");
redirectStr = node.attributeValue("redirect");
pathStr = node.getText();
result = new Result();
if(resultStr == null || resultStr.isEmpty()){
result.setName("success");
if(redirectStr == null || redirectStr.isEmpty() || redirectStr.equals("false"))
result.setRedirect(false);
else
result.setRedirect(true);
result.setPath(pathStr);
}else{
result.setName(resultStr);
if(redirectStr == null || redirectStr.isEmpty() || redirectStr.equals("false"))
result.setRedirect(false);
else
result.setRedirect(true);
result.setPath(pathStr);
}
System.out.println("result循環");
mapping.addResult(resultStr, result);
}
actionMappings.put(mapping.getName(), mapping);
System.out.println("加載配置文件完畢!");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public ActionMapping getActionMappingByName(String name){
ActionMapping mapping = null;
try {
if(actionMappings.isEmpty()) throw new Exception("映射管理沒有數據!");
mapping = actionMappings.get(name);
if(mapping == null) throw new Exception("映射爲空!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mapping;
}
}
5、寫完各個類之後就是打包,右鍵點擊項目export,保存爲JAR file文件即可!
瀏覽完設計流程,就讓我們測試一下我們的MVC框架吧,let's go!
1、創建一個Web Project項目,導入咱們剛剛寫好的包,還要導入dom4j-1.6.1.jar,別忘了!
2、在web.xml文件裏配置框架的servlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>com.huan.frame.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
3、創建一個dao層,寫一個虛擬數據庫
package com.huan.test;
import java.util.*;
import com.huan.entity.User;
public class UserDaoImp {
private static List<User> list = new ArrayList<User>();
//虛擬數據庫
static{
list.add(new User("111","aaa"));
list.add(new User("222","bbb"));
list.add(new User("333","ccc"));
}
public User getUserByName(String name){
Iterator<User> it = list.iterator();
User user = null;
while(it.hasNext()){
user = it.next();
if(user.getName().equals(name))
return user;
}
return null;
}
}
4、創建頁面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="LoginAction.action" method="post">
用戶名:<input type="text" name="username"/>
密碼:<input type="password" name="password"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
5、創建Action
package com.huan.test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.huan.entity.User;
import com.huan.frame.ActionSuport;
public class LoginAction implements ActionSuport {
private UserDaoImp user = new UserDaoImp();
@Override
public String execute(HttpServletRequest request, HttpServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
String name = request.getParameter("username");
String pwd = request.getParameter("password");
User u = user.getUserByName(name);
if(u == null){
request.setAttribute("msg", "找不到該用戶!");
}else if(!u.getPwd().equals(pwd)){
request.setAttribute("msg", "密碼錯誤!");
}else{
return "success";
}
return "error";
}
}
6、在src下創建ActionConfig.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ActionConfig[
<!ELEMENT ActionConfig (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">
]>
<ActionConfig>
<actions>
<action name="LoginAction" class="com.huan.test.LoginAction">
<result name="success">index.jsp</result>
</action>
</actions>
</ActionConfig>
當你順利的跳轉到index.jsp界面的時候,就說明自定義MVC框架沒問題!
今天的struts運行原理就跟大家探討到這裏,想交流的朋友請留言或私信。