一直以来对0配置的mvc框架很感兴趣。
最近,突发奇想,想试验一下如何利用url来实现契约式的mvc零配置框架。
首先,我们以一个普通的url为例。
"http://ipaddress:prot/project_name/business_name/moudle_name/action_name/"
我们假定从business_name开始我们对应的是java中的类包,moudle_name我们对应成 相应业务的对象名称。
而action_name则是 这个对象中的方法名称。
上面是我们假定的规则。
然后我们可以通过reflect可以找到这个请求相关的方法。这样就可以不同过配置文件来配置相关信息。
同事,我们在定义相对应的annotation来为操作成功失败后做跳转。
以上就是一个大概的思路。现在给大家看看相应的代码。
首先是我们的web。xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" 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-app_2_4.xsd"> <servlet> <servlet-name>action</servlet-name> <servlet-class>com.pig.hub.dev.frameWork.action.ActionServlet</servlet-class> <init-param> <param-name>filename</param-name> <param-value>pig.web</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.pig</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
其中定义了com.pig.hub.dev.frameWork.action.ActionServlet来去拦截所有的请求(。pig)。filename这个属性是为了给出系统中相应的完成的包名。
下面是ActionServlet相应的java代码
import com.pig.hub.dev.frameWork.action.exception.MakeUriException; /** * @author */ public abstract class AbActionServlet extends HttpServlet implements BasicActionServlet { /** * */ private static final long serialVersionUID = 7911661010594064823L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { doWork(request, response); } catch (MakeUriException e) { } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { doWork(request, response); } catch (MakeUriException e) { } } /** * @param request * @param response * @throws ServletException * @throws IOException * @see com.pig.hub.dev.frameWork.action.BasicActionServlet#doWork(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) */ public abstract void doWork(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, MakeUriException; } ---------------------------------------------------------
package com.pig.hub.dev.frameWork.action; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.pig.hub.dev.frameWork.action.exception.MakeUriException; /** * */ public interface BasicActionServlet { /** * @param request * @param response * @throws ServletException * @throws IOException * @throws MakeUriException */ public void doWork(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException,MakeUriException; } -------------------------------------------------------
package com.pig.hub.dev.frameWork.action; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.pig.hub.dev.frameWork.action.config.MethodBean; import com.pig.hub.dev.frameWork.action.exception.MakeUriException; import com.pig.hub.dev.frameWork.action.exception.MappingException; import com.pig.hub.dev.frameWork.action.exception.MethodException; public class ActionServlet extends AbActionServlet implements BasicActionServlet { /** * */ private static final long serialVersionUID = 2848825411739564234L; private String fileName; public void init() throws ServletException { fileName = this.getInitParameter("filename"); } @SuppressWarnings("unchecked") public void doWork(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, MakeUriException { String s[] = BusinessConfig.makeUri(request); String errorMessage=""; HashMap map = new HashMap(); if (s.length > 2) throw new MakeUriException(); try { MethodBean mBean = BusinessConfig.makeConfig(s, fileName); Method m = mBean.getM(); Class c = mBean.getC(); m.invoke(c.newInstance(), request, response); map = MappingUtil.makeHashMap(m); request.getRequestDispatcher((String) map.get("success")).forward( request, response); } catch (SecurityException e) { errorMessage = "someting"; } catch (ClassNotFoundException e1) { errorMessage = "someting"; } catch (MethodException e2) { errorMessage = "someting"; } catch (NoSuchMethodException e3) { errorMessage = "someting"; } catch (IllegalArgumentException e4) { errorMessage = "someting"; } catch (IllegalAccessException e5) { errorMessage = "someting"; } catch (InvocationTargetException e6) { errorMessage = "someting"; } catch (InstantiationException e) { errorMessage = "someting"; } catch (MappingException e) { errorMessage = "someting"; } finally { if (!errorMessage.equals("")) request.getRequestDispatcher((String) map.get("fail")).forward( request, response); } } }
以上基本有一个抽象类一个接口一个实现构成,其实只是用到了简单的模板方法。
其中,String s[] = BusinessConfig.makeUri(request);是为了得到url中相应的业务名对象名以及方法名称。
然后通过MethodBean mBean = BusinessConfig.makeConfig(s, fileName)来构建一个自定义的方法对象。
package com.pig.hub.dev.frameWork.action.config; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.pig.hub.dev.frameWork.action.exception.MethodException; public class MethodBean implements java.io.Serializable { /** * */ private static final long serialVersionUID = -5753278542873561978L; private Class c; private Method m; private String name; public Class getC() { return c; } public void setC(Class c) { this.c = c; } public Method getM() { return m; } public void setM() throws MethodException, ClassNotFoundException, SecurityException, NoSuchMethodException { if (name == null || name.equals("")) throw new MethodException(); if (c == null) throw new ClassNotFoundException(); m = c.getDeclaredMethod(name, HttpServletRequest.class, HttpServletResponse.class); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
通过 m = c.getDeclaredMethod(name, HttpServletRequest.class, HttpServletResponse.class);得到url对应的方法对象。
下面就简单了
m.invoke(c.newInstance(), request, response);
执行而已。
现在通过契约式的url可以访问到相应的对象了。那么还差一个如何跳转。
首先我们自定义一个annotation
package com.pig.hub.dev.frameWork.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MappingConfig { String success(); String fail(); String exception(); }
其中有三个属性,success fail exception分别指在成功后跳转的地方或者失败后跳转的。。。
下面是在实际对象中如何使用这三个对象。
public class aa { @MappingConfig(success="../index.jsp",fail="",exception="") public void bb(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.print("test------------"); request.setAttribute("123", "成功了"); } }
然后通过
package com.pig.hub.dev.frameWork.action; import java.lang.reflect.Method; import java.util.HashMap; import com.pig.hub.dev.frameWork.action.exception.MappingException; import com.pig.hub.dev.frameWork.annotation.MappingConfig; public class MappingUtil { @SuppressWarnings("unchecked") public static HashMap makeHashMap(Method m) throws MappingException { MappingConfig an = m.getAnnotation(MappingConfig.class); if (an == null) throw new MappingException(); HashMap map = new HashMap(); map.put("success", an.success()); map.put("fail", an.fail()); map.put("exception", an.exception()); return map; } }
得到要执行的方法上的annotation然后将他属性放入一个hashmap中。
下面就是跳转了(成功的)
request.getRequestDispatcher((String) map.get("success")).forward(
request, response);
这样就完成了一个基于url契约的零配置mvc的实现。
呵呵,实在有点简单,问题也很多。
写这个东西的目的其实在于学习一下java的基本知识。现在大家没事干就说这样那样的框架,我想不如自己来试着如何实现。通过自己来实现,可以明白好多东西,然后在去用那写框架我想会更加得心应手。
以上纯属功能上的实现,问题很多很多,例如在actionservlet中有一大堆的异常,这样写出来很别扭,其中还有自己定义的异常。
欢迎大家给我提出建议。