自己动手实现IOC和MVC(七)

来源:互联网 发布:庄家统软件2016 编辑:程序博客网 时间:2024/06/15 19:28

相信大家都用过struts或者spring mvc这样的mvc框架,先来介绍一下mvc吧,

MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller)。 MVC模式的目的就是实现Web系统的职能分工。 Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现。 View层用于与用户的交互,通常用JSP来实现。 Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。

mvc带来的好处 ,google一下一大箩筐,这里就不说了。

其实没个mvc底层的实现就是一个大的servlet ,来拦截我们得请求 ,分发到不同处理操作,然后跳转到相应的视图,当然这些都可配置的,mvc这个project我们也会机遇java annotation的方式来实现的

我们知道spring 通过java annotation就可以注释一个类为action ,在方法上添加上一个java annotation 就可以配置请求的路径了 ,那么我们得实现也参考这个过程来完成我们要做的事情

①定义请求路径的java annotation

RequestMapping.java

package com.ajunframework.servlet.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** *  * @author ajun * @http://blog.csdn.net/ajun_studio */@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME)  @Documented  @Inherited  public @interface RequestMapping {public String value() default "";}
此时请求的路径 ,我们可以做一个解析 ,然后找到你的action类中方法上的注释和你解析出来的路径一致,说名就是这个方法,接着我们利用java反射机制调用这个类得方法,就可以了,接着这个方法会返回一个路径,就是我们跳转的视图返回给我们总的servlet ,就行跳转。

这些功能改怎么实现呢?

首先考虑你返回的视图的路径,其中还有包含的数据怎么办呢?还有就是服务器端跳转还是客户端跳转呢?

此时我们要定义一个视图类,对这些操作属性进行封装,其中包括条状的路径 、展现到页面的数据(这里只是做request范围内的)、跳转方式。

下面是视图类得封装代码:

package com.ajunframework.servlet.view;import com.ajunframework.servlet.constant.DispatchActionConstant;/** * @author ajun * @http://blog.csdn.net/ajun_studio   **/public class View {private String url;//跳转路径private String dispathAction = DispatchActionConstant.FORWARD;//跳转方式public View(String url) {this.url = url;}public View(String url,String name,Object value) {this.url = url;ViewData view = new ViewData();view.put(name, value);}public View(String url,String name,String dispathAction ,Object value) {this.dispathAction = dispathAction;this.url = url;ViewData view = new ViewData();//请看后面的代码view.put(name, value);}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getDispathAction() {return dispathAction;}public void setDispathAction(String dispathAction) {this.dispathAction = dispathAction;}}
request范围的数据存储类ViewData.java

package com.ajunframework.servlet.view;import javax.servlet.http.HttpServletRequest;import com.ajunframework.servlet.WebContext;/** * @author ajun * @http://blog.csdn.net/ajun_studio   **/public class ViewData {private HttpServletRequest request;public ViewData() {initRequestAndResponse();}private void initRequestAndResponse(){this.request = WebContext.requestHodler.get();//下面会介绍}public void put(String name,Object value){this.request.setAttribute(name, value);}}
还有就是我们在每次请求的时候,到达action里的时候 我们会用ViewData.put()往request中存数据,而action中并没有request的情况如何处理呢?

下面我提供一个在进入action之前进行初始化request的类WebContext.java

package com.ajunframework.servlet;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;/** * @author ajun * @http://blog.csdn.net/ajun_studio   **/public class WebContext {public static ThreadLocal<HttpServletRequest> requestHodler = new ThreadLocal<HttpServletRequest>();   public HttpServletRequest getRequest(){           return requestHodler.get();    }   public HttpSession getSession(){           return requestHodler.get().getSession();    }   public ServletContext getServletContext(){           return requestHodler.get().getSession().getServletContext();    }}

通过这个类 ,你可以当前请求的request或者session相关请求类的实例变量,线程间互不干扰的,因为用到了ThreadLocal这个类。

下面来介绍一下servlet的实现,这是无论是get post请求都会调用我封转的方法 ,这个方法,会根据你请求的url,找到你对象的action ,然后调用其中方法注释和改url配置的方法,同事返回View视图类,接着根据View中的路径,返回到相应的视图。

为了方便这里我用到了我们写的ioc,用于在servlet初始化的过程中,实例化和注入相关的class,供我们调用。这里耦合在一起了 ,不是很好。。。

DispatchServlet.java

package com.ajunframework.servlet;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.ajunframework.beans.applicationContext.AnnotationClassPathApplicationContext;import com.ajunframework.beans.factory.AnnotationBeanFactory;import com.ajunframework.beans.factory.RequestMapingMap;import com.ajunframework.beans.utils.BeanUtils;import com.ajunframework.servlet.annotation.RequestMapping;import com.ajunframework.servlet.constant.DispatchActionConstant;import com.ajunframework.servlet.view.View;/** * @author ajun * @http://blog.csdn.net/ajun_studio   **/public class DispatchServlet extends HttpServlet {private static final long serialVersionUID = 5325307163972641802L;@Overridepublic void init(ServletConfig config) throws ServletException {super.init(config);/*String configPth=config.getInitParameter("configFile");InputStream in =config.getServletContext().getResourceAsStream(configPth);Properties p = new Properties();try {p.load(in);} catch (IOException e) {e.printStackTrace();} */AnnotationClassPathApplicationContext.getAnnotationClassPathApplicationContext().init();//初始化bean}public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.excute(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.excute(request, response);}private void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{WebContext.requestHodler.set(request);//初始化当前请求的requestString lasturl = pareRequestURI(request);//person/list,解析urlString className = RequestMapingMap.getRequesetMap().get(lasturl);Object actionClass = AnnotationBeanFactory.getBeanFactory().getBean(className);Method [] methods = BeanUtils.findDeclaredMethods(actionClass.getClass());Method method = null;for(Method m:methods){//循环方法,找匹配的方法进行执行if(m.isAnnotationPresent(RequestMapping.class)){String anoPath = m.getAnnotation(RequestMapping.class).value();if(anoPath!=null && !"".equals(anoPath.trim()) && lasturl.equals(anoPath.trim())){method = m;break;}}}try {if(method!=null){View view = (View)method.invoke(actionClass, request,response);//执行action的方法if(view.getDispathAction().equals(DispatchActionConstant.FORWARD)){//不同的跳转方式request.getRequestDispatcher(view.getUrl()).forward(request, response);}else if(view.getDispathAction().equals(DispatchActionConstant.REDIRECT)){response.sendRedirect(view.getUrl());}else{request.getRequestDispatcher(view.getUrl()).forward(request, response);}}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}private String pareRequestURI(HttpServletRequest request){String path = request.getContextPath()+"/";// /ajunString requestUri = request.getRequestURI();// ajun/person/list.ajunString midUrl = requestUri.replaceFirst(path, "");String lasturl = midUrl.substring(0, midUrl.lastIndexOf("."));//person/listreturn lasturl;}}


web.xml对这个servlet的配置

<?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>DispatchServlet</servlet-name>    <servlet-class>com.ajunframework.servlet.DispatchServlet</servlet-class>  </servlet>  <servlet-mapping>    <servlet-name>DispatchServlet</servlet-name>    <url-pattern>*.ajun</url-pattern>  </servlet-mapping>    <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list></web-app>


这里还用到了一个跳转方式的常量类介绍给大家DispatchActionConstant.java

package com.ajunframework.servlet;/** * 跳转常量 * @author ajun * */public class DispatchActionConstant {public static String FORWARD = "forward";//服务器跳转public static String REDIRECT = "redirect";//客户端跳转}

现在这个简单的mvc已经实现了,下一节做个测试。。。

原创粉丝点击