SDKでできること ~上級編~

SDKでできること ~上級編~

これからSDKで開発する人や既に開発している人のために、SDKでどんなことができるのか、サンプルを紹介していきます。

ASP.NETの知識があれば、FullWEB SDKの知識ゼロでも読み進められます。
(以下のサンプルコードはVisual Basicで書いています)

第8回 登録時イベントによる複数ファイルの自動関連付け

FullWEBには属性を記述したCSVファイルと登録したいファイルをセットでドラッグ&ドロップして属性付きでファイルを登録するCSV入力機能がありますが、今回は複数の登録ファイルをドラッグ&ドロップすることで登録完了後に追加の処理を行うサンプルについてご説明します。

サンプルの動作は次の通りです。

  1. 案件管理ファイル(xlsx)と要件定義書(pdf)と仕様書(docx) を同じフォルダに配置
  2. 1. のフォルダに追加処理.xml を配置
  3. 登録ファイル3つと追加処理.xmlの合計4ファイルを選択してFullWEBにドラッグ&ドロップ
  4. 登録が完了すると案件管理ファイルから属性抽出された属性を要件定義書と仕様書に転記し、
    案件管理ファイルと親子関係で紐づけされる。
  5. 追加処理.xmlは登録処理後に自動的に削除される
画像:FullWEB画面
図1. サンプルの動作

本サンプルでは登録ファイル同士を親子関係で紐づける追加処理を行っていますが、同じイベントを使って登録済みのファイルとの親子関係やBOM構成の作成など様々な応用が可能で、最もよく使われるイベント処理の一つです。

FullWEBでの設定

本サンプルでは、「案件資料」という分類ラベルを作成して「案件名」「種別」を定義しておきます。

画像:分類ラベルの定義

SDK で開発する内容

SDKマニュアルのチュートリアルにある「登録(前処理/後処理)プラグインの作成」と同じ要領でプロジェクトを作成します。
IGAPEx インターフェイスはドラッグ&ドロップでファイルを登録するとき、次の順でイベントを呼び出します。

1 StartCheckIn ドラッグ&ドロップが開始されたときに発生する。
初期化を行う。
2 IsSupported 登録ファイルごとに発生する。
対象ファイルに対して追加処理を行う必要があるかを返答する。
3 GetAttrEx IsSupported で true を返すと続けて呼び出される。
属性値の追加設定などを行う。
4 CheckInFinished 一連の登録処理が完了したときに呼び出される。
登録完了後の後処理を行う。
画像 図2. 登録時のイベントフロー
図2. 登録時のイベントフロー

今回はそれぞれのイベントで次の処理を行います。

1 StartCheckIn 登録ファイルを保持するディクショナリを初期化します。
2 IsSupported 常に true を返します。
3 GetAttrEx 登録ファイルのFIDとファイル名をディクショナリに追加します。
登録ファイルが追加処理.xmlであればXMLの内容を変数に読み込んでおきます。
4 CheckInFinished 追加処理.xml が読み込まれていれば、内容に従って登録後の後処理を行います。

今回のサンプルでは、追加処理.xml は次の内容とします。

<?xml version="1.0"?>
<config>
  <top fnameExp="案件管理"/>
  <children>
    <child name="要件定義" fnameExp="要件定義">
      <attrs>
        <add attr="案件資料¥案件名" value="={%TOPATTR%}"/>
        <add attr="案件資料¥種別" value="要件定義"/>
      </attrs>
    </child>
    <child name="仕様書" fnameExp="仕様書">
      <attrs>
        <add attr="案件資料¥案件名" value="={%TOPATTR%}"/>
        <add attr="案件資料¥種別" value="仕様書"/>
      </attrs>
    </child>
  </children>
</config>
top 正規表現 fnameExp で指定されたファイル名を持つファイルを案件管理の代表ファイルとします。
children 代表ファイルに紐づける設定。fnameExp に合致した設定を使って親子関係の種別を決定します。
attrs 登録ファイルに付与する属性を指定します。
={%TOPATTER%} という値を指定すると、代表ファイルから属性値を転記します。

この追加処理.xml の例では、登録されたファイルの中に「案件管理」という文字列を含むファイル名があれば、「要件定義」「仕様書」の文字列をファイル名に含むファイルを親子設定し、コメントに種別を設定するという動作になります。子ファイルの「案件名」属性には案件管理ファイルの属性値として設定された値が転記されます。

属性の設定や親子関係の設定は最後のイベント「CheckInFinished」でまとめて行われます。
CheckInFinished イベントの処理の流れは次のようになります。

Public Sub CheckInFinished() Implements IGetAttrEx.CheckInFinished
    '   追加処理.xml が読み込まれていなければ終了
    If m_xConfig Is Nothing Then
        Return
    End If

    '   GetAttrEx でキャッシュしたファイル一覧でループして処理対象の File オブジェクト一覧を作成
    '   1. GetFile() でファイルが登録されていなければスキップ(※1)。登録されていればディクショナリで保持
    '   2. top の fnameExp に合致するものであれば fid を設定に紐づけ
    '   3. childタグでループして fnameExp に合致するものがあれば fid を設定に紐づけ

    '   追加処理.xml が登録されていたら削除
    '   代表ファイルが見つからなければ終了

    '   child タグでループして、子ファイルの属性設定と代表ファイルへの親子関係の設定を行う。

End Sub

※1登録時に登録画面でキャンセルされた場合に未登録となるのでこの判定を行います。

最終的なコードは次のようになります。

Imports System.Text
Imports System.Xml
Imports cnWebCoreTest

Public Class GAPEx
    Implements cnWebCoreTest.IGetAttrEx
    Implements cnWebCoreTest.ISetAttr

    Private m_db As cnWebCoreTest.Database = Nothing
    Private m_xConfig As XElement = Nothing
    Private m_configFid As Integer = 0
    Private m_dicFidFname As New Dictionary(Of Integer, String)

    Public Function Initinstanse(db As Database) As Boolean Implements IGetAttrEx.Initinstanse
        m_db = db
        Return True
    End Function

    Public Sub StartCheckIn() Implements IGetAttrEx.StartCheckIn
        m_dicFidFname.Clear()
        m_xConfig = Nothing
        m_configFid = 0
    End Sub

    Public ReadOnly Property IsSupported(path As String) As Boolean Implements IGetAttrEx.IsSupported
        Get
            Return True
        End Get
    End Property

    Public Sub GetAttrEx(f As File, ByRef fls As Files) Implements IGetAttrEx.GetAttrEx
        m_dicFidFname.Add(f.Fid, f.Name)
        If String.Equals(f.Name, "追加処理.xml") Then
            Try
                m_xConfig = New XElement(XElement.Load(f.LocalFile.LocalPath))
                m_configFid = f.Fid
            Catch ex As Exception
                m_xConfig = Nothing
            End Try
        End If
    End Sub

    Public Sub CheckInFinished() Implements IGetAttrEx.CheckInFinished
        '   追加処理.xml が読み込まれていなければ終了
        If m_xConfig Is Nothing Then
            Return
        End If

        Dim xTop As XElement = m_xConfig.<top>.First

        '   m_dicFidFname でループ
        Dim dicFidFile As New Dictionary(Of String, cnWebCoreTest.File)
        For Each fid As Integer In m_dicFidFname.Keys
            '   1. GetFile() でファイルが登録されていなければスキップ。登録されていればディクショナリで保持
            Dim f As cnWebCoreTest.File = m_db.SafeGetFile(fid)
            If f Is Nothing Then
                Continue For
            End If
            dicFidFile(fid.ToString) = f

            '   2. top の fnameExp に合致するものであれば fid を設定に紐づけ
            If Regex.Match(f.Name, xTop.@fnameExp).Success Then
                xTop.@fid = f.Fid.ToString
                Continue For
            End If

            '   3. childタグでループして fnameExp に合致するものがあれば fid を設定に紐づけ
            For Each xChild As XElement In m_xConfig.<children>.<child>
                If Regex.Match(f.Name, xChild.@fnameExp).Success Then
                    xChild.@fids = xChild.@fids & "," & f.Fid.ToString
                    Exit For
                End If
            Next
        Next

        '   追加処理.xml が登録されていたら削除
        If dicFidFile.ContainsKey(m_configFid) Then
            dicFidFile(m_configFid).MoveToTrash()
        End If

        '   代表ファイルが見つからなければ終了
        If xTop.@fid = "" Then
            Return
        End If

        '   child タグでループして、子ファイルの属性設定と代表ファイルへの親子関係の設定を行う。
        Dim topFile As cnWebCoreTest.File = dicFidFile(xTop.@fid)
        For Each xChild As XElement In m_xConfig.<children>.<child>
            If xChild.@fids = "" Then
                Continue For
            End If
            Dim dicAttrVal As New Dictionary(Of String, Object)
            For Each xAdd As XElement In xChild.<attrs>.<add>
                Dim acai() As String = xAdd.@attr.Split("¥")
                If acai.Length <> 2 Then
                    Continue For
                End If
                Dim aaid As Integer = m_db.GetALID(acai(0), acai(1))
                If aaid = 0 Then
                    Continue For
                End If
                Dim value As String = xAdd.@value
                If value = "={%TOPATTR%}" Then
                    If topFile.ContainsAttr(acai(0)) Then
                        value = topFile.Attrs(acai(0)).Item("k" & aaid.ToString).Value
                    Else
                        Continue For
                    End If
                End If
                xAdd.@acname = acai(0)
                xAdd.@aaid = aaid.ToString
                dicAttrVal(xAdd.@attr) = value
            Next
            Dim fids() As String = xChild.@fids.Substring(1).Split(",")
            For Each fidStr As String In fids
                '   子ファイルの属性設定
                Dim f As cnWebCoreTest.File = dicFidFile(fidStr)
                For Each xAdd As XElement In xChild.<attrs>.<add>
                    If dicAttrVal.ContainsKey(xAdd.@attr) = False Then
                        Continue For
                    End If
                    f.AddAttr(xAdd.@acname).Item("k" & xAdd.@aaid).Value = dicAttrVal(xAdd.@attr)
                Next
                f.UpdateAttr(True)

                '   親子関係の設定
                topFile.Links.AddLink(f.Fid, xChild.@name, "")
            Next
        Next
    End Sub

    Public Sub Terminate() Implements IGetAttrEx.Terminate
        m_db = Nothing
    End Sub

    Private Function ISetAttr_Initinstanse(db As Database) As Boolean Implements ISetAttr.Initinstanse
        Initinstanse(db)
        Return True
    End Function

    Public ReadOnly Property IsGatAttr As Boolean Implements ISetAttr.IsGatAttr
        Get
            Return True
        End Get
    End Property

    Private ReadOnly Property ISetAttr_IsSupported(path As String) As Boolean Implements ISetAttr.IsSupported
        Get
            Return False
        End Get
    End Property

    Public Sub SetAttr(f As File, strDavPath As String) Implements ISetAttr.SetAttr
        '   何もしない
    End Sub

    Private Sub ISetAttr_Terminate() Implements ISetAttr.Terminate
        '   何もしない
    End Sub
End Class

今回のサンプルは成果物管理でファイルをまとめて登録するような用途で活用できる作りとなっています。ファイル名をルールに基づいて作成しておき、案件管理ファイルを Excelで作成して案件名などを属性抽出させるようにすれば、作成したファイルをまとめてドロップするだけで案件に紐づくファイルの関連を自動で設定することができるようになります。

第9回 BOMメニューにメニューを追加し、そのメニューからJavaScript関数を呼ぶ方法(1/3)

今回より全3回にわたり、FullWEB-PDMユーザ向けにBOMの処理をするプログラムを紹介します。
下図のように、CSVファイルの行と列でBOMの構成を表現した帳票を表示させます。

画像-CSVファイルの行と列でBOMの構成を表現した帳票

処理フロー

処理フロー

処理の大まかな流れは以下のようになります。

画像-処理フロー

処理フロー

  1. ①BOMエディタからブラウザのJavaScript関数をコールする。
  2. ➁JavaScript関数はサーバへページを要求する。
  3. ③サーバはクライアントへページを返す。
  4. ④ページからサーバへCSVファイルを要求する。
  5. ⑤サーバはCSVファイルを返す。

※FullWEB-PDM 9.0以降のBOMエディタはWindowsアプリケーションとして動作します。

SDKで開発する内容

SDKで開発する内容

BOM機能の開発はボリュームがあるので、処理フロー①を2回に分けて説明します。

処理フロー①(前編)BOMエディタからブラウザのJavaScript関数をコールする。

最初にVisual Studio でFullWEB WEBアプリケーション用の開発環境を整えます。
(FullWEB SDKマニュアルに掲載しています)
※以下ではプロジェクト名をcmdsampleとしています。

Visual Studioの[すべてのファイルを表示] ボタンをクリックしてFullWEBパッケージのファイルを表示し、
以下の3つのファイルをプロジェクトに追加しておきます。

  • ClientBin¥bom¥fullweb¥config.xml
  • ClientBin¥ApplicationInfo.xml
  • ExCmdBom.js

※必須操作ではありませんが、ソース管理しやすくなると思います。

画像-Visual Studio画面

続いて、BOMエディタ用のプロジェクトを追加します。
WPFユーザーコントロールライブラリ(.NET Framework)として作成します。
cmdsampleプロジェクトのClientBin¥bom¥fullweb¥CnBomEditorCore.dll を参照に追加します。
※以下ではプロジェクト名をbomcmdsampleとしています。

画像-Visual Studio画面

bomcmdsampleプロジェクトにクラスを追加します。
CnBomEditorCore.Commandクラスを継承し、DispNameプロパティとExecuteメソッドをオーバーライドします。
DispNameプロパティでは、コマンドの表示名(BOMエディタで表示されるメニュー名)を設定します。
Executeメソッドでは、ブラウザのJavaScript関数を呼び出します。
JavaScript関数呼び出しには HtmlPage.Window.Eval() を使います。
パラメータとして渡す文字列に JavaScriptのステートメントを記載します。
以下の例では、後編に向けてJavaScript関数にはBOMエディタを一意に識別するキー文字列(MyBase.Application.Bomkey)を渡しています。

コードは以下のようになります。

Imports CnBomEditorCore

Public Class CustomCommand
    Inherits Command

    Public outDir As String

    ''' <summary>
    ''' コマンドの表示名を返す
    ''' </summary>
    ''' <param name="param"></param>
    ''' <returns></returns>
    Public Overrides ReadOnly Property DispName(param As Object) As String
        Get
            Return "BOM帳票出力"
        End Get
    End Property

    ''' <summary>
    ''' コマンドを実行する。(メニューが選択されるとこのメソッドが実行される)
    ''' </summary>
    ''' <param name="parameter"></param>
    Public Overrides Sub Execute(parameter As Object)
        HtmlPage.Window.Eval(String.Format("openGetBomDataWin('{0}');", MyBase.Application.Bomkey))
    End Sub
End Class

HtmlPage.Window.Eval()で呼び出す JavaScript関数をExCmdBom.js に定義します。
今回は、単にアラート表示するだけの関数です。

function openGetBomDataWin(bomkey) {
    alert(`Order from BOM Editor (bomkey=${ bomkey })`);
}

作成した機能をBOMエディタのメニューとして追加するには、config.xml に設定を追記します。
config.xml を開いてcommandList 要素内にcommand要素を追加してコマンドを定義します。
また、追加したい親メニューの buttonMenu 要素内に、menu 要素を追加します。
今回は、BOMエディタの[ツール]コマンドのサブメニューに追加することにしますので、「ツールボタン」というコメントがあるbuttonMenu要素内に追記します。
command要素、menu要素の定義は以下です。

command要素

type
属性名 説明
name コマンドの名前。一意であることが必要。
クラス名。
params コマンドに渡すパラメータ。{a=>b}という形式で渡すとICommandのExecute関数にDictionaryクラスのオブジェクトを渡す。
invalidMode 使用不可となるモード。
dは表示モード(スナップショット含む)、rは読取専用、pは逆展開、sは製番展開、aは添付先表示、nは通常ユーザ(管理者、読取専用でない)、tはスナップショット表示、fは構成フィルター展開をあらわす。

menu要素

属性名 説明
command コマンド名を指定。
hiddenMode メニューを表示させないモード。
dは表示モード(スナップショット含む)、rは読取専用、pは逆展開、sは製番展開、aは添付先表示、nは通常ユーザ(管理者、読取専用でない)をあらわす。

記載例は以下のようになります。

  <commandList>
  ・・・
    <command name="OutputBOMCSV" type="bomcmdsample.CustomCommand" params="" invalidMode="p,a,f" />
  </commandList>

  <buttonMenuList>
  ・・・
    <buttonMenu command="" img="btnTool" title="Tool" subMenu="False" toolTip="mnuToolText">
      <!-- ツールボタン -->
   ・・・
      <menu command="OutputBOMCSV" hiddenMode="p,a"/>
    </buttonMenu>     
  </buttonMenuList>

第9回(1/3)まとめ

第9回(1/3)まとめ

<第9回(1/3)で学んだ内容>

  • BOMエディタへのカスタムメニューの追加方法
  • BOMエディタからJavaScript関数の呼び出し方法

<以降で学ぶ内容>

  • WEBアプリケーションへのカスタマイズプログラムの配置方法
  • BOM構成情報の収集方法
  • 帳票をクライアントへダウンロードさせる方法
第10回 カスタム開発DLLをクライアントへ配置する方法(2/3)

第9回~第11回は全3回にわたりFullWEB-PDMユーザ向けにBOMの処理をするプログラムを紹介します。
今回は、第9回に続きFullWEB-PDMユーザ向けにBOMの処理をするプログラムの処理フローの①「BOMエディタからブラウザのJavaScript関数をコールする」の後半について説明します。

処理フロー

処理フロー

処理の大まかな流れは以下のようになります。

画像-処理フロー

処理フロー

  1. ①BOMエディタからブラウザのJavaScript関数をコールする。
  2. ➁JavaScript関数はサーバへページを要求する。
  3. ③サーバはクライアントへページを返す。
  4. ④ページからサーバへCSVファイルを要求する。
  5. ⑤サーバはCSVファイルを返す。

※FullWEB-PDM 9.0以降のBOMエディタはWindowsアプリケーションとして動作します。

SDKで開発する内容

SDKで開発する内容

処理フロー①(後編)BOMエディタからブラウザのJavaScript関数をコールする。

BOMエディタのプログラムはメンテナンス情報の「クライアントプログラムインストールのお願い」からインストールされます。
今回開発する機能もインストールに含める必要があります。
次の[1]、[2]の設定をしてください。

[1]ApplicationInfo.xml にbomcmdsample.dll を追加する
 <application name=”bom1″>要素内に以下のようにmodule要素を追加します。

module要素

属性名 説明
srcurl FullWEBアプリケーションからの相対パスのURL。
version ピリオドで区切ったバージョン番号。
クライアントとサーバのApplicationInfo.xml が比較され、サーバのバージョン番号が大きい場合に更新される仕組み。

記載例は以下のようになります。

<application name="bom1" dir="bom" requireSeparate="true" required="9.7.56.0">
    <module srcurl="ClientBin/bom/fullweb/bomcmdsample.dll" version="1.0.0" />
  ・・・
  </application>
[2]ClientBin¥bom¥fullweb フォルダにbomcmdsample.dll を配置します。
 bomcmdsampleプロジェクトの[ビルド後イベント]に以下を追加することでビルド時に自動で配置されます。

copy /Y $(TargetPath) $(SolutionDir)cmdsample¥ClientBin¥bom¥fullweb¥$(TargetFileName)

動作確認

動作確認

FullWEBにログインしたら、メンテナンス情報の「クライアントプログラムインストールのお願い」でクライアントプログラムをインストールします。
クライアントプログラムをインストールしたら、BOMエディタを開きます。
[ツール] > [BOM帳票出力] メニューをクリックすると、ブラウザでアラートが表示されます。
これでBOMエディタからブラウザのJavaScript関数が呼ばれることが確認できました。

画像:[ツール] > [BOM帳票出力] メニュー” width=”211″ height=”156″></a></p>
<p><a href=画像:アラート

第10回(2/3)まとめ

第10回(2/3)まとめ

<第10回(2/3)で学んだ内容>

  • WEBアプリケーションへのカスタマイズプログラムの配置方法

<次回で学ぶ内容>

  • BOM構成情報の収集方法
  • 帳票をクライアントへダウンロードさせる方法
第11回 サーバーで作成したCSVファイル(BOM構成)をダウンロードする方法(3/3)

第9回~第11回は全3回にわたりFullWEB-PDMユーザ向けにBOMの処理をするプログラムを紹介します。
今回は、BOM帳票出力の後半部分(処理フローの②~⑤)について説明します。

処理フロー

処理フロー

処理の大まかな流れは以下のようになります。

画像-処理フロー

処理フロー

  1. ①BOMエディタからブラウザのJavaScript関数をコールする。
  2. ➁JavaScript関数はサーバへページを要求する。
  3. ③サーバはクライアントへページを返す。
  4. ④ページからサーバへCSVファイルを要求する。
  5. ⑤サーバはCSVファイルを返す。

※FullWEB-PDM 9.0以降のBOMエディタはWindowsアプリケーションとして動作します。

SDKで開発する内容

SDKで開発する内容

処理フロー②JavaScript関数はサーバへページを要求する。

まず、処理フローの②です。
openGetBomDataWin() の処理を以下の内容に変更します。

function openGetBomDataWin(bomkey) {
    window.open("GetBomData.aspx?bomkey=" + bomkey, "newwindow", "width=640,height=300");
}

処理フロー③サーバはクライアントへページを返す。

次に、処理フロー③で返すWEBページを作成します。
cmdsampleプロジェクトにGetBomData.aspx という名前のページを追加します。
サーバは、このページが要求されたらBOM帳票作成中であるということを表示したページをクライアントに返します。
BOMエディタから呼ばれたWEBページはBOMエディタの背面で起動しますので、
前面に表示させるために FullWeb.js のsetForegroundWin() 関数を呼び出してください。

処理フロー④ページからサーバへCSVファイルを要求する。

クライアントにページを表示したら、ただちにサーバにポストバックさせます(処理フローの④)。
aspx側のコードは以下のようになります。

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="GetBomData.aspx.vb" Inherits="cmdsample.GetBomData" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>BOM帳票出力</title>
    <script type="text/javascript" src="FullWeb.js?v=<asp:Literal runat='server' Text='<%$ AppSettings: FullWEBVersion %>'/>"></script>
    <script type="text/javascript">
        function init() {
            setForegroundWin();
            document.getElementById("form1").submit();
        }
    </script>
</head>
<body onload="init();">
    <form id="form1" runat="server">
        <div>
            BOM帳票生成中...
        </div>
    </form>
</body>
</html>

処理フロー⑤サーバはCSVファイルを返す。

最後に処理フローの⑤です。
GetBomData.aspx のコードビハインドでは、ポストバックを受け付けたらCSVファイルを作成してクライアントに送信します。

まずは、BOMエディタを一意に識別するキー文字列をもとにDatabaseクラスのGetBom() でBOMオブジェクトを取得します。

Dim bom As IBom = db.GetBom(bomkey)

次に、先頭のノードオブジェクトを取得します。

Dim bn As IBomNode = bom.CacheRootHead

先頭ノードから、BOMの行番号の小さいほうから順に辿っていきます。
以下のような再帰処理になります。

  1. カレントノードを処理
  2. 子ノードを処理
  3. 次の兄弟ノードを処理

再帰関数で処理を行うと、構成の規模によってはメモリ不足やタイムアウトが起きやすくなるため、スタックを使うことにします。
後入れ先出しの原則なので、以下の処理順になります。

  1. スタックからポップしてカレントノードを取得
  2. 次の兄弟ノードをスタックにプッシュ
  3. 子ノードをスタックにプッシュ

ノードを移動するAPIはIBomNode.GetRelatedNode() です。
引数パラメータに以下を指定します。

引数パラメータ 意味
Relationship.RelationshipChildHead 子ノードの先頭
Relationship.RelationshipNext 同一階層の次のノード

CSVファイルをサーバ上に作成したら、最後に以下のようにしてFullWEB標準機能でダウンロードさせます。
※サーバ上のCSVファイルはダウンロード後、標準機能によって削除されます。
※サーバ上のファイルは、ファイル名の後ろにダミー拡張子を付与する必要があります。

Session("DownloadLocalFolder") = <クライアントの取り出し先フォルダ>
Session("DownloadServerFile") = <サーバ上のCSVファイルのパス>
Response.Redirect("getstat.aspx?type=1&open=true")

コード全体は以下のようになります。

Imports cnWebCoreTest

Public Class GetBomData
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If IsPostBack Then
            Dim bomkey As String = ViewState("bomkey")
            ' クライアントの取り出し先
            Dim outDir As String = "C:¥davtmp"
            ' サーバ上に作成するCSVファイルのパス
            Dim csvPath As String = String.Format("C:¥DAV¥bomdata.csv.{0}", Guid.NewGuid.ToString)

            Dim db As cnWebCoreTest.Database = GetDB(Me)

            ' BOMオブジェクト
            Dim bom As IBom = db.GetBom(bomkey)

            ' 先頭ノード
            Dim bn As IBomNode = bom.CacheRootHead

            ' 移動先スタック
            Dim stackMoveTo As New Stack(Of KeyValuePair(Of Integer, IBomNode))
            ' 階層とノードのペアで移動先スタックに追加
            stackMoveTo.Push(New KeyValuePair(Of Integer, IBomNode)(1, bn))

            Using sw As New IO.StreamWriter(csvPath, False, Encoding.GetEncoding("shift_jis"))
                ' 階層を辿る
                Do While stackMoveTo.Count > 0
                    ' 階層とノードのペア
                    Dim levelAndBn As KeyValuePair(Of Integer, IBomNode) = stackMoveTo.Pop()
                    Dim level As Integer = levelAndBn.Key
                    Dim currentNode As IBomNode = levelAndBn.Value

                    ' CSVに書き込む
                    For i As Integer = 1 To level - 1
                        sw.Write(",")
                    Next
                    sw.WriteLine(String.Format("""{0}""", currentNode.PartNo))

                    ' 次の兄弟があれば、移動先としてスタックに追加
                    Dim nextNode As IBomNode = currentNode.GetRelatedNode(Relationship.RelationshipNext)
                    If nextNode IsNot Nothing Then
                        stackMoveTo.Push(New KeyValuePair(Of Integer, IBomNode)(level, nextNode))
                    End If

                    ' 子があれば、移動先としてスタックに追加
                    Dim childNode As IBomNode = currentNode.GetRelatedNode(Relationship.RelationshipChildHead)
                    If childNode IsNot Nothing Then
                        stackMoveTo.Push(New KeyValuePair(Of Integer, IBomNode)(level + 1, childNode))
                    End If
                Loop
            End Using

            ' FullWEB標準機能の取り出し
            Session("DownloadLocalFolder") = outDir
            Session("DownloadServerFile") = csvPath
            Response.Redirect("getstat.aspx?type=1&open=true")
        Else
            ' リクエストパラメータをViewStateに保持
            ViewState("bomkey") = Request.Params("bomkey")
        End If
    End Sub
End Class

動作確認

動作確認

FullWEBにログインして、任意の構成をBOMエディタで開きます。
[ツール] > [BOM帳票出力] メニューをクリックすると、「BOM帳票生成中」画面が表示されます。
しばらくすると取り出し画面に切り替わり、CSVファイルが開きます。

画像:「BOM帳票生成中」画面

第11回(3/3)まとめ

第11回(3/3)まとめ

<第11回(3/3)で学んだ内容>

  • BOM構成情報の収集方法
  • 帳票をクライアントへダウンロードさせる方法

以上、第9回より3回にわたってFullWEB-PDMユーザ向けにBOMの処理をするプログラムを紹介しました。

< SDKでできること~中級編~