(五)Alian 的 Spring Cloud DB Starter(第一个Spring Cloud starter)

一、创建maven工程

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

二、maven依赖

pom.xml

<?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>cn.alian.microservice</groupId>
        <artifactId>parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>common-db</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--整合ebean-->
        <dependency>
            <groupId>io.github.hexagonframework.boot</groupId>
            <artifactId>spring-boot-starter-data-ebean</artifactId>
        </dependency>
        <dependency>
            <groupId>io.ebean</groupId>
            <artifactId>ebean</artifactId>
        </dependency>
        <!--dozermapper映射增强-->
        <dependency>
            <groupId>com.github.dozermapper</groupId>
            <artifactId>dozer-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <inherited>false</inherited>
                <executions>
                    <execution>
                        <id>spring-boot-repackage</id>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

三、编码

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();
    }

}

  这里扫描的目录不要错了哦,我们这里的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());
    }

}

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

四、配置spring.factories

   resources/META-INF/spring.factories

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

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

五、打包发布脚本

deploy.bat

cd %~dp0
cd..

call mvn clean source:jar deploy -Dmaven.test.skip=true

cd bin
pause

install.bat

cd %~dp0
cd..

call mvn clean install -Dmaven.test.skip=true

cd bin
pause

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

六、使用

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

 <dependency>
     <groupId>cn.alian.microservice</groupId>
     <artifactId>common-db</artifactId>
     <version>1.0.0-SNAPSHOT</version>
 </dependency>

七、验证

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

7.1、验证

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--eureka注册中心-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--订单实体,自动生成ebean querybean-->
    <dependency>
        <groupId>cn.alian.domain</groupId>
        <artifactId>domain-order</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
	<!--自己写的db starter-->
    <dependency>
        <groupId>cn.alian.microservice</groupId>
        <artifactId>common-db</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </dependency>
	<!--mysql数据库连接-->
    <dependency>
        <groupId>com.googlecode.log4jdbc</groupId>
        <artifactId>log4jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

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

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;
    }
}

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);
    }

}

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

{"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"}

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

特别提醒:

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

    @Autowired
    private EbeanServer ebeanServer;

  不然就会有如下提示

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.<init>(Ebean.java:87) ~[ebean-12.2.6.jar:na]
	at io.ebean.Ebean$ServerManager.<init>(Ebean.java:50) ~[ebean-12.2.6.jar:na]
	at io.ebean.Ebean.<clinit>(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.<init>(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.<init>(Ebean.java:77) ~[ebean-12.2.6.jar:na]
	... 46 common frames omitted

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值