Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

UMLモデリングを通して、一歩一歩作ってみる 「UMLモデリング練習帳アプリ」#2 Flask適用

はじめに

UMLモデリングを通して、一歩一歩作ってみる 「UMLモデリング練習帳アプリ」第二回目です。
今回は、前回作ったものをWebアプリとして実装すること考えてみたいと思います。

前回はこちら
(https://qiita.com/tomohiro_odan/items/48a96141a2a96916f3b2)

作るものを考える

では、ざっくり作るものを考えましょう
前回は、CUIベースでplantUMLを利用した作成UMLモデルと解答UMLモデルを比較するプログラムを作成しました。
「でもなぁ…サービスなんだから、UMLモデル作成も含めて、Webブラウザ上でやりたいよねー。」
そんな要望きたということにします。
…ということで、今回はWebブラウザ上でできる仕組みを考えていきます。

概念

今回も、UMLモデル学習者がUMLモデルを作成し、与えられた問題に対して、作り切れたかを確認することを考えます。(詳細は前回...)

conceptual model.png

ユースケース

それでは、そういった概念の中でどこをUMLモデリング練習帳アプリの範囲として開発していくか考えます。
ユースケースを考えてみると、「UC1.UMLモデルを作成する」、「UC2.UMLモデルを確認する」の二つを考えていました。
今回は、考えたユースケースは、ブラウザ上で実施したいので、「UC1.UMLモデルを作成する」を新たに含め、どちらも「UMLモデリング練習帳アプリの範囲」としました。

usecase.png

ユースケースのシナリオ(シーケンス)

続いて、ユースケースのシナリオ(シーケンス)を検討していきます。

UMLモデリング練習帳 シーケンス図.png

前回からの変更点は、「UMLモデルを作成する()」を「UMLモデリング練習帳アプリ」で行うことです。
また、それに伴い、ユースケースのシナリオとして、UMLモデリング練習帳アプリは、下記の二つの機能を追加で開発することになりそうです。

  • 今回追加で開発するUMLモデリング練習帳アプリ機能
    • UMLモデリング問題表示
    • UMLモデル記述

ユースケースと機能

先ほどの分析結果からユースケースとアプリの機能の対応は以下となりました。

SnapCrab_NoName_2020-3-1_23-25-13_No-00.png

作るものを決めよう

さて、作るべき機能が明確になったので作るものを決めていきましょう。
Pythonを開発言語としていますが、今回はWebブラウザ上のアプリを想定しています。
そのため、配置や実装に加えて、画面について考える必要がありそうです。
今回は、簡素で使いやすいflaskを利用することにしました。

画面

遷移

今回は単純な1つの画面(index.html)だけで実現することを考えることにしました。

screen_statemachine.png

イメージ

画面では、UMLモデル記述用の一つのテキストフィールドとモデル確認用のボタンを持つものを考えました。
結果を受けて、最初は何も表示されていませんが、解答結果表示を行う想定です。
(問題文表示を書き忘れてますが、上部に表示する想定です…)

index.html.png

配置

前回は、main.pyというファイルに全て作成していましたが、今回は、server.pyというファイルに機能を実装することにしました。
UMLモデリング学習者は、Google ChromeなどのウェブブラウザでそのURLにアクセスします。そのため、server.pyは、'localhost:8000'にアクセスできるようにします。
モデル確認ボタンを押すと、画面からUMLモデル記述が書かれたテキストエリアの内容を読み取り、解答UMLモデルスクリプトの記述と比較し、UMLモデルの画像ファイルを出力し画面上に表示します。
また、今回から構築が容易なCentos7上で動作を想定としました。

deployment.png
※→は、「参照や呼び出し元→参照や呼び出し先」

[フォルダ構成]
server.py(「UMLモデリング練習帳アプリ」サーバースクリプト)
|_static(画像、CSS、Javascriptなどの静的ファイル置き場)
|    |_plantuml.png(ダミーUMLモデル画像)
|    |_forminput.png(出力UMLモデル画像)
|
|_templates(HTMLのテンプレート置き場)
|    |_index.html(トップページhtml)
|
|_answers(解答UMLモデルスクリプト置き場)
|    |_usecase001a.pu(解答UMLモデルスクリプト)
|
|_run_plantuml.sh(UMLモデル画像の出力用shellファイル)
|_forminut.pu(出力UMLモデルスクリプト)

実装

それでは実装していきます。
今回もかなりべた書き…。

[server.py]
#! /usr/bin/env python
# -*- coding: utf-8 -*-

from flask import Flask, render_template, request
import subprocess
import sys
import difflib as diff

app = Flask(__name__)

# キャッシュをなくす(入れないと画像が古いままになる)
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0

# 最初のページ
@app.route('/', methods=['GET'])
def index():
    return render_template('index.html', \
      image_pass = "/static/plantumlimage.png" )

# UC2.UMLモデルを確認する
# モデル確認を実行する
@app.route('/', methods=['POST'])
def model_conform():

    # UMLモデル解析
    # plantumlファイル作成
    file = "forminput.pu"
    fileobj = open(file, "w", encoding = "utf_8")
    fileobj.write("@startuml{static/forminput.png}\n") 
    fileobj.write(str(request.form['modelingform'])+"\n")
    fileobj.write("@enduml\n")   
    fileobj.close()

    # 差分出力
    with open("./forminput.pu","r") as f:
        submit = f.readlines()

    with open("./answers/usecase0001a.pu","r") as f:
        answer = f.readlines()

    # 差分をunified形式で取得
    difflist = list(diff.unified_diff(submit, answer, fromfile=str("submit model"), tofile=str("answer model")))

    # 確認結果を表示
    if len(difflist) == 0 :
        result = "確認結果:OK"
    else :
        result = "確認結果:NG"

    # png画像出力
    subprocess.Popen(["pwd"], shell=True)
    completed_process = subprocess.run(["./run_plantuml.sh"], shell=True)

    # 解答結果表示   
    return render_template('index.html', \
      image_pass = "/static/forminput.png", \
      check_result = result, \
      diffs= difflist)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)
[index.html]
<!-- index.html -->
<!DOCTYPE html>
<html lang="ja">
  <head>
  </head>
  <body>

    <h1>UMLモデリング練習帳アプリfrom index.html</h1>

    <label for="title">問題①</label><br>
    <p>下記の文章からユースケース図を作成しなさい。</p>
    <p>UMLモデル学習者は、UMLモデルを作成する。</p>

    <form action="/" method="POST">
      <textarea name="modelingform" id="modelingform">{{ request.form['modelingform'] }}</textarea><br>
      <input type="submit" value="モデル確認"><br>
    </form>

    <p><img src={{ image_pass }} ></p>

    <p>{{ check_result }}</p>

    {% for diff in diffs %}
      <p>{{ diff }}</p>
    {% endfor %} 

  </body>
</html>
[usecase0001a.pu]
@startuml{static/forminput.png}
usecase UC1.UMLモデルを作成する
UMLモデリング学習者 --> (UC1.UMLモデルを作成する)
@enduml
[run_plantuml.sh]
前回と同様のため省略。
[forminput.pu]
初期は、何も記載されていないので省略。

動きをみてみよう

実装し終えたので、今度は動作を確認しましょう。

実行結果

plantuml,Graphvizは利用できるように環境変数を登録しておきます。
アプリを起動し、動作を確認してみましょう。

$ export FLASK_APP=server.py
$ flask run --host=0.0.0.0 --port=8000

出力結果

確認結果がOKの場合

画像が古いやつですが、イメージ的に下記のような内容になります。差がない場合は、「確認結果:OK」のみが表示されます。

image.png

確認結果がNGの場合

「確認結果:NG」と提出したUMLモデルスクリプトと解答UMLモデルスクリプトとの差分が表示されます。
ちなみに、前回は補足できていませんでしたが、差分はunified形式で行の差分が出力されます。

image.png

以上で、確認結果が出力できることを確認できました。

次回に向けて

今回はwebブラウザで実現できるようにしてみました。なんとなくアプリらしくなってきました。
しかし…

「これだと1問しかできないじゃん。出題者が問題を登録したりできるようにしたいよ。」

と言われてしましました。

ということで次回は、UMLモデリング出題者というアクターが新たに登場し、問題を登録・削除・編集できるようにすることに取り組んでいきます。

参考文献

以上。

mamezou
先進の工学的手法と独自のスタンス。お客様とともにビジネスを活かすITを追求します。
http://www.mamezou.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away