### Example Usage of Predicate Methods Source: https://github.com/blinkfox/fenix/blob/develop/docs/sp-api/main-method.md Demonstrates how to use various Predicate methods, including combinations of 'AND' and 'OR' logic, and conditional generation of predicates using the 'match' parameter. ```java @Test public void testOrGreaterThanEqual() { // 测试等于、大于等于混用的场景. int totalPage = (Integer) paramMap.get("totalPage"); List books = bookRepository.findAll(FenixSpecification.of(builder -> builder.andEquals("id", paramMap.get("id")) .orGreaterThanEqual("totalPage", totalPage) .build())); Assert.assertEquals(6, books.size()); // 测试等于、大于等于混用的场景,但大于等于条件不生成. String isbn = (String) paramMap.get("isbn"); List books2 = bookRepository.findAll(FenixSpecification.of(builder -> builder.andEquals("isbn", isbn) .orGreaterThanEqual("totalPage", totalPage, false) .build())); Assert.assertEquals(1, books2.size()); // 测试等于、大于等于混用的场景,但等于条件不生成. List books3 = bookRepository.findAll(FenixSpecification.of(builder -> builder.andEquals("isbn", isbn, false) .orGreaterThanEqual("totalPage", totalPage, totalPage > 0) .build())); Assert.assertEquals(5, books3.size()); books3.forEach(book -> Assert.assertTrue(book.getTotalPage() >= PAGE)); } ``` -------------------------------- ### Dynamic Blog Querying with Specification Java API Source: https://github.com/blinkfox/fenix/blob/develop/docs/usage-example.md Demonstrates dynamic querying of blog information using Fenix's Specification Java API. This example simulates constructing query parameters from a map and building a query using a chained Java API. ```java /** * 测试使用 Fenix 中的 {@link FenixSpecification} 的链式 Java API 来动态查询博客信息. */ @Test public void queryBlogsWithSpecifition() { // 这一段代码是在模拟构造前台传递查询的相关 map 型参数,当然也可以使用其他 Java 对象,作为查询参数. Map params = new HashMap<>(); params.put("ids", new String[]{"1", "2", "3", "4", "5", "6", "7", "8"}); params.put("author", "ZhangSan"); params.put("startTime", Date.from(LocalDateTime.of(2019, Month.APRIL, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant())); params.put("endTime", Date.from(LocalDateTime.of(2019, Month.OCTOBER, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant())); // 开始真正的查询,使用. Object[] ids = (Object[]) params.get("ids"); List blogs = blogRepository.findAll(builder -> builder.andIn("id", ids, ids != null && ids.length > 0) .andLike("title", params.get("title"), params.get("title") != null) .andLike("author", params.get("author")) .andBetween("createTime", params.get("startTime"), params.get("endTime")) .build()); // 单元测试断言查询结果的正确性. Assert.assertEquals(3, blogs.size()); blogs.forEach(blog -> Assert.assertTrue(blog.getAuthor().endsWith("ZhangSan"))); } ``` -------------------------------- ### Fenix Generated SQL and Parameters Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/example.md Example output showing the JPQL and parameters generated by Fenix during the execution of the Java API dynamic SQL query. This is useful for debugging. ```sql ------------------------------------------------------------ Fenix 生成的 SQL 信息 --------------------------------------------------------- -------- SQL: SELECT b FROM Blog AS b WHERE b.id IN :b_id AND b.author LIKE :b_author AND b.createTime BETWEEN :b_createTime_start AND :b_createTime_end ----- Params: {b_createTime_end=Tue Oct 08 00:00:00 CST 2019, b_id=[1, 2, 3, 4, 5, 6, 7, 8], b_author=%ZhangSan%, b_createTime_start=Mon Apr 08 00:00:00 CST 2019} ------------------------------------------------------------------------------------------------------------------------------------------- ``` -------------------------------- ### Example Usage of Fenix text() Method Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/main-method.md Demonstrates how to use the text() method to build a SQL query with various parameters. Ensure correct SQL syntax for actual execution. ```java /** * 测试 text 任何文本和参数的相关方法测试. */ @Test public void testText() { SqlInfo sqlInfo = Fenix.start() .text("select u.id, u.nickName from User as u where ") .text("u.id = :id ", "id", 5) .text("and u.nickName like :nickName ", "nickName", "lisi") .text("and u.sex in :sex ").param("sex", new Integer[]{2, 3, 4}) .text("and u.city in :city ", "city", context.get("citys")) .end(); assertEquals("select u.id, u.nickName from User as u where u.id = :id and u.nickName like :nickName " + "and u.sex in :sex and u.city in :city", sqlInfo.getSql()); assertEquals(4, sqlInfo.getParams().size()); } ``` -------------------------------- ### Example Usage of Fenix Conditional Annotations Source: https://github.com/blinkfox/fenix/blob/develop/docs/sp-bean/annotations.md Demonstrates the usage of `@Equals` and `@OrGreaterThan` annotations. `@Equals` uses the property name as the field name by default, while `@OrGreaterThan` explicitly specifies the database field name 'totalPage'. ```java /** * 图书的 ISBN 编号. * 注解中没有填写 `value()` 值,将默认使用字符串 `isbn` 作为数据库关联的实体字段名称. */ @Equals private String isbn; /** * 图书总页数. * 注解中填写了 `value()` 的值为 `totalPage`,将使用 `totalPage` 作为数据库关联的实体字段名称. */ @OrGreaterThan("totalPage") private Integer bookTotalPage; ``` -------------------------------- ### Bean-based Specification Query Example Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Fenix's ActiveRecord pattern supports Specification queries using Bean annotations. This approach simplifies query construction. ```java @Getter @Setter @Accessors(chain = true) public class BlogSearchParam { /** * Condition for exact query by ID. If this value is not null, an exact query will be performed. */ @Equals private Long id; /** * Condition for fuzzy query by name. If this value is not null, a fuzzy query will be performed. */ @Like private String name; /** * Condition for range query by status. If this value is not empty, an in range query will be performed. */ @In("status") private List states; /** * Condition for range query by publish date. If this value is not empty, a Between and query will be performed, * or it will degenerate into a greater than or equal to or less than or equal to query based on the boundary values. */ @Between private BetweenValue publishDate; } ``` -------------------------------- ### Get SQL Info from XML (Fenix API) Source: https://github.com/blinkfox/fenix/blob/develop/docs/more/other-features.md Retrieve SqlInfo objects from XML configurations using Fenix's Java API. Provide the full Fenix ID or namespace and Fenix ID along with context parameters. ```java Fenix.getXmlSqlInfo(String fullFenixId, Object context) Fenix.getXmlSqlInfo(String namespace, String fenixId, Object context) ``` -------------------------------- ### SQL Data Initialization Source: https://github.com/blinkfox/fenix/blob/develop/docs/quick-start.md SQL script to insert initial data into the 'test.t_blog' table. Populates the table with sample blog entries, each having an ID, user ID, author, title, content, and creation/update timestamps. ```sql -- 初始化插入一些博客信息数据,方便查询. INSERT INTO test.t_blog VALUES ('1', '1', '张三-ZhangSan', 'Spring从入门到精通', '这是 Spring 相关的内容', '2019-03-01 00:41:33', '2019-03-01 00:41:36'); INSERT INTO test.t_blog VALUES ('2', '1', '李四-LiSi', 'Spring Data JPA 基础教程','这是 Spring Data JPA 相关的内容', '2019-05-01 00:41:33', '2019-05-01 00:41:36'); INSERT INTO test.t_blog VALUES ('3', '1', '张三-ZhangSan', 'Spring Data JPA 文档翻译','这是 Spring Data JPA 文档翻译的内容', '2019-07-01 00:41:33', '2019-07-01 00:41:36'); INSERT INTO test.t_blog VALUES ('4', '1', '张三-ZhangSan', 'MyBatis 中文教程','这是 MyBatis 中文教程的内容', '2019-07-05 00:41:33', '2019-07-05 00:41:36'); INSERT INTO test.t_blog VALUES ('5', '2', '张三-ZhangSan', 'SpringBoot 快速入门','这是 SpringBoot 快速入门的内容', '2019-07-08 00:41:33', '2019-07-08 00:41:36'); INSERT INTO test.t_blog VALUES ('6', '2', '张三-WangWu', 'Java 初级教程','这是 Java 初级教程的内容', '2019-07-12 00:41:33', '2019-07-12 00:41:36'); INSERT INTO test.t_blog VALUES ('7', '3', '王五-WangWu', '分库分表之最佳实践','这是分库分表之最佳实践的内容', '2019-08-01 00:41:33', '2019-08-01 00:41:36'); INSERT INTO test.t_blog VALUES ('8', '3', '王五-WangWu', '你不知道的 CSS 使用技巧','这是你不知道的 CSS 使用技巧的内容', '2019-08-03 00:41:33', '2019-08-03 00:41:36'); INSERT INTO test.t_blog VALUES ('9', '4', '马六-Maliu', 'Vue 项目实战','这是Vue 项目实战的内容', '2019-08-07 00:41:33', '2019-08-07 00:41:36'); INSERT INTO test.t_blog VALUES ('10', '5', '马六-Maliu', 'JavaScript 精粹','这是 JavaScript 精粹的内容', '2019-08-13 00:41:33', '2019-08-13 00:41:36'); ``` -------------------------------- ### SQL Schema Initialization Source: https://github.com/blinkfox/fenix/blob/develop/docs/quick-start.md SQL script to create the 'test' schema and the 't_blog' table within it. Defines columns for blog ID, user ID, author, title, content, and timestamps, with 'c_id' as the primary key. ```sql -- 创建数据库表所在的模式 schema 为 test. CREATE SCHEMA test; commit; -- 在 test 模式下创建数据库表. DROP TABLE IF EXISTS test.t_blog; CREATE TABLE test.t_blog ( c_id varchar(32) NOT NULL, c_user_id varchar(255), c_author varchar(255), c_title varchar(255), c_content varchar(255), dt_create_time timestamp(6) NULL, dt_update_time timestamp(6) NULL, constraint pk_test_blog primary key(c_id) ); commit; ``` -------------------------------- ### Traditional Map Creation Source: https://github.com/blinkfox/fenix/blob/develop/docs/more-features.md Before using ParamWrapper, developers had to manually create and populate HashMaps. ```java Map context = new HashMap(); context.put("sex", "1"); context.put("stuId", "123"); ``` -------------------------------- ### Spring Boot Application Configuration Source: https://github.com/blinkfox/fenix/blob/develop/docs/quick-start.md Configuration for an in-memory HSQLDB database and JPA settings in `application.yml`. Includes datasource details, JPA show-sql, and Fenix-specific configurations with default values. ```yaml # 内存数据库 和 JPA 的配置. spring: datasource: url: jdbc:hsqldb:mem:dbtest username: test password: 123456 driver-class-name: org.hsqldb.jdbcDriver platform: hsqldb schema: classpath:db/schema.sql data: classpath:db/data.sql jpa: show-sql: true hibernate: ddl-auto: update # Fenix 的几个配置,都有默认值. 所以通常不需要配置,下面的配置代码也都可以删掉,你视具体情况配置即可. fenix: debug: false print-banner: true print-sql: xml-locations: handler-locations: predicate-handlers: ``` -------------------------------- ### Create and Execute Unit Test for Blog Repository Source: https://github.com/blinkfox/fenix/blob/develop/docs/quick-start.md This Java code defines a unit test class for the BlogRepository using Spring Boot and JUnit. It tests a method that queries blog information based on multiple fuzzy criteria and pagination. ```java package com.blinkfox.fenix.example.repository; import com.blinkfox.fenix.example.entity.Blog; import java.util.Date; import javax.annotation.Resource; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.test.context.junit4.SpringRunner; /** * BlogRepository 的单元测试类. * * @author blinkfox on 2019-08-16. */ @RunWith(SpringRunner.class) @SpringBootTest public class BlogRepositoryTest { @Resource private BlogRepository blogRepository; /** * 测试使用 {@link com.blinkfox.fenix.jpa.QueryFenix} 注解根据任意参数多条件模糊分页查询博客信息. */ @Test public void queryMyBlogs() { // 构造查询的相关参数. List ids = Arrays.asList("1", "2", "3", "4", "5", "6"); Blog blog = new Blog().setAuthor("ZhangSan").setUpdateTime(new Date()); Pageable pageable = PageRequest.of(0, 3, Sort.by(Sort.Order.desc("createTime"))); // 查询并断言查询结果的正确性. Page blogs = blogRepository.queryMyBlogs(ids, blog, pageable); Assert.assertEquals(4, blogs.getTotalElements()); Assert.assertEquals(3, blogs.getContent().size()); } } ``` -------------------------------- ### JPQL/SQL XML Dynamic Query Test Source: https://github.com/blinkfox/fenix/blob/develop/README.md Unit test for the `queryMyBlogs` method, demonstrating how to call the repository method with sample parameters and assert the results. ```java /** * 测试使用 {@link QueryFenix} 注解根据任意参数多条件模糊分页查询博客信息. */ @Test public void queryMyBlogs() { // 模拟构造查询的相关参数. List ids = Arrays.asList("1", "2", "3", "4", "5", "6"); Blog blog = new Blog().setAuthor("ZhangSan").setUpdateTime(new Date()); Pageable pageable = PageRequest.of(0, 3, Sort.by(Sort.Order.desc("createTime"))); // 查询并断言查询结果的正确性. Page blogs = blogRepository.queryMyBlogs(ids, blog, pageable); Assert.assertEquals(4, blogs.getTotalElements()); Assert.assertEquals(3, blogs.getContent().size()); } ``` -------------------------------- ### ParamWrapper for Context Parameters (Fenix) Source: https://github.com/blinkfox/fenix/blob/develop/docs/more/other-features.md Utilize ParamWrapper for a fluent API to build HashMap context parameters. This simplifies the creation of context maps for Fenix operations. ```java Map context = new HashMap(); context.put("sex", "1"); context.put("stuId", "123"); ``` ```java Map context = ParamWrapper.newInstance("sex", "1").put("stuId", "123").toMap()); ``` -------------------------------- ### Insert or Update Data using Blog Object Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Save or update data directly through a Blog object. This method is provided by Fenix and requires implementing FenixJpaModel for saveOrUpdateByNotNullProperties. ```java // Directly save or update data through a Blog object. new Blog() .setTitle(TITLE) ... .save(); // Save new data or update fields that are not null (this method is provided by Fenix, requires implementing FenixJpaModel) blog.saveOrUpdateByNotNullProperties(); ``` -------------------------------- ### Dynamic Multi-Condition Paginated Query with Lambda Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Perform dynamic multi-condition fuzzy pagination queries using Fenix's condition builder lambda. Conditions can be dynamically generated. ```java // Simulate constructing query and pagination conditions passed from the frontend. String name = "hello"; String startDate = "2022-03-02"; String endDate = "2022-03-07"; List statusList = Arrays.asList(0, 1, 2, 3); Pageable pageable = PageRequest.of(0, 3, Sort.by(Sort.Order.desc("birthday"))); // Use Fenix's condition Lambda for fuzzy queries; dynamic conditions can be appended after each query condition. Page blogsPage = new Blog().findAll(builder -> builder .andIn("status", statusList) .andLike("name", name, StringUtils.isNotBlank(name)) .andBetween("publishDate", startDate, endDate) .build(), pageable); ``` -------------------------------- ### Unit Test for Java API Dynamic SQL Query Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/example.md A unit test demonstrating how to call the repository method that uses Fenix's Java API for dynamic SQL. It sets up parameters and asserts the query results. ```java /** * 测试使用 {@link QueryFenix} 注解和 Java API 来拼接 SQL 的方式来查询博客信息. */ @Test public void queryBlogsWithJava() { // 构造查询的相关参数. String[] ids = new String[]{"1", "2", "3", "4", "5", "6", "7", "8"}; Blog blog = new Blog().setAuthor("ZhangSan"); Date startTime = Date.from(LocalDateTime.of(2019, Month.APRIL, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant()); Date endTime = Date.from(LocalDateTime.of(2019, Month.OCTOBER, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant()); // 查询并断言查询结果的正确性. List blogs = blogRepository.queryBlogsWithJava(blog, startTime, endTime, ids); Assert.assertEquals(3, blogs.size()); } ``` -------------------------------- ### Fenix Generated SQL Log Output Source: https://github.com/blinkfox/fenix/blob/develop/docs/quick-start.md This output shows the SQL query generated by Fenix for the `queryMyBlogs` method, including the XML file and method used, the generated JPQL, and the parameters passed. ```sql ------------------------------------------------------------ Fenix 生成的 SQL 信息 --------------------------------------------------------- -- Fenix xml: fenix/BlogRepository.xml -> queryMyBlogs -------- SQL: SELECT b FROM Blog AS b WHERE b.id IN :ids AND b.author LIKE :blog_author AND b.createTime <= :blog_updateTime ----- Params: {blog_updateTime=Fri Aug 16 13:23:17 CST 2019, blog_author=%ZhangSan%, ids=[1, 2, 3, 4, 5, 6]} ------------------------------------------------------------------------------------------------------------------------------------------- ``` -------------------------------- ### BlogRepository extending FenixJpaSpecificationExecutor Source: https://github.com/blinkfox/fenix/blob/develop/README.md The BlogRepository interface must extend FenixJpaSpecificationExecutor to enable Specification-based queries. This can be used alongside JpaRepository. ```java // JpaRepository 和 FenixJpaSpecificationExecutor 可以混用,也可以只使用某一个. public interface BlogRepository extends JpaRepository, FenixJpaSpecificationExecutor { } ``` -------------------------------- ### Define Repository Query Method with @QueryFenix Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/example.md Defines a repository interface method annotated with @QueryFenix, specifying the provider class and method for dynamic SQL generation. This links the repository method to the Java provider. ```java /** * 使用 {@link QueryFenix} 注解和 Java API 来拼接 SQL 的方式来查询博客信息. * * @param blog 博客信息实体 * @param startTime 开始时间 * @param endTime 结束时间 * @param blogIds 博客 ID 集合 * @return 用户信息集合 */ @QueryFenix(provider = BlogSqlProvider.class, method = "queryBlogsWithJava") List queryBlogsWithJava(@Param("blog") Blog blog, @Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("blogIds") String[] blogIds); ``` -------------------------------- ### Create SqlInfo Provider Method with Java API Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/example.md Defines a Java method that returns a SqlInfo object using Fenix's fluent API. Use this when you need to dynamically build SQL queries in Java. ```java import com.blinkfox.fenix.bean.SqlInfo; import com.blinkfox.fenix.core.Fenix; import com.blinkfox.fenix.example.entity.Blog; import com.blinkfox.fenix.helper.CollectionHelper; import com.blinkfox.fenix.helper.StringHelper; import java.util.Date; import org.springframework.data.repository.query.Param; /** * 博客 {@link SqlInfo} 信息的提供类. * * @author blinkfox on 2019-08-17. */ public class BlogSqlProvider { /** * 通过 Java API 来拼接得到 {@link SqlInfo} 的方式来查询博客信息. * * @param blogIds 博客 ID 集合 * @param blog 博客信息实体 * @param startTime 开始时间 * @param endTime 结束时间 * @return {@link SqlInfo} 示例 */ public SqlInfo queryBlogsWithJava(@Param("blogIds") String[] blogIds, @Param("blog") Blog blog, @Param("startTime") Date startTime, @Param("endTime") Date endTime) { return Fenix.start() .select("b") .from("Blog").as("b") .where() .in("b.id", blogIds, CollectionHelper.isNotEmpty(blogIds)) .andLike("b.title", blog.getTitle(), StringHelper.isNotBlank(blog.getTitle())) .andLike("b.author", blog.getAuthor(), StringHelper.isNotBlank(blog.getAuthor())) .andBetween("b.createTime", startTime, endTime, startTime != null || endTime != null) .end(); } } ``` -------------------------------- ### JPQL/SQL Java API Dynamic Query Provider Source: https://github.com/blinkfox/fenix/blob/develop/README.md Implements the `queryBlogsWithJava` method using Fenix's Java API to dynamically construct JPQL/SQL queries. It supports filtering by IDs, title, author, and creation/update time ranges. ```java public class BlogSqlProvider { /** * 通过 Java API 来拼接得到 {@link SqlInfo} 的方式来查询博客信息. * * @param blogIds 博客 ID 集合 * @param blog 博客信息实体 * @param startTime 开始时间 * @param endTime 结束时间 * @return {@link SqlInfo} 示例 */ public SqlInfo queryBlogsWithJava(@Param("blogIds") String[] blogIds, @Param("blog") Blog blog, @Param("startTime") Date startTime, @Param("endTime") Date endTime) { return Fenix.start() .select("b") .from("Blog").as("b") .where() .in("b.id", blogIds, CollectionHelper.isNotEmpty(blogIds)) .andLike("b.title", blog.getTitle(), StringHelper.isNotBlank(blog.getTitle())) .andLike("b.author", blog.getAuthor(), StringHelper.isNotBlank(blog.getAuthor())) .andBetween("b.createTime", startTime, endTime, startTime != null || endTime != null) .end(); } } ``` -------------------------------- ### Query Data by ID using Blog Object Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Retrieve an entity by its ID or check for its existence. ```java // Query entity data by ID. new Blog().setId().findById(); // Check if an entity exists by ID. blog.existsById(); ``` -------------------------------- ### Basic trimWhere Tag Structure Source: https://github.com/blinkfox/fenix/blob/develop/docs/xml/xml-tags.md Demonstrates the basic wrapper structure for the trimWhere tag. Any SQL or XML semantic SQL tags can be placed inside. ```xml ``` -------------------------------- ### Dynamic Querying with Java Bean Annotations Source: https://github.com/blinkfox/fenix/blob/develop/README.md Demonstrates dynamic querying by passing a Java Bean object with condition annotations. The query conditions are derived from the bean's properties and their annotations. ```java /** * 测试使用 Fenix 中的 {@link FenixSpecification} 的 Java Bean 条件注解的方式来动态查询博客信息. */ @Test public void queryBlogsWithAnnotaion() { // 这一段代码是在模拟构造前台传递的或单独定义的 Java Bean 对象参数. Date startTime = Date.from(LocalDateTime.of(2019, Month.APRIL, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant()); Date endTime = Date.from(LocalDateTime.of(2019, Month.OCTOBER, 8, 0, 0, 0) .atZone(ZoneId.systemDefault()).toInstant()); BlogParam blogParam = new BlogParam() .setIds(Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8")) .setAuthor("ZhangSan") .setCreateTime(BetweenValue.of(startTime, endTime)); // 开始真正的查询. List blogs = blogRepository.findAllOfBean(blogParam); // 单元测试断言查询结果的正确性. Assert.assertEquals(3, blogs.size()); blogs.forEach(blog -> Assert.assertTrue(blog.getAuthor().endsWith("ZhangSan"))); } ``` -------------------------------- ### Extend FenixJpaSpecificationExecutor for Blog Repository Source: https://github.com/blinkfox/fenix/blob/develop/docs/usage-example.md Extend JpaRepository with FenixJpaSpecificationExecutor to enable Specification-based queries. This provides additional default methods and a more direct API compared to the standard JpaSpecificationExecutor. ```java public interface BlogRepository extends JpaRepository, FenixJpaSpecificationExecutor { } ``` -------------------------------- ### Activate Fenix with @EnableFenix Source: https://github.com/blinkfox/fenix/blob/develop/README.md Annotate your Spring Boot application class with @EnableFenix to activate Fenix configurations. This is essential for Fenix to function correctly. ```java /** * 请在 Spring Boot 应用中标注 {code @EnableFenix} 注解. * * @author blinkfox on 2020-02-01. */ @EnableFenix @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` -------------------------------- ### NanoId Generation (Spring Boot < 3.4.0) Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/id-generator.md For Spring Boot versions 3.3.x and below, use @GeneratedValue and @GenericGenerator with the 'com.blinkfox.fenix.id.NanoIdGenerator' strategy to generate NanoIds. This provides a compact and fast ID generation solution. ```java @Entity @Table(name = "t_my_entity") public class MyEntity { @Id @GeneratedValue(generator = "nanoId") @GenericGenerator(name = "nanoId", strategy = "com.blinkfox.fenix.id.NanoIdGenerator") private String id; } ``` -------------------------------- ### Configure Custom Handlers in Non-Spring Boot Projects Source: https://github.com/blinkfox/fenix/blob/develop/docs/sp-bean/custom-annotation.md In non-Spring Boot projects, add instances of your custom predicate handlers to the Fenix configuration programmatically using `FenixConfig.add(handler);` during initialization. ```java // 初始化加载 Fenix 的配置信息. FenixConfigManager.getInstance().initLoad(); // 添加自定义的处理器的对象实例到 FenixConfig 中,可以添加任意多个处理器实例. FenixConfig.add(new MyEqualsPredicateHandler()); FenixConfig.add(new MyOtherPredicateHandler()); ``` -------------------------------- ### Fenix text() Method Overloads Source: https://github.com/blinkfox/fenix/blob/develop/docs/java/main-method.md These are the available overloads for the text() method, used for appending SQL strings and parameters. ```java text(String text) // 追加 SQL 字符串和命名参数的方法,其中 key 为命名参数名称,value 为参数值. text(String text, String key, Object value) // 在 SQL 后追加任何 SQL 字符串,后可追加 Map 型参数,Map 中的 key 为命名参数名称,value 为参数值. text(String text, Map paramMap) // 在 SQL 后追加任何 SQL 字符串,并设置该 SQL 字符串的命名参数,如果 match 为 true 时,才生成此 SQL 文本和参数. text(boolean match, String text, String key, Object value) // 在 SQL 后追加任何 SQL 字符串,后可追加 Map 型参数,如果 match 为 true 时,才生成此 SQL 文本和参数. text(boolean match, String text, Map paramMap) ``` -------------------------------- ### Optional Fenix Configuration in application.yml Source: https://github.com/blinkfox/fenix/blob/develop/README.md Customize Fenix behavior by setting properties in your application.yml file. These configurations are optional as Fenix follows a convention-over-configuration approach. ```yaml # Fenix 的几个配置项、默认值及详细说明,通常情况下你不需要填写这些配置信息(下面的配置代码也都可以删掉). fenix: # 成功加载 Fenix 配置信息后,是否打印启动 banner,默认 true. print-banner: true # 是否打印 Fenix 生成的 SQL 信息,默认为空. # 当该值为空时,会读取 'spring.jpa.show-sql' 的值,为 true 就打印 SQL 信息,否则不打印. # 当该值为 true 时,就打印 SQL 信息,否则不打印. 生产环境不建议设置为 true. print-sql: # 扫描 Fenix XML 文件的所在位置,默认是 fenix 目录及子目录,可以用 yaml 文件方式配置多个值. xml-locations: fenix # 扫描你自定义的 XML 标签处理器的位置,默认为空,可以是包路径,也可以是 Java 或 class 文件的全路径名 # 可以配置多个值,不过一般情况下,你不自定义自己的 XML 标签和处理器的话,不需要配置这个值. handler-locations: # v2.2.0 版本新增的配置项,表示自定义的继承自 AbstractPredicateHandler 的子类的全路径名 # 可以配置多个值,通常情况下,你也不需要配置这个值. predicate-handlers: # v2.7.0 新增的配置项,表示带前缀下划线转换时要移除的自定义前缀,多个值用英文逗号隔开,通常你不用配置这个值. underscore-transformer-prefix: ``` -------------------------------- ### JPQL/SQL Java API Dynamic Query Method Source: https://github.com/blinkfox/fenix/blob/develop/README.md Defines a repository method for dynamic queries using JPQL/SQL with a Java API provider. This method is intended to be implemented by `BlogSqlProvider`. ```java public interface BlogRepository extends JpaRepository { /** * 使用 {@link QueryFenix} 注解和 Java API 来拼接 SQL 的方式来查询博客信息. * * @param blog 博客信息实体 * @param startTime 开始时间 * @param endTime 结束时间 * @param blogIds 博客 ID 集合 * @return 用户信息集合 */ @QueryFenix(provider = BlogSqlProvider.class) List queryBlogsWithJava(@Param("blog") Blog blog, @Param("startTime") Date startTime, @Param("endTime") Date endTime, @Param("blogIds") String[] blogIds); } ``` -------------------------------- ### Custom Pagination Count Query with @QueryFenix Source: https://github.com/blinkfox/fenix/blob/develop/docs/queryfenix-introduction.md Define a custom SQL for counting total records in paginated queries using the `countQuery` attribute in @QueryFenix, referencing a specific fenix ID for the count query. ```xml SELECT count(*) FROM Blog AS b WHERE b.id in #{ids} AND b.author LIKE '%${blog.author}%' ``` ```java // 这个时候,countQuery 的值必须跟你自定义的查询总记录数的 fenix id 值一样. @QueryFenix(countQuery = "queryMyBlogsCount") Page queryMyBlogs(@Param("ids") List ids, @Param("blog") Blog blog, Pageable pageable); ``` -------------------------------- ### Execute Bean-based Specification Query Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Execute fuzzy queries using a Fenix object with condition annotations, which is a more straightforward method. ```java // Simulate constructing query and pagination conditions passed from the frontend. BlogSearchParam blogSearch = new BlogSearchParam() .setName("hello") .setStates(Arrays.asList(0, 1, 2, 3)) .setPublishDate(BetweenValue.of(startDate, endDate)); Pageable pageable = PageRequest.of(0, 3, Sort.by(Sort.Order.desc("publishDate"))); // Use Fenix's object with condition annotations for fuzzy queries, which is simpler. Page blogsPage = new Blog().findAllOfBean(blogSearch, pageable); ``` -------------------------------- ### JPQL/SQL XML Dynamic Query Definition Source: https://github.com/blinkfox/fenix/blob/develop/README.md Defines the Fenix query logic in an XML file for the `queryMyBlogs` repository method. It specifies conditions for filtering blog data. ```xml SELECT b FROM Blog AS b WHERE ``` -------------------------------- ### ParamWrapper for Simplified Map Creation Source: https://github.com/blinkfox/fenix/blob/develop/docs/more-features.md Use ParamWrapper to chain put operations and simplify the creation of Map objects for context parameters. ```java Map context = ParamWrapper.newInstance("sex", "1").put("stuId", "123").toMap()); ``` -------------------------------- ### trimWhere with Conditional Fields Source: https://github.com/blinkfox/fenix/blob/develop/docs/xml/xml-tags.md Shows how trimWhere works when some fields are empty. If user.email is empty, the generated SQL will exclude the email condition. ```xml SELECT u FROM @{entityName} anD u.id = #{user.id} ORDER BY u.updateTime DESC ``` -------------------------------- ### MyBatis XML Dynamic Query SQL Source: https://github.com/blinkfox/fenix/blob/develop/docs/compare-mybatis.md Demonstrates dynamic SQL generation in MyBatis for multi-condition queries, using if and foreach tags. ```xml SELECT ol.c_id, ol.c_title, ol.n_type, ol.n_result, ol.dt_create_time, ol.c_description FROM t_operation_log AS ol ol.n_result = #{log.result} AND ol.c_title like CONCAT('%', #{log.title}, '%') AND ol.n_type in #{item} AND ol.dt_create_time BETWEEN #{log.startTime} AND #{log.endTime} AND ol.dt_create_time >= #{log.startTime} AND ol.dt_create_time <= #{log.endTime} AND ``` -------------------------------- ### BlogParam VO for Annotation-Based Querying Source: https://github.com/blinkfox/fenix/blob/develop/README.md Defines a Java Bean (VO) for dynamic querying using FenixSpecification annotations. Each property can be annotated to specify the query condition. ```java import com.blinkfox.fenix.specification.annotation.Between; import com.blinkfox.fenix.specification.annotation.In; import com.blinkfox.fenix.specification.annotation.Like; import com.blinkfox.fenix.specification.handler.bean.BetweenValue; import java.util.Date; import java.util.List; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; /** * 用于测试 {@code FenixSpecification} 注解动态查询的博客 VO 类. * * @author blinkfox on 2020-01-28. */ @Getter @Setter @Accessors(chain = true) public class BlogParam { /** * 用于 IN 范围查询的 ID 集合,{@link In} 注解的属性值可以是数组,也可以是 {@link java.util.Collection} 集合数据. */ @In("id") private List ids; /** * 模糊查询博客信息的作者名称关键字内容的字符串. */ @Like private String author; /** * 用于根据博客创建时间 {@link Between} 区间查询博客信息的开始值和介绍值, * 区间查询的值类型建议是 {@link BetweenValue} 类型的. * 当然值类型也可以是二元数组,也可以是 {@link List} 集合,如果是这两种类型的值,元素的顺序必须是开始值和结束值才行. */ @Between("createTime") private BetweenValue createTime; } ``` -------------------------------- ### Using Native SQL with @QueryFenix Source: https://github.com/blinkfox/fenix/blob/develop/docs/queryfenix-introduction.md Set `nativeQuery()` to `true` within the @QueryFenix annotation to indicate that the JPQL statement should be executed as a native SQL query. ```java @QueryFenix(nativeQuery = true) List findBlogsByAuthorNative(@Param("author") String author); ``` -------------------------------- ### Gradle Dependency for Fenix (Spring Boot 2.x) Source: https://github.com/blinkfox/fenix/blob/develop/README.md Add this dependency to your Gradle project if you are using Spring Boot version 2.x. ```bash // Spring Boot 版本要求 2.x 版本. implementation("com.blinkfox:fenix-spring-boot-starter:2.7.0") ``` -------------------------------- ### JPQL/SQL XML Dynamic Query Method Source: https://github.com/blinkfox/fenix/blob/develop/README.md Defines a repository method for paginated dynamic queries using JPQL/SQL with XML configuration. Supports filtering by IDs, author, title, and creation/update time ranges. ```java /** * BlogRepository. * * @author blinkfox on 2019-08-16. */ public interface BlogRepository extends JpaRepository { /** * 使用 {@link QueryFenix} 注解来演示根据散参数、博客信息Bean(可以是其它Bean 或者 Map)来多条件模糊分页查询博客信息. * * @param ids 博客信息 ID 集合 * @param blog 博客信息实体类,可以是其它 Bean 或者 Map. * @param pageable JPA 分页排序参数 * @return 博客分页信息 */ @QueryFenix Page queryMyBlogs(@Param("ids") List ids, @Param("blog") Blog blog, Pageable pageable); } ``` -------------------------------- ### Simplified @QueryFenix with Namespace Alignment Source: https://github.com/blinkfox/fenix/blob/develop/docs/queryfenix-introduction.md When the XML namespace matches the repository interface's full path, the @QueryFenix annotation can be simplified to only include the fenix ID. ```xml ``` ```java // QueryFenix 注解只需要写 fenix id 即可. @QueryFenix("queryMyBlogs") Page queryMyBlogs(@Param("ids") List ids, @Param("blog") Blog blog, Pageable pageable); ``` -------------------------------- ### Gradle Dependency for Fenix (Spring Boot 3.x) Source: https://github.com/blinkfox/fenix/blob/develop/README.md Add this dependency to your Gradle project if you are using Spring Boot version 3.x. ```bash // Spring Boot 版本要求 3.x 版本. implementation("com.blinkfox:fenix-spring-boot-starter:3.1.0") ``` -------------------------------- ### Further Simplified @QueryFenix with Matching Method Name Source: https://github.com/blinkfox/fenix/blob/develop/docs/queryfenix-introduction.md If the fenix ID in the XML also matches the repository method name, the @QueryFenix annotation can be used without any arguments. ```java @QueryFenix Page queryMyBlogs(@Param("ids") List ids, @Param("blog") Blog blog, Pageable pageable); ``` -------------------------------- ### Gradle Dependency for Fenix (Spring Boot 4.x) Source: https://github.com/blinkfox/fenix/blob/develop/README.md Add this dependency to your Gradle project if you are using Spring Boot version 4.x or above. ```bash // Spring Boot 版本要求 4.x 版本. implementation("com.blinkfox:fenix-spring-boot-starter:4.0.0") ``` -------------------------------- ### Query Custom Entities with Fenix XML Source: https://github.com/blinkfox/fenix/blob/develop/docs/more-features.md Define a query interface in a repository using @QueryFenix and specify the custom DTO as the return type. Ensure all selected columns are aliased to match the DTO's property names (case-insensitive). ```java /** * 使用 {@link QueryFenix} 注解来连表模糊查询自定义的用户博客实体分页信息. * * @param userId 用户ID * @param blog 博客实体信息 * @return 用户博客信息集合 */ @QueryFenix("BlogRepository.queryUserBlogsWithFenixResultType") Page queryUserBlogPageWithFenixResultType(@Param("userId") String userId, @Param("blog") Blog blog, Pageable pageable); ``` ```xml SELECT u.id as userId, u.name as name, b.id as blogId, b.title as title, b.author as author, b.content as content FROM Blog as b, User as u WHERE u.id = b.userId ``` -------------------------------- ### Define Associated Repository with SpecificationExecutor Source: https://github.com/blinkfox/fenix/blob/develop/docs/cud/active-record.md Define the corresponding Repository interface, which should extend both JpaRepository and FenixJpaSpecificationExecutor. ```java @Repository public interface BlogRepository extends JpaRepository, FenixJpaSpecificationExecutor { } ```