lichen 2 months ago
parent
commit
c103c2df9c
31 changed files with 1564 additions and 0 deletions
  1. 2 0
      pom.xml
  2. 84 0
      springboot-ldaptive/pom.xml
  3. 23 0
      springboot-ldaptive/src/main/java/org/example/lc/LdaptiveApplication.java
  4. 30 0
      springboot-ldaptive/src/main/java/org/example/lc/config/LdapConfig.java
  5. 263 0
      springboot-ldaptive/src/main/java/org/example/lc/config/RabbitConfig.java
  6. 32 0
      springboot-ldaptive/src/main/java/org/example/lc/config/SwaggerConfig.java
  7. 25 0
      springboot-ldaptive/src/main/java/org/example/lc/controller/HelloController.java
  8. 46 0
      springboot-ldaptive/src/main/java/org/example/lc/controller/LdapController.java
  9. 33 0
      springboot-ldaptive/src/main/java/org/example/lc/controller/OneSendMultiRecverController.java
  10. 29 0
      springboot-ldaptive/src/main/java/org/example/lc/controller/TopicExchangeController.java
  11. 21 0
      springboot-ldaptive/src/main/java/org/example/lc/request/AddUserReq.java
  12. 17 0
      springboot-ldaptive/src/main/java/org/example/lc/request/DelUserReq.java
  13. 22 0
      springboot-ldaptive/src/main/java/org/example/lc/request/LoginRequest.java
  14. 224 0
      springboot-ldaptive/src/main/java/org/example/lc/response/BasePageResponse.java
  15. 77 0
      springboot-ldaptive/src/main/java/org/example/lc/response/ResponseBean.java
  16. 7 0
      springboot-ldaptive/src/main/java/org/example/lc/response/ResponseStatus.java
  17. 58 0
      springboot-ldaptive/src/main/java/org/example/lc/service/LdapService.java
  18. 22 0
      springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloMoreReceiver1.java
  19. 23 0
      springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloMoreReceiver2.java
  20. 26 0
      springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloOneSender.java
  21. 22 0
      springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicMessageReceiver.java
  22. 22 0
      springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicMessagesReceiver.java
  23. 30 0
      springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicSender.java
  24. 12 0
      springboot-ldaptive/src/main/resources/application.properties
  25. 44 0
      springboot-ldaptive/src/test/java/org/example/lc/LdapSearchExample.java
  26. 55 0
      springboot-tabula/pom.xml
  27. 29 0
      springboot-tabula/src/main/java/org/example/lc/TabulaApplication.java
  28. 31 0
      springboot-tabula/src/main/java/org/example/lc/config/SwaggerConfig.java
  29. 25 0
      springboot-tabula/src/main/java/org/example/lc/controller/HelloController.java
  30. 115 0
      springboot-tabula/src/test/java/org/example/lc/Test.java
  31. 115 0
      springboot-tabula/src/test/java/org/example/lc/TestSE.java

+ 2 - 0
pom.xml

@@ -13,5 +13,7 @@
         <module>springboot-swagger</module>
         <module>springboot-knife</module>
         <module>springboot-jdbc-mysql</module>
+        <module>springboot-ldaptive</module>
+        <module>springboot-tabula</module>
     </modules>
 </project>

+ 84 - 0
springboot-ldaptive/pom.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>springboot-ldaptive</artifactId>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.6.RELEASE</version>
+    </parent>
+
+    <properties>
+        <swagger.version>2.7.0</swagger.version>
+    </properties>
+
+    <dependencies>
+        <!-- Spring Boot web依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <!-- Knife4j Dependency -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.ldaptive</groupId>
+            <artifactId>ldaptive</artifactId>
+            <version>1.2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.16</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+            <version>2.0.1.Final</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-core</artifactId>
+            <version>3.5.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.tika</groupId>
+            <artifactId>tika-core</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tika</groupId>
+            <artifactId>tika-parsers-standard-package</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+
+    </dependencies>
+</project>

+ 23 - 0
springboot-ldaptive/src/main/java/org/example/lc/LdaptiveApplication.java

@@ -0,0 +1,23 @@
+package org.example.lc;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@SpringBootApplication
+public class LdaptiveApplication {
+    public static void main(String[] args) {
+
+        // 程序启动入口
+        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
+        SpringApplication.run(LdaptiveApplication.class, args);
+    }
+}

+ 30 - 0
springboot-ldaptive/src/main/java/org/example/lc/config/LdapConfig.java

@@ -0,0 +1,30 @@
+package org.example.lc.config;
+
+import org.ldaptive.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class LdapConfig {
+    @Value("${ldap.url}")
+    private String ldapUrl;
+
+    @Value("${ldap.base-dn}")
+    private String baseDn;
+
+    @Value("${ldap.user-dn}")
+    private String userDn;
+
+    @Value("${ldap.password}")
+    private String password;
+
+    @Bean
+    public ConnectionFactory connectionFactory() {
+        ConnectionConfig connConfig = new ConnectionConfig(ldapUrl);
+        connConfig.setConnectionInitializer(
+                new BindConnectionInitializer(
+                        userDn, new Credential(password)));
+        return new DefaultConnectionFactory(connConfig);
+    }
+}

+ 263 - 0
springboot-ldaptive/src/main/java/org/example/lc/config/RabbitConfig.java

@@ -0,0 +1,263 @@
+package org.example.lc.config;
+
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+@Configuration
+public class RabbitConfig {
+
+
+	@Value("${rabbitmq.host}")
+	private String host;
+
+	@Value("${rabbitmq.port}")
+	private int port;
+
+	@Value("${rabbitmq.username}")
+	private String username;
+
+	@Value("${rabbitmq.password}")
+	private String password;
+
+	@Value("${rabbitmq.publisher-confirms}")
+	private boolean publisherConfirm;
+
+	@Value("${rabbitmq.virtual-host}")
+	private String virtualHost;
+
+
+
+	@Bean
+	public ConnectionFactory connFactory() {
+		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
+		connectionFactory.setHost(host);
+		connectionFactory.setPort(port);
+		connectionFactory.setUsername(username);
+		connectionFactory.setPassword(password);
+		connectionFactory.setVirtualHost(virtualHost);
+		connectionFactory.setPublisherConfirms(publisherConfirm); //必须要设置
+		return connectionFactory;
+	}
+
+	//////////////////////////////针对消息 delay queue////////////////////////////////
+	/**
+	 * 发送到该队列的message会在一段时间后过期进入到delay_process_queue
+	 * 每个message可以控制自己的失效时间
+	 */
+	public final static String DELAY_QUEUE_MSG = "delay_queue";
+
+	/**
+	 * DLX
+	 */
+	public final static String DELAY_EXCHANGE_NAME = "delay_exchange";
+
+
+	/**
+	 * 正常消费的队列
+	 */
+	public final static String PROCESS_QUEUE = "process_queue";
+
+	/**
+	 * 正常队列对应的exchange
+	 */
+	public final static String PROCESS_EXCHANGE_NAME = "process_exchange";
+
+
+	public static String ROUTING_KEY = "delay";
+
+	/**
+	 * 延迟队列 exchange
+	 * @return
+	 */
+	@Bean
+	public DirectExchange delayExchange() {
+		return new DirectExchange(DELAY_EXCHANGE_NAME);
+	}
+
+	@Bean
+	public DirectExchange processExchange() {
+		return new DirectExchange(PROCESS_EXCHANGE_NAME);
+	}
+
+	/**
+	 * 存放延迟消息的队列 最后将会转发给exchange(实际消费队列对应的)
+	 * @return
+	 */
+	@Bean
+    Queue delayQueue4Msg(){
+		return QueueBuilder.durable(DELAY_QUEUE_MSG)
+				.withArgument("x-dead-letter-exchange", PROCESS_EXCHANGE_NAME) // DLX,dead letter发送到的exchange
+				.withArgument("x-dead-letter-routing-key", ROUTING_KEY) // dead letter携带的routing key
+				.build();
+	}
+
+	@Bean
+	public Queue processQueue() {
+		return QueueBuilder.durable(PROCESS_QUEUE)
+				.build();
+	}
+
+
+
+	/**
+	 * 将延迟队列与exchange绑定,即到达指定时间之后需要转交给queue消费
+	 * @return
+	 */
+	@Bean
+    Binding delayBinding() {
+		return BindingBuilder.bind(delayQueue4Msg())
+				.to(delayExchange())
+				.with(ROUTING_KEY);
+	}
+
+	@Bean
+    Binding queueBinding() {
+		return BindingBuilder.bind(processQueue())
+				.to(processExchange())
+				.with(ROUTING_KEY);
+	}
+
+	//////////////////////////////delay////////////////////////////////
+
+
+	//////////////////////////////针对队列delay////////////////////////////////
+
+	/**
+	 * 针对队列设置过期时间的队列
+	 */
+	public final static String DELAY_QUEUE_NAME = "delay_queue_queue";
+
+	public final static String DELAY_QUEUE_EXCHANGE_NAME = "delay_queue_exchange";
+
+	@Bean
+	public DirectExchange delayQueueExchange() {
+		return new DirectExchange(DELAY_QUEUE_EXCHANGE_NAME);
+	}
+
+	/**
+	 * 存放消息的延迟队列 最后将会转发给exchange(实际消费队列对应的)
+	 * @return
+	 */
+	@Bean
+	public Queue delayQueue4Queue() {
+		return QueueBuilder.durable(DELAY_QUEUE_NAME)
+				.withArgument("x-dead-letter-exchange", PROCESS_EXCHANGE_NAME) // DLX
+				.withArgument("x-dead-letter-routing-key", ROUTING_KEY) // dead letter携带的routing key
+				.withArgument("x-message-ttl", 3000) // 设置队列的过期时间
+				.build();
+	}
+
+	@Bean
+    Binding delayQueueBind() {
+		return BindingBuilder.bind(delayQueue4Queue())
+				.to(delayQueueExchange())
+				.with(ROUTING_KEY);
+	}
+
+
+
+	@Bean
+	public Queue helloQueue() {
+		return new Queue("helloQueue");
+	}
+
+	@Bean
+	public Queue msgQueue() {
+		return new Queue("msgQueue");
+	}
+
+	//===============以下是验证topic Exchange的队列==========
+	@Bean
+	public Queue queueMessage() {
+		return new Queue("topic.message");
+	}
+
+	@Bean
+	public Queue queueMessages() {
+		return new Queue("topic.messages");
+	}
+	//===============以上是验证topic Exchange的队列==========
+
+
+	//===============以下是验证Fanout Exchange的队列==========
+	@Bean
+	public Queue AMessage() {
+		return new Queue("fanout.A");
+	}
+
+	@Bean
+	public Queue BMessage() {
+		return new Queue("fanout.B");
+	}
+
+	@Bean
+	public Queue CMessage() {
+		return new Queue("fanout.C");
+	}
+	//===============以上是验证Fanout Exchange的队列==========
+
+
+	@Bean
+    TopicExchange exchange() {
+		return new TopicExchange("exchange");
+	}
+
+	@Bean
+    FanoutExchange fanoutExchange() {
+		return new FanoutExchange("fanoutExchange");
+	}
+
+	/**
+	 * 将队列topic.message与exchange绑定,binding_key为topic.message,就是完全匹配
+	 * @param queueMessage
+	 * @param exchange
+	 * @return
+	 */
+	@Bean
+    Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
+		return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
+	}
+
+	/**
+	 * 将队列topic.messages与exchange绑定,binding_key为topic.#,模糊匹配
+	 * @param queueMessages
+	 * @param exchange
+	 * @return
+	 */
+	@Bean
+    Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
+		return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
+	}
+
+	@Bean
+    Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
+		return BindingBuilder.bind(AMessage).to(fanoutExchange);
+	}
+
+	@Bean
+    Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
+		return BindingBuilder.bind(BMessage).to(fanoutExchange);
+	}
+
+	@Bean
+    Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
+		return BindingBuilder.bind(CMessage).to(fanoutExchange);
+	}
+
+
+	@Bean
+	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+	//必须是prototype类型
+	public RabbitTemplate rabbitTemplate() {
+		RabbitTemplate template = new RabbitTemplate(connFactory());
+		return template;
+	}
+
+}

+ 32 - 0
springboot-ldaptive/src/main/java/org/example/lc/config/SwaggerConfig.java

@@ -0,0 +1,32 @@
+package org.example.lc.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
+                .apis(RequestHandlerSelectors.basePackage("org.example.lc")) //扫描API的包路径
+                .paths(PathSelectors.any()).build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder().title("SpringBoot整合Ldaptive") // 标题
+                .description("api接口的文档整理,支持在线测试") // 描述
+                .contact(new Contact("vector.wang", "http://blog.wangxc.club/", "vector4wang@qq.com"))
+                .version("1.0") // 版本号
+                .build();
+    }
+}

+ 25 - 0
springboot-ldaptive/src/main/java/org/example/lc/controller/HelloController.java

@@ -0,0 +1,25 @@
+package org.example.lc.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * Spring Boot Hello案例
+ *
+ * Created by bysocket on 26/09/2017.
+ */
+@Api(value = "HelloController", tags = {"hello 控制类"})
+@Controller
+public class HelloController {
+
+    @ApiOperation("打招呼")
+    @RequestMapping(value = "/hello",method = RequestMethod.GET)
+    @ResponseBody
+    public String sayHello() {
+        return "Hello,Spring Boot!";
+    }
+}

+ 46 - 0
springboot-ldaptive/src/main/java/org/example/lc/controller/LdapController.java

@@ -0,0 +1,46 @@
+package org.example.lc.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.example.lc.request.AddUserReq;
+import org.example.lc.request.DelUserReq;
+import org.example.lc.response.ResponseBean;
+import org.example.lc.service.LdapService;
+import org.ldaptive.LdapException;
+import org.ldaptive.SearchResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+@Api(value = "LdapController", tags = {"ldap控制类"})
+@RestController
+@RequestMapping("/user")
+public class LdapController {
+
+    @Autowired
+    private LdapService ldapService;
+
+    @ApiOperation("查询")
+    @GetMapping("/search")
+    public SearchResult search(@RequestParam String filter) throws LdapException {
+        return ldapService.search(filter);
+    }
+
+    @ApiOperation("新增用户")
+    @PostMapping("/add")
+    public ResponseBean<Boolean> add(@Valid @RequestBody AddUserReq addUserReq) {
+        try {
+            ldapService.addUser(addUserReq);
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }
+        return null;
+    }
+
+    @ApiOperation("删除用户")
+    @PostMapping("/del")
+    public ResponseBean<Boolean> del(@Valid @RequestBody DelUserReq delUserReq) {
+        return null;
+    }
+}

+ 33 - 0
springboot-ldaptive/src/main/java/org/example/lc/controller/OneSendMultiRecverController.java

@@ -0,0 +1,33 @@
+package org.example.lc.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.example.lc.service.onesendmultirecver.HelloOneSender;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created with IDEA
+ * User: vector
+ * Data: 2017/7/7
+ * Time: 17:06
+ * Description:
+ */
+@RestController
+@RequestMapping("/rabbit2")
+@Api(value = "单生产者-多消费者",description = "")
+public class OneSendMultiRecverController {
+    @Autowired
+    private HelloOneSender helloSender1;
+
+    @ApiOperation("单生产者-多消费者")
+    @RequestMapping(value = "/oneToMany",method = RequestMethod.GET)
+    public void oneToMany() {
+        for(int i=0;i<10;i++){
+            helloSender1.send("hellomsg:"+i);
+        }
+
+    }
+}

+ 29 - 0
springboot-ldaptive/src/main/java/org/example/lc/controller/TopicExchangeController.java

@@ -0,0 +1,29 @@
+package org.example.lc.controller;
+
+import io.swagger.annotations.Api;
+import org.example.lc.service.topicExChange.TopicSender;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @Author: wangxc
+ * @GitHub: https://github.com/vector4wang
+ * @CSDN: http://blog.csdn.net/qqhjqs?viewmode=contents
+ * @BLOG: http://vector4wang.tk
+ * @wxid: BMHJQS
+ */
+@RestController
+@RequestMapping("/rabbit5")
+@Api(value = "topic exchange类型rabbitmq",description = "")
+public class TopicExchangeController {
+
+    @Autowired
+    private TopicSender topicSender;
+
+    @RequestMapping(value = "/topic",method = RequestMethod.GET)
+    public void topicTest() {
+        topicSender.send();
+    }
+}

+ 21 - 0
springboot-ldaptive/src/main/java/org/example/lc/request/AddUserReq.java

@@ -0,0 +1,21 @@
+package org.example.lc.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@ApiModel(value = "新增用户")
+@Data
+public class AddUserReq implements Serializable {
+    private static final long serialVersionUID = -924264960096376543L;
+
+    @ApiModelProperty(value = "用户名", example = "san.zhang001", required = true)
+    private String userName;
+    @ApiModelProperty(value = "密码", example = "", required = true)
+    private String pwd;
+    @ApiModelProperty(value = "邮箱", example = "san.zhang001@northking.net", required = true)
+    private String email;
+
+}

+ 17 - 0
springboot-ldaptive/src/main/java/org/example/lc/request/DelUserReq.java

@@ -0,0 +1,17 @@
+package org.example.lc.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@ApiModel(value = "删除用户")
+@Data
+public class DelUserReq implements Serializable {
+
+    private static final long serialVersionUID = 5219352610963835022L;
+    @ApiModelProperty(value = "用户名", example = "san.zhang001", required = true)
+    private String userName;
+
+}

+ 22 - 0
springboot-ldaptive/src/main/java/org/example/lc/request/LoginRequest.java

@@ -0,0 +1,22 @@
+package org.example.lc.request;
+
+public class LoginRequest {
+    private String username;
+    private String password;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 224 - 0
springboot-ldaptive/src/main/java/org/example/lc/response/BasePageResponse.java

@@ -0,0 +1,224 @@
+package org.example.lc.response;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class BasePageResponse<Condition, T> implements IPage<T> {
+    private static final long serialVersionUID = 6992537305369600956L;
+    @ApiModelProperty("查询条件")
+    protected Condition condition;
+    @ApiModelProperty("查询数据列表")
+    protected List<T> records;
+    @ApiModelProperty(
+            value = "总记录数",
+            example = "10",
+            required = true
+    )
+    protected long total;
+    @ApiModelProperty(
+            value = "每页显示条数,默认 10",
+            example = "10",
+            required = true
+    )
+    protected long size;
+    @ApiModelProperty(
+            value = "当前页,第一页用1表示",
+            example = "1",
+            required = true
+    )
+    protected long current;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "排序字段信息",
+            required = false,
+            hidden = true
+    )
+    protected List<OrderItem> orders;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "是否自动优化 COUNT SQL",
+            hidden = true
+    )
+    protected boolean optimizeCountSql;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "是否进行 count 查询",
+            hidden = true
+    )
+    protected boolean isSearchCount;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "是否命中count缓存",
+            hidden = true
+    )
+    protected boolean hitCount;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "COUNT SQL的方法名",
+            hidden = true
+    )
+    protected String countId;
+    @JsonIgnore
+    @ApiModelProperty(
+            value = "最大每页分页数限制",
+            hidden = true
+    )
+    protected Long maxLimit;
+
+    public BasePageResponse() {
+        this.records = Collections.emptyList();
+        this.total = 0L;
+        this.size = 10L;
+        this.current = 1L;
+        this.orders = new ArrayList();
+        this.optimizeCountSql = true;
+        this.isSearchCount = true;
+        this.hitCount = false;
+    }
+
+    public BasePageResponse(long current, long size) {
+        this(current, size, 0L);
+    }
+
+    public BasePageResponse(long current, long size, long total) {
+        this(current, size, total, true);
+    }
+
+    public BasePageResponse(long current, long size, boolean isSearchCount) {
+        this(current, size, 0L, isSearchCount);
+    }
+
+    public BasePageResponse(long current, long size, long total, boolean isSearchCount) {
+        this.records = Collections.emptyList();
+        this.total = 0L;
+        this.size = 10L;
+        this.current = 1L;
+        this.orders = new ArrayList();
+        this.optimizeCountSql = true;
+        this.isSearchCount = true;
+        this.hitCount = false;
+        if (current > 1L) {
+            this.current = current;
+        }
+
+        this.size = size;
+        this.total = total;
+        this.isSearchCount = isSearchCount;
+    }
+
+    public List<OrderItem> orders() {
+        return this.orders;
+    }
+
+    public BasePageResponse<Condition, T> setRecords(List<T> records) {
+        this.records = records;
+        return this;
+    }
+
+    public BasePageResponse<Condition, T> setTotal(long total) {
+        this.total = total;
+        return this;
+    }
+
+    public BasePageResponse<Condition, T> setSize(long size) {
+        this.size = size;
+        return this;
+    }
+
+    public BasePageResponse<Condition, T> setCurrent(long current) {
+        this.current = current;
+        return this;
+    }
+
+    public boolean hasPrevious() {
+        return this.current > 1L;
+    }
+
+    public boolean hasNext() {
+        return this.current < this.getPages();
+    }
+
+    public Condition getCondition() {
+        return this.condition;
+    }
+
+    public List<T> getRecords() {
+        return this.records;
+    }
+
+    public long getTotal() {
+        return this.total;
+    }
+
+    public long getSize() {
+        return this.size;
+    }
+
+    public long getCurrent() {
+        return this.current;
+    }
+
+    public List<OrderItem> getOrders() {
+        return this.orders;
+    }
+
+    public boolean isOptimizeCountSql() {
+        return this.optimizeCountSql;
+    }
+
+    public boolean isSearchCount() {
+        return this.isSearchCount;
+    }
+
+    public boolean isHitCount() {
+        return this.hitCount;
+    }
+
+    public String getCountId() {
+        return this.countId;
+    }
+
+    public Long getMaxLimit() {
+        return this.maxLimit;
+    }
+
+    public void setCondition(Condition condition) {
+        this.condition = condition;
+    }
+
+    @JsonIgnore
+    public void setOrders(List<OrderItem> orders) {
+        this.orders = orders;
+    }
+
+    @JsonIgnore
+    public void setOptimizeCountSql(boolean optimizeCountSql) {
+        this.optimizeCountSql = optimizeCountSql;
+    }
+
+    @JsonIgnore
+    public void setSearchCount(boolean isSearchCount) {
+        this.isSearchCount = isSearchCount;
+    }
+
+    @JsonIgnore
+    public void setHitCount(boolean hitCount) {
+        this.hitCount = hitCount;
+    }
+
+    @JsonIgnore
+    public void setCountId(String countId) {
+        this.countId = countId;
+    }
+
+    @JsonIgnore
+    public void setMaxLimit(Long maxLimit) {
+        this.maxLimit = maxLimit;
+    }
+}

+ 77 - 0
springboot-ldaptive/src/main/java/org/example/lc/response/ResponseBean.java

@@ -0,0 +1,77 @@
+package org.example.lc.response;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+public final class ResponseBean<T> implements Serializable {
+    private static final long serialVersionUID = -8313419428896543658L;
+    @NotNull
+    @ApiModelProperty(
+            value = "返回编码",
+            example = "000000",
+            required = true
+    )
+    private String code;
+    @NotNull
+    @ApiModelProperty(
+            value = "返回信息",
+            example = "操作成功",
+            required = true
+    )
+    private String message;
+    @ApiModelProperty("返回数据")
+    private T object;
+
+    /** @deprecated */
+    @Deprecated
+    public ResponseBean() {
+    }
+
+    ResponseBean(@NotNull ResponseStatus status) {
+        this.code = status.getCode();
+        this.message = status.getMessage();
+    }
+
+    ResponseBean(@NotNull ResponseStatus status, T object) {
+        this.code = status.getCode();
+        this.message = status.getMessage();
+        this.object = object;
+    }
+
+    ResponseBean(@NotNull ResponseBean responseBean) {
+        this.code = responseBean.getCode();
+        this.message = responseBean.getMessage();
+    }
+
+    ResponseBean(@NotNull ResponseBean responseBean, T object) {
+        this.code = responseBean.getCode();
+        this.message = responseBean.getMessage();
+        this.object = object;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getMessage() {
+        return this.message;
+    }
+
+    public T getObject() {
+        return this.object;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public void setObject(T object) {
+        this.object = object;
+    }
+}

+ 7 - 0
springboot-ldaptive/src/main/java/org/example/lc/response/ResponseStatus.java

@@ -0,0 +1,7 @@
+package org.example.lc.response;
+
+public interface ResponseStatus {
+    String getCode();
+
+    String getMessage();
+}

+ 58 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/LdapService.java

@@ -0,0 +1,58 @@
+package org.example.lc.service;
+
+import org.example.lc.request.AddUserReq;
+import org.example.lc.response.ResponseBean;
+import org.ldaptive.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Service
+public class LdapService {
+    @Value("${ldap.base-dn}")
+    private String baseDn;
+
+    @Autowired
+    private ConnectionFactory connectionFactory;
+
+    public SearchResult search(String filter) throws LdapException {
+        Connection conn = connectionFactory.getConnection();
+        try {
+            conn.open();
+
+            SearchOperation search = new SearchOperation(conn);
+            SearchResult result = search.execute(
+                    new SearchRequest(
+                            baseDn, "(cn=*)")).getResult();
+
+            for (LdapEntry entry : result.getEntries()) {
+                // do something useful with the entry
+                System.out.println(entry.getDn());
+                entry.getAttributes();
+
+            }
+
+        } finally {
+            conn.close();
+        }
+        return null;
+    }
+
+    public ResponseBean<Boolean> addUser(AddUserReq req) throws LdapException {
+        LdapEntry entry = new LdapEntry(
+                "cn=" + req.getUserName() + ",cn=readers,ou=users,dc=northking,dc=net",
+                new LdapAttribute("userName", req.getUserName()),
+                new LdapAttribute("pwd", req.getPwd()),
+                new LdapAttribute("email", req.getEmail()));
+
+        Connection conn = connectionFactory.getConnection();
+        try {
+            conn.open();
+            AddOperation add = new AddOperation(conn);
+            add.execute(new AddRequest(entry.getDn(), entry.getAttributes()));
+        } finally {
+            conn.close();
+        }
+        return null;
+    }
+}

+ 22 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloMoreReceiver1.java

@@ -0,0 +1,22 @@
+package org.example.lc.service.onesendmultirecver;
+
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created with IDEA
+ * User: vector
+ * Data: 2017/7/7
+ * Time: 17:05
+ * Description:
+ */
+@Component
+@RabbitListener(queues = "helloQueue")
+public class HelloMoreReceiver1 {
+
+    @RabbitHandler
+    public void process(String hello) {
+        System.out.println("Receiver1  : " + hello);
+    }
+}

+ 23 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloMoreReceiver2.java

@@ -0,0 +1,23 @@
+package org.example.lc.service.onesendmultirecver;
+
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created with IDEA
+ * User: vector
+ * Data: 2017/7/7
+ * Time: 17:05
+ * Description:
+ */
+@Component
+@RabbitListener(queues = "helloQueue")
+public class HelloMoreReceiver2 {
+
+    @RabbitHandler
+    public void process(String hello) {
+        System.out.println("Receiver2  : " + hello);
+    }
+
+}

+ 26 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/onesendmultirecver/HelloOneSender.java

@@ -0,0 +1,26 @@
+package org.example.lc.service.onesendmultirecver;
+
+import org.springframework.amqp.core.AmqpTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+/**
+ * Created with IDEA
+ * User: vector
+ * Data: 2017/7/7
+ * Time: 17:04
+ * Description:单生产者-多消费者
+ */
+@Component
+public class HelloOneSender {
+    @Autowired
+    private AmqpTemplate rabbitTemplate;
+
+    public void send(String msg) {
+        String sendMsg = msg + new Date();
+        System.out.println("Sender1 : " + sendMsg);
+        this.rabbitTemplate.convertAndSend("helloQueue", sendMsg);
+    }
+}

+ 22 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicMessageReceiver.java

@@ -0,0 +1,22 @@
+package org.example.lc.service.topicExChange;
+
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: wangxc
+ * @GitHub: https://github.com/vector4wang
+ * @CSDN: http://blog.csdn.net/qqhjqs?viewmode=contents
+ * @BLOG: http://vector4wang.tk
+ * @wxid: BMHJQS
+ */
+@Component
+@RabbitListener(queues = "topic.message")
+public class TopicMessageReceiver {
+
+    @RabbitHandler
+    public void process(String msg) {
+        System.out.println("topicMessageReceiver  : " +msg);
+    }
+}

+ 22 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicMessagesReceiver.java

@@ -0,0 +1,22 @@
+package org.example.lc.service.topicExChange;
+
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: wangxc
+ * @GitHub: https://github.com/vector4wang
+ * @CSDN: http://blog.csdn.net/qqhjqs?viewmode=contents
+ * @BLOG: http://vector4wang.tk
+ * @wxid: BMHJQS
+ */
+@Component
+@RabbitListener(queues = "topic.messages")
+public class TopicMessagesReceiver {
+
+    @RabbitHandler
+    public void process(String msg) {
+        System.out.println("topicMessagesReceiver  : " +msg);
+    }
+}

+ 30 - 0
springboot-ldaptive/src/main/java/org/example/lc/service/topicExChange/TopicSender.java

@@ -0,0 +1,30 @@
+package org.example.lc.service.topicExChange;
+
+import org.springframework.amqp.core.AmqpTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: wangxc
+ * @GitHub: https://github.com/vector4wang
+ * @CSDN: http://blog.csdn.net/qqhjqs?viewmode=contents
+ * @BLOG: http://vector4wang.tk
+ * @wxid: BMHJQS
+ */
+@Component
+public class TopicSender {
+
+    @Autowired
+    private AmqpTemplate rabbitTemplate;
+
+    public void send() {
+        String msg1 = "I am topic.mesaage msg======";
+        System.out.println("sender1 : " + msg1);
+        this.rabbitTemplate.convertAndSend("exchange", "topic.message", msg1);
+
+        String msg2 = "I am topic.mesaages msg########";
+        System.out.println("sender2 : " + msg2);
+        this.rabbitTemplate.convertAndSend("exchange", "topic.messages", msg2);
+    }
+
+}

+ 12 - 0
springboot-ldaptive/src/main/resources/application.properties

@@ -0,0 +1,12 @@
+ldap.url=ldap://localhost:1389
+ldap.base-dn=dc=northking,dc=net
+ldap.user-dn=cn=admin,dc=northking,dc=net
+ldap.password=123456
+
+
+rabbitmq.host=localhost
+rabbitmq.port=5672
+rabbitmq.username=guest
+rabbitmq.password=guest
+rabbitmq.publisher-confirms=true
+rabbitmq.virtual-host=/

+ 44 - 0
springboot-ldaptive/src/test/java/org/example/lc/LdapSearchExample.java

@@ -0,0 +1,44 @@
+package org.example.lc;
+
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import java.util.Hashtable;
+
+public class LdapSearchExample {
+    public static void main(String[] args) {
+        String ldapUrl = "ldap://localhost:1389";
+        String baseDn = "dc=northking,dc=net";
+        String userDn = "cn=admin,dc=northking,dc=net";
+        String password = "123456";
+        String filter = "(uid=jdoe)"; // 示例过滤器
+
+        Hashtable<String, String> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put(Context.PROVIDER_URL, ldapUrl);
+        env.put(Context.SECURITY_AUTHENTICATION, "simple");
+        env.put(Context.SECURITY_PRINCIPAL, userDn);
+        env.put(Context.SECURITY_CREDENTIALS, password);
+
+        try {
+            DirContext ctx = new InitialDirContext(env);
+            SearchControls searchControls = new SearchControls();
+            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
+
+            NamingEnumeration<SearchResult> results = ctx.search(baseDn, filter, searchControls);
+
+            while (results.hasMore()) {
+                SearchResult result = results.next();
+                System.out.println(result.getNameInNamespace());
+            }
+
+            ctx.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 55 - 0
springboot-tabula/pom.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>springboot-tabula</artifactId>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.6.RELEASE</version>
+    </parent>
+
+    <properties>
+        <swagger.version>2.7.0</swagger.version>
+    </properties>
+
+    <dependencies>
+        <!-- Spring Boot web依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <!-- Knife4j Dependency -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>technology.tabula</groupId>
+            <artifactId>tabula</artifactId>
+            <version>1.0.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>3.0.2</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 29 - 0
springboot-tabula/src/main/java/org/example/lc/TabulaApplication.java

@@ -0,0 +1,29 @@
+package org.example.lc;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+//@EnableSwagger2
+public class TabulaApplication {
+//    @Bean
+//    public Docket createRestApi() {
+//        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
+//                .apis(RequestHandlerSelectors.basePackage("org.example.lc")) //扫描API的包路径
+//                .paths(PathSelectors.any()).build();
+//    }
+//
+//    private ApiInfo apiInfo() {
+//        return new ApiInfoBuilder().title("SpringBoot整合Knife") // 标题
+//                .description("api接口的文档整理,支持在线测试") // 描述
+//                .contact(new Contact("vector.wang", "http://blog.wangxc.club/", "vector4wang@qq.com"))
+//                .version("1.0") // 版本号
+//                .build();
+//    }
+    public static void main(String[] args) {
+
+        // 程序启动入口
+        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
+        SpringApplication.run(TabulaApplication.class, args);
+    }
+}

+ 31 - 0
springboot-tabula/src/main/java/org/example/lc/config/SwaggerConfig.java

@@ -0,0 +1,31 @@
+package org.example.lc.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
+                .apis(RequestHandlerSelectors.basePackage("org.example.lc")) //扫描API的包路径
+                .paths(PathSelectors.any()).build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder().title("SpringBoot整合Tabula") // 标题
+                .description("api接口的文档整理,支持在线测试") // 描述
+                .contact(new Contact("vector.wang", "http://blog.wangxc.club/", "vector4wang@qq.com"))
+                .version("1.0") // 版本号
+                .build();
+    }
+}

+ 25 - 0
springboot-tabula/src/main/java/org/example/lc/controller/HelloController.java

@@ -0,0 +1,25 @@
+package org.example.lc.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * Spring Boot Hello案例
+ *
+ * Created by bysocket on 26/09/2017.
+ */
+@Api(value = "HelloController", tags = {"hello 控制类"})
+@Controller
+public class HelloController {
+
+    @ApiOperation("打招呼")
+    @RequestMapping(value = "/hello",method = RequestMethod.GET)
+    @ResponseBody
+    public String sayHello() {
+        return "Hello,Spring Boot!";
+    }
+}

+ 115 - 0
springboot-tabula/src/test/java/org/example/lc/Test.java

@@ -0,0 +1,115 @@
+package org.example.lc;
+
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import technology.tabula.*;
+import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+public class Test {
+
+    private List<String> readPdfTables(String filename, String startMarker, String endMarker) throws Exception {
+        PDDocument document = Loader.loadPDF(new File(filename));
+        List<String> tableRows = new ArrayList<>();
+        SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
+        PageIterator pi = new ObjectExtractor(document).extract();
+        boolean endFlag = false;
+        while (pi.hasNext()) {
+            // iterate over the pages of the document
+            Page page = pi.next();
+            List<Table> table = sea.extract(page);
+            // iterate over the tables of the page
+            for (Table tables : table) {
+                if (endFlag) {
+                    break;
+                }
+                boolean containsStartMarker = false;
+                boolean containsEndMarker = false;
+                List<List<RectangularTextContainer>> rows = tables.getRows();
+                // iterate over the rows of the table
+                for (List<RectangularTextContainer> cells : rows) {
+                    String rowStr = cells.stream()
+                            .map(item -> item.getText().replace("\r", " ") + "|")
+                            .collect(Collectors.joining());
+                    if (rowStr.contains(startMarker)) {
+                        containsStartMarker = true;
+                        containsEndMarker = false;
+                    }
+                    if (rowStr.contains(endMarker)) {
+                        containsStartMarker = false;
+                        containsEndMarker = true;
+                    }
+                    if (containsStartMarker) {
+                        tableRows.add(rowStr);
+                    }
+                    if (containsEndMarker) {
+                        tableRows.add(rowStr);
+                        endFlag = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return tableRows;
+    }
+
+    public static String generatePipeString(int numberOfPipes) {
+        if (numberOfPipes <= 0) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < numberOfPipes; i++) {
+            sb.append("-"); // 添加横线
+            if (i < numberOfPipes - 1) {
+                sb.append("|"); // 添加竖线,除了最后一个
+            }
+        }
+
+        return sb.toString();
+    }
+
+    public static int countOccurrences(String str, String ch) {
+        if (str == null || str.isEmpty()) {
+            return 0;
+        }
+
+        // 使用 split 方法分割字符串,并计算分割出的部分数量
+        String[] parts = str.split(ch, -1);
+        return parts.length - 1; // 出现次数等于分割部分数量减去 1
+    }
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        Test t = new Test();
+        String filePath = "C:\\Users\\Acer\\Desktop\\新员工资料\\3、项目\\1、邮储POC\\迭代资料\\工元致远2021年第一期汽车分期绿色资产证券化信托受托机构报告2022年第7期(总第10期).pdf";
+        String startMarker = "利息兑付情况";
+        String endMarker = "31,087,874.27|31,087,874.27";
+        try {
+            List<String> rows = t.readPdfTables(filePath, startMarker, endMarker);
+            if (rows.size() > 0) {
+                //根据第一行内容,添加markdown表格分隔符,放置到第二行
+                String pipeCharacter = "\\|";
+                // 统计字符串中 | 的数量
+                int count = countOccurrences(rows.get(0), pipeCharacter);
+                rows.add(1, generatePipeString(count));
+            }
+            for (String row : rows) {
+                System.out.println(row);
+            }
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+}

+ 115 - 0
springboot-tabula/src/test/java/org/example/lc/TestSE.java

@@ -0,0 +1,115 @@
+package org.example.lc;
+
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import technology.tabula.*;
+import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class TestSE {
+    public static void main(String[] args) {
+        String pdfPath = "C:\\Users\\Acer\\Desktop\\新员工资料\\3、项目\\1、邮储POC\\迭代资料\\工元致远2021年第一期汽车分期绿色资产证券化信托受托机构报告2022年第7期(总第10期).pdf";
+        String startMarker = "";
+        String endMarker = "";
+
+        try {
+            List<Table> extractedTables = extractTablesWithMarkers(pdfPath, startMarker, endMarker);
+            // 输出提取到的表格
+            for (Table table : extractedTables) {
+                System.out.println(table);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static List<Table> extractTablesWithMarkers(String pdfPath, String startMarker, String endMarker) throws IOException {
+        List<Table> result = new ArrayList<>();
+        boolean inRange = false;
+
+        PDDocument document = Loader.loadPDF(new File(pdfPath));
+        ObjectExtractor extractor = new ObjectExtractor(document);
+        SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
+
+        for (int i = 1; i <= document.getNumberOfPages(); i++) {
+            Page page = extractor.extract(i);
+            List<Table> tables = sea.extract(page);
+
+            for (Table table : tables) {
+                boolean containsStartMarker = false;
+                boolean containsEndMarker = false;
+                for (List<RectangularTextContainer> row : table.getRows()) {
+
+
+                    String rowStr = row.stream()
+                            .map(RectangularTextContainer::getText)
+                            .reduce("", (acc, text) -> acc + " " + text);
+
+                    if (rowStr.contains(startMarker)) {
+                        inRange = true;
+                        containsStartMarker = true;
+                    }
+
+                    if (rowStr.contains(endMarker)) {
+                        inRange = false;
+                        containsEndMarker = true;
+                    }
+
+                    if (inRange || containsStartMarker || containsEndMarker) {
+                        result.add(table);
+                        break;
+                    }
+                }
+            }
+        }
+
+        document.close();
+        return result;
+    }
+
+//    private void readPdfTables(String filename) throws Exception {
+//        PDDocument document = Loader.loadPDF(new File(filename));
+//        SpreadsheetExtractionAlgorithm sea = new SpreadsheetExtractionAlgorithm();
+//        PageIterator pi = new ObjectExtractor(document).extract();
+//        while (pi.hasNext()) {
+//            // iterate over the pages of the document
+//            Page page = pi.next();
+//            List<Table> table = sea.extract(page);
+//            // iterate over the tables of the page
+//            for (Table tables : table) {
+//                List<List<RectangularTextContainer>> rows = tables.getRows();
+//                // iterate over the rows of the table
+//                for (List<RectangularTextContainer> cells : rows) {
+//                    // print all column-cells of the row plus linefeed
+//                    for (RectangularTextContainer content : cells) {
+//                        // Note: Cell.getText() uses \r to concat text chunks
+//                        String text = content.getText().replace("\r", " ");
+//                        System.out.print(text + "|");
+//                    }
+//                    System.out.println();
+//                }
+//            }
+//        }
+//    }
+
+//    /**
+//     * @param args
+//     */
+//    public static void main(String[] args) {
+//        TestSE t = new TestSE();
+//        try {
+//            t.readPdfTables("C:\\Users\\Acer\\Desktop\\新员工资料\\3、项目\\1、邮储POC\\迭代资料\\工元致远2021年第一期汽车分期绿色资产证券化信托受托机构报告2022年第7期(总第10期).pdf");
+//        } catch (Exception e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        }
+//    }
+
+}