使用注解简单实现SpringMVC

使用注解简单实现SpringMVC
1:web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <display-name>WTK Web Application</display-name>

    <servlet>
        <servlet-name>WTKSpringMVC</servlet-name>
        <!--<servlet-class>com.wtk.mvcframework.servlet.WTKDispatcherServlet</servlet-class>-->
        <servlet-class>com.wtk.springmvc.servlet.WTKDispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>application.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>WTKSpringMVC</servlet-name>
         <servlet-name>WTKSpringMVC</servlet-name>
        <!--"/" 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。-->
        <!-- " /*"  会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

2:自定义controller注解,

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WTKController {
    /**
     * 表示给controller注册别名
     * @return
     */
    String value() default "";
}

3:自定义RequestMapping注解,

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

4:自定义前端控制器,和web.xml匹配

/**
 *自定义前端控制器
 * 1:创建一个前端控制器(WTKDispatcherServlet) 拦截所有的请求(springmvc 基于servlet实现)
 * 2:初始化操作,重写 servlet init方法
 * 2.1:将扫包范围的所有类,注入到springmvc容器里,存放到map集合中,key为默认类名小写,value为对象
 * 2.2:将url映射和方法进行关联
 * 2.2.1:判断方法上是否有注解,使用java反射机制循环遍历方法,判断方法上是否有注解,进行封装url和方法对应 存入到map集合
 * 3:处理请求,重写GET/POST方法
 * 3.1:获取请求url,从urlbean集合获取实例对象,获取成功实例对象后,调用urlMether集合获取请求方法名称,使用反射机制执行,
 *
 *
 * */

public class WTKDispatcherServlet extends HttpServlet{
    //springmvc 容器对象key : 类名id,value 对象
    private ConcurrentHashMap<String,Object> springmvcBean = new ConcurrentHashMap<String, Object>();
    //springmvc 容器对象,key 请求地址,value 类
    private ConcurrentHashMap<String,Object> urlBeans = new ConcurrentHashMap<String, Object>();
    //springmvc容器对象 key:请求地址,value 方法名
    private ConcurrentHashMap<String,String> urlMethods = new ConcurrentHashMap<String, String>();


    @Override
    public void init() throws ServletException{

        //1:获取当前包下的所有类
        List<Class<?>> classes = ClassUtil.getClasses("com.wtk.springmvc.controller");
        //2:将扫包的范围内所有的类,注入到springMVC容器里面,存放在Map集合中,key默认为类名小写,value 为对象
       try {
           findClassMVCAnnotation(classes);
       }catch (Exception e){

       }
        //3:将url映射和方法进行关联
        handlerMapping();
    }

    public void findClassMVCAnnotation(List<Class<?>> classes) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        for(Class<?> classInof : classes){
            //判断类上是否有加注解
            WTKController wtkController = classInof.getDeclaredAnnotation(WTKController.class);
            if(wtkController != null){
                //默认类名为小写
                String beanId = ClassUtil.toLowerCaseFirstOne(classInof.getSimpleName());
                Object object = ClassUtil.newInstance(classInof);
                springmvcBean.put(beanId,object);
            }
        }
    }
    //3:将url映射和方法进行关联
    public void handlerMapping(){
        //1:遍历springmv Bean容器,判断类上是否有url映射路径
        for (Map.Entry<String,Object> mvcBean : springmvcBean.entrySet()){
            //遍历所有的方法上是否有url映射注解
            Object object = mvcBean.getValue();
            //3判断类上是否加上了url映射注解
            Class<? extends Object> classInfo = object.getClass();
            WTKRequestMapping declareAnnotation = classInfo.getDeclaredAnnotation(WTKRequestMapping.class);
            String beaseUrl = "";
            if(declareAnnotation != null){
                //获取类上的url映射地址
                beaseUrl = declareAnnotation.value();
            }
            Method[] declaresMethods  = classInfo.getDeclaredMethods();
            for (Method method : declaresMethods){
                //判断方法上是否加url映射地址
                WTKRequestMapping wtkRequestMapping = method.getDeclaredAnnotation(WTKRequestMapping.class);
                if(wtkRequestMapping!=null){
                    String methodUrl = beaseUrl +  wtkRequestMapping.value();
                    //springmvc容器对象 key:请求地址,value:类
                    urlBeans.put(methodUrl,object);
                    //springmc 容器对象,key:请求地址,value: 方法名称
                    urlMethods.put(methodUrl,method.getName());
                }
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request.getRequestURI());
        doPost(request,response);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1:获取请求URL
        String requestURL = req.getRequestURI();
        if (StringUtils.isEmpty(requestURL)) {
            return;
        }
        //2:从map集合中获取控制对象
        Object object = urlBeans.get(requestURL);
        if(object == null){
            resp.getWriter().println("not foun 404 url");
            return;
        }
        //3:使用url地址获取方法
        String methodName = urlMethods.get(requestURL);
        if(StringUtils.isEmpty(methodName)){
            resp.getWriter().println("not found method");
        }
        //4:使用java的反射机制调用方法
        String resultPage = (String) methodInvoke(object,methodName);

        //5:使用java的反射机制获取方法返回结果
        extResourceViewResolver(resultPage,req,resp);
        //6:调用视图转换器渲染给页面展示
    }

    private void extResourceViewResolver(String pageName,HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException {
        // 根路径
        String prefix = "/";
        String suffix = ".jsp";
        req.getRequestDispatcher(prefix + pageName + suffix).forward(req, res);
    }

    private Object methodInvoke(Object object,String methodName){
        try {
            Class<? extends Object> clseeInof = object.getClass();
            Method method = clseeInof.getMethod(methodName);
            Object result =  method.invoke(object);
            return result;
        } catch (Exception e) {

            return null;
        }
    }

}

5:controller实现

@WTKController
@WTKRequestMapping("/wtk")
public class WtkIndexController {
    @WTKRequestMapping("/test")
    public String test(){
        System.out.println("手写springmvc框架。。。。");
        return "indexs";
    }
}

6:遇到的问题
(1)在web.xml配置文件中因为在servlet配置的是"/*"导致返回jsp时候会跳入DispatcherServlet导致无法跳入页面,问题找了很久。

<servlet-mapping>
        <servlet-name>WTKSpringMVC</servlet-name>
        <!--"/" 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。-->
        <!-- " /*"  会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

该内容大部分借鉴蚂蚁课堂,如有侵权请指出!!!
如有错误,请指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值