`
xiaoqzai414
  • 浏览: 15530 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

用Servlet实现MVC模式

阅读更多
MVC模式的学习

今天的内容:理解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。



分享到:
评论
3 楼 spe294096580 2012-06-11  
[size=medium]zxX
[/align][align=left]
[flash=200,200][/flash]
[url][/url]

    [*]

    [*]
引用
[/i][i]
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
引用
[/size]
2 楼 spe294096580 2012-06-11  
zczxzdcx
1 楼 spe294096580 2012-06-11  
xs[b][/b][i][/i][u][/u]

相关推荐

Global site tag (gtag.js) - Google Analytics