├── .classpath ├── .project ├── .settings ├── .jsdtscope ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.wst.jsdt.ui.superType.name └── org.eclipse.wst.validation.prefs ├── README.md ├── pom.xml ├── src └── main │ ├── java │ └── com │ │ └── liugh │ │ ├── annotation │ │ ├── MyController.java │ │ ├── MyRequestMapping.java │ │ └── MyRequestParam.java │ │ ├── core │ │ └── controller │ │ │ └── TestController.java │ │ └── servlet │ │ └── MyDispatcherServlet.java │ ├── resources │ └── application.properties │ └── webapp │ └── WEB-INF │ └── web.xml └── target ├── classes ├── application.properties └── com │ └── liugh │ ├── annotation │ ├── MyController.class │ ├── MyRequestMapping.class │ └── MyRequestParam.class │ ├── core │ └── controller │ │ └── TestController.class │ └── servlet │ └── MyDispatcherServlet.class └── m2e-wtp └── web-resources └── META-INF ├── MANIFEST.MF └── maven └── com.liugh └── liughMVC ├── pom.properties └── pom.xml /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | liughMVC 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.validation.validationbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.eclipse.jem.workbench.JavaEMFNature 31 | org.eclipse.wst.common.modulecore.ModuleCoreNature 32 | org.eclipse.jdt.core.javanature 33 | org.eclipse.m2e.core.maven2Nature 34 | org.eclipse.wst.common.project.facet.core.nature 35 | org.eclipse.wst.jsdt.core.jsNature 36 | 37 | 38 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/main/webapp=UTF-8 5 | encoding//src/test/java=UTF-8 6 | encoding//src/test/resources=UTF-8 7 | encoding/=UTF-8 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.8 9 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### [博客地址](https://my.oschina.net/liughDevelop/blog/1622646) -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.liugh 4 | liughMVC 5 | 0.0.1-SNAPSHOT 6 | war 7 | 8 | 9 | UTF-8 10 | 1.8 11 | 1.8 12 | 1.8 13 | 14 | 15 | 16 | 17 | javax.servlet 18 | javax.servlet-api 19 | 3.0.1 20 | provided 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/liugh/annotation/MyController.java: -------------------------------------------------------------------------------- 1 | package com.liugh.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface MyController { 13 | /** 14 | * 表示给controller注册别名 15 | * @return 16 | */ 17 | String value() default ""; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/liugh/annotation/MyRequestMapping.java: -------------------------------------------------------------------------------- 1 | package com.liugh.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target({ElementType.TYPE,ElementType.METHOD}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface MyRequestMapping { 13 | /** 14 | * 表示访问该方法的url 15 | * @return 16 | */ 17 | String value() default ""; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/liugh/annotation/MyRequestParam.java: -------------------------------------------------------------------------------- 1 | package com.liugh.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | @Target(ElementType.PARAMETER) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface MyRequestParam { 13 | /** 14 | * 表示参数的别名,必填 15 | * @return 16 | */ 17 | String value(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/liugh/core/controller/TestController.java: -------------------------------------------------------------------------------- 1 | package com.liugh.core.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import com.liugh.annotation.MyController; 9 | import com.liugh.annotation.MyRequestMapping; 10 | import com.liugh.annotation.MyRequestParam; 11 | 12 | @MyController 13 | @MyRequestMapping("/test") 14 | public class TestController { 15 | 16 | 17 | 18 | @MyRequestMapping("/doTest") 19 | public void test1(HttpServletRequest request, HttpServletResponse response, 20 | @MyRequestParam("param") String param){ 21 | System.out.println(param); 22 | try { 23 | response.getWriter().write( "doTest method success! param:"+param); 24 | } catch (IOException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | 29 | 30 | @MyRequestMapping("/doTest2") 31 | public void test2(HttpServletRequest request, HttpServletResponse response){ 32 | try { 33 | response.getWriter().println("doTest2 method success!"); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/liugh/servlet/MyDispatcherServlet.java: -------------------------------------------------------------------------------- 1 | package com.liugh.servlet; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.lang.reflect.Method; 7 | import java.net.URL; 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Map.Entry; 14 | import java.util.Properties; 15 | 16 | import javax.servlet.ServletConfig; 17 | import javax.servlet.ServletException; 18 | import javax.servlet.http.HttpServlet; 19 | import javax.servlet.http.HttpServletRequest; 20 | import javax.servlet.http.HttpServletResponse; 21 | 22 | import com.liugh.annotation.MyController; 23 | import com.liugh.annotation.MyRequestMapping; 24 | 25 | public class MyDispatcherServlet extends HttpServlet{ 26 | 27 | private Properties properties = new Properties(); 28 | 29 | private List classNames = new ArrayList<>(); 30 | 31 | private Map ioc = new HashMap<>(); 32 | 33 | private Map handlerMapping = new HashMap<>(); 34 | 35 | private Map controllerMap =new HashMap<>(); 36 | 37 | 38 | @Override 39 | public void init(ServletConfig config) throws ServletException { 40 | 41 | //1.加载配置文件 42 | doLoadConfig(config.getInitParameter("contextConfigLocation")); 43 | 44 | //2.初始化所有相关联的类,扫描用户设定的包下面所有的类 45 | doScanner(properties.getProperty("scanPackage")); 46 | 47 | //3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v beanName-bean) beanName默认是首字母小写 48 | doInstance(); 49 | 50 | //4.初始化HandlerMapping(将url和method对应上) 51 | initHandlerMapping(); 52 | 53 | 54 | } 55 | 56 | 57 | 58 | @Override 59 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 60 | this.doPost(req,resp); 61 | } 62 | 63 | @Override 64 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 65 | try { 66 | //处理请求 67 | doDispatch(req,resp); 68 | } catch (Exception e) { 69 | resp.getWriter().write("500!! Server Exception"); 70 | } 71 | 72 | } 73 | 74 | 75 | private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception { 76 | if(handlerMapping.isEmpty()){ 77 | return; 78 | } 79 | 80 | String url =req.getRequestURI(); 81 | String contextPath = req.getContextPath(); 82 | 83 | //拼接url并把多个/替换成一个 84 | url=url.replace(contextPath, "").replaceAll("/+", "/"); 85 | 86 | if(!this.handlerMapping.containsKey(url)){ 87 | resp.getWriter().write("404 NOT FOUND!"); 88 | return; 89 | } 90 | 91 | Method method =this.handlerMapping.get(url); 92 | 93 | //获取方法的参数列表 94 | Class[] parameterTypes = method.getParameterTypes(); 95 | 96 | //获取请求的参数 97 | Map parameterMap = req.getParameterMap(); 98 | 99 | //保存参数值 100 | Object [] paramValues= new Object[parameterTypes.length]; 101 | 102 | //方法的参数列表 103 | for (int i = 0; i param : parameterMap.entrySet()) { 119 | String value =Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ","); 120 | paramValues[i]=value; 121 | } 122 | } 123 | } 124 | //利用反射机制来调用 125 | try { 126 | method.invoke(this.controllerMap.get(url), paramValues);//obj是method所对应的实例 在ioc容器中 127 | } catch (Exception e) { 128 | e.printStackTrace(); 129 | } 130 | } 131 | 132 | 133 | 134 | private void doLoadConfig(String location){ 135 | //把web.xml中的contextConfigLocation对应value值的文件加载到留里面 136 | InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location); 137 | try { 138 | //用Properties文件加载文件里的内容 139 | properties.load(resourceAsStream); 140 | } catch (IOException e) { 141 | e.printStackTrace(); 142 | }finally { 143 | //关流 144 | if(null!=resourceAsStream){ 145 | try { 146 | resourceAsStream.close(); 147 | } catch (IOException e) { 148 | e.printStackTrace(); 149 | } 150 | } 151 | } 152 | 153 | } 154 | 155 | private void doScanner(String packageName) { 156 | //把所有的.替换成/ 157 | URL url =this.getClass().getClassLoader().getResource("/"+packageName.replaceAll("\\.", "/")); 158 | File dir = new File(url.getFile()); 159 | for (File file : dir.listFiles()) { 160 | if(file.isDirectory()){ 161 | //递归读取包 162 | doScanner(packageName+"."+file.getName()); 163 | }else{ 164 | String className =packageName +"." +file.getName().replace(".class", ""); 165 | classNames.add(className); 166 | } 167 | } 168 | } 169 | 170 | 171 | 172 | private void doInstance() { 173 | if (classNames.isEmpty()) { 174 | return; 175 | } 176 | for (String className : classNames) { 177 | try { 178 | //把类搞出来,反射来实例化(只有加@MyController需要实例化) 179 | Class clazz =Class.forName(className); 180 | if(clazz.isAnnotationPresent(MyController.class)){ 181 | ioc.put(toLowerFirstWord(clazz.getSimpleName()),clazz.newInstance()); 182 | }else{ 183 | continue; 184 | } 185 | 186 | 187 | } catch (Exception e) { 188 | e.printStackTrace(); 189 | continue; 190 | } 191 | } 192 | } 193 | 194 | 195 | private void initHandlerMapping(){ 196 | if(ioc.isEmpty()){ 197 | return; 198 | } 199 | try { 200 | for (Entry entry: ioc.entrySet()) { 201 | Class clazz = entry.getValue().getClass(); 202 | if(!clazz.isAnnotationPresent(MyController.class)){ 203 | continue; 204 | } 205 | 206 | //拼url时,是controller头的url拼上方法上的url 207 | String baseUrl =""; 208 | if(clazz.isAnnotationPresent(MyRequestMapping.class)){ 209 | MyRequestMapping annotation = clazz.getAnnotation(MyRequestMapping.class); 210 | baseUrl=annotation.value(); 211 | } 212 | Method[] methods = clazz.getMethods(); 213 | for (Method method : methods) { 214 | if(!method.isAnnotationPresent(MyRequestMapping.class)){ 215 | continue; 216 | } 217 | MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class); 218 | String url = annotation.value(); 219 | 220 | url =(baseUrl+"/"+url).replaceAll("/+", "/"); 221 | //这里应该放置实例和method 222 | handlerMapping.put(url,method); 223 | controllerMap.put(url,clazz.newInstance()); 224 | System.out.println(url+","+method); 225 | } 226 | 227 | } 228 | 229 | } catch (Exception e) { 230 | e.printStackTrace(); 231 | } 232 | 233 | } 234 | 235 | 236 | /** 237 | * 把字符串的首字母小写 238 | * @param name 239 | * @return 240 | */ 241 | private String toLowerFirstWord(String name){ 242 | char[] charArray = name.toCharArray(); 243 | charArray[0] += 32; 244 | return String.valueOf(charArray); 245 | } 246 | 247 | 248 | } 249 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | scanPackage=com.liugh.core -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | MySpringMVC 8 | com.liugh.servlet.MyDispatcherServlet 9 | 10 | contextConfigLocation 11 | application.properties 12 | 13 | 1 14 | 15 | 16 | MySpringMVC 17 | /* 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /target/classes/application.properties: -------------------------------------------------------------------------------- 1 | scanPackage=com.liugh.core -------------------------------------------------------------------------------- /target/classes/com/liugh/annotation/MyController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq53182347/liughMVC/a6559383071053fa04088303b02193088b24fdab/target/classes/com/liugh/annotation/MyController.class -------------------------------------------------------------------------------- /target/classes/com/liugh/annotation/MyRequestMapping.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq53182347/liughMVC/a6559383071053fa04088303b02193088b24fdab/target/classes/com/liugh/annotation/MyRequestMapping.class -------------------------------------------------------------------------------- /target/classes/com/liugh/annotation/MyRequestParam.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq53182347/liughMVC/a6559383071053fa04088303b02193088b24fdab/target/classes/com/liugh/annotation/MyRequestParam.class -------------------------------------------------------------------------------- /target/classes/com/liugh/core/controller/TestController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq53182347/liughMVC/a6559383071053fa04088303b02193088b24fdab/target/classes/com/liugh/core/controller/TestController.class -------------------------------------------------------------------------------- /target/classes/com/liugh/servlet/MyDispatcherServlet.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qq53182347/liughMVC/a6559383071053fa04088303b02193088b24fdab/target/classes/com/liugh/servlet/MyDispatcherServlet.class -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Built-By: Administrator 3 | Build-Jdk: 1.8.0_101 4 | Created-By: Maven Integration for Eclipse 5 | 6 | -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/maven/com.liugh/liughMVC/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven Integration for Eclipse 2 | #Fri Feb 23 17:11:07 CST 2018 3 | version=0.0.1-SNAPSHOT 4 | groupId=com.liugh 5 | m2e.projectName=liughMVC 6 | m2e.projectLocation=D\:\\javaSoft\\eclipse-neon\\eclipse\\workspace\\liughMVC 7 | artifactId=liughMVC 8 | -------------------------------------------------------------------------------- /target/m2e-wtp/web-resources/META-INF/maven/com.liugh/liughMVC/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.liugh 4 | liughMVC 5 | 0.0.1-SNAPSHOT 6 | war 7 | 8 | 9 | UTF-8 10 | 1.8 11 | 1.8 12 | 1.8 13 | 14 | 15 | 16 | 17 | javax.servlet 18 | javax.servlet-api 19 | 3.0.1 20 | provided 21 | 22 | 23 | --------------------------------------------------------------------------------