用Servlet实现MVC模式

来源:互联网 发布:万方数据库收录期刊 编辑:程序博客网 时间:2024/06/15 00:12
今天的内容:理解MVC的原理方法,以及看代码熟悉MVC的建议框架的实现 
1. 看程序使用mvc实现helloworld的输出; 
2. 看程序使用mvc实现猜数字游戏; 


今天阅读的程序清单: 
DispaterFilter.java 
package com.yuqiaotech.simplejee.mvc; 

import java.io.IOException; 
import java.io.InputStream; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.Map; 

import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.ParserConfigurationException; 

import org.w3c.dom.Document; 
import org.w3c.dom.Element; 
import org.w3c.dom.NodeList; 
import org.xml.sax.SAXException; 
/** 
* 本过滤器是作为mvc的前端控制器。 
* 用来根据请求路径和配置文件的内容,触发相应的处理类(我们称为handler)的handler方法, 
* 然后获取该方法返回的对象,调用其display方法进行显示。 

*/ 
public class DispatcherFilter implements Filter { 
private String contextPath; 
public String configFile = "/mvc.xml"; 
public Map<String,HandlerConfig> handlerMapping = new HashMap<String,HandlerConfig>(); 
/** 
* 初始化。 
* 读取配置文件的位置,分析配置文件的内容。 
* 并将配置内容转化为HandlerConfig对象, 
* 然后以contextPath+path为key,放到一个map里,方便后续使用。 
*/ 
public void init(FilterConfig cfg) throws ServletException { 
System.out.println("DispatcherFilter init."); 
String configFile = cfg.getInitParameter("configFile"); 
if(configFile != null)this.configFile = configFile; 
contextPath = cfg.getServletContext().getContextPath(); 
parseConfigFile(); 


private void parseConfigFile(){ 
        InputStream in = DispatcherFilter.class.getResourceAsStream(configFile); 
        DocumentBuilderFactory factory = DocumentBuilderFactory  
                .newInstance(); 
        DocumentBuilder builder; 
try { 
builder = factory.newDocumentBuilder(); 
Document doc = builder.parse(in); 
NodeList nodes = doc.getElementsByTagName("handler"); 
for (int i = 0; i < nodes.getLength(); i++) { 
Element ele = (Element)nodes.item(i); 
//现在很简单只有几个属性 
String path = ele.getAttribute("path"); 
String clazz = ele.getAttribute("class"); 
String method = ele.getAttribute("method"); 
HandlerConfig handlerConfig = new HandlerConfig(); 
handlerConfig.setClazz(clazz); 
handlerConfig.setPath(path); 
handlerConfig.setMethod(method); 

NodeList views = ele.getElementsByTagName("view");//注意与ele.getChildNodes()的区别 
if(views != null){ 
for (int j = 0; j < views.getLength(); j++) { 
Element viewEle = (Element) views.item(j); 
View v = new View(); 
v.setName(viewEle.getAttribute("name")); 
v.setType(viewEle.getAttribute("type")); 
v.setValue(viewEle.getFirstChild().getNodeValue());//注意这里 
handlerConfig.putView(v.getName(), v); 



handlerMapping.put(contextPath+path, handlerConfig); 

} catch (ParserConfigurationException e) { 
throw new RuntimeException(e); 
} catch (SAXException e) { 
throw new RuntimeException(e); 
} catch (IOException e) { 
throw new RuntimeException(e); 
}  

public void destroy() { 
System.out.println("DispatcherFilter: bye."); 

/** 
* 拦截请求。 

* 从handlerMapping查找是否有对应当前请求路径的handler, 
* 如果没有的话,继续chain.doFilter(request, response); 
* 如果有的话,就实例化handler类,然后调用其handler方法, 
* 然后处理返回的对象,如果返回的是String,那么包装成一个ForwardView对象, 
* 否则调用返回对象的display方法。 
*/ 
public void doFilter(ServletRequest req, ServletResponse res, 
FilterChain chain) throws IOException, ServletException { 
        HttpServletRequest request = (HttpServletRequest)req; 
        HttpServletResponse response = (HttpServletResponse)res; 
        
        String url = request.getRequestURI(); 
        HandlerConfig handlerConfig = handlerMapping.get(url); 
        if(handlerConfig != null){ 
        MvcServletContext context = new MvcServletContext(); 
        context.setRequest(request); 
        context.setResponse(response); 
        MvcContext.context.set(context); 
        
        Object handler = newInstance(handlerConfig); 
        
        //获取需要执行的方法名 
String methodName = "handler"; 
String methodNameCfg = handlerConfig.getMethod(); 
if( methodNameCfg != null && !"".equals(methodNameCfg)){ 
methodName = handlerConfig.getMethod(); 
}else{ 
Enumeration<String> enuma = request.getParameterNames(); 
while(enuma.hasMoreElements()){ 
String pName = enuma.nextElement(); 
if(pName.startsWith("method:")){ 
methodName = pName.substring("method:".length()); 
break; 


}//struts2还支持actionName!methodName的方式。 
//执行方法并得到view对象 
        Object view = invokeHandler(handlerConfig,handler,methodName); 
        if(view != null){ 
        //获取如果返回的是字符串, 
        //那么就使用该字符串从配置中找到相应的view 
        if(view instanceof String){ 
        View v = handlerConfig.getView((String)view); 
        if(v == null)throw new RuntimeException("no such view with name ["+view+"]"); 
        //这里显然太不灵活,不具备可扩展性。 
        String type = v.getType(); 
        String viewValue = v.getValue(); 
        if("redirect".equals(type)){ 
        view = new RedirectView(viewValue); 
        }else{ 
        view = new ForwardView(viewValue); 
        } 
        } 
        invokeDisplay(handlerConfig,view); 
        } 
        //如果view为null,说明handler已经处理了显示问题 
        }else{ 
        chain.doFilter(request, response); 
        } 

/** 
* 实例化Handler类。 
* @param handlerConfig 
* @return 
*/ 
private Object newInstance(HandlerConfig handlerConfig){ 
try { 
return Class.forName(handlerConfig.getClazz()).newInstance(); 
} catch (InstantiationException e) { 
throw new RuntimeException(e); 
} catch (IllegalAccessException e) { 
throw new RuntimeException(e); 
} catch (ClassNotFoundException e) { 
throw new RuntimeException(e); 


/** 
* 触发Handler类的handler方法。 
* 本mvc框架处于演示反射的目的,以及为struts2做准备的目的, 
* 没有规定handler类必须实现特定接口,而只是规定需要有个方法名叫handler。 
* @param handlerConfig 
* @param o 
* @return 
*/ 
private Object invokeHandler(HandlerConfig handlerConfig,Object o,String methodName){ 
try { 

Method m = o.getClass().getMethod(methodName, null); 
return m.invoke(o, null); 
} catch (SecurityException e) { 
throw new RuntimeException(e); 
} catch (NoSuchMethodException e) { 
throw new RuntimeException(e); 
} catch (IllegalArgumentException e) { 
throw new RuntimeException(e); 
} catch (IllegalAccessException e) { 
throw new RuntimeException(e); 
} catch (InvocationTargetException e) { 
throw new RuntimeException(e); 


/** 
* 触发handler方法返回的对象的display方法。 
* @param handlerConfig 
* @param view 
*/ 
private void invokeDisplay(HandlerConfig handlerConfig,Object view){ 
try { 
Method m = view.getClass().getMethod("display", null); 
m.invoke(view, null); 
} catch (SecurityException e) { 
throw new RuntimeException(e); 
} catch (NoSuchMethodException e) { 
throw new RuntimeException(e); 
} catch (IllegalArgumentException e) { 
throw new RuntimeException(e); 
} catch (IllegalAccessException e) { 
throw new RuntimeException(e); 
} catch (InvocationTargetException e) { 
throw new RuntimeException(e); 


/** 

*/ 
class HandlerConfig{ 
private String path; 
private String clazz; 
private String method; 
private Map<String, View> views = new HashMap<String, View>(); 
public String getPath() { 
return path; 

public void setPath(String path) { 
this.path = path; 

public String getClazz() { 
return clazz; 

public void setClazz(String clazz) { 
this.clazz = clazz; 


public String getMethod() { 
return method; 

public void setMethod(String method) { 
this.method = method; 

public void putView(String name,View v){ 
views.put(name, v); 

public View getView(String name){ 
return this.views.get(name); 


}; 
class View{ 
private String name; 
private String type; 
private String value; 
public String getName() { 
return name; 

public void setName(String name) { 
this.name = name; 

public String getType() { 
return type; 

public void setType(String type) { 
this.type = type; 

public String getValue() { 
return value; 

public void setValue(String value) { 
this.value = value; 

public String toString(){ 
return name+"_"+type+"_"+value; 







ForwardView.java 

package com.yuqiaotech.simplejee.mvc; 

import java.io.IOException; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class ForwardView { 

private String forwardTo; 
public ForwardView(String forwardTo) { 
this.forwardTo = forwardTo; 

public void display(){ 
HttpServletRequest request = MvcContext.getRequest(); 
HttpServletResponse response = MvcContext.getResponse(); 
try { 
request.getRequestDispatcher(forwardTo).forward(request, response); 
} catch (ServletException e) { 
throw new RuntimeException(e.getMessage(),e); 
} catch (IOException e) { 
throw new RuntimeException(e.getMessage(),e); 





MvcContext.java 
package com.yuqiaotech.simplejee.mvc; 

import javax.servlet.ServletContext; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 

/** 
* 这里主要是通过ThreadLocal技术,使得在一个线程之内,可以方便的 
* 访问request,response等对象,而不是通过一层层的传输传递。 

*/ 
public class MvcContext { 
    public static final ThreadLocal <MvcServletContext> context = 
        new ThreadLocal <MvcServletContext> (); 
    public static HttpServletRequest getRequest(){ 
    return context.get().getRequest(); 
    } 
    public static HttpSession getSession(){ 
    return context.get().getRequest().getSession(); 
    } 
    public static ServletContext getApplication(){ 
    return context.get().getRequest().getSession().getServletContext(); 
    } 
    public static HttpServletResponse getResponse(){ 
    return context.get().getResponse(); 
    } 


MvcServletContext.java 

package com.yuqiaotech.simplejee.mvc; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
/** 
* 为方便存取request和response写的一个简单的类。 

*/ 
public class MvcServletContext { 
private HttpServletRequest request; 
private HttpServletResponse response; 
public HttpServletRequest getRequest() { 
return request; 

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

public HttpServletResponse getResponse() { 
return response; 

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



RedirectView.java 

package com.yuqiaotech.simplejee.mvc; 

import java.io.IOException; 

import javax.servlet.http.HttpServletResponse; 
/** 
* 发送Location头信息的转向方式。 

*/ 
public class RedirectView { 

private String redirect; 
public RedirectView(String redirect) { 
this.redirect = redirect; 

public void display(){ 
HttpServletResponse response = MvcContext.getResponse(); 
try { 
response.sendRedirect(redirect); 
} catch (IOException e) { 
throw new RuntimeException(e.getMessage(),e); 




自己写的MVC猜数字程序清单: 
NumberGuessServlet1.java 
package com.yuqiao.qiu; 

import java.io.IOException; 
import java.io.PrintWriter; 
import java.util.Random; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

public class NumberGuessServlet1 extends HttpServlet { 

public  NumberGuessServlet1(){ 


@Override 
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException { 
doPost(request,response); 




public void doPost(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException{ 


// request.getSession().removeAttribute("randomNo"); 

String act=request.getParameter("act"); 
// Integer randomNo1=(Integer)request.getSession().getAttribute("randomNo"); 

if(null==request.getSession().getAttribute("randomNo")||"NewGuess".equals(act)) 

Random random=new Random(); 
Integer randomNo=random.nextInt(101); 
System.out.print(randomNo); 
request.getSession().removeAttribute("GuessTimes"); 
request.getSession().setAttribute("randomNo", randomNo); 

if(null==this.getServletContext().getAttribute("times")){ 

this.getServletContext().setAttribute("times", 0);

else{ 
Integer times=(Integer)this.getServletContext().getAttribute("times"); 
++times; 
this.getServletContext().setAttribute("times",times); 

if("NewGuess".equals(act)) 

// this.getServletContext().setAttribute("times",times); 
request.getRequestDispatcher("/list.jsp").forward(request, response); 



if("guess".equals(act)) 

Integer number=Integer.parseInt(request.getParameter("number").trim()); 
request.getSession().setAttribute("number", number); 
Integer GuessTimes=(Integer)request.getSession().getAttribute("GuessTimes"); 
if(GuessTimes == null)GuessTimes = 0; 
GuessTimes+=1; 
request.getSession().setAttribute("GuessTimes", GuessTimes); 

if(number<(Integer)request.getSession().getAttribute("randomNo")){ 
request.setAttribute("content", "对不起你猜的数字小了"); 

if(number>(Integer)request.getSession().getAttribute("randomNo")){ 
request.setAttribute("content", "对不起你猜的数字大了"); 

if(number==(Integer)request.getSession().getAttribute("randomNo")){ 
// request.getSession().setAttribute("number", number); 
request.getSession().removeAttribute("randomNo"); 
request.setAttribute("content", "恭喜你,你猜对了");

// 
request.getRequestDispatcher("/result.jsp").forward(request, response); 

if("new".equals(act)) 

request.getRequestDispatcher("/list.jsp").forward(request, response); 





@Override 
// protected void service(HttpServletRequest request, HttpServletResponse response) 
// throws ServletException, IOException { 
//
// } 
// 
// public Integer StringToInt(String number) 
// { 
// return Integer.parseInt(number); 
// } 

public void destroy() { 
super.destroy(); // Just puts "destroy" string in log 
// Put your code here 

public void init() throws ServletException { 
// Put your code here 






Web.xml的配置 

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

    <welcome-file-list> 
    <welcome-file>/list.jsp</welcome-file> 
    </welcome-file-list> 

<servlet> 
    <servlet-name>NumberGuessServlet</servlet-name> 
    <servlet-class>com.yuqiao.qiu.NumberGuessServlet1</servlet-class> 
  </servlet> 
  
  
  <servlet-mapping> 
    <servlet-name>NumberGuessServlet</servlet-name> 
    <url-pattern>/NumberGuessServlet</url-pattern> 
  </servlet-mapping> 
  

</web-app> 

  




List.jsp 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<% 
String path = request.getContextPath(); 
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 
%> 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
  <head> 
    <base href="<%=basePath%>"> 
    
    <title>欢迎进入猜数字游戏</title> 
    
<meta http-equiv="pragma" content="no-cache"> 
<meta http-equiv="cache-control" content="no-cache"> 
<meta http-equiv="expires" content="0">    
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
<meta http-equiv="description" content="This is my page"> 
<!-- 
<link rel="stylesheet" type="text/css" href="styles.css"> 
--> 

  </head> 
  
  <body> 
   <div align=center><h1>NumberGuess</h1></div> 
   <p></p> 
   <p></p> 
    <hr width=80%> 
    <div align="center"><a href="<%=request.getContextPath() %>/NumberGuessServlet?act=NewGuess">新游戏</a></div> 
    <div align=center> 
       <form name=f action="<%=request.getContextPath() %>/NumberGuessServlet?act=guess" method="post"> 
          <input type="text" size=8  name="number"> 
          <input type="submit" value="guess"> 
       </form> 
    </div> 
  </body> 
</html> 



Result.jsp 

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 
<% 
String path = request.getContextPath(); 
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 
%> 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html> 
  <head> 
    <base href="<%=basePath%>"> 
    
    <title>My JSP 'result.jsp' starting page</title> 
    
<meta http-equiv="pragma" content="no-cache"> 
<meta http-equiv="cache-control" content="no-cache"> 
<meta http-equiv="expires" content="0">    
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 
<meta http-equiv="description" content="This is my page"> 
<!-- 
<link rel="stylesheet" type="text/css" href="styles.css"> 
--> 

  </head> 
  
  <body> 
  <div align=center><P>结果显示</P></div> 
  <p></p> 
  <p></p> 
  <hr width="80%"></hr> 
  <div align=center>${content}</div> 
  <div align=center> 你总共猜了${GuessTimes }次</div> 
  <div align=center>总共有${times}人玩过此游戏</div> 
  <div align=center><a href='<%=request.getContextPath()%>/NumberGuessServlet?act=new'>返回重新猜</a></div> 
  
  
  
  </body> 
</html> 


今天学到的方法: 
1. getContextPath() 获取的路径到底是哪边! 
2. org.w3c.com.Node 
NodeList getChildNodes() 
包含此节点的所有子节点的 NodeList。如果不存在子节点,则这是不包含节点的 NodeList 
   Org.w3c.com.Element NodeList getElementsByTagName(String name) 
以文档顺序返回具有给定标记名称的所有后代 Elements 的 NodeList。
0 0
原创粉丝点击