JavaWeb之搭建自己的MVC框架(三)

1. 前言

在前两节的内容中,我们完成了一个基本的框架搭建。但是如果我们在前端请求中增加参数,我们要怎么传递到后台方法呢?接下来我们就来研讨这部分内容。

2. 实现

(1)首先我们增加一个新的注解ParamMapping,用来给方法的参数标注其对应的前端参数名称。

package com.mvc.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;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamMapping {    
    public String param() default "";
}

(2)我们在SayController中增加一个方法SayAnything,内容如下:

package com.mvc.controller;

import com.mvc.annotation.ParamMapping;
import com.mvc.annotation.URLMapping;

@URLMapping(url="/Say")
public class SayController{
    
    @URLMapping(url="/Hello")
    public String SayHello(){
        System.out.println("Hello");
        return "Hello";
    }
    
    @URLMapping(url="/Hi")
    public String SayHi(){
        System.out.println("Hi");
        return "Hi";
    }
    
    @URLMapping(url="/Anything")
    public String SayAnything(@ParamMapping(param="word") String word){
        System.out.println(word);
        return word;
    }    
}

 在SayAnything的参数中,我们对String word参数进行了注解@ParamMapping(param="word"),表示将来前端传参数名word,我们的框架会将其对应到SayAnything的String word参数中。

(3)我们在SayController中增加一个方法SayAnything,内容如下:

package com.mvc.controller;

import com.mvc.annotation.ParamMapping;
import com.mvc.annotation.URLMapping;

@URLMapping(url="/Eat")
public class EatController {
    
    @URLMapping(url="/Apple")
    public String EatApple(){
        System.out.println("I'm eating apples");
        return "Apple";
    }
    
    @URLMapping(url="/Banana")
    public String EatBanana(){
        System.out.println("I'm eating Banana");
        return "Banana";
    }
    
    @URLMapping(url="/Anything")
    public String EatAnything(@ParamMapping(param="fruit") String fruit, 
                              @ParamMapping(param="cnt") Integer cnt) {
        System.out.println("I'm eating "+fruit+", "+cnt);
        return fruit;
    }
}

 EatAnything的参数的注解和SayAnything是同一个道理。  

(4)调整ServletCenter,使其完成前端参数到JAVA后台参数的传递过程。

package com.mvc.servlet;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mvc.annotation.ParamMapping;
import com.mvc.base.MVCBase;
import com.mvc.listener.UrlMappingCollection;

public class ServletCenter extends HttpServlet {
    private static final long serialVersionUID = -1163369749078348562L;

    private void doTransfer(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException, ClassNotFoundException, 
                   SecurityException, NoSuchMethodException, IllegalArgumentException, 
                   IllegalAccessException, InvocationTargetException, 
                   InstantiationException {        
        for (MVCBase mvcBase : UrlMappingCollection.getMvcBases()) {
            if (req.getRequestURI().equals(
                         req.getServletContext().getContextPath()+mvcBase.getUrl())) {
                Class<?> clazz = Class.forName(mvcBase.getController());
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (method.getName().equals(mvcBase.getMethod())) {
                        //拿到参数类型列表
                        Class<?>[] paramTypes =  method.getParameterTypes();
                        //拿到参数的注解列表
                        Annotation[][] paramAnno = method.getParameterAnnotations();
                        //new一个参数值数组吗,将来调用方法的时候要用
                        Object[] paramValues = new Object[paramTypes.length];
                        //每个参数会形成paramAnno的第一维,每个参数的每个注解会行程paramAnno的第二维
                        //所以paramAnno.length和paramTypes.length是相等的。
                        for (int i=0; i<paramAnno.length; i++) { 
                            for (int j=0; j<paramAnno[i].length; j++) {
                                if (paramAnno[i][j] instanceof ParamMapping) {
                                    String paramName = ((ParamMapping) paramAnno[i][j]).param();
                                    if (req.getParameter(paramName) != null) {
                                        if (paramTypes[i].equals(String.class)) {
                                            paramValues[i] = req.getParameter(paramName);
                                        } else if (paramTypes[i].equals(Integer.class)) {
                                            paramValues[i] = Integer.valueOf(
                                                               req.getParameter(paramName));
                                        } else {
                                            //其他类型待后续扩展
                                        }
                                    }    
                                }
                            }
                        }
                        method.invoke(clazz.newInstance(), paramValues);
                    }
                }            
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
                           throws ServletException, IOException {
        try {
            doTransfer(req, resp);
        } catch (Exception e) {
            System.out.println(e.toString());
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
                            throws ServletException, IOException {
        try {
            doTransfer(req, resp);
        } catch (Exception e) {
            System.out.println(e.toString());
        }
    }
}

3. 测试效果:

启动tomcat,在浏览器中输入:

http://127.0.0.1:8080/MyMVC/Say/Anything?word=12345678

http://127.0.0.1:8080/MyMVC/Eat/Anything?fruit=1234&cnt=2

可以看到控制台打印出:

12345678    

I'm eating 1234, 2

posted @ 2016-03-24 21:31  柚子苹果果  阅读(500)  评论(0编辑  收藏  举报