编写一个自己的web框架(SimpleWebFrameWork)

为什么编写一个自己的web框架,传统web编程模型有什么不好?
一个请求对应一个servlet,导致servlet过多,web.xml文件特别大,维护起来麻烦。
即使采用根据请求参数method在servlet里派发的方式,以减少servlet的个数。但这种方式也要求在每个servlet中写上很多重复的if…else…代码
Servlet的映射地址写在web.xml文件中,工程大时,如果映射地址发生修改,修改起来特别麻烦。
更为重要的是,servlet调用由web服务器负责,开发人员想控制servlet的调度,以加入一些类似于权限控制的功能特别困难。

SimpleWebFrameWordk的特点:
由一个中央控制器ControllerServlet处理所有的请求,并根据请求uri,派发不同的action进行处理。
全注解配置,处理请求的action由注解配置其映射地址。
支持method请求参数,根据客户机带来的method,调用action的相应方法进行处理,以减少action的数量。

难点:自动扫描类路径,并通过自定义类装载器加载所有处理请求的action,并关联到相应的处理uri上。


具体的实现步骤与代码:

1. 在web.xml文件配置一个servlet , 这个servlet 用来处理URL以.do 结尾的所有HTTP请求

  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>ControllerServlet</servlet-name>
    <servlet-class>com.alex.framework.ControllerServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>ControllerServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>	

2.编写ControllerServlet(web框架的核心类)

package com.alex.framework;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ControllerServlet extends HttpServlet {
	//Map中的key用来存放URI,value用来存放URI相对应的Action对象(Action指处理各类请求的控制器)
	private Map<String,Object> map = new HashMap<String,Object>();
	
	@Override
	public void init() throws ServletException {
		String classPath = this.getServletContext().getRealPath("/WEB-INF/classes");
		scanClassPath(new File(classPath));
	}
	
	/*
	 * 扫描类路径所有类文件,如果类文件含有Control注解,则把注解的value(URI)放进Map中作为key,
	 * 并将类的实例对象作为Map当中的value
	 */
	private void scanClassPath(File file) {
		try{
			if(file.isFile()){
				if(file.getName().endsWith(".class")){
					String path = file.getPath();
					MyClassLoader myClassLoader = new MyClassLoader(ControllerServlet.class.getClassLoader());
					Class clazz = myClassLoader.load(path);
					Control control = (Control)clazz.getAnnotation(Control.class);
					if(control!=null){
						String uri = control.value();
						Object action = clazz.newInstance();
						map.put(uri, action);
					}
				}
				
			}else{
				File[] files = file.listFiles();
				for(File child:files){
					scanClassPath(child);
				}
			}
		}catch(Exception e){
			throw new RuntimeException(e);
		}
		
		
	}
	//自定义一个类加载器,使得类加载器能够通过类文件路径获得该类的字节码文件
	class MyClassLoader extends ClassLoader{
		public MyClassLoader(ClassLoader parent){
			super(parent);
		}
		
		public Class load(String path){
			FileInputStream fis = null;
			try{
				fis = new FileInputStream(path);
				byte[] buf = new byte[fis.available()];
				int len = 0;
				int total = 0;
				int fileLength = buf.length;
				while(total<fileLength){
					len=fis.read(buf, total,fileLength-total);
					total=total+len;
				}
				return super.defineClass(null, buf, 0, fileLength);
			}catch(Exception e){
				throw new RuntimeException(e);
			}finally{
				if(fis!=null){
					try {
						fis.close();
					} catch (IOException e) {
						throw new RuntimeException(e);
					}
					fis=null;
				}
			}
		}
		
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		//获得http请求的URI并截掉后面的请求参数字符串
		String uri = request.getRequestURI();
		uri = uri.substring(request.getContextPath().length(), uri.length()-3);
		if(map.containsKey(uri)){
			//通过http请求uri获得相对应的Action对象
			Object obj = map.get(uri);
			//获得http请求的方法名
			String methodName = request.getParameter("method");
			//如果请求的方法null,则默认调用Action对象中的exec方法
			if(methodName==null){
				methodName="exec";
			}
			Method method = null;
			try {
				//通过反射获得要执行的方法对象
				method = obj.getClass().getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
				
			} catch (Exception e){
				throw new RuntimeException("在"+obj.getClass().getName()+"上找不到与" + methodName +"相对应的方法!!!");
			}
			
			try {
				//执行Action对象中的方法
				method.invoke(obj, request,response);
			} catch (Exception e){
				e.printStackTrace();
			}
		}
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request,response);
	}

}

3.编写需要用到的注解Control(value 属性为http请求的uri)

package com.alex.framework;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Control {
	String value();
}

4. 当我们访问的URL为 http://localhost:8088/project_name /control/customer/customer.do?method=list 时,

框架便会调用CustomerAction中list方法对请求进行处理

@Control("/control/customer/customer")
public class CustomerAction {
    
    private CustomerService customerService = new CustomerService();
    
    
    public void list(HttpServletRequest request,HttpServletResponse response) throws Exception{
        
        PageInfo pageInfo = WebUtils.request2Bean(request, PageInfo.class);
        PageBean pageBean = customerService.pageQuery(pageInfo);
        request.setAttribute("pageBean",pageBean);
        request.getRequestDispatcher("/WEB-INF/pages/customer/listCustomer.jsp").forward(request, response);
    }
    




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值