前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己写springmvc框架

自己写springmvc框架

作者头像
爱撒谎的男孩
发布2019-12-31 14:48:37
6930
发布2019-12-31 14:48:37
举报
文章被收录于专栏:码猿技术专栏

文章目录

  1. 1. 简易的springmvc框架
    1. 1.1. 三层架构
    2. 1.2. 什么是mvc
      1. 1.2.1. 好处
    3. 1.3. 实现
      1. 1.3.1. 思想
      2. 1.3.2. 创建注解RequestMapping
      3. 1.3.3. 创建Handler类
      4. 1.3.4. config.xml(resource目录下)
      5. 1.3.5. XMLUtils
      6. 1.3.6. HandlerMapping
      7. 1.3.7. 视图解析器
      8. 1.3.8. DispatcherServlet

简易的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
代码语言:javascript
复制
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`
代码语言:javascript
复制
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 DispatcherServlet extends 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();
		}
	}

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简易的springmvc框架
    • 三层架构
      • 什么是mvc
        • 好处
      • 实现
        • 思想
        • 创建注解RequestMapping
        • 创建Handler类
        • config.xml(resource目录下)
        • XMLUtils
        • HandlerMapping
        • 视图解析器
        • DispatcherServlet
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档