ご注意ください

  • 当ブログのコメントやトラックバックに、アカウントハックサイトや、そのようなサイトへリダイレクト(転送)される可能性が高いサイトへのリンクが時々貼られているようです。
    そのようなサイトへのリンクが貼られたコメント・トラックバックは、見つけ次第削除・禁止ワード登録していますが、今後も危険なサイトへのリンクが貼られる可能性がありますので、安易にリンク先へ飛ばないよう充分ご注意ください。

オンラインゲーム関連

著作権表示

  • 当ブログに記載されている
    会社名・製品名・システム名などは、
    各社の登録商標、もしくは商標です。

    当ブログ上の文章・写真・画像の
    無断転載、無断転用、直リンクなどは
    行わないでください。

    (C) 1998-2016 Vertex.
    (C) 2002-2016 SQUARE ENIX CO., LTD.
    (C) CAPCOM CO., LTD. 2007, 2016

    All Rights Reserved.
無料ブログはココログ

[Java] ICE Facesでポップアップ画面

ICE Facesでポップアップ画面を出すには、JavaScriptでwindow.open()してしまわずに、ICE Facesのポップアップ機能を使う方がいいらしい。

確かに、ポップアップとは言えブラウザのウィンドウが新しく開くわけでもないし、ポップアップ元画面が操作できなくなることで、いろいろ処理を簡略できるかもしれないし。

とりあえず、備忘録メモメモということで、JSP側はこんな感じ。

<ice:panelGroup rendered="#{TestPage.isPopupDisplay}">
  <ice:panelPopup draggable="false" modal="true" autoCentre="false"
                  visible="#{TestPage.isPopupDisplay}"
                  style="background-color: white;
                         background-image:url('./image/wall.jpg');
                         background-repeat: repeat-x;">

    <f:facet name="header">
      <ice:panelGrid>
        <ice:panelGroup>
          <ice:outputText value="ポップアップテスト"/>
        </ice:panelGroup>
      </ice:panelGrid>
    </f:facet>

    <f:facet name="body">
      <ice:panelGroup styleClass="popupBody">
        ~HTMLのBODY部分~
      </ice:panelGroup>
    </f:facet>
  </ice:panelPopup>
</ice:panelGroup>

そしたら後は、ポップアップ画面を呼び出すアクションメソッドが走ったときにManagedBean側でisPopupDisplayをtrueにしてあげれば、ICE Facesのポップアップ画面が出る、という寸法。

元画面が透過グレーアウトされて、その上にポップアップのウィンドウが出てくる。

このポップアップを消すには、閉じるボタンを実装してそのボタンのアクションメソッドが走ったときにisPopupDisplayをfalseにしてあげるだけ。

JavaScriptで開くポップアップよりも管理が楽な反面、ポップアップ元画面とポップアップ画面を比較しながら作業をしたい用途ではとても不便かもしれない…。

[Java] JasperReportで二次元の帳票出力

PDF出力をするときに、何ページにも渡る帳票を出力するのは簡単ですが、二次元方向に伸びるページを出力する方法がなかなか思いつかず、苦労しました。

具体的には、印刷したページを並べてみると以下のような配置になるような帳票の出力です。

+-----+-----+-----+
| A-1 | B-1 | C-1 |
+-----+-----+-----+
| A-2 | B-2 | C-2 |
+-----+-----+-----+
| A-3 | B-3 | C-3 |
+-----+-----+-----+

いろいろ悩んで試行錯誤した結果、以下のような処理で出力することができた!…が、どうにもやり方が回りくどいような。無駄が多い気もするし。でも、とりあえず動いた時点のソースということでメモメモ。

これからデバッグして、問題ないことを確認してから、もっとスマートな方法がないかチャレンジしてみる予定。

FacesContext context = FacesContext.getCurrentInstance();
ExternalContext excon = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) excon.getRequest();
HttpServletResponse response = (HttpServletResponse) excon.getResponse();

// A列用のリスト
List<Map> listA = new ArrayList<Map>();
// B列用のリスト
List<Map> listB = new ArrayList<Map>();
// C列用のリスト
List<Map> listC = new ArrayList<Map>();
// 各列のリストを配列に入れる
List[] list = {listA, listB, listC};

// 上記リストに、実際にはデータが入っているものとして…

int columnNum = list.length;

// InputStream と JRDataSource は配列の数だけ用意していないと
// PDF出力が0byteになってしまうので、ここで用意する。
// fname はコンパイル済みのテンプレートファイルパス
InputStream[] stream = new InputStream[columnNum];
JRDataSource[] ds = new JRDataSource[columnNum];
for (int i = 0; i < columnNum; i++) {
    stream[i] = excon.getResourceAsStream(fname[i]);
    ds[i] = new JRBeanArrayDataSource(list[i].toArray());
}

// ここは特に普段と変更なし
JRExporter exporter = new JRPdfExporter();
exporter.setParameter(
         JRExporterParameter.OUTPUT_STREAM,
         response.getOutputStream());

// いったんA列のデータを変換しておく
JasperPrint jasperPrint = null;
jasperPrint = JasperFillManager.fillReport(
              stream[0], new HashMap(), ds[0]);

// B列以降のデータを変換し、変換したA列に1ページ分ずつ追加していく
for (int i = 1; i < columnNum; i++) {
    JasperPrint jp = JasperFillManager.fillReport(
                     stream[i], new HashMap(), ds[i]);
    for (int j = 0; j < jp.getPages().size(); j++) {
        jasperPrint.addPage((JRPrintPage) jp.getPages().get(j));
    }
}

// PDF出力する
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
request.getSession().setAttribute(
        ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE,
        jasperPrint);
exporter.exportReport();

// 後処理
for (int i = 0; i < columnNum; i++) {
    stream[i].close();
}

JRExporterParameter に JASPER_PRINT_LIST というパラメータがあるんだけど、これを使えばもっとスマートな処理になるかも?ただし、このパラメータの使い方がよくわからないので、今の時点では何とも言えず…。

[Java] ICEfacesでファイルのダウンロード

どんなファイルでも必ずダウンロードダイアログを表示させることができたのでメモメモ。Firefox3.5でしか動作確認はしていないけど…。

まずダウンロード処理用にクラスをひとつ作る。

class OutputStream implements Resource {
    private String resourceName = null;
    private Date lastModified = null;
    private InputStream inputStream = null;

    public OutputStream(
            final ExternalContext argExcon,
            final String argResourceName) {
        this.resourceName = argResourceName;
        this.inputStream = argExcon.getResourceAsStream(argResourceName);
        this.lastModified = new Date();
    }

    @Override
    public InputStream open() throws IOException {
        return this.inputStream;
    }

    @Override
    public String calculateDigest() {
        return this.resourceName;
    }

    @Override
    public Date lastModified() {
        return this.lastModified;
    }

    @Override
    public void withOptions(final Options arg) throws IOException {
    }
}

次に、マネージドBeanに処理を追加。

private Resource csvResource = null;

public final void csvOutputAction() {
    FacesContext context = FacesContext.getCurrentInstance();
    ExternalContext excon = context.getExternalContext();

    csvResourceForEvent =
            new OutputStream(excon, "/page/report/sample.csv");
}

public final Resource getCsvResource() {
    return this.csvResource;
}

"/page/report/sample.csv" としているところは、コンテキストルートを基準として、ダウンロードするファイルの場所を指定。動的に作成したファイルでもOK。

最後に、JSPにボタンを配置。

<ice:outputResource
     fileName="sample.csv"
     resource="#{page$report$OutputCsv.csvResource}"
     type="button"
     label="ダウンロード"/>

動的に作成したファイルの場合は、fileNameも動的に変える必要あり。例えば「#{page$report$OutputCsv.downloadFName}」など。

これでブラウザのダウンロードダイアログが必ず出るようになったので、プレーンテキストだろうとバイナリファイルだろうと、そのまま開くかダウンロードするかをユーザーに選択してもらえるようになった。

一応できたことはできたんだけど、イマイチまだ理解に乏しいのが難点…。

[Java] ICEfacesでCSV出力

ICEfacesを使うと、CSVを出力するのにストリームが使えない…?

getWrite()は既に呼ばれています、というExceptionが出てしまう。

ゆっくり調べている時間もなく、とにかくCSVで出せればいいから、とのことだったので、一旦サーバ上にCSVファイルとして作成し、それに動的にリンクを貼ってダウンロードする方法にしてみた。

何となく動いたので、とりあえず動くものをメモメモ。まだファイル名が動的ではないけど、その辺はすぐに改修できるので(笑)



まずはJSP側でCSV作成ボタンを用意。せっかくICEfacesを使っているので、ボタンをクリックしたら「しばらくお待ちください」と表示させ、CSVファイルが準備できたらダウンロードを促すメッセージとリンクを表示するようにしてみる。

<ice:outputConnectionStatus
     activeLabel="CSVファイルを準備しています。しばらくお待ちください。"
     rendered="#{!page$Test.isDownloadReady}"/>
<ice:outputText value="CSVファイルの準備ができました。"
     rendered="#{page$Test.isDownloadReady}"/>
<br />
<ice:outputText
     value="下のリンクを右クリックしてファイルに保存してください。"
     rendered="#{page$Test.isDownloadReady}"/>
<br />
<br />
<ice:commandButton id="csvout1"
     action="#{page$Test.btnCsvOut}"
     value="CSVファイル出力"
     rendered="#{!page$Test.isDownloadReady}"/>
<ice:outputLink value="#{page$Test.downloadPath}"
     rendered="#{page$Test.isDownloadReady}">
<ice:outputText value="CSVファイルをダウンロードする"
     rendered="#{page$Test.isDownloadReady}"/>
</ice:outputLink><br />

ManagedBean側は、以下のメソッドを用意してみる。

private static final String LOCAL_PATH =
                "../applications/j2ee-apps/Test-ear/Test-war_war";
private static final String FILE_NAME = "/page/csv_test.csv";

private boolean isDownloadReady = false;
private String downloadPath = "";

public boolean getIsDownloadReady() {
    return this.isDownloadReady;
}

public String getDownloadPath() {
    return this.downloadPath;
}

public void btnCsvOut() {
    FacesContext fcon = FacesContext.getCurrentInstance();
    ExternalContext excon = fcon.getExternalContext();
    try {
        List<Map> mapList = new ArrayList<Map>();
        Map m = new HashMap();
        m.put("AAA", "あいうえお");
        m.put("BBB", "かきくけこ");
        m.put("CCC", "さしすせそ");
        mapList.add(m);

        InputStream stream = excon.getResourceAsStream(
                                   "/WEB-INF/reports/Test.jasper");
        JRDataSource ds = new JRBeanArrayDataSource(mapList.toArray());
        JasperPrint jasperPrint =
                 JasperFillManager.fillReport(stream, null, ds);

        JRExporter exporter = new JRCsvExporter();
        exporter.setParameter(
                 JRExporterParameter.CHARACTER_ENCODING,
                 "Windows-31J");
        exporter.setParameter(
                 JRExporterParameter.JASPER_PRINT,
                 jasperPrint);
        exporter.setParameter(
                 JRExporterParameter.OUTPUT_FILE_NAME,
                 LOCAL_PATH + FILE_NAME);
        exporter.exportReport();
    } catch (Exception e) {
        throw new FacesException(e);
    }
    this.downloadPath = excon.getRequestContextPath() + FILE_NAME;
    isDownloadReady = true;
}

お粗末だけど、とりあえず機能としてはこれでよさそう。

ちなみに、LOCAL_PATH が変な指定になっているけど、これはなぜかカレントフォルダが glassfish\domain\domain1\config になってしまっていたので、そこからの相対パスでデプロイされたフォルダの中のCSVファイル仮置き場を指定しています。

なんでconfigフォルダなんだろう…そこまで調べている時間もないので、そういうものと割り切って、とりあえず汎用性のない作りで(笑)

時間が無いと言いつつ、これを書いてるのは…そう、いつかまたこういった処理を使うことがあるかもしれないから。たぶんきっと…。

[Java] PermGen spaceの恐怖

だいぶ前にPermGen spaceの対処法を記事にしていましたが、それから年月が経ち、今やメモリ4GB(実質3.5GB弱の認識)を積んだマシンになり、MaxPermSizeをもっと大きめに取るようにしてしますが、ここ最近は、またPermGen spaceが時々出てきます。

頻繁にガベージコレクションを行うことである程度抑えることはできるようですが、やはりコーディング→動作確認→コーディングの繰り返しをしていると、発生頻度が高い。

これが出てしまったらglassfishを再起動するだけでエラーは消えるので、特に困ることは無い。けど、再起動に時間がかかるのが難点。

そして、ついに今日、PermGen spaceが反撃してきました(笑)

JasperReportを使ってCSVファイルを作成する処理を作っていたときのこと。いつものように動作確認をしながらコーディングしていたら、動作途中でPermGen spaceが発生。しかもいつもとちがって、システムログに滝のようにログを吐いている。全部PermGen space。

サーバを止めようとしても、停止処理すらPermGen spaceで止まってしまう勢い。

しょうがないのでプロセスをkillして、再度glassfishを立ち上げようとしたら、ポートを開放してくれなかったらしく、起動エラー。結局PCを再起動するハメに。

再起動後は何事も無かったかのように正常動作していますが…いきなり大量のログを吐き出すなんて、一体何だったのだろう…。

glassfishでSSL証明書の発行

glassfishでSSLを使う必要があったので、いろいろ調べた結果をメモ代わりに書き残し。

とりあえず開発中のテストに使うだけなので、自己署名したものを証明書として使ってみたけど、やっぱりブラウザにはかなり怒られるなぁ(笑)

以下、WindowsXP SP3 + glassfish v2.1 + JDK 1.6.0_14 の組み合わせでやってみました。全てDOSプロンプト上で。

コマンドは複数行に分けて書いていますが、実際は一行で入力すること。



1.証明書を置く場所へ移動する
例:cd "\Program Files\glassfish-v2.1\domains\domain1\config"

2.デフォルトで用意されている証明書を削除する
keytool -delete
        -alias s1as
        -keystore keystore.jks
        -storepass changeit
※パスワードをデフォルトから変更している人は、changeit を変更したパスワードに置き換えて実行(以下同様に)

3.証明書を作成
keytool -genkeypair
        -keyalg RSA
        -keystore keystore.jks
        -validity 365
        -alias s1as
        -storepass changeit

姓名を入力してください。
  [Unknown]:  Test User
組織単位名を入力してください。
  [Unknown]:  Development Div.
組織名を入力してください。
  [Unknown]:  Company Co., LTD.
都市名または地域名を入力してください。
  [Unknown]:  Tokyo
州名または地方名を入力してください。
  [Unknown]:  Minato-ku
この単位に該当する 2 文字の国番号を入力してください。
  [Unknown]:  JP
CN=Test User, OU=Development Div., O="Company Co., LTD.", L=Tokyo, ST=Minato-ku, C=JP でよろしいですか?[no]:  yes

<s1as> の鍵パスワードを入力してください。
   (キーストアのパスワードと同じ場合は RETURN を押してください):

4.証明書に署名をする
keytool -certreq
        -alias s1as
        -file s1as.csr
        -keystore keystore.jks
        -storepass changeit

5.証明書をファイルにエクスポートする
keytool -export
        -alias s1as
        -storepass changeit
        -file server.cer
        -keystore keystore.jks
証明書がファイル <server.cer> に保存されました。

6.glassfishを再起動する



以上の手順で証明書を作り、https://SERVER_NAME:8181/ でアクセスしたら、ブラウザからいろいろとお叱りを受けつつも、SSLで暗号化通信することができました。

OpenSSLとかを入れて、面倒なセットアップをしないといけないのかと思っていたら、意外にも簡単にできてしまってびっくりでした。

参考サイト:Sun Developer Connection

[Java] JasperReportでPDF出力してみたが…

うーん、これって仕様なのかな。

jrxml の detail タグの中の band タグに、textFieldの途中で改ページしないように isSplitAllowed="false" と入れてみた。

しかし、Stretch With Overflow(横幅が足りない場合は自動的に複数行表示にしてくれるパラメータ)にチェックを入れている textField では、自動で複数行になってしまった部分の改ページ禁止がうまく動かない。

ダメ元で、isSplitAllowed="true" にしてみた。今度は textField の途中で改ページされないで、うまい具合に出力できた。

isSplitAllowed って「分割されるのを許すか?」って意味で、true = 許す、false = 許さない、という意味だと思っていたけれど…どうやら違ったらしい…?

[Java] JasperReportでHTMLヘッダフッタ出力

あまりメジャーじゃないのか、それとも情報が出回っていないのか、探してもなかなか知りたい情報に出会えずに苦戦している JasperReport+iReport での帳票作成。PDFでの出力は jrxml の記述だけである程度できたけど、HTML として表示するにはいろいろパラメータを渡す必要があるようで、なかなか思い通りに表示されなくて悩むこと数時間。とりあえず HTML 出力時のヘッダとフッタの指定方法を備忘録がてらメモメモ。

◆HTMLのヘッダ作成例
exporter = new JRHtmlExporter();
exporter.setParameter(JRHtmlExporterParameter.HTML_HEADER,
          "<html><head>\n"
        + "<title>Sample Page</title>\n"
        + "</head>\n"
        + "<body text='#000000' bgcolor='#ffffff'>\n"
        + "<div align='center'>\n"
        );

◆HTMLのフッタ作成例
exporter.setParameter(JRHtmlExporterParameter.HTML_FOOTER, "</div></body></html>");

上記ヘッダやフッタを指定しなければ、デフォルトのヘッダとフッタが付与される模様。画面表示と印刷時で表示される項目を変えたい場合や、何かしら JavaScript を使いたい場合などには、自分でヘッダを作成して、印刷用の css をロードする記述なり、JavaScript を記述するなりすればよい。

たったこれだけの情報でも、使い方がわからずに苦労します…が、こんな手探りもなかなか楽しいかも。

さすがに JasperReport の参考書?は100ドルもするらしいので、なかなか手が出せないしね…。

つーか、素直に PDF を使ってくれよ。HTML だけで PDF 並みの表示+印刷機能を提供なんて無茶を言うにもほどがある(´Д`)

[Java] iReportを使って帳票出力

正直なところ、まだよくわかっていないかも。とりあえず日本語での出力に苦労して、やっと出せるようになったので、備忘録ということで動いたソースをメモメモ。

private static final String   PREFIX = "/WEB-INF/reports/";
private static final String   SUFFIX = ".jasper";
private static final String[] TYPES  = { "text/html", "application/pdf" };
private static final String   ENCODE = "Windows-31J";

public void jasperReport(String name, String type, ResultSet data, Map map)
       throws UnsupportedEncodingException, SQLException, JRException, IOException {

    // コンテントタイプが有効かどうかチェック
    boolean isFound = false;
    for (int i = 0; i < TYPES.length; i++) {
        if (TYPES[i].equals(type)) {
            isFound = true;
            break;
        }
    }
    // 有効なコンテントタイプでない場合は例外をスローする
    if (!isFound) {
        throw new IllegalArgumentException("出力形式異常 [" + type + "]");
    }

    // 文字コードを指定する(ここで指定しないとLatin1になってしまう?)
    ExternalContext econtext = getExternalContext();
    econtext.setResponseCharacterEncoding(ENCODE);
    econtext.setRequestCharacterEncoding(ENCODE);

    // コンパイル後のレポート定義ファイルをチェック
    InputStream stream = econtext.getResourceAsStream(PREFIX + name + SUFFIX);
    if (stream == null) {
        throw new IllegalArgumentException("レポート定義異常 [" + name + "]");
    }

    // カーソルを出力データの先頭に移動
    data.beforeFirst();

    // 出力するデータを読み込む
    JRResultSetDataSource ds = new JRResultSetDataSource(data);
    JasperPrint jasperPrint = null;
    try {
        jasperPrint = JasperFillManager.fillReport(stream, map, ds);
    } catch (JRException e) {
        throw e;
    } finally {
        stream.close();
    }

    // データを整形して出力
    JRExporter exporter = null;
    HttpServletResponse response = (HttpServletResponse) econtext.getResponse();
    response.setContentType(type);

    // ------ PDF出力の場合
    if (TYPES[1].equals(type)) {
        exporter = new JRPdfExporter();
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM,
                              response.getOutputStream());

        // ------ ファイル出力にする場合は以下の処理に置き換える ここから
//            JasperExportManager.exportReportToPdfFile(jasperPrint, "JasperSample1.pdf");
        // ------ ファイル出力にする場合は以上の処理に置き換える ここまで
    }
    // ------ HTML出力の場合
    else if (TYPES[0].equals(type)) {
        FacesContext fcontext = FacesContext.getCurrentInstance();

        exporter = new JRHtmlExporter();
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_WRITER,
                              response.getWriter());
        exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, ENCODE);

        // ここでの文字コードセットは意味ないかも?
        response.setContentType(TYPES[0] + "; charset=" + ENCODE);

        HttpServletRequest request =
                (HttpServletRequest) fcontext.getExternalContext().getRequest();
        request.getSession().setAttribute(
                ImageServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE,
                jasperPrint);

        fcontext.responseComplete();
    }

    // 出力の実行
    if (exporter != null) { exporter.exportReport(); }
}

これを、例えばボタンが押されたときに呼べば、HTML形式もしくはPDF形式でDBにあるデータを読み込んで表示します。日本語も化けずにちゃんと表示できました。

パラメータに渡す値や例外処理は、上で何とかしてください(笑)

ほとんどが、「これ参考にしてね」と渡されたサンプルプログラムそのままなので、何か変なところがあってもキニシナイ(´Д`)

[Shell] 標準出力と標準エラー出力

調べればたくさんのサイトが検索結果に出てくると思うけど、とりあえず備忘録ということで、標準エラー出力をファイルに出力する方法。

標準エラー出力だけをファイルに出力させたい場合は、

$ test.sh 2> logfile.log

でよい。標準出力も出したい場合は、

$ touch logfile.log
$ test.sh 1>> logfile.log 2>> logfile.log

でよさそう。どちらが先に書き出されるかわからないので、前もってログファイルを作成しておいたほうがいいかも。

画面とファイルの両方に出力する場合は、標準出力も混ざるけど

$ test.sh 2>&1 | tee logfile.log

とすればよい。

じゃあ実際に動かしてみるとどうなるかというと…。

まず標準出力と標準エラー出力を出すためのプログラムを作って確認。

$ cat HelloWorld.java
import java.util.List;
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello World");
    List<String> list = null;
    System.out.println(list.get(0));
  }
}

コンパイルして

$ javac HelloWorld.java

実行。

$ java HelloWorld 2> logfile.log
Hello World
$ cat logfile.log
Exception in thread "main" java.lang.NullPointerException
        at HelloWorld.main(HelloWorld.java:6)

tee を使って画面とファイル出力。

$ java HelloWorld 2>&1 | tee logfile.log
Hello World
Exception in thread "main" java.lang.NullPointerException
        at HelloWorld.main(HelloWorld.java:6)
$ cat logfile.log
Hello World
Exception in thread "main" java.lang.NullPointerException
        at HelloWorld.main(HelloWorld.java:6)

tee を使って標準エラーだけをファイル出力する方法は、ちょっと調べてみたけど面倒そうなので省略…。
フォト
2017年5月
  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      

最近のトラックバック