NOVOTS KMS 词汇表 Glossary    联系我们 Contact Us
查询 Search  
   
按类别浏览 Browse by Category
NOVOTS KMS .: 工作心得 .: 手写springmvc框架

手写springmvc框架

手写springmvc框架
Springmvc是基于servlet的一个框架,其设计非常简洁,此次我们将实现一个简单的springmvc框架,进一步了解框架运行过程中发生了什么。
SpringMVC工作原理
第1步:浏览器发送指定的请求都会交给DispatcherServlet,他会委托其他模块进行真正的业务和数据处理 
第2步:DispatcherServlet会查找到HandleMapping,根据浏览器的请求找到对应的Controller,并将请求交给目标Controller 
第3步:目标Controller处理完业务后,返回一个ModelAndView给DispatcherServlet 
第4步:DispatcherServlet通过ViewResolver视图解析器找到对应的视图对象View 
第5步:视图对象View负责渲染,并返回到浏览器
在这里我们主要完成第2步,根据url去查找到对应的方法。
这个项目是maven项目,我们所需要的pom文件是
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
    <scope>provided</scope>
</dependency>


在这里我们定义两个注解
这两个注解规定了由哪个类的哪个方法来处理请求
SelfController
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface SelfController {
  String value() default "";
}


SelfRequestMappping
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
public @interface SelfRequestMappping {
  String value() default "";
}

我们写上一段业务逻辑代码
@SelfController
@SelfRequestMappping("/mvc")
public class MvxController {
 
 @SelfRequestMappping("/hello")
 public void hello(HttpServletRequest req, HttpServletResponse resp ) {
 String name = req.getParameter("name");
 String age = req.getParameter("age");
 try {
 PrintWriter writer = resp.getWriter();
 writer.write("{age:"+age+",name:"+name+"}");
 writer.flush();
 writer.close();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } 
 }
}

在web.xml我们需要写上
<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
   <servlet-name>DispathServlet</servlet-name>
   <servlet-class>com.mvc.servlet.DispathServlet</servlet-class>
   <load-on-startup>0</load-on-startup>
  </servlet>
 
  <servlet-mapping>
   <servlet-name>DispathServlet</servlet-name>
   <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
这里我们拦截到所有url请求,将其交给com.mvc.servlet.DispathServlet来处理 ,在这之中HttpServlet的init是最先被执行的,所以我们在init里面写上初始化函数
1.  找到所有class文件,将其放入classNames数组里面
scanPackage("com.mvc"); //获取所有class文件
 /**
  * @param scanPackage
  * 获取到所有class文件
  */
 private void scanPackage(String scanPackage) {
 // TODO Auto-generated method stub
 String fp = "/"+scanPackage.replaceAll("\\.", "/");
 URL url = this.getClass().getClassLoader().getResource(fp);
 String strFile = url.getFile();
 File[] files = new File(strFile).listFiles();
 for (File f : files) {
 if(f.isDirectory()) { //文件夾
 this.scanPackage(scanPackage+"."+f.getName());
 }else {//文件
 classNames.add(scanPackage+"."+f.getName());
 }
 }
 }
2. doInstance(); //实例化  new MvxController()


 /**
  * 实例化,存入bean
  */
 private void doInstance() {
 for (String cname : classNames) {
 String replace = cname.replace(".class", "");
 try {
 Class<?> forName = Class.forName(replace);
 if(forName.isAnnotationPresent(SelfController.class)) {//处理controller修饰的类
 Object newInstance = forName.newInstance();
 String key = forName.getAnnotation(SelfRequestMappping.class).value();
 beans.put(key, newInstance);
  }
 } catch (ClassNotFoundException |InstantiationException |IllegalAccessException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }  
 }
 }
 urlMapping(); // 所有url对应的Method  
 /**
  * mapping映射
  * http到method
  */
 private void urlMapping() {
 // TODO Auto-generated method stub
 for (Entry<String, Object> entry : beans.entrySet()) {
 Object instance = entry.getValue();
 Class<? extends Object> clazz = instance.getClass();
 if(clazz.isAnnotationPresent(SelfController.class)) {
 String url1 = clazz.getAnnotation(SelfRequestMappping.class).value();
 Method[] methods = clazz.getMethods();//获取到所有方法
 for (Method method : methods) {
 if(method.isAnnotationPresent(SelfRequestMappping.class)) {
 String url2 = method.getAnnotation(SelfRequestMappping.class).value(); 
 handlerMap.put(url1+url2, method);
 }else {
 continue;
 }
 }
 }
 }
 }
在上述三段程序中有三个集类的参与
 /**
  * 所有.class文件名  com.mvc.controller.MvxController.class
  */
 private List<String> classNames = new ArrayList<>();
 /**
  * 所有加注解的bean
  */
 private HashMap<String, Object> beans = new HashMap<>();
 /**
  * url对应的method
  */
 private HashMap<String, Method> handlerMap = new HashMap<>();//路径映射
我们最后的目的就是拿到handlerMap 这个装有以路径为key,以Method为value的HashMap函数
只要只有这个我们就能根据url获取到对应的method与其对应的返回参数,一般来说就 get ,post两种请求方式,稍作处理就是这样
 /* (non-Javadoc)
  * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
  *  业务请求相关代码
  */
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 this.doPost(req, resp);
 }
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 String uri = req.getRequestURI(); //   /项目名/mvc/hello
 String contextPath = req.getContextPath(); //项目名
 String path = uri.replace(contextPath, "");
 Object object = beans.get("/"+path.split("/")[1]);
 Method method = handlerMap.get(path);
 try {
 method.invoke( object, req,resp);
 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }

最后测试一下
 
Gitee源码: https://gitee.com/mijin/selfmvc


这篇文章对你多有用?

用户评语

添加评语
当前还没有评语.


.: .: .: .: .:
[ 登陆 ]
北京护航科技有限公司 2006

Novots Technologies Limited