PageDTO<T>,PageQuery,BeanUtils,CollUtils的封装

一、PageDTO<T>

java 复制代码
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.Convert;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页结果")
public class PageDTO<T> {
    @ApiModelProperty("总条数")
    protected Long total;
    @ApiModelProperty("总页码数")
    protected Long pages;
    @ApiModelProperty("当前页数据")
    protected List<T> list;

    public static <T> PageDTO<T> empty(Long total, Long pages) {
        return new PageDTO<>(total, pages, CollUtils.emptyList());
    }
    public static <T> PageDTO<T> empty(Page<?> page) {
        return new PageDTO<>(page.getTotal(), page.getPages(), CollUtils.emptyList());
    }

    public static <T> PageDTO<T> of(Page<T> page) {
        if(page == null){
            return new PageDTO<>();
        }
        if (CollUtils.isEmpty(page.getRecords())) {
            return empty(page);
        }
        return new PageDTO<>(page.getTotal(), page.getPages(), page.getRecords());
    }
    public static <T,R> PageDTO<T> of(Page<R> page, Function<R, T> mapper) {
        if(page == null){
            return new PageDTO<>();
        }
        if (CollUtils.isEmpty(page.getRecords())) {
            return empty(page);
        }
        return new PageDTO<>(page.getTotal(), page.getPages(),
                page.getRecords().stream().map(mapper).collect(Collectors.toList()));
    }
    public static <T> PageDTO<T> of(Page<?> page, List<T> list) {
        return new PageDTO<>(page.getTotal(), page.getPages(), list);
    }

    public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz) {
        return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz));
    }

    public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz, Convert<R, T> convert) {
        return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz, convert));
    }

    @ApiModelProperty(hidden = true)
    @JsonIgnore
    public boolean isEmpty(){
        return list == null || list.size() == 0;
    }
}

二、 PageQuery

2.1 PageQuery代码

java 复制代码
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxx.common.constants.Constant;
import com.xxx.common.utils.StringUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.Min;

@Data
@ApiModel(description = "分页请求参数")
@Accessors(chain = true)
public class PageQuery {
    public static final Integer DEFAULT_PAGE_SIZE = 20;
    public static final Integer DEFAULT_PAGE_NUM = 1;

    @ApiModelProperty(value = "页码", example = "1")
    @Min(value = 1, message = "页码不能小于1")
    private Integer pageNo = DEFAULT_PAGE_NUM;

    @ApiModelProperty(value = "每页大小", example = "5")
    @Min(value = 1, message = "每页查询数量不能小于1")
    private Integer pageSize = DEFAULT_PAGE_SIZE;

    @ApiModelProperty(value = "是否升序", example = "true")
    private Boolean isAsc = true;

    @ApiModelProperty(value = "排序字段", example = "id")
    private String sortBy;

    public int from(){
        return (pageNo - 1) * pageSize;
    }

    public <T> Page<T> toMpPage(OrderItem ... orderItems) {
        Page<T> page = new Page<>(pageNo, pageSize);
        // 是否手动指定排序方式
        if (orderItems != null && orderItems.length > 0) {
            for (OrderItem orderItem : orderItems) {
                page.addOrder(orderItem);
            }
            return page;
        }
        // 前端是否有排序字段
        if (StringUtils.isNotEmpty(sortBy)){
            OrderItem orderItem = new OrderItem();
            orderItem.setAsc(isAsc);
            orderItem.setColumn(sortBy);
            page.addOrder(orderItem);
        }
        return page;
    }

    public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) {
        if (StringUtils.isBlank(sortBy)){
            sortBy = defaultSortBy;
            this.isAsc = isAsc;
        }
        Page<T> page = new Page<>(pageNo, pageSize);
        OrderItem orderItem = new OrderItem();
        orderItem.setAsc(this.isAsc);
        orderItem.setColumn(sortBy);
        page.addOrder(orderItem);
        return page;
    }
    public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {
        return toMpPage(Constant.DATA_FIELD_NAME_CREATE_TIME, false);
    }
}

2.2 使用举例

java 复制代码
@EqualsAndHashCode(callSuper = true)
@Data
@ApiModel(description = "互动问题分页查询条件")
public class QuestionPageQuery extends PageQuery {
    // 用户端查询条件
    @ApiModelProperty(value = "课程id")
    private Long courseId;
    @ApiModelProperty(value = "小节id", example = "1")
    private Long sectionId;
    @ApiModelProperty(value = "是否只查询我的问题", example = "1")
    private Boolean onlyMine;
}

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

//1 获取用户id
Long userId = UserContext.getUser();

Boolean onlyMine = query.getOnlyMine(); // 是否只查询自己
Long sectionId = query.getSectionId();
Long courseId = query.getCourseId();
//2 分页查询问题表(question)数据
// selecgt * from question  where user_id=?  and course_id =? and section_id=? and hidden= false;
Page<InteractionQuestion> page = this.lambdaQuery()
        .eq(onlyMine, InteractionQuestion::getUserId, userId) // 只查询自己,才拼接条件
        .eq(courseId != null, InteractionQuestion::getCourseId, courseId) // 传递了 课程,才拼接课程查询
        .eq(sectionId != null, InteractionQuestion::getSectionId, sectionId)  // 传递了 小节,才拼接小节查询
        .eq(InteractionQuestion::getHidden, false) // 被管理员隐藏的不显示
        .page(query.toMpPageDefaultSortByCreateTimeDesc()); // 按照创建日期倒叙排序
List<InteractionQuestion> records = page.getRecords();
if(CollUtils.isEmpty(records)){ // 如果没有
    return PageDTO.empty(page);
}
java 复制代码
// 1.获取用户id
Long userId = UserContext.getUser();
// 2) 分页查询数据库
// select * from learning_lesson where user_id=?  order by create_time desc  limit 5

Page<LearningLesson> page = this.lambdaQuery()
        .eq(LearningLesson::getUserId, userId)
        .page(query.toMpPage("latest_learn_time", false));

//  mybatis  会把  查询的数据全部封装到 page 中: 数据, 总条数数据集
List<LearningLesson> records = page.getRecords(); // 获取当前页数据
if(CollUtils.isEmpty(records)){
    return PageDTO.empty(page); // 如果没有数据返回空对象
}

三、BeanUtils

3.1 BeanUtils代码

java 复制代码
import cn.hutool.core.bean.BeanUtil;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 继承自 hutool 的BeanUtil,增加了bean转换时自定义转换器的功能
 */
public class BeanUtils extends BeanUtil {

    /**
     * 将原对象转换成目标对象,对于字段不匹配的字段可以使用转换器处理
     *
     * @param source  原对象
     * @param clazz   目标对象的class
     * @param convert 转换器
     * @param <R>     原对象类型
     * @param <T>     目标对象类型
     * @return 目标对象
     */
    public static <R, T> T copyBean(R source, Class<T> clazz, Convert<R, T> convert) {
        T target = copyBean(source, clazz);
        if (convert != null) {
            convert.convert(source, target);
        }
        return target;
    }
    /**
     * 将原对象转换成目标对象,对于字段不匹配的字段可以使用转换器处理
     *
     * @param source  原对象
     * @param clazz   目标对象的class
     * @param <R>     原对象类型
     * @param <T>     目标对象类型
     * @return 目标对象
     */
    public static <R, T> T copyBean(R source, Class<T> clazz){
        if (source == null) {
            return null;
        }
        return toBean(source, clazz);
    }

    public static <R, T> List<T> copyList(List<R> list, Class<T> clazz) {
        if (list == null || list.size() == 0) {
            return CollUtils.emptyList();
        }
        return copyToList(list, clazz);
    }

    public static <R, T> List<T> copyList(List<R> list, Class<T> clazz, Convert<R, T> convert) {
        if (list == null || list.size() == 0) {
            return CollUtils.emptyList();
        }
        return list.stream().map(r -> copyBean(r, clazz, convert)).collect(Collectors.toList());
    }
}
java 复制代码
package com.xxx.common.utils;

/**
 * 对原对象进行计算,设置到目标对象中
 **/
public interface Convert<R,T>{
    void convert(R origin, T target);
}

3.2 举例

java 复制代码
    public void save(CourseTeacherSaveDTO courseTeacherSaveDTO) {

        //1.数据删除条件
        LambdaUpdateWrapper<CourseTeacherDraft> updateWrapper =
                Wrappers.lambdaUpdate(CourseTeacherDraft.class)
                        .eq(CourseTeacherDraft::getCourseId, courseTeacherSaveDTO.getId());
        //1.1.数据删除
        baseMapper.delete(updateWrapper);

        //2.组装即将插入的数据
        // List<TeacherInfo> teachers
        List<CourseTeacherDraft> courseTeacherDrafts =
                BeanUtils.copyList(courseTeacherSaveDTO.getTeachers(),
                        CourseTeacherDraft.class,
                        (teacherInfo, teacherDraft) -> {
                            //2.1.设置课程id
                            teacherDraft.setCourseId(courseTeacherSaveDTO.getId());
                            //2.2.设置老师id
                            teacherDraft.setTeacherId(teacherInfo.getId());
                            //2.3.设置课程中老师排序
                            teacherDraft.setCIndex(courseTeacherSaveDTO.getTeachers().indexOf(teacherInfo));
                        });
        //3.批量插入课程的老师信息
        saveBatch(courseTeacherDrafts);
        //4.更新课程填写进度
        courseDraftService.updateStep(courseTeacherSaveDTO.getId(), CourseConstants.CourseStep.TEACHER);
    }

-----------------------------------------------------
@ApiModel("课程老师关系模型")
public class CourseTeacherSaveDTO {
    @ApiModelProperty("课程id")
    @NotNull(message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_COURSE_ID_NULL)
    private Long id;
    @ApiModelProperty("老师id和用户端是否展示,该列表按照界面上的顺序")
    @NotNull(message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_TEACHERS_NULL)
//    @Min(value = 1, message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_TEACHERS_NULL)
    @Size(min = 1, max = 5, message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_TEACHERS_NUM_MAX )
    private List<TeacherInfo> teachers;

    @Data
    @ApiModel("老师id和用户端是否显示")
    public static class TeacherInfo{
        @ApiModelProperty("老师id")
        @NotNull(message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_TEACHER_ID_NULL)
        private Long id;
        @ApiModelProperty("用户端是否展示")
        @NotNull(message = CourseErrorInfo.Msg.COURSE_TEACHER_SAVE_TEACHER_SHOW)
        private Boolean isShow;
    }
}

四、CollUtils

4.1 CollUtils代码

java 复制代码
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.IterUtil;
import com.xxx.common.validate.Checker;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 继承自 hutool 的集合工具类
 */
public class CollUtils extends CollectionUtil {

    public static <T> List<T> emptyList() {
        return Collections.emptyList();
    }

    public static <T> Set<T> emptySet() {
        return Collections.emptySet();
    }

    public static <K,V> Map<K, V> emptyMap() {
        return Collections.emptyMap();
    }

    public static <T> Set<T> singletonSet(T t) {
        return Collections.singleton(t);
    }

    public static <T> List<T> singletonList(T t) {
        return Collections.singletonList(t);
    }

    public static List<Integer> convertToInteger(List<String> originList){
        return CollUtils.isNotEmpty(originList) ? originList.stream().map(NumberUtils::parseInt).collect(Collectors.toList()) : null;
    }

    public static List<Long> convertToLong(List<String> originLIst){
        return CollUtils.isNotEmpty(originLIst) ? originLIst.stream().map(NumberUtils::parseLong).collect(Collectors.toList()) : null;
    }

    /**
     * 以 conjunction 为分隔符将集合转换为字符串 如果集合元素为数组、Iterable或Iterator,则递归组合其为字符串
     * @param collection 集合
     * @param conjunction 分隔符
     * @param <T> 集合元素类型
     * @return 连接后的字符串
     * See Also: IterUtil.join(Iterator, CharSequence)
     */
    public static <T> String join(Collection<T> collection, CharSequence conjunction) {
        if (null == collection || collection.isEmpty()) {
            return null;
        }
        return IterUtil.join(collection.iterator(), conjunction);
    }

    public static <T> String joinIgnoreNull(Collection<T> collection, CharSequence conjunction) {
        if (null == collection || collection.isEmpty()) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (T t : collection) {
            if(t == null) continue;
            sb.append(t).append(",");
        }
        if(sb.length() <= 0){
            return null;
        }
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

    /**
     * 集合校验逻辑
     *
     * @param data 要校验的集合
     * @param checker 校验器
     * @param <T> 集合元素类型
     */
    public static  <T> void  check(List<T> data, Checker<T> checker){
        if(data == null){
            return;
        }
        for (T t : data){
            checker.check(t);
        }
    }

    /**
     * 集合校验逻辑
     *
     * @param data 要校验的集合
     * @param <T> 集合元素类型
     */
    public static  <T extends Checker<T>> void  check(List<T> data){
        if(data == null){
            return;
        }
        for (T t : data){
            t.check();
        }
    }

    /**
     * 将元素加入到集合中,为null的过滤掉
     *
     * @param list 集合
     * @param data 要添加的数据
     * @param <T> 元素类型
     */
    public static <T> void add(Collection<T> list, T... data) {
        if (list == null || ArrayUtils.isEmpty(data)) {
            return;
        }
        for (T t : data) {
            if (ObjectUtils.isNotEmpty(t)) {
                list.add(t);
            }
        }
    }
    //将两个集合出现次数相加
    public static Map<Long, Integer> union(Map<Long, Integer> map1, Map<Long, Integer> map2) {
        if (CollUtils.isEmpty(map1)) {
            return map2;
        } else if (CollUtils.isEmpty(map2)) {
            return map1;
        }
        for (Map.Entry<Long, Integer> entry : map1.entrySet()) {
            Integer num = map2.get(entry.getKey());
            map2.put(entry.getKey(), NumberUtils.null2Zero(num) + entry.getValue());
        }
        return map2;
    }

    public static <T,R> R getFiledOfFirst(List<T> list, Function<T, R> function) {
        if (CollUtils.isEmpty(list)) {
            return null;
        }
        return function.apply(list.get(0));
    }
}
java 复制代码
/**
 * 实现后在接口访问时如果接口实现了这个接口
 * 会被自动自行接口check进行校验
 **/
public interface Checker<T> {

    /**
     * 用于实现validation不能校验的数据逻辑
     */
    default void check(){

    }

    default void check(T data){
    }
}

4.2 checker举例

java 复制代码
@ApiModel(description = "章节")
public class CataSaveDTO implements Checker {
    @ApiModelProperty("章、节、练习id")
    private Long id;
    @ApiModelProperty("目录类型1:章,2:节,3:测试")
    @NotNull(message = "")
    private Integer type;
    @ApiModelProperty("章节练习名称")
    private String name;
    @ApiModelProperty("章排序,章一定要传,小节和练习不需要传")
    private Integer index;

    @ApiModelProperty("当前章的小节或练习")
    @Size(min = 1, message = "不能出现空章")
    private List<CataSaveDTO> sections;

    @Override
    public void check() {
        //名称为空校验
        if(type == CourseConstants.CataType.CHAPTER && StringUtils.isEmpty(name)) {
            throw new BadRequestException(CourseErrorInfo.Msg.COURSE_CATAS_SAVE_NAME_NULL);
        }else if(StringUtils.isEmpty(name)){
            throw new BadRequestException(CourseErrorInfo.Msg.COURSE_CATAS_SAVE_NAME_NULL2);
        }
        //名称长度问题
        if (type == CourseConstants.CataType.CHAPTER && name.length() > 30){
            throw new BadRequestException(CourseErrorInfo.Msg.COURSE_CATAS_SAVE_NAME_SIZE);
        }else if(name.length() > 30) {
            throw new BadRequestException(CourseErrorInfo.Msg.COURSE_CATAS_SAVE_NAME_SIZE2);
        }
        if(CollUtils.isEmpty(sections)){
            throw new BadRequestException("不能出现空章");
        }

    }
}
java 复制代码
@ApiModel("题目保存模型")
@Data
public class SubjectSaveDTO implements Checker {
    @ApiModelProperty("题目id,为空新增,不为空更新")
    private Long id;
    @ApiModelProperty("名称")
    @NotNull(message = "题目为空,请设置题目")
    @Size(max = 200, min = 5, message = "题目长度为5-200")
    private String name;
    @ApiModelProperty("所属题目分类")
    @NotNull(message = "题目分类为空,请设置题目分类")
    private List<List<Long>> cates;
    @ApiModelProperty("题目类型")
    @NotNull(message = "题目类型为空,请设置题目类型")
    @EnumValid(enumeration = {1,2,3,4,5}, message = "题目类型只有单选题,多选题,不定向选择题,判断题,您的题目超出题纲")
    private Integer subjectType;
    @ApiModelProperty("题目难易度")
    @NotNull(message = "难度不能为空")
    @EnumValid(enumeration = {1,2,3},message = "题目难度只有简单,中等,困难")
    private Integer difficulty;
    @ApiModelProperty("分值")
    private Integer score;

    @ApiModelProperty("课程id")
    private List<Long> courseIds;

    @ApiModelProperty("选项,最多10个")
    private List<String> options;

    @ApiModelProperty("答案,判断题,数组第一个如果是1,代表正确,其他代表错误")
    @NotNull(message = "题目答案不能为空")
    private List<Integer> answers;
    @ApiModelProperty("解析")
    private String analysis;

    @Override
    public void check() {
        //选择题 单选,多选,不定向选择
        if(subjectType == SubjectConstants.Type.SIGNLE_CHOICE.getType() ||
                subjectType == SubjectConstants.Type.MUtiple_CHOICE.getType() ||
                subjectType == SubjectConstants.Type.NON_DIRECTIONAL_CHOICE.getType()){
            Integer answerOptionMax = answers.stream().max(Integer::compare).get();
            //选项最少1个最多10个
            if(CollUtils.isEmpty(options) || options.size() > 10){
                throw new BizIllegalException("最少1个选项,最多10个选项");
            }
            //选择题答案 不能超过选项数
            if(answerOptionMax > options.size()){
                throw new BizIllegalException("存在正确的答案找不到选项");
            }
            if(StringUtils.isNotEmpty(analysis)
                    && (StringUtils.length(analysis) < 5
                    || StringUtils.length(analysis) > 300)) {
                throw new BadRequestException("答案解析长度为5-300");
            }
        }

    }
}
相关推荐
Be_Somebody2 分钟前
[这可能是最好的Spring教程!]Maven的模块管理——如何拆分大项目并且用parent继承保证代码的简介性
java·spring boot·spring·spring入门
一个数据小开发18 分钟前
业务开发问题之ConcurrentHashMap
java·开发语言·高并发·map
会飞的架狗师34 分钟前
【Spring】Spring框架中有有哪些常见的设计模式
java·spring·设计模式
Jakarta EE44 分钟前
在JPA和EJB中用乐观锁解决并发问题
java
花心蝴蝶.1 小时前
并发编程中常见的锁策略
java·jvm·windows
A_cot1 小时前
一篇Spring Boot 笔记
java·spring boot·笔记·后端·mysql·spring·maven
tryCbest2 小时前
java8之Stream流
java·后端
江梦寻3 小时前
解决SLF4J: Class path contains multiple SLF4J bindings问题
java·开发语言·spring boot·后端·spring·intellij-idea·idea
鸡鸭扣3 小时前
springboot苍穹外卖实战:五、公共字段自动填充(aop切面实现)+新增菜品功能+oss
java·spring boot·后端
徐*红5 小时前
java 线程池
java·开发语言