springboot 整合mybatis 实现通用dao

1、版本

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.fd</groupId>
    <artifactId>dome</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dome</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.12</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


2、定义通用entity

package com.fd.dome.base.entity;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class BaseEntity implements Serializable {
    public final static String IS_TRUE = "1";
    public final static String IS_FALSE = "0";

    private Long id;
    private String createUser;
    private Date createTime;
    private String updateUser;
    private Date updateTime;
    private String isDel; //0 正常状态, 1 删除/隐藏状态
}

3、定义通用的dao

package com.fd.dome.base.dao;

import com.fd.dome.base.dao.provider.BaseDaoProvider;
import com.fd.dome.base.entity.BaseEntity;
import org.apache.ibatis.annotations.*;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface BaseDao<E extends BaseEntity> {

    @SelectProvider(type = BaseDaoProvider.class, method = "findById")
    E findById(Long id, Class clazz);

    @SelectProvider(type = BaseDaoProvider.class, method = "findAll")
    List<E> findAll(Class clazz);

    @UpdateProvider(type = BaseDaoProvider.class, method = "save")
    void save(@Param("entity") E entity, Class clazz);

    @UpdateProvider(type = BaseDaoProvider.class, method = "delById")
    void delById(Long id, Class clazz);

    @UpdateProvider(type = BaseDaoProvider.class, method = "delByIdAndUpdateUser")
    void delByIdAndUpdateUser(Long id, String updateUser, Class clazz);

    @InsertProvider(type = BaseDaoProvider.class, method = "insertBatch")
    void insertBatch(@Param("collection") Collection<E> entityCollection, Class clazz);
}

4、定义BaseDaoProvider用Java实现dao接口

package com.fd.dome.base.dao.provider;

import com.fd.dome.base.entity.BaseEntity;
import com.fd.dome.base.util.LocalObjectUtil;
import com.fd.dome.base.util.LocalStringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.jdbc.SQL;

import java.util.*;

import static com.fd.dome.base.constants.Constants.BaseEntityConstant.*;
import static com.fd.dome.base.constants.Constants.Symbol.*;

@Slf4j
public class BaseDaoProvider<E extends BaseEntity> {

    public String findById(Long id, Class clazz) {
        return new SQL() {{
            SELECT(LocalObjectUtil.getPropertyNameLines(clazz));
            FROM(LocalStringUtil.classToLine(clazz));
            WHERE("id = #{id}");
        }}.toString();
    }

    public String findAll(Class clazz) {
        return new SQL() {{
            SELECT(LocalObjectUtil.getPropertyNameLines(clazz));
            FROM(LocalStringUtil.classToLine(clazz));
            WHERE("is_del = " + BaseEntity.IS_FALSE);
        }}.toString();
    }

    public String save(@Param("entity") E entity, Class clazz) {
        String sql;
        Set<String> notNullPropertyNameSet = LocalObjectUtil.getNotNullPropertyNameSet(entity);

        if (ObjectUtils.isEmpty(entity.getId())) {
            sql = new SQL(){{
                INSERT_INTO(LocalStringUtil.classToLine(clazz));
                notNullPropertyNameSet.forEach(e -> {
                    if (e.equalsIgnoreCase(ID)) return;
                    if (e.equalsIgnoreCase(CREATE_TIME)) return;
                    if (e.equalsIgnoreCase(UPDATE_TIME)) return;
                    if (e.equalsIgnoreCase(UPDATE_USER)) return;
                    if (e.equalsIgnoreCase(IS_DEL)) return;
                    VALUES(LocalStringUtil.humpToLine(e) , "#{entity." + LocalStringUtil.toLowerCaseFirstOne(e)+  "}");
                });
                if (StringUtils.isNotBlank(entity.getCreateUser()))
                    VALUES("update_user", "#{entity.createUser}");
                INTO_COLUMNS("create_time", "update_time", "is_del");
                INTO_VALUES("now()", "now()", BaseEntity.IS_FALSE);
            }}.toString();
        } else {
            sql = new SQL(){{
                UPDATE(LocalStringUtil.classToLine(clazz));
                notNullPropertyNameSet.forEach(e -> {
                    if (e.equalsIgnoreCase(ID)) return;
                    if (e.equalsIgnoreCase(CREATE_USER)) return;
                    if (e.equalsIgnoreCase(CREATE_TIME)) return;
                    if (e.equalsIgnoreCase(UPDATE_TIME)) return;
                    if (e.equalsIgnoreCase(IS_DEL)) return;
                    SET(LocalStringUtil.humpToLine(e) + "= #{entity." + LocalStringUtil.toLowerCaseFirstOne(e)+  "}");
                });
                SET("update_time = now()");
                WHERE("id = #{entity.id}");
            }}.toString();
        }

        return sql;
    }

    public String delById(Long id, Class clazz) {
        return new SQL(){{
            UPDATE(LocalStringUtil.classToLine(clazz));
            SET("is_del = " + BaseEntity.IS_TRUE, "update_time = now()");
            WHERE("id = #{id}");
        }}.toString();
    }

    public String delByIdAndUpdateUser(Long id, String updateUser, Class clazz) {
        return new SQL(){{
            UPDATE(LocalStringUtil.classToLine(clazz));
            SET("is_del = " + BaseEntity.IS_TRUE, "update_user = #{updateUser}", "update_time = now()");
            WHERE("id = #{id}");
        }}.toString();
    }

    public String insertBatch(@Param("collection") Collection<E> entityCollection, Class clazz) {
        List<String> columnList = LocalObjectUtil.getPropertyNameList(clazz, new ArrayList<>());
        StringBuffer columnName = new StringBuffer();
        StringBuffer columnValue = new StringBuffer();
        columnList.forEach(column -> {
            if (column.equalsIgnoreCase(ID)) return;
            if (column.equalsIgnoreCase(CREATE_TIME)) return;
            if (column.equalsIgnoreCase(UPDATE_TIME)) return;
            if (column.equalsIgnoreCase(UPDATE_USER)) return;
            if (column.equalsIgnoreCase(IS_DEL)) return;
            columnName.append(LocalStringUtil.humpToLine(column)).append(COMMA);
            columnValue.append(", #{collection[__0].").append(column).append("}");
        });
        columnName.append(" create_time, update_time, update_user, is_del ");
        columnValue.append(", now(), now(), #{collection[__0].createUser}, ").append(BaseEntity.IS_FALSE);
        String valueTmp = LEFT_BRACKETS +  columnValue.toString().substring(1) + RIGHT_BRACKETS;

        StringBuilder value = new StringBuilder();
        for (int i = 0; i < entityCollection.size(); i++) {
            value.append(valueTmp.replaceAll("__0", i+""));
            if (entityCollection.size() - 1 > i)
                value.append(COMMA);
        }

        return "INSERT INTO " + LocalStringUtil.classToLine(clazz) + SPACE +
                LEFT_BRACKETS + columnName.toString() + RIGHT_BRACKETS + SPACE +
                " VALUES " + value;
    }
}

5、工具类:

package com.fd.dome.base.constants;

import com.fd.dome.base.entity.BaseEntity;

/**
 * Created by winfrd on 17-7-26.
 */
public class Constants {

    public static final class Symbol {
        public static final String COMMA = ",";
        public static final String UNDER_LINE = "_";
        public static final String MID_LINE = "-";
        public static final String GREATER_THAN = ">";
        public static final String DOUBLE_QUOTES = "\"";
        public static final String POINT = ".";
        public static final String COLON = ":";
        public static final String PERCENT_SIGN = "%";
        public static final String BACKSLASH = "/";
        public static final String SEPARATOR = "\\|";
        public static final String SEPARATOR2 = "|";
        public static final String NULL_STRING = "";
        public static final String SPACE = " ";
        public static final String LEFT_BRACKETS = "(";
        public static final String RIGHT_BRACKETS = ")";
    }

    public static final class Num {
        public static final class IntNum {
            public static final int ONE = 1;
        }
    }

    public static final class BaseEntityConstant {
        public static final String ID = "id";
        public static final String CREATE_USER = "createUser";
        public static final String CREATE_TIME = "createTime";
        public static final String UPDATE_USER = "updateUser";
        public static final String UPDATE_TIME = "updateTime";
        public static final String IS_DEL = "isDel";
    }

}


package com.fd.dome.base.util;

import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;

public class LocalObjectUtil {

    public static void copyNonNullProperties(Object source, Object target) {
        BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }

    public static String[] getNullPropertyNames (Object source) {
        return getPropertyNames(true, source);
    }

    public static String[] getNotNullPropertyNames(Object source) {
        return getPropertyNames(false, source);
    }

    public static String[] getPropertyNames(boolean isNull, Object source){
        Set<String> emptyNames = getPropertyNameSet(isNull, source);
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static Set<String> getNotNullPropertyNameSet(Object source) {
        return getPropertyNameSet(false, source);
    }

    public static Set<String> getPropertyNameSet(boolean isNull, Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for(java.beans.PropertyDescriptor pd : pds) {
            if ("class".equalsIgnoreCase(pd.getName())) continue;
            Object srcValue = src.getPropertyValue(pd.getName());
            if (isNull)  {
                if (ObjectUtils.isEmpty(srcValue)) emptyNames.add(pd.getName());
            } else {
                if (ObjectUtils.isNotEmpty(srcValue)) emptyNames.add(pd.getName());
            }

        }
        return emptyNames;
    }


    public static List<String> getPropertyNameList(Class clazz, List<String> nameList) {
        return getPropertyNameList(clazz, nameList, true);
    }
    public static List<String> getNotSupperPropertyNameList(Class clazz, List<String> nameList) {
        return getPropertyNameList(clazz, nameList, false);
    }


    private static List<String> getPropertyNameList(Class clazz, List<String> nameList, boolean needSuper) {
        Field[] pFields = clazz.getFields();
        List<Field> fieldList = Arrays.asList(pFields);
        Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
            if (fieldList.contains(field)) return;
            nameList.add(LocalStringUtil.toLowerCaseFirstOne(field.getName()));
        });
        if (needSuper&& clazz.getSuperclass() !=  Object.class) {
            getPropertyNameList(clazz.getSuperclass(), nameList);
        }
        return nameList;
    }


    public static String[] getPropertyNameLines(Class clazz) {
        List<String> nameList = getPropertyNameList(clazz, new ArrayList<>());
        String[] names = new String[nameList.size()];
        for (int i = 0; i < nameList.size(); i++) {
            names[i] = LocalStringUtil.humpToLine(nameList.get(i));
        }
        return names;
    }

    public static boolean isEmpty(Object object) {
        if (object == null) {
            return true;
        } else if (object instanceof CharSequence) {
            return ((CharSequence)object).length() == 0;
        } else if (object.getClass().isArray()) {
            return Array.getLength(object) == 0;
        } else if (object instanceof Collection) {
            return ((Collection)object).isEmpty();
        } else {
            return object instanceof Map ? ((Map)object).isEmpty() : false;
        }
    }

}


package com.fd.dome.base.util;

import com.fd.dome.base.constants.Constants;

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

public class LocalStringUtil {
    private static Pattern humpPattern = Pattern.compile("[A-Z]");
    private static Pattern linePattern = Pattern.compile("_(\\w)");
    private static Pattern midLinePattern = Pattern.compile("-(\\w)");

    /** 驼峰转下划线 */
    public static String humpToLine(String str) {
        Matcher matcher = humpPattern.matcher(toLowerCaseFirstOne(str));
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);

        return sb.toString();
    }

    /** 下划线转驼峰 */
    public static String lineToHump(String str) {
       return toHump(str, Constants.Symbol.UNDER_LINE);
    }

    /**  中横线转驼峰 */
    public static String midLineToHump(String str) {
        return toHump(str, Constants.Symbol.MID_LINE);
    }

    private static String toHump(String str, String symbol) {
        str = str.toLowerCase();
        Matcher matcher;
        if (Constants.Symbol.MID_LINE.equals(symbol)) {
            matcher = midLinePattern.matcher(str);
        } else {
            matcher = linePattern.matcher(str);
        }

        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /** 对象转下划线 BaseDaoProvider => base_dao_provider*/
    public static String classToLine(Class clazz) {
        return humpToLine(clazz.getSimpleName());
    }

    /** 首字母转小写*/
    public static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return Character.toLowerCase(s.charAt(0)) + s.substring(1);
    }


    public static Set<String> getTargetListWithPattern(Pattern pattern , String str) {
        Set<String> list = new HashSet<>();
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            list.add(matcher.group());
        }
        return list;
    }

}



6、通用service接口与实现类

package com.fd.dome.base.service;

import com.fd.dome.base.entity.BaseEntity;
import com.fd.dome.base.vo.PageVo;

import java.util.Collection;
import java.util.List;
import java.util.Map;

public interface BaseService<E extends BaseEntity> {
    E findById(Long id);
    List<E> findAll();
    void save(E entity);
    void delById(Long id);
    void delByIdAndUpdateUser(Long id, String updateUser);
    void insertBatch(Collection<E> entityCollection);
}

package com.fd.dome.base.service.impl;

import com.fd.dome.base.constants.Constants;
import com.fd.dome.base.dao.BaseDao;
import com.fd.dome.base.entity.BaseEntity;
import com.fd.dome.base.service.BaseService;
import com.fd.dome.base.vo.PageVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.ParameterizedType;
import java.util.*;

public abstract class BaseServiceImpl<E extends BaseEntity, DAO extends BaseDao<E>> implements BaseService<E> {

    @Autowired
    protected DAO dao;

    @Override
    public E findById(Long id) {
        return dao.findById(id, getLocalClass());
    }

    @Override
    public List<E> findAll() {
        return dao.findAll(getLocalClass());
    }

    @Override
    public void save(E entity) {
        dao.save(entity, entity.getClass());
    }

    @Override
    public void delById(Long id) {
        dao.delById(id, getLocalClass());
    }

    @Override
    public void delByIdAndUpdateUser(Long id, String updateUser) {
        dao.delByIdAndUpdateUser(id, updateUser, getLocalClass());
    }

    @Override
    public void insertBatch(Collection<E> entityCollection) {
        insertBatch(entityCollection, 100);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertBatch(Collection<E> entityCollection, int size) {
        int tmp = (int)Math.ceil((double)entityCollection.size()/size);
        Iterator<E> iterator = entityCollection.iterator();
        for (int i = 0; i < tmp; i++) {
            Collection<E> collection = new ArrayList<>();
            for (int j = 0; j < size; j++) {
                if (iterator.hasNext())
                    collection.add(iterator.next());
            }
            dao.insertBatch(collection, getLocalClass());
        }
    }

    private Class<E> getLocalClass() {
        return  (Class <E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
}

7、springboot中的mybatis配置

mybatis:
  mapper-locations: mapper/*Mapper.xml  # 通用方法以外的方法实习
  configuration:
    map-underscore-to-camel-case: true # 驼峰

8、使用用例:

package com.fd.dome.entity;

import com.fd.dome.base.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@EqualsAndHashCode(callSuper = true)
@Data
@ToString(callSuper = true)
public class User extends BaseEntity {
    private String account;
    private String car;
}


package com.fd.dome.dao;

import com.fd.dome.base.dao.BaseDao;
import com.fd.dome.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserDao extends BaseDao<User> {
    User findByAccount(String account);
}


package com.fd.dome.service;

import com.fd.dome.base.service.BaseService;
import com.fd.dome.entity.User;

public interface UserService extends BaseService<User> {
    User findBuAccount(String account);
}


package com.fd.dome.service.impl;

import com.fd.dome.base.service.impl.BaseServiceImpl;
import com.fd.dome.dao.UserDao;
import com.fd.dome.entity.User;
import com.fd.dome.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends BaseServiceImpl<User, UserDao> implements UserService {
    @Override
    public User findBuAccount(String account) {
        return dao.findByAccount(account);
    }
}

 UserDaoMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fd.dome.dao.UserDao">


    <select id="findByAccount" resultType="com.fd.dome.entity.User">
        select * from user where account = #{account} and is_del = 0
    </select>

</mapper>

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中整合MyBatis-Plus实现Presto分页,可以按照以下步骤进行操作: 1. 首先,确保已经在项目的pom.xml文件中添加了MyBatis-Plus和Presto的依赖。 2. 在application.properties或application.yml文件中配置Presto的连接信息,包括URL、用户名和密码等。 3. 创建一个Presto分页查询的方法,可以使用MyBatis-Plus提供的Page对象来实现分页功能。在该方法中,使用@Select注解定义SQL查询语句,并使用@Param注解指定方法参数。 4. 在方法中,使用Page对象的setRecords方法将查询结果设置到Page对象中,并使用Page对象的setTotal方法设置总记录数。 5. 在方法中,使用MyBatis-Plus的selectPage方法执行分页查询,并将Page对象作为参数传递给该方法。 6. 在Controller层调用Presto分页查询的方法,并将查询结果返回给前端。 下面是一个示例代码,演示了如何在Spring Boot中整合MyBatis-Plus实现Presto分页: ```java // 引入相关的包和注解 @Service public class PrestoService { @Autowired private PrestoMapper prestoMapper; public Page<PrestoEntity> getPrestoPage(int pageNum, int pageSize) { Page<PrestoEntity> page = new Page<>(pageNum, pageSize); List<PrestoEntity> records = prestoMapper.getPrestoPage(page); page.setRecords(records); return page; } } @Mapper public interface PrestoMapper { @Select("SELECT * FROM table_name") List<PrestoEntity> getPrestoPage(Page<PrestoEntity> page); } @RestController public class PrestoController { @Autowired private PrestoService prestoService; @GetMapping("/presto/page") public Page<PrestoEntity> getPrestoPage(@RequestParam int pageNum, @RequestParam int pageSize) { return prestoService.getPrestoPage(pageNum, pageSize); } } ``` 请注意,上述代码仅为示例,实际使用时需要根据具体的表名、字段名和查询条件进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值