├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── jisuye │ │ ├── annotations │ │ ├── Component.java │ │ ├── Config.java │ │ ├── Service.java │ │ ├── SquareApplication.java │ │ ├── aop │ │ │ ├── Aspect.java │ │ │ ├── Before.java │ │ │ └── Pointcut.java │ │ └── web │ │ │ ├── Controller.java │ │ │ ├── DeleteMapping.java │ │ │ ├── GetMapping.java │ │ │ ├── PostMapping.java │ │ │ ├── PutMapping.java │ │ │ ├── RequestBody.java │ │ │ └── RequestParam.java │ │ ├── core │ │ ├── ApplicationContext.java │ │ ├── AspectObject.java │ │ ├── BeanObject.java │ │ ├── BeansMap.java │ │ ├── ControllerObject.java │ │ ├── DispatcherServlet.java │ │ ├── JdbcTemplate.java │ │ ├── RequestContextHolder.java │ │ ├── SquareApplication.java │ │ ├── SquareConfig.java │ │ ├── SquareParam.java │ │ ├── SquareProxy.java │ │ └── SquareProxyHandler.java │ │ ├── exception │ │ └── SquareException.java │ │ └── util │ │ ├── ArgsToKVUtil.java │ │ ├── BeansInitUtil.java │ │ ├── ClassesPathUtil.java │ │ ├── DbUtil.java │ │ ├── LoadApplicationYmlUtil.java │ │ └── StringUtil.java └── resources │ ├── default-banner.txt │ └── public │ └── index.html └── test ├── java └── com │ └── jisuye │ ├── T.java │ └── service │ ├── Abc.java │ ├── AbcEntity.java │ ├── ClassDi.java │ ├── Def.java │ ├── ResponseVo.java │ ├── TestController.java │ ├── TestVo.java │ ├── aop │ └── WebLogAspect.java │ └── impl │ ├── AbcImpl.java │ ├── Def2Impl.java │ └── DefImpl.java └── resources └── application.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # Intellij 7 | .idea/ 8 | *.iml 9 | *.iws 10 | 11 | # Mac 12 | .DS_Store 13 | 14 | # Maven 15 | log/ 16 | map-spatial/log/ 17 | target/ 18 | pom.xml.tag 19 | pom.xml.releaseBackup 20 | pom.xml.versionsBackup 21 | pom.xml.next 22 | release.properties 23 | dependency-reduced-pom.xml 24 | buildNumber.properties 25 | 26 | # java 27 | *.class 28 | *.war 29 | *.ear 30 | 31 | # jrebel 32 | rebel.xml 33 | 34 | # bak 35 | *.bak 36 | /bin/ 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ixx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 天天面对各种各样的轮子,有没有想过自己造一个? 2 | 3 | 看过常见轮子的源码,总是感慨于复杂的设计逻辑。 4 | 5 | 纸上学来终觉浅,于是乎想换个思路,如果从零开始造(抄)一个轮子,那一定会遇到很多问题,带着问题再去看,也许会容易吧(也许并不容易...) 6 | 7 | 因为是第一次造轮子,造出来的东西可以想像的到有多粗糙。反正也不能跑那就定位造一个方形的轮子吧。 8 | 9 | 我先试着列了一下目录清单,写了两篇,感觉还行,但目录结构可能还是会随着造轮子的过程有所调整,到时候会在这里同步修改: 10 | 11 | >[造一个方形的轮子0--起源](http://blog.jisuye.com/2019/06/18/square0/) 12 | > 13 | >[造一个方形的轮子1--嵌入容器](http://blog.jisuye.com/2019/06/20/square1/) 14 | > 15 | >[造一个方形的轮子2--添加配置](http://blog.jisuye.com/2019/06/24/square2/) 16 | > 17 | >[造一个方形的轮子3--控制反转](http://blog.jisuye.com/2019/06/26/square3/) 18 | > 19 | >[造一个方形的轮子4--依赖注入](http://blog.jisuye.com//2019/06/29/square4) 20 | > 21 | >[造一个方形的轮子5--数据库支持](http://blog.jisuye.com/2019/07/08/square5) 22 | > 23 | >[造一个方形的轮子6--Controller支持(上)](http://blog.jisuye.com//2019/07/17/square6) 24 | > 25 | >[造一个方形的轮子7--Controller支持(下)](http://blog.jisuye.com/2019/07/17/square7) 26 | > 27 | >[造一个方形的轮子8--Aop支持](http://blog.jisuye.com/2019/08/10/square8) 28 | > 29 | >[造一个方形的轮子9--编译打包](http://blog.jisuye.com/2019/08/15/square9) 30 | > 31 | >[造一个方形的轮子10--集成第三方](http://blog.jisuye.com/2019/09/09/square10) 32 | > 33 | >[造一个方形的轮子11--后记](http://blog.jisuye.com/2019/09/20/square11) 34 | 35 | 36 | 37 | 38 | 项目名就叫square吧。项目地址: 39 | 40 | 41 | 42 | 后续我会把每一篇对应的代码打一个tag,方便查看。 43 | 44 | 文章的话会不定期更新。 45 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.jisuye 8 | square 9 | 0.1-SNAPSHOT 10 | This is a square wheel 11 | 12 | 9.0.35 13 | 1.7.20 14 | 1.2.3 15 | 1.9 16 | 3.8.1 17 | UTF-8 18 | 5.1.35 19 | 3.3.1 20 | 1.2.58 21 | 22 | 23 | 24 | 25 | org.apache.tomcat.embed 26 | tomcat-embed-core 27 | ${tomcat-version} 28 | 29 | 30 | org.apache.tomcat 31 | tomcat-util 32 | ${tomcat-version} 33 | 34 | 35 | org.apache.tomcat.embed 36 | tomcat-embed-jasper 37 | ${tomcat-version} 38 | 39 | 40 | org.slf4j 41 | slf4j-api 42 | ${slf4j-version} 43 | 44 | 45 | ch.qos.logback 46 | logback-classic 47 | ${logback-version} 48 | 49 | 50 | org.yaml 51 | snakeyaml 52 | ${snakeyaml.version} 53 | 54 | 55 | mysql 56 | mysql-connector-java 57 | ${mysql.version} 58 | provided 59 | 60 | 61 | com.zaxxer 62 | HikariCP 63 | ${hikariCP.version} 64 | 65 | 66 | com.alibaba 67 | fastjson 68 | ${fastjson.version} 69 | 70 | 71 | 72 | 73 | 74 | maven-compiler-plugin 75 | ${compiler.plugin.version} 76 | 77 | 1.8 78 | 1.8 79 | UTF-8 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/Component.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Component注解 10 | * @author ixx 11 | * @date 2019-06-20 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Component { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/Config.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Config注解 10 | * @author ixx 11 | * @date 2019-09-06 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Config { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/Service.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Service注解 10 | * @author ixx 11 | * @date 2019-06-20 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Service { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/SquareApplication.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations; 2 | 3 | public @interface SquareApplication { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/aop/Aspect.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Aspect 10 | * @author ixx 11 | * @date 2019-07-21 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Aspect { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/aop/Before.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 前置aop处理 10 | * @author ixx 11 | * @date 2019-07-21 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Before { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/aop/Pointcut.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 切入点 10 | * @author ixx 11 | * @date 2019-07-21 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Pointcut { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/Controller.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Web Controller annotations 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface Controller { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/DeleteMapping.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * http delete 注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface DeleteMapping { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/GetMapping.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * http get 注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface GetMapping { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/PostMapping.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * http post 注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface PostMapping { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/PutMapping.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * http put 注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.METHOD) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface PutMapping { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/RequestBody.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 请求体body参数注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface RequestBody { 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/annotations/web/RequestParam.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.annotations.web; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * url参数注解 10 | * @author ixx 11 | * @date 2019-07-14 12 | */ 13 | @Target(ElementType.PARAMETER) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | public @interface RequestParam { 16 | String value() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/ApplicationContext.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 应用程序上下文 7 | * @author ixx 8 | * @date 2019-07-01 9 | */ 10 | public class ApplicationContext { 11 | private static Map CONF_MAP; 12 | 13 | public static void init(Map conf){ 14 | CONF_MAP = conf; 15 | } 16 | 17 | public static BeanObject getBean(String name){ 18 | return BeansMap.get(name); 19 | } 20 | 21 | public static BeanObject getBean(Class clazz){ 22 | return BeansMap.get(clazz.getName()); 23 | } 24 | 25 | public static Object getConf(String key){ 26 | return CONF_MAP.get(key); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/AspectObject.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | 9 | /** 10 | * AspectObject 封装 11 | * @author ixx 12 | * @date 2019-08-03 13 | */ 14 | public class AspectObject { 15 | /** 16 | * 包路径 17 | */ 18 | private String packagePath; 19 | 20 | /** 21 | * 方法切面规则 22 | */ 23 | private List methodEx = new ArrayList<>(); 24 | 25 | /** 26 | * 保存Aspect对象 27 | */ 28 | private Object AspectBean; 29 | 30 | /** 31 | * 执行方法集 32 | * key : methodEx 33 | * value : AspectBean.method() 34 | */ 35 | private Map methodMap = new HashMap<>(); 36 | 37 | /** 38 | * 类匹配 39 | */ 40 | private String className; 41 | 42 | /** 43 | * 返回类型 44 | */ 45 | private String retClass; 46 | 47 | /** 48 | * 切面类型(before、after...) 49 | */ 50 | private String type; 51 | 52 | public String getPackagePath() { 53 | return packagePath; 54 | } 55 | 56 | public void setPackagePath(String packagePath) { 57 | this.packagePath = packagePath; 58 | } 59 | 60 | public List getMethodEx() { 61 | return methodEx; 62 | } 63 | 64 | public void setMethodEx(String methodEx) { 65 | this.methodEx.add(methodEx); 66 | } 67 | 68 | public Object getAspectBean() { 69 | return AspectBean; 70 | } 71 | 72 | public void setAspectBean(Object aspectBean) { 73 | AspectBean = aspectBean; 74 | } 75 | 76 | public Map getMethodMap() { 77 | return methodMap; 78 | } 79 | 80 | public void setMethodMap(String key, Method method) { 81 | this.methodMap.put(key, method); 82 | } 83 | 84 | public String getClassName() { 85 | return className; 86 | } 87 | 88 | public void setClassName(String className) { 89 | this.className = className; 90 | } 91 | 92 | public String getType() { 93 | return type; 94 | } 95 | 96 | public void setType(String type) { 97 | this.type = type; 98 | } 99 | 100 | public String getRetClass() { 101 | return retClass; 102 | } 103 | 104 | public void setRetClass(String retClass) { 105 | this.retClass = retClass; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/BeanObject.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Field; 5 | 6 | /** 7 | * 封装Bean对象 8 | * @author ixx 9 | * @date 2019-06-20 10 | */ 11 | public class BeanObject { 12 | 13 | public BeanObject(Class clzz, Object srcObj){ 14 | this.setClass(clzz); 15 | this.srcObj = srcObj; 16 | } 17 | 18 | /** 19 | * 类全名(带包路径) 20 | */ 21 | private String className; 22 | /** 23 | * 类名 24 | */ 25 | private String simpleName; 26 | /** 27 | * 代理(实际)对象 28 | */ 29 | private Object object; 30 | /** 31 | * 实际对象 32 | */ 33 | private Object srcObj; 34 | /** 35 | * 包路径(com.jisuye) 36 | */ 37 | private String packages; 38 | /** 39 | * 注解类型集合 40 | */ 41 | private Annotation[] annotaions; 42 | 43 | /** 44 | * 使用链表处理同一接口多个实现类的情况 45 | */ 46 | private BeanObject next; 47 | 48 | /** 49 | * 接口名 50 | */ 51 | private Class[] interfacs; 52 | 53 | /** 54 | * 字段数组 55 | */ 56 | private Field[] fields; 57 | 58 | /** 59 | * Bean对象的类 60 | */ 61 | private Class beanClass; 62 | 63 | public String getClassName() { 64 | return className; 65 | } 66 | 67 | public void setClassName(String className) { 68 | this.className = className; 69 | } 70 | 71 | public Object getObject() { 72 | return object; 73 | } 74 | 75 | public Object getSrcObj() { 76 | return srcObj; 77 | } 78 | 79 | public void setSrcObj(Object srcObj) { 80 | this.srcObj = srcObj; 81 | } 82 | 83 | public void setObject(Object obj) { 84 | this.object = obj; 85 | } 86 | 87 | public String getPackages() { 88 | return packages; 89 | } 90 | 91 | public void setPackages(String packages) { 92 | this.packages = packages; 93 | } 94 | 95 | public String getSimpleName() { 96 | return simpleName; 97 | } 98 | 99 | public void setSimpleName(String simpleName) { 100 | this.simpleName = simpleName; 101 | } 102 | 103 | public Annotation[] getAnnotaions() { 104 | return annotaions; 105 | } 106 | 107 | public void setAnnotaions(Annotation[] annotaions) { 108 | this.annotaions = annotaions; 109 | } 110 | 111 | public Class[] getInterfacs() { 112 | return interfacs; 113 | } 114 | 115 | public void setInterfacs(Class[] interfacs) { 116 | this.interfacs = interfacs; 117 | } 118 | 119 | public BeanObject getNext() { 120 | return next; 121 | } 122 | 123 | public void setNext(BeanObject next) { 124 | this.next = next; 125 | } 126 | 127 | public Field[] getFields() { 128 | return fields; 129 | } 130 | 131 | public void setFields(Field[] fields) { 132 | this.fields = fields; 133 | } 134 | 135 | public Class getBeanClass() { 136 | return beanClass; 137 | } 138 | 139 | public void setBeanClass(Class beanClass) { 140 | this.beanClass = beanClass; 141 | } 142 | 143 | public void setClass(Class clzz){ 144 | this.setSimpleName(clzz.getSimpleName()); 145 | this.setClassName(clzz.getName()); 146 | this.setInterfacs(clzz.getInterfaces()); 147 | this.setPackages(clzz.getPackage().toString()); 148 | this.setFields(clzz.getDeclaredFields()); 149 | this.setBeanClass(clzz); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/BeansMap.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * beans容器 7 | * @author ixx 8 | * @date 2019-07-14 9 | */ 10 | public class BeansMap { 11 | // bean容器 12 | private static HashMap beans = new HashMap<>(); 13 | 14 | // 保存遍历的所有class 15 | private static List classList = new ArrayList<>(); 16 | 17 | // controller容器 18 | private static HashMap controllers = new HashMap<>(); 19 | 20 | // aop容器 21 | private static HashMap aops = new HashMap<>(); 22 | 23 | public static void putAop(String key, AspectObject aspectObject){ 24 | aops.put(key, aspectObject); 25 | } 26 | 27 | public static AspectObject getAop(String key){ 28 | return aops.get(key); 29 | } 30 | 31 | public static void putController(String key, ControllerObject controllerObject){ 32 | controllers.put(key, controllerObject); 33 | } 34 | 35 | public static ControllerObject getController(String key){ 36 | return controllers.get(key); 37 | } 38 | 39 | public static void put(String key, BeanObject beanObject){ 40 | beans.put(key, beanObject); 41 | } 42 | 43 | public static Set keySet(){ 44 | return beans.keySet(); 45 | } 46 | 47 | public static BeanObject get(String key){ 48 | return beans.get(key); 49 | } 50 | 51 | public static Set> entrySet(){ 52 | return beans.entrySet(); 53 | } 54 | 55 | public static int size(){ 56 | return beans.size(); 57 | } 58 | 59 | public static void addClass(Class clzz){ 60 | classList.add(clzz); 61 | } 62 | public static List getClassList(){ 63 | return classList; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/ControllerObject.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.jisuye.exception.SquareException; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.io.BufferedReader; 11 | import java.io.IOException; 12 | import java.lang.reflect.Method; 13 | 14 | /** 15 | * controller对象 16 | * @author ixx 17 | * @date 2019-07-14 18 | */ 19 | public class ControllerObject { 20 | private static final Logger log = LoggerFactory.getLogger(ControllerObject.class); 21 | 22 | public ControllerObject(SquareParam[] params, String httpMethod,Method method, String beanKey){ 23 | this.params = params; 24 | this.httpMethod = httpMethod; 25 | this.method = method; 26 | // 这里不从容器中获取Bean 只保存获取bean的key (为了做aop兼容)获取动作放到controller调用阶段 27 | this.beanKey = beanKey; 28 | } 29 | /** 30 | * bean 实例 31 | */ 32 | private Object object; 33 | 34 | /** 35 | * 具体方法 36 | */ 37 | private Method method; 38 | 39 | /** 40 | * http请求方式 41 | */ 42 | private String httpMethod; 43 | 44 | /** 45 | * 参数列表(获取@RequestParam指定的参数名,或者@RequestBody指定的类) 46 | */ 47 | private SquareParam[] params; 48 | 49 | /** 50 | * bean 实例在容器中保存的key(为了兼容Aop,延时获取对象使用) 51 | */ 52 | private String beanKey; 53 | 54 | /** 55 | * 反射执行controller方法 56 | * @param req 57 | * @return 58 | */ 59 | public Object invoke(HttpServletRequest req){ 60 | Object[] os = new Object[params.length]; 61 | int i = 0; 62 | for (SquareParam param : params) { 63 | // 如果是String类型则当然参数名从req中取值 否则 当做类 去反射生成 64 | if(param.isParam()){ 65 | os[i++] = toBasicDataType(req.getParameter(param.getParamName()), param.getClazz()); 66 | } else { 67 | String body = getBody(req); 68 | Object tmp = JSON.toJavaObject(JSONObject.parseObject(body), param.getClazz()); 69 | os[i++] = tmp; 70 | } 71 | } 72 | try { 73 | // 延时从容器中获取对象 74 | if(object == null){ 75 | this.setObject(BeansMap.get(beanKey).getObject()); 76 | } 77 | Object o = this.getMethod().invoke(this.getObject(), os); 78 | return o; 79 | } catch (Exception e) { 80 | log.error("Controller method.invoke() is error!", e); 81 | throw new SquareException("Controller method.invoke() is error!", e); 82 | } 83 | } 84 | 85 | private Object toBasicDataType(Object obj, Class clazz){ 86 | if(obj == null || clazz == null){ 87 | return obj; 88 | } 89 | switch (clazz.getName()){ 90 | case "int": 91 | case "java.lang.Integer" : obj = Integer.parseInt(obj.toString()); break; 92 | case "long": 93 | case "java.lang.Long" : obj = Long.parseLong(obj.toString()); break; 94 | case "double": 95 | case "java.lang.Double" : obj = Double.parseDouble(obj.toString()); break; 96 | case "float": 97 | case "java.lang.Float" : obj = Float.parseFloat(obj.toString()); break; 98 | case "boolean": 99 | case "java.lang.Boolean" : obj = Boolean.parseBoolean(obj.toString()); break; 100 | case "char": 101 | case "java.lang.Character" : obj = obj.toString().charAt(0); break; 102 | case "byte": 103 | case "java.lang.Byte" : obj = Byte.parseByte(obj.toString()); break; 104 | default: break; 105 | } 106 | return obj; 107 | } 108 | 109 | public String getBody(HttpServletRequest req){ 110 | String body = ""; 111 | try { 112 | BufferedReader br = req.getReader(); 113 | String tmp; 114 | while ((tmp = br.readLine()) != null){ 115 | body += tmp; 116 | } 117 | } catch (IOException e) { 118 | log.error("getBody data error!", e); 119 | throw new SquareException("Controller parameter getBody data error!", e); 120 | } 121 | return body; 122 | } 123 | 124 | public Object getObject() { 125 | return object; 126 | } 127 | 128 | public void setObject(Object object) { 129 | this.object = object; 130 | } 131 | 132 | public Method getMethod() { 133 | return method; 134 | } 135 | 136 | public void setMethod(Method method) { 137 | this.method = method; 138 | } 139 | 140 | public String getHttpMethod() { 141 | return httpMethod; 142 | } 143 | 144 | public void setHttpMethod(String httpMethod) { 145 | this.httpMethod = httpMethod; 146 | } 147 | 148 | public SquareParam[] getParams() { 149 | return params; 150 | } 151 | 152 | public void setParams(SquareParam[] params) { 153 | this.params = params; 154 | } 155 | 156 | public String getBeanKey() { 157 | return beanKey; 158 | } 159 | 160 | public void setBeanKey(String beanKey) { 161 | this.beanKey = beanKey; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/DispatcherServlet.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | import java.io.IOException; 12 | 13 | /** 14 | * 统一请求Servlet处理 15 | * @author ixx 16 | * @date 2019-07-14 17 | */ 18 | public class DispatcherServlet extends HttpServlet { 19 | private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class); 20 | 21 | @Override 22 | protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 23 | // 保存web上下文 24 | RequestContextHolder.init(req, resp); 25 | // 解析url 26 | String contextPath = req.getContextPath(); 27 | String httpMethod = req.getMethod(); 28 | String uri = req.getRequestURI(); 29 | // 匹配到对应的controller 30 | String controllerKey = httpMethod.toLowerCase()+":"+uri.replaceFirst(contextPath, ""); 31 | log.info("http request path:" + controllerKey); 32 | ControllerObject controllerObject = BeansMap.getController(controllerKey); 33 | // 如果没有匹配,返回404 34 | if(controllerObject == null){ 35 | resp.sendError(404); 36 | } else { 37 | try { 38 | // 执行对应方法 39 | Object obj = controllerObject.invoke(req); 40 | // 处理返回结果 41 | String json; 42 | if (obj instanceof String) { 43 | json = (String) obj; 44 | } else { 45 | json = JSON.toJSONString(obj); 46 | resp.setHeader("content-type", "application/json;charset=UTF-8"); 47 | } 48 | log.info("exec method :" + controllerObject.getMethod().getName()); 49 | log.info("response:" + json); 50 | resp.getWriter().print(json); 51 | } catch (Exception e){ 52 | log.error("Controller invoke error! controllerKey:{}", controllerKey); 53 | resp.sendError(500); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/JdbcTemplate.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import com.jisuye.util.DbUtil; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 添加数据库支持(默认不加载该Bean,有其它Bean引用时再加载) 9 | * @author ixx 10 | * @date 2019-07-05 11 | */ 12 | public class JdbcTemplate { 13 | 14 | public int insert(String sql){ 15 | return DbUtil.update(sql) ? 1 : 0; 16 | } 17 | public int insert(String sql, Object... params){ 18 | return DbUtil.update(sql, params) ? 1 : 0; 19 | } 20 | 21 | public int update(String sql, Object... params){ 22 | return DbUtil.update(sql, params) ? 1 : 0; 23 | } 24 | public int update(String sql){ 25 | return DbUtil.update(sql) ? 1 : 0; 26 | } 27 | 28 | public int delete(String sql){ 29 | return DbUtil.update(sql) ? 1 : 0; 30 | } 31 | public int delete(String sql, Object... params){ 32 | return DbUtil.update(sql, params) ? 1 : 0; 33 | } 34 | 35 | public List select(String sql,Class clazz, Object... param){ 36 | return DbUtil.select(sql, clazz, param); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/RequestContextHolder.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | /** 7 | * 保存当前线程对应Request请求 8 | * @author ixx 9 | * @date 2019-07-27 10 | */ 11 | public class RequestContextHolder { 12 | private static ThreadLocal requestThreadLocal; 13 | 14 | private static ThreadLocal responseThreadLocal; 15 | 16 | 17 | public static HttpServletRequest getRequest() { 18 | if(requestThreadLocal == null){ 19 | return null; 20 | } 21 | return requestThreadLocal.get(); 22 | } 23 | 24 | public static void setRequest(HttpServletRequest request) { 25 | requestThreadLocal = ThreadLocal.withInitial(() -> request); 26 | } 27 | 28 | public static HttpServletResponse getResponse() { 29 | if(responseThreadLocal == null){ 30 | return null; 31 | } 32 | return responseThreadLocal.get(); 33 | } 34 | 35 | public static void setResponse(HttpServletResponse response) { 36 | responseThreadLocal = ThreadLocal.withInitial(() -> response); 37 | } 38 | 39 | public static void init(HttpServletRequest request, HttpServletResponse response){ 40 | requestThreadLocal = ThreadLocal.withInitial(() -> request); 41 | responseThreadLocal = ThreadLocal.withInitial(() -> response); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/SquareApplication.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import com.jisuye.exception.SquareException; 4 | import com.jisuye.util.*; 5 | import org.apache.catalina.Context; 6 | import org.apache.catalina.WebResourceRoot; 7 | import org.apache.catalina.Wrapper; 8 | import org.apache.catalina.servlets.DefaultServlet; 9 | import org.apache.catalina.startup.Tomcat; 10 | import org.apache.catalina.webresources.StandardRoot; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.io.*; 15 | import java.net.URL; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | /** 20 | * 项目启动类 21 | * @author ixx 22 | * @date 2019-6-13 23 | */ 24 | public class SquareApplication { 25 | private static final Logger log = LoggerFactory.getLogger(SquareApplication.class); 26 | private static Map CONF_MAP = new HashMap<>(); 27 | private static Tomcat tomcat = null; 28 | private static String CONTEXT_PATH = "/"; 29 | private static String ENCODING = "UTF-8"; 30 | private static String SUFFIXS = "htm,html,css,js,jpg,jpeg,png,gif,json,mp4,mp3,avi,rm"; 31 | private static int TOMCAT_PORT = 8080; 32 | private static ClassesPathUtil classesPathUtil; 33 | public static String TEMP_TOMCAT_DIR = "/tmp/square/tomcat"; 34 | 35 | public static void run(Class clzz, String[] args) { 36 | try { 37 | long startTime = System.currentTimeMillis(); 38 | ApplicationContext.init(CONF_MAP); 39 | classesPathUtil = new ClassesPathUtil(clzz); 40 | // 加载配置 41 | loadYaml(classesPathUtil.getProjectPath()); 42 | // 初始化参数 43 | setArgs(args); 44 | // 输出banner 45 | printBanner(classesPathUtil.getProjectPath()); 46 | BeansInitUtil.init(clzz); 47 | log.info("beans size is:{}", BeansMap.size()); 48 | //查看bean是否注入成功 49 | tomcat = new Tomcat(); 50 | tomcat.setPort(TOMCAT_PORT); 51 | // 设置Tomcat工作目录 52 | File f = new File(TEMP_TOMCAT_DIR); 53 | if(!f.exists()){ 54 | f.mkdirs(); 55 | } 56 | f.deleteOnExit(); 57 | tomcat.setBaseDir(f.getPath()); 58 | Context context = tomcat.addWebapp(CONTEXT_PATH, classesPathUtil.getPublicPath()); 59 | // jar包中静态文件特殊处理 60 | if(classesPathUtil.getProjectPath().indexOf("!")>0) { 61 | String jar = "jar:"+classesPathUtil.getProjectPath()+"/"; 62 | URL url = new URL(jar); 63 | context.setResources(new StandardRoot(context)); 64 | context.getResources().createWebResourceSet(WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", url, "/public"); 65 | } 66 | // 添加DsipatcherServlet 67 | Wrapper wrapper = Tomcat.addServlet(context, "DispatcherServlet", new DispatcherServlet()); 68 | wrapper.addMapping("/"); 69 | // 设置静态资源走默认Servlet处理 70 | Tomcat.addServlet(context, "DefaultServlet", new DefaultServlet()); 71 | String[] suffixs = SUFFIXS.split(","); 72 | for (String suffix : suffixs) { 73 | context.addServletMappingDecoded("*."+suffix, "DefaultServlet"); 74 | } 75 | // 执行这句才能支持JDNI查找 76 | tomcat.enableNaming(); 77 | tomcat.getConnector().setURIEncoding(ENCODING); 78 | tomcat.start(); 79 | log.info("Tomcat started on port(s): {} with context path '{}'", TOMCAT_PORT, CONTEXT_PATH); 80 | log.info("Started Application in {} ms." , (System.currentTimeMillis() - startTime)); 81 | // 保持服务器进程 82 | tomcat.getServer().await(); 83 | } catch (Exception e) { 84 | if(e instanceof SquareException){ 85 | log.error(((SquareException) e).getMsg()); 86 | } 87 | log.error("Application startup failed...", e); 88 | } 89 | } 90 | 91 | /** 92 | * 初始化参数 93 | * @param args 94 | */ 95 | private static void setArgs(String[] args){ 96 | Map map = ArgsToKVUtil.convert(args); 97 | if(map.get("--server.port") != null){ 98 | TOMCAT_PORT = Integer.parseInt(map.get("--server.port")); 99 | } 100 | } 101 | 102 | /** 103 | * 加载配置文件 104 | * @param projectPath 105 | */ 106 | private static void loadYaml(String projectPath){ 107 | CONF_MAP.putAll(LoadApplicationYmlUtil.load(projectPath)); 108 | if(CONF_MAP.get("server.port") != null){ 109 | TOMCAT_PORT = (Integer)CONF_MAP.get("server.port"); 110 | } 111 | if(CONF_MAP.get("server.servlet.context-path") != null){ 112 | CONTEXT_PATH = (String)CONF_MAP.get("server.servlet.context-path"); 113 | } 114 | } 115 | 116 | /** 117 | * 输出Banner图 118 | * @param projectPath 119 | */ 120 | private static void printBanner(String projectPath){ 121 | BufferedReader br = null; 122 | try{ 123 | File f = new File(projectPath+"/default-banner.txt"); 124 | if(f.exists()){ 125 | br = new BufferedReader(new FileReader(f)); 126 | } else { 127 | InputStream is = SquareApplication.class.getClassLoader().getResourceAsStream("default-banner.txt"); 128 | br = new BufferedReader(new InputStreamReader(is)); 129 | } 130 | StringBuilder stringBuilder = new StringBuilder("\n"); 131 | String line; 132 | while ((line = br.readLine()) != null){ 133 | stringBuilder.append(line).append("\n"); 134 | } 135 | log.info(stringBuilder.toString()); 136 | } catch (Exception e){ 137 | log.info("load banner file error!!", e); 138 | if(br != null){ 139 | try { 140 | br.close(); 141 | } catch (IOException e1) { 142 | } 143 | } 144 | } 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/SquareConfig.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | /** 4 | * 定义config接口,使用@config注解的类需要继承 5 | * @author ixx 6 | * @date 2019-09-08 7 | */ 8 | public interface SquareConfig { 9 | void config(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/SquareParam.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | /** 4 | * 封装参数类型 5 | * @author ixx 6 | * @date 2019-07-14 7 | */ 8 | public class SquareParam { 9 | /** 10 | * 是否是url参数 11 | */ 12 | private boolean param; 13 | 14 | /** 15 | * 参数类型 16 | */ 17 | private Class clazz; 18 | 19 | /** 20 | * 参数名(只有是url参数是才有) 21 | */ 22 | private String paramName; 23 | 24 | public SquareParam(Class clazz){ 25 | this.param = false; 26 | this.clazz = clazz; 27 | } 28 | 29 | public SquareParam(String paramName, Class clazz){ 30 | this.param = true; 31 | this.paramName = paramName; 32 | this.clazz = clazz; 33 | } 34 | 35 | public boolean isParam() { 36 | return param; 37 | } 38 | 39 | public void setParam(boolean param) { 40 | this.param = param; 41 | } 42 | 43 | public Class getClazz() { 44 | return clazz; 45 | } 46 | 47 | public void setClazz(Class clazz) { 48 | this.clazz = clazz; 49 | } 50 | 51 | public String getParamName() { 52 | return paramName; 53 | } 54 | 55 | public void setParamName(String paramName) { 56 | this.paramName = paramName; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/SquareProxy.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | 6 | /** 7 | * square 代理类 使用jdk自带方式 8 | * @author ixx 9 | * @date 2019-07-27 10 | */ 11 | public class SquareProxy implements InvocationHandler { 12 | @Override 13 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/core/SquareProxyHandler.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.core; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.util.List; 6 | import java.util.regex.Pattern; 7 | 8 | /** 9 | * Square 代理类,使用JDK自带代理,只支持接口方式 10 | * @author ixx 11 | * @date 2019-08-03 12 | */ 13 | public class SquareProxyHandler implements InvocationHandler { 14 | 15 | private Object obj; 16 | 17 | public SquareProxyHandler(Object obj){ 18 | this.obj = obj; 19 | } 20 | 21 | @Override 22 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 23 | // 处理Aop 逻辑 24 | String packageClass = obj.getClass().getName(); 25 | // 包名 26 | String packageStr = packageClass.substring(0, packageClass.lastIndexOf(".")); 27 | // 类名 28 | String classStr = packageClass.substring(packageStr.length()+1); 29 | // 获取AspectObject 30 | AspectObject aspectObject = BeansMap.getAop(packageStr); 31 | if(aspectObject != null){ 32 | // 匹配类名,方法名,返回值类型 看是否需符合切面规则 33 | Method aspectMethod = verification(method, classStr, aspectObject); 34 | if(aspectMethod != null){ 35 | // 前置 36 | if(aspectObject.getType().equals("before")){ 37 | aspectMethod.invoke(aspectObject.getAspectBean(), null); 38 | Object o = method.invoke(obj, args); 39 | return o; 40 | } 41 | } 42 | } 43 | Object o = method.invoke(obj, args); 44 | return o; 45 | } 46 | 47 | /** 48 | * 验证是否符合切面规则 49 | * @param method 当前要执行的方法 50 | * @param aspectObject 切面对象 51 | * @return 52 | */ 53 | private Method verification(Method method, String className, AspectObject aspectObject){ 54 | // 判断类名 55 | if(!Pattern.matches(aspectObject.getClassName(), className)){ 56 | return null; 57 | } 58 | // 判断返回值类型 59 | if(!Pattern.matches(aspectObject.getRetClass(), method.getReturnType().getSimpleName())){ 60 | return null; 61 | } 62 | // 判断方法名 63 | List list = aspectObject.getMethodEx(); 64 | String methodName = method.getName()+"(..)"; 65 | for (String s : list) { 66 | if(Pattern.matches(s, methodName)){ 67 | Method aspectMethod = aspectObject.getMethodMap().get(s); 68 | return aspectObject.getMethodMap().get(aspectMethod.getName()); 69 | } 70 | } 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/exception/SquareException.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.exception; 2 | 3 | public class SquareException extends RuntimeException{ 4 | private String msg; 5 | public SquareException(String msg, Exception e){ 6 | super(e); 7 | this.msg = msg; 8 | } 9 | public SquareException(String msg){ 10 | this.msg = msg; 11 | } 12 | 13 | public String getMsg() { 14 | return msg; 15 | } 16 | 17 | public void setMsg(String msg) { 18 | this.msg = msg; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/ArgsToKVUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 参数转kv工具类 8 | * @author ixx 9 | * @date 2019-06-13 10 | */ 11 | public class ArgsToKVUtil { 12 | public static Map convert(String[] args){ 13 | Map map = new HashMap(args.length); 14 | for (String arg : args) { 15 | String[] tmp = arg.split("="); 16 | if(tmp.length == 2){ 17 | map.put(tmp[0], tmp[1]); 18 | } 19 | } 20 | return map; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/BeansInitUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | import com.jisuye.annotations.*; 4 | import com.jisuye.annotations.aop.Aspect; 5 | import com.jisuye.annotations.aop.Before; 6 | import com.jisuye.annotations.aop.Pointcut; 7 | import com.jisuye.annotations.web.*; 8 | import com.jisuye.core.*; 9 | import com.jisuye.exception.SquareException; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import javax.annotation.Resource; 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.lang.annotation.Annotation; 17 | import java.lang.reflect.*; 18 | import java.util.*; 19 | import java.util.jar.JarEntry; 20 | import java.util.jar.JarFile; 21 | 22 | /** 23 | * Bean初始化类 24 | * @author ixx 25 | * @date 2019-06-20 26 | */ 27 | public class BeansInitUtil { 28 | private static final Logger log = LoggerFactory.getLogger(BeansInitUtil.class); 29 | 30 | public static void init(Class clazz){ 31 | String path = clazz.getResource("").getPath(); 32 | log.info("===bean init path:{}", path); 33 | if(path.indexOf("!")<0) { 34 | File root = new File(path); 35 | // 处理控制反转(加载aop切面,controller) 36 | initFile(root); 37 | } else { 38 | // 处理jar包内的反射逻辑 39 | initJar(path); 40 | } 41 | // 处理aop类 42 | initAop(); 43 | // 处理config 44 | initConfig(); 45 | // 处理依赖注入 46 | initDI(); 47 | } 48 | 49 | private static void initConfig(){ 50 | // 循环所有Bean处理Config 51 | Set keySet = BeansMap.keySet(); 52 | String[] keys = new String[keySet.size()]; 53 | keySet.toArray(keys); 54 | List list = new ArrayList<>(); 55 | for (String key : keys) { 56 | BeanObject beanObject = BeansMap.get(key); 57 | if(list.contains(beanObject)){ 58 | continue; 59 | } 60 | list.add(beanObject); 61 | for (Annotation annotaion : beanObject.getAnnotaions()) { 62 | // 如果是配置则调用config()方法 63 | if(annotaion instanceof Config){ 64 | try { 65 | Method method = beanObject.getBeanClass().getMethod("config"); 66 | method.invoke(beanObject.getObject()); 67 | } catch (Exception e) { 68 | log.error("execute config method error!!", e); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | private static void initAop(){ 76 | // 循环所有Bean处理Aop 77 | for(Map.Entry entry : BeansMap.entrySet()) { 78 | BeanObject beanObject = (BeanObject) entry.getValue(); 79 | // 如果已经处理过,则跳过 80 | if (beanObject.getObject() != null) { 81 | continue; 82 | } 83 | beanObject.setObject(getInstance(beanObject.getBeanClass(), beanObject.getSrcObj())); 84 | } 85 | } 86 | 87 | private static void loadAop(Class clzz){ 88 | try { 89 | Annotation[] annotations = clzz.getAnnotations(); 90 | if (annotations.length > 0 && filterAspectAnnotation(annotations)) { 91 | Object obj = clzz.newInstance(); 92 | Method[] methods = clzz.getMethods(); 93 | for (Method method : methods) { 94 | Annotation[] methodAnnotations = method.getAnnotations(); 95 | if(methodAnnotations != null && methodAnnotations.length > 0){ 96 | // 切点 97 | if(methodAnnotations[0] instanceof Pointcut){ 98 | AspectObject aspectObject = BeansMap.getAop(method.getName()); 99 | if(aspectObject == null){ 100 | aspectObject = new AspectObject(); 101 | aspectObject.setAspectBean(obj); 102 | } 103 | String packageStr = setPointPackageAndMethod(((Pointcut)methodAnnotations[0]).value(), aspectObject, method); 104 | BeansMap.putAop(packageStr, aspectObject); 105 | BeansMap.putAop(method.getName(), aspectObject); 106 | } else if(methodAnnotations[0] instanceof Before){ 107 | // Before 处理 108 | String val = ((Before)methodAnnotations[0]).value(); 109 | val = val.substring(0, val.indexOf("(")); 110 | AspectObject aspectObject1 = BeansMap.getAop(val); 111 | if(aspectObject1 == null){ 112 | aspectObject1 = new AspectObject(); 113 | aspectObject1.setAspectBean(obj); 114 | } 115 | aspectObject1.setType("before"); 116 | aspectObject1.setMethodMap(val, method); 117 | BeansMap.putAop(val, aspectObject1); 118 | } 119 | } 120 | } 121 | } 122 | } catch (Exception e){ 123 | log.error("load aop error!!", e); 124 | } 125 | } 126 | 127 | private static String setPointPackageAndMethod(String ex, AspectObject aspectObject, Method method){ 128 | if(ex == null || ex.equals("")){ 129 | throw new SquareException("Aop Acpect config is error, pointCut must value!"); 130 | } 131 | ex = ex.replace("excution(", ""); 132 | ex = ex.substring(0, ex.length()-1); 133 | String[] exs = ex.split(" "); 134 | if(exs.length != 3){ 135 | throw new SquareException("Aop Acpect config is error!"); 136 | } else { 137 | String packages = exs[2]; 138 | String classStr = packages.replaceAll("\\.[a-zA-Z0-9\\*]*\\(.*\\)", ""); 139 | String methods = packages.substring(classStr.length()); 140 | methods = methods.substring(1).replace("*", ".*"); 141 | String packageStr = classStr.replaceAll("\\.[a-zA-Z0-9\\*]*$", ""); 142 | classStr = classStr.substring(packageStr.length()); 143 | 144 | // 设置 包名 返回类型匹配 类名匹配 方法匹配 145 | aspectObject.setPackagePath(packageStr); 146 | aspectObject.setMethodEx(methods); 147 | aspectObject.setMethodMap(methods, method); 148 | aspectObject.setRetClass(exs[1].replace("*", ".*")); 149 | aspectObject.setClassName(classStr.substring(1).replace("*", ".*")); 150 | return packageStr; 151 | } 152 | } 153 | private static void initJar(String jarPath){ 154 | try { 155 | log.info("jarPath :{}", jarPath); 156 | String packageStr = jarPath.substring(jarPath.indexOf("!")+2).replaceAll("/", "."); 157 | log.info("packageStr :{}", packageStr); 158 | jarPath = jarPath.substring(0, jarPath.indexOf("!")).replace("file:", ""); 159 | log.info("jar file path:{}", jarPath); 160 | JarFile jarFile = new JarFile(new File(jarPath)); 161 | // 获取jar文件条目 162 | Enumeration enumFiles = jarFile.entries(); 163 | JarEntry entry; 164 | while(enumFiles.hasMoreElements()){ 165 | entry = enumFiles.nextElement(); 166 | String className = entry.getName().replaceAll("/", "."); 167 | // 只处理自己包下的class文件 168 | if(className.startsWith(packageStr) && className.indexOf(".class")>=0){ 169 | className = className.substring(0,className.length()-6).replace("/", "."); 170 | log.info("class:{}", className); 171 | loadClass(className); 172 | } 173 | } 174 | } catch (IOException e) { 175 | log.error("load jar file error!", e); 176 | } 177 | } 178 | private static void initFile(File file){ 179 | File[] fs = file.listFiles(); 180 | for (File f : fs) { 181 | if(f.isDirectory()){ 182 | // 递归目录 183 | initFile(f); 184 | } else { 185 | // 处理class 186 | if(f.getPath().endsWith("class")) { 187 | loadClass(getClassPath(f.getPath())); 188 | } 189 | } 190 | } 191 | } 192 | private static String getClassPath(String filePath){ 193 | String path = filePath; 194 | path = path.substring(path.indexOf("classes")+8).replace(".class", ""); 195 | path = path.replace(File.separatorChar+"", "."); 196 | return path; 197 | } 198 | private static void loadClass(String className){ 199 | if(className == null){ 200 | return; 201 | } 202 | try { 203 | log.info("load bean class:{}", className); 204 | Class clzz = Class.forName(className); 205 | Annotation[] annotations = clzz.getAnnotations(); 206 | // 保存所有类 207 | BeansMap.addClass(clzz); 208 | if(annotations.length >0 && filterClassAnnotation(annotations)){ 209 | BeanObject beanObject = new BeanObject(clzz, clzz.newInstance()); 210 | beanObject.setAnnotaions(annotations); 211 | // 按接口设置bean 212 | for (Class aClass : beanObject.getInterfacs()) { 213 | BeanObject tmp = BeansMap.get(aClass.getName()); 214 | if(tmp != null){ 215 | beanObject.setNext(tmp); 216 | } 217 | BeansMap.put(aClass.getName(), beanObject); 218 | } 219 | // 按类设置bean 220 | BeansMap.put(beanObject.getClassName(), beanObject); 221 | String simpleName = StringUtil.firstToLowerCase(beanObject.getSimpleName()); 222 | if(BeansMap.get(simpleName) != null){ 223 | throw new SquareException("There are duplicate beans ,beanName:"+simpleName); 224 | } 225 | BeansMap.put(simpleName, beanObject); 226 | // 按注解输入value设置bean 227 | for (Annotation annotation : annotations) { 228 | String tmp_name = ""; 229 | if(annotation instanceof Service){ 230 | tmp_name = ((Service)annotation).value(); 231 | } else if(annotation instanceof Component) { 232 | tmp_name = ((Component)annotation).value(); 233 | } else if(annotation instanceof Controller) { 234 | initController(clzz, ((Controller)annotation).value()); 235 | } else if(annotation instanceof Aspect){ 236 | loadAop(clzz); 237 | } 238 | if(tmp_name != null && !tmp_name.equals("")) { 239 | if(BeansMap.get(tmp_name) != null){ 240 | throw new SquareException("There are duplicate beans ,beanName:"+tmp_name); 241 | } 242 | BeansMap.put(tmp_name, beanObject); 243 | } 244 | } 245 | } 246 | } catch (SquareException e) { 247 | throw e; 248 | } catch (Exception e){ 249 | log.error("Bean init error...", e); 250 | throw new SquareException("Bean init error...."); 251 | } 252 | } 253 | 254 | /** 255 | * 获取反射实例,判断是否符合切面,是否需要做代理处理 256 | * @param clzz 257 | * @return 258 | */ 259 | private static Object getInstance(Class clzz, Object obj){ 260 | String packageStr = clzz.getPackage().getName(); 261 | // 如果不符合切面规则,则直接反射生成 不使用代理 262 | if(BeansMap.getAop(packageStr) == null){ 263 | return obj; 264 | } 265 | // 使用JDK动态代理 266 | Class[] interfaces = clzz.getInterfaces(); 267 | if(interfaces == null || interfaces.length == 0){ 268 | log.warn("{} Aop proxy class must implements interface!!", clzz.getName()); 269 | return obj; 270 | } 271 | SquareProxyHandler squareProxyHandler = new SquareProxyHandler(obj); 272 | Object newProxyInstance = Proxy.newProxyInstance(interfaces[0].getClassLoader(), new Class[]{interfaces[0]}, squareProxyHandler); 273 | return newProxyInstance; 274 | } 275 | /** 276 | * 初始化Controller 277 | * @param clzz 278 | * @param classPath 279 | */ 280 | private static void initController(Class clzz, String classPath){ 281 | try { 282 | classPath = classPath.equals("/") ? "" : classPath; 283 | Method[] methods = clzz.getMethods(); 284 | log.info("classPath:{}, methods.length:{}", classPath, methods.length); 285 | // 处理每一个方法 286 | for (Method method : methods) { 287 | String[] methodPath = getMethodAnnotationValue(method.getDeclaredAnnotations()); 288 | // 说明是@GetMapping @PostMapping @PutMapping @DeleteMapping 中的一个 289 | if (methodPath != null) { 290 | // 获取参数及注解 291 | Parameter[] parameters = method.getParameters(); 292 | SquareParam[] params = new SquareParam[parameters.length]; 293 | int i = 0; 294 | for (Parameter parameter : parameters) { 295 | params[i++] = getParam(parameter.getAnnotations(), parameter.getType()); 296 | } 297 | ControllerObject co = new ControllerObject(params, methodPath[0], method, StringUtil.firstToLowerCase(clzz.getSimpleName())); 298 | String key = methodPath[0] +":"+ classPath+methodPath[1]; 299 | log.info("add controller key:{}", key); 300 | BeansMap.putController(key, co); 301 | } 302 | } 303 | } catch (Exception e){ 304 | log.error("init controller error.", e); 305 | throw new SquareException("init controller error", e); 306 | } 307 | } 308 | /** 309 | * 处理关系依赖 310 | */ 311 | private static void initDI(){ 312 | List list = new ArrayList<>(); 313 | BeanObject sqlBean = null; 314 | // 循环所有Bean处理依赖 315 | for(Map.Entry entry : BeansMap.entrySet()){ 316 | BeanObject beanObject = (BeanObject)entry.getValue(); 317 | // 如果已经处理过,则跳过 318 | if(list.contains(beanObject)){ 319 | continue; 320 | } 321 | // 添加到已处理列表 322 | list.add(beanObject); 323 | // 先判断是否有Resource注解 324 | for (Field field : beanObject.getFields()) { 325 | if(filterFieldAnnotation(field.getAnnotations())){ 326 | String name = getResourceName(field.getAnnotations()); 327 | BeanObject bean; 328 | // 有指定bean名字按指定去取 329 | if(name != null && !name.equals("")){ 330 | bean = BeansMap.get(StringUtil.firstToLowerCase(name)); 331 | } else { 332 | // 没有指定按接口(如果有的话)或类型去取 333 | Class fieldClass = field.getType(); 334 | bean = BeansMap.get(fieldClass.getName()); 335 | // 如果有next说明是有多个实现的接口,则要判断名字 336 | if(bean != null && bean.getNext() != null){ 337 | String fieldName = field.getName(); 338 | while(bean != null){ 339 | if(StringUtil.firstToLowerCase(bean.getSimpleName()).equals(fieldName)){ 340 | break; 341 | } 342 | bean = bean.getNext(); 343 | } 344 | if(bean == null){ 345 | log.error("无法确定的Bean依赖,field:{}, 存在多个依赖!", beanObject.getClassName()+"."+fieldName); 346 | throw new SquareException("无法确定的Bean依赖,存在多个依赖!"); 347 | } 348 | } else if(fieldClass.getName().equals(JdbcTemplate.class.getName())){ 349 | // 如果是JdbcTemplate依赖,则初始化DbUtil并初始化及注入JdbcTemplate 350 | if(sqlBean == null) { 351 | DbUtil.init(); 352 | JdbcTemplate jdbcTemplate = new JdbcTemplate(); 353 | sqlBean = new BeanObject(JdbcTemplate.class, jdbcTemplate); 354 | sqlBean.setObject(jdbcTemplate); 355 | } 356 | bean = sqlBean; 357 | } 358 | } 359 | if(bean == null){ 360 | // 找不到依赖bean异常 361 | log.error("无法找到Bean依赖,field:{}", beanObject.getClassName()+"."+field.getName()); 362 | throw new SquareException("无法找到Bean依赖"); 363 | } 364 | // 注入依赖 365 | try { 366 | field.setAccessible(true); 367 | field.set(beanObject.getSrcObj(), bean.getObject()); 368 | } catch (IllegalAccessException e) { 369 | log.error("Bean注入失败,field:{}", beanObject.getClassName()+"."+field.getName(), e); 370 | throw new SquareException("Bean注入失败"); 371 | } 372 | } 373 | } 374 | } 375 | BeansMap.put(JdbcTemplate.class.getName(), sqlBean); 376 | } 377 | /** * 判断类上加的注解是不是要初始化为bean */ 378 | private static boolean filterClassAnnotation(Annotation[] annotations){ 379 | boolean b = false; 380 | for (Annotation annotation : annotations) { 381 | b = annotation instanceof Service || annotation instanceof Component; 382 | b = b || annotation instanceof Controller; 383 | b = b || annotation instanceof Config; 384 | if(b){ 385 | break; 386 | } 387 | } 388 | return b; 389 | } 390 | /** * 判断字段上加的注解是否需要做注入 */ 391 | private static boolean filterFieldAnnotation(Annotation[] annotations){ 392 | boolean b = false; 393 | for (Annotation annotation : annotations) { 394 | b = annotation instanceof Resource; 395 | if(b){ 396 | break; 397 | } 398 | } 399 | return b; 400 | } 401 | /** * 判断类上加的注解是不是Aspect */ 402 | private static boolean filterAspectAnnotation(Annotation[] annotations){ 403 | boolean b = false; 404 | for (Annotation annotation : annotations) { 405 | b = annotation instanceof Aspect; 406 | if(b){ 407 | break; 408 | } 409 | } 410 | return b; 411 | } 412 | /** * 获取方法上的注解value */ 413 | private static String[] getMethodAnnotationValue(Annotation[] annotations){ 414 | String[] methodPath = null; 415 | for (Annotation annotation : annotations) { 416 | if(annotation instanceof DeleteMapping){ 417 | methodPath = new String[]{"delete", ((DeleteMapping) annotation).value()}; 418 | } else if(annotation instanceof GetMapping){ 419 | methodPath = new String[]{"get", ((GetMapping) annotation).value()}; 420 | } else if(annotation instanceof PostMapping){ 421 | methodPath = new String[]{"post", ((PostMapping) annotation).value()}; 422 | } else if(annotation instanceof PutMapping){ 423 | methodPath = new String[]{"put", ((PutMapping) annotation).value()}; 424 | } else { 425 | continue; 426 | } 427 | break; 428 | } 429 | return methodPath; 430 | } 431 | /** * 获取参数@RequestParam注解的value 如果没有,则取参数名*/ 432 | private static SquareParam getParam(Annotation[] annotations, Class clazz){ 433 | SquareParam param = null; 434 | for (Annotation annotation : annotations) { 435 | if(annotation instanceof RequestParam){ 436 | param = new SquareParam(((RequestParam) annotation).value(), clazz); 437 | } else if(annotation instanceof RequestBody){ 438 | param = new SquareParam(clazz); 439 | } 440 | } 441 | return param; 442 | } 443 | /** 获取注入注解上指定的Bean名字 */ 444 | private static String getResourceName(Annotation[] annotations){ 445 | String name = null; 446 | for (Annotation annotation : annotations) { 447 | name = ((Resource)annotation).name(); 448 | } 449 | return name; 450 | } 451 | } -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/ClassesPathUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | import com.jisuye.core.SquareApplication; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.*; 8 | 9 | /** 10 | * 处理项目路径问题 11 | * @author ixx 12 | * @date 2019-06-15 13 | */ 14 | public class ClassesPathUtil { 15 | private static final Logger log = LoggerFactory.getLogger(ClassesPathUtil.class); 16 | /** 17 | * 项目目录(.../classes) 18 | */ 19 | private String projectPath; 20 | /** 21 | * 静态资源目录(.../classes/public) 22 | */ 23 | private String publicPath; 24 | 25 | public ClassesPathUtil(Class clzz){ 26 | String basePath = clzz.getResource("").getPath(); 27 | log.info("basePath+++++{}", basePath); 28 | // ..../classes 29 | if(basePath.indexOf("classes")>0) { 30 | projectPath = basePath.substring(0, basePath.indexOf("classes")+7); 31 | publicPath = basePath.substring(0, basePath.indexOf("target")); 32 | publicPath = publicPath+"target/classes/public"; 33 | } else { 34 | projectPath = basePath.substring(0, basePath.indexOf("!")+1); 35 | publicPath = SquareApplication.TEMP_TOMCAT_DIR; 36 | } 37 | } 38 | 39 | private String setPublic(String basePath, String path){ 40 | File publicFile = new File(basePath+path); 41 | if(!publicFile.exists()){ 42 | publicFile.mkdirs(); 43 | } 44 | return basePath+path; 45 | } 46 | 47 | public String getProjectPath() { 48 | return projectPath; 49 | } 50 | 51 | public String getPublicPath() { 52 | return publicPath; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/DbUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | import com.jisuye.core.ApplicationContext; 4 | import com.jisuye.exception.SquareException; 5 | import com.zaxxer.hikari.HikariDataSource; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import javax.sql.DataSource; 10 | import java.lang.reflect.Method; 11 | import java.sql.*; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | /** 16 | * 数据库操作工具 17 | * @author ixx 18 | * @date 2019-07-01 19 | */ 20 | public class DbUtil { 21 | private static final Logger log = LoggerFactory.getLogger(DbUtil.class); 22 | private static Connection connection; 23 | private static DataSource dataSource; 24 | 25 | /** 初始化方法*/ 26 | public static void init(){ 27 | try { 28 | if(connection != null && dataSource != null){ 29 | return; 30 | } 31 | String url = ApplicationContext.getConf("square.datasource.url").toString(); 32 | String username = ApplicationContext.getConf("square.datasource.username").toString(); 33 | String password = ApplicationContext.getConf("square.datasource.password").toString(); 34 | 35 | HikariDataSource ds = new HikariDataSource(); 36 | ds.setJdbcUrl(url); 37 | ds.setUsername(username); 38 | ds.setPassword(password); 39 | // HikariCP提供的优化设置 40 | ds.addDataSourceProperty("cachePrepStmts", "true"); 41 | ds.addDataSourceProperty("prepStmtCacheSize", "250"); 42 | ds.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); 43 | connection = ds.getConnection(); 44 | dataSource = ds; 45 | } catch (Exception e) { 46 | log.error("mysql connection init error..", e); 47 | throw new SquareException("mysql connection init error...."); 48 | } 49 | } 50 | 51 | /** install/update 带参数占位符方法*/ 52 | public static boolean update(String sql, Object... params){ 53 | PreparedStatement statement; 54 | try { 55 | statement = connection.prepareStatement(sql); 56 | if(params != null) { 57 | for (int i = 1; i <= params.length; i++) { 58 | statement.setObject(i, params[i - 1]); 59 | } 60 | } 61 | return statement.execute(); 62 | } catch (Exception e) { 63 | log.error("install/update exception.", e); 64 | } 65 | return false; 66 | } 67 | /** install/update 无参数占位符方法*/ 68 | public static boolean update(String sql){ 69 | return update(sql, null); 70 | } 71 | 72 | /** 73 | * 通用查询方法 74 | * @param sql sql语句 75 | * @param clazz 返回列表类型 76 | * @param params 参数列表 77 | * @param 返回列表类型 78 | * @return 79 | */ 80 | public static List select(String sql,Class clazz, Object... params){ 81 | List list = new ArrayList<>(); 82 | PreparedStatement statement; 83 | try { 84 | statement = connection.prepareStatement(sql); 85 | for(int i=1; i<= params.length; i++){ 86 | statement.setObject(i, params[i-1]); 87 | } 88 | ResultSet rs = statement.executeQuery(); 89 | while(rs.next()){ 90 | T t = clazz.newInstance(); 91 | Method[] methods = clazz.getMethods(); 92 | for (Method method : methods) { 93 | if(method.getName().startsWith("set")){ 94 | String field = StringUtil.firstToLowerCase(method.getName().substring(3)); 95 | String paramClass = method.getParameterTypes()[0].getSimpleName(); 96 | switch (paramClass){ 97 | case "Integer": 98 | method.invoke(t, rs.getInt(field)); break; 99 | case "Float": 100 | method.invoke(t, rs.getFloat(field)); break; 101 | case "Double": 102 | method.invoke(t, rs.getDouble(field)); break; 103 | case "Short": 104 | method.invoke(t, rs.getShort(field)); break; 105 | case "Byte": 106 | method.invoke(t, rs.getByte(field)); break; 107 | case "Long": 108 | method.invoke(t, rs.getLong(field)); break; 109 | case "Boolean": 110 | method.invoke(t, rs.getBoolean(field)); break; 111 | default: 112 | method.invoke(t, rs.getObject(field)); 113 | } 114 | } 115 | } 116 | list.add(t); 117 | } 118 | } catch (Exception e) { 119 | log.error("select exception.", e); 120 | } 121 | return list.size()>0 ? list : null; 122 | } 123 | public static DataSource getDataSource(){ 124 | if (dataSource == null) { 125 | init(); 126 | } 127 | return dataSource; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/LoadApplicationYmlUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.yaml.snakeyaml.Yaml; 6 | 7 | import java.io.FileInputStream; 8 | import java.io.FileNotFoundException; 9 | import java.io.InputStream; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | /** 14 | * 加载application.yml文件 15 | * @author ixx 16 | * @date 2019-06-15 17 | */ 18 | public class LoadApplicationYmlUtil { 19 | private static final Logger log = LoggerFactory.getLogger(LoadApplicationYmlUtil.class); 20 | public static Map load(String projectPath){ 21 | Map retMap = new HashMap<>(); 22 | try { 23 | InputStream is; 24 | if(projectPath != null && projectPath.indexOf("!") > 0){ 25 | is = ClassLoader.getSystemResourceAsStream("application.yml"); 26 | } else { 27 | projectPath += "/application.yml"; 28 | log.info("load yml file path:{}", projectPath); 29 | is = new FileInputStream(projectPath); 30 | } 31 | Yaml yaml = new Yaml(); 32 | Map map = (Map)yaml.load(is); 33 | if(map != null && map.size()>0){ 34 | for(Map.Entry e : map.entrySet()) { 35 | convert("", retMap, e); 36 | } 37 | } 38 | } catch (FileNotFoundException e) { 39 | log.error("load application.yml file error.", e); 40 | } 41 | return retMap; 42 | } 43 | 44 | /** 45 | * 递归组装配置参数 46 | * @param key 父级key路径(类似server.servlet) 47 | * @param retMap 要返回的map 48 | * @param entry 49 | */ 50 | private static void convert(String key, Map retMap, Map.Entry entry){ 51 | if(entry.getValue() instanceof Map){ 52 | key = key+entry.getKey()+"."; 53 | for(Map.Entry e : ((Map)entry.getValue()).entrySet()){ 54 | convert(key, retMap, e); 55 | } 56 | } else { 57 | key = key+entry.getKey(); 58 | retMap.put(key, entry.getValue()); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/jisuye/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.util; 2 | 3 | /** 4 | * String 处理工具类 5 | * @author ixx 6 | * @date 2019-08-11 7 | */ 8 | public class StringUtil { 9 | /** 首字段转大写*/ 10 | public static String firstToUpperCase(String str){ 11 | if(str == null || str.equals("")){ 12 | return str; 13 | } 14 | char f = str.charAt(0); 15 | str = str.substring(1); 16 | if(f>'Z'){ 17 | f = (char)(f-32); 18 | } 19 | return f+str; 20 | } 21 | 22 | /** 首字段转大写*/ 23 | public static String firstToLowerCase(String str){ 24 | if(str == null || str.equals("")){ 25 | return str; 26 | } 27 | char f = str.charAt(0); 28 | str = str.substring(1); 29 | if(f<'a'){ 30 | f = (char)(f+32); 31 | } 32 | return f+str; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/default-banner.txt: -------------------------------------------------------------------------------- 1 | __________ ____ 2 | | ____ |/ ___| __ _ _ _ __ _ _ __ ___ 3 | | | | |\___ \ / _` | | | |/ _` | '__/ _ \ 4 | | |____| | ___) | (_| | |_| | (_| | | | __/ 5 | |__________||____/ \__, |\__,_|\__,_|_| \___| 6 | ======================|_|==================== 7 | :: Square :: (v0.1) -------------------------------------------------------------------------------- /src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

There was an unexpected error (type=Not Found, status=404).
No message available
5 | 6 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/T.java: -------------------------------------------------------------------------------- 1 | package com.jisuye; 2 | 3 | import com.jisuye.core.SquareApplication; 4 | 5 | public class T { 6 | public static void main(String args[]){ 7 | SquareApplication.run(T.class, args); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/Abc.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | public interface Abc { 4 | int test(String name); 5 | int abc(String name); 6 | int abc2(String name); 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/AbcEntity.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | public class AbcEntity { 4 | private Integer id; 5 | private String name; 6 | 7 | public Integer getId() { 8 | return id; 9 | } 10 | 11 | public void setId(Integer id) { 12 | this.id = id; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/ClassDi.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | import com.jisuye.annotations.Service; 4 | 5 | @Service 6 | public class ClassDi { 7 | 8 | public String exe(String name){ 9 | return "Class DI "+name; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/Def.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | public interface Def { 4 | String exe(String name); 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/ResponseVo.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | public class ResponseVo { 4 | private int resId; 5 | private String resName; 6 | private int resAge; 7 | 8 | public String getResName() { 9 | return resName; 10 | } 11 | 12 | public void setResName(String resName) { 13 | this.resName = resName; 14 | } 15 | 16 | public int getResAge() { 17 | return resAge; 18 | } 19 | 20 | public void setResAge(int resAge) { 21 | this.resAge = resAge; 22 | } 23 | 24 | public int getResId() { 25 | return resId; 26 | } 27 | 28 | public void setResId(int resId) { 29 | this.resId = resId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/TestController.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | import com.jisuye.annotations.web.*; 4 | import com.jisuye.core.JdbcTemplate; 5 | 6 | import javax.annotation.Resource; 7 | import java.util.List; 8 | 9 | @Controller("/test") 10 | public class TestController { 11 | 12 | @Resource 13 | private Abc abc; 14 | 15 | @Resource 16 | private JdbcTemplate jdbcTemplate; 17 | 18 | @GetMapping("/hello") 19 | public List test(@RequestParam("name") String name, @RequestParam("a") String age){ 20 | List list = jdbcTemplate.select("select * from abc where name=?", AbcEntity.class, name); 21 | // abc.test("ixx"); 22 | return list; 23 | } 24 | 25 | @GetMapping("/abc") 26 | public String abc(){ 27 | abc.abc("ixx"); 28 | return "success"; 29 | } 30 | 31 | @GetMapping("/abc2") 32 | public String abc2(){ 33 | abc.abc2("ixx"); 34 | return "success"; 35 | } 36 | 37 | @DeleteMapping 38 | public String testDel(@RequestParam("id") int id){ 39 | int i = jdbcTemplate.delete("delete from abc where id=?", id); 40 | return "delete id : "+id+" is success"; 41 | } 42 | 43 | @PostMapping("/post") 44 | public ResponseVo testPost(@RequestParam("id") int id, @RequestBody TestVo vo){ 45 | ResponseVo responseVo = new ResponseVo(); 46 | responseVo.setResId(id*10); 47 | responseVo.setResAge(vo.getAge()*2); 48 | responseVo.setResName(vo.getName()); 49 | return responseVo; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/TestVo.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service; 2 | 3 | public class TestVo { 4 | private String name; 5 | private int age; 6 | 7 | public int getAge() { 8 | return age; 9 | } 10 | 11 | public void setAge(int age) { 12 | this.age = age; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/aop/WebLogAspect.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service.aop; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.jisuye.annotations.Component; 5 | import com.jisuye.annotations.aop.Aspect; 6 | import com.jisuye.annotations.aop.Before; 7 | import com.jisuye.annotations.aop.Pointcut; 8 | import com.jisuye.core.RequestContextHolder; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | /** 15 | * 定义切面类,测试切面 16 | */ 17 | @Aspect 18 | @Component 19 | public class WebLogAspect { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(WebLogAspect.class); 22 | 23 | /** 24 | * 测试com.jisuye.service.impl包下的所以类的abc开头方法(所有参数)添加AOP 25 | */ 26 | @Pointcut("excution(public * com.jisuye.service.impl.*.abc*(..))") 27 | public void log(){} 28 | 29 | @Before("log()") 30 | public void doBefore(){ 31 | HttpServletRequest request = RequestContextHolder.getRequest(); 32 | if(request != null) { 33 | log.info("AOP exe... url:{}, params:{}", request.getRequestURI(), JSON.toJSONString(request.getParameterMap())); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/impl/AbcImpl.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service.impl; 2 | 3 | import com.jisuye.annotations.Service; 4 | import com.jisuye.core.JdbcTemplate; 5 | import com.jisuye.service.Abc; 6 | import com.jisuye.service.ClassDi; 7 | import com.jisuye.service.Def; 8 | 9 | import javax.annotation.Resource; 10 | 11 | @Service 12 | public class AbcImpl implements Abc { 13 | // 名字对不上会报异常 14 | @Resource 15 | private Def defImpl; 16 | // 名字对不上可以使用注解中指定bean名字的方式 17 | @Resource(name = "def2Impl") 18 | private Def defByName; 19 | 20 | // 添加jdbcTemplate依赖 21 | @Resource 22 | private JdbcTemplate jdbcTemplate; 23 | 24 | // 注入Class类实例 25 | @Resource 26 | private ClassDi classDi; 27 | 28 | @Override 29 | public int test(String name) { 30 | jdbcTemplate.insert("insert into abc(`name`) values('ixx')"); 31 | System.out.println(defImpl.exe(name)); 32 | System.out.println(defByName.exe(name)); 33 | System.out.println(classDi.exe(name)); 34 | return 0; 35 | } 36 | 37 | @Override 38 | public int abc(String name) { 39 | return 0; 40 | } 41 | 42 | @Override 43 | public int abc2(String name) { 44 | return 0; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/impl/Def2Impl.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service.impl; 2 | 3 | import com.jisuye.annotations.Service; 4 | import com.jisuye.service.Def; 5 | 6 | @Service 7 | public class Def2Impl implements Def { 8 | @Override 9 | public String exe(String name) { 10 | return "def2 "+name; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/jisuye/service/impl/DefImpl.java: -------------------------------------------------------------------------------- 1 | package com.jisuye.service.impl; 2 | 3 | import com.jisuye.annotations.Service; 4 | import com.jisuye.core.JdbcTemplate; 5 | import com.jisuye.service.AbcEntity; 6 | import com.jisuye.service.Def; 7 | 8 | import javax.annotation.Resource; 9 | import java.util.List; 10 | 11 | @Service 12 | public class DefImpl implements Def { 13 | @Resource 14 | private JdbcTemplate jdbcTemplate; 15 | 16 | @Override 17 | public String exe(String name) { 18 | List list = jdbcTemplate.select("select * from abc where name=?", AbcEntity.class, name); 19 | System.out.println(list.size()); 20 | System.out.println(list.get(0).getId()); 21 | System.out.println(list.get(0).getName()); 22 | return "Interface DI... "+name; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8888 3 | servlet: 4 | context-path: /abc 5 | square: 6 | datasource: 7 | url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true 8 | username: admin 9 | password: 123456 --------------------------------------------------------------------------------