Sharing custom page query tool of JAP list

Posted by hightechredneck on Mon, 20 Jan 2020 17:46:08 +0100

The paging tool based on JPA supports multi table Association of native sql, and the generation of conditions only needs to be explicitly annotated on dto.

It can simplify development, improve development efficiency, and conform to the development habits of mybatis developers.

1. User defined condition generation annotation NativeQueryCondition constant class OperatorConstant
/**Annotation used to generate native sql conditions, applied to dto's fields
 * @author tlj
 * @date 2019/5/31
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NativeQueryCondition {
    int order() default 0;
    String operator();
    String tbColumn() default "";
    String classColumn() default "";
    String tbAlias() default "";
    // Extension type, field type requiring special handling
    String expandType() default "";
}



/**
 * @author tlj
 * @date 2019/10/17
 */
public class OperatorConstant {
    private OperatorConstant(){}
    public static final String EQ = "=";
    public static final String GRATER_EQ = ">=";
    public static final String LESS_EQ = "<=";
    public static final String LIKE = "like";

}

2. Basic method of paging BaseProfilePage

/**
 * @author tlj
 * @date 2019/7/13
 */
@Component
public class BaseProfilePage {
    @Autowired
    protected EntityManager entityManager;

    public <T> Page<T> queryPage(String sql, Map<String, Object> params, Pageable pageable, Class<T> clazz){
        Query query = entityManager.createNativeQuery(sql);
        PageUtil.setParameters(query, params);
        Integer currentPage = pageable.getPageNumber();
        int total = query.getResultList().size();
        int pageSize = pageable.getPageSize();
        int startCurrentPage = currentPage * pageSize;
        query.setFirstResult(startCurrentPage);
        query.setMaxResults(pageSize);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        List<Map> list = query.getResultList();
        List<T> data = BeanUtil.convertListMapToListT(list, clazz);
        return (Page<T>) new PageImpl(data, pageable, total);
    }
    public <T> List<T> queryList(String sql, Map<String, Object> params, Class<T> clazz){
        Query query =entityManager.createNativeQuery(sql);
        PageUtil.setParameters(query, params);
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        return  BeanUtil.convertListMapToListT(query.getResultList(), clazz);
    }
}

3. Native sqlbuilder: a tool class for users to dynamically build sql conditions

/**JPA native sql Encapsulation
 * @author tlj
 * @date 2019/5/31
 */
@Getter
@Slf4j
public class NativeSqlBuilder {
    private final StringBuilder sql = new StringBuilder();
    private final List<String> where = Lists.newArrayList();
    private final Map<String, Object> params = Maps.newHashMap();

    /**
     *Conditions for building dynamic sql (rule part)
     * @param tableAliaName Table alias
     * @param dto Annotated DTO instance
     * @param <T>
     */
     public <T> NativeSqlBuilder buildConditionsStandard( String tableAliaName, T dto ){
         // Get dto instance fields with conditional generation annotation
         List<Field> fs =Arrays.stream(dto.getClass().getDeclaredFields()).filter(it->it.isAnnotationPresent(NativeQueryCondition.class))
                 .sorted(Comparator.comparingInt(it->it.getAnnotation(NativeQueryCondition.class).order())).collect(Collectors.toList());
         fs.forEach(it->it.setAccessible(true));
         // Conditions for generating native sql based on fields
         for(Field it : fs){
             Object columnObj = null;
             try {
                 columnObj = it.get(dto);
             } catch (IllegalAccessException e) {
                 log.error("{}",e);
             }
             if( null == columnObj || (String.class.equals(columnObj.getClass()) && StringUtils.isBlank(String.valueOf(columnObj))) ){
                 continue;
             }
             NativeQueryCondition condition = it.getAnnotation(NativeQueryCondition.class);
             buildFieldCondition(tableAliaName,columnObj,condition,it.getName());
         }
         return this;
     }
     private void buildFieldCondition(String tableAliaName, Object columnObj, NativeQueryCondition condition, String fieldName ){
         String tbColumn = condition.tbColumn();
         if(StringUtils.isBlank(tbColumn)){
             tbColumn =camel2Underline( fieldName );
         }
         String classColumn = condition.classColumn();
         if(StringUtils.isBlank(classColumn)){
             classColumn = fieldName;
         }
         if( StringUtils.isNotBlank(condition.tbAlias()) ){
             tableAliaName = condition.tbAlias();
         }
         where.add( tableAliaName+"." + tbColumn + " " + condition.operator() + ":" + classColumn );
         if( LocalDate.class.equals(columnObj.getClass()) && OperatorConstant.LESS_EQ.equals(condition.operator()) ){
             // The < = of the end date needs to be increased by 1 on the original basis
             LocalDate localDate = (LocalDate)columnObj;
             params.put( classColumn, localDate.plusDays(1));
         }else{
             if("like".equals(condition.operator())){
                 params.put( classColumn, "%" + columnObj + "%");
             }else{
                 params.put( classColumn, columnObj);
             }
         }

     }

    /** Build special conditions (irregular parts, single)
     *  where.add("store.status=:status");
     *  params.put("status", BaseStatusEnum.VALID.getCode());
     * @return
     */
     public NativeSqlBuilder buildConditionSpecial(String whereItem,String paramKey,Object paramValue){
         where.add( whereItem );
         params.put(paramKey, paramValue);
         return this;
     }


    public  NativeSqlBuilder joinWhereList(){
        if (!where.isEmpty()) {
            sql.append(" where ").append(String.join(" and ", where));
        }
         return this;
    }
    public  NativeSqlBuilder orderBy(String tabAlias,String orderBy, String  xsc){
        sql.append(" order by ").append(tabAlias).append(".").append(orderBy).append(" ").append(xsc);
         return this;
    }
    public  NativeSqlBuilder orderBy(String tabAlias,String orderBy, String  xsc,Class clazz){
        sql.append(" order by ").append(tabAlias).append(".");
        if (StringUtils.isNotBlank(orderBy) && StringUtils.isNotBlank(xsc)) {
            sql.append(ColumnUtil.getColumn(clazz,orderBy)).append(" ").append(xsc);
        } else {
            sql.append("date_created").append(" ").append("desc");
        }
         return this;
    }
    public NativeSqlBuilder append(String str){
        sql.append(str);
        return this;
    }

    /**
     * Hump to underline
     *
     * @param line
     *            Source string
     * @return Converted String
     */
    private static String camel2Underline(String line) {
        if (line == null || "".equals(line)) {
            return "";
        }
        line = String.valueOf(line.charAt(0)).toUpperCase()
                .concat(line.substring(1));
        StringBuilder sb = new StringBuilder();
        Pattern pattern = Pattern.compile("[A-Z]([a-z\\d]+)?");
        Matcher matcher = pattern.matcher(line);
        while (matcher.find()) {
            String word = matcher.group();
            sb.append(word.toUpperCase());
            sb.append(matcher.end() == line.length() ? "" : "_");
        }
        return sb.toString();
    }

    @Override
    public String toString() {
        return sql.toString();
    }
}

4. Write a real paging business method (inherit BaseProfilePage)

/**
 * @author tlj
 * @date 2019/6/17
 */
@Component
public class LineMainProfilePage extends BaseProfilePage{

    /**
     * Background management system -- business line list Pagination
     */
    @Transactional(readOnly = true)
    public Page<LinePageItemDTO> page(LinePageQueryDTO req) {
        NativeSqlBuilder nativeSqlBuilder = new NativeSqlBuilder();
        nativeSqlBuilder.append("SELECT line.id, line.`code`, line.bus_status busStatus, line.`name`, line.first_category firstCategory, line.second_category secondCategory, c1.`name` firstCategoryName, c2.`name` secondCategoryName FROM t_line_main line LEFT JOIN t_base_category c1 ON line.first_category = c1.id LEFT JOIN t_base_category c2 ON line.second_category = c2.id");
        // Dynamic sql
        nativeSqlBuilder.buildConditionsStandard("line",req ).joinWhereList()
                .orderBy("line",req.getOrderBy(),req.getXsc(),LineMainEntity.class);
        Page<LinePageItemDTO> page = super.queryPage(nativeSqlBuilder,req.getPage(),LinePageItemDTO.class);
        page.getContent().forEach(it->it.setBuStatusName(StepEnum.map.get(it.getBusStatus())));
        return page;
    }


}

5. Declaration of query conditions for DTO parameters @ NativeQueryCondition(operator = OperatorConstant.LIKE) supports fuzzy matching, which is exactly equal to. The default field name and database field name are hump to underline relationships. You can also customize the corresponding relationship. See native query condition and native sqlbuilder code for details. The tool class can be expanded by itself. Now, the tool class can meet the needs of the project temporarily.

/**
 * @author tlj
 * @date 2019/10/17
 */
@Data
@ApiModel
public class LinePageQueryDTO extends QueryPagingDTO implements Serializable {
    private static final long serialVersionUID = -1181156497389378741L;
    @ApiModelProperty(value = "Business line name")
    @NativeQueryCondition(operator = OperatorConstant.LIKE)
    private String name;
    @ApiModelProperty(value = "Business line code")
    @NativeQueryCondition(operator = OperatorConstant.LIKE)
    private String code;

    @ApiModelProperty(value = "state:0 Disabled 1 enabled")
    @NativeQueryCondition(operator = OperatorConstant.EQ)
    @EnumValidator(value = BusStatusEnum.class,message = "State optional:0 Disabled 1 enabled")
    private Integer busStatus;


}

 

13 original articles published, 3 praised, 2603 visited
Private letter follow

Topics: SQL Mybatis Database