├── src
├── main
│ ├── webapp
│ │ ├── static
│ │ │ └── coding.jpg
│ │ ├── WEB-INF
│ │ │ └── jsp
│ │ │ │ └── hello.jsp
│ │ └── templates
│ │ │ └── addheadline.jsp
│ ├── java
│ │ └── com
│ │ │ └── enndfp
│ │ │ ├── simpleframework
│ │ │ ├── mvc
│ │ │ │ ├── type
│ │ │ │ │ ├── RequestMethod.java
│ │ │ │ │ ├── RequestPathInfo.java
│ │ │ │ │ ├── ControllerMethod.java
│ │ │ │ │ └── ModelAndView.java
│ │ │ │ ├── render
│ │ │ │ │ ├── ResultRender.java
│ │ │ │ │ └── impl
│ │ │ │ │ │ ├── DefaultResultRender.java
│ │ │ │ │ │ ├── InternalErrorResultRender.java
│ │ │ │ │ │ ├── ResourceNotFoundResultRender.java
│ │ │ │ │ │ ├── JsonResultRender.java
│ │ │ │ │ │ └── ViewResultRender.java
│ │ │ │ ├── processor
│ │ │ │ │ ├── RequestProcessor.java
│ │ │ │ │ └── impl
│ │ │ │ │ │ ├── PreRequestProcessor.java
│ │ │ │ │ │ ├── JspRequestProcessor.java
│ │ │ │ │ │ ├── StaticResourceRequestProcessor.java
│ │ │ │ │ │ └── ControllerRequestProcessor.java
│ │ │ │ ├── annotation
│ │ │ │ │ ├── ResponseBody.java
│ │ │ │ │ ├── RequestParam.java
│ │ │ │ │ └── RequestMapping.java
│ │ │ │ ├── DispatcherServlet.java
│ │ │ │ └── RequestProcessorChain.java
│ │ │ ├── aop
│ │ │ │ ├── annotation
│ │ │ │ │ ├── Aspect.java
│ │ │ │ │ └── Order.java
│ │ │ │ ├── aspect
│ │ │ │ │ ├── AspectInfo.java
│ │ │ │ │ ├── DefaultAspect.java
│ │ │ │ │ └── PointcutLocator.java
│ │ │ │ ├── ProxyCreator.java
│ │ │ │ ├── AspectListExecutor.java
│ │ │ │ └── AspectWeaver.java
│ │ │ ├── core
│ │ │ │ ├── annotation
│ │ │ │ │ ├── Service.java
│ │ │ │ │ ├── Component.java
│ │ │ │ │ ├── Controller.java
│ │ │ │ │ └── Repository.java
│ │ │ │ └── BeanContainer.java
│ │ │ ├── inject
│ │ │ │ ├── annotation
│ │ │ │ │ └── Autowired.java
│ │ │ │ └── DependencyInjector.java
│ │ │ └── utils
│ │ │ │ ├── ValidationUtil.java
│ │ │ │ ├── ConverterUtil.java
│ │ │ │ └── ClassUtil.java
│ │ │ └── demo
│ │ │ ├── service
│ │ │ ├── combine
│ │ │ │ ├── HeadLineShopCategoryCombineService.java
│ │ │ │ └── impl
│ │ │ │ │ └── HeadLineShopCategoryCombineServiceImpl.java
│ │ │ └── solo
│ │ │ │ ├── impl
│ │ │ │ ├── HeadLineServiceImpl.java
│ │ │ │ └── ShopCategoryServiceImpl.java
│ │ │ │ ├── HeadLineService.java
│ │ │ │ └── ShopCategoryService.java
│ │ │ ├── entity
│ │ │ ├── dto
│ │ │ │ ├── MainPageInfoDTO.java
│ │ │ │ └── Result.java
│ │ │ └── bo
│ │ │ │ ├── HeadLine.java
│ │ │ │ └── ShopCategory.java
│ │ │ ├── HelloServlet.java
│ │ │ ├── aspect
│ │ │ └── ControllerTimeCalculatorAspect.java
│ │ │ └── controller
│ │ │ ├── superadmin
│ │ │ ├── HeadLineOperationController.java
│ │ │ └── ShopCategoryOperationController.java
│ │ │ └── frontend
│ │ │ └── MainPageController.java
│ └── resources
│ │ └── log4j.properties
└── test
│ └── java
│ └── com
│ └── enndfp
│ └── simpleframework
│ ├── aop
│ ├── mock
│ │ ├── Mock1.java
│ │ ├── Mock2.java
│ │ ├── Mock3.java
│ │ ├── Mock4.java
│ │ └── Mock5.java
│ ├── AspectWeaverTest.java
│ └── AspectListExecutorTest.java
│ ├── utils
│ └── ClassUtilTest.java
│ ├── inject
│ └── DependencyInjectorTest.java
│ └── core
│ └── BeanContainerTest.java
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
├── vcs.xml
├── .gitignore
├── encodings.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── JavaSceneConfigState.xml
├── compiler.xml
├── misc.xml
├── jarRepositories.xml
└── uiDesigner.xml
├── LICENSE
├── pom.xml
├── README.md
└── README-EN.md
/src/main/webapp/static/coding.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Enndfp/simple-framework/HEAD/src/main/webapp/static/coding.jpg
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/JavaSceneConfigState.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
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/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/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 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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