自己动手实现简易的springmvc

目录

实现过程思路分析

自定义注解

中央控制器DispatcherServlet

总结


实现过程思路分析

1、创建Maven工程
2、创建控制层、业务层代码(Controller、Service、自定义注解)、准备SpringMvc核心配置文件
3、准备前端控制器 ,创建一个Servlet,同时在web.xml文件中声明该前端控制器
4、创建Spring容器,通过DOM4J解析springmvc的XML文件
5、扫描springmvc中的控制器以及service类并实例化对象放入容器中
6、实现容器中对象的注入,比如将服务层对象注入至控制层
7、建立请求映射地址与控制器以及方法之间的映射关系
8、接收用户请求并进行分发操作
9、用户请求参数处理
10、控制器方法调用以及不同返回值数据处理

作业:封装用户请求参数

Springmvc核心配置文件:springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <!-- 配置创建容器时要扫描的包-->
    <component-scan base-package="com.baiqi.controller,com.baiqi.service"></component-scan>

</beans>

web项目核心配置文件:web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>


    <!--配置前端控制器-->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>com.springmvc.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--Web服务器一旦启动,Servlet就会实例化创建对象,然后初始化(预备创建对象)-->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

 

 

自定义注解

Controller.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

Service.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

Autowired.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
	String value() default "";
}

RequestMapping.java

package cn.huangyan.spring.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

注意:

  1. ElementType.TYPE表示定义的这个注解以后可以用在类上;
  2. ElementType.METHOD表示这个注解可以用在方法上;
  3. @Retention(RetentionPolicy.RUNTIME)  表示保留到运行时,运行时能通过反射获取到注解的相关信息

中央控制器DispatcherServlet

package com.springmvc.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.springmvc.annotation.Controller;
import com.springmvc.annotation.RequestMapping;
import com.springmvc.annotation.ResponseBody;
import com.springmvc.context.WebApplicationContext;
import com.springmvc.handler.MyHandler;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DispatcherServlet extends HttpServlet {

    //指定SpringMvc容器
    private WebApplicationContext webApplicationContext;

    //创建集合  用于存放  映射关系    映射地址  与  控制器.方法,用于发送请求直接从该集合中进行匹配
    List<MyHandler>  handList = new ArrayList<>();


    @Override
    public void init() throws ServletException {

        //1、加载初始化参数   classpath:springmvc.xml
       String  contextConfigLocation =  this.getServletConfig().getInitParameter("contextConfigLocation");

        //2、创建Springmvc容器
        webApplicationContext = new WebApplicationContext(contextConfigLocation);

        //3、进行初始化操作
        webApplicationContext.onRefresh();

        //4、初始化请求映射关系   /findUser   ===》控制器.方法
        initHandlerMapping();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

          //进行请求分发处理
          doDispatcher(request,response);
    }

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

    //进行请求分发处理
    public void  doDispatcher(HttpServletRequest req, HttpServletResponse resp){

            //根据用户的请求地址  /findUser   查找Handler|Controller
            MyHandler myHandler = getHandler(req);

            try{

                if(myHandler == null){
                    resp.getWriter().print("<h1>404 NOT  FOUND!</h1>");
                }else{

                    //调用处理方法之前 进行参数的注入

                    //调用目标方法
                   Object result = myHandler.getMethod().invoke(myHandler.getController());

                    if(result instanceof String){
                        //跳转JSP
                        String viewName=(String)result;
                        // forward:/success.jsp
                        if(viewName.contains(":")){
                            String viewType=viewName.split(":")[0];
                            String viewPage=viewName.split(":")[1];
                            if(viewType.equals("forward")){
                                req.getRequestDispatcher(viewPage).forward(req,resp);
                            }else{
                                // redirect:/user.jsp
                                resp.sendRedirect(viewPage);
                            }
                        }else{
                            //默认就转发
                            req.getRequestDispatcher(viewName).forward(req,resp);
                        }
                    }else{
                        //返回JSON格式数据
                        Method method = myHandler.getMethod();
                        if(method.isAnnotationPresent(ResponseBody.class)){
                            //将返回值转换成 json格式数据
                            ObjectMapper objectMapper = new ObjectMapper();
                            String json = objectMapper.writeValueAsString(result);
                            resp.setContentType("text/html;charset=utf-8");
                            PrintWriter writer = resp.getWriter();
                            writer.print(json);
                            writer.flush();
                            writer.close();

                        }
                    }

                }
            }catch(Exception e){
               e.printStackTrace();
        }


    }

    //根据用户请求查找对应的Handler
    /***
     * 获取请求对应的handler
     * @param req
     * @return
     */
    public MyHandler getHandler(HttpServletRequest req) {
        // /findUser
        String requestURI = req.getRequestURI();
        for (MyHandler myHandler : handList) {
            //从容器的Handle取出URL  和  用户的请求地址进行匹配,找到满足条件的Handler
            if (myHandler.getUrl().equals(requestURI)) {
                return myHandler;
            }
        }
        return null;
    }

    //初始化请求映射关系
    public void  initHandlerMapping(){

        for (Map.Entry<String, Object> entry : webApplicationContext.iocMap.entrySet()) {
            //获取bean的class类型
            Class<?> clazz =  entry.getValue().getClass();

            if(clazz.isAnnotationPresent(Controller.class)){
                //获取bean中所有的方法,为这些方法建立映射关系
                Method[] methods =  clazz.getDeclaredMethods();
                for (Method method : methods) {

                    if(method.isAnnotationPresent(RequestMapping.class)){
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        //获取注解中的值   /findUser
                        String url = requestMapping.value();

                        //建立  映射地址  与  控制器.方法
                        MyHandler myHandler = new MyHandler(url,entry.getValue(),method);
                        handList.add(myHandler);
                    }
                }

            }
        }
            
    }
}

package com.springmvc.context;

import com.springmvc.annotation.AutoWired;
import com.springmvc.annotation.Controller;
import com.springmvc.annotation.Service;
import com.springmvc.xml.XmlPaser;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * springMvc容器
 */
public class WebApplicationContext {

    //classpath:springmvc.xml
    String contextConfigLocation;

    //定义集合  用于存放 bean 的权限名|包名.类名
    List<String> classNameList = new ArrayList<String>();

    //创建Map集合用于扮演IOC容器:  key存放bean的名字   value存放bean实例
    public Map<String,Object> iocMap = new ConcurrentHashMap<>();

    public WebApplicationContext() {
    }

    public WebApplicationContext(String contextConfigLocation) {
           this.contextConfigLocation = contextConfigLocation;
    }

    /**
     * 初始化Spring容器
     */
    public void onRefresh(){

        //1、进行解析springmvc配置文件操作  ==》 com.baiqi.controller,com.baiqi.service
         String pack = XmlPaser.getbasePackage(contextConfigLocation.split(":")[1]);

         String[] packs = pack.split(",");
         //2、进行包扫描
         for(String pa : packs){
             excuteScanPackage(pa);
         }

         //3、实例化容器中bean
        executeInstance();

         //4、进行 自动注入操作
        executeAutoWired();
    }

    //进行自动注入操作
    public void executeAutoWired(){

        try {
            //从容器中 取出  bean  ,然后判断 bean中是否有属性上使用 AutoWired,如果使用了搞注解,就需要进行自动注入操作
            for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
                //获取容器中的bean
                Object bean = entry.getValue();
                //获取bean中的属性
                Field[] fields = bean.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if(field.isAnnotationPresent(AutoWired.class)){
                        //获取注解中的value值|该值就是bean的name
                        AutoWired autoWiredAno =  field.getAnnotation(AutoWired.class);
                        String beanName = autoWiredAno.value();
                        //取消检查机制
                        field.setAccessible(true);
                        field.set(bean,iocMap.get(beanName));

                    }
                }


            }
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    /**
     * 实例化容器中的bean
     */
    public void executeInstance(){

        try{
            // com.baiqi.controller.UserController      com.baiqi.service.impl.UserServiceImpl
            for (String className : classNameList) {

                Class<?> clazz =   Class.forName(className);

                if(clazz.isAnnotationPresent(Controller.class)){
                    //控制层 bean

                    String beanName = clazz.getSimpleName().substring(0,1).toLowerCase()+ clazz.getSimpleName().substring(1);
                    iocMap.put(beanName,clazz.newInstance());

                }else if(clazz.isAnnotationPresent(Service.class)){
                    //Service层  bean
                    Service serviceAn = clazz.getAnnotation(Service.class);
                    String beanName = serviceAn.value();
                    iocMap.put(beanName,clazz.newInstance());
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }


    }

    /**
     * 扫描包
     */
    public void excuteScanPackage(String pack){
        //   com.baiqi.controller   ==> com/baiqi/controller
        URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
        String path = url.getFile();
        // /com/bruce/service
        File dir=new File(path);
        for(File f:dir.listFiles()){
            if(f.isDirectory()){
                //当前是一个文件目录  com.baiqi.service.impl
                excuteScanPackage(pack+"."+f.getName());
            }else{
                //文件目录下文件  获取全路径   UserController.class  ==> com.baiqi.controller.UserController
                String className=pack+"."+f.getName().replaceAll(".class","");
                classNameList.add(className);
            }
        }
    }

}

URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/,path = cn/huangyan/spring
        String filePath = url.getFile();
        File[] files = new File(filePath).listFiles();

package com.springmvc.xml;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;

/**
 * @BelongsProject: SpringMvc
 * @Description: 解析springmvc.xml
 */
public class XmlPaser {


    public static String getbasePackage(String xml){
        try {
            SAXReader saxReader=new SAXReader();
            InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
            //XML文档对象
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Element componentScan = rootElement.element("component-scan");
            Attribute attribute = componentScan.attribute("base-package");
            String basePackage = attribute.getText();
            return  basePackage;
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
        }
        return "";
    }

}

用于存储url和处理器的映射关系的基础组件

package com.springmvc.handler;


import java.lang.reflect.Method;

/**
 * @BelongsProject: SpringMvc
 * @Description: TODO
 */

public class MyHandler {

	//请求URL地址
    private String url;

    //后台控制器
    private Object controller;

    //控制器中指定的方法
    private Method method;
    
	public MyHandler() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	
	public MyHandler(String url, Object controller, Method method) {
		super();
		this.url = url;
		this.controller = controller;
		this.method = method;
	}

	// 省略getter/setter方法
}

总结

  • 学习如何通过包名,扫描定位到包名下的具体一个个的类文件,并对这些类文件进行解析
  • 学习如何通过反射获取字段的注解属性值,并通过反射给bean字段设值值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值