olap分析平臺的設計與實現(十七)- springboot集成mondrian

開發環境搭建:

1個想法一通向導搞定spring boot

ps:使用IDEA構建一個SpringBoot + Hibernate + Gradle項目

這一步,算是建造了spring + hibernate,後面還有連接池,換成mybatis的問題。

idea中Alt + Enter導入包,和eclipse有點不一樣。

甲骨文罐子??:ps:  gradle開發springboot項目,連接甲骨文數據庫

然後狂建一堆model .....

測試運行一遍:報錯:

java.lang.IllegalArgumentException: Not a managed type: class com.comm.f_olap.model.CommObject...

。實體類加上註解啥的,問題解決。

@Entity
@Table(name = "user")//數據庫的表名
public class CommObject {
	@Id
	private int id;
	@Column(name = "name")//數據庫的字段名,數據庫 不區分大小寫 這個 要注意
.....

連接池:

ps:深入理解Spring Boot數據源與連接池原理

spring boot自帶了連接池?測試一把:

@SpringBootTest
class FOlapApplicationTests {
    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() {
        System.out.println(dataSource.getClass());
    }

}

結果:com.zaxxer.hikari.HikariDataSource類。

貌似HikariDataSource蠻強大,本想約會德魯伊,有了可用的連接池,就不看其他的,否則,我可能還得做加配置文件等工作。

HikariDataSource是spring boot2才約會的。

ps:本想約會德魯伊:

build.gradle:中加一行:

compile group: 'com.alibaba', name: 'druid', version: '1.1.10'

屬性文件(application.properties)如下:

server:
    port: 8881
    max-http-header-size: 102400

spring:
    datasource:
        url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
        username: SUPERVISION
        password: 1
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: oracle.jdbc.OracleDriver
        druid:
            initial-size: 1
            min-idle: 1
            max-active: 300
            max-wait: 60000
            time-between-eviction-runs-millis: 60000
            min-evictable-idle-time-millis: 30000
            validation-query: SELECT 'x' from dual
            test-while-idle: true
            test-on-borrow: false
            test-on-return: false
            pool-prepared-statements: true
            max-pool-prepared-statement-per-connection-size: 20
            filters: stat,slf4j
            connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
            web-stat-filter.enabled: true
            web-stat-filter.principal-session-name: username
            stat-view-servlet.enabled:  true
            stat-view-servlet.url-pattern:  /druid/*
    jpa:
        show-sql: true
        database: oracle
        properties:
            hibernate:
                dialect: org.hibernate.dialect.OracleDialect
                enable_lazy_load_no_trans: true
        open-in-view: true

運行報錯:應該是還要加一個配置文件,既然用HikariDataSource,這個就不進行下去了。

ps:相關參考:用到時候,參考一下,這裏先記下。

  1. 深入瞭解Spring Boot數據源與連接池原理
  2.  
  3. Spring Boot集成Druid連接池(MySQL8.0.11)
  4. springBoot + gradle + Oracle配置德魯伊
  5. springboot多數據源(三種數據庫連接池--JDBC,dbcp2,Druid)
  6.  
  7. Springboot整合Druid,添加攔截器進行數據監控
  8. springboot添加德魯伊步驟
  9. Springboot + Mybatis的+ dbcp + MySQL的簡單集成
  10. springboot配置數據庫連接池
  11. SpringBoot配置連接池
  12. springboot添加druid步驟(兩種方案)
  13. springboot2.0整合德魯伊,以及springboot自動裝配DataSource原理

持久層考慮因素:

        1,我們要集成mondrian,mondrian好像是jdbc直連,所以測試一下mondrian集成在spring boot 2.0下的表現。

                       從2個方面測試,一個是mondrian直聯jdbc,一個是和spring boot jdbc template Integrated?

        2,我們項目用hibernate還是mybatis?

                     hibernate?對我來說,類是繼承的pojo,hibernate如何實現,得測試一遍。

                      mybatis?貌似蠻靈活,但可以點擊,也得測試一遍。

        因此,我們要從三個方面進行測試:

  1.                       mondrian集成;
  2.                       hibrenate中,pojo是繼承關係的rud測試。
  3.                       mybatis測試。    

spring boot環境下 mondrian集成:

    mondrian集成?參考我前面寫的《非稅olap分析平臺的設計與實現(二)_測試開發配置》。

ps:Zxing的集成---- Maven對應Gradle的寫法

測試不成功,可能是代理,GW惹的禍?

不管它:

直接約會lib,

gradle中,加入 dependencies{compile files('lib/mondrian-4.7.0.0-12.jar')} ok!

搭建環境中,沒必要掌握所有細節,還是得以解決問題爲導向。

mondrian集成過程:gradle中添加如下內容(也許有多的jar):

    dependencies{compile files('lib/mondrian-4.7.0.0-12.jar')}
    dependencies{compile files('lib/eigenbase-xom-1.3.4.jar')}
    dependencies{compile files('lib/eigenbase-resgen-1.3.1.jar')}
    compile group: 'org.olap4j', name: 'olap4j', version: '1.2.0'
    compile group: 'org.olap4j', name: 'olap4j-xmlaserver', version: '1.2.0'
    //compile group: 'eigenbase', name: 'eigenbase-xom', version: '1.3.4'
    compile group: 'net.hydromatic', name: 'eigenbase-properties', version: '1.1.5'
    //compile group: 'eigenbase', name: 'eigenbase-resgen', version: '1.3.1'
    compile group: 'commons-math', name: 'commons-math', version: '1.2'
    compile group: 'apache-log4j', name: 'log4j', version: '1.2.14'
    compile group: 'commons-vfs', name: 'commons-vfs', version: '1.0'
    compile group: 'org.apache.commons', name: 'commons-vfs2', version: '2.1'

但 測試運行報錯:

org.apache.commons.vfs.FileSystemException: Could not create a file system manager of class "org.apache.commons.vfs.impl.StandardFileSystemManager".
	at org.apache.commons.vfs.VFS.createManager(VFS.java:93)
	at org.apache.commons.vfs.VFS.getManager(VFS.java:47)
	at mondrian.spi.impl.ApacheVfsVirtualFileHandler.readVirtualFile(ApacheVfsVirtualFileHandler.java:37)
	at mondrian.olap.Util.readVirtualFile(Util.java:3479)
	at 
......
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal
	at java.lang.ClassLoader.defineClass1(Native Method)
	......
Caused by: java.lang.ClassNotFoundException: org.w3c.dom.ElementTraversal
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 97 more

java.lang.NoClassDefFoundError: org/apache/commons/collections/map/ReferenceMap

	......
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.map.ReferenceMap
	at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 78 more

提示差java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal ,百度一番,發現這個jar 報名是xml-apis

ps:java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal 的解決辦法

打開原來maven引用的情況如下:

可以看到,olap4j 依賴xml_apis.jar,

我這裏是complie引用該jar,因此,(gradle 沒有優先讀本地maven?這方式沒有加載olap4j 所依賴的庫?或者maven庫有問題?)

另外ClassNotFoundException:org.apache.commons.collections.map.ReferenceMap,這個問題,是差commons-collections。

重新引入它,運行測試,報錯:

2019-11-14 13:59:36.548  INFO 83320 --- [           main] o.a.c.vfs.impl.DefaultFileReplicator     : Using "C:\Users\tbxc\AppData\Local\Temp\vfs_cache" as temporary files store.
mondrian.olap.MondrianException: Mondrian Error:Internal error: Virtual file is not readable: FSCK_MDX.xml
	at mondrian.resource.MondrianResource$_Def0.ex(MondrianResource.java:989)
	at mondrian.olap.Util.newInternal(Util.java:2536)
	at mondrian.olap.Util.newError(Util.java:2551)
	at 
......

mondrian.olap.MondrianException: Mondrian Error:Connect string must contain property 'Catalog' or property 'CatalogContent'

	at mondrian.resource.MondrianResource$_Def1.ex(MondrianResource.java:1009)
	......

文件路徑不對?重新copy路徑如下圖:

ok! 測試通過!

完整gradle如下:

plugins {
    id 'org.springframework.boot' version '2.2.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
}

group = 'com.Comm'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
    mavenCentral()
}

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'



    implementation('org.springframework.boot:spring-boot-starter-actuator')
    implementation('org.springframework.boot:spring-boot-starter-data-jpa')
    implementation('org.springframework.boot:spring-boot-starter-jdbc')
    implementation('org.springframework.boot:spring-boot-starter-web')
    testImplementation('org.springframework.boot:spring-boot-starter-test')

    dependencies{compile files('lib/ojdbc6.jar')}

    dependencies{compile files('lib/mondrian-4.7.0.0-12.jar')}
    dependencies{compile files('lib/eigenbase-xom-1.3.4.jar')}
    dependencies{compile files('lib/eigenbase-resgen-1.3.1.jar')}
    dependencies{compile files('lib/xml-apis-1.4.01.jar')}
    compile group: 'org.olap4j', name: 'olap4j', version: '1.2.0'
    compile group: 'org.olap4j', name: 'olap4j-xmlaserver', version: '1.2.0'

    compile group: 'net.hydromatic', name: 'eigenbase-properties', version: '1.1.5'

    compile group: 'commons-math', name: 'commons-math', version: '1.2'
    compile group: 'apache-log4j', name: 'log4j', version: '1.2.14'
    compile group: 'commons-vfs', name: 'commons-vfs', version: '1.0'
    compile group: 'org.apache.commons', name: 'commons-vfs2', version: '2.1'
    compile group: 'commons-collections', name: 'commons-collections', version: '3.2.2'

}

test {
    useJUnitPlatform()
}

hibernate5:

繼承關係的測試:

//父類
@Entity
@Table(name = "COMMOBJECT")//數據庫的表名
@Inheritance(strategy = InheritanceType.JOINED)
public class CommObject {
	@Id
	private int id;
	@Column(name = "name")//數據庫的字段名,數據庫 不區分大小寫 這個 要注意
	private String name;
....

//子類

@Entity
@Table
@PrimaryKeyJoinColumn(name = "id")
public class FormFolder extends CommObject {
....

以前我都是寫配置文件,這次換註解,測試通過。

參考文檔:

spring-data-jpa實現繼承實體類詳解

Hibernate繼承註解

SpringBoot 與JPA結合中 JpaRepository 裏自定義查詢

ibats?算了,用hibernate就夠了!

原型需要的數據:

開發先做關鍵原型,接下來準備各種原型需要的數據。

先準備維度數據:年度、期間、版本、幣別、場景、項目、組織

                                                                             (維度的管理類) 

一個具體維度,數據庫上有三張表反映:

                                                                             (維度及mondrian相關表) 

維度相關的表:

  1. commObject,所有原始的祖先表;
  2. 前綴爲 “c_” 的表,用於管理各類維度。
  3. 前綴爲““c_dim_”的表,是mondrain引擎用到維度表。

配置mondrian的schemal相關的維度表用"c_dim_"前綴開頭。

維度數據準備,以後應該用kettle抽取?

由於我先搞了一個項目維度表,感覺內容多了,相關數據重新遷移到commobject表。

  select p.projectkey + 500000,
         p.projectname,
         1,
         -100,    --上級id 下面再處理
         case   --代數
           when p.projectcode = p.level1projectcode then
            1
           when p.projectcode = p.level2projectcode then
            2
           when p.projectcode = p.level3projectcode then
            3
           when p.projectcode = p.level4projectcode then
            4
           when p.projectcode = p.level5projectcode then
            5
           when p.projectcode = p.level6projectcode then
            6
           when p.projectcode = p.level7projectcode then
            7
           when p.projectcode = p.level8projectcode then
            8
         end,
         
         case p.isleaf   --是否有子節點
           when '0' then
            1
           when '1' then
            0
         end,
         rank,
         0,
         to_timestamp(to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss'),     --時間戳
                      'yyyy-mm-dd hh24:mi:ss')
    from dim_chargeproject p,
         
         (select p.projectkey projectkey,
                 p.projectcode,
                 p.projectname
                 
                ,
                 rank() over(order by p.projectcode) rank   --排序號 可能有問題
            from dim_chargeproject p) pr
   where pr.projectkey = p.projectkey

ps:timestamp 是oracle對date的擴展,其度量精度比date類型更高。

case when 在這條語句中有2個形態,注意語法上些許差別。

上面沒有更新commobject表中parent,後面用一條語句更新一下,即根據一張表的數據更新另外一張表相關字段。

--temp22 是一張臨時表 
update commobject t

   set t.parent = (select s.pk2 from temp22 s where s.pk0 = t.id)

 where t.id in (select s.pk0 from temp22 s)

mondrian用到的維度表是偏平化結構,所以要去掉非末級節點:


delete   from c1_dim_account  c1 where c1.id in (

select p.projectkey+500000 pk0 from dim_chargeproject p where p.isleaf=0);

 到此,模擬維度數據準備完畢。

 

其他開發配置:

我們項目何vue前端,採取json交換,因此,引入了json相關jar,json消息,我們需要進行格式化封裝,沿用我們原有項目格式,又是一番copy,解決問題。

測試vue 前端和後端服務連接,上一段測試代碼,ok! 測試代碼如下:

<template>
  <div id="vue_olap_showData">
    <div>
      <el-button type="primary" @click="get_olap_showData">讀取後臺數據</el-button>
    </div>
    <div class="olapResult" v-html="olapData"></div>
  </div>
</template>

<script  type="text/javascript">
import olapShowData from "@/api/olap/olap_showData.js";
export default {
  data() {
    return {
      olapData: ""
    };
  },
  methods: {
    get_olap_showData() {
      olapShowData.olapShowData().then(res => {
        this.olapData = res.data;
      });
    }
  }
};
</script>

<style lang='scss'>
.olapResult {

  td {
    font-size: 12px;
    border-left: solid 1px silver;
    border-right: none;
    border-top: none;
    border-bottom: solid 1px silver;
    text-align: right;
    width: 105px;
    height: 25px;
  }
}
//flex 高度控制的問題,還有點模糊,先放着
.vue_olap_showData {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}


</style>

效果如下圖:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章