一个简单的MVC框架

    一个简单的mvc框架

1、actionmap,action name与action object之间的映射

public class actionmap {

private map<string, object> actionmap = new hashmap<string, object>();

public object getaction(string actionname){
return actionmap.get(actionname);
}

public void initfromproperties(configuration conf) throws instantiationexception, illegalaccessexception, classnotfoundexception{
system.out.println("init actionmap from properties " + conf.getfilename() + " ...");
set<entry<object, object>> keyvalues = conf.entryset();
for(entry<object, object> keyvalue : keyvalues){
this.actionmap.put(keyvalue.getkey().tostring(), class.forname(keyvalue.getvalue().tostring()).newinstance());

}
system.out.println("init actionmap success, total size " + this.actionmap.size());
}
}

2、normalurl是用来解析url中的servlet path中的action name与method name的(本来还有一个restfulurl的,但又不想在这里实现),约定为 http://www.unclepeng.com:xxxx/appname/actionname/methodname/...

public class normalurl {

public static final string  default_method_name = "index";

private string actionname;

private string methodname;

private int level = 2;

public string getactionname() {
return actionname;
}

public string getmethodname() {
return methodname;
}

public static normalurl fromservletpath(string str){
if(str.startswith("/")){
str = str.substring(1);
}
string[] strs = stringutils.split(str, '/', true);
normalurl url = new normalurl();
if(strs == null || strs.length == 0){
throw new illegalargumentexception(string.format("illegal servlet path %s", str));
}
url.actionname = stringutils.split(strs[0], '.', true)[0];
if(strs.length > 1){
url.methodname = stringutils.split(strs[1], '.', true)[0];
}else{
url.methodname = default_method_name;
url.level = 1;
}
return url;
}

public int getlevel() {
return level;
}

public void setlevel(int level) {
this.level = level;
}
}

3、核心dispatcherservlet,在init的时候初始化actionmap,在doget方法中根据servlet path解析出对应的actionname与methodname,再找到对应的action object,然后invoke method

public class dispatcherservlet extends httpservlet {

private static final long serialversionuid = - 8330920476525405610l;

    public static final string include_path_info =
        "javax.servlet.include.path_info";

public dispatcherservlet() {
super();
}

private actionmap actionmap = new actionmap();

public static int file_not_found = 404;

public void destroy() {
super.destroy();
this.actionmap = null;
}

public void doget(httpservletrequest request, httpservletresponse response)
throws servletexception, ioexception {
//split url
string path = request.getservletpath();

normalurl url = normalurl.fromservletpath(path);
string actionname = url.getactionname();
string methodname = url.getmethodname();

//get action by name, if not found, response 404
object action = this.actionmap.getaction(actionname);
if(action == null){//action not found
system.err.println(string.format("action named '%s' not found", actionname));
response.senderror(file_not_found);
}

//invoke action method, and forward if invoke result not returns null
try{
method method = action.getclass().getmethod(methodname, httpservletrequest.class, httpservletresponse.class);
object o = method.invoke(action, new object[]{request, response});
if(o!= null){
if(url.getlevel() == 2){
request.getrequestdispatcher("../" + (string)o).forward(request, response);
}else{
request.getrequestdispatcher((string)o).forward(request, response);
}
return;
}
}catch(exception e){
e.printstacktrace();
response.senderror(file_not_found);
return;
}
}

public void doput(httpservletrequest request, httpservletresponse response)
throws servletexception, ioexception {
doget(request, response);
}

public void dodelete(httpservletrequest request, httpservletresponse response)
throws servletexception, ioexception {
doget(request, response);
}

public void dopost(httpservletrequest request, httpservletresponse response)
throws servletexception, ioexception {
doget(request, response);
}

public void init() throws servletexception {
        servletconfig servletconfig = this.getservletconfig();         
        string mvcconfigfilepath = servletconfig.getinitparameter("mvc_config"); 
        configuration conf = null;
        if(mvcconfigfilepath != null){//case 1, use properites configuration
        try {
conf = new propertiesconfiguration(mvcconfigfilepath);
actionmap.initfromproperties(conf);
return;
} catch (exception e) {
e.printstacktrace();
system.exit(1);
}
        }else{//case 2, use packages setting
        string realpath = this.getservletcontext().getrealpath("/");
        string packagespath = servletconfig.getinitparameter("action_packages");
        string[] packagepatharray = stringutils.split(packagespath, ',', true);
        for(string packagepath : packagepatharray){
       
        }
        }
}

}

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>dispatcher</servlet-name>  
    <servlet-class>com.upeng.webcommons.mvc.dispatcherservlet</servlet-class>  
    <init-param>  
        <param-name>mvc_config</param-name>  
        <param-value>mvc.properties</param-value>  
    </init-param>  
  </servlet>  
  <servlet-mapping>  
    <servlet-name>dispatcher</servlet-name>  
    <url-pattern>*.do</url-pattern>  
  </servlet-mapping>
</web-app>

5、示例action

public class productaction {

public string index(httpservletrequest request, httpservletresponse response){
return "product.jsp";
}
}

6、mvc.properties配置
product =com.upeng.webcommons.test.productaction

7、test
http://localhost:222/webcommons/product/index.do 或者 http://localhost:222/webcommons/product.do,其中的product为action名,index为action中的方法名,当没指定方法时,默认选择action中的index方法

总结与选型过程:
1、本来想实现基于类的mvc,类似struts2,然后把对应的url parameter注入到action的field中,这样做好处是能跟servletapi完全解耦,坏处是为每次请求以反射的方式生成一个临时的action object,效率上要打些折扣。

2、也想过实现类似mvc.net 1.0中的把action实现成sigton,然后实现基于方法的mvc把对应的url parameter注入到方法的参数里然后回调,这样做要求action中不能有重名的方法,另外在查找方法的时候要做一次遍历,稍微比直接指定method name跟parametertypes式的查找慢了那么一点。
但是还需要把string型的url parameters转型为方法参数对应的类型效率上又打了一点点的折扣。综合考虑下便又打消了这个念头

3、这还只是一个mvc雏形,初步实现了url到action乃到action中的method之间的mapping,当然,也可以添加对参数检验,错误处理、国际化等的支持。  

你可能感兴趣的:(java,工作)