SpringMVC 功能实现(自己写的,不喜欢勿喷)

springmvc执行流程:
在这里插入图片描述

一 .创建前端控制器

public class MyDispatcherServlet extends HttpServlet

属性:

//配置文件
    private Properties configProperties = null;
    //spring mvc 的ioc容器
    private ConcurrentHashMap<String,Object> ioc = null;

    //springmvc的 地址映射与类之间的关联
    // key:地址 URI             value: 哪个类
    private ConcurrentHashMap<String,Object> beanUrl = null;

    //springmvc的  地址映射的  对应的要执行的方法是哪个
    private ConcurrentHashMap<String,String> beanMethod = null;

初始化操作
1.加载配置文件
2.完成ioc容器的初始化操作
3.完成地址映射 的两个map的初始化

/**
     * 容器初始化的操作 加载配置文件,这里为了方便就用 properties 文件
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException
    {
        System.out.println ("初始化");
        //读取配置文件
        loadConfig(config);

        //实例化ioc容器,地址映射和方法映射
        this.ioc = new ConcurrentHashMap<> ();
        this.beanUrl = new ConcurrentHashMap<> ();
        this.beanMethod = new ConcurrentHashMap<> ();

        //从properties获取包名 然后扫描该包下的所有类   此时ioc容器已经加载完毕了
        loadAnnotationClass(this.configProperties.getProperty ("packageName"));

        //加下来就要初始化 beanUrl 和 beanMethod
        initBeanUrlAndBeanMethod();

        printAll ();
    }
 /**
     * 加载 properties 配置文件
     * @param config
     */
    private void loadConfig(ServletConfig config)
    {
        //获取文件地址  classpath
        String configurationFile = config.getInitParameter ("contextConfigLocation");
        System.out.println ("configurationFile:"+configurationFile);
        //加载配置文件
        this.configProperties = new Properties ();
        configurationFile = configurationFile.substring (configurationFile.indexOf (":")+1,configurationFile.length ());

        InputStream is = this.getClass ().getClassLoader ().getResourceAsStream (configurationFile);
        try
        {
            this.configProperties.load (is);
        } catch (IOException e)
        {
            e.printStackTrace ();
        }finally
        {
            if(null != is)
            {
                try
                {  //关闭流
                    is.close ();
                } catch (IOException e)
                {
                    e.printStackTrace ();
                }
            }
        }


    }
 /**
     *  加载 包下的所有类 (加了MyController注解的)
     * @return
     */
    private void loadAnnotationClass(String packageName)
    {
        try
        {
            //获取该报下的所有类,不包含接口  不管加没加注解都获取到
            List<Class<?>> classList = MyClassUtils.getClasses (packageName);
            //返回  加了MyController注解的 类
            List<Class<?>> annoClasses = findClassIsPreAnnoctation (classList);
            //实例化,加载到 ioc 中
            newInstanceBean (annoClasses);


        } catch (Exception e)
        {
            e.printStackTrace ();
        }
    }
/**
     * 返回被注解申明的 class
     *
     * @param classes
     * @return
     */
    private List<Class<?>> findClassIsPreAnnoctation(List<Class<?>> classes)
    {
        //加了注解的集合
        List<Class<?>> annoctationPresentClasses = new ArrayList<> ();

        for (Class clazz : classes)
        {
            //MyController
            if (clazz.isAnnotationPresent (MyController.class))
            {
                //添加到容器中
                annoctationPresentClasses.add (clazz);
                continue;
            }
        }
        return annoctationPresentClasses;
    }
/**
     * 反射实例化bean
     */
    private void newInstanceBean(List<Class<?>> anncotaionedClasses) throws Exception
    {
        //没有空参构造器的 clazz  等有空参构造器的初始化完了再初始化
        List<Class<?>> nullConstructor = new ArrayList<> ();

        for (Class<?> clazz : anncotaionedClasses)
        {
            //判断是否有空参构造方法,有的话直接初始化,没有的话放置到后面
            Constructor constructor = clazz.getConstructor ();
            if (constructor == null)
            {
                anncotaionedClasses.remove (clazz);
                nullConstructor.add (clazz);
                continue;
            }
            //反射实例化
            Object o = clazz.newInstance ();
            MyController declaredAnnotation = clazz.getDeclaredAnnotation (MyController.class);

            //如果名字为空,默认为首字母小写
            if ("".equals (declaredAnnotation.value ()))
            {
                // 获取 类名即可
                String className = toLowerCaseFirstOne (clazz.getSimpleName ());
                String beanId = toLowerCaseFirstOne (className);
                //添加到ioc容器中
                ioc.put (beanId, o);
                continue;
            }
            else  //代表 用户自定义类名的id
            {
                String beanId=declaredAnnotation.value ();
                ioc.put (beanId,o);
            }

        }
    }

```java
 /**
     *  对beanUrl 和 beanMethod 初始化
     */
    private void initBeanUrlAndBeanMethod()
    {
        if(ioc == null)
        {
            return;
        }
        Set<Map.Entry<String, Object>> entries = this.ioc.entrySet ();
        for(Map.Entry entry : entries)
        {
            //得到ioc中每一个bean对象
            Object bean = entry.getValue ();
            //第一步判断类上是否有加有 MyRequestMapping 注解
            MyRequestMapping mapping = bean.getClass ().getDeclaredAnnotation (MyRequestMapping.class);

            String classMapping = "";
            String methodMapping = "";

            //类上的不为空
            if(mapping != null)
            {
                classMapping = mapping.value ();
            }
            //遍历每个方法,判断方法上是否加有 RequestMapping
            Method[] methods = bean.getClass ().getMethods ();
            //地址映射id
            String url="";

            for(Method method : methods)
            {
                MyRequestMapping methoAnnotation = method.getDeclaredAnnotation (MyRequestMapping.class);
                if(methoAnnotation != null) //代表注解上加有MyRequestmapping
                {
                    methodMapping = methoAnnotation.value ();
                    //最后判断 如果方法上的url 没有地址  则不添加 否者 添加进去
                    if(StringUtils.isNotBlank (methodMapping))
                    {
                        if(classMapping.indexOf ("/")!=0 && StringUtils.isNotBlank (classMapping))
                        {
                            classMapping = "/"+classMapping;
                        }
                        if(methodMapping.indexOf ("/")!=0 && StringUtils.isNotBlank (methodMapping))
                        {
                            methodMapping = "/"+methodMapping;
                        }
                        url = classMapping + methodMapping;
                        beanUrl.put (url,bean);
                        beanMethod.put (url,method.getName ());
                    }
                }
            }
        }
    }
// 首字母转小写
    public static String toLowerCaseFirstOne(String s)
    {
        if (Character.isLowerCase (s.charAt (0)))
        {
            return s;
        }

        else
        {
            return (new StringBuilder ()).append (Character.toLowerCase (s.charAt (0))).append (s.substring (1)).toString ();
        }
    }

处理 用户端的请求

这里重写了doget和dopost方法

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

    /**
     * 真正的实现 接收请求和响应请求
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doDispatachMethod(request,response);
    }
/**
     * 实现 地址映射 请求  执行相应的方法
     */
    private void doDispatachMethod(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
    {
        //得到请求的地址  是端口号后面的地址
        String requestURI = request.getRequestURI ();

        //向 地址映射的 beanUrl 查找类
        Object bean = beanUrl.get (requestURI);
        //如果为空,代表没有 这个地址映射
        if(bean == null)
        {
            response.getWriter ().println ("Sorry 404 你访问的页面不存在!");
            return;
        }
        //后面代表不为空  得到 地址映射的方法
        String methodName = this.beanMethod.get (requestURI);
        if(StringUtils.isEmpty (methodName))
        {
            response.getWriter ().println ("Sorry 404 你访问的页面不存在!");
            return;
        }

        /**
         * 执行方法  得到class  反射执行
         */
        Class<?> beanClass = bean.getClass ();
        Object result=invokeBeanMethod(beanClass,methodName,bean);

        //最后 展示视图
        viewResolver(result,request,response);
    }
/**
     * 最后根据返回值 处理视图跳转
     * @param result
     * @param request
     * @param response
     */
    private void viewResolver(Object result, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // 获取后缀信息
        String suffix = ".jsp";
        // 页面目录地址
        String prefix = "/";

        String pageName=(String)result;

        String path = prefix + pageName + suffix;
        if(pageName.contains ("redirect"))
        {
            response.sendRedirect (path);
        }
        else //默认请求转发
        {
            request.getRequestDispatcher (path).forward (request,response);
        }
    }

最终效果

@MyController
@MyRequestMapping ("/product")
public class ProductController
{

    @MyRequestMapping("addProduct")
    public String addProduct()
    {
        return "wZF";
    }
    @MyRequestMapping("/updateProduct")
    public void updateProduct()
    {
    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值