SpringBoot集成Bean Searcher实现各种复杂查询

导入依赖

		<dependency>
            <groupId>com.ejlchina</groupId>
            <artifactId>bean-searcher-boot-starter</artifactId>
            <version>3.8.2</version>
        </dependency>

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

实体类

import com.ejlchina.searcher.bean.DbField;
import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

/**
 * @author qingshi
 * @date 2023/1/5 8:53
 * info:
 */
@Data
@Table
@Entity
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @DbField("user_name")//如果实体类的字段和数据库不匹配,就需要通过这个注解指定一下
    @Column(name = "user_name",columnDefinition = "varchar(100) comment '姓名'") // 若实体属性和表字段名称一致时,可以不用加@Column注解
    private String name;

    @Column(name = "sex")
    private int sex;

    @Column(name = "grade")
    private String grade;

    @Column(name = "age",columnDefinition = "varchar(2) comment '性别'")
    private String age;
}

测试

	@Autowired
	private BeanSearcher beanSearcher;
	
    void getSearch(){
        Map<String, Object> params = MapUtils.builder()
                .page(0,10)                                    //第1页10条
                .orderBy(Student::getAge).desc()               // age 字段,降序
                .onlySelect(Student::getName,Student::getAge)  //只查询 age 与 name 字段
                .field(Student::getName).op("小红")             //查询 name 等于 小红 的用户
                .field(Student::getName).op(NotEmpty.class)    //查询 name 不为空的用户
                .field(Student::getName, "小红").op(Contain.class)    // 查询 name 中包含字符串 小红 的用户
                .build();
        SearchResult<Student> search = beanSearcher.search(Student.class, params);
        List<Student> dataList = search.getDataList();        //获取数据列表
        Number totalCount = search.getTotalCount();           //获取数据总数
        System.out.println(dataList);
        System.out.println(totalCount);
    }

将bean-searcher日志转换成sql

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SqlParser {
    public static void main(String[] args) {
        String log = "2023-04-27 16:01:32.562 [http-nio-8080-exec-3] DEBUG cn.zhxu.bs.implement.DefaultSqlExecutor:249 - bean-searcher [2ms] sql: [select distinct CONCAT( LPAD( 0 + CAST(product.sequence_no AS CHAR), 3, '0' ), ' - ', IFNULL( IFNULL( product.production_name, product.foreign_name ), product.temporary_name)) c_32, COUNT(*) c_0, IF(!ISNULL( chapter.sequence_no ), CONCAT( FORMAT( MIN( chapter.sequence_no ), 0, '' ), '~', FORMAT( MAX( chapter.sequence_no ), 0 )),NULL) c_1, task_settle.unit_price c_2, task_settle.calc_count c_3, task_settle.calc_unit c_4, task_settle.result_price c_5 from mx_production_chapter_task task left join mx_production product on task.production_id = product.production_id left join mx_platform platform on product.platform_id = platform.platform_id left join mx_production_chapter chapter on task.chapter_id = chapter.chapter_id left join mx_stage stage on task.stage_id = stage.stage_id left join mx_task_kpi kpi on task.task_id = kpi.task_id LEFT JOIN mx_task_settle task_settle ON task.task_id = task_settle.task_id where (task.del_flag = 0 AND product.del_flag = 0 AND platform.del_flag = 0 AND chapter.del_flag = 0  AND CONCAT( LPAD( 0 + CAST(product.sequence_no AS CHAR), 3, '0' ), ' - ', IFNULL( IFNULL( product.production_name, product.foreign_name ), product.temporary_name)) IS NOT NULL) and ((stage.stage_name = ?) and (platform.platform_name = ?) and (task.task_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))) group by CONCAT( LPAD( 0 + CAST(product.sequence_no AS CHAR), 3, '0' ), ' - ', IFNULL( IFNULL( product.production_name, product.foreign_name ), product.temporary_name)) order by platform.sequence_no asc, product.sequence_no asc, chapter.sequence_no asc, stage.sequence_no asc, DATE_FORMAT(task.deadline,'%Y-%m-%d') asc] params: [监制, KW简转繁, 84897, 97440, 97453, 119437, 44131, 44144, 44157, 44170, 44183, 44196, 44209, 44222, 109852, 119536, 126714, 44136, 44149, 44162, 44175, 44188, 44201, 44214, 44227, 109857, 119541, 126719, 84798, 97370, 84803, 97375, 119445, 119450, 119367, 119372, 70491, 97764, 119133, 70496, 97769, 119138, 61149, 61154, 70543, 119510, 119523, 70548, 119528, 57660, 61071, 70425, 84947, 84960, 84973, 97305, 119172, 57665, 61076, 70430, 84952, 84965, 84978, 97310, 119177, 60980, 60993, 64330, 64343, 97409, 97422, 119406, 119419, 24820, 24846, 24859, 24872, 119549, 60985, 60998, 64335, 64348, 97414, 97427, 119411, 119424, 43988, 70380, 70393, 84811, 97383, 97396, 119094, 24825, 24851, 24864, 24877, 119554, 59027, 61045, 61058, 43993, 70385, 70398, 84816, 97388, 97401, 119099, 70367, 84692, 84705, 59032, 61050, 61063, 70372, 84697, 84710, 84892, 97435, 97448, 119432, 84822, 84835, 84848, 44129, 44142, 44155, 44168, 44181, 44194, 44207, 44220, 109850, 119534, 126712, 115549, 115562, 124197, 124210, 124223, 124236, 124249, 84796, 97368, 119066, 119079, 119378, 84932, 97472, 97485, 115536, 119443, 97498, 97511, 97524, 97537, 109785, 109798, 97782, 97795, 119209, 119222, 91259, 97355, 109824, 119365, 90532, 90544, 90556, 90568, 90580, 90592, 90604, 90616, 90628, 90640, 70489, 97762, 119131, 84984, 84997, 85010, 85023, 85036, 84903, 97459, 115523, 61147, 84864, 97329, 97342, 109837, 97710, 97723, 97736, 97749, 109811, 70541, 119508, 119521, 57658, 61069, 70423, 84945, 84958, 84971, 97303, 119170, 60978, 60991, 64328, 64341, 97407, 97420, 119404, 119417, 24818, 24844, 24857, 24870, 119547, 119183, 43986, 70378, 70391, 84809, 97381, 97394, 119092, 59025, 61043, 61056, 70365, 84690, 84703, 70606, 70619, 84890, 97433, 97446, 119430, 84877]";

        String pattern = ".*sql:\\s*(\\[.*\\])\\s*params:\\s*(\\[.*\\])";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(log);

        if (m.find()) {
            String sql = m.group(1);
            String paramsStr = m.group(2);

            String[] params = paramsStr.replaceAll("\\s", "").replaceAll("[\\[\\]]", "").split(",");
            String[] newParams = new String[params.length];
            for (int i = 0; i < params.length; i++) {
                if (params[i].matches("^\\d+$")) {
                    newParams[i] = params[i];
                } else {
                    newParams[i] = "\"" + params[i] + "\"";
                }
            }

            String sqlWithParams = sql;
            for (String param : newParams) {
                sqlWithParams = sqlWithParams.replaceFirst("\\?", param);
            }

            System.out.println(sqlWithParams);
        }
    }
}

官网地址:https://bs.zhxu.cn/

### Spring Boot 3 中 Bean Searcher 实现与用法 Spring Boot 提供了一种强大的机制用于管理依赖注入和组件扫描,这使得开发者可以轻松定义并检索应用程序中的 `Bean`。对于特定功能如 `bean-searcher` 的实现或用法,在 Spring Boot 3 中可以通过多种方式完成。 #### 使用 Component Scanning 自动注册 Beans 在 Spring Boot 中,默认情况下会通过注解驱动的方式自动发现和注册 `@Component`, `@Service`, `@Repository`, 和 `@Controller` 等标注的类作为容器内的 `Beans`。这种行为由 `@SpringBootApplication` 注解触发,它隐含了 `@EnableAutoConfiguration` 和 `@ComponentScan` 功能[^1]。 如果需要自定义扫描路径或者调整默认配置,则可以在启动类上指定额外参数: ```java @SpringBootApplication(scanBasePackages = {"com.example.beans"}) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` 上述代码片段展示了如何限定扫描范围至特定包下,从而更精确控制哪些类会被识别为 Spring 容器中的 beans。 #### 手动获取 Bean 实例 除了依靠框架自动化过程外,还可以利用 `ApplicationContext` 接口手动访问已存在的 bean 资源。例如: ```java @Autowired private ApplicationContext context; @Bean public String getBeanByName() { return (String)this.context.getBean("myCustomBean"); } ``` 这里演示了怎样借助于 `ApplicationContext` 来按名称提取某个具体类型的对象实例。注意实际开发过程中应尽量减少直接操作上下文的行为,保持业务逻辑清晰分离才是最佳实践。 #### 配置文件支持复杂场景下的 Bean 查找优化 当面对较为复杂的多模块项目架构时,可能涉及到跨不同子项目的 bean 加载需求。此时可通过 YAML 或 properties 格式的外部化配置来进一步增强灵活性: ```yaml spring: profiles: dev application.name: my-spring-boot-app custom: enabledFeatures: featureA,featureB ``` 配合条件装配技术(Conditional Configuration),能够依据环境变量动态决定某些部分是否生效以及相应资源加载策略: ```java @Configuration @Profile("dev") @EnableConfigurationProperties(SomeConfigProps.class) public class DevSpecificConfig { @Bean public SomeFeature someFeature(@Value("${custom.enabledFeatures}") List<String> features){ // Implementation here... } } ``` 综上所述,虽然官方文档并未单独提及所谓 “bean searcher” 这一术语,但从广义角度看以上介绍的内容涵盖了相似的功能范畴——即高效定位所需服务单元并与之交互的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值