转载

【java实例】自己动手实现IOC和MVC(七)

相信大家都用过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
  1. package com.ajunframework.servlet.annotation;
  2. import java.lang.annotation.Documented;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Inherited;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. /**
  9.  * 
  10.  * @author harries
  11.  * @http://www.liuhaihua.cn
  12.  */
  13. @Target(ElementType.METHOD)
  14. @Retention(RetentionPolicy.RUNTIME)
  15. @Documented
  16. @Inherited
  17. public @interface RequestMapping {
  18.     public String value() default "";
  19. }
此时请求的路径 ,我们可以做一个解析 ,然后找到你的action类中方法上的注释和你解析出来的路径一致,说名就是这个方法,接着我们利用java反射机制调用这个类得方法,就可以了,接着这个方法会返回一个路径,就是我们跳转的视图返回给我们总的servlet ,就行跳转。 这些功能改怎么实现呢? 首先考虑你返回的视图的路径,其中还有包含的数据怎么办呢?还有就是服务器端跳转还是客户端跳转呢? 此时我们要定义一个视图类,对这些操作属性进行封装,其中包括条状的路径 、展现到页面的数据(这里只是做request范围内的)、跳转方式。 下面是视图类得封装代码:
  1. package com.ajunframework.servlet.view;
  2. import com.ajunframework.servlet.constant.DispatchActionConstant;
  3. /**
  4.  * @author harries
  5.  * @http://www.liuhaihua.cn
  6.  **/
  7. public class View {
  8.     private String url;//跳转路径
  9.     private String dispathAction = DispatchActionConstant.FORWARD;//跳转方式
  10.     public View(String url) {
  11.         this.url = url;
  12.     }
  13.     public View(String url,String name,Object value) {
  14.         this.url = url;
  15.         ViewData view = new ViewData();
  16.         view.put(name, value);
  17.     }
  18.     public View(String url,String name,String dispathAction ,Object value) {
  19.         this.dispathAction = dispathAction;
  20.         this.url = url;
  21.         ViewData view = new ViewData();//请看后面的代码
  22.         view.put(name, value);
  23.     }
  24.     public String getUrl() {
  25.         return url;
  26.     }
  27.     public void setUrl(String url) {
  28.         this.url = url;
  29.     }
  30.     public String getDispathAction() {
  31.         return dispathAction;
  32.     }
  33.     public void setDispathAction(String dispathAction) {
  34.         this.dispathAction = dispathAction;
  35.     }
  36. }
request范围的数据存储类ViewData.java
  1. package com.ajunframework.servlet.view;
  2. import javax.servlet.http.HttpServletRequest;
  3. import com.ajunframework.servlet.WebContext;
  4. /**
  5.  * @author harries
  6.  * @http://www.liuhaihua.cn
  7.  **/
  8. public class ViewData {
  9.     private HttpServletRequest request;
  10.     public ViewData() {
  11.         initRequestAndResponse();
  12.     }
  13.     private void initRequestAndResponse(){
  14.         this.request = WebContext.requestHodler.get();//下面会介绍
  15.     }
  16.     public void put(String name,Object value){
  17.         this.request.setAttribute(name, value);
  18.     }
  19. }
还有就是我们在每次请求的时候,到达action里的时候 我们会用ViewData.put()往request中存数据,而action中并没有request的情况如何处理呢? 下面我提供一个在进入action之前进行初始化request的类WebContext.java
  1. package com.ajunframework.servlet;
  2. import javax.servlet.ServletContext;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpSession;
  5. /**
  6.  * @author harries
  7.  * @http://www.liuhaihua.cn
  8.  **/
  9. public class WebContext {
  10.     public static ThreadLocal<HttpServletRequest> requestHodler = new ThreadLocal<HttpServletRequest>();
  11.     public HttpServletRequest getRequest(){
  12.            return requestHodler.get();
  13.     }
  14.     public HttpSession getSession(){
  15.            return requestHodler.get().getSession();
  16.     }
  17.     public ServletContext getServletContext(){
  18.            return requestHodler.get().getSession().getServletContext();
  19.     }
  20. }
通过这个类 ,你可以当前请求的request或者session相关请求类的实例变量,线程间互不干扰的,因为用到了ThreadLocal这个类。 下面来介绍一下servlet的实现,这是无论是get post请求都会调用我封转的方法 ,这个方法,会根据你请求的url,找到你对象的action ,然后调用其中方法注释和改url配置的方法,同事返回View视图类,接着根据View中的路径,返回到相应的视图。 为了方便这里我用到了我们写的ioc,用于在servlet初始化的过程中,实例化和注入相关的class,供我们调用。这里耦合在一起了 ,不是很好。。。 DispatchServlet.java
  1. package com.ajunframework.servlet;
  2. import java.io.IOException;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Method;
  5. import javax.servlet.ServletConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.http.HttpServlet;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import com.ajunframework.beans.applicationContext.AnnotationClassPathApplicationContext;
  11. import com.ajunframework.beans.factory.AnnotationBeanFactory;
  12. import com.ajunframework.beans.factory.RequestMapingMap;
  13. import com.ajunframework.beans.utils.BeanUtils;
  14. import com.ajunframework.servlet.annotation.RequestMapping;
  15. import com.ajunframework.servlet.constant.DispatchActionConstant;
  16. import com.ajunframework.servlet.view.View;
  17. /**
  18.  * @author harries
  19.  * @http://www.liuhaihua.cn 
  20.  **/
  21. public class DispatchServlet extends HttpServlet {
  22.     private static final long serialVersionUID = 5325307163972641802L;
  23.     @Override
  24.     public void init(ServletConfig config) throws ServletException {
  25.         super.init(config);
  26.         /*String configPth=config.getInitParameter("configFile");
  27.         InputStream in =config.getServletContext().getResourceAsStream(configPth);
  28.         Properties p = new Properties();
  29.         try {
  30.             p.load(in);
  31.         } catch (IOException e) {
  32.             e.printStackTrace();
  33.         } */
  34.         AnnotationClassPathApplicationContext.getAnnotationClassPathApplicationContext().init();//初始化bean
  35.     }
  36.     public void doGet(HttpServletRequest request, HttpServletResponse response)
  37.             throws ServletException, IOException {
  38.         this.excute(request, response);
  39.     }
  40.     public void doPost(HttpServletRequest request, HttpServletResponse response)
  41.             throws ServletException, IOException {
  42.         this.excute(request, response);
  43.     }
  44.     private void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
  45.         WebContext.requestHodler.set(request);//初始化当前请求的request
  46.         String lasturl = pareRequestURI(request);//person/list,解析url
  47.         String className = RequestMapingMap.getRequesetMap().get(lasturl);
  48.         Object actionClass = AnnotationBeanFactory.getBeanFactory().getBean(className);
  49.         Method [] methods = BeanUtils.findDeclaredMethods(actionClass.getClass());
  50.         Method method = null;
  51.         for(Method m:methods){//循环方法,找匹配的方法进行执行
  52.             if(m.isAnnotationPresent(RequestMapping.class)){
  53.                 String anoPath = m.getAnnotation(RequestMapping.class).value();
  54.                 if(anoPath!=null && !"".equals(anoPath.trim()) && lasturl.equals(anoPath.trim())){
  55.                     method = m;
  56.                     break;
  57.                 }
  58.             }
  59.         }
  60.         try {
  61.             if(method!=null){
  62.                 View view = (View)method.invoke(actionClass, request,response);//执行action的方法
  63.                 if(view.getDispathAction().equals(DispatchActionConstant.FORWARD)){//不同的跳转方式
  64.                     request.getRequestDispatcher(view.getUrl()).forward(request, response);
  65.                 }else if(view.getDispathAction().equals(DispatchActionConstant.REDIRECT)){
  66.                     response.sendRedirect(view.getUrl());
  67.                 }else{
  68.                     request.getRequestDispatcher(view.getUrl()).forward(request, response);
  69.                 }
  70.             }
  71.         } catch (IllegalArgumentException e) {
  72.             e.printStackTrace();
  73.         } catch (IllegalAccessException e) {
  74.             e.printStackTrace();
  75.         } catch (InvocationTargetException e) {
  76.             e.printStackTrace();
  77.         }
  78.     }
  79.     private String pareRequestURI(HttpServletRequest request){
  80.         String path = request.getContextPath()+"/";// /ajun
  81.         String requestUri = request.getRequestURI();// ajun/person/list.ajun
  82.         String midUrl = requestUri.replaceFirst(path, "");
  83.         String lasturl = midUrl.substring(0, midUrl.lastIndexOf("."));//person/list
  84.         return lasturl;
  85.     }
  86. }
web.xml对这个servlet的配置
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app version="2.5"
  3.     xmlns="http://java.sun.com/xml/ns/javaee"
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
  6.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  7.   <servlet>
  8.     <servlet-name>DispatchServlet</servlet-name>
  9.     <servlet-class>com.ajunframework.servlet.DispatchServlet</servlet-class>
  10.   </servlet>
  11.   <servlet-mapping>
  12.     <servlet-name>DispatchServlet</servlet-name>
  13.     <url-pattern>*.ajun</url-pattern>
  14.   </servlet-mapping>
  15.   <welcome-file-list>
  16.     <welcome-file>index.jsp</welcome-file>
  17.   </welcome-file-list>
  18. </web-app>
这里还用到了一个跳转方式的常量类介绍给大家DispatchActionConstant.java
  1. package com.ajunframework.servlet;
  2. /**
  3.  * 跳转常量
  4.  * @author harries
  5.  *
  6.  */
  7. public class DispatchActionConstant {
  8.     public static String FORWARD = "forward";//服务器跳转
  9.     public static String REDIRECT = "redirect";//客户端跳转
  10. }
现在这个简单的mvc已经实现了,下一节做个测试。。。
正文到此结束
Loading...