├── .gitignore
├── pom.xml
├── readme.md
└── src
└── main
├── java
└── com
│ └── bcc
│ ├── MainLoader.java
│ ├── annotation
│ ├── Action.java
│ ├── Aspect.java
│ ├── Controller.java
│ ├── Inject.java
│ ├── Service.java
│ └── Transaction.java
│ ├── helper
│ ├── AopHelper.java
│ ├── BeanHelper.java
│ ├── ClassHelper.java
│ ├── ConfigHelper.java
│ ├── ControllerHelper.java
│ ├── DatabaseHelper.java
│ └── IocHelper.java
│ ├── proxy
│ ├── AbstractAspect.java
│ ├── Proxy.java
│ ├── ProxyChain.java
│ ├── ProxyManager.java
│ └── TransactionAspect.java
│ ├── test
│ ├── Test01.java
│ ├── TestController.java
│ └── TestService.java
│ ├── util
│ ├── CastUtil.java
│ ├── ClassUtil.java
│ ├── CodecUtil.java
│ ├── ConfigConstant.java
│ ├── JsonUtil.java
│ ├── MethodEunm.java
│ ├── PropsUtil.java
│ ├── ReflectionUtil.java
│ ├── StreamUtil.java
│ └── StringUtil.java
│ └── web
│ ├── DispatchServlet.java
│ ├── Handler.java
│ ├── ModelAndView.java
│ ├── Request.java
│ ├── RequestParam.java
│ └── ServerResponse.java
└── resources
├── log4j.properties
└── smart.properties
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 |
20 | ### NetBeans ###
21 | nbproject/private/
22 | build/
23 | nbbuild/
24 | dist/
25 | nbdist/
26 | .nb-gradle/
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.bcc
8 | mySpring
9 | 1.0.0
10 |
11 |
12 | UTF-8
13 |
14 |
15 |
16 |
17 |
27 |
28 |
29 | org.apache.maven.plugins
30 | maven-compiler-plugin
31 |
32 |
33 | 1.8
34 | 1.8
35 | 1.8
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | javax.servlet
47 | javax.servlet-api
48 | 3.1.0
49 | provided
50 |
51 |
52 |
53 | javax.servlet.jsp
54 | jsp-api
55 | 2.2
56 | provided
57 |
58 |
59 |
60 | javax.servlet
61 | jstl
62 | 1.2
63 | runtime
64 |
65 |
66 |
67 |
68 | org.slf4j
69 | slf4j-log4j12
70 | 1.7.7
71 |
72 |
73 |
74 |
75 | mysql
76 | mysql-connector-java
77 | 5.1.33
78 | runtime
79 |
80 |
81 |
82 |
83 | org.apache.commons
84 | commons-lang3
85 | 3.3.2
86 |
87 |
88 |
89 | org.apache.commons
90 | commons-collections4
91 | 4.0
92 |
93 |
94 |
95 | com.fasterxml.jackson.core
96 | jackson-databind
97 | 2.9.3
98 |
99 |
100 |
101 |
102 | commons-dbutils
103 | commons-dbutils
104 | 1.6
105 |
106 |
107 |
108 | org.apache.commons
109 | commons-dbcp2
110 | 2.0.1
111 |
112 |
113 |
114 | junit
115 | junit
116 | 4.12
117 |
118 |
119 |
120 |
121 | cglib
122 | cglib
123 | 3.2.6
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # 开发 javaWeb 框架 #
2 | 自己手写一个 Javaweb 框架,仿 spring 和 springMvc 实现相同功能
3 | ## 基础功能 ##
4 | - 快速搭建框架
5 | - 加载读取配置文件
6 | - 加载指定注解的类
7 | - 实现 IOC
8 | - 实现 Aop : 仿照 spring + aspect 的 aop , 自定义注解,自己利用代理实现 aop 功能
9 | - 实现数据库事务
10 | ## 使用方式 ##
11 |
12 | 1. 需要在你的项目中加入框架需要的配置文件 smart.properties
13 | 1. Service 表示业务层注解,Controller 表示 web层注解,Inject bean 注入注解,Transaction 事务注解
14 | 1. 下载项目安装到本地 mvn install 。 在你自己开发的项目 pom 文件导入此项目 `
15 | com.bcc
16 | myspring
17 | 1.0.0
18 | `
19 | 1. Action 注解的使用,加在 controller 的方法上 @Action("请求方法:/请求路径") eg. @Action("get:/getById")
20 | 1. Cotroller 里面方法的写法 . 如果想返回页面,返回值为 ModelAndView 对象 ; 只想返回数据,则返回 ServerResponse 对象 . 想要传入参数 , 在方法参数里面放 RequestParam 对象即可 , 目前只支持将参数映射到 map 中 ,以 key-value 形式使用 , 不支持对象
21 | 1. 自定义 AOP 的使用 ,切面类继承 AbstractAspect 类,重写想要拦截的方法。在切面类上加上 @Aspect(Controller.class) , 想要拦截那个类就在那个类上加上 @Controller 注解,或者其它各种自定义注解都可以
22 | 1. 事务的使用 : 目前只支持 添加了 @Service 注解的类的事务,在 service 类的某个方法上加 @Transaction 注解即可实现事务
23 | ## 优化提高 ##
24 | 1.
25 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/MainLoader.java:
--------------------------------------------------------------------------------
1 | package com.bcc;
2 |
3 | import com.bcc.helper.AopHelper;
4 | import com.bcc.helper.BeanHelper;
5 | import com.bcc.helper.ClassHelper;
6 | import com.bcc.helper.ConfigHelper;
7 | import com.bcc.helper.ControllerHelper;
8 | import com.bcc.helper.IocHelper;
9 | import com.bcc.util.ClassUtil;
10 |
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | /**
15 | * 初始化所有类
16 | * 注意加载的顺序
17 | */
18 | public class MainLoader {
19 |
20 | public static void init() {
21 | List> classes = Arrays.asList(ConfigHelper.class, ClassHelper.class, BeanHelper.class, AopHelper.class, IocHelper.class, ControllerHelper.class);
22 | for (Class> aClass : classes) {
23 | ClassUtil.loadClass(aClass.getName());
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Action.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
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 | * action 方法注解
10 | */
11 |
12 | @Target(ElementType.METHOD)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface Action {
15 |
16 | /**
17 | * 请求方法和路径 eg. get:list
18 | * @return
19 | */
20 | String value();
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Aspect.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
2 |
3 | import java.lang.annotation.Annotation;
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 | /**
10 | * 切面注解
11 | */
12 | @Target(ElementType.TYPE)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface Aspect {
15 |
16 | /**
17 | * 切点
18 | */
19 | Class extends Annotation> value();
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Controller.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
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 | * Controller
10 | */
11 |
12 | @Target(ElementType.TYPE)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface Controller {
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Inject.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
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 | */
11 | @Target(ElementType.FIELD)
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface Inject {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Service.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
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 | @Target(ElementType.TYPE)
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Service {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/annotation/Transaction.java:
--------------------------------------------------------------------------------
1 | package com.bcc.annotation;
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 | */
11 |
12 | @Target(ElementType.METHOD)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface Transaction {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/AopHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.annotation.Aspect;
4 | import com.bcc.annotation.Service;
5 | import com.bcc.proxy.AbstractAspect;
6 | import com.bcc.proxy.Proxy;
7 | import com.bcc.proxy.ProxyManager;
8 | import com.bcc.proxy.TransactionAspect;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.lang.annotation.Annotation;
14 | import java.util.ArrayList;
15 | import java.util.HashMap;
16 | import java.util.HashSet;
17 | import java.util.List;
18 | import java.util.Map;
19 | import java.util.Set;
20 |
21 | public final class AopHelper {
22 |
23 | private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);
24 |
25 | private AopHelper() {
26 |
27 | }
28 |
29 | static {
30 | Map, Set>> proxyMap = createProxyMap();
31 | try {
32 | Map, List> targetMap = createTargetMap(proxyMap);
33 | for (Map.Entry, List> entry : targetMap.entrySet()) {
34 | Class> targetClass = entry.getKey();
35 | List proxies = entry.getValue();
36 | Object proxy = ProxyManager.createProxy(targetClass, proxies); // ! ! !
37 | BeanHelper.addBean(targetClass, proxy); // ! ! ! 如何起作用的
38 | // 将原来 IOC 容器中的 Controller 对象, 已经替换成现在创建的代理对象
39 | // dispatchServlet 中获取到的是代理对象 , 是调用了代理对象的方法进行处理 .
40 | }
41 | } catch (Exception e) {
42 | e.printStackTrace();
43 | LOGGER.error("aophelper 初始化错误", e);
44 | throw new RuntimeException(e);
45 | }
46 | }
47 |
48 | /**
49 | * 获取某个 Aspect 注解 所代理的所有类
50 | */
51 | private static Set> createTargetClassSet(Aspect aspect) {
52 | Set> classes = new HashSet<>();
53 | Class extends Annotation> anno = aspect.value();
54 | if (!anno.equals(Aspect.class)) {
55 | classes.addAll(ClassHelper.getClassesByAnnotation(anno));
56 | }
57 | return classes;
58 | }
59 |
60 |
61 | /**
62 | * 一个切面类 对应多个目标类
63 | * 1. 先获取所有 AbstractAspect 的子类 , 即先获取到所有的切面类
64 | * 2. 循环,获取每个切面类对应的所有 目标类 集合
65 | */
66 | private static Map, Set>> createProxyMap() {
67 | HashMap, Set>> map = new HashMap<>();
68 | addCommoAspectProxy(map);
69 | addTransactionAspectProxy(map);
70 | return map;
71 | }
72 |
73 | // TODO 暂时只支持 service 上的 事务注解
74 | /**
75 | * 将所有 service 类 都添加事务切面 TransactionAspect
76 | */
77 | private static void addTransactionAspectProxy(HashMap, Set>> map) {
78 | Set> classes = ClassHelper.getClassesByAnnotation(Service.class);
79 | map.put(TransactionAspect.class, classes);
80 | }
81 |
82 | /**
83 | * key = 继承自 AbastractAspect 的所有普通切面类
84 | * value = Aspect 的 value 值 所指向的所有类
85 | */
86 | private static void addCommoAspectProxy(HashMap, Set>> map) {
87 | Set> aspectClasses = ClassHelper.getClassesBySuper(AbstractAspect.class);
88 | aspectClasses.stream().filter(c -> c.isAnnotationPresent(Aspect.class))
89 | .forEach(c -> {
90 | Aspect annotation = c.getAnnotation(Aspect.class);
91 | Set> classesByAnnotation = ClassHelper.getClassesByAnnotation(annotation.value());
92 | map.put(c, classesByAnnotation);
93 | });
94 | }
95 |
96 |
97 | /**
98 | * 一个目标类 对应 多个 切面类
99 | * 由上个方法得到的集合进行整理
100 | */
101 | private static Map, List> createTargetMap(Map, Set>> proxyMap) throws IllegalAccessException, InstantiationException {
102 |
103 | // 目标类 和 代理类 一对多关系
104 | HashMap, List> map = new HashMap<>();
105 |
106 | Set, Set>>> entries = proxyMap.entrySet();
107 |
108 | for (Map.Entry, Set>> entry : entries) {
109 | Class> proxyClass = entry.getKey();
110 | Set> aimClasses = entry.getValue();
111 |
112 | for (Class> aimClass : aimClasses) {
113 | if (map.containsKey(aimClass)) {
114 | map.get(aimClass).add((Proxy) proxyClass.newInstance());
115 | } else {
116 | ArrayList proxies = new ArrayList<>();
117 | proxies.add((Proxy) proxyClass.newInstance());
118 | map.put(aimClass, proxies);
119 | }
120 | }
121 | }
122 | return map;
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/BeanHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.util.ReflectionUtil;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 | import java.util.Set;
8 |
9 | /**
10 | * bean 容器类
11 | * 生成被框架管理的 bean
12 | * 放入 map 中,方便管理和使用
13 | */
14 | public class BeanHelper {
15 |
16 | /**
17 | * 管理所有的 bean
18 | */
19 | private static final Map, Object> BEAN_MAP = new HashMap<>();
20 |
21 | static {
22 | Set> beanClassSet = ClassHelper.getBeanClassSet();
23 | for (Class> c : beanClassSet) {
24 | Object o = ReflectionUtil.newInstance(c);
25 | BEAN_MAP.put(c, o);
26 | }
27 | }
28 |
29 | public static Map, Object> getBeanMap() {
30 | return BEAN_MAP;
31 | }
32 |
33 | /**
34 | * 获取指定的 bean
35 | */
36 | public static T getBean(Class clazz) {
37 | Object o = BEAN_MAP.get(clazz);
38 | if (o == null) {
39 | throw new RuntimeException("未找到指定的 bean , clazz = " + clazz);
40 | }
41 | return (T) o;
42 | }
43 |
44 | public static void addBean(Class> targetClass, Object proxy) {
45 | BEAN_MAP.put(targetClass, proxy);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/ClassHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.annotation.Controller;
4 | import com.bcc.annotation.Service;
5 | import com.bcc.util.ClassUtil;
6 |
7 | import java.lang.annotation.Annotation;
8 | import java.util.Set;
9 | import java.util.stream.Collectors;
10 |
11 | /**
12 | * 获取指定路径下的各种 类 Class
13 | */
14 | public final class ClassHelper {
15 |
16 | private ClassHelper() {
17 | }
18 |
19 | /**
20 | * 存放应用项目包下的所有类
21 | */
22 | private static final Set> CLASS_SET;
23 |
24 | static {
25 | String basePackage = ConfigHelper.getAppBasePackage();
26 | CLASS_SET = ClassUtil.getClassSet(basePackage);
27 | }
28 |
29 | public static Set> getClassSet() {
30 | return CLASS_SET;
31 | }
32 |
33 | /**
34 | * 获取所有带 service 注解的类
35 | */
36 | public static Set> getServiceClassSet() {
37 | return CLASS_SET.stream().filter(c -> c.isAnnotationPresent(Service.class)).collect(Collectors.toSet());
38 | }
39 |
40 | /**
41 | * 获取所有带 controller 注解的类
42 | */
43 | public static Set> getControllerClassSet() {
44 | return CLASS_SET.stream().filter(c -> c.isAnnotationPresent(Controller.class)).collect(Collectors.toSet());
45 | }
46 |
47 |
48 | /**
49 | * 获取所有带注解的 bean (service , controller)
50 | * @return
51 | */
52 | public static Set> getBeanClassSet() {
53 | return CLASS_SET.stream().filter(c -> c.isAnnotationPresent(Controller.class) || c.isAnnotationPresent(Service.class)).collect(Collectors.toSet());
54 | }
55 |
56 | /**
57 | * 获取某个类及其所有子类
58 | */
59 | public static Set> getClassesBySuper(Class> superClass) {
60 | return CLASS_SET.stream().filter(c->superClass.isAssignableFrom(c)&&!superClass.equals(c))
61 | .collect(Collectors.toSet());
62 | }
63 |
64 | /**
65 | * 获取带有某注解的类
66 | * eg. 获取带有 @Aspect 注解的类
67 | */
68 | public static Set> getClassesByAnnotation(Class extends Annotation> anno) {
69 | return CLASS_SET.stream().filter(c->c.isAnnotationPresent(anno))
70 | .collect(Collectors.toSet());
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/ConfigHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.util.ConfigConstant;
4 | import com.bcc.util.PropsUtil;
5 |
6 | import java.util.Properties;
7 |
8 | /**
9 | * 获取各种配置属性
10 | *
11 | */
12 | public final class ConfigHelper {
13 |
14 | private static final Properties CONFIG_PROPS = PropsUtil.loadProps(ConfigConstant.CONFIG_FILE);
15 |
16 | private ConfigHelper() {
17 | }
18 |
19 | /**
20 | * 获取 JDBC 驱动
21 | */
22 | public static String getJdbcDriver() {
23 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.JDBC_DRIVER);
24 | }
25 |
26 | /**
27 | * 获取 JDBC URL
28 | */
29 | public static String getJdbcUrl() {
30 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.JDBC_URL);
31 | }
32 |
33 | /**
34 | * 获取 JDBC 用户名
35 | */
36 | public static String getJdbcUsername() {
37 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.JDBC_USERNAME);
38 | }
39 |
40 | /**
41 | * 获取 JDBC 密码
42 | */
43 | public static String getJdbcPassword() {
44 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.JDBC_PASSWORD);
45 | }
46 |
47 | /**
48 | * 获取应用基础包名
49 | */
50 | public static String getAppBasePackage() {
51 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.APP_BASE_PACKAGE);
52 | }
53 |
54 | /**
55 | * 获取应用 JSP 路径
56 | */
57 | public static String getAppJspPath() {
58 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.APP_JSP_PATH, "/WEB-INF/view/");
59 | }
60 |
61 | /**
62 | * 获取应用静态资源路径
63 | */
64 | public static String getAppAssetPath() {
65 | return PropsUtil.getString(CONFIG_PROPS, ConfigConstant.APP_ASSET_PATH, "/asset/");
66 | }
67 |
68 | /**
69 | * 获取应用文件上传限制
70 | */
71 | // public static int getAppUploadLimit() {
72 | // return PropsUtil.getInt(CONFIG_PROPS, ConfigConstant.APP_UPLOAD_LIMIT, 10);
73 | // }
74 |
75 | /**
76 | * 根据属性名获取 String 类型的属性值
77 | */
78 | public static String getString(String key) {
79 | return PropsUtil.getString(CONFIG_PROPS, key);
80 | }
81 |
82 | /**
83 | * 根据属性名获取 int 类型的属性值
84 | */
85 | public static int getInt(String key) {
86 | return PropsUtil.getInt(CONFIG_PROPS, key);
87 | }
88 |
89 | /**
90 | * 根据属性名获取 boolean 类型的属性值
91 | */
92 | public static boolean getBoolean(String key) {
93 | return PropsUtil.getBoolean(CONFIG_PROPS, key);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/ControllerHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.annotation.Action;
4 | import com.bcc.web.Handler;
5 | import com.bcc.web.Request;
6 |
7 | import java.lang.reflect.Method;
8 | import java.util.Arrays;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 | import java.util.Set;
12 |
13 | /**
14 | * 获取所有的 controller 。
15 | * 及 request 和 handler 之间的 一对一关系
16 | */
17 | public final class ControllerHelper {
18 |
19 | private ControllerHelper() {
20 | }
21 |
22 | /**
23 | * request 和 handler 之间的 一对一关系
24 | */
25 | private static final Map ACTION_MAP = new HashMap<>();
26 |
27 | static {
28 | Set> classSet = ClassHelper.getControllerClassSet();
29 | classSet.stream().forEach(c -> {
30 | Method[] methods = c.getDeclaredMethods();
31 | Arrays.stream(methods).filter(method -> method.isAnnotationPresent(Action.class)).forEach(method -> {
32 | Request request = new Request();
33 | String[] array = method.getDeclaredAnnotation(Action.class).value().split(":");
34 | request.setMethod(array[0].toLowerCase());
35 | request.setPath(array[1].startsWith("/") ? array[1] : "/" + array[1]);
36 |
37 | Handler handler = new Handler();
38 | handler.setController(c);
39 | handler.setActionMethod(method);
40 | if (ACTION_MAP.containsKey(request)) {
41 | throw new RuntimeException("请求路径不能相同 request = "+request+" , handler = "+handler);
42 | }
43 | ACTION_MAP.put(request, handler);
44 | });
45 | });
46 | }
47 |
48 | public static Map getActionMap() {
49 | return ACTION_MAP;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/DatabaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.util.ConfigConstant;
4 | import com.bcc.util.PropsUtil;
5 |
6 | import org.apache.commons.dbcp2.BasicDataSource;
7 | import org.apache.commons.dbutils.QueryRunner;
8 | import org.apache.commons.dbutils.handlers.ArrayHandler;
9 | import org.apache.commons.dbutils.handlers.BeanListHandler;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import java.sql.Connection;
14 | import java.sql.SQLException;
15 | import java.util.List;
16 | import java.util.Properties;
17 |
18 | public final class DatabaseHelper {
19 |
20 | private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHelper.class);
21 | private static final QueryRunner QUERY_RUNNER = new QueryRunner();
22 | private static final BasicDataSource BASIC_DATA_SOURCE;
23 |
24 | private static final String DRIVER;
25 | private static final String URL;
26 | private static final String USERNAME;
27 | private static final String PASSWORD;
28 |
29 | private static ThreadLocal threadLocal = new ThreadLocal<>();
30 |
31 |
32 | static {
33 | Properties conf = PropsUtil.loadProps("smart.properties");
34 | DRIVER = conf.getProperty(ConfigConstant.JDBC_DRIVER);
35 | URL = conf.getProperty(ConfigConstant.JDBC_URL);
36 | USERNAME = conf.getProperty(ConfigConstant.JDBC_USERNAME);
37 | PASSWORD = conf.getProperty(ConfigConstant.JDBC_PASSWORD);
38 | BASIC_DATA_SOURCE = new BasicDataSource();
39 | BASIC_DATA_SOURCE.setDriverClassName(DRIVER);
40 | BASIC_DATA_SOURCE.setUrl(URL);
41 | BASIC_DATA_SOURCE.setUsername(USERNAME);
42 | BASIC_DATA_SOURCE.setPassword(PASSWORD);
43 |
44 | // try {
45 | // Class.forName("com.mysql.jdbc.Driver");
46 | // } catch (Exception e) {
47 | // LOGGER.error("数据库驱动错误", e);
48 | // }
49 | }
50 |
51 | private DatabaseHelper() {
52 | }
53 |
54 | public static Connection getConnection() throws SQLException {
55 | Connection connection = threadLocal.get();
56 | if (connection == null) {
57 | connection = BASIC_DATA_SOURCE.getConnection();
58 | threadLocal.set(connection);
59 | }
60 | return connection;
61 | }
62 |
63 | public static void closeConnection(Connection connection) {
64 | if (connection != null) {
65 | try {
66 | connection.close();
67 | } catch (SQLException e) {
68 | e.printStackTrace();
69 | }
70 | threadLocal.remove();
71 | } else {
72 | LOGGER.error("连接为 null");
73 | }
74 | }
75 |
76 | public static List getEntityList(Class clazz, String sql, Object... params) {
77 | List list = null;
78 | Connection connection = null;
79 | try {
80 | connection = getConnection();
81 | list = QUERY_RUNNER.query(connection, sql, new BeanListHandler<>(clazz), params);
82 | } catch (SQLException e) {
83 | throw new RuntimeException(e);
84 | }
85 | return list;
86 | }
87 |
88 | public static int insert(String sql, Object... params) {
89 | Connection connection = null;
90 | Object[] insert;
91 | try {
92 | connection = getConnection();
93 | insert = QUERY_RUNNER.insert(connection, sql, new ArrayHandler(), params);
94 | } catch (SQLException e) {
95 | LOGGER.error("getConnection 异常 ", e);
96 | throw new RuntimeException("getConnection 异常");
97 | }
98 | return insert.length;
99 | }
100 |
101 | /**
102 | * 开启事务
103 | */
104 | public static void beginTransaction() {
105 | Connection connection;
106 | try {
107 | connection = getConnection();
108 | } catch (SQLException e) {
109 | LOGGER.error("getConnection 异常 ", e);
110 | throw new RuntimeException("getConnection 异常");
111 | }
112 | if (connection != null) {
113 | try {
114 | connection.setAutoCommit(false);
115 | } catch (SQLException e) {
116 | LOGGER.error("connection.setAutoCommit 异常 ", e);
117 | throw new RuntimeException("connection.setAutoCommit 异常");
118 | }
119 | }
120 | }
121 |
122 | /**
123 | * 提交事务
124 | */
125 | public static void commitTransaction() {
126 | Connection connection;
127 | try {
128 | connection = getConnection();
129 | } catch (SQLException e) {
130 | LOGGER.error("getConnection 异常 ", e);
131 | throw new RuntimeException("getConnection 异常");
132 | }
133 | if (connection == null) {
134 | LOGGER.error("connection = null ");
135 | throw new RuntimeException("connection = null 异常");
136 | }
137 | try {
138 | connection.commit();
139 | } catch (SQLException e) {
140 | LOGGER.error("connection.commit 异常");
141 | throw new RuntimeException("connection.commit 异常");
142 | } finally {
143 | closeConnection(connection);
144 | }
145 | }
146 |
147 | /**
148 | * 事务回滚
149 | */
150 | public static void rollBack() {
151 | Connection connection;
152 | try {
153 | connection = getConnection();
154 | } catch (SQLException e) {
155 | LOGGER.error("getConnection 异常 ", e);
156 | throw new RuntimeException("getConnection 异常");
157 | }
158 | if (connection == null) {
159 | LOGGER.error("connection = null ");
160 | throw new RuntimeException("connection = null 异常");
161 | }
162 | try {
163 | connection.rollback();
164 | } catch (SQLException e) {
165 | LOGGER.error("connection.rollback 异常");
166 | throw new RuntimeException("connection.rollback 异常");
167 | } finally {
168 | closeConnection(connection);
169 | }
170 | }
171 |
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/helper/IocHelper.java:
--------------------------------------------------------------------------------
1 | package com.bcc.helper;
2 |
3 | import com.bcc.annotation.Inject;
4 | import com.bcc.util.ReflectionUtil;
5 |
6 | import java.lang.reflect.Field;
7 | import java.util.Arrays;
8 | import java.util.Map;
9 |
10 | /**
11 | * IOC 实现依赖注入
12 | * 遍历 beanMap , 若某个成员变量带有 inject 注解, 再从 map 中取出对应的bean ,为他赋值
13 | * eg. Controller 中注入 service
14 | */
15 | public final class IocHelper {
16 | private IocHelper() {
17 | }
18 |
19 | static {
20 | Map, Object> beanMap = BeanHelper.getBeanMap();
21 | if (!beanMap.isEmpty()) {
22 | beanMap.entrySet().stream().forEach(entry -> {
23 | Class> clazz = entry.getKey();
24 | Object instance = entry.getValue();
25 | Field[] fields = clazz.getDeclaredFields();
26 |
27 | // 对 bean 中成员变量带有 Inject 注解的类 , 进行赋值
28 | Arrays.stream(fields).filter(field -> field.isAnnotationPresent(Inject.class))
29 | .forEach(field -> {
30 | Class> type = field.getType();
31 | Object fieldInstance = BeanHelper.getBean(type); // TODO 可能为 null 么 ?
32 | ReflectionUtil.setFiled(instance, field, fieldInstance);
33 | });
34 | });
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/proxy/AbstractAspect.java:
--------------------------------------------------------------------------------
1 | package com.bcc.proxy;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.lang.reflect.Method;
7 |
8 | /**
9 | * 抽象的切面类
10 | */
11 | public abstract class AbstractAspect implements Proxy {
12 |
13 | private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
14 |
15 | @Override
16 | public Object doProxy(ProxyChain proxyChain) throws Throwable {
17 | Object result;
18 | Class> targetClass = proxyChain.getTargetClass();
19 | Method targetMethod = proxyChain.getTargetMethod();
20 | Object[] params = proxyChain.getMethodParams();
21 | begin();
22 | try {
23 | if (intercept(targetClass, targetMethod, params)) {
24 | before(targetClass, targetMethod, params);
25 | result = proxyChain.doProxyChain();
26 | after(targetClass, targetMethod, params, result);
27 | } else {
28 | result = proxyChain.doProxyChain();
29 | }
30 | } catch (Throwable e) {
31 | LOGGER.error("代理过程出错", e);
32 | error(targetClass, targetMethod, params, e);
33 | throw e;
34 | } finally {
35 | end();
36 | }
37 |
38 |
39 | return result;
40 | }
41 |
42 | /**
43 | *
44 | */
45 | public void end() {
46 |
47 | }
48 |
49 | public void error(Class> targetClass, Method targetMethod, Object[] params, Throwable e) {
50 | }
51 |
52 | public void after(Class> targetClass, Method targetMethod, Object[] params, Object result) {
53 | }
54 |
55 | public void before(Class> targetClass, Method targetMethod, Object[] params) {
56 | }
57 |
58 | public boolean intercept(Class> targetClass, Method targetMethod, Object[] params) {
59 | return true;
60 | }
61 |
62 | public void begin() {
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/proxy/Proxy.java:
--------------------------------------------------------------------------------
1 | package com.bcc.proxy;
2 |
3 | public interface Proxy {
4 |
5 | /**
6 | * 执行代理
7 | */
8 | Object doProxy(ProxyChain proxyChain) throws Throwable;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/proxy/ProxyChain.java:
--------------------------------------------------------------------------------
1 | package com.bcc.proxy;
2 |
3 | import net.sf.cglib.proxy.MethodProxy;
4 |
5 | import java.lang.reflect.Method;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class ProxyChain {
10 |
11 | private final Class> targetClass;
12 | private final Object targetObj;
13 | private final Method targetMethod;
14 | private final MethodProxy methodProxy;
15 | private final Object[] methodParams;
16 | private List proxyList = new ArrayList<>();
17 | private int proxyIndex = 0;
18 |
19 | public ProxyChain(Class> targetClass, Object targetObj, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List proxyList) {
20 | this.targetClass = targetClass;
21 | this.targetObj = targetObj;
22 | this.targetMethod = targetMethod;
23 | this.methodProxy = methodProxy;
24 | this.methodParams = methodParams;
25 | this.proxyList = proxyList;
26 | }
27 |
28 | public Method getTargetMethod() {
29 | return targetMethod;
30 | }
31 |
32 | public Class> getTargetClass() {
33 | return targetClass;
34 | }
35 |
36 | public Object getTargetObj() {
37 | return targetObj;
38 | }
39 |
40 | public Object[] getMethodParams() {
41 | return methodParams;
42 | }
43 |
44 | /**
45 | * 执行代理链
46 | */
47 | public Object doProxyChain() throws Throwable {
48 | Object result;
49 | if (proxyIndex < proxyList.size()) {
50 | result = proxyList.get(proxyIndex++).doProxy(this);
51 | } else {
52 | result = methodProxy.invokeSuper(targetObj,methodParams);
53 | }
54 | return result;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/proxy/ProxyManager.java:
--------------------------------------------------------------------------------
1 | package com.bcc.proxy;
2 |
3 | import net.sf.cglib.proxy.Enhancer;
4 | import net.sf.cglib.proxy.MethodInterceptor;
5 | import net.sf.cglib.proxy.MethodProxy;
6 |
7 | import java.lang.reflect.Method;
8 | import java.util.List;
9 |
10 | public class ProxyManager {
11 |
12 |
13 | /**
14 | * 创建代理对象
15 | */
16 | @SuppressWarnings("unchecked")
17 | public static T createProxy(Class> targetClass, List proxyList) {
18 | return (T)Enhancer.create(targetClass, new MethodInterceptor() {
19 | @Override
20 | public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
21 | return new ProxyChain(targetClass,o,method,methodProxy,objects,proxyList).doProxyChain();
22 | }
23 | });
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/proxy/TransactionAspect.java:
--------------------------------------------------------------------------------
1 | package com.bcc.proxy;
2 |
3 | import com.bcc.annotation.Transaction;
4 | import com.bcc.helper.DatabaseHelper;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.lang.reflect.Method;
10 |
11 | /**
12 | * 事务切面类 , 类似于普通切面类 AbstractAspect
13 | */
14 | public class TransactionAspect implements Proxy {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(TransactionAspect.class);
17 |
18 | private static ThreadLocal IS_EXECUTE = ThreadLocal.withInitial(() -> false);
19 |
20 | @Override
21 | public Object doProxy(ProxyChain proxyChain) throws Throwable {
22 | Object reult = null;
23 | Boolean flag = IS_EXECUTE.get();
24 | Method method = proxyChain.getTargetMethod();
25 |
26 | if (flag || !method.isAnnotationPresent(Transaction.class)) {
27 | return proxyChain.doProxyChain();
28 | }
29 | IS_EXECUTE.set(true);
30 | try {
31 | DatabaseHelper.beginTransaction();
32 | System.out.println("beginTransaction");
33 | reult = proxyChain.doProxyChain();
34 | DatabaseHelper.commitTransaction();
35 | System.out.println("commitTransaction");
36 | } catch (Exception e) {
37 | DatabaseHelper.rollBack();
38 | System.out.println("rollBack");
39 | throw new RuntimeException("事务执行过程出错", e);
40 | } finally {
41 | IS_EXECUTE.remove();
42 | }
43 |
44 | return reult;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/test/Test01.java:
--------------------------------------------------------------------------------
1 | package com.bcc.test;
2 |
3 | import com.bcc.MainLoader;
4 | import com.bcc.helper.ControllerHelper;
5 | import com.bcc.web.Handler;
6 | import com.bcc.web.Request;
7 |
8 | import java.util.Map;
9 |
10 | public class Test01 {
11 |
12 | public static void main(String[] args) {
13 |
14 | MainLoader.init();
15 |
16 | // Map, Object> beanMap = BeanHelper.getBeanMap();
17 | // System.out.println(beanMap);
18 | // TestController controller = BeanHelper.getBean(TestController.class);
19 | // System.out.println(controller);
20 | // System.out.println(controller.getTestService());
21 |
22 | Map actionMap = ControllerHelper.getActionMap();
23 | System.out.println(actionMap.size());
24 | for (Map.Entry entry : actionMap.entrySet()) {
25 | System.out.println(entry.getKey());
26 | System.out.println(entry.getValue());
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/test/TestController.java:
--------------------------------------------------------------------------------
1 | package com.bcc.test;
2 |
3 | import com.bcc.annotation.Action;
4 | import com.bcc.annotation.Controller;
5 | import com.bcc.annotation.Inject;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | @Controller
11 | public class TestController {
12 |
13 | @Inject
14 | private TestService testService;
15 |
16 | public TestService getTestService() {
17 | return testService;
18 | }
19 |
20 | @Action("get:/getList")
21 | public List getList() {
22 | return Arrays.asList("aa", "bb", "cc");
23 | }
24 |
25 | @Action("post:update")
26 | public void updatePersion() {
27 | System.out.println("updatePersion ...");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/test/TestService.java:
--------------------------------------------------------------------------------
1 | package com.bcc.test;
2 |
3 | import com.bcc.annotation.Service;
4 |
5 | @Service
6 | public class TestService {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/CastUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | /**
4 | * 转型操作工具类
5 | */
6 | public final class CastUtil {
7 |
8 | /**
9 | * 转为 String 型
10 | */
11 | public static String castString(Object obj) {
12 | return CastUtil.castString(obj, "");
13 | }
14 |
15 | /**
16 | * 转为 String 型(提供默认值)
17 | */
18 | public static String castString(Object obj, String defaultValue) {
19 | return obj != null ? String.valueOf(obj) : defaultValue;
20 | }
21 |
22 | /**
23 | * 转为 double 型
24 | */
25 | public static double castDouble(Object obj) {
26 | return CastUtil.castDouble(obj, 0);
27 | }
28 |
29 | /**
30 | * 转为 double 型(提供默认值)
31 | */
32 | public static double castDouble(Object obj, double defaultValue) {
33 | double doubleValue = defaultValue;
34 | if (obj != null) {
35 | String strValue = castString(obj);
36 | if (StringUtil.isNotEmpty(strValue)) {
37 | try {
38 | doubleValue = Double.parseDouble(strValue);
39 | } catch (NumberFormatException e) {
40 | doubleValue = defaultValue;
41 | }
42 | }
43 | }
44 | return doubleValue;
45 | }
46 |
47 | /**
48 | * 转为 long 型
49 | */
50 | public static long castLong(Object obj) {
51 | return CastUtil.castLong(obj, 0);
52 | }
53 |
54 | /**
55 | * 转为 long 型(提供默认值)
56 | */
57 | public static long castLong(Object obj, long defaultValue) {
58 | long longValue = defaultValue;
59 | if (obj != null) {
60 | String strValue = castString(obj);
61 | if (StringUtil.isNotEmpty(strValue)) {
62 | try {
63 | longValue = Long.parseLong(strValue);
64 | } catch (NumberFormatException e) {
65 | longValue = defaultValue;
66 | }
67 | }
68 | }
69 | return longValue;
70 | }
71 |
72 | /**
73 | * 转为 int 型
74 | */
75 | public static int castInt(Object obj) {
76 | return CastUtil.castInt(obj, 0);
77 | }
78 |
79 | /**
80 | * 转为 int 型(提供默认值)
81 | */
82 | public static int castInt(Object obj, int defaultValue) {
83 | int intValue = defaultValue;
84 | if (obj != null) {
85 | String strValue = castString(obj);
86 | if (StringUtil.isNotEmpty(strValue)) {
87 | try {
88 | intValue = Integer.parseInt(strValue);
89 | } catch (NumberFormatException e) {
90 | intValue = defaultValue;
91 | }
92 | }
93 | }
94 | return intValue;
95 | }
96 |
97 | /**
98 | * 转为 boolean 型
99 | */
100 | public static boolean castBoolean(Object obj) {
101 | return CastUtil.castBoolean(obj, false);
102 | }
103 |
104 | /**
105 | * 转为 boolean 型(提供默认值)
106 | */
107 | public static boolean castBoolean(Object obj, boolean defaultValue) {
108 | boolean booleanValue = defaultValue;
109 | if (obj != null) {
110 | booleanValue = Boolean.parseBoolean(castString(obj));
111 | }
112 | return booleanValue;
113 | }
114 | }
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/ClassUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.File;
7 | import java.io.FileFilter;
8 | import java.net.JarURLConnection;
9 | import java.net.URL;
10 | import java.util.Enumeration;
11 | import java.util.HashSet;
12 | import java.util.Set;
13 | import java.util.jar.JarEntry;
14 | import java.util.jar.JarFile;
15 |
16 | /**
17 | * 类操作工具类
18 | *
19 | */
20 | public final class ClassUtil {
21 |
22 | private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
23 |
24 | /**
25 | * 获取类加载器
26 | */
27 | public static ClassLoader getClassLoader() {
28 | return Thread.currentThread().getContextClassLoader();
29 | }
30 |
31 | /**
32 | * 加载类
33 | */
34 | public static Class> loadClass(String className, boolean isInitialized) {
35 | Class> cls;
36 | try {
37 | cls = Class.forName(className, isInitialized, getClassLoader());
38 | } catch (ClassNotFoundException e) {
39 | LOGGER.error("load class failure", e);
40 | throw new RuntimeException(e);
41 | }
42 | return cls;
43 | }
44 |
45 | /**
46 | * 加载类(默认将初始化类)
47 | */
48 | public static Class> loadClass(String className) {
49 | return loadClass(className, true);
50 | }
51 |
52 | //TODO 项目不能放在磁盘上有中文的路径下
53 | /**
54 | * 获取指定包名下的所有类
55 | */
56 | public static Set> getClassSet(String packageName) {
57 | Set> classSet = new HashSet>();
58 | try {
59 | Enumeration urls = getClassLoader().getResources(packageName.replace(".", "/"));
60 | while (urls.hasMoreElements()) {
61 | URL url = urls.nextElement();
62 | if (url != null) {
63 | String protocol = url.getProtocol();
64 | if (protocol.equals("file")) {
65 | String packagePath = url.getPath().replaceAll("%20", " ");
66 | addClass(classSet, packagePath, packageName);
67 | } else if (protocol.equals("jar")) {
68 | JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
69 | if (jarURLConnection != null) {
70 | JarFile jarFile = jarURLConnection.getJarFile();
71 | if (jarFile != null) {
72 | Enumeration jarEntries = jarFile.entries();
73 | while (jarEntries.hasMoreElements()) {
74 | JarEntry jarEntry = jarEntries.nextElement();
75 | String jarEntryName = jarEntry.getName();
76 | if (jarEntryName.endsWith(".class")) {
77 | String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
78 | doAddClass(classSet, className);
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 | } catch (Exception e) {
87 | LOGGER.error("get class set failure", e);
88 | throw new RuntimeException(e);
89 | }
90 | return classSet;
91 | }
92 |
93 | private static void addClass(Set> classSet, String packagePath, String packageName) {
94 | File[] files = new File(packagePath).listFiles(new FileFilter() {
95 | public boolean accept(File file) {
96 | return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
97 | }
98 | });
99 | LOGGER.info("files = "+files);
100 | if (files == null || files.length == 0) {
101 | return;
102 | }
103 | for (File file : files) {
104 | String fileName = file.getName();
105 | if (file.isFile()) {
106 | String className = fileName.substring(0, fileName.lastIndexOf("."));
107 | if (StringUtil.isNotEmpty(packageName)) {
108 | className = packageName + "." + className;
109 | }
110 | doAddClass(classSet, className);
111 | } else {
112 | String subPackagePath = fileName;
113 | if (StringUtil.isNotEmpty(packagePath)) {
114 | subPackagePath = packagePath + "/" + subPackagePath;
115 | }
116 | String subPackageName = fileName;
117 | if (StringUtil.isNotEmpty(packageName)) {
118 | subPackageName = packageName + "." + subPackageName;
119 | }
120 | addClass(classSet, subPackagePath, subPackageName);
121 | }
122 | }
123 | }
124 |
125 | private static void doAddClass(Set> classSet, String className) {
126 | Class> cls = loadClass(className, false);
127 | classSet.add(cls);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/CodecUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.net.URLDecoder;
7 | import java.net.URLEncoder;
8 |
9 | /**
10 | * 编码与解码操作工具类
11 | *
12 | * @author huangyong
13 | * @since 1.0.0
14 | */
15 | public final class CodecUtil {
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(CodecUtil.class);
18 |
19 | /**
20 | * 将 URL 编码
21 | */
22 | public static String encodeURL(String source) {
23 | String target;
24 | try {
25 | target = URLEncoder.encode(source, "UTF-8");
26 | } catch (Exception e) {
27 | LOGGER.error("encode url failure", e);
28 | throw new RuntimeException(e);
29 | }
30 | return target;
31 | }
32 |
33 | /**
34 | * 将 URL 解码
35 | */
36 | public static String decodeURL(String source) {
37 | String target;
38 | try {
39 | target = URLDecoder.decode(source, "UTF-8");
40 | } catch (Exception e) {
41 | LOGGER.error("decode url failure", e);
42 | throw new RuntimeException(e);
43 | }
44 | return target;
45 | }
46 |
47 | /**
48 | * MD5 加密
49 | */
50 | // public static String md5(String source) {
51 | // return DigestUtils.md5Hex(source);
52 | // }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/ConfigConstant.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | /**
4 | * 配置文件 属性常量
5 | */
6 | public interface ConfigConstant {
7 |
8 | String CONFIG_FILE = "smart.properties";
9 |
10 | String JDBC_DRIVER = "smart.framework.jdbc.driver";
11 | String JDBC_URL = "smart.framework.jdbc.url";
12 | String JDBC_USERNAME = "smart.framework.jdbc.username";
13 | String JDBC_PASSWORD = "smart.framework.jdbc.password";
14 |
15 | String APP_BASE_PACKAGE = "smart.framework.app.base_package";
16 | String APP_JSP_PATH = "smart.framework.app.jsp_path";
17 | String APP_ASSET_PATH = "smart.framework.app.asset_path";
18 |
19 | // String APP_UPLOAD_LIMIT = "smart.framework.app.upload_limit";
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/JsonUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | /**
8 | * JSON 工具类
9 | *
10 | * @author huangyong
11 | * @since 1.0.0
12 | */
13 | public final class JsonUtil {
14 |
15 | private static final Logger LOGGER = LoggerFactory.getLogger(JsonUtil.class);
16 |
17 | private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
18 |
19 | /**
20 | * 将 POJO 转为 JSON
21 | */
22 | public static String toJson(T obj) {
23 | String json;
24 | try {
25 | json = OBJECT_MAPPER.writeValueAsString(obj);
26 | } catch (Exception e) {
27 | LOGGER.error("convert POJO to JSON failure", e);
28 | throw new RuntimeException(e);
29 | }
30 | return json;
31 | }
32 |
33 | /**
34 | * 将 JSON 转为 POJO
35 | */
36 | public static T fromJson(String json, Class type) {
37 | T pojo;
38 | try {
39 | pojo = OBJECT_MAPPER.readValue(json, type);
40 | } catch (Exception e) {
41 | LOGGER.error("convert JSON to POJO failure", e);
42 | throw new RuntimeException(e);
43 | }
44 | return pojo;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/MethodEunm.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | public enum MethodEunm {
4 |
5 | GET("GET"),POST("POST"),PUT("PUT"),DELETE("DELETE");
6 |
7 | private String method;
8 |
9 | MethodEunm(String method) {
10 | this.method = method;
11 | }
12 |
13 | public String getMethod() {
14 | return method;
15 | }
16 |
17 | public void setMethod(String method) {
18 | this.method = method;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/PropsUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.FileNotFoundException;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.util.Properties;
10 |
11 | /**
12 | * 属性文件工具类
13 | */
14 | public final class PropsUtil {
15 |
16 | private static final Logger LOGGER = LoggerFactory.getLogger(PropsUtil.class);
17 |
18 | /**
19 | * 加载属性文件
20 | */
21 | public static Properties loadProps(String fileName) {
22 | Properties props = null;
23 | InputStream is = null;
24 | try {
25 | is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
26 | if (is == null) {
27 | throw new FileNotFoundException(fileName + " file is not found");
28 | }
29 | props = new Properties();
30 | props.load(is);
31 | } catch (IOException e) {
32 | LOGGER.error("load properties file failure", e);
33 | } finally {
34 | if (is != null) {
35 | try {
36 | is.close();
37 | } catch (IOException e) {
38 | LOGGER.error("close input stream failure", e);
39 | }
40 | }
41 | }
42 | return props;
43 | }
44 |
45 | /**
46 | * 获取字符型属性(默认值为空字符串)
47 | */
48 | public static String getString(Properties props, String key) {
49 | return getString(props, key, "");
50 | }
51 |
52 | /**
53 | * 获取字符型属性(可指定默认值)
54 | */
55 | public static String getString(Properties props, String key, String defaultValue) {
56 | String value = defaultValue;
57 | if (props.containsKey(key)) {
58 | value = props.getProperty(key);
59 | }
60 | return value;
61 | }
62 |
63 | /**
64 | * 获取数值型属性(默认值为 0)
65 | */
66 | public static int getInt(Properties props, String key) {
67 | return getInt(props, key, 0);
68 | }
69 |
70 | // 获取数值型属性(可指定默认值)
71 | public static int getInt(Properties props, String key, int defaultValue) {
72 | int value = defaultValue;
73 | if (props.containsKey(key)) {
74 | value = CastUtil.castInt(props.getProperty(key));
75 | }
76 | return value;
77 | }
78 |
79 | /**
80 | * 获取布尔型属性(默认值为 false)
81 | */
82 | public static boolean getBoolean(Properties props, String key) {
83 | return getBoolean(props, key, false);
84 | }
85 |
86 | /**
87 | * 获取布尔型属性(可指定默认值)
88 | */
89 | public static boolean getBoolean(Properties props, String key, boolean defaultValue) {
90 | boolean value = defaultValue;
91 | if (props.containsKey(key)) {
92 | value = CastUtil.castBoolean(props.getProperty(key));
93 | }
94 | return value;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/ReflectionUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.lang.reflect.Field;
7 | import java.lang.reflect.Method;
8 |
9 | /**
10 | * 反射工具类
11 | */
12 | public final class ReflectionUtil {
13 |
14 | private ReflectionUtil() {
15 | }
16 |
17 | private static final Logger LOGGER = LoggerFactory.getLogger(ReflectionUtil.class);
18 |
19 | /**
20 | * 创建对象
21 | */
22 | public static Object newInstance(Class> clazz) {
23 | Object instance;
24 | try {
25 | instance = clazz.newInstance();
26 | } catch (Exception e) {
27 | LOGGER.error("反射创建对象错误", e);
28 | throw new RuntimeException(e);
29 | }
30 | return instance;
31 | }
32 |
33 | /**
34 | * 调用方法
35 | */
36 | public static Object invokeMethod(Object target, Method method, Object... args) {
37 | Object result;
38 | method.setAccessible(true);
39 | try {
40 | result = method.invoke(target, args);
41 | } catch (Exception e) {
42 | LOGGER.error("反射调用方法错误", e);
43 | throw new RuntimeException(e);
44 | }
45 | return result;
46 | }
47 |
48 | /**
49 | * 设置 filed 值
50 | */
51 | public static void setFiled(Object target, Field field, Object value) {
52 | field.setAccessible(true);
53 | try {
54 | field.set(target, value);
55 | } catch (IllegalAccessException e) {
56 | LOGGER.error("反射设置 filed 错误", e);
57 | throw new RuntimeException(e);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/StreamUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.io.OutputStream;
10 |
11 | /**
12 | * 流操作工具类
13 | *
14 | * @author huangyong
15 | * @since 1.0.0
16 | */
17 | public final class StreamUtil {
18 |
19 | private static final Logger LOGGER = LoggerFactory.getLogger(StreamUtil.class);
20 |
21 | /**
22 | * 从输入流中获取字符串
23 | */
24 | public static String getString(InputStream is) {
25 | StringBuilder sb = new StringBuilder();
26 | try {
27 | BufferedReader reader = new BufferedReader(new InputStreamReader(is));
28 | String line;
29 | while ((line = reader.readLine()) != null) {
30 | sb.append(line);
31 | }
32 | } catch (Exception e) {
33 | LOGGER.error("get string failure", e);
34 | throw new RuntimeException(e);
35 | }
36 | return sb.toString();
37 | }
38 |
39 | /**
40 | * 将输入流复制到输出流
41 | */
42 | public static void copyStream(InputStream inputStream, OutputStream outputStream) {
43 | try {
44 | int length;
45 | byte[] buffer = new byte[4 * 1024];
46 | while ((length = inputStream.read(buffer, 0, buffer.length)) != -1) {
47 | outputStream.write(buffer, 0, length);
48 | }
49 | outputStream.flush();
50 | } catch (Exception e) {
51 | LOGGER.error("copy stream failure", e);
52 | throw new RuntimeException(e);
53 | } finally {
54 | try {
55 | inputStream.close();
56 | outputStream.close();
57 | } catch (Exception e) {
58 | LOGGER.error("close stream failure", e);
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/util/StringUtil.java:
--------------------------------------------------------------------------------
1 | package com.bcc.util;
2 |
3 | import org.apache.commons.lang3.StringUtils;
4 |
5 | /**
6 | * 字符串工具类
7 | */
8 | public final class StringUtil {
9 |
10 | /**
11 | * 判断字符串是否为空
12 | */
13 | public static boolean isEmpty(String str) {
14 | if (str != null) {
15 | str = str.trim();
16 | }
17 | return StringUtils.isEmpty(str);
18 | }
19 |
20 | /**
21 | * 判断字符串是否非空
22 | */
23 | public static boolean isNotEmpty(String str) {
24 | return !isEmpty(str);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/DispatchServlet.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | import com.bcc.MainLoader;
4 | import com.bcc.helper.BeanHelper;
5 | import com.bcc.helper.ConfigHelper;
6 | import com.bcc.helper.ControllerHelper;
7 | import com.bcc.util.CodecUtil;
8 | import com.bcc.util.JsonUtil;
9 | import com.bcc.util.ReflectionUtil;
10 | import com.bcc.util.StreamUtil;
11 |
12 | import org.apache.commons.lang3.ArrayUtils;
13 | import org.apache.commons.lang3.StringUtils;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import java.io.IOException;
18 | import java.io.PrintWriter;
19 | import java.lang.reflect.Method;
20 | import java.util.Enumeration;
21 | import java.util.HashMap;
22 | import java.util.Map;
23 |
24 | import javax.servlet.ServletConfig;
25 | import javax.servlet.ServletContext;
26 | import javax.servlet.ServletException;
27 | import javax.servlet.ServletRegistration;
28 | import javax.servlet.annotation.WebServlet;
29 | import javax.servlet.http.HttpServlet;
30 | import javax.servlet.http.HttpServletRequest;
31 | import javax.servlet.http.HttpServletResponse;
32 |
33 | /**
34 | * web 层核心
35 | * 根据请求 request (method:path) , 找到对应的 handler (controller.action) 处理
36 | */
37 | @WebServlet(urlPatterns = "/*",loadOnStartup = 0)
38 | public class DispatchServlet extends HttpServlet {
39 |
40 | private static final Logger LOGGER = LoggerFactory.getLogger(DispatchServlet.class);
41 |
42 | @Override
43 | public void init(ServletConfig config) throws ServletException {
44 |
45 | MainLoader.init();
46 | ServletContext context = config.getServletContext();
47 |
48 | // jsp
49 | ServletRegistration registration = context.getServletRegistration("jsp");
50 | registration.addMapping(ConfigHelper.getAppJspPath() + "*");
51 |
52 | // asset 下静态资源
53 | ServletRegistration defaultRegistration = context.getServletRegistration("default");
54 | defaultRegistration.addMapping(ConfigHelper.getAppAssetPath() + "*");
55 |
56 | }
57 |
58 |
59 | @Override
60 | protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
61 |
62 | Map actionMap = ControllerHelper.getActionMap();
63 |
64 | String method = request.getMethod().toLowerCase();
65 | String path = request.getPathInfo();
66 | Request requestAction = new Request(method, path);
67 | if (!actionMap.containsKey(requestAction)) {
68 | throw new RuntimeException("请求不存在 requestAction = " + requestAction);
69 | }
70 | Handler handler = actionMap.get(requestAction);
71 | Method actionMethod = handler.getActionMethod();
72 | Class> controllerClass = handler.getController();
73 | Object controllerBean = BeanHelper.getBean(controllerClass);
74 |
75 | // 获取请求参数 Param
76 | HashMap paramMap = new HashMap<>();
77 | Enumeration parameterNames = request.getParameterNames();
78 | while (parameterNames.hasMoreElements()) {
79 | String name = parameterNames.nextElement();
80 | String val = request.getParameter(name);
81 | paramMap.put(name, val);
82 | }
83 | String body = CodecUtil.decodeURL(StreamUtil.getString(request.getInputStream()));
84 | if (body != null && body.length() > 0) {
85 | String[] params = body.trim().split("&");
86 | if (!ArrayUtils.isEmpty(params)) {
87 | for (String param : params) {
88 | String[] arr = param.split("=");
89 | if (arr.length == 2) {
90 | paramMap.put(arr[0], arr[1]);
91 | }
92 | }
93 | }
94 | }
95 | RequestParam param = new RequestParam(paramMap);
96 |
97 | // 调用 action 方法
98 | Object result = ReflectionUtil.invokeMethod(controllerBean, actionMethod, param);
99 |
100 | // 跳转页面
101 | if (result instanceof ModelAndView) {
102 | ModelAndView view = (ModelAndView) result;
103 | String viewPath = view.getPath();
104 | if (StringUtils.isEmpty(viewPath)) {
105 | throw new RuntimeException("跳转路径不能为空");
106 | }
107 | if (viewPath.startsWith("/")) {
108 | response.sendRedirect(request.getContextPath() + viewPath); // 为什么要把有没有 / 区别对待 ???
109 |
110 | } else {
111 | Map model = view.getModel();
112 | for (Map.Entry entry : model.entrySet()) {
113 | request.setAttribute(entry.getKey(), entry.getValue());
114 | }
115 | request.getRequestDispatcher(ConfigHelper.getAppJspPath() + viewPath).forward(request, response);
116 | }
117 |
118 | } else if (result instanceof ServerResponse) {
119 | // 给浏览器写回 data 数据
120 | ServerResponse data = (ServerResponse) result;
121 | Object model = data.getModel();
122 | if (model != null) {
123 | response.setContentType("application/json");
124 | response.setCharacterEncoding("UTF-8");
125 | PrintWriter writer = response.getWriter();
126 | String json = JsonUtil.toJson(model);
127 | writer.write(json);
128 | writer.flush();
129 | writer.close();
130 | }
131 |
132 | } else {
133 | LOGGER.error("未知的返回类型 result= " + result);
134 | }
135 |
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/Handler.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | import java.lang.reflect.Method;
4 |
5 | /**
6 | * 处理器 : controller.action
7 | */
8 | public class Handler {
9 |
10 | private Class> controller;
11 |
12 | private Method actionMethod;
13 |
14 | public Handler() {
15 | }
16 |
17 | public Handler(Class> controller, Method actionMethod) {
18 | this.controller = controller;
19 | this.actionMethod = actionMethod;
20 | }
21 |
22 | public Class> getController() {
23 | return controller;
24 | }
25 |
26 | public void setController(Class> controller) {
27 | this.controller = controller;
28 | }
29 |
30 | public Method getActionMethod() {
31 | return actionMethod;
32 | }
33 |
34 | public void setActionMethod(Method actionMethod) {
35 | this.actionMethod = actionMethod;
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return "Handler{" +
41 | "controller=" + controller +
42 | ", actionMethod=" + actionMethod +
43 | '}';
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/ModelAndView.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * handler 返回 view ,跳转页面
7 | */
8 | public class ModelAndView {
9 |
10 | private String path;
11 |
12 | /**
13 | * 携带的数据
14 | */
15 | private Map model;
16 |
17 | public ModelAndView(String path) {
18 | this.path = path;
19 | }
20 |
21 | public String getPath() {
22 | return path;
23 | }
24 |
25 | public void setPath(String path) {
26 | this.path = path;
27 | }
28 |
29 | public Map getModel() {
30 | return model;
31 | }
32 |
33 | public void setModel(Map model) {
34 | this.model = model;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/Request.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | import java.util.Objects;
4 |
5 | /**
6 | * 请求对象 : 请求方法 + 请求路径
7 | */
8 | public class Request {
9 |
10 | private String method;
11 | private String path;
12 |
13 | public Request() {
14 | }
15 |
16 | public Request(String method, String path) {
17 | this.method = method;
18 | this.path = path;
19 | }
20 |
21 | public String getMethod() {
22 | return method;
23 | }
24 |
25 | public void setMethod(String method) {
26 | this.method = method;
27 | }
28 |
29 | public String getPath() {
30 | return path;
31 | }
32 |
33 | public void setPath(String path) {
34 | this.path = path;
35 | }
36 |
37 | @Override
38 | public boolean equals(Object o) {
39 | if (this == o)
40 | return true;
41 | if (o == null || getClass() != o.getClass())
42 | return false;
43 | Request request = (Request) o;
44 | return Objects.equals(method, request.method) &&
45 | Objects.equals(path, request.path);
46 | }
47 |
48 | @Override
49 | public int hashCode() {
50 |
51 | return Objects.hash(method, path);
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "Request{" +
57 | "method='" + method + '\'' +
58 | ", path='" + path + '\'' +
59 | '}';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/RequestParam.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | import com.bcc.util.CastUtil;
4 |
5 | import java.util.Map;
6 |
7 | /**
8 | * 请求参数
9 | */
10 | public class RequestParam {
11 |
12 | private Map paramMap;
13 |
14 | public RequestParam(Map paramMap) {
15 | this.paramMap = paramMap;
16 | }
17 |
18 | public Map getParamMap() {
19 | return paramMap;
20 | }
21 |
22 | public long getLong(String name) {
23 | return CastUtil.castInt(paramMap.get(name));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/bcc/web/ServerResponse.java:
--------------------------------------------------------------------------------
1 | package com.bcc.web;
2 |
3 | /**
4 | * 返回数据
5 | */
6 | public class ServerResponse {
7 |
8 | private Object model;
9 |
10 | public Object getModel() {
11 | return model;
12 | }
13 |
14 | public void setModel(Object model) {
15 | this.model = model;
16 | }
17 |
18 | public ServerResponse(Object model) {
19 | this.model = model;
20 | }
21 |
22 | public ServerResponse() {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=ERROR,console,file
2 |
3 | log4j.appender.console=org.apache.log4j.ConsoleAppender
4 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
5 | log4j.appender.console.layout.ConversionPattern=%m%n
6 |
7 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
8 | log4j.appender.file.File=${user.home}/logs/book.log
9 | log4j.appender.file.DatePattern='_'yyyyMMdd
10 | log4j.appender.file.layout=org.apache.log4j.PatternLayout
11 | log4j.appender.file.layout.ConversionPattern=%d{HH:mm:ss,SSS} %p %c (%L) - %m%n
12 |
13 | log4j.logger.org.smart4j=DEBUG
--------------------------------------------------------------------------------
/src/main/resources/smart.properties:
--------------------------------------------------------------------------------
1 | #mysql
2 | #smart.framework.jdbc.driver=com.mysql.jdbc.Driver
3 | #smart.framework.jdbc.url=jdbc:mysql://localhost:3306/javaweb01
4 | #smart.framework.jdbc.username=root
5 | #smart.framework.jdbc.password=root
6 | #smart.framework.app.base_package=com.bcc
7 | #smart.framework.app.jsp_path=/WEB-INF/view
8 | #smart.framework.app.asset_path=/asset/
--------------------------------------------------------------------------------