如何简单的实现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&¶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
阅读全文
0 0
- 如何简单的实现springmvc进行调用
- springMVC的简单实现
- springMVC框架下如何实现移动端接口调用
- springMVC框架下如何实现移动端接口调用2
- Android JNI实现简单的c层调用Java层函数(C层调用Java层Toast进行提示)
- springMVC简单的实现代码(一)
- SpringMVC请求分发的简单实现
- SpringMVC请求分发的简单实现
- SpringMVC请求分发的简单实现
- SpringMVC搭建------最简单的实现
- websocket+springmvc 简单的demo实现
- springmvc 分页查询的简单实现
- [置顶] springmvc 分页查询的简单实现
- 简单的springMVC+vue.js+axios实现
- springmvc+Mybatis 分页查询的简单实现
- 如何实现点击UITableViewCell中的控件,能调用到所在的ViewController对象进行页面跳转
- JFinal 如何进行XSS过滤(JFinal 的简单介绍到利用JFinal 的handler实现)
- 如何使用 JMeter 调用你的 Restful Web Service?进行简单的压力测试和自动化测试
- 试水VISA编程(1)——对仪器的基本的控制
- super|this
- Python 管理系统程序
- SpringMVC RequestContextListener配置问题
- 使用Android Studio时报错 Manifest merger failed...Suggestion: add 'tools:replace="android:label"'
- 如何简单的实现springmvc进行调用
- android自定义控件显示小红点
- 判断网络是否可用
- PAT乙级1026. 程序运行时间(15)
- [译]Python的enumerate()函数揭秘
- 3
- [历史最值线段树] UOJ#164. 【清华集训2015】V
- AttributeError: ‘module’ object has no attribute’xxx 问题解决
- 算法学习(1)——算法绪论