├── .idea
├── .gitignore
├── JavaSceneConfigState.xml
├── codeStyles
│ └── codeStyleConfig.xml
├── compiler.xml
├── encodings.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── jarRepositories.xml
├── misc.xml
├── uiDesigner.xml
└── vcs.xml
├── LICENSE
├── README-EN.md
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── enndfp
│ │ ├── demo
│ │ ├── HelloServlet.java
│ │ ├── aspect
│ │ │ └── ControllerTimeCalculatorAspect.java
│ │ ├── controller
│ │ │ ├── frontend
│ │ │ │ └── MainPageController.java
│ │ │ └── superadmin
│ │ │ │ ├── HeadLineOperationController.java
│ │ │ │ └── ShopCategoryOperationController.java
│ │ ├── entity
│ │ │ ├── bo
│ │ │ │ ├── HeadLine.java
│ │ │ │ └── ShopCategory.java
│ │ │ └── dto
│ │ │ │ ├── MainPageInfoDTO.java
│ │ │ │ └── Result.java
│ │ └── service
│ │ │ ├── combine
│ │ │ ├── HeadLineShopCategoryCombineService.java
│ │ │ └── impl
│ │ │ │ └── HeadLineShopCategoryCombineServiceImpl.java
│ │ │ └── solo
│ │ │ ├── HeadLineService.java
│ │ │ ├── ShopCategoryService.java
│ │ │ └── impl
│ │ │ ├── HeadLineServiceImpl.java
│ │ │ └── ShopCategoryServiceImpl.java
│ │ └── simpleframework
│ │ ├── aop
│ │ ├── AspectListExecutor.java
│ │ ├── AspectWeaver.java
│ │ ├── ProxyCreator.java
│ │ ├── annotation
│ │ │ ├── Aspect.java
│ │ │ └── Order.java
│ │ └── aspect
│ │ │ ├── AspectInfo.java
│ │ │ ├── DefaultAspect.java
│ │ │ └── PointcutLocator.java
│ │ ├── core
│ │ ├── BeanContainer.java
│ │ └── annotation
│ │ │ ├── Component.java
│ │ │ ├── Controller.java
│ │ │ ├── Repository.java
│ │ │ └── Service.java
│ │ ├── inject
│ │ ├── DependencyInjector.java
│ │ └── annotation
│ │ │ └── Autowired.java
│ │ ├── mvc
│ │ ├── DispatcherServlet.java
│ │ ├── RequestProcessorChain.java
│ │ ├── annotation
│ │ │ ├── RequestMapping.java
│ │ │ ├── RequestParam.java
│ │ │ └── ResponseBody.java
│ │ ├── processor
│ │ │ ├── RequestProcessor.java
│ │ │ └── impl
│ │ │ │ ├── ControllerRequestProcessor.java
│ │ │ │ ├── JspRequestProcessor.java
│ │ │ │ ├── PreRequestProcessor.java
│ │ │ │ └── StaticResourceRequestProcessor.java
│ │ ├── render
│ │ │ ├── ResultRender.java
│ │ │ └── impl
│ │ │ │ ├── DefaultResultRender.java
│ │ │ │ ├── InternalErrorResultRender.java
│ │ │ │ ├── JsonResultRender.java
│ │ │ │ ├── ResourceNotFoundResultRender.java
│ │ │ │ └── ViewResultRender.java
│ │ └── type
│ │ │ ├── ControllerMethod.java
│ │ │ ├── ModelAndView.java
│ │ │ ├── RequestMethod.java
│ │ │ └── RequestPathInfo.java
│ │ └── utils
│ │ ├── ClassUtil.java
│ │ ├── ConverterUtil.java
│ │ └── ValidationUtil.java
├── resources
│ └── log4j.properties
└── webapp
│ ├── WEB-INF
│ └── jsp
│ │ └── hello.jsp
│ ├── static
│ └── coding.jpg
│ └── templates
│ └── addheadline.jsp
└── test
└── java
└── com
└── enndfp
└── simpleframework
├── aop
├── AspectListExecutorTest.java
├── AspectWeaverTest.java
└── mock
│ ├── Mock1.java
│ ├── Mock2.java
│ ├── Mock3.java
│ ├── Mock4.java
│ └── Mock5.java
├── core
└── BeanContainerTest.java
├── inject
└── DependencyInjectorTest.java
└── utils
└── ClassUtilTest.java
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/JavaSceneConfigState.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Enndfp
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-EN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [简体中文](README.md) | **English**
4 |
5 |
6 |
🌟 SimpleFramework
7 |
8 |
9 |
10 | 🛠️ Wheel-making project: Implementing the Spring framework from scratch
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ## 📖 Project Description
27 |
28 | > The Spring framework occupies a pivotal position in the Java development world, mainly due to its easy-to-understand and powerful features. It widely applies a variety of design patterns to provide a standardized architecture for the project. More importantly, Spring, as an open source framework, provides developers with opportunities to learn and improve, and brings an innovative spring breeze to Java development.
29 | >
30 | > In view of these advantages of Spring, many Java developers are eager to use basic technologies to implement a framework similar to Spring. This approach is not only an in-depth understanding of Spring architecture and design concepts, but also a demonstration of technical capabilities. Therefore, the "simple-framework" project came into being, aiming to implement a simplified version of the Spring framework so that developers can more easily understand its core concepts and at the same time improve their technical level in the field of Java development.
31 |
32 | **Simple-Framework is a free open source project that provides an easy-to-use and learn Java development framework for all individuals and enterprises, supporting the common progress and innovation of the developer community. **
33 |
34 | ## 🚀 Technical Highlights
35 |
36 | - **Java 1.8**: Provides optimized performance and stability and is the cornerstone of Java development.
37 | - **CGLIB 3.3.0 & AspectJWeaver 1.9.5**: Powerful libraries that provide a solid foundation for AOP.
38 | - **Java Servlet API & Gson & Lombok**: These technologies together form a powerful web application development environment.
39 |
40 | ## 📚 Project architecture diagram
41 |
42 | ### 🔄 IOC
43 |
44 | 
45 |
46 | ### 🔀 AOP
47 |
48 | 
49 |
50 | ### 🕸️ MVC
51 |
52 | 
53 |
54 | ## ✨ The main function
55 |
56 | This project is a **simple version of the Spring Framework** that implements the three core functions of the Spring Framework: **IOC** (Inversion of Control), **AOP** (Aspect-Oriented Programming) and **MVC* * (Model-View-Controller) and split it into the following core packages:
57 |
58 | #### 📦 Core package
59 |
60 | **Function**: The Core package implements the **core functions** of the framework, including **Bean scanning and loading**, **container maintenance**, **single case mode implementation**, and** Handling of custom beans**.
61 |
62 | **Implementation method**: Use **Java reflection mechanism** to dynamically scan and load classes under specified packages, identify and process different types of annotations (such as `@Component`, `@Controller`, etc.) to manage different types of Beans. At the same time, it implements the **single case mode**, ensuring that each Bean is instantiated only once, and provides basic methods for operating Beans, such as adding, obtaining, and managing Bean instances.
63 |
64 | #### 💉 Inject package
65 |
66 | **Function**: The Inject package is responsible for **dependency injection**, including processing `@Autowired` annotations, implementing **dependency injection in singleton mode**, and injecting implementation classes for **interfaces**.
67 |
68 | **Implementation method**: Scan the fields of the Bean through the **Java reflection mechanism** to find the fields with the `@Autowired` annotation, and use the Bean container to obtain and inject the required dependencies. It supports dependency injection in singleton mode to ensure the consistency and uniqueness of dependencies. At the same time, it can also dynamically inject appropriate implementation classes into the interface, improving the flexibility and maintainability of the code.
69 |
70 | #### 🔍 AOP package
71 |
72 | **Function**: The AOP package follows the **aspect-oriented programming idea**, uses `Aspect` and `Order` annotations to identify and sort aspect classes, and implements horizontal aspects through **CGlib dynamic proxy** and **AspectJWeaver** Weave in all logic and dynamically modify method logic.
73 |
74 | **Implementation method**: Use **CGlib** to create a proxy of the target class, and intercept method calls by implementing the `MethodInterceptor` interface. This allows aspect logic (such as logging, permission checks, etc.) to be performed before and after method execution. At the same time, the expression language of **AspectJ** provides more precise control over the proxy class, allowing the method logic to be modified and enhanced according to different needs.
75 |
76 | #### 🌐 MVC package
77 |
78 | **Function**: MVC package handles **request distribution related functions**, including reconstructing `DispatcherServlet`, implementing `RequestProcessorChain` and `RequestProcessor` matrices, and `ResultRender` matrix to complete various request processing and response rendering .
79 |
80 | **Implementation**: Use `DispatcherServlet` as the **central controller** to process all HTTP requests and distribute them to the corresponding processors. Use `RequestProcessorChain` to manage and execute a series of request processors to handle different types of requests (such as static resources, controller methods, etc.). The `ResultRender` matrix is responsible for selecting an appropriate rendering strategy based on the processing results, such as rendering an HTML page or returning JSON data, ensuring that the response is correctly rendered and returned to the client.
81 |
82 | ## 💡 Quick start guide
83 |
84 | To get started using **SimpleFramework**, you can take the following steps:
85 |
86 | ### 📥 Method 1: Use source code
87 |
88 | 1. Clone the repository:
89 |
90 | ```bash
91 | git clone https://github.com/Enndfp/simple-framework.git
92 | ```
93 |
94 | 2. Import the project into your IDE (eg IntelliJ IDEA).
95 |
96 | 3. Perform relevant tests in the `demo` directory. This is similar to developing projects with Spring Boot.
97 |
98 | ### 📦 Method 2: War package deployment
99 |
100 | 1. Build the project and generate the War package.
101 | 2. Deploy the War package to your Servlet container, such as Apache Tomcat.
102 | 3. Start the container and the application will be deployed automatically.
103 |
104 | ### 🌟 Sample code
105 |
106 | Here is a simple example showing how to use **SimpleFramework** in your project:
107 |
108 | ```java
109 | import com.simpleframework.core.BeanContainer;
110 |
111 | public class MyApplication {
112 | public static void main(String[] args) {
113 | //Initialize container
114 | BeanContainer container = BeanContainer.getInstance();
115 | container.loadBeans("com.yourpackage");
116 |
117 | // Use the container to get the Bean
118 | MyService myService = (MyService) container.getBean(MyService.class);
119 | myService.doSomething();
120 | }
121 | }
122 | ```
123 |
124 | In this example, we first obtain an instance of `BeanContainer` and then load all beans under the specified package path. After that, we get an instance of the `MyService` class from the container and call its methods.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | **简体中文** | [English](README-EN.md)
4 |
5 |
6 |
🌟 SimpleFramework
7 |
8 |
9 |
10 | 🛠️ 造轮子项目:从头实现Spring框架
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ## 📖 项目简介
26 |
27 | > Spring框架在Java开发界占据了举足轻重的地位,这主要归功于其易于理解和功能强大的特性。它广泛应用了多种设计模式,为项目提供了规范化的架构。更重要的是,Spring作为一个开源框架,为广大开发者提供了学习和提升的机会,为Java开发带来了一种革新的春风。
28 | >
29 | > 鉴于Spring的这些优势,很多Java开发者渴望使用基础技术来实现一个类似于Spring的框架。这种做法不仅是对Spring架构和设计理念的深入理解,也是一种技术能力的展示。因此,“simple-framework”项目应运而生,旨在通过实现一个简化版的Spring框架,使开发者更容易地理解其核心概念,同时也能够提升自己在Java开发领域的技术水平。
30 |
31 | **Simple-Framework是一个免费的开源项目,面向所有个人和企业,提供易于使用和学习的Java开发框架,支持开发者社区的共同进步与创新。**
32 |
33 | ## 🚀 技术亮点
34 |
35 | - **Java 1.8**: 提供优化的性能和稳定性,是Java开发的基石。
36 | - **CGLIB 3.3.0 & AspectJWeaver 1.9.5**: 强大的库,为AOP提供了坚实的基础。
37 | - **Java Servlet API & Gson & Lombok**: 这些技术共同构成了一个强大的Web应用开发环境。
38 |
39 | ## 📚 项目架构图
40 |
41 | ### 🔄 IOC
42 |
43 | 
44 |
45 | ### 🔀 AOP
46 |
47 | 
48 |
49 | ### 🕸️ MVC
50 |
51 | 
52 |
53 | ## ✨ 主要功能
54 |
55 | 本项目是一个**简易版本的Spring框架**,实现了Spring框架的三大核心功能:**IOC**(控制反转)、**AOP**(面向切面编程)和**MVC**(模型-视图-控制器),并将其分为以下核心包:
56 |
57 | #### 📦 Core包
58 |
59 | **功能**: Core包实现了框架的**核心功能**,包括**Bean的扫描加载**、**容器的维护**、**单例模式的实现**,以及**自定义Bean的处理**。
60 |
61 | **实现方式**: 利用**Java反射机制**动态扫描和加载指定包下的类,识别并处理不同类型的注解(如 `@Component`, `@Controller` 等)以管理不同种类的Bean。同时,它实现了**单例模式**,确保每个Bean只被实例化一次,并提供了操作Bean的基本方法,例如添加、获取和管理Bean实例。
62 |
63 | #### 💉 Inject包
64 |
65 | **功能**: Inject包负责**依赖注入**,包括处理 `@Autowired` 注解,实现**单例模式下的依赖注入**,以及为**接口注入实现类**。
66 |
67 | **实现方式**: 通过**Java反射机制**扫描Bean的字段,查找带有 `@Autowired` 注解的字段,并利用Bean容器获取并注入所需依赖。它支持单例模式下的依赖注入,确保依赖的一致性和唯一性。同时,它也能为接口动态地注入适当的实现类,提高了代码的灵活性和可维护性。
68 |
69 | #### 🔍 AOP包
70 |
71 | **功能**: AOP包遵循**面向切面编程思想**,使用 `Aspect` 和 `Order` 注解来标识和排序切面类,通过**CGlib动态代理**和**AspectJWeaver**实现横切逻辑的织入,动态修改方法逻辑。
72 |
73 | **实现方式**: 利用**CGlib**创建目标类的代理,并通过实现 `MethodInterceptor` 接口来拦截方法调用。这允许在方法执行前后执行切面逻辑(如日志记录、权限检查等)。同时,通过**AspectJ**的表达式语言提供对被代理类更精细的控制,使得可以根据不同的需要对方法逻辑进行修改和增强。
74 |
75 | #### 🌐 MVC包
76 |
77 | **功能**: MVC包处理**请求分发相关功能**,包括重构 `DispatcherServlet`,实现 `RequestProcessorChain` 和 `RequestProcessor` 矩阵,以及 `ResultRender` 矩阵,完成多种请求的处理与响应渲染。
78 |
79 | **实现方式**: 通过 `DispatcherServlet` 作为**中心控制器**,处理所有的HTTP请求并将其分发到相应的处理器。利用 `RequestProcessorChain` 管理和执行一系列请求处理器,以处理不同类型的请求(如静态资源、控制器方法等)。`ResultRender` 矩阵负责根据处理结果选择合适的渲染策略,例如渲染HTML页面或返回JSON数据,确保响应正确地渲染和返回给客户端。
80 |
81 | ## 💡 快速上手指南
82 |
83 | 要开始使用 **SimpleFramework**,您可以采取以下步骤:
84 |
85 | ### 📥 方法一:源码使用
86 |
87 | 1. 克隆仓库:
88 |
89 | ```bash
90 | git clone https://github.com/Enndfp/simple-framework.git
91 | ```
92 |
93 | 2. 导入项目到您的IDE(例如IntelliJ IDEA)。
94 |
95 | 3. 在 `demo` 目录下进行相关测试。这与使用Spring Boot开发项目类似。
96 |
97 | ### 📦 方法二:War包部署
98 |
99 | 1. 构建项目并生成War包。
100 | 2. 将War包部署到您的Servlet容器中,如Apache Tomcat。
101 | 3. 启动容器,应用将自动部署。
102 |
103 | ### 🌟 示例代码
104 |
105 | 以下是一个简单的示例,展示了如何在您的项目中使用 **SimpleFramework**:
106 |
107 | ```java
108 | import com.simpleframework.core.BeanContainer;
109 |
110 | public class MyApplication {
111 | public static void main(String[] args) {
112 | // 初始化容器
113 | BeanContainer container = BeanContainer.getInstance();
114 | container.loadBeans("com.yourpackage");
115 |
116 | // 使用容器获取Bean
117 | MyService myService = (MyService) container.getBean(MyService.class);
118 | myService.doSomething();
119 | }
120 | }
121 | ```
122 |
123 | 在这个例子中,我们首先获取了 `BeanContainer` 的实例,然后加载了指定包路径下的所有Bean。之后,我们从容器中获取了 `MyService` 类的实例,并调用了其方法。
124 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.enndfp
8 | simple-framework
9 | 1.0-SNAPSHOT
10 | war
11 |
12 |
13 | 8
14 | 8
15 | UTF-8
16 |
17 |
18 |
19 |
20 | cglib
21 | cglib
22 | 3.3.0
23 |
24 |
25 | org.aspectj
26 | aspectjweaver
27 | 1.9.5
28 |
29 |
30 | javax.servlet
31 | javax.servlet-api
32 | 4.0.1
33 | provided
34 |
35 |
36 | javax.servlet.jsp
37 | javax.servlet.jsp-api
38 | 2.3.3
39 | provided
40 |
41 |
42 | com.google.code.gson
43 | gson
44 | 2.8.6
45 |
46 |
47 | org.slf4j
48 | slf4j-log4j12
49 | 1.7.28
50 |
51 |
52 | org.projectlombok
53 | lombok
54 | 1.18.30
55 |
56 |
57 | org.junit.jupiter
58 | junit-jupiter-api
59 | 5.5.2
60 | test
61 |
62 |
63 |
64 | simple-framework
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-compiler-plugin
70 | 3.8.1
71 |
72 | 8
73 | 8
74 |
75 |
76 |
77 | org.apache.tomcat.maven
78 | tomcat7-maven-plugin
79 | 2.2
80 |
81 | /${project.artifactId}
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/HelloServlet.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import javax.servlet.ServletException;
8 | import javax.servlet.annotation.WebServlet;
9 | import javax.servlet.http.HttpServlet;
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.io.IOException;
13 |
14 | /**
15 | * @author Enndfp
16 | */
17 | @Slf4j
18 | @WebServlet("/hello")
19 | public class HelloServlet extends HttpServlet {
20 | @Override
21 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
22 | String name = "我的简易框架";
23 | log.debug("name is " + name);
24 | req.setAttribute("name", name);
25 | req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req, resp);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/aspect/ControllerTimeCalculatorAspect.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.aspect;
2 |
3 | import com.enndfp.simpleframework.aop.annotation.Aspect;
4 | import com.enndfp.simpleframework.aop.annotation.Order;
5 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | import java.lang.reflect.Method;
9 |
10 | /**
11 | * @author Enndfp
12 | */
13 | @Slf4j
14 | @Aspect(pointcut = "execution(* com.enndfp.demo.controller..*.*(..))")
15 | @Order(0)
16 | public class ControllerTimeCalculatorAspect extends DefaultAspect {
17 | private long timestampCache;
18 |
19 | @Override
20 | public void before(Class> targetClass, Method method, Object[] args) throws Throwable {
21 | log.info("开始计时,执行的类是[{}],执行的方法是[{}],参数是[{}]",
22 | targetClass.getName(), method.getName(), args);
23 | this.timestampCache = System.currentTimeMillis();
24 | }
25 |
26 | @Override
27 | public Object afterReturning(Class> targetClass, Method method, Object[] args, Object returnValue) {
28 | long endTime = System.currentTimeMillis();
29 | long costTime = endTime - this.timestampCache;
30 | log.info("结束计时,执行的类是[{}],执行的方法是[{}],参数是[{}],返回值是[{}],时间为[{}]ms",
31 | targetClass.getName(), method.getName(), args, returnValue, costTime);
32 | return returnValue;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/controller/frontend/MainPageController.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.controller.frontend;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.dto.MainPageInfoDTO;
5 | import com.enndfp.demo.entity.dto.Result;
6 | import com.enndfp.demo.service.combine.HeadLineShopCategoryCombineService;
7 | import com.enndfp.simpleframework.core.annotation.Controller;
8 | import com.enndfp.simpleframework.inject.annotation.Autowired;
9 | import com.enndfp.simpleframework.mvc.annotation.RequestMapping;
10 | import com.enndfp.simpleframework.mvc.annotation.RequestParam;
11 | import com.enndfp.simpleframework.mvc.annotation.ResponseBody;
12 | import com.enndfp.simpleframework.mvc.type.ModelAndView;
13 | import com.enndfp.simpleframework.mvc.type.RequestMethod;
14 | import lombok.Getter;
15 |
16 | import javax.servlet.http.HttpServletRequest;
17 | import javax.servlet.http.HttpServletResponse;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * @author Enndfp
23 | */
24 | @Controller
25 | @Getter
26 | @RequestMapping("/main")
27 | public class MainPageController {
28 | @Autowired()
29 | private HeadLineShopCategoryCombineService headLineShopCategoryCombineService;
30 |
31 | /**
32 | * 获取主页信息
33 | *
34 | * @param req
35 | * @param resp
36 | * @return
37 | */
38 | public Result getMainPageInfo(HttpServletRequest req, HttpServletResponse resp) {
39 | return headLineShopCategoryCombineService.getMainPageInfo();
40 | }
41 |
42 | @RequestMapping(value = "/test1", method = RequestMethod.GET)
43 | public void getTest() {
44 | System.out.println("调用test1方法");
45 | return;
46 | }
47 |
48 | @RequestMapping(value = "/test2", method = RequestMethod.GET)
49 | public void getTest2() {
50 | System.out.println("调用test2方法");
51 | throw new RuntimeException("test error");
52 | }
53 |
54 | @RequestMapping(value = "/test3", method = RequestMethod.GET)
55 | @ResponseBody
56 | public Result queryList() {
57 | List headLineList = new ArrayList<>();
58 | HeadLine headLine1 = new HeadLine();
59 | headLine1.setLineId(1L);
60 | headLine1.setLineName("头条1");
61 | headLine1.setLineLink("www.baidu.com");
62 | headLine1.setLineImg("头条图片1地址");
63 | headLineList.add(headLine1);
64 | HeadLine headLine2 = new HeadLine();
65 | headLine2.setLineId(2L);
66 | headLine2.setLineName("头条2");
67 | headLine2.setLineLink("www.google.com");
68 | headLine2.setLineImg("头条图片2地址");
69 | headLineList.add(headLine2);
70 | return Result.ok(headLineList);
71 | }
72 |
73 | @RequestMapping(value = "/add", method = RequestMethod.POST)
74 | public ModelAndView add(@RequestParam("lineName") String lineName
75 | , @RequestParam("lineLink") String lineLink
76 | , @RequestParam("lineImg") String lineImg
77 | , @RequestParam("priority") Integer priority) {
78 | HeadLine headLine = new HeadLine();
79 | headLine.setLineLink(lineLink);
80 | headLine.setLineImg(lineImg);
81 | headLine.setLineName(lineName);
82 | headLine.setPriority(priority);
83 | System.out.println(headLine);
84 | Result result = new Result<>(200, "请求成功", true);
85 | ModelAndView modelAndView = new ModelAndView();
86 | modelAndView.setViewPath("addheadline.jsp").addViewData("result", result);
87 | return modelAndView;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/controller/superadmin/HeadLineOperationController.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.controller.superadmin;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.dto.Result;
5 | import com.enndfp.demo.service.solo.HeadLineService;
6 | import com.enndfp.simpleframework.core.annotation.Controller;
7 | import com.enndfp.simpleframework.inject.annotation.Autowired;
8 |
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.util.List;
12 |
13 | /**
14 | * @author Enndfp
15 | */
16 | @Controller
17 | public class HeadLineOperationController {
18 |
19 | @Autowired
20 | private HeadLineService headLineService;
21 |
22 | /**
23 | * 添加头条
24 | *
25 | * @param req
26 | * @param resp
27 | * @return
28 | */
29 | public Result addHeadLine(HttpServletRequest req, HttpServletResponse resp) {
30 | return headLineService.addHeadLine(new HeadLine());
31 | }
32 |
33 | /**
34 | * 删除头条
35 | *
36 | * @param req
37 | * @param resp
38 | * @return
39 | */
40 | public Result removeHeadLine(HttpServletRequest req, HttpServletResponse resp) {
41 | return headLineService.removeHeadLine(1);
42 | }
43 |
44 | /**
45 | * 修改头条
46 | *
47 | * @param req
48 | * @param resp
49 | * @return
50 | */
51 | public Result modifyHeadLine(HttpServletRequest req, HttpServletResponse resp) {
52 | return headLineService.modifyHeadLine(new HeadLine());
53 | }
54 |
55 | /**
56 | * 查询头条
57 | *
58 | * @param req
59 | * @param resp
60 | * @return
61 | */
62 | public Result queryHeadLineById(HttpServletRequest req, HttpServletResponse resp) {
63 | return headLineService.queryHeadLineById(1);
64 | }
65 |
66 | /**
67 | * 查询头条列表
68 | *
69 | * @param req
70 | * @param resp
71 | * @return
72 | */
73 | public Result> queryHeadLine(HttpServletRequest req, HttpServletResponse resp) {
74 | return headLineService.queryHeadLine(null, 1, 100);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/controller/superadmin/ShopCategoryOperationController.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.controller.superadmin;
2 |
3 | import com.enndfp.demo.entity.bo.ShopCategory;
4 | import com.enndfp.demo.entity.dto.Result;
5 | import com.enndfp.demo.service.solo.ShopCategoryService;
6 | import com.enndfp.simpleframework.core.annotation.Controller;
7 | import com.enndfp.simpleframework.inject.annotation.Autowired;
8 |
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.util.List;
12 |
13 | /**
14 | * @author Enndfp
15 | */
16 | @Controller
17 | public class ShopCategoryOperationController {
18 |
19 | @Autowired
20 | private ShopCategoryService shopCategoryService;
21 |
22 | /**
23 | * 添加店铺类别
24 | *
25 | * @param req
26 | * @param resp
27 | * @return
28 | */
29 | public Result addShopCategory(HttpServletRequest req, HttpServletResponse resp) {
30 | return shopCategoryService.addShopCategory(new ShopCategory());
31 | }
32 |
33 | /**
34 | * 删除店铺类别
35 | *
36 | * @param req
37 | * @param resp
38 | * @return
39 | */
40 | public Result removeShopCategory(HttpServletRequest req, HttpServletResponse resp) {
41 | return shopCategoryService.removeShopCategory(1);
42 | }
43 |
44 | /**
45 | * 修改店铺类别
46 | *
47 | * @param req
48 | * @param resp
49 | * @return
50 | */
51 | public Result modifyShopCategory(HttpServletRequest req, HttpServletResponse resp) {
52 | return shopCategoryService.modifyShopCategory(new ShopCategory());
53 | }
54 |
55 | /**
56 | * 查询店铺类别
57 | *
58 | * @param req
59 | * @param resp
60 | * @return
61 | */
62 | public Result queryShopCategoryById(HttpServletRequest req, HttpServletResponse resp) {
63 | return shopCategoryService.queryShopCategoryById(1);
64 | }
65 |
66 | /**
67 | * 查询店铺类别列表
68 | *
69 | * @param req
70 | * @param resp
71 | * @return
72 | */
73 | public Result> queryShopCategory(HttpServletRequest req, HttpServletResponse resp) {
74 | return shopCategoryService.queryShopCategory(new ShopCategory(), 1, 100);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/entity/bo/HeadLine.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.entity.bo;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * @author Enndfp
9 | */
10 | @Data
11 | public class HeadLine {
12 |
13 | private Long lineId;
14 |
15 | private String lineName;
16 |
17 | private String lineLink;
18 |
19 | private String lineImg;
20 |
21 | private Integer priority;
22 |
23 | private Integer enableStatus;
24 |
25 | private Date createTime;
26 |
27 | private Date lastEditTime;
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/entity/bo/ShopCategory.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.entity.bo;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * @author Enndfp
9 | */
10 | @Data
11 | public class ShopCategory {
12 |
13 | private Long shopCategoryId;
14 |
15 | private String shopCategoryName;
16 |
17 | private String shopCategoryDesc;
18 |
19 | private String shopCategoryImg;
20 |
21 | private Integer priority;
22 |
23 | private Date createTime;
24 |
25 | private Date lastEditTime;
26 |
27 | private ShopCategory parent;
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/entity/dto/MainPageInfoDTO.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.entity.dto;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.bo.ShopCategory;
5 | import lombok.Data;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * @author Enndfp
11 | */
12 | @Data
13 | public class MainPageInfoDTO {
14 |
15 | // 头条列表
16 | private List headLineList;
17 |
18 | // 店铺类别列表
19 | private List shopCategoryList;
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/entity/dto/Result.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.entity.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | @Data
9 | public class Result {
10 |
11 | // 本次请求结果的状态码,200表示成功
12 | private int code;
13 |
14 | // 本次请求结果的详情
15 | private String message;
16 |
17 | // 本次请求返回的结果集
18 | private T data;
19 |
20 | public Result(int code, String message, T data) {
21 | this.code = code;
22 | this.message = message;
23 | this.data = data;
24 | }
25 |
26 | public static Result ok(E data) {
27 | return new Result<>(200, "成功!", data);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/combine/HeadLineShopCategoryCombineService.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.combine;
2 |
3 | import com.enndfp.demo.entity.dto.Result;
4 | import com.enndfp.demo.entity.dto.MainPageInfoDTO;
5 |
6 | /**
7 | * @author Enndfp
8 | */
9 | public interface HeadLineShopCategoryCombineService {
10 |
11 | /**
12 | * 获取主页信息
13 | *
14 | * @return
15 | */
16 | Result getMainPageInfo();
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/combine/impl/HeadLineShopCategoryCombineServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.combine.impl;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.bo.ShopCategory;
5 | import com.enndfp.demo.entity.dto.Result;
6 | import com.enndfp.demo.service.combine.HeadLineShopCategoryCombineService;
7 | import com.enndfp.demo.service.solo.HeadLineService;
8 | import com.enndfp.demo.service.solo.ShopCategoryService;
9 | import com.enndfp.demo.entity.dto.MainPageInfoDTO;
10 | import com.enndfp.simpleframework.core.annotation.Service;
11 | import com.enndfp.simpleframework.inject.annotation.Autowired;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * @author Enndfp
18 | */
19 | @Slf4j
20 | @Service
21 | public class HeadLineShopCategoryCombineServiceImpl implements HeadLineShopCategoryCombineService {
22 |
23 | @Autowired
24 | private HeadLineService headLineService;
25 |
26 | @Autowired
27 | private ShopCategoryService shopCategoryService;
28 |
29 | @Override
30 | public Result getMainPageInfo() {
31 | log.info("getMainPageInfo方法被执行!");
32 | // 1. 获取头条列表
33 | HeadLine headLineCondition = new HeadLine();
34 | headLineCondition.setEnableStatus(1);
35 | Result> headLineResult = headLineService.queryHeadLine(headLineCondition, 1, 4);
36 |
37 | // 2. 获取店铺类别列表
38 | ShopCategory shopCategoryCondition = new ShopCategory();
39 | Result> shopCategoryResult = shopCategoryService.queryShopCategory(shopCategoryCondition, 1, 100);
40 |
41 | // 3. 合并两者并返回
42 | Result result = mergeMainPageInfoResult(headLineResult, shopCategoryResult);
43 | return result;
44 | }
45 |
46 | private Result mergeMainPageInfoResult(Result> headLineResult, Result> shopCategoryResult) {
47 | return null;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/solo/HeadLineService.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.solo;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.dto.Result;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author Enndfp
10 | */
11 | public interface HeadLineService {
12 | /**
13 | * 添加头条
14 | *
15 | * @param headLine
16 | * @return
17 | */
18 | Result addHeadLine(HeadLine headLine);
19 |
20 | /**
21 | * 删除头条
22 | *
23 | * @param headLineId
24 | * @return
25 | */
26 | Result removeHeadLine(int headLineId);
27 |
28 | /**
29 | * 修改头条
30 | *
31 | * @param headLine
32 | * @return
33 | */
34 | Result modifyHeadLine(HeadLine headLine);
35 |
36 | /**
37 | * 查询头条
38 | *
39 | * @param headLineId
40 | * @return
41 | */
42 | Result queryHeadLineById(int headLineId);
43 |
44 | /**
45 | * 查询头条列表
46 | *
47 | * @param headLineCondition
48 | * @param pageIndex
49 | * @param pageSize
50 | * @return
51 | */
52 | Result> queryHeadLine(HeadLine headLineCondition, int pageIndex, int pageSize);
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/solo/ShopCategoryService.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.solo;
2 |
3 | import com.enndfp.demo.entity.bo.ShopCategory;
4 | import com.enndfp.demo.entity.dto.Result;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author Enndfp
10 | */
11 | public interface ShopCategoryService {
12 | /**
13 | * 添加店铺类别
14 | *
15 | * @param shopCategory
16 | * @return
17 | */
18 | Result addShopCategory(ShopCategory shopCategory);
19 |
20 | /**
21 | * 删除店铺类别
22 | *
23 | * @param shopCategoryId
24 | * @return
25 | */
26 | Result removeShopCategory(int shopCategoryId);
27 |
28 | /**
29 | * 修改店铺类别
30 | *
31 | * @param shopCategory
32 | * @return
33 | */
34 | Result modifyShopCategory(ShopCategory shopCategory);
35 |
36 | /**
37 | * 查询店铺类别
38 | *
39 | * @param shopCategoryId
40 | * @return
41 | */
42 | Result queryShopCategoryById(int shopCategoryId);
43 |
44 | /**
45 | * 查询店铺类别列表
46 | *
47 | * @param shopCategoryCondition
48 | * @param pageIndex
49 | * @param pageSize
50 | * @return
51 | */
52 | Result> queryShopCategory(ShopCategory shopCategoryCondition, int pageIndex, int pageSize);
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/solo/impl/HeadLineServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.solo.impl;
2 |
3 | import com.enndfp.demo.entity.bo.HeadLine;
4 | import com.enndfp.demo.entity.dto.Result;
5 | import com.enndfp.demo.service.solo.HeadLineService;
6 | import com.enndfp.simpleframework.core.annotation.Service;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * @author Enndfp
12 | */
13 | @Service
14 | public class HeadLineServiceImpl implements HeadLineService {
15 | @Override
16 | public Result addHeadLine(HeadLine headLine) {
17 | return null;
18 | }
19 |
20 | @Override
21 | public Result removeHeadLine(int headLineId) {
22 | return null;
23 | }
24 |
25 | @Override
26 | public Result modifyHeadLine(HeadLine headLine) {
27 | return null;
28 | }
29 |
30 | @Override
31 | public Result queryHeadLineById(int headLineId) {
32 | return null;
33 | }
34 |
35 | @Override
36 | public Result> queryHeadLine(HeadLine headLineCondition, int pageIndex, int pageSize) {
37 | return null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/demo/service/solo/impl/ShopCategoryServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.demo.service.solo.impl;
2 |
3 | import com.enndfp.demo.entity.bo.ShopCategory;
4 | import com.enndfp.demo.entity.dto.Result;
5 | import com.enndfp.demo.service.solo.ShopCategoryService;
6 | import com.enndfp.simpleframework.core.annotation.Service;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * @author Enndfp
12 | */
13 | @Service
14 | public class ShopCategoryServiceImpl implements ShopCategoryService {
15 | @Override
16 | public Result addShopCategory(ShopCategory shopCategory) {
17 | return null;
18 | }
19 |
20 | @Override
21 | public Result removeShopCategory(int shopCategoryId) {
22 | return null;
23 | }
24 |
25 | @Override
26 | public Result modifyShopCategory(ShopCategory shopCategory) {
27 | return null;
28 | }
29 |
30 | @Override
31 | public Result queryShopCategoryById(int shopCategoryId) {
32 | return null;
33 | }
34 |
35 | @Override
36 | public Result> queryShopCategory(ShopCategory shopCategoryCondition, int pageIndex, int pageSize) {
37 | return null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/AspectListExecutor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.AspectInfo;
4 | import com.enndfp.simpleframework.utils.ValidationUtil;
5 | import lombok.Getter;
6 | import net.sf.cglib.proxy.MethodInterceptor;
7 | import net.sf.cglib.proxy.MethodProxy;
8 |
9 | import java.lang.reflect.Method;
10 | import java.util.Comparator;
11 | import java.util.Iterator;
12 | import java.util.List;
13 |
14 | /**
15 | * @author Enndfp
16 | */
17 | public class AspectListExecutor implements MethodInterceptor {
18 | // 被代理的类
19 | private Class> targetClass;
20 | // 排好序的Aspect列表
21 | @Getter
22 | private List sortedAspectInfoList;
23 |
24 | public AspectListExecutor(Class> targetClass, List aspectInfoList) {
25 | this.targetClass = targetClass;
26 | this.sortedAspectInfoList = sortAspectInfoList(aspectInfoList);
27 | }
28 |
29 | /**
30 | * 按照order的值进行升序排序,确保order值小的aspect先被织入
31 | *
32 | * @param aspectInfoList 切面集合
33 | * @return 排序好的切面集合
34 | */
35 | private List sortAspectInfoList(List aspectInfoList) {
36 | aspectInfoList.sort(new Comparator() {
37 | @Override
38 | public int compare(AspectInfo o1, AspectInfo o2) {
39 | return o1.getOrderIndex() - o2.getOrderIndex();
40 | }
41 | });
42 | return aspectInfoList;
43 | }
44 |
45 | /**
46 | * 横切逻辑
47 | *
48 | * @param proxy
49 | * @param method
50 | * @param args
51 | * @param methodProxy
52 | * @return
53 | * @throws Throwable
54 | */
55 | @Override
56 | public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
57 | Object returnValue = null;
58 | collectAccurateMatchedAspectList(method);
59 | if (ValidationUtil.isEmpty(sortedAspectInfoList)) {
60 | returnValue = methodProxy.invokeSuper(proxy, args);
61 | return returnValue;
62 | }
63 | // 1. 按照order的顺序升序执行完所有Aspect的before方法
64 | invokeBeforeAdvices(method, args);
65 | try {
66 | // 2. 执行被代理类的方法
67 | returnValue = methodProxy.invokeSuper(proxy, args);
68 | // 3. 如果被代理方法正常返回,则按照order的顺序降序执行完所有Aspect的afterReturning方法
69 | returnValue = invokeAfterReturningAdvices(method, args, returnValue);
70 | } catch (Exception e) {
71 | // 4. 如果被代理方法抛出异常,则按照order的顺序降序执行完所有Aspect的afterThrowing方法
72 | invokeAfterThrowingAdvices(method, args, e);
73 | }
74 | return returnValue;
75 | }
76 |
77 | /**
78 | * 精筛特定的方法
79 | *
80 | * @param method
81 | */
82 | private void collectAccurateMatchedAspectList(Method method) {
83 | if (ValidationUtil.isEmpty(sortedAspectInfoList)) return;
84 | // for-each不支持动态移除元素,改用迭代器
85 | Iterator iterator = sortedAspectInfoList.iterator();
86 | while (iterator.hasNext()) {
87 | AspectInfo aspectInfo = iterator.next();
88 | if (!aspectInfo.getPointcutLocator().accurateMatches(method)) {
89 | iterator.remove();
90 | }
91 | }
92 | }
93 |
94 | /**
95 | * 如果被代理方法抛出异常,则按照order的顺序降序执行完所有Aspect的afterThrowing方法
96 | *
97 | * @param method
98 | * @param args
99 | * @param e
100 | */
101 | private void invokeAfterThrowingAdvices(Method method, Object[] args, Exception e) throws Throwable {
102 | for (int i = sortedAspectInfoList.size() - 1; i >= 0; i--) {
103 | sortedAspectInfoList.get(i).getAspectObject().afterThrowing(targetClass, method, args, e);
104 | }
105 | }
106 |
107 | /**
108 | * 如果被代理方法正常返回,则按照order的顺序降序执行完所有Aspect的afterReturning方法
109 | *
110 | * @param method
111 | * @param args
112 | * @param returnValue
113 | * @return
114 | */
115 | private Object invokeAfterReturningAdvices(Method method, Object[] args, Object returnValue) throws Throwable {
116 | Object result = null;
117 | for (int i = sortedAspectInfoList.size() - 1; i >= 0; i--) {
118 | result = sortedAspectInfoList.get(i).getAspectObject().afterReturning(targetClass, method, args, returnValue);
119 | }
120 | return result;
121 | }
122 |
123 | /**
124 | * 按照order的顺序升序执行完所有Aspect的before方法
125 | *
126 | * @param method
127 | * @param args
128 | * @throws Throwable
129 | */
130 | private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
131 | for (AspectInfo aspectInfo : sortedAspectInfoList) {
132 | aspectInfo.getAspectObject().before(targetClass, method, args);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/AspectWeaver.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop;
2 |
3 | import com.enndfp.simpleframework.aop.annotation.Aspect;
4 | import com.enndfp.simpleframework.aop.annotation.Order;
5 | import com.enndfp.simpleframework.aop.aspect.AspectInfo;
6 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
7 | import com.enndfp.simpleframework.aop.aspect.PointcutLocator;
8 | import com.enndfp.simpleframework.core.BeanContainer;
9 | import com.enndfp.simpleframework.utils.ValidationUtil;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.Set;
14 |
15 | /**
16 | * @author Enndfp
17 | */
18 | public class AspectWeaver {
19 | private final BeanContainer beanContainer;
20 |
21 | public AspectWeaver() {
22 | this.beanContainer = BeanContainer.getInstance();
23 | }
24 |
25 | /**
26 | * 基于Aspectj实现
27 | */
28 | public void doAOP() {
29 | // 1. 获取所有的切面类
30 | Set> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
31 | if (ValidationUtil.isEmpty(aspectSet)) return;
32 | // 2. 拼装AspectInfoList
33 | List aspectInfoList = packAspectInfoList(aspectSet);
34 | // 3. 遍历容器中的类
35 | Set> classSet = beanContainer.getClasses();
36 | for (Class> targetClass : classSet) {
37 | // 排除AspectClass自身
38 | if (targetClass.isAnnotationPresent(Aspect.class)) continue;
39 | // 4. 粗筛符合条件的Aspect
40 | List roughMatchedAspectList = collectRoughMatchedAspectListForSpecificClass(aspectInfoList, targetClass);
41 | // 5. 尝试进行Aspect织入
42 | wrapIfNecessary(roughMatchedAspectList, targetClass);
43 | }
44 | }
45 |
46 | /**
47 | * 进行Aspect织入
48 | *
49 | * @param roughMatchedAspectList
50 | * @param targetClass
51 | */
52 | private void wrapIfNecessary(List roughMatchedAspectList, Class> targetClass) {
53 | // 1. 校验
54 | if (ValidationUtil.isEmpty(roughMatchedAspectList)) return;
55 | // 2. 创建动态代理对象
56 | AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass, roughMatchedAspectList);
57 | Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
58 | // 3. 将动态代理对象实例添加到容器中,取代未被代理前的类实例
59 | beanContainer.addBean(targetClass, proxyBean);
60 | }
61 |
62 | /**
63 | * 粗筛符合表达式的特定类
64 | *
65 | * @param aspectInfoList
66 | * @param targetClass
67 | * @return
68 | */
69 | private List collectRoughMatchedAspectListForSpecificClass(List aspectInfoList, Class> targetClass) {
70 | List roughMatchedAspectList = new ArrayList<>();
71 | for (AspectInfo aspectInfo : aspectInfoList) {
72 | // 将符合表达式的类加入到集合
73 | if (aspectInfo.getPointcutLocator().roughMatches(targetClass)) {
74 | roughMatchedAspectList.add(aspectInfo);
75 | }
76 | }
77 | return roughMatchedAspectList;
78 | }
79 |
80 | /**
81 | * 将所有被@Aspect标记的类拼接成List集合
82 | *
83 | * @param aspectSet 被标记的类集合
84 | * @return
85 | */
86 | private List packAspectInfoList(Set> aspectSet) {
87 | List aspectInfoList = new ArrayList<>();
88 | for (Class> aspectClass : aspectSet) {
89 | if (!verifyAspect(aspectClass)) {
90 | throw new RuntimeException("@Aspect and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect");
91 | }
92 | // 1. 获取标签值
93 | Order orderTag = aspectClass.getAnnotation(Order.class);
94 | Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
95 | // 2. 从容器中获取aspect实例
96 | DefaultAspect defaultAspect = (DefaultAspect) beanContainer.getBean(aspectClass);
97 | // 3. 初始化表达式定位器
98 | PointcutLocator pointcutLocator = new PointcutLocator(aspectTag.pointcut());
99 | AspectInfo aspectInfo = new AspectInfo(orderTag.value(), defaultAspect, pointcutLocator);
100 | aspectInfoList.add(aspectInfo);
101 | }
102 | return aspectInfoList;
103 | }
104 |
105 | /**
106 | * 验证被Aspect标记的类是否满足条件
107 | *
108 | * @param aspectClass Aspect标记的类
109 | * @return
110 | */
111 | private boolean verifyAspect(Class> aspectClass) {
112 | return aspectClass.isAnnotationPresent(Aspect.class) &&
113 | aspectClass.isAnnotationPresent(Order.class) &&
114 | DefaultAspect.class.isAssignableFrom(aspectClass);
115 | }
116 |
117 | // public void doAOP() {
118 | // // 1. 获取所有的切面类
119 | // Set> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);
120 | // // 2. 将切面类按照不同的织入目标进行分类
121 | // Map, List> categorizedWeavingTargetMap = new HashMap<>();
122 | // if (ValidationUtil.isEmpty(aspectSet)) return;
123 | // for (Class> aspectClass : aspectSet) {
124 | // if (!verifyAspect(aspectClass)) {
125 | // throw new RuntimeException("@Aspect and @Order have not been added to the Aspect class, " +
126 | // "or Aspect class does not extend from DefaultAspect, or the value in Aspect Tag equals @Aspect");
127 | // }
128 | // categorizeAspect(categorizedWeavingTargetMap, aspectClass);
129 | // }
130 | // // 3. 按照不同的织入目标分别去按序织入Aspect
131 | // if (ValidationUtil.isEmpty(categorizedWeavingTargetMap)) return;
132 | // for (Class extends Annotation> weavingTarget : categorizedWeavingTargetMap.keySet()) {
133 | // weaveByWeavingTarget(weavingTarget, categorizedWeavingTargetMap.get(weavingTarget));
134 | // }
135 | // }
136 |
137 | // /**
138 | // * 按照不同的织入目标分别去按序织入Aspect
139 | // *
140 | // * @param weavingTarget 织入目标
141 | // * @param aspectInfoList 切面类的集合
142 | // */
143 | // private void weaveByWeavingTarget(Class extends Annotation> weavingTarget, List aspectInfoList) {
144 | // // 1. 获取被代理类的集合
145 | // Set> targetClassSet = beanContainer.getClassesByAnnotation(weavingTarget);
146 | // if (ValidationUtil.isEmpty(targetClassSet)) return;
147 | // // 2. 遍历被代理类,分别为每个被代理类生成动态代理
148 | // for (Class> targetClass : targetClassSet) {
149 | // // 创建动态代理对象
150 | // AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass, aspectInfoList);
151 | // Object proxyBean = ProxyCreator.createProxy(targetClass, aspectListExecutor);
152 | // // 3. 将动态代理对象实例添加到容器中,取代未被代理前的类实例
153 | // beanContainer.addBean(targetClass, proxyBean);
154 | // }
155 | // }
156 | //
157 | // /**
158 | // * 将切面类按照不同的织入目标进行分类
159 | // *
160 | // * @param categorizedWeavingTargetMap 分类完成的织入目标Map
161 | // * @param aspectClass 待分类的切面类
162 | // */
163 | // private void categorizeAspect(Map, List> categorizedWeavingTargetMap, Class> aspectClass) {
164 | // // 1. 获取标签值
165 | // Order orderTag = aspectClass.getAnnotation(Order.class);
166 | // Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
167 | // // 2. 从容器中获取aspect实例
168 | // DefaultAspect aspect = (DefaultAspect) beanContainer.getBean(aspectClass);
169 | // AspectInfo aspectInfo = new AspectInfo(orderTag.value(), aspect);
170 | // // 3. 将切面类加入到对应的位置的Map
171 | // if (!categorizedWeavingTargetMap.containsKey(aspectTag.value())) {
172 | // categorizedWeavingTargetMap.put(aspectTag.value(), new ArrayList<>());
173 | // }
174 | // categorizedWeavingTargetMap.get(aspectTag.value()).add(aspectInfo);
175 | // }
176 | //
177 | // /**
178 | // * 验证被Aspect标记的类是否满足条件
179 | // *
180 | // * @param aspectClass Aspect标记的类
181 | // * @return
182 | // */
183 | // private boolean verifyAspect(Class> aspectClass) {
184 | // return aspectClass.isAnnotationPresent(Aspect.class) &&
185 | // aspectClass.isAnnotationPresent(Order.class) &&
186 | // DefaultAspect.class.isAssignableFrom(aspectClass) &&
187 | // aspectClass.getAnnotation(Aspect.class).value() != Aspect.class;
188 | // }
189 | }
190 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/ProxyCreator.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop;
2 |
3 | import net.sf.cglib.proxy.Enhancer;
4 | import net.sf.cglib.proxy.MethodInterceptor;
5 |
6 | /**
7 | * @author Enndfp
8 | */
9 | public class ProxyCreator {
10 | /**
11 | * 创建动态代理对象并返回
12 | *
13 | * @param targetClass 被代理的Class对象
14 | * @param methodInterceptor 方法拦截器
15 | * @return
16 | */
17 | public static Object createProxy(Class> targetClass, MethodInterceptor methodInterceptor) {
18 | return Enhancer.create(targetClass, methodInterceptor);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/annotation/Aspect.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | @Target(ElementType.TYPE)
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Aspect {
11 |
12 | // 切入点
13 | String pointcut();
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/annotation/Order.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | @Target(ElementType.TYPE)
9 | @Retention(RetentionPolicy.RUNTIME)
10 | public @interface Order {
11 |
12 | // 控制类的执行顺序,值越小优先级越高
13 | int value();
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/aspect/AspectInfo.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.aspect;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | /**
7 | * @author Enndfp
8 | */
9 | @AllArgsConstructor
10 | @Getter
11 | public class AspectInfo {
12 |
13 | private int orderIndex;
14 |
15 | private DefaultAspect aspectObject;
16 |
17 | private PointcutLocator pointcutLocator;
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/aspect/DefaultAspect.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.aspect;
2 |
3 | import java.lang.reflect.Method;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public abstract class DefaultAspect {
9 |
10 | /**
11 | * 事前拦截
12 | *
13 | * @param targetClass 被代理的目标类
14 | * @param method 被代理的目标方法
15 | * @param args 被代理的目标方法对应的参数列表
16 | * @throws Throwable 异常
17 | */
18 | public void before(Class> targetClass, Method method, Object[] args) throws Throwable {
19 |
20 | }
21 |
22 | /**
23 | * 正常返回后拦截
24 | *
25 | * @param targetClass 被代理的目标类
26 | * @param method 被代理的目标方法
27 | * @param args 被代理的目标方法对应的参数列表
28 | * @param returnValue 被代理的目标方法执行后的返回值
29 | * @return 返回值
30 | * @throws Throwable 异常
31 | */
32 | public Object afterReturning(Class> targetClass, Method method, Object[] args, Object returnValue) throws Throwable {
33 | return returnValue;
34 | }
35 |
36 | /**
37 | * 发生异常时拦截
38 | *
39 | * @param targetClass 被代理的目标类
40 | * @param method 被代理的目标方法
41 | * @param args 被代理的目标方法对应的参数列表
42 | * @param e 被代理的目标方法抛出的异常
43 | * @return 返回值
44 | * @throws Throwable 异常
45 | */
46 | public void afterThrowing(Class> targetClass, Method method, Object[] args, Throwable e) throws Throwable {
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/aop/aspect/PointcutLocator.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.aspect;
2 |
3 | import org.aspectj.weaver.tools.PointcutExpression;
4 | import org.aspectj.weaver.tools.PointcutParser;
5 | import org.aspectj.weaver.tools.ShadowMatch;
6 |
7 | import java.lang.reflect.Method;
8 |
9 | /**
10 | * 解析Aspect表达式并且定位被织入的目标
11 | *
12 | * @author Enndfp
13 | */
14 | public class PointcutLocator {
15 |
16 | // Pointcut解析器,使其支持Aspect所有表达式的解析语法
17 | private PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingContextClassloaderForResolution(
18 | PointcutParser.getAllSupportedPointcutPrimitives()
19 | );
20 |
21 | // 表达式的解析
22 | private PointcutExpression pointcutExpression;
23 |
24 | public PointcutLocator(String expression) {
25 | this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
26 | }
27 |
28 | /**
29 | * 判断传入的Class对象是否是Aspect的目标代理类,即匹配Pointcut表达式(初筛)
30 | *
31 | * @param targetClass 目标类
32 | * @return 是否匹配
33 | */
34 | public boolean roughMatches(Class> targetClass) {
35 | // 只能校验within,不能校验execution、call、get、set,面对无法校验的表达式,直接返回true
36 | return pointcutExpression.couldMatchJoinPointsInType(targetClass);
37 | }
38 |
39 | /**
40 | * 判断传入的Method对象是否是Aspect的目标代理方法,即匹配Pointcut表达式(精筛)
41 | *
42 | * @param method 目标代理方法
43 | * @return 是否匹配
44 | */
45 | public boolean accurateMatches(Method method) {
46 | ShadowMatch shadowMatch = pointcutExpression.matchesMethodExecution(method);
47 | return shadowMatch.alwaysMatches();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/core/BeanContainer.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core;
2 |
3 | import com.enndfp.simpleframework.aop.annotation.Aspect;
4 | import com.enndfp.simpleframework.core.annotation.Component;
5 | import com.enndfp.simpleframework.core.annotation.Controller;
6 | import com.enndfp.simpleframework.core.annotation.Repository;
7 | import com.enndfp.simpleframework.core.annotation.Service;
8 | import com.enndfp.simpleframework.utils.ClassUtil;
9 | import com.enndfp.simpleframework.utils.ValidationUtil;
10 | import lombok.AccessLevel;
11 | import lombok.NoArgsConstructor;
12 | import lombok.extern.slf4j.Slf4j;
13 |
14 | import java.lang.annotation.Annotation;
15 | import java.util.*;
16 | import java.util.concurrent.ConcurrentHashMap;
17 |
18 | /**
19 | * @author Enndfp
20 | */
21 | @Slf4j
22 | @NoArgsConstructor(access = AccessLevel.PRIVATE)
23 | public class BeanContainer {
24 |
25 | // 存放所有被标记的目标对象
26 | private final Map, Object> beanMap = new ConcurrentHashMap<>();
27 |
28 | // 加载Bean的注解列表
29 | private static final List> BEAN_ANNOTATION
30 | = Arrays.asList(Component.class, Controller.class, Service.class, Repository.class, Aspect.class);
31 |
32 | // 容器是否已经加载过Bean
33 | private boolean loaded = false;
34 |
35 | /**
36 | * 枚举类型的饿汉式单例
37 | */
38 | private enum ContainerHolder {
39 | HOLDER;
40 | private final BeanContainer instance;
41 |
42 | ContainerHolder() {
43 | instance = new BeanContainer();
44 | }
45 | }
46 |
47 | /**
48 | * 获取是否已经加载过Bean
49 | *
50 | * @return
51 | */
52 | public boolean isLoaded() {
53 | return loaded;
54 | }
55 |
56 | /**
57 | * 获取Bean容器实例
58 | *
59 | * @return
60 | */
61 | public static BeanContainer getInstance() {
62 | return ContainerHolder.HOLDER.instance;
63 | }
64 |
65 | /**
66 | * 获取Bean实例的数量
67 | *
68 | * @return
69 | */
70 | public int size() {
71 | return beanMap.size();
72 | }
73 |
74 | /**
75 | * 扫描加载所有Bean
76 | *
77 | * @param packageName 包名
78 | */
79 | public synchronized void loadBeans(String packageName) {
80 | // 1. 判断容器是否已经加载过
81 | if (isLoaded()) {
82 | log.warn("BeanContainer has been loaded.");
83 | return;
84 | }
85 |
86 | // 2. 获取指定包名的class对象集合
87 | Set> classSet = ClassUtil.extractPackageClass(packageName);
88 | if (ValidationUtil.isEmpty(classSet)) {
89 | log.warn("extract nothing from packageName " + packageName);
90 | return;
91 | }
92 |
93 | // 3. 实例化指定注解的class对象
94 | for (Class> clazz : classSet) {
95 | for (Class extends Annotation> annotation : BEAN_ANNOTATION) {
96 | // 类上面标记了定义的注解
97 | if (clazz.isAnnotationPresent(annotation)) {
98 | // 将目标类作为键,对应的实例作为值,放入到beanMap中
99 | beanMap.put(clazz, ClassUtil.newInstance(clazz, true));
100 | }
101 | }
102 | }
103 |
104 | // 4. 修改容器是否被加载的标记
105 | loaded = true;
106 | }
107 |
108 | /**
109 | * 添加Bean实例
110 | *
111 | * @param clazz Class对象
112 | * @param bean Bean实例
113 | * @return 添加的Bean实例,没有则返回null
114 | */
115 | public Object addBean(Class> clazz, Object bean) {
116 | return beanMap.put(clazz, bean);
117 | }
118 |
119 | /**
120 | * 删除Bean实例
121 | *
122 | * @param clazz Class对象
123 | * @return 删除的Bean实例,没有则返回null
124 | */
125 | public Object removeBean(Class> clazz) {
126 | return beanMap.remove(clazz);
127 | }
128 |
129 | /**
130 | * 获取Bean实例
131 | *
132 | * @param clazz Class对象
133 | * @return Bean实例
134 | */
135 | public Object getBean(Class> clazz) {
136 | return beanMap.get(clazz);
137 | }
138 |
139 | /**
140 | * 获取所有Class对象的集合
141 | *
142 | * @return Class集合
143 | */
144 | public Set> getClasses() {
145 | return beanMap.keySet();
146 | }
147 |
148 | /**
149 | * 获取所有Bean集合
150 | *
151 | * @return Bean集合
152 | */
153 | public Set getBeans() {
154 | return new HashSet<>(beanMap.values());
155 | }
156 |
157 | /**
158 | * 根据注解获取Bean的Class集合
159 | *
160 | * @param annotation 注解
161 | * @return Class集合
162 | */
163 | public Set> getClassesByAnnotation(Class extends Annotation> annotation) {
164 | // 1. 获取beanMap的所有class对象
165 | Set> keySet = getClasses();
166 | if (ValidationUtil.isEmpty(keySet)) {
167 | log.warn("nothing in beanMap");
168 | return null;
169 | }
170 |
171 | // 2. 获取指定注解的class对象,并添加到classSet中
172 | Set> classSet = new HashSet<>();
173 | for (Class> clazz : keySet) {
174 | if (clazz.isAnnotationPresent(annotation)) {
175 | classSet.add(clazz);
176 | }
177 | }
178 | return classSet.size() > 0 ? classSet : null;
179 | }
180 |
181 | /**
182 | * 通过接口或者父类获取实现类或者子类的Class集合,不包括其本身
183 | *
184 | * @param interfaceOrClass 接口或者父类
185 | * @return Class集合
186 | */
187 | public Set> getClassesBySuper(Class> interfaceOrClass) {
188 | // 1. 获取beanMap的所有class对象
189 | Set> keySet = getClasses();
190 | if (ValidationUtil.isEmpty(keySet)) {
191 | log.warn("nothing in beanMap");
192 | return null;
193 | }
194 |
195 | // 2. 获取指定接口或父类的class对象,并添加到classSet中
196 | Set> classSet = new HashSet<>();
197 | for (Class> clazz : keySet) {
198 | if (interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)) {
199 | classSet.add(clazz);
200 | }
201 | }
202 | return classSet.size() > 0 ? classSet : null;
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/core/annotation/Component.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core.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 | * @author Enndfp
10 | */
11 | @Target(ElementType.TYPE) // 作用于类
12 | @Retention(RetentionPolicy.RUNTIME) // 运行时有效
13 | public @interface Component {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/core/annotation/Controller.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core.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 | * @author Enndfp
10 | */
11 | @Target(ElementType.TYPE) // 作用于类
12 | @Retention(RetentionPolicy.RUNTIME) // 运行时有效
13 | public @interface Controller {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/core/annotation/Repository.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core.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 | * @author Enndfp
10 | */
11 | @Target(ElementType.TYPE) // 作用于类
12 | @Retention(RetentionPolicy.RUNTIME) // 运行时有效
13 | public @interface Repository {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/core/annotation/Service.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core.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 | * @author Enndfp
10 | */
11 | @Target(ElementType.TYPE) // 作用于类
12 | @Retention(RetentionPolicy.RUNTIME) // 运行时有效
13 | public @interface Service {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/inject/DependencyInjector.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.inject;
2 |
3 | import com.enndfp.simpleframework.core.BeanContainer;
4 | import com.enndfp.simpleframework.inject.annotation.Autowired;
5 | import com.enndfp.simpleframework.utils.ClassUtil;
6 | import com.enndfp.simpleframework.utils.ValidationUtil;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | import java.lang.reflect.Field;
10 | import java.util.Set;
11 |
12 | /**
13 | * @author Enndfp
14 | */
15 | @Slf4j
16 | public class DependencyInjector {
17 |
18 | // Bean容器
19 | private final BeanContainer beanContainer;
20 |
21 | public DependencyInjector() {
22 | beanContainer = BeanContainer.getInstance();
23 | }
24 |
25 | /**
26 | * 执行IOC
27 | */
28 | public void doIOC() {
29 | Set> classSet = beanContainer.getClasses();
30 | if (ValidationUtil.isEmpty(classSet)) {
31 | log.warn("empty classSet in beanContainer");
32 | return;
33 | }
34 | // 1. 遍历Bean容器中所有的Class对象
35 | for (Class> clazz : classSet) {
36 | // 2. 遍历Class对象的所有成员变量
37 | Field[] fields = clazz.getDeclaredFields();
38 | if (ValidationUtil.isEmpty(fields)) {
39 | continue;
40 | }
41 | for (Field field : fields) {
42 | // 3. 找出被Autowired标记的成员变量
43 | if (field.isAnnotationPresent(Autowired.class)) {
44 | Autowired autowired = field.getAnnotation(Autowired.class);
45 | String autowiredValue = autowired.value();
46 |
47 | // 4. 获取这些变量的类型
48 | Class> fieldClass = field.getType();
49 | // 5. 根据类型在容器中找到对应的实例
50 | Object fieldInstance = getFieldInstance(fieldClass, autowiredValue);
51 | if (fieldInstance == null) {
52 | throw new RuntimeException("unable to inject relevant type, target fieldClass is :"
53 | + fieldClass.getName() + "autowiredValue is " + autowiredValue);
54 | }
55 |
56 | // 6. 通过反射将对应的成员变量实例注入到相应位置
57 | Object targetBean = beanContainer.getBean(clazz);
58 | ClassUtil.setField(field, targetBean, fieldInstance, true);
59 | }
60 | }
61 | }
62 |
63 | }
64 |
65 | /**
66 | * 根据Class对象获取beanContainer里的实例
67 | *
68 | * @param fieldClass Class对象
69 | * @param autowiredValue 指定注入的具体类型
70 | * @return Bean实例
71 | */
72 | private Object getFieldInstance(Class> fieldClass, String autowiredValue) {
73 | // 1. 从容器中获取bean
74 | Object fieldInstance = beanContainer.getBean(fieldClass);
75 | if (fieldInstance != null) return fieldInstance;
76 |
77 | // 2. 如果是接口类型则根据实现类获取bean
78 | Class> implementedClass = getImplementClass(fieldClass, autowiredValue);
79 | if (implementedClass == null) return null;
80 | return beanContainer.getBean(implementedClass);
81 | }
82 |
83 | /**
84 | * 根据Class对象获取接口的实现类
85 | *
86 | * @param fieldClass Class对象
87 | * @param autowiredValue 指定注入的具体类型
88 | * @return 实现类
89 | */
90 | private Class> getImplementClass(Class> fieldClass, String autowiredValue) {
91 | Set> classSet = beanContainer.getClassesBySuper(fieldClass);
92 | if (ValidationUtil.isEmpty(classSet)) return null;
93 |
94 | // 针对有多个实现类,根据类型则无法判断注入哪个实例,则根据指定的类型值
95 | // 1. 用户没有指定类型值
96 | if (ValidationUtil.isEmpty(autowiredValue)) {
97 | // 有多个实现类,报错
98 | if (classSet.size() > 1) {
99 | throw new RuntimeException("multiple implemented classes for "
100 | + fieldClass.getName() + " please set @Autowired's value to pick one: " + classSet);
101 | }
102 | // 只有一个实现类,返回
103 | return classSet.iterator().next();
104 | }
105 | // 2. 用户指定了类型值
106 | for (Class> clazz : classSet) {
107 | if (autowiredValue.equals(clazz.getSimpleName())) {
108 | return clazz;
109 | }
110 | }
111 | return null;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/inject/annotation/Autowired.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.inject.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 | * @author Enndfp
12 | */
13 | @Target(ElementType.FIELD)
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface Autowired {
16 | String value() default "";
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/DispatcherServlet.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc;
2 |
3 | import com.enndfp.simpleframework.aop.AspectWeaver;
4 | import com.enndfp.simpleframework.core.BeanContainer;
5 | import com.enndfp.simpleframework.inject.DependencyInjector;
6 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
7 | import com.enndfp.simpleframework.mvc.processor.impl.ControllerRequestProcessor;
8 | import com.enndfp.simpleframework.mvc.processor.impl.JspRequestProcessor;
9 | import com.enndfp.simpleframework.mvc.processor.impl.PreRequestProcessor;
10 | import com.enndfp.simpleframework.mvc.processor.impl.StaticResourceRequestProcessor;
11 |
12 | import javax.servlet.ServletException;
13 | import javax.servlet.annotation.WebServlet;
14 | import javax.servlet.http.HttpServlet;
15 | import javax.servlet.http.HttpServletRequest;
16 | import javax.servlet.http.HttpServletResponse;
17 | import java.io.IOException;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * @author Enndfp
23 | */
24 | @WebServlet("/*")
25 | public class DispatcherServlet extends HttpServlet {
26 |
27 | List PROCESSOR = new ArrayList<>();
28 |
29 | @Override
30 | public void init() throws ServletException {
31 | // 1. 初始化容器
32 | BeanContainer beanContainer = BeanContainer.getInstance();
33 | beanContainer.loadBeans("com.enndfp.demo");
34 | new AspectWeaver().doAOP();
35 | new DependencyInjector().doIOC();
36 | // 2. 初始化请求处理器责任链
37 | PROCESSOR.add(new PreRequestProcessor());
38 | PROCESSOR.add(new StaticResourceRequestProcessor(getServletContext()));
39 | PROCESSOR.add(new JspRequestProcessor(getServletContext()));
40 | PROCESSOR.add(new ControllerRequestProcessor());
41 | }
42 |
43 | @Override
44 | protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
45 | // 1. 创建责任链实例对象
46 | RequestProcessorChain requestProcessorChain = new RequestProcessorChain(PROCESSOR.iterator(), req, resp);
47 | // 2. 通过责任链模式来依次调用请求处理器对请求进行处理
48 | requestProcessorChain.doRequestProcessorChain();
49 | // 3. 对处理结果进行渲染
50 | requestProcessorChain.doRender();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/RequestProcessorChain.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc;
2 |
3 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 | import com.enndfp.simpleframework.mvc.render.impl.DefaultResultRender;
6 | import com.enndfp.simpleframework.mvc.render.impl.InternalErrorResultRender;
7 | import lombok.Data;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | import javax.servlet.http.HttpServletRequest;
11 | import javax.servlet.http.HttpServletResponse;
12 | import java.util.Iterator;
13 |
14 | /**
15 | * 1. 以责任链的模式执行注册的请求处理器
16 | * 2. 委派给特定的Render实例对处理后的结果进行渲染
17 | *
18 | * @author Enndfp
19 | */
20 | @Slf4j
21 | @Data
22 | public class RequestProcessorChain {
23 |
24 | // 请求处理器的迭代器
25 | private Iterator requestProcessorIterator;
26 |
27 | // 请求request
28 | private HttpServletRequest request;
29 |
30 | // 响应response
31 | private HttpServletResponse response;
32 |
33 | // http请求方法
34 | private String requestMethod;
35 |
36 | // http请求路径
37 | private String requestPath;
38 |
39 | // http响应状态码
40 | private int responseCode;
41 |
42 | // 请求结果渲染器
43 | private ResultRender resultRender;
44 |
45 | public RequestProcessorChain(Iterator iterator, HttpServletRequest req, HttpServletResponse resp) {
46 | this.requestProcessorIterator = iterator;
47 | this.request = req;
48 | this.response = resp;
49 | this.requestMethod = req.getMethod();
50 | this.requestPath = req.getPathInfo();
51 | this.responseCode = HttpServletResponse.SC_OK;
52 | }
53 |
54 | /**
55 | * 以责任链的模式执行请求链
56 | */
57 | public void doRequestProcessorChain() {
58 | try {
59 | // 1. 通过迭代器遍历注册的请求处理器实现类列表
60 | while (requestProcessorIterator.hasNext()) {
61 | // 2. 直到某个请求处理器执行后返回false为止
62 | if (!requestProcessorIterator.next().process(this)) {
63 | break;
64 | }
65 | }
66 | } catch (Exception e) {
67 | // 3. 期间如果出现异常,则交由内部异常渲染器处理
68 | this.resultRender = new InternalErrorResultRender(e.getMessage());
69 | log.error("doRequestProcessorChain error: ", e);
70 | }
71 | }
72 |
73 | /**
74 | * 执行渲染器
75 | */
76 | public void doRender() {
77 | // 1. 如果请求处理器实现类均未选择合适的渲染器,则使用默认的
78 | if (this.resultRender == null) {
79 | this.resultRender = new DefaultResultRender();
80 | }
81 | // 2. 调用渲染器的render方法对结果进行渲染
82 | try {
83 | this.resultRender.render(this);
84 | } catch (Exception e) {
85 | log.error("doRender error: ", e);
86 | throw new RuntimeException(e);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/annotation/RequestMapping.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.annotation;
2 |
3 | import com.enndfp.simpleframework.mvc.type.RequestMethod;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 标识Controller的方法与请求路径和请求方法的映射关系
12 | *
13 | * @author Enndfp
14 | */
15 | @Target({ElementType.TYPE, ElementType.METHOD})
16 | @Retention(RetentionPolicy.RUNTIME)
17 | public @interface RequestMapping {
18 | // 请求路径
19 | String value() default "";
20 |
21 | // 请求方法
22 | RequestMethod method() default RequestMethod.GET;
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/annotation/RequestParam.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.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 | * @author Enndfp
12 | */
13 | @Target(ElementType.PARAMETER)
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface RequestParam {
16 | // 方法参数名称
17 | String value() default "";
18 |
19 | // 该参数是否必须
20 | boolean required() default true;
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/annotation/ResponseBody.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.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 | * 用于标记返回json格式
10 | *
11 | * @author Enndfp
12 | */
13 | @Target(ElementType.METHOD)
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface ResponseBody {
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/processor/RequestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.processor;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 |
5 | /**
6 | * 请求执行器
7 | * @author Enndfp
8 | */
9 | public interface RequestProcessor {
10 |
11 | boolean process(RequestProcessorChain requestProcessorChain) throws Exception;
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/processor/impl/ControllerRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.processor.impl;
2 |
3 | import com.enndfp.simpleframework.core.BeanContainer;
4 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
5 | import com.enndfp.simpleframework.mvc.annotation.RequestMapping;
6 | import com.enndfp.simpleframework.mvc.annotation.RequestParam;
7 | import com.enndfp.simpleframework.mvc.annotation.ResponseBody;
8 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
9 | import com.enndfp.simpleframework.mvc.render.ResultRender;
10 | import com.enndfp.simpleframework.mvc.render.impl.JsonResultRender;
11 | import com.enndfp.simpleframework.mvc.render.impl.ResourceNotFoundResultRender;
12 | import com.enndfp.simpleframework.mvc.render.impl.ViewResultRender;
13 | import com.enndfp.simpleframework.mvc.type.ControllerMethod;
14 | import com.enndfp.simpleframework.mvc.type.RequestPathInfo;
15 | import com.enndfp.simpleframework.utils.ConverterUtil;
16 | import com.enndfp.simpleframework.utils.ValidationUtil;
17 | import lombok.extern.slf4j.Slf4j;
18 |
19 | import javax.servlet.http.HttpServletRequest;
20 | import java.lang.reflect.InvocationTargetException;
21 | import java.lang.reflect.Method;
22 | import java.lang.reflect.Parameter;
23 | import java.util.*;
24 | import java.util.concurrent.ConcurrentHashMap;
25 |
26 | /**
27 | * Controller请求处理器
28 | *
29 | * @author Enndfp
30 | */
31 | @Slf4j
32 | public class ControllerRequestProcessor implements RequestProcessor {
33 |
34 | // ICO容器
35 | private BeanContainer beanContainer;
36 |
37 | // 请求和Controller方法的映射Map
38 | private Map pathControllerMethodMap = new ConcurrentHashMap<>();
39 |
40 | /**
41 | * 依靠容器的能力,建立起请求路径、请求方法与Controller方法实例的映射
42 | */
43 | public ControllerRequestProcessor() {
44 | this.beanContainer = BeanContainer.getInstance();
45 | Set> requestMappingSet = beanContainer.getClassesByAnnotation(RequestMapping.class);
46 | initPathControllerMethodMap(requestMappingSet);
47 | }
48 |
49 | /**
50 | * 初始化路径到控制器方法的映射
51 | *
52 | * @param requestMappingSet
53 | */
54 | private void initPathControllerMethodMap(Set> requestMappingSet) {
55 | if (ValidationUtil.isEmpty(requestMappingSet)) return;
56 |
57 | for (Class> requestMappingClass : requestMappingSet) {
58 | processClassMapping(requestMappingClass);
59 | }
60 | }
61 |
62 | /**
63 | * 处理类级别的 @RequestMapping 注解
64 | *
65 | * @param requestMappingClass
66 | */
67 | private void processClassMapping(Class> requestMappingClass) {
68 | // 1. 获取类上面的请求地址
69 | RequestMapping classRequestMapping = requestMappingClass.getAnnotation(RequestMapping.class);
70 | String classBasePath = classRequestMapping.value();
71 | if (!classBasePath.startsWith("/")) {
72 | classBasePath = "/" + classBasePath;
73 | }
74 |
75 | // 2. 获取该类所有申明的方法
76 | Method[] methods = requestMappingClass.getDeclaredMethods();
77 | if (ValidationUtil.isEmpty(methods)) return;
78 |
79 | for (Method method : methods) {
80 | processMethodMapping(requestMappingClass, classBasePath, method);
81 | }
82 | }
83 |
84 | /**
85 | * 处理方法级别的 @RequestMapping 注解
86 | *
87 | * @param requestMappingClass
88 | * @param classBasePath
89 | * @param method
90 | */
91 | private void processMethodMapping(Class> requestMappingClass, String classBasePath, Method method) {
92 | if (!method.isAnnotationPresent(RequestMapping.class)) return;
93 |
94 | // 1. 获取方法上的请求地址
95 | RequestMapping methodRequestMapping = method.getAnnotation(RequestMapping.class);
96 | String methodPath = methodRequestMapping.value();
97 | if (!methodPath.startsWith("/")) {
98 | methodPath = "/" + methodPath;
99 | }
100 | // 1.1 拼接完整的请求地址
101 | String url = classBasePath + methodPath;
102 |
103 | // 2. 获取方法的参数列表
104 | Map> methodParamMap = new HashMap<>();
105 | Parameter[] parameters = method.getParameters();
106 |
107 | if (!ValidationUtil.isEmpty(parameters)){
108 | for (Parameter parameter : parameters) {
109 | processParameterAnnotation(parameter, methodParamMap);
110 | }
111 | }
112 |
113 | // 3. 封装 RequestPathInfo
114 | String httpMethod = String.valueOf(methodRequestMapping.method());
115 | RequestPathInfo requestPathInfo = new RequestPathInfo(httpMethod, url);
116 | // 4. 处理路径信息并将其添加到映射表中
117 | handlePathInfo(requestPathInfo, requestMappingClass, method, methodParamMap);
118 | }
119 |
120 | /**
121 | * 处理路径信息并将其添加到映射表中
122 | *
123 | * @param requestPathInfo
124 | * @param requestMappingClass
125 | * @param method
126 | * @param methodParamMap
127 | */
128 | private void handlePathInfo(RequestPathInfo requestPathInfo, Class> requestMappingClass, Method method, Map> methodParamMap) {
129 | if (pathControllerMethodMap.containsKey(requestPathInfo)) {
130 | log.warn("Duplicate URL:{} registration, current class {} method {} will override the former one",
131 | requestPathInfo.getHttpPath(), requestMappingClass.getName(), method.getName());
132 | }
133 | ControllerMethod controllerMethod = new ControllerMethod(requestMappingClass, method, methodParamMap);
134 | pathControllerMethodMap.put(requestPathInfo, controllerMethod);
135 | }
136 |
137 | /**
138 | * 处理参数级别的 @RequestParam 注解
139 | *
140 | * @param parameter
141 | * @param methodParamMap
142 | */
143 | private void processParameterAnnotation(Parameter parameter, Map> methodParamMap) {
144 | RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
145 | // 简化实现,controller里所有的参数都需要标注注解
146 | if (requestParam == null) {
147 | throw new RuntimeException("The parameter must have @RequestParam annotation");
148 | }
149 | methodParamMap.put(requestParam.value(), parameter.getType());
150 | }
151 |
152 | @Override
153 | public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {
154 | // 1. 解析HttpServletRequest的请求方法,请求路径,获取对应的ControllerMethod实例
155 | String requestMethod = requestProcessorChain.getRequestMethod();
156 | String requestPath = requestProcessorChain.getRequestPath();
157 | ControllerMethod controllerMethod = pathControllerMethodMap.get(new RequestPathInfo(requestMethod, requestPath));
158 | if (controllerMethod == null) {
159 | requestProcessorChain.setResultRender(new ResourceNotFoundResultRender(requestMethod, requestPath));
160 | return false;
161 | }
162 |
163 | // 2. 解析请求参数,并传递给获取到的ControllerMethod实例去执行
164 | Object result = invokeControllerMethod(controllerMethod, requestProcessorChain.getRequest());
165 |
166 | // 3. 根据处理的结果,选择对应的render进行渲染
167 | setResultRender(result, controllerMethod, requestProcessorChain);
168 | return false;
169 | }
170 |
171 | /**
172 | * 根据不同情况设置不同的渲染器
173 | *
174 | * @param result
175 | * @param controllerMethod
176 | * @param requestProcessorChain
177 | */
178 | private void setResultRender(Object result, ControllerMethod controllerMethod, RequestProcessorChain requestProcessorChain) {
179 | if (result == null) return;
180 | ResultRender resultRender;
181 | boolean isJson = controllerMethod.getInvokeMethod().isAnnotationPresent(ResponseBody.class);
182 | if (isJson) {
183 | resultRender = new JsonResultRender(result);
184 | } else {
185 | resultRender = new ViewResultRender(result);
186 | }
187 | requestProcessorChain.setResultRender(resultRender);
188 | }
189 |
190 | /**
191 | * 执行对应Controller的方法
192 | *
193 | * @param controllerMethod
194 | * @param request
195 | * @return
196 | */
197 | private Object invokeControllerMethod(ControllerMethod controllerMethod, HttpServletRequest request) {
198 | // 1. 从请求里获取GET或者POST的参数名及其对应的值
199 | Map requestParamMap = new HashMap<>();
200 | // GET,POST方法的请求参数获取方式
201 | Map parameterMap = request.getParameterMap();
202 | for (Map.Entry parameter : parameterMap.entrySet()) {
203 | if (!ValidationUtil.isEmpty(parameter.getValue())) {
204 | // 只支持一个参数对应一个值的形式
205 | requestParamMap.put(parameter.getKey(), parameter.getValue()[0]);
206 | }
207 | }
208 |
209 | // 2. 根据获取到的请求参数名及其对应的值,以及controllerMethod里面的参数和类型的映射关系,去实例化出参数列表
210 | List methodParams = new ArrayList<>();
211 | Map> methodParamMap = controllerMethod.getMethodParameters();
212 | for (String paramName : methodParamMap.keySet()) {
213 | Class> type = methodParamMap.get(paramName);
214 | String requestParamValue = requestParamMap.get(paramName);
215 | Object value;
216 | // 只支持String以及基础类型char,int,short,byte,double,long,float,boolean及它们的包装类型
217 | if (requestParamValue == null) {
218 | // 将请求里的参数值转成适配于参数类型的空值
219 | value = ConverterUtil.primitiveNull(type);
220 | } else {
221 | value = ConverterUtil.convert(type, requestParamValue);
222 | }
223 | methodParams.add(value);
224 | }
225 |
226 | // 3. 执行Controller里面对应的方法并返回结果
227 | Object controller = beanContainer.getBean(controllerMethod.getControllerClass());
228 | Method invokeMethod = controllerMethod.getInvokeMethod();
229 | invokeMethod.setAccessible(true);
230 | Object result;
231 | try {
232 | if (methodParams.size() == 0) {
233 | result = invokeMethod.invoke(controller);
234 | } else {
235 | result = invokeMethod.invoke(controller, methodParams.toArray());
236 | }
237 | } catch (IllegalAccessException e) {
238 | throw new RuntimeException(e);
239 | } catch (InvocationTargetException e) {
240 | throw new RuntimeException(e.getTargetException());
241 | }
242 | return result;
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/processor/impl/JspRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.processor.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
5 |
6 | import javax.servlet.RequestDispatcher;
7 | import javax.servlet.ServletContext;
8 |
9 | /**
10 | * jsp资源请求处理
11 | *
12 | * @author Enndfp
13 | */
14 | public class JspRequestProcessor implements RequestProcessor {
15 |
16 | private static final String JSP_SERVLET = "jsp";
17 |
18 | private static final String JSP_RESOURCE_PREFIX = "/templates/";
19 |
20 | // 处理jsp资源的RequestDispatcher
21 | private final RequestDispatcher jspDispatcher;
22 |
23 | public JspRequestProcessor(ServletContext servletContext) {
24 | jspDispatcher = servletContext.getNamedDispatcher(JSP_SERVLET);
25 | if (null == jspDispatcher) {
26 | throw new RuntimeException("there is no jsp servlet");
27 | }
28 | }
29 |
30 | @Override
31 | public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {
32 | // 1. 通过请求路径判断请求的是不是jsp资源 webapp/templates
33 | if (isJspResource(requestProcessorChain.getRequestPath())) {
34 | // 2. 如果是jsp资源,则将请求转发给 jspDispatcher 处理
35 | jspDispatcher.forward(requestProcessorChain.getRequest(), requestProcessorChain.getResponse());
36 | return false;
37 | }
38 | return true;
39 | }
40 |
41 | /**
42 | * 通过请求路径前缀(目录)判断是否是jsp资源 /templates/
43 | *
44 | * @param requestPath
45 | * @return
46 | */
47 | private boolean isJspResource(String requestPath) {
48 | return requestPath.startsWith(JSP_RESOURCE_PREFIX);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/processor/impl/PreRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.processor.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
5 |
6 | /**
7 | * 请求预处理,包括编码以及路径处理
8 | *
9 | * @author Enndfp
10 | */
11 | public class PreRequestProcessor implements RequestProcessor {
12 | @Override
13 | public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {
14 | // 1. 设置请求编码,将其统一设置成UTF-8
15 | requestProcessorChain.getRequest().setCharacterEncoding("UTF-8");
16 |
17 | // 2. 将请求路径末尾的 / 剔除,为后续匹配Controller请求路径做准备
18 | // 一般Controller的处理路径是/aaa/bbb,所以如果传入的路径结尾是/aaa/bbb/,就需要处理成/aaa/bbb
19 | String requestPath = requestProcessorChain.getRequestPath();
20 | //http://localhost:8080/simple-framework requestPath="/"
21 | if (requestPath.length() > 1 && requestPath.endsWith("/")) {
22 | requestProcessorChain.setRequestPath(requestPath.substring(0, requestPath.length() - 1));
23 | }
24 | return true;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/processor/impl/StaticResourceRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.processor.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.processor.RequestProcessor;
5 |
6 | import javax.servlet.RequestDispatcher;
7 | import javax.servlet.ServletContext;
8 |
9 | /**
10 | * 静态资源请求处理,包括但不限于图片、css以及js文件等
11 | *
12 | * @author Enndfp
13 | */
14 | public class StaticResourceRequestProcessor implements RequestProcessor {
15 |
16 | private static final String DEFAULT_SERVLET = "default";
17 |
18 | private static final String STATIC_RESOURCE_PREFIX = "/static/";
19 |
20 | // tomcat默认请求派发器RequestDispatcher的名称
21 | private final RequestDispatcher defaultDispatcher;
22 |
23 | public StaticResourceRequestProcessor(ServletContext servletContext) {
24 | this.defaultDispatcher = servletContext.getNamedDispatcher(DEFAULT_SERVLET);
25 | if (null == defaultDispatcher) {
26 | throw new RuntimeException("There is no default tomcat servlet");
27 | }
28 | }
29 |
30 | @Override
31 | public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {
32 | // 1. 通过请求路径判断请求的是不是静态资源 webapp/static
33 | if (isStaticResource(requestProcessorChain.getRequestPath())) {
34 | // 2. 如果是静态资源,则将请求转发给 defaultDispatcher 处理
35 | defaultDispatcher.forward(requestProcessorChain.getRequest(), requestProcessorChain.getResponse());
36 | return false;
37 | }
38 | return true;
39 | }
40 |
41 | /**
42 | * 通过请求路径前缀(目录)判断是否是静态资源 /static/
43 | *
44 | * @param requestPath
45 | * @return
46 | */
47 | private boolean isStaticResource(String requestPath) {
48 | return requestPath.startsWith(STATIC_RESOURCE_PREFIX);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/ResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 |
5 | /**
6 | * 渲染请求结果
7 | *
8 | * @author Enndfp
9 | */
10 | public interface ResultRender {
11 |
12 | void render(RequestProcessorChain requestProcessorChain) throws Exception;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/impl/DefaultResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 |
6 | /**
7 | * 默认渲染器
8 | *
9 | * @author Enndfp
10 | */
11 | public class DefaultResultRender implements ResultRender {
12 | @Override
13 | public void render(RequestProcessorChain requestProcessorChain) throws Exception {
14 | int responseCode = requestProcessorChain.getResponseCode();
15 | requestProcessorChain.getResponse().setStatus(responseCode);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/impl/InternalErrorResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 |
6 | import javax.servlet.http.HttpServletResponse;
7 |
8 | /**
9 | * 内部异常渲染器
10 | *
11 | * @author Enndfp
12 | */
13 | public class InternalErrorResultRender implements ResultRender {
14 |
15 | private String errorMsg;
16 |
17 | public InternalErrorResultRender(String errorMsg) {
18 | this.errorMsg = errorMsg;
19 | }
20 |
21 | @Override
22 | public void render(RequestProcessorChain requestProcessorChain) throws Exception {
23 | int serverErrorCode = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
24 | requestProcessorChain.getResponse().sendError(serverErrorCode, errorMsg);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/impl/JsonResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 | import com.google.gson.Gson;
6 |
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.PrintWriter;
9 |
10 | /**
11 | * json渲染器
12 | *
13 | * @author Enndfp
14 | */
15 | public class JsonResultRender implements ResultRender {
16 |
17 | private Object result;
18 |
19 | public JsonResultRender(Object result) {
20 | this.result = result;
21 | }
22 |
23 | @Override
24 | public void render(RequestProcessorChain requestProcessorChain) throws Exception {
25 | // 1. 设置响应头
26 | HttpServletResponse response = requestProcessorChain.getResponse();
27 | response.setContentType("application/json");
28 | response.setCharacterEncoding("UTF-8");
29 |
30 | // 2. 将经过Gson处理后的结果写入响应流,try-with-resources 语句确保在语句结束时自动关闭每个资源
31 | try (PrintWriter writer = response.getWriter()) {
32 | Gson gson = new Gson();
33 | writer.write(gson.toJson(result));
34 | // flush()不是必需的,因为close()将被自动调用
35 | writer.flush();
36 | } catch (Exception e) {
37 | e.printStackTrace();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/impl/ResourceNotFoundResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 |
6 | import javax.servlet.http.HttpServletResponse;
7 |
8 | /**
9 | * 资源找不到时使用的渲染器
10 | *
11 | * @author Enndfp
12 | */
13 | public class ResourceNotFoundResultRender implements ResultRender {
14 |
15 | private String requestMethod;
16 |
17 | private String requestPath;
18 |
19 | public ResourceNotFoundResultRender(String requestMethod, String requestPath) {
20 | this.requestMethod = requestMethod;
21 | this.requestPath = requestPath;
22 | }
23 |
24 | @Override
25 | public void render(RequestProcessorChain requestProcessorChain) throws Exception {
26 | int notFoundCode = HttpServletResponse.SC_NOT_FOUND;
27 | requestProcessorChain.getResponse().sendError(notFoundCode,
28 | "获取不到对应的请求资源:请求路径[" + requestPath + "]," + "请求方法[" + requestMethod + "]");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/render/impl/ViewResultRender.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.render.impl;
2 |
3 | import com.enndfp.simpleframework.mvc.RequestProcessorChain;
4 | import com.enndfp.simpleframework.mvc.render.ResultRender;
5 | import com.enndfp.simpleframework.mvc.type.ModelAndView;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 | import java.util.Map;
10 |
11 | /**
12 | * 页面渲染器
13 | *
14 | * @author Enndfp
15 | */
16 | public class ViewResultRender implements ResultRender {
17 |
18 | public static final String VIEW_PATH = "/templates/";
19 |
20 | private ModelAndView modelAndView;
21 |
22 | /**
23 | * 对传入的参数进行处理,并赋值给ModelAndView成员变量
24 | *
25 | * @param mv
26 | */
27 | public ViewResultRender(Object mv) {
28 | if (mv instanceof ModelAndView) {
29 | // 1. 如果入参类型是ModelAndView,则直接赋值给成员变量
30 | this.modelAndView = (ModelAndView) mv;
31 | } else if (mv instanceof String) {
32 | // 2. 如果入参类型是String,则为视图,需要包装后才赋值给成员变量
33 | this.modelAndView = new ModelAndView().setViewPath((String) mv);
34 | } else {
35 | // 3. 针对其他情况,则直接抛出异常
36 | throw new RuntimeException("illegal request result type");
37 | }
38 | }
39 |
40 | /**
41 | * 根据请求结果按照视图路径转发至对应视图进行展示
42 | *
43 | * @param requestProcessorChain
44 | * @throws Exception
45 | */
46 | @Override
47 | public void render(RequestProcessorChain requestProcessorChain) throws Exception {
48 | HttpServletRequest request = requestProcessorChain.getRequest();
49 | HttpServletResponse response = requestProcessorChain.getResponse();
50 |
51 | String viewPath = modelAndView.getViewPath();
52 | Map viewData = modelAndView.getViewData();
53 | for (Map.Entry entry : viewData.entrySet()) {
54 | request.setAttribute(entry.getKey(), entry.getValue());
55 | }
56 | request.getRequestDispatcher(VIEW_PATH + viewPath).forward(request, response);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/type/ControllerMethod.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.type;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.lang.reflect.Method;
8 | import java.util.Map;
9 |
10 | /**
11 | * 待执行的Controller及其方法实例和参数的映射
12 | *
13 | * @author Enndfp
14 | */
15 | @Data
16 | @AllArgsConstructor
17 | @NoArgsConstructor
18 | public class ControllerMethod {
19 | // Controller对应的Class对象
20 | private Class> controllerClass;
21 |
22 | // 执行的Controller方法实例
23 | private Method invokeMethod;
24 |
25 | // 方法参数名称以及对应的参数类型
26 | private Map> methodParameters;
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/type/ModelAndView.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.type;
2 |
3 | import lombok.Getter;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * 存储处理完后的结果数据以及显示该数据的视图
10 | *
11 | * @author Enndfp
12 | */
13 | @Getter
14 | public class ModelAndView {
15 |
16 | // 页面所在的路径
17 | private String viewPath;
18 |
19 | // 页面的data数据
20 | private Map viewData = new HashMap<>();
21 |
22 | public ModelAndView setViewPath(String viewPath) {
23 | this.viewPath = viewPath;
24 | return this;
25 | }
26 |
27 | public ModelAndView addViewData(String attributeName, Object attributeValue) {
28 | viewData.put(attributeName, attributeValue);
29 | return this;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/type/RequestMethod.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.type;
2 |
3 | /**
4 | * 目前支持的请求方法
5 | *
6 | * @author Enndfp
7 | */
8 | public enum RequestMethod {
9 | GET,
10 | POST;
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/mvc/type/RequestPathInfo.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.mvc.type;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | /**
8 | * 存储http请求路径和请求方法
9 | *
10 | * @author Enndfp
11 | */
12 | @Data
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class RequestPathInfo {
16 | // http请求方法
17 | private String httpMethod;
18 |
19 | // http请求路径
20 | private String httpPath;
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/utils/ClassUtil.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.utils;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | import java.io.File;
6 | import java.io.FileFilter;
7 | import java.lang.reflect.Constructor;
8 | import java.lang.reflect.Field;
9 | import java.net.URL;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | /**
14 | * @author Enndfp
15 | */
16 | @Slf4j
17 | public class ClassUtil {
18 |
19 | public static final String FILE_PROTOCOL = "file";
20 |
21 | /**
22 | * 获取包下所有类的集合
23 | *
24 | * @param packageName 包名
25 | * @return 类集合
26 | */
27 | public static Set> extractPackageClass(String packageName) {
28 | // 1. 获取到类的加载器
29 | ClassLoader classLoader = getClassLoader();
30 |
31 | // 2. 通过类加载器获取到加载的资源信息
32 | URL url = classLoader.getResource(packageName.replace(".", "/"));
33 | if (url == null) {
34 | log.warn("unable to retrieve anything from package: " + packageName);
35 | return null;
36 | }
37 |
38 | // 3. 依据不同的资源类型,采用不同的方式获取资源的集合
39 | Set> classSet = null;
40 | // 3.1 仅处理文件类型的资源
41 | if (url.getProtocol().equalsIgnoreCase(FILE_PROTOCOL)) {
42 | classSet = new HashSet<>();
43 | File packageDirectory = new File(url.getPath());
44 | extractClassFile(classSet, packageDirectory, packageName);
45 | }
46 | return classSet;
47 | }
48 |
49 | /**
50 | * 递归获取目标package及其子目录里面的所有class文件
51 | *
52 | * @param classSet 装载目标类的集合
53 | * @param fileSource 文件或者目录
54 | * @param packageName 包名
55 | */
56 | private static void extractClassFile(Set> classSet, File fileSource, String packageName) {
57 | if (!fileSource.isDirectory()) return;
58 | // 获取目录下的文件夹(不包括子文件夹)
59 | File[] files = fileSource.listFiles(new FileFilter() {
60 | @Override
61 | public boolean accept(File file) {
62 | if (file.isDirectory()) {
63 | return true;
64 | } else {
65 | // 获取文件的绝对值路径
66 | String absolutePath = file.getAbsolutePath();
67 | if (absolutePath.endsWith(".class")) {
68 | // 若是class文件,则直接加载
69 | addToClassSet(absolutePath);
70 | }
71 | }
72 | return false;
73 | }
74 |
75 | // 根据class文件的绝对值路径,获取并生成class对象,并放入classSet中
76 | private void addToClassSet(String absolutePath) {
77 | // 1. 从class文件的绝对值路径里提取出包含了package的类名
78 | absolutePath = absolutePath.replace(File.separator, ".");
79 | String className = absolutePath.substring(absolutePath.indexOf(packageName));
80 | className = className.substring(0, className.lastIndexOf("."));
81 |
82 | // 2. 通过反射机制获取对应的class对象并加入到classSet中
83 | Class> targetClass = loadClass(className);
84 | classSet.add(targetClass);
85 | }
86 | });
87 | if (files != null) {
88 | for (File f : files) {
89 | // 递归调用
90 | extractClassFile(classSet, f, packageName);
91 | }
92 | }
93 | }
94 |
95 | /**
96 | * 获取ClassLoader
97 | *
98 | * @return 当前ClassLoader
99 | */
100 | public static ClassLoader getClassLoader() {
101 | return Thread.currentThread().getContextClassLoader();
102 | }
103 |
104 | /**
105 | * 获取class对象
106 | *
107 | * @param className class全名 = package + 类名
108 | * @return
109 | */
110 | public static Class> loadClass(String className) {
111 | try {
112 | return Class.forName(className);
113 | } catch (ClassNotFoundException e) {
114 | log.error("load class error: ", e);
115 | throw new RuntimeException(e);
116 | }
117 | }
118 |
119 | /**
120 | * 实例化Class对象
121 | *
122 | * @param clazz Class
123 | * @param Class的类型
124 | * @param accessible 是否支持创建出私有class对象的实例
125 | * @return 类的实例化
126 | */
127 | public static T newInstance(Class> clazz, boolean accessible) {
128 | try {
129 | Constructor> constructor = clazz.getDeclaredConstructor();
130 | constructor.setAccessible(accessible);
131 | return (T) constructor.newInstance();
132 | } catch (Exception e) {
133 | log.error("newInstance error ", e);
134 | throw new RuntimeException(e);
135 | }
136 | }
137 |
138 | /**
139 | * 设置类的属性值
140 | *
141 | * @param field 成员变量
142 | * @param target 类实例
143 | * @param value 成员变量的值
144 | * @param accessible 是否允许设置私有属性
145 | */
146 | public static void setField(Field field, Object target, Object value, boolean accessible) {
147 | field.setAccessible(accessible);
148 | try {
149 | field.set(target, value);
150 | } catch (IllegalAccessException e) {
151 | log.error("setField error ", e);
152 | throw new RuntimeException();
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/utils/ConverterUtil.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.utils;
2 |
3 | /**
4 | * @author Enndfp
5 | */
6 | public class ConverterUtil {
7 |
8 | /**
9 | * 返回基本数据类型的空值
10 | * 需要特殊处理的基本类型即int\double\short\long\byte\float\boolean
11 | *
12 | * @param type
13 | * @return
14 | */
15 | public static Object primitiveNull(Class> type) {
16 | if (type == int.class || type == double.class ||
17 | type == short.class || type == long.class ||
18 | type == byte.class || type == float.class) {
19 | return 0;
20 | } else if (type == boolean.class) {
21 | return false;
22 | }
23 | return null;
24 | }
25 |
26 | /**
27 | * String类型转换成对应的参数类型
28 | *
29 | * @param type 参数类型
30 | * @param requestParamValue 参数值
31 | * @return 转换后的Object
32 | */
33 | public static Object convert(Class> type, String requestParamValue) {
34 | if (isPrimitive(type)) {
35 | if (ValidationUtil.isEmpty(requestParamValue)) {
36 | return primitiveNull(type);
37 | }
38 | if (type.equals(int.class) || type.equals(Integer.class)) {
39 | return Integer.parseInt(requestParamValue);
40 | } else if (type.equals(String.class)) {
41 | return requestParamValue;
42 | } else if (type.equals(Double.class) || type.equals(double.class)) {
43 | return Double.parseDouble(requestParamValue);
44 | } else if (type.equals(Float.class) || type.equals(float.class)) {
45 | return Float.parseFloat(requestParamValue);
46 | } else if (type.equals(Long.class) || type.equals(long.class)) {
47 | return Long.parseLong(requestParamValue);
48 | } else if (type.equals(Boolean.class) || type.equals(boolean.class)) {
49 | return Boolean.parseBoolean(requestParamValue);
50 | } else if (type.equals(Short.class) || type.equals(short.class)) {
51 | return Short.parseShort(requestParamValue);
52 | } else if (type.equals(Byte.class) || type.equals(byte.class)) {
53 | return Byte.parseByte(requestParamValue);
54 | }
55 | return requestParamValue;
56 | } else {
57 | throw new RuntimeException("count not support non primitive type conversion yet");
58 | }
59 | }
60 |
61 | /**
62 | * 判断是否是基本数据类型(包括包装类以及String)
63 | *
64 | * @param type 参数类型
65 | * @return 是否为基本数据类型
66 | */
67 | private static boolean isPrimitive(Class> type) {
68 | return type == boolean.class
69 | || type == Boolean.class
70 | || type == double.class
71 | || type == Double.class
72 | || type == float.class
73 | || type == Float.class
74 | || type == short.class
75 | || type == Short.class
76 | || type == int.class
77 | || type == Integer.class
78 | || type == long.class
79 | || type == Long.class
80 | || type == String.class
81 | || type == byte.class
82 | || type == Byte.class
83 | || type == char.class
84 | || type == Character.class;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/com/enndfp/simpleframework/utils/ValidationUtil.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.utils;
2 |
3 | import java.util.Collection;
4 | import java.util.Map;
5 |
6 | /**
7 | * @author Enndfp
8 | */
9 | public class ValidationUtil {
10 |
11 | /**
12 | * String是否为null或“”
13 | *
14 | * @param obj String
15 | * @return 是否为空
16 | */
17 | public static boolean isEmpty(String obj) {
18 | return (obj == null || "".equals(obj));
19 | }
20 |
21 | /**
22 | * Array是否为null或size为0
23 | *
24 | * @param obj Array
25 | * @return 是否为空
26 | */
27 | public static boolean isEmpty(Object[] obj) {
28 | return obj == null || obj.length == 0;
29 | }
30 |
31 | /**
32 | * Collection是否为null或size为0
33 | *
34 | * @param obj Collection
35 | * @return 是否为空
36 | */
37 | public static boolean isEmpty(Collection> obj) {
38 | return obj == null || obj.isEmpty();
39 | }
40 |
41 | /**
42 | * Map是否为null或size为0
43 | *
44 | * @param obj Map
45 | * @return 是否为空
46 | */
47 | public static boolean isEmpty(Map, ?> obj) {
48 | return obj == null || obj.isEmpty();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # 设置日志的打印级别以及要输出到的地方
2 | # 优先级从高到低分别是 ERROR、WARN、INFO、DEBUG
3 | # 比如在这里定义了 INFO 级别,则应用程序中所有 DEBUG 级别的日志信息将不被打印
4 | # stdout 指代要输出到的地方,可以是不同的自定义名称,也可以有多个,表示输出到控制台
5 | log4j.rootLogger=debug,stdout
6 |
7 | # 输出信息到控制台
8 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
9 | log4j.appender.stdout.Target=System.out
10 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
11 |
12 | # 输出日志的格式
13 | # %c: 输出日志信息所属的类目,通常就是所在类的全名
14 | # %d: 输出日志时间点的日期或时间
15 | # %p: 输出日志信息优先级,即 DEBUG,INFO,WARN,ERROR,FATAL
16 | # %m: 输出代码中指定的消息,产生的日志具体信息
17 | # %n: 输出一个回车换行符,Windows 平台为"\r\n",Unix 平台为"\n"输出日志信息换行
18 | # 示例:com.enndfp.demo.HelloServlet 15:00:00 -- DEBUG -- test
19 | log4j.appender.stdout.layout.ConversionPattern=%c %d{HH:mm:ss} -- %p -- %m%n
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/jsp/hello.jsp:
--------------------------------------------------------------------------------
1 | <%@ page pageEncoding="UTF-8" isELIgnored="false" %>
2 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
3 |
4 |
5 | Hello
6 |
7 |
8 | Hello!
9 | 太牛逼了,${name}
10 |
11 |
--------------------------------------------------------------------------------
/src/main/webapp/static/coding.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Enndfp/simple-framework/98bb7e2d70c68bd5f4e932da1fcc95e9a62c6b18/src/main/webapp/static/coding.jpg
--------------------------------------------------------------------------------
/src/main/webapp/templates/addheadline.jsp:
--------------------------------------------------------------------------------
1 | <%@ page pageEncoding="UTF-8" isELIgnored="false" %>
2 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
3 |
4 |
5 | addheadline
6 |
7 |
8 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/AspectListExecutorTest.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.AspectInfo;
4 | import com.enndfp.simpleframework.aop.mock.*;
5 | import org.junit.jupiter.api.Test;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * @author Enndfp
12 | */
13 | public class AspectListExecutorTest {
14 |
15 | @Test
16 | public void sortTest() {
17 | List aspectInfoList = new ArrayList<>();
18 | aspectInfoList.add(new AspectInfo(3, new Mock1(),null));
19 | aspectInfoList.add(new AspectInfo(5, new Mock2(),null));
20 | aspectInfoList.add(new AspectInfo(2, new Mock3(),null));
21 | aspectInfoList.add(new AspectInfo(4, new Mock4(),null));
22 | aspectInfoList.add(new AspectInfo(1, new Mock5(),null));
23 | AspectListExecutor aspectListExecutor = new AspectListExecutor(AspectListExecutorTest.class, aspectInfoList);
24 | List sortedAspectInfoList = aspectListExecutor.getSortedAspectInfoList();
25 | for (AspectInfo aspectInfo : sortedAspectInfoList) {
26 | System.out.println(aspectInfo.getAspectObject().getClass().getName());
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/AspectWeaverTest.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop;
2 |
3 | import com.enndfp.demo.controller.frontend.MainPageController;
4 | import com.enndfp.simpleframework.core.BeanContainer;
5 | import com.enndfp.simpleframework.inject.DependencyInjector;
6 | import org.junit.jupiter.api.Test;
7 |
8 | /**
9 | * @author Enndfp
10 | */
11 | public class AspectWeaverTest {
12 |
13 | @Test
14 | void doAOPTest() {
15 | BeanContainer beanContainer = BeanContainer.getInstance();
16 | beanContainer.loadBeans("com.enndfp.demo");
17 | new AspectWeaver().doAOP();
18 | new DependencyInjector().doIOC();
19 | MainPageController mainPageController = (MainPageController) beanContainer.getBean(MainPageController.class);
20 | mainPageController.getMainPageInfo(null, null);
21 | }
22 | }
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/mock/Mock1.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.mock;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public class Mock1 extends DefaultAspect {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/mock/Mock2.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.mock;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public class Mock2 extends DefaultAspect {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/mock/Mock3.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.mock;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public class Mock3 extends DefaultAspect {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/mock/Mock4.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.mock;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public class Mock4 extends DefaultAspect {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/aop/mock/Mock5.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.aop.mock;
2 |
3 | import com.enndfp.simpleframework.aop.aspect.DefaultAspect;
4 |
5 | /**
6 | * @author Enndfp
7 | */
8 | public class Mock5 extends DefaultAspect {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/core/BeanContainerTest.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.core;
2 |
3 | import com.enndfp.simpleframework.mvc.DispatcherServlet;
4 | import com.enndfp.demo.controller.frontend.MainPageController;
5 | import com.enndfp.demo.service.solo.HeadLineService;
6 | import com.enndfp.demo.service.solo.impl.HeadLineServiceImpl;
7 | import com.enndfp.simpleframework.core.annotation.Controller;
8 | import org.junit.jupiter.api.*;
9 |
10 | /**
11 | * @author Enndfp
12 | */
13 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
14 | public class BeanContainerTest {
15 |
16 | private static BeanContainer beanContainer;
17 |
18 | @BeforeAll
19 | static void init() {
20 | beanContainer = BeanContainer.getInstance();
21 | }
22 |
23 | @Order(1)
24 | @Test
25 | public void loadBeansTest() {
26 | Assertions.assertEquals(false, beanContainer.isLoaded());
27 | beanContainer.loadBeans("com.enndfp.demo");
28 | Assertions.assertEquals(7, beanContainer.size());
29 | Assertions.assertEquals(true, beanContainer.isLoaded());
30 | }
31 |
32 | @Order(2)
33 | @Test
34 | public void getBeanTest() {
35 | MainPageController controller = (MainPageController) beanContainer.getBean(MainPageController.class);
36 | Assertions.assertEquals(true, controller instanceof MainPageController);
37 | DispatcherServlet dispatcherServlet = (DispatcherServlet) beanContainer.getBean(DispatcherServlet.class);
38 | Assertions.assertEquals(null, dispatcherServlet);
39 | }
40 |
41 | @Order(3)
42 | @Test
43 | public void getClassesByAnnotationTest() {
44 | Assertions.assertEquals(true, beanContainer.isLoaded());
45 | Assertions.assertEquals(3, beanContainer.getClassesByAnnotation(Controller.class).size());
46 | }
47 |
48 | @Order(4)
49 | @Test
50 | public void getClassesBySuperTest() {
51 | Assertions.assertEquals(true, beanContainer.isLoaded());
52 | Assertions.assertEquals(true, beanContainer.getClassesBySuper(HeadLineService.class).contains(HeadLineServiceImpl.class));
53 | }
54 | }
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/inject/DependencyInjectorTest.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.inject;
2 |
3 | import com.enndfp.demo.controller.frontend.MainPageController;
4 | import com.enndfp.demo.service.combine.impl.HeadLineShopCategoryCombineServiceImpl;
5 | import com.enndfp.simpleframework.core.BeanContainer;
6 | import org.junit.jupiter.api.Assertions;
7 | import org.junit.jupiter.api.Test;
8 |
9 | /**
10 | * @author Enndfp
11 | */
12 | public class DependencyInjectorTest {
13 |
14 | @Test
15 | public void doIOCTest() {
16 | BeanContainer beanContainer = BeanContainer.getInstance();
17 | beanContainer.loadBeans("com.enndfp.demo");
18 | Assertions.assertEquals(true,beanContainer.isLoaded());
19 | MainPageController mainPageController = (MainPageController) beanContainer.getBean(MainPageController.class);
20 | Assertions.assertEquals(true, mainPageController instanceof MainPageController);
21 | Assertions.assertEquals(null,mainPageController.getHeadLineShopCategoryCombineService());
22 | new DependencyInjector().doIOC();
23 | Assertions.assertNotEquals(null,mainPageController.getHeadLineShopCategoryCombineService());
24 | Assertions.assertEquals(true,mainPageController.getHeadLineShopCategoryCombineService() instanceof HeadLineShopCategoryCombineServiceImpl);
25 | }
26 | }
--------------------------------------------------------------------------------
/src/test/java/com/enndfp/simpleframework/utils/ClassUtilTest.java:
--------------------------------------------------------------------------------
1 | package com.enndfp.simpleframework.utils;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.Set;
7 |
8 | /**
9 | * @author Enndfp
10 | */
11 | public class ClassUtilTest {
12 |
13 | @Test
14 | public void extractPackageClassTest() {
15 | Set> classSet = ClassUtil.extractPackageClass("com.enndfp.demo.entity");
16 | System.out.println(classSet);
17 | Assertions.assertEquals(4, classSet.size());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------