转载

自己写springmvc框架

  1. 表示层(视图层,显示层)

    • jsp
    • servlet
  2. 业务逻辑层

    • service
  3. 数据访问层(持久层)

    • dao

什么是mvc

  • Model View Controller
  • 是一种架构思想,其核心思想将项目划分成三种不同模块,分别是模型,视图,控制器

    • 模型: 负责封装业务逻辑和数据访问
    • 控制器: 负责调度
    • 视图: 负责显示
  • View : JSP 负责显示

  • Controller :控制器 起到调度分发请求
  • Model : 模型层 代表除了Servlet,Controller之外的java代码,包括service,dao

好处

  • 项目的可维护性,可扩展性更高,抽取service

实现

思想

  1. 首先需要一个RequestMapping注解
  2. 创建前端控制器DispatcherServlet用来转发请求
  3. 创建视图解析器来对应不同的页面

创建注解RequestMapping

  • 使用@Target可以设置这个注解在方法体上还是在类上使用,这里我们只是在方法体上使用,这个和Springmvc有点出入
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Target(ElementType.METHOD)   //设置这个注解是给方法使用的
    @Retention(RetentionPolicy.RUNTIME)  //设置注解的存在时间为运行时
    public @interface RequestMapping {
    	//设置传入的参数
    	public String value();   //设置一个参数 ,必须传入参数 如果添加 default "" ,那么默认的参数就是空字符串
    	//public String method() default "get"; //设置method参数,默认的是get方法
    }
    

创建Handler类

  • 用来保存反射调用的方法和对象
    import java.lang.reflect.Method;
    public class Handler{
    	private Method method; // 方法
    	private Object object; // Object对象,用于反射调用方法method
    
    	public Handler(Method method, Object object){
    		super();
    		this.method = method;
    		this.object = object;
    	}
    
    	public Method getMethod(){
    		return method;
    	}
    
    	public void setMethod(Method method){
    		this.method = method;
    	}
    
    	public Object getObject(){
    		return object;
    	}
    
    	public void setObject(Object object){
    		this.object = object;
    	}
    
    	@Override
    	public String toString(){
    		return "Handler [method=" + method + ", object=" + object + "]";
    	}
    
    }
    

config.xml(resource目录下)

  • 用来存放bean,不同的controller类都需要在这个配置文件重视配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    	<bean class="cn.controller.UserController"></bean>
    	<bean class="cn.controller.DeptController"></bean>
    </beans>
    

XMLUtils

  • 解析config.xml的文件,使用的是Dom4j

  • 在pom.xml中导入依赖

    <!-- 读取xml文件的jar包 -->
    <dependency>
    	<groupId>dom4j</groupId>
    	<artifactId>dom4j</artifactId>
    	<version>1.6.1</version>
    </dependency>
    
  • 解析xml文件的工具类

    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import cn.reflect.ReflectDemo;
    
    /**
     * 读取XML文件的工具类
     * @author chenjiabing
     *
     */
    public class XMLUtils{
    	/**
    	 * 读取xml文件中的内容,使用的jar包是dom4j
    	 * @return xml配置文件中的所有bean的对象
    	 */
    	public static List<Object> getBeans()throws Exception{
    		SAXReader reader=new SAXReader();
    		InputStream inputStream=ReflectDemo.class.getClassLoader().getResourceAsStream("config.xml");  //获取输入流
    		Document document=reader.read(inputStream);
    		//得到根节点
    		Element beansEle=document.getRootElement();
    		//得到根节点下面的所有子节点
    		List<Element> elements=beansEle.elements();
    
    		List<Object> beans=new ArrayList<Object>();   //保存bean中的class属性创建的对象
    		//遍历子节点
    		for (Element element : elements) {
    			//得到class属性的值
    			String className=element.attributeValue("class");
    			//直接使用遍历的className创建对象并且保存在集合中
    			Class cls=Class.forName(className);
    			Object bean=cls.newInstance();
    			beans.add(bean);   //将创建的对象添加到集合中
    		}
    		return beans;
    	}
    }
    

HandlerMapping

  • 读取config.xml中的bean,并且利用反射获取注解上的value值(请求路径)、方法、创建类。存储在Map中
    package cn.reflect;
    
    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    
    import cn.annoation.RequestMapping;
    
    public class HandlerMapping{
    	private Map<String, Handler> map = new HashMap<String, Handler>(); // 创建一个Map存储path和Handler
    	/**
    	 * 初始化方法,将指定类的带有注解的方法放入Map中
    	 * @param beans  对象集合
    	 */
    	public void init(List<Object> beans){
    		for (Object bean : beans) {
    			Class cls=bean.getClass();
    			//获取所有方法
    			Method[] methods=cls.getDeclaredMethods();
    			for (Method method : methods) {
    				RequestMapping requestMapping=method.getAnnotation(RequestMapping.class);
    				//如果方法上面存在RequestMapping注解
    				if (requestMapping!=null) {
    					String path=requestMapping.value();  //获取注解上的地址
    					Handler handler=new Handler(method, bean);  //创建handler对象
    					map.put(path, handler);  //存放键值对
    				}
    			}
    		}
    	}
    
    	/**
    	 * 根据给定的path返回一个Handler对象
    	 *
    	 * @param path
    	 *            指定的路径,map中的key
    	 * @return Handler 对象
    	 */
    	public Handler getHandler(String path){
    		return map.get(path);
    	}
    
    }
    

视图解析器

  • 根据controller方法中的返回值转发或者重定向到指定的视图
    • 默认是转发的
    • 重定向需要使用: redirect:add.do
import java.io.IOException;

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

public class ViewResolver{
	/**
	 * 视图解析器
	 * @param returnValue   controller方法的返回值
	 */
	public void process(Object returnValue, HttpServletRequest request,
			HttpServletResponse response) {
		String path=(String)returnValue;
		try {
			//判断是转发还是重定向
			if (path.startsWith("redirect:")) {   //重定向
					response.sendRedirect(request.getContextPath()+"/"+path.split(":")[1]);
			}else {   //转发
					request.getRequestDispatcher("/WEB-INF/"+path+".jsp").forward(request, response);
				}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

DispatcherServlet

  • 前端控制器,其实是一个Servlet,不过用来拦截 .do的请求,因此需要在web.xml中配置` .do`
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Scanner;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.reflect.Handler;
import cn.reflect.HandlerMapping;
import cn.reflect.ViewResolver;
import cn.utils.XMLUtils;

/**
 * Servlet implementation class DispatcherServlet
 */
public class DispatcherServletextends HttpServlet{
	@Override
	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		List<Object> beans;
		try {
			beans = XMLUtils.getBeans();// 获取xml配置文件中所有bean的对象
			HandlerMapping handlerMapping = new HandlerMapping();
			String uri = request.getRequestURI(); // 请求地址
			String appName = request.getContextPath(); // 工程名
			String path = uri.replace(appName, ""); // 获取注解的path
			handlerMapping.init(beans); // 初始化
			Handler handler = handlerMapping.getHandler(path); // 获取指定的Handler
			Method method = handler.getMethod();
			Object object = handler.getObject();
			Class[] paramTypes = method.getParameterTypes(); // 获取方法中的参数类型
			Object returnValue=null;  //申明目标方法的返回值
			// 如果调用的方法有参数
			if (paramTypes.length > 0) {
				Object[] args = new Object[paramTypes.length];   //创建参数列表
				for (int i = 0; i < args.length; i++) {
					Class cls = paramTypes[i];
					// 判断类型是request或者response
					if (cls == HttpServletRequest.class) {
						args[i] = request;
					} else if (cls == HttpServletResponse.class) {
						args[i] = response;
					}
				}
				returnValue=method.invoke(object, args);
			} else {
				returnValue=method.invoke(handler.getObject()); // 调用方法执行
			}

			//有返回值,要么转发,要么重定向
			if (returnValue!=null) {
				//通过视图解析器对象,处理转发或者重定向
				ViewResolver viewResolver=new ViewResolver();
				viewResolver.process(returnValue,request,response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
原文  https://chenjiabing666.github.io/2018/04/22/自己写springmvc框架/
正文到此结束
Loading...