如何简单的实现springmvc进行调用

来源:互联网 发布:java web网站开发 编辑:程序博客网 时间:2024/05/16 17:58

我是模拟springmvc的使用使用Controller和RequestMapping和RequestBody注解进行的

主要的类也是DispatchServlet:它里面进行的动作是扫描指定的包下面的类,本将映射地址和方法对象加载到内存中,controller类也是单列类;


maven依赖

<!-- https://mvnrepository.com/artifact/javax.activation/activation -->    <dependency>      <groupId>javax.activation</groupId>      <artifactId>activation</artifactId>      <version>1.1.1</version>    </dependency>    <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->    <dependency>      <groupId>commons-beanutils</groupId>      <artifactId>commons-beanutils</artifactId>      <version>1.9.3</version>    </dependency>    <!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->    <dependency>      <groupId>commons-dbutils</groupId>      <artifactId>commons-dbutils</artifactId>      <version>1.7</version>    </dependency>    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->    <dependency>      <groupId>commons-io</groupId>      <artifactId>commons-io</artifactId>      <version>2.6</version>    </dependency>    <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->    <dependency>      <groupId>commons-logging</groupId>      <artifactId>commons-logging</artifactId>      <version>1.2</version>    </dependency>    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->    <dependency>      <groupId>javax.servlet.jsp.jstl</groupId>      <artifactId>jstl</artifactId>      <version>1.2</version>    </dependency>     <dependency>      <groupId>taglibs</groupId>      <artifactId>standard</artifactId>      <version>1.1.1</version>    </dependency>    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->    <dependency>      <groupId>javax.servlet</groupId>      <artifactId>javax.servlet-api</artifactId>      <version>3.1.0</version>      <scope>provided</scope>    </dependency>    <dependency>      <groupId>org.javassist</groupId>      <artifactId>javassist</artifactId>      <version>3.22.0-GA</version>    </dependency>    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->    <dependency>      <groupId>com.alibaba</groupId>      <artifactId>fastjson</artifactId>      <version>1.2.41</version>    </dependency>

自定义工具类:

import java.io.Serializable;import java.lang.reflect.Method;//自定义方法数据结构public class BeanDefination implements Serializable{    private Object target;//目标对象    private Method method;//目标方法对象    public BeanDefination(Object target, Method method) {        this.target = target;        this.method = method;    }    public BeanDefination() {    }    public Object getTarget() {        return target;    }    public void setTarget(Object target) {        this.target = target;    }    public Method getMethod() {        return method;    }    public void setMethod(Method method) {        this.method = method;    }}

import java.util.HashMap;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;/** * 方法名称和里面参数名称进行缓存 */public  class MethodParamCache {    private Map<String,List<String>> paramMap = new HashMap<>();    private MethodParamCache(){    }    public static MethodParamCache getInstance(){        return Inner.methodParamCache;    }    public void put(String methodName,List<String> paramsName){        paramMap.put(methodName,paramsName);    }    public List<String> get(String methodName){        return paramMap.get(methodName);    }    private static class Inner{        private static MethodParamCache methodParamCache = new MethodParamCache();    }}

import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.Properties;/** * 读取配置文件工具类,它读取source目录下config.properties文件 */public abstract class ReadUtils {    private static Map<String,Object> cache = new HashMap<>();    private static Properties properties = null;    static {        properties = new Properties();        try {            properties.load(ReadUtils.class.getResourceAsStream("/config.properties"));        } catch (IOException e) {            e.printStackTrace();        }    }    public static Object read(String key){        Object value = cache.get(key);        if(value==null){            synchronized (ReadUtils.class){                value = cache.get(key);                if(value==null) {                    value = properties.get(key);                    cache.put(key, value);                }            }        }        return value;    }}



存储映射关系和自定义方法数据结构BeanDefinationimport cn.ishow.manage.domain.BeanDefination;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;/** * 将映射与方法对应起来 */public class MappingMethodCache {    private Map<String,BeanDefination> mappingCahe = new HashMap<>();    public static MappingMethodCache getInstance(){        return Inner.instance;    }    public void put(String mapper,BeanDefination method){        BeanDefination temp = mappingCahe.get(mapper);       if(temp!=null){           throw new RuntimeException(mapper+"该映射对应的方法不唯一。");       }        mappingCahe.put(mapper,method);    }    public BeanDefination get(String mapper){        return mappingCahe.get(mapper);    }    private static class Inner{      private   static MappingMethodCache instance = new MappingMethodCache();    }}

import javassist.ClassPool;import javassist.CtClass;import javassist.CtMethod;import javassist.Modifier;import javassist.bytecode.CodeAttribute;import javassist.bytecode.LocalVariableAttribute;import javassist.bytecode.MethodInfo;import java.util.LinkedList;import java.util.List;public class ReflectUtils {    /**     * 顺序获取方法上面参数名称     * @param target     * @param methodName     * @return     */    public static List<String> listParamNames(Class target, String methodName){        ClassPool pool = ClassPool.getDefault();        try{            CtClass ctClass = pool.get(target.getName());            CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);            MethodInfo methodInfo = ctMethod.getMethodInfo();            CodeAttribute codeAttribute = methodInfo.getCodeAttribute();            LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute                    .getAttribute(LocalVariableAttribute.tag);            List<String> paramNames = new LinkedList<String>();            if (attr != null) {                int len = ctMethod.getParameterTypes().length;                int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;                for (int i = 0; i < len; i++) {                    String key = attr.variableName(i + pos);                    paramNames.add(key);                }            }            return paramNames;        }catch(Exception e){            throw new RuntimeException(e);        }    }}


最核心的类分析

package cn.ishow.manage.system;import cn.ishow.manage.annotation.Controller;import cn.ishow.manage.annotation.RequestMapping;import cn.ishow.manage.annotation.ResponseBody;import cn.ishow.manage.domain.BeanDefination;import cn.ishow.manage.utils.MappingMethodCache;import cn.ishow.manage.utils.MethodParamCache;import cn.ishow.manage.utils.ReadUtils;import cn.ishow.manage.utils.ReflectUtils;import com.alibaba.fastjson.JSON;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.IOException;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;public class DispatchServlet extends HttpServlet {    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {            doServlet(req, resp);    }    private void doServlet(HttpServletRequest req, HttpServletResponse resp) {        try {            RequestContextHodler.setAttribute(req,resp);           Object value =  invokeMethod(req, resp);           String str = (String) value;            resp.setHeader("Content-type", "text/html;charset=UTF-8");            resp.setCharacterEncoding("utf-8");            resp.getWriter().write(str);        } catch (Exception e) {           throw new RuntimeException(e);        }finally {            RequestContextHodler.remove();        }    }    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {               doServlet(req, resp);    }    private Object invokeMethod(HttpServletRequest request,HttpServletResponse response)throws Exception{        String uri = request.getRequestURI();//获取request中请求后面一部分        BeanDefination beanDefination = MappingMethodCache.getInstance().get(uri);//根据uri获取对应的方法        if(beanDefination==null){            return "{\"code\":500,\"msg\":\"no mapping method find\"}";        }        Object target = beanDefination.getTarget();        Method method = beanDefination.getMethod();        String methodName = method.getName();       List<String> paramsName = null;       paramsName = MethodParamCache.getInstance().get(methodName);//根据方法名从缓存中获取对应的参数       if(paramsName==null) {        paramsName =  ReflectUtils.listParamNames(target.getClass(), methodName);//如何缓存中没有就反射获取并放入到缓存中        MethodParamCache.getInstance().put(methodName,paramsName);       }       if(paramsName==null||paramsName.size()==0) {//方法没有参数就进入这里           Object object =  method.invoke(target, null);//调用方法           return parseObjectToString(method, object);       }       //参数抓换        List<String> values = new ArrayList<>();        if(paramsName!=null&&paramsName.size()>0){            for(String paramName:paramsName){               String value =  request.getParameter(paramName);              values.add(value);            }        }        Class[] paramterTyps = method.getParameterTypes();        List<Object> params = new ArrayList<>(values.size());        for(int i=0;i<paramterTyps.length;i++){            Class paramterType = paramterTyps[i];            String value = values.get(i);            if(paramterType.equals(String.class)){                params.add(value);            }else if(paramterType.equals(Integer.class)){                Integer temp = Integer.parseInt(value);                params.add(temp);            }else if(paramterType.equals(Long.class)){                Long temp = Long.parseLong(value);                params.add(temp);            }else if(paramterType.equals(Boolean.class)){                Boolean temp = Boolean.parseBoolean(value);                params.add(temp);            }else{                throw new RuntimeException("目前还没提供该类型支持");            }        }        Object object =    method.invoke(target,params.toArray());//调用方法         return parseObjectToString(method, object);    }    //这里是将返回的结果变为String输出,如果方法上面有ResponseBody注解则采用Json格式输出    private Object parseObjectToString(Method method, Object object) {        boolean flag = method.isAnnotationPresent(ResponseBody.class);        if(flag){            return JSON.toJSONString(object);        }else{            return object;        }    }    //Servlet初始化方法,这个方法会扫描指定包下面的类并加装到内存    @Override    public void init() throws ServletException {        super.init();        String webPackage = (String) ReadUtils.read("web_scan");        String totalPath = resovleTotalPath(webPackage);        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>totalPath:"+totalPath);        List<String> classNames = new ArrayList<>();        //解析className        parseClassName(totalPath, webPackage, classNames);        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>classNames:"+classNames);        resolveMethodMapping(classNames);        System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>解析完成................");    }    /**     * 产生该包下的全路径     * @param webPackage     * @return     */    private String resovleTotalPath(String webPackage) {        //扫码所有的包并把其放入到访问关系和方法放入到内存中        File f = new File(getClass().getResource("/").getPath());        String totalPath = f.getAbsolutePath();        System.out.println(totalPath);        String pageName = getClass().getPackage().getName().replace(".","\\");        totalPath = totalPath.replace(pageName,"");        String  packagePath = webPackage.replace(".","\\");        totalPath=totalPath+"\\"+packagePath;        return totalPath;    }    private void resolveMethodMapping(List<String> classNames) {        if(classNames.size()!=0){            for(String className:classNames){                try{                  Class clazz = Class.forName(className);                  Object target = clazz.newInstance();                  boolean flag = clazz.isAnnotationPresent(Controller.class);                  if(!flag)                      continue;                 RequestMapping head = (RequestMapping) clazz.getAnnotation(RequestMapping.class);                 String headUrl = head.value();                 Method[]  methods = clazz.getMethods();                 if(methods==null||methods.length==0)                     continue;                 for(Method method:methods){                    RequestMapping body =  method.getAnnotation(RequestMapping.class);                    if(body==null)                        continue;;                  String totalUrl = headUrl + body.value();                    MappingMethodCache.getInstance().put(totalUrl,new BeanDefination(target,method));                 }                }catch (Exception e){                    throw new RuntimeException(e);                }            }        }    }    private void parseClassName(String totalPath, String webPackage, List<String> classNames) {        File path = new File(totalPath);        if(path.exists()){           File[] childs =  path.listFiles();           if(childs!=null&&childs.length>0){               for(File child:childs){                  String fileName =  child.getName();                  if(fileName.endsWith(".class")){                      String temp = fileName.replace(".class","");                      classNames.add(webPackage+"."+temp);                  }               }           }        }    }}


项目地址的github地址

https://github.com/yinbucheng/myspringmvc

 
阅读全文
0 0
原创粉丝点击