serlvet的mvc架构最简版

写了个最简单的最粗糙的mvc的架构。

在web的xml中配置过滤器以及在页面上显示的标签。

  
<filter>
		<filter-name>bushyou</filter-name>
		<filter-class>com.bushyou.servlet.dispatcher.FilterDispatcher</filter-class>
	</filter>
	<!-- Extension -->
	<filter-mapping>
		<filter-name>bushyou</filter-name>
		<url-pattern>*.html</url-pattern>
	</filter-mapping>
	<jsp-config>
		<taglib>
			<taglib-uri>/bushyou</taglib-uri>
			<taglib-location>/WEB-INF/bushyou.tld</taglib-location>
		</taglib>
	</jsp-config>

将web的含有.html的请求都经过FilterDispatcher这个过滤器。

    在FilterDispatcher中。
/**
 * 拦截请求
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.servlet.dispatcher;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.bushyou.action.IAction;
import com.bushyou.servlet.context.ActionMapper;
import com.bushyou.servlet.context.ListBushyouActionMapper;
import com.bushyou.servlet.context.ValueContext;

public class FilterDispatcher implements Filter {
    private FilterConfig filterConfig;

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        ServletContext servletContext = getServletContext();
        //将request,response,servletContext放入值域中。
        ValueContext valueContext = new ValueContext(request, response,
                servletContext);
        //将值域放入request对象中。
        request.setAttribute("bushyou_value_context", valueContext);
        //返回的jsp页面。mvc中的 v
        String pa = "";
        if (ListBushyouActionMapper.map.containsKey(valueContext.getPath())) {
            ActionMapper actionMapper = ListBushyouActionMapper.map.get(valueContext.getPath());
            valueContext.setActionMapper(actionMapper);
            IAction action = null;
            String returnStr = null;
            try {
                //反射出acion对象。
                Class classType = Class.forName(valueContext.getActionMapper().getClassPath());
                //执行构造函数。
                Constructor constructor = classType.getConstructor();
                action  = (IAction) constructor.newInstance();
                //执行excuse方法。得到返回值。
                returnStr = action.excute();
            } catch (ClassNotFoundException e) {
            } catch (SecurityException e) {
            } catch (NoSuchMethodException e) {
            } catch (IllegalArgumentException e) {
            } catch (InstantiationException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
            //将action对象放入值域中。
            valueContext.setAction(action);
            pa = valueContext.getActionMapper().getReturnUrl();
        }
        
        //forward
        RequestDispatcher requestDispatcher = request
                .getRequestDispatcher(pa);
        requestDispatcher.forward(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    protected ServletContext getServletContext() {
        return filterConfig.getServletContext();
    }

}

在上面的代码中。我们已经将整个mvc的过程走完了。

当请求经过这个过滤器的时候,过滤器想将值域放入request对象,然后反射出action对象。执行提供出去的excuse方法。

/**
 * 值栈
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.servlet.context;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import com.bushyou.action.IAction;



public class ValueContext {
     ValueMap valueMap;    //值域,放入的request,response,servletContext,action执行后 对象
     ActionMapper actionMapper ;    //action对象
     List extensions = new ArrayList() {{ add("html");}};
     IAction action;
     String path;

    public ValueContext(HttpServletRequest request,
            HttpServletResponse response, ServletContext servletContext) {
        valueMap = new ValueMap();
        valueMap.setRequest(request);
        valueMap.setResponse(response);
        valueMap.setServletContext(servletContext);
        String path = getServletPath(request);
        this.path = path;
        path = dropExtension(path);
        parseNameAndNamespace(path);
    }
    
    /**
     * 拿到请求的url
     * @param request
     * @return
     */
    public static String getServletPath(HttpServletRequest request) {
        String servletPath = request.getServletPath();

        if (null != servletPath && !"".equals(servletPath)) {
            return servletPath;
        }

        String requestUri = request.getRequestURI();
        int startIndex = request.getContextPath().equals("") ? 0 : request.getContextPath().length();
        int endIndex = request.getPathInfo() == null ? requestUri.length() : requestUri.lastIndexOf(request.getPathInfo());

        if (startIndex > endIndex) { // this should not happen
            endIndex = startIndex;
        }

        return requestUri.substring(startIndex, endIndex);
    }
    
    String dropExtension(String name) {
        if (extensions == null) {
            return name;
        }
        Iterator it = extensions.iterator();
        while (it.hasNext()) {
            String extension = "." + (String) it.next();
            if (name.endsWith(extension)) {
                name = name.substring(0, name.length() - extension.length());
                return name;
            }
        }
        return name;
    }

    /**
     * 解析成 actionMapper对象。
     * @param uri
     */
    void parseNameAndNamespace(String uri) {
        String namespace, name;
        int lastSlash = uri.lastIndexOf("/");
        if (lastSlash == -1) {
            namespace = "";
            name = uri;
        } else if (lastSlash == 0) {
            // ww-1046, assume it is the root namespace, it will fallback to
            // default
            // namespace anyway if not found in root namespace.
            namespace = "/";
            name = uri.substring(lastSlash + 1);
        }else {
            namespace = uri.substring(0, lastSlash);
            name = uri.substring(lastSlash + 1);
        }
        
        if (name != null) {
            int pos = name.lastIndexOf('/');
            if (pos > -1 && pos < name.length() - 1) {
                name = name.substring(pos + 1);
            }
        }
        
        actionMapper = new ActionMapper();
        actionMapper.setActionName(name);
        actionMapper.setNamespace(namespace);
        

    }
   
    public Map getValueMap() {
        return valueMap;
    }


    public IAction getAction() {
        return action;
    }

    public void setAction(IAction action) {
        this.valueMap.setAction(action);
        this.action = action;
    }

    public ActionMapper getActionMapper() {
        return actionMapper;
    }

    public void setActionMapper(ActionMapper actionMapper) {
        this.actionMapper = actionMapper;
    }

    public String getPath() {
        return path;
    }

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

}
上面是放入的值域。主要是用在前台的jsp标签使用。
/**
 * property 标签,用于显示属性。
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.servlet.tag;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;

import com.bushyou.servlet.context.ValueContext;

public class PropertyTag extends BodyTagSupport {

    @Override
    public int doEndTag() throws JspException {
        HttpServletRequest request = (HttpServletRequest) pageContext
                .getRequest();
        ValueContext valueContext = (ValueContext) request
                .getAttribute("bushyou_value_context");
        Object o = valueContext.getValueMap().get(value);
        // 取得标签体对象
        try {
            pageContext.getOut().write((String)o);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return super.doAfterBody();
    }

    private String value;
    private boolean escape;
    private static final long serialVersionUID = 8921307524633290358L;

    public String getValue() {
        return value;
    }

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

    public boolean isEscape() {
        return escape;
    }

    public void setEscape(boolean escape) {
        this.escape = escape;
    }

}

上面是jsp的自定义标签的方法。

/**
 * 继承hashmap
 * 
 * 在页面上用于展现的时候,所有的值域都在这个容器内。
 * 
 * 复写他的get方法
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.servlet.context;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;

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

import com.bushyou.action.IAction;

public class ValueMap<K, V> extends HashMap<K, V> {

    /**
     * 
     */
    private static final long serialVersionUID = 4023788960770640801L;

    HttpServletRequest request;
    HttpServletResponse response;
    ServletContext servletContext;
    IAction action;

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

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

    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }

    @Override
    public V get(Object key) {
        V v = null;
        Class classType = action.getClass();
        try {
            Field field = classType.getDeclaredField((String) key);
            if (!Modifier.isPublic(field.getModifiers())) {
                field.setAccessible(true);
            }
            v = (V) field.get(action);
        } catch (SecurityException e) {
        } catch (NoSuchFieldException e) {
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        }
        if (v != null) {
            return v;
        }
        v = super.get(key);
        if (v != null) {
            return v;
        }
        v = (V) request.getAttribute(key + "");
        if (v != null) {
            return v;
        }

        return v;
    }

    public void setAction(IAction action) {
        this.action = action;
    }

}

从标签中取值的相应的类。

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">
	<tlib-version>1.0</tlib-version>
	<short-name>b</short-name>
	<uri>http://www.koubei.com</uri>
	<tag>
		<name>property</name>
		<tag-class>com.bushyou.servlet.tag.PropertyTag</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<name>value</name>
			<required>false</required>
			<rtexprvalue>false</rtexprvalue>
			<description><![CDATA[Value to be displayed]]></description>
		</attribute>
		<attribute>
			<name>escape</name>
			<required>false</required>
			<rtexprvalue>false</rtexprvalue>
			<description><![CDATA[ Whether to escape HTML]]></description>
		</attribute>
	</tag>

</taglib>

tld文件。

现在写点测试的例子:

/**
 * mvc的m的入口
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.action;

import java.io.Serializable;

public interface IAction extends Serializable{
    String excute();
}
/**
 * hello的例子
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.action;

public class YeXiaoGangHelloAction implements IAction{

    /**
     * 
     */
    private static final long serialVersionUID = -5712396283469842107L;
    private String str1;
    private String str2;
    @Override
    public String excute() {
        str1 = "hello str1";
        str2 = "hello str2";
        return "success";
    }
    public String getStr1() {
        return str1;
    }
    public void setStr1(String str1) {
        this.str1 = str1;
    }
    public String getStr2() {
        return str2;
    }
    public void setStr2(String str2) {
        this.str2 = str2;
    }

}
/**
 * test的例子
 *
 * @author shanzhu
 * @version 1.0 2011-9-29
 */
package com.bushyou.action;

public class YeXiaoGangTestAction implements IAction{

    /**
     * 
     */
    private static final long serialVersionUID = -5712396283469842107L;
    private String str1;
    private String str2;
    @Override
    public String excute() {
        str1 = "test str1";
        str2 = "test str2";
        return "success";
    }
    public String getStr1() {
        return str1;
    }
    public void setStr1(String str1) {
        this.str1 = str1;
    }
    public String getStr2() {
        return str2;
    }
    public void setStr2(String str2) {
        this.str2 = str2;
    }

}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="b" uri="/bushyou" %>
<!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>First HelloWorldServlet</title>
</head>
<body>
11
<br />
<b:property value="str1"></b:property>
<br />
22222
<br />
<b:property value="str2"></b:property>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib prefix="b" uri="/bushyou" %>
<!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>test</title>
</head>
<body>
<b:property value="str1"></b:property>
||
<b:property value="str2"></b:property>
</body>
</html>

在浏览器上输入http://localhost/testweb/yexiaogang/hello.html

http://localhost/testweb/yexiaogang/test.html

就可以看到效果了。

相关推荐