自己动手写Struts
1. MVC框架示意图
本例简单介绍:
1>.视图层使用JSP实现
2>.控制层使用Servlet实现,整个框架采用同一个Servlet,以实现请求的中转。
3>.模型层采用JAVA实现,主要决定用来做什么。
模型层后可以添加一个DAO目的是将决定做什么和具体怎么做分开。
整个框架的大致流程:首先客户端发送请求,提交JSP页面给中转器(SERVLET);中转器根据用户的请求,选择相应的模型层,即LOGIC,LOGIC进行相应的逻辑处理;如果需要使用数据库,则通过DAO进行相应的数据库操作。
2. 视图层设计
视图层采用JSP,JAVASCRIPT,JAVABEAN和自定义标签组成。
页面中常用到的代码:
1>.便于统一管理,在JSP页面顶部添加如下代码:
<%! Public static final String pageName=”页面名称” %>
2>.提交时防止页面的跳转混乱,在JSP页面底部添加如下代码:
<script>
Window.name=”<%=页面名称+”_”+session.getId()%>”;
</script>
3>.在提交数据时,因为在控制层需要判断客户端提交的动作、要调用的模型层和要返回的页面,所以需要在JSP的表单中隐藏3个元素:method(动作)、logicName(要调用的模型层)和forwardJsp(要返回的页面)。示例代码如下:
<form name="form1" action="" method="post">
<input type="hidden" name="action" value="">
<input type="hidden" name="logicName" value="">
<input type="hidden" name="forwardJsp" value=" ">
</form>
这样,在提交数据时,就可以通过submit方法来提交数据。示例代码如下:
function submit() {
form1.forwardJsp.value = "index";
form1.logicName.value = "Logic";
form1.target = "<%="index _"+session.getId()%>";
form1.action.value = "insert";
form1.submit();
}
一个完整的JSP实例:
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%!public static final String page = "index";%>
<%
HashMap<String, Object> dataOut = (null == request
.getAttribute("dataOut")) ? new HashMap<String, Object>()
: (HashMap<String, Object>) request.getAttribute("dataOut");
String message = (String)dataOut.get("message");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>index</title>
<mce:script type="text/javascript"><!--
function submit1(target,method){
form1.target = target;
form1.method.value = method;
form1.submit();
}
function insert() {
form1.forwordJsp.value = "index";
form1.logicName.value ="Check";
submit1('<%="index_"+session.getId()%>','login');
}
// --></mce:script>
</head>
<body>
<p><%=message%></p>
<form action="index.do" name="form1" method="post" target="">
<input type="hidden" name="logicName" value="" />
<input type="hidden" name="forwordJsp" value="" />
<input type="hidden" name="method" value="" />
<table>
<tr>
<td>
UserName
</td>
<td>
<input type="text" name="userName" value="" />
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
<input type="password" name="password" value="" />
</td>
</tr>
<tr>
<td>
<input type="button" οnclick="insert()" value="提交" />
</td>
<td>
<input type="reset" value="重置" />
</td>
</tr>
</table>
</form>
<br>
<mce:script type="text/javascript"><!--
window.name="<%="index_"+session.getId()%>";
// --></mce:script>
</body>
</html>
3.控制层的设计
1>.首先写意方法获取从视图层传过来的数据。
private HashMap<String, Object> getRequestToMap(HttpServletRequest request) {
HashMap<String, Object> dateIn = new HashMap<String, Object>();
for (Enumeration<String> e = request.getParameterNames(); e
.hasMoreElements();) {
String name = e.nextElement();
String[] values = request.getParameterValues(name);
if (values == null) {
dateIn.put(name, "");
} else if (values.length == 1) {
dateIn.put(name, values[0]);
} else {
dateIn.put(name, values);
}
}
return dateIn;
}
使用HashMap封装了所有的数据。
2>.处理请求转移到模型层。
一个视图对应一个模型,也可能一个视图对应多个模型,但只有一个控制器,所以,为了实现一个控制器可以转发到多个模型中去,就需要使用接口,让所有模型都实现这个接口,然后在控制器里,仅仅是面对接口编程即可。这里定义一个接口Action.java,Action.java的示例代码如下:
package cn.com.action;
import java.util.HashMap;
public interface Action {
public abstract HashMap<String, Object> do_Action(
HashMap<String, Object> dataIn);
}
在控制器中只针对这个接口处理即可。示例代码如下:
Action action = (Action) Class
.forName("cn.com.action." + logicName).newInstance();
HashMap<String, Object> dataOut = action.do_Action(dataIn);
3>.返回视图。
request.setAttribute("dataOut", dataOut);
String sendRedirect = (String) dataOut.get("success");
if(null != sendRedirect && !"".equals(sendRedirect)){
response.sendRedirect("/MVCStruts/jsp/"+sendRedirect);
return;
}
RequestDispatcher dispatcher = request
.getRequestDispatcher("/jsp/" + forwardJsp
+ ".jsp");
dispatcher.forward(request, response);
4>.定义web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
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_2_5.xsd">
<servlet>
<servlet-name>ControlServlet</servlet-name>
<servlet-class>cn.com.control.ControlServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControlServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
一个完整的控制层实例:
4.模型层设计
package cn.com.control;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.com.action.Action;
public class ControlServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
do_Dispatcher(request, response);
}
private void do_Dispatcher(HttpServletRequest request,
HttpServletResponse response) throws UnsupportedEncodingException {
request.setCharacterEncoding("GBK");
HashMap<String, Object> dataIn = getRequestToMap(request);
String forwardJsp = request.getParameter("forwordJsp");
String logicName = request.getParameter("logicName");
try {
Action action = (Action) Class
.forName("cn.com.action." + logicName).newInstance();
HashMap<String, Object> dataOut = action.do_Action(dataIn);
request.setAttribute("dataOut", dataOut);
String sendRedirect = (String) dataOut.get("success");
if(null != sendRedirect && !"".equals(sendRedirect)){
response.sendRedirect("/MVCStruts/jsp/"+sendRedirect);
return;
}
RequestDispatcher dispatcher = request
.getRequestDispatcher("/jsp/" + forwardJsp
+ ".jsp");
dispatcher.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
private HashMap<String, Object> getRequestToMap(HttpServletRequest request) {
HashMap<String, Object> dateIn = new HashMap<String, Object>();
for (Enumeration<String> e = request.getParameterNames(); e
.hasMoreElements();) {
String name = e.nextElement();
String[] values = request.getParameterValues(name);
if (values == null) {
dateIn.put(name, "");
} else if (values.length == 1) {
dateIn.put(name, values[0]);
} else {
dateIn.put(name, values);
}
}
return dateIn;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
super.destroy();
}
@Override
public void init() throws ServletException {
// TODO Auto-generated method stub
super.init();
}
}
在上面的示例中,并没有具体地给出从视图层传来的请求如何经过控制器到达模型层的,只是给出了一个接口,然后让所有模型层类都实现这个接口,最后通过这个接口中的方法doAction来转入模型层进行处理
1>.实现一个公用的接口Action.java
package cn.com.action;
import java.util.HashMap;
public interface Action {
public abstract HashMap<String, Object> do_Action(
HashMap<String, Object> dataIn);
}
所有模型层实现这个接口,实例:
package cn.com.action;
import java.util.HashMap;
public class Check implements Action {
public HashMap<String, Object> do_Action(HashMap<String, Object> dataIn) {
String method = (String)dataIn.get("method");
HashMap<String, Object> dataOut = null;
if("".equals(method) || null==method){
dataOut = init(dataIn);
}else if("login".equals(method)){
dataOut = login(dataIn);
}
return dataOut;
}
private HashMap<String, Object> login(HashMap<String, Object> dataIn) {
System.out.println("login");
String userName = (String) dataIn.get("userName");
String password = (String) dataIn.get("password");
String message = "";
if("".equals(userName) || "".equals(password)){
System.out.println("error");
message = "请输入用户名和密码!";
}else if(!("zhangsan".equals(userName) || "123".equals(password))){
//System.out.println("success");
message = "用户名或密码错误!";
}else if("zhangsan".equals(userName) && "123".equals(password)){
String sendRedirect = "success.jsp";
dataIn.put("success", sendRedirect);
message = "登录成功";
}
dataIn.put("message", message);
return dataIn;
}
private HashMap<String, Object> init(HashMap<String, Object> dataIn) {
String messge="初始化中";
dataIn.put("message", messge);
return dataIn;
}
}
上面实现的MVC框架,在JSP中必须指定LogicName(模型层处理的类名),method(模型层中处理请求的方法),forwJsp(要返回的页面),控制器通过得到这几个参数来决定怎么执行相应的操作,也就是调用哪个模型,返回到哪个JSP页面。显然如果要是每次写一JSP页面都要决定这几个参数,那是相当的繁琐的,而且完全是不可取的。但本例基本上实现了MVC的流程及框架的雏形。将在下面改进此框架。