谈起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运行原理就跟大家探讨到这里,想交流的朋友请留言或私信。