设计模式责任链模式【二】

编程

什么是责任链模式

客户端发出一个请求,链上的对象都有机会处理这个请求,客户端不需要知道谁是具体的处理对象。

好处:

发送者和接受之间结耦,并且客户端可以实现动态组合责任链,编程更加方便灵活。

应用场景:

过滤器,api限流,权限控制,参数过滤,session过滤,表单过滤,请求头过滤等

项目结构和结果

这里我们以拦截关的形式,链表形式,开始上代码!

数据库表结构

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for gateway_handler

-- ----------------------------

DROP TABLE IF EXISTS `gateway_handler`;

CREATE TABLE `gateway_handler` (

`ID` int(11) NOT NULL AUTO_INCREMENT COMMENT "主键ID",

`handler_name` varchar(32) DEFAULT NULL COMMENT "handler名称",

`handler_id` varchar(32) DEFAULT NULL COMMENT "handler主键id",

`prev_handler_id` varchar(32) DEFAULT NULL,

`next_handler_id` varchar(32) DEFAULT NULL COMMENT "下一个handler",

PRIMARY KEY (`ID`)

) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT="权限表";

-- ----------------------------

-- Records of gateway_handler

-- ----------------------------

BEGIN;

INSERT INTO `gateway_handler` VALUES (16, "Api接口限流", "currentLimitHandler", NULL, "blacklistHandler");

INSERT INTO `gateway_handler` VALUES (17, "黑名单拦截", "blacklistHandler", "currentLimitHandler", "conversationHandler");

INSERT INTO `gateway_handler` VALUES (18, "会话验证", "conversationHandler", "blacklistHandler", NULL);

COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

pom.xml 配置

   <parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>2.0.1.RELEASE</version>

</parent>

<dependencies>

<!-- sprinboot web -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>1.16.10</version>

</dependency>

<dependency>

<groupId>commons-lang</groupId>

<artifactId>commons-lang</artifactId>

<version>2.6</version>

</dependency>

<dependency>

<groupId>org.mybatis.spring.boot</groupId>

<artifactId>mybatis-spring-boot-starter</artifactId>

<version>1.1.1</version>

</dependency>

<!-- mysql 依赖 -->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

</dependency>

</dependencies>

application.yml 配置文件

###服务启动端口号

server:

port: 80

spring:

###数据库相关连接

datasource:

username: root

password: root

driver-class-name: com.mysql.jdbc.Driver

url: jdbc:mysql://127.0.0.1:3306/design?useUnicode=true&characterEncoding=UTF-8

####打印MyBatias日志

logging:

level:

### 开发环境使用DEBUG 生产环境info或者error

com.mayikt.daiison.mapper: DEBUG

启动类

@SpringBootApplication

@MapperScan("com.daiison")

public class APP {

public static void main(String[] args) {

SpringApplication.run(APP.class,args);

}

}

springUtils可以根据类名小写获取类

import org.springframework.beans.BeansException;

import org.springframework.context.ApplicationContext;

import org.springframework.context.ApplicationContextAware;

import org.springframework.stereotype.Component;

@Component

public class SpringUtils implements ApplicationContextAware {

private static ApplicationContext applicationContext;

@Override

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

this.applicationContext = applicationContext;

}

//获取applicationContext

public static ApplicationContext getApplicationContext() {

return applicationContext;

}

//通过name获取 Bean.

public static Object getBean(String name){

return getApplicationContext().getBean(name);

}

//通过class获取Bean.

public static <T> T getBean(Class<T> clazz){

return getApplicationContext().getBean(clazz);

}

//通过name,以及Clazz返回指定的Bean

public static <T> T getBean(String name,Class<T> clazz){

return getApplicationContext().getBean(name, clazz);

}

}

pojo实体类

import lombok.Data;

import java.io.Serializable;

@Data

public class GatewayHandlerEntity implements Serializable, Cloneable {

/**

* 主键ID

*/

private Integer id;

/**

* handler名称

*/

private String handlerName;

/**

* handler主键id

*/

private String handlerId;

/**

* 下一个handler

*/

private String nextHandlerId;

}

mapper

import com.daiison.handler.mapper.entity.GatewayHandlerEntity;

import org.apache.ibatis.annotations.Select;

public interface GatewayHandlerMapper {

/**

* 获取第一个GatewayHandler

* @return

*/

@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE prev_handler_id is null;")

public GatewayHandlerEntity getFirstGatewayHandler();

@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE handler_id=#{handlerId}")

public GatewayHandlerEntity getByHandler(String handlerId);

}

 

public abstract class GatewayHandler {

/**

* 执行下一个handler

*/

protected GatewayHandler nextGatewayHandler;

/**

* 实现的handler 处理方案 强制必须实现

*/

public abstract void service();

public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {

this.nextGatewayHandler = nextGatewayHandler;

}

protected void nextService() {

if (nextGatewayHandler != null)

nextGatewayHandler.service();// 指向下一关黑名单

}

}

 

 

import com.daiison.handler.GatewayHandler;

import com.daiison.handler.mapper.GatewayHandlerMapper;

import com.daiison.handler.mapper.entity.GatewayHandlerEntity;

import com.daiison.utils.SpringUtils;

import org.apache.commons.lang.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

@Component

public class GatewayHandlerService {

@Autowired

private GatewayHandlerMapper gatewayHandlerMapper;

private GatewayHandler firstGatewayHandler;

public GatewayHandler getDbFirstGatewayHandler() {

if (firstGatewayHandler != null) {

return firstGatewayHandler;

}

// 1.从数据库中查询地址hanlder

GatewayHandlerEntity firstGatewayHandlerEntity = gatewayHandlerMapper.getFirstGatewayHandler();

if (firstGatewayHandlerEntity == null) {

return null;

}

// 2.获取springboot注入容器id

String handlerId = firstGatewayHandlerEntity.getHandlerId();

GatewayHandler firstGatewayHandler = SpringUtils.getBean(handlerId, GatewayHandler.class);

// 3.获取下一个handler容器beanid

String nextHandlerId = firstGatewayHandlerEntity.getNextHandlerId();

// 4. 记录当前循环hanlder对象

GatewayHandler tempGatewayHandler = firstGatewayHandler;

while (!StringUtils.isEmpty(nextHandlerId)) {

// 5.从springboot容器获取下一个handerl对象

GatewayHandler nextGatewayHandler = SpringUtils.getBean(nextHandlerId, GatewayHandler.class);

tempGatewayHandler.setNextGatewayHandler(nextGatewayHandler);

// 6.设置下一个nextHandlerId

GatewayHandlerEntity nextGatewayHandlerEntity = gatewayHandlerMapper.getByHandler(nextHandlerId);

if (nextGatewayHandlerEntity == null) {

break;

}

nextHandlerId = nextGatewayHandlerEntity.getNextHandlerId();

tempGatewayHandler = nextGatewayHandler;

}

this.firstGatewayHandler = firstGatewayHandler;

return firstGatewayHandler;

}

}

 

 

三个实现

 

@Component

public class CurrentLimitHandler extends GatewayHandler {

public void service() {

System.out.println("第一关-->api 接口的限流。。。");

nextService();

}

}

 

@Component

public class ConversationHandler extends GatewayHandler {

public void service() {

System.out.println("第三关-->api 黑名单拦截。。。");

}

}

 

@Component

public class BlacklistHandler extends GatewayHandler {

public void service() {

System.out.println("第二关-->api 用户会话拦截。。。");

nextService();// 指向下一关黑名单

}

}

 

最后controller

@RestController

public class HandlerController {

@Autowired

private GatewayHandlerService gatewayHandlerService;

@RequestMapping("/clentHanlder")

public String clentHanlder() {

GatewayHandler firstGatewayHandler = gatewayHandlerService.getDbFirstGatewayHandler();

firstGatewayHandler.service();

return "success";

}

}

 

以上是 设计模式责任链模式【二】 的全部内容, 来源链接: utcz.com/z/514593.html

回到顶部