• (五)Alian 的 Spring Cloud DB Starter(自己写个starter)


    一、创建maven工程

      总听人说写一个 starter ,感觉很高大上一样的,没事,我们也弄一个简单的 starter ,只要引入了,就可以自动配置我们的 ebean 数据源,注意这里需要创建的是一个maven工程,项目的结构图如下:
    在这里插入图片描述

    二、maven依赖

    pom.xml

    
    <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.0modelVersion>
    
        <parent>
            <groupId>cn.alian.microservicegroupId>
            <artifactId>parentartifactId>
            <version>1.0.0-SNAPSHOTversion>
        parent>
    
        <artifactId>common-dbartifactId>
        <version>1.0.0-SNAPSHOTversion>
        <packaging>jarpackaging>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
            
            <dependency>
                <groupId>io.github.hexagonframework.bootgroupId>
                <artifactId>spring-boot-starter-data-ebeanartifactId>
            dependency>
            <dependency>
                <groupId>io.ebeangroupId>
                <artifactId>ebeanartifactId>
            dependency>
            
            <dependency>
                <groupId>com.github.dozermappergroupId>
                <artifactId>dozer-coreartifactId>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
            dependency>
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <inherited>falseinherited>
                    <executions>
                        <execution>
                            <id>spring-boot-repackageid>
                            <phase>nonephase>
                        execution>
                    executions>
                plugin>
            plugins>
        build>
    
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    三、编码

    3.1、配置类

    Config

    package cn.alian.microservice.db.config;
    
    import com.github.dozermapper.core.DozerBeanMapperBuilder;
    import com.github.dozermapper.core.Mapper;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("cn.alian.microservice.db")
    public class Config {
    
        @Bean
        @ConditionalOnMissingBean
        public Mapper mapper() {
            return DozerBeanMapperBuilder.buildDefault();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

      这里扫描的目录不要错了哦,我们这里的java类都是在 cn.alian.microservice.db 这个下面,所以扫描这个,大家可以看我前面的目录结构。

    3.2、Ebean封装类

    EbeanService

    package cn.alian.microservice.db.service;
    
    import com.github.dozermapper.core.Mapper;
    import io.ebean.EbeanServer;
    import io.ebean.ExpressionList;
    import io.ebean.PagedList;
    import io.ebean.Query;
    import org.apache.commons.lang3.tuple.Pair;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.PageImpl;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.ebean.util.Converters;
    import org.springframework.stereotype.Service;
    
    import java.util.stream.Collectors;
    
    @Service
    public class EbeanService {
    
        @Autowired
        private Mapper mapper;
    
        @Autowired
        private EbeanServer ebeanServer;//不要删除这个哦
    
    	//封装一个分页查询(其他的根据需要可以加其他的方法哦)
        public <T, D> Page<D> pageDtoList(Pair<ExpressionList<T>, PageRequest> pair, Class<D> d) {
            Page<T> page = pageList(pair);
            return new PageImpl<>(page.getContent().stream().map(e -> mapper.map(e, d)).collect(Collectors.toList()),
                    page.getPageable(), page.getTotalElements());
        }
    
        public <T> Page<T> pageList(Pair<ExpressionList<T>, PageRequest> pair) {
            ExpressionList<T> where = pair.getLeft();
            PageRequest pageRequest = pair.getRight();
            Query<T> query = where.order().getQuery().setMaxRows(pageRequest.getPageSize())
                    .setFirstRow((int) pageRequest.getOffset());
            PagedList<T> pagedList = query.findPagedList();
            return Converters.convertToSpringDataPage(pagedList, pageRequest.getSort());
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

      以后可以根据项目需要写公共的操作方法,像我这里所有的项目引入这个就可以使用分页的方法了。

    四、配置spring.factories

       resources/META-INF/spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    cn.alian.microservice.db.config.Config
    
    • 1
    • 2

      这里的配置项就是我们的配置类,配置类会自动扫描我们指定的包,从而达到自动装配,尤其是那个
    io.ebean.EbeanServer 类,它才是真正的关键哦, 不要因为本类没有用就删除哦。

    五、打包发布脚本

    deploy.bat

    cd %~dp0
    cd..
    
    call mvn clean source:jar deploy -Dmaven.test.skip=true
    
    cd bin
    pause
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    install.bat

    cd %~dp0
    cd..
    
    call mvn clean install -Dmaven.test.skip=true
    
    cd bin
    pause
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

      如果是发布到私服就用第一个,如果是本地开发可以用第二个安装到本地。

    六、使用

      当任意项目需要使用我们自己写的starter,引入以下依赖即可(当然你还得加上跟数据库相关的配置,我们后面会有)

     <dependency>
         <groupId>cn.alian.microservicegroupId>
         <artifactId>common-dbartifactId>
         <version>1.0.0-SNAPSHOTversion>
     dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    七、验证

      由于我们在验证服务注册时,我们已经创建了order订单服务,我们只需要继续改造下就行了。

    7.1、验证

    pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        
        <dependency>
            <groupId>cn.alian.domaingroupId>
            <artifactId>domain-orderartifactId>
            <version>1.0.0-SNAPSHOTversion>
        dependency>
    	
        <dependency>
            <groupId>cn.alian.microservicegroupId>
            <artifactId>common-dbartifactId>
            <version>1.0.0-SNAPSHOTversion>
        dependency>
    	
        <dependency>
            <groupId>com.googlecode.log4jdbcgroupId>
            <artifactId>log4jdbcartifactId>
        dependency>
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    7.2、配置文件

      接下里就是你期待的配置文件,没错就是很普通的spring datasource的配置文件,看起来和 ebean 都没有关系, 是不是有种错觉,博主是不是粘贴错了? 来,我们验证下!

    application.properties

    #服务名
    spring.application.name=order
    #端口
    server.port=7001
    #eureka注册中心地址
    eureka.client.serviceUrl.defaultZone=http://10.130.3.222:8761/eureka
    
    #数据库配置
    spring.datasource.driver-class-name=net.sf.log4jdbc.DriverSpy
    spring.datasource.url=jdbc:log4jdbc:mysql://10.130.3.99:3306/order?autoReconnect=true&useSSL=false
    spring.datasource.username=alian
    spring.datasource.password=Alian1223
    spring.datasource.hikari.connection-timeout=5000
    spring.datasource.hikari.maximum-pool-size=10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.3、service层

    TestDbService

    package cn.alian.mall.order.service;
    
    import cn.alian.domain.order.domain.Order;
    import cn.alian.domain.order.domain.query.QOrder;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Service;
    
    @Slf4j
    @Service
    public class TestDbService {
    
        public Order queryOrder(int id) {
            Order order = new QOrder()._id().eq(id).findOne();
            log.info("查询的结果:{}", order);
            return order;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.4、controller层

    TestDbController

    package cn.alian.mall.order.controller;
    
    import cn.alian.domain.order.domain.Order;
    import cn.alian.mall.order.service.TestDbService;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @Slf4j
    @Validated
    @RestController
    @RequestMapping({"/test"})
    public class TestDbController {
    
        @Autowired
        private TestDbService testDbService;
    
        @GetMapping("/getOrder")
        public Order testOrder() {
            return testDbService.queryOrder(1);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    请求后能查询到数据库的数据:

    {"id":1,"userId":8001,"goodsId":10001,"price":10,"num":3,"title":"数字藏品","orderStatus":"00","createTime":"2022-04-07T03:37:23.654","updateTime":"2022-04-07T03:37:23.893"}
    
    • 1

      事实证明,博主没有贴错吧,说明我们的Ebean的整合是可以用了,并且 Query Bean 也是可以用的。

    特别提醒:

      如果是使用 @PostConstruct 进行测试,还需要引入如下依赖

        @Autowired
        private EbeanServer ebeanServer;
    
    • 1
    • 2

      不然就会有如下提示

    Caused by: io.ebean.datasource.DataSourceConfigurationException: Configuration error creating DataSource for the default Database. This typically means a missing application-test.yaml or missing ebean-test dependency. See https://ebean.io/docs/trouble-shooting#datasource
    	at io.ebean.Ebean$ServerManager.(Ebean.java:87) ~[ebean-12.2.6.jar:na]
    	at io.ebean.Ebean$ServerManager.(Ebean.java:50) ~[ebean-12.2.6.jar:na]
    	at io.ebean.Ebean.(Ebean.java:45) ~[ebean-12.2.6.jar:na]
    	... 44 common frames omitted
    Caused by: io.ebean.datasource.DataSourceConfigurationException: DataSource user is null?
    	at io.ebean.datasource.pool.ConnectionPool.(ConnectionPool.java:220) ~[ebean-datasource-4.7.3.jar:na]
    	at io.ebean.datasource.core.Factory.createPool(Factory.java:15) ~[ebean-datasource-4.7.3.jar:na]
    	at io.ebeaninternal.server.core.DefaultContainer.getDataSourceFromConfig(DefaultContainer.java:290) ~[ebean-12.2.6.jar:na]
    	at io.ebeaninternal.server.core.DefaultContainer.setDataSource(DefaultContainer.java:234) ~[ebean-12.2.6.jar:na]
    	at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:100) ~[ebean-12.2.6.jar:na]
    	at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:70) ~[ebean-12.2.6.jar:na]
    	at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:36) ~[ebean-12.2.6.jar:na]
    	at io.ebean.EbeanServerFactory.create(EbeanServerFactory.java:58) ~[ebean-12.2.6.jar:na]
    	at io.ebean.Ebean$ServerManager.getWithCreate(Ebean.java:128) ~[ebean-12.2.6.jar:na]
    	at io.ebean.Ebean$ServerManager.(Ebean.java:77) ~[ebean-12.2.6.jar:na]
    	... 46 common frames omitted
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

      因为 Query Bean 就像一堆静态的方法,需要数据源初始化好了才能用,执行 @PostConstruct 时,ebean数据源可能还没有初始化,需要让容器扫描到才会加载, 这个"坑",我一般不告诉别人的。 当然如果你不是用的 @PostConstruct 测试就不用加了。

  • 相关阅读:
    探索跨境电商产品开发流程的最佳工具
    访问者模式 行为型设计模式之九
    k8s yaml文件编写技巧
    设计一个支持百万用户的系统
    macOS上实现「灵动岛」效果
    script defer async模式
    MySQL常用函数汇总
    多场景适用,多卡聚合路由器才是真刚需
    PyTorch深度强化学习中蒙特卡洛策略梯度法在短走廊环境(CartPole-v0)中的实战(超详细 附源码)
    maven的生命周期
  • 原文地址:https://blog.csdn.net/Alian_1223/article/details/124026228