如何简单的实现springmvc进行调用
2017-12-13 20:08
246 查看
我是模拟springmvc的使用使用Controller和RequestMapping和RequestBody注解进行的
主要的类也是DispatchServlet:它里面进行的动作是扫描指定的包下面的类,本将映射地址和方法对象加载到内存中,controller类也是单列类;
maven依赖
自定义工具类:
最核心的类分析
项目地址的github地址
https://github.com/yinbucheng/myspringmvc
主要的类也是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; } }
存储映射关系和自定义方法数据结构BeanDefination import 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&¶msName.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
相关文章推荐
- 一个简单RPC框架是如何炼成的(III)——实现带参数的RPC调用
- [置顶] 如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试
- 如何用js实现,在一个页面有个输入文档框,然后点击查询按扭后,调用IE的查询功能在当前页面进行查询
- 【远程调用框架】如何实现一个简单的RPC框架(二)实现与使用
- 如何用Java来进行文件切割和简单的内容过滤的实现
- springMVC框架下如何实现移动端接口调用
- springMVC框架下如何实现移动端接口调用——代码实例
- html嵌套iframe如何实现等iframe页面加载完进行下一步调用
- 【远程调用框架】如何实现一个简单的RPC框架(五)优化三:软负载中心设计与实现
- 如何实现点击UITableViewCell中的控件,能调用到所在的ViewController对象进行页面跳转
- springMVC框架下如何实现移动端接口调用2
- 【远程调用框架】如何实现一个简单的RPC框架(四)优化二:改变底层通信框架
- javascript异步调用XML进行解析的简单实现
- Cumulus RTMFP实现P2P视频流如何调用BitMapData.draw()进行截图?
- Android JNI实现简单的c层调用Java层函数(C层调用Java层Toast进行提示)
- springMVC框架下如何实现移动端接口调用——流程简介篇
- 【远程调用框架】如何实现一个简单的RPC框架(一)想法与设计
- 【远程调用框架】如何实现一个简单的RPC框架(三)优化一:利用动态代理改变用户服务调用方式
- 如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试
- 用批处理如何实现telnet登陆并进行一些简单命令