ラベル Java の投稿を表示しています。 すべての投稿を表示
ラベル Java の投稿を表示しています。 すべての投稿を表示

2015年9月12日土曜日

Glassfish+Derby+JDBCレルムについて(ソースコード解説)

JDBCレルムについてソースコード内容について概要を記述。
下記GitHubのコードの解説である。
https://github.com/Fufuhu/SimpleAuthentication

NetBeans上でMavenのWebプロジェクトで作成している。


Servletとjspだけで構成されたシンプルな構成になっている。
(Webページディレクトリ直下のindex.jspは無視してもらって構いません。)

■画面遷移について

以下のような形で画面遷移を構成しています。


index.jspがログインページLoginServletにてJDBCレルム認証を実行後、
認証を通過すればtoppage.jsp, 失敗すればerror.jspに遷移する。


■index.jsp
ログインページ。ユーザ名とパスワードの入力したのちに、
ログインボタンクリックで、LoginServletを呼び出し、JDBCレルム
認証を実行することができる。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>ログイン</title>
    </head>
    <body>
        ログイン情報<br/>
        <form method="POST" action="../LoginServlet">
            ユーザ名:<input type="text" name="username"/> <br/>
            パスワード:<input type="password" name="password"/><br/>
            <input type="submit" method="GET" value="ログイン"/>
        </form>
    </body>
</html>



■LoginServlet(一部抜粋)
42行目のrequest.login(username, password);でJDBCレルム認証を実行している。
index.jspで入力されたユーザ名、パスワードの内容に応じてログイン可否を判断している。
loginメソッドで認証ができれば、そのままtoppage.jspへの遷移を続行。(ユーザ認証情報がセッションに含まれるようになる。)できなければServletExceptionがスローされるので、error.jspに遷移する。

package authentication;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author USER
 */
@WebServlet(name = "LoginServlet", urlPatterns = {"/LoginServlet"})
public class LoginServlet extends HttpServlet {

   
    private final String topPage = "/login/toppage.jsp";
    private final String errorPage = "/login/error.jsp";
    /**
     *
     * @param request servlet request
     * @param response servlet response
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        response.setContentType("text/html;charset=UTF-8");
            String username = request.getParameter("username");
            String password = request.getParameter("password");
           
            ServletContext sc = getServletContext();
           
            try {
                //JDBCレルム認証部分(認証に失敗すると例外をスロー)
                request.login(username, password);
            } catch (ServletException ex) {
                Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
                try {
                    sc.getRequestDispatcher(errorPage).forward(request, response);
                } catch (ServletException ex1) {
                    Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex1);
                }
            }
            try {
                sc.getRequestDispatcher(topPage).forward(request, response);
            } catch (ServletException ex) {
                Logger.getLogger(LoginServlet.class.getName()).log(Level.SEVERE, null, ex);
            }
    } 
    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}

■toppage.jsp
仮のトップページ。ウェルカムメッセージと、
ログアウトのための処理呼び出しが可能なだけ。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>トップページ</title>
    </head>
    <body>
        <h1>ログインに成功しました。</h1><br/>
        <form action="./LogoutServlet">
            ${param["username"]}様、いらっしゃいませ。<br/>
            <input type="submit" value="ログアウト"/>
        </form>
    </body>
</html>

■LogoutServlet(一部抜粋)
request.getSession().invalidate();でセッション情報を明示的に破棄するとともに
request.logout();でログアウト処理を実行している。

package authentication;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author USER
 */
@WebServlet(name = "LogoutServlet", urlPatterns = {"/LogoutServlet"})
public class LogoutServlet extends HttpServlet {

    private final String indexPage = "./login/index.jsp";
    private final String errorPage = "./login/error.jsp";
    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
     * methods.
     *
     * @param request servlet request
     * @param response servlet response
     */
    /**
     * @param request servlet request
     * @param response servlet response
     * @throws java.io.IOException
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        //セッションを明示的に破棄する。
        request.getSession().invalidate();
        ServletContext sc = getServletContext();
       
        try {
           //認証からのログアウトを行う処理。
            request.logout();
        } catch (ServletException ex) {
            Logger.getLogger(LogoutServlet.class.getName()).log(Level.SEVERE, null, ex);
            try {
                sc.getRequestDispatcher(errorPage).forward(request, response);
            } catch (ServletException ex1) {
                Logger.getLogger(LogoutServlet.class.getName()).log(Level.SEVERE, null, ex1);
            }
        }
        response.sendRedirect(indexPage);      
    }
    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }
}


■error.jsp
ログイン処理時にrequest.login()に失敗するとこちらのページに遷移する。

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>ログイン失敗</h1><br/>
        <a href="./index.jsp">ログインページへ</a>
    </body>
</html>


次の記事では、コードではなく、アクセス制御(web.xml)の記入について説明します。
※生のxmlを書くわけではなく、NetBeansにおんぶにだっこで設定します。

Glassfish+Derby+JDBCレルムについて(Glassfishの設定)

Glassfish側の設定。

以下の項目を作成していきます。

  1. コネクションプール
  2. JNDIリソース
1.についてはもともとあるものを流用してもよいのですが、
個人的に気持ち悪さを感じてしまうのであえて新しく作成することにします。

1. コネクションプールの作成
Glassfishの管理画面にログインします。
ローカルで実行している場合は、
http://localhost:4848にアクセスしてもらえれば管理画面に
アクセスできるはずです。
初期状態では特にパスワードなどは設定していないので
そのまま管理画面にアクセスできるはずです。

アクセス後は、管理画面の「JDBC」→「JDBC Connection Pools」と
選択をしていきます。作成済みのコネクションプールの一覧が
表形式で表示されるので、「New」ボタンをクリックしたのち、下記画面の内容を入力します。


これで以前の記事で作成したデータベースに対する
JDBCのコネクションプールは作成完了です。

一枚目の画像の「Ping」ボタンをクリックして

コネクションプールの名前にAuthenticationPoolと名付けたことを覚えておいて
ください。

2. JNDIリソースの作成

次はJNDIリソースを作成します。
管理画面の「JDBC」→「JDBC Resources」を選択します。
作成済みのJDBCプールのJNDIリソースの一覧が表示されるので、
「New」ボタンをクリックしたのち、下記の内容を入力します。


3. JDBCレルム設定の作成

「Conifgurations」→「Conifgurations」→「Security」→「Realms」を選択したのち、
「New」ボタンをクリックします。

下記画像の設定を投入します。


設定内容は以前の記事にて作成したDerbyのデータベースの設定に
準拠しています。

これでGlassfish側のJDBCレルムの設定は完了です。




2015年9月10日木曜日

Glassfish+Derby+JDBCレルムについて(Derby(JavaDB)の設定)

JDBCレルム認証を実現するためにはまずデータベースの作成が必要です。
ここでは、NetBeansをつかってローカルのJavaDB上にJDBCレルム認証に利用するデータベースを構築する方法を説明します。


NetBeansのサービスタグを選択、JavaDBを右クリックしてデータベースの
作成を選択します。


ここでは、データベース名をAuthenticationSampleとして作成しています。
ユーザ名はAPP, パスワードもユーザ名と同じにしています。
(当然ですが、本番環境での利用の際にはユーザ名、パスワードともに配慮が必要です。)

これで、JavaDB上にAuthenticationSampleデータベースが作成されました。



次は新規の接続先として先ほど作成したAuthenticationSampleに接続します。
下記のような設定を行ってください。


これで、接続先の設定が完了しました。
次にテーブルの作成に移ります。

テーブルの作成には先ほど作成した接続先を右クリックし、
コマンドの実行を選択します。新しい画面が開くので、下記のSQLを入力し、
usertableとgrouptableを作成します。


create table usertable (
username varchar(20) NOT NULL CONSTRAINT USER_PK PRIMARY KEY ,
mailaddress varchar(100) NOT NULL,
password varchar(128) NOT NULL
);


create table grouptable(
username varchar(20) NOT NULL,
groupid varchar(20) NOT NULL,
CONSTRAINT GROUP_PK PRIMARY KEY(username, groupid),
CONSTRAINT USER_FK FOREIGN KEY(username)
REFERENCES usertable(username) ON DELETE
);

これで、JDBCレルム認証用のデータベースが作成できました。
次以降の設定で必要となる内容は以下の通りです。

usertableのパスワード列には生パスワードではなく、SHA-256でハッシュ化した
値を入れないといけません。こちらについてはサンプルコードを
寺田佳央さんが提供してくれています。
https://github.com/yoshioterada/JDBC-Realm-Sample/tree/master/src/main/java/jp/co/oracle/jdbcrealm/SHADigestUtil


以下の情報は次回以降に利用するため、記載しておきます。

JDBC URL: jdbc:derby//localhost:1527/AuthenticationSample
データベース名: AuthenticationSample
データベースのユーザ名/パスワード: APP/APP
ユーザテーブル: usertable
ユーザ名: username
パスワード: password

グループテーブル: grouptable
ユーザ名: username
グループ名: groupid




Glassfish + Derby + JDBCレルムについて

JDBCレルム認証を説明した可能な限りシンプルなコードを作成しました。


https://github.com/Fufuhu/SimpleAuthentication


具体的な説明は後日。

2015年9月7日月曜日

Glassfish + Derby + JDBCレルムについて(導入編)

私の妄想が7割くらいなので、正しい理解なのかは保証しません。
図にしないと理解しづらい低能なので、JDBC、JNDI、JDBCレルムの依存関係はこんな感じ。
(コネクションプールを利用する場合)



  • JDBC Connection Pool ... どこにあるDBに接続するか
  • JDBC Resource(JNDI) ... JNDIとしてJDBC Connection Poolを取り扱えるようにする。
  • JDBCレルム ... JNDIからJDBC Connection Poolへ接続し、特定のテーブルからユーザ名・パスワードとロール名を読み取る。
JDBCレルムでパスワードを取り扱う際には、生パスワードをDBに書き込むことができないのでうっかりさんも安心。寺田さんの記事の例ではSHA-256でハッシュ化してあります。

一応私の方でも実装編を解説しようかと思います。以下の寺田さんの例だとJSFを使っているので、前提知識多めな感じになってしまっているので...私の方ではもっとシンプルにServletとJSPを使って実装しようかと思います。

2015年9月5日土曜日

JSFのfaceletsきめぇな方へ

JSFってエンジニアにはうれしいけど、デザイナにとってはつらいよね。

漢らしい業務臭い画面ってそれはそれで味があっていいけれども、
かわいらしいデザインって欲しいじゃない?

ってことでHTMLっぽくJSFを記述する方法をちょいと調べてみた。

JSF 2.2 でさらに便利になったMarkupを使ってみよう


公式に近い部分だとこれかな??
HTML(5) Friendly Markup in JSF 2.2


これをつかえばcssとかJavaScriptも一緒に使えるかな??

CDIメモ(自分向け)

完全に自分向けメモ。
ぼやっと本読んでたら何やら理解できて来た気がするので……

内容が正しいかはまったくもって保証しません。

■ CDI(Context and Dependency Injection)


    @Named(value = "injectSample")
    public class InjectSample {
        @Inject InjectedSample injected;
        public void sample() {
            injected.execute();
        }
    }


通常であればinjectedはどこかでインスタンス化する
必要がある(new InjectedSample();)が、CDIを利用することで
これをしなくてよくなる。

これによって、
InjectSampleとInjectedSampleの間の依存関係を疎にすることができる。
(その代わりInjectedSampleは引数を受け付けないコンストラクタによって
インスタンス化される)

■ コンテキスト

上記の内容を理解するにはコンテキスト(Context)にるいて理解する必要がある。

CDIにおけるコンテキストとは
スコープアノテーションによって指定されたオブジェクトの存続設定

■スコープアノテーション

CDIビーンに対して設定されるオブジェクトの存続期間


  • @RequestScoped
  • @SessionScoped
  • @ApplicationScoped
  • @ConversationScoped
  • @Dependent

■CDIビーン

管理ビーンの一種。CDIサービスによって管理される。
管理ビーンはコンテナ内で管理されており、
スコープに応じて適切なオブジェクトが自動で選択され、
変数に代入される。

2015年9月1日火曜日

WebSocketのサンプルコード(クライアント編)


WebSocketのクライアント(ブラウザ)側の実装サンプル。

テキストフィールドにメッセージを入れてSubmitボタンをクリックすると
他のクライアントにもメッセージが配信される。そんだけ。


Bootstrapを使ってみたけど、説明するって意味では、
明らかにコード可読性の低下要因でしかないな~......


以下の解説の用語とかは信用しないでください。
jQueryとBootstrap使ってるけれども正しい使い方ではないと思う。
基本的には、

  1. Websocketプロトコルでのアクセス先(wsUri)を指定
  2. Websocketをnewする(websocket)
  3. websocketに対して必要なメソッドを実装(ここではonerror, onopen, onmessage)
  4. クライアント上の操作内容に応じてjQueryでぐりぐりする
(ここでは、submitボタンをクリックするとテキストフィールドに入力したメッセージが 送信される。同時に他のクライアントにもメッセージが配信される。)
<html>
    <head>
        <title>Chatter</title>
        
        
        <link href="css/bootstrap.min.css" rel="stylesheet"></link>
        <script src="./js/jquery-2.1.1.js" type="text/javascript"></script>
        <script type="text/javascript">
            $(function(){
                var wsUri = "ws://" + document.location.host + "/WebSocketChatter/MessageReceiptor";
                var websocket = new WebSocket(wsUri);
                websocket.onerror = function(evt) {
                    
                };
                websocket.onopen = function(evt) {
                    
                };
                websocket.onmessage = function(message) {
                    console.log('Received Text:'+message.data);
                    $('<div class="well row" style="margin-bottom: 2px;">
'+message.data+'</div>
').appendTo('#container_message');
                };
                
                $('#btn_submit').on('click', function(){
                    var text = $('#text_message').val();
                    if(text !== '') {
                        websocket.send(text);                        
                        console.log('Send Text:'+text);
                    }
                });
                
                $('#btn_clear').on('click', function(){
                    $('#text_message').val('');
                });
            });
        </script>
    </head>
    <body>
        <div class="row">
            <div class="col-lg-3">
</div>
<div class="col-lg-3">
                <h1 class="label-primary" style="border-radius: 3px 3px;">
WebSocketChatter</h1>
</div>
</div>
<div class="row">
            <div class="col-lg-3">
</div>
<div class="col-lg-3">
                <h2 class="label-info">
入力項目</h2>
</div>
</div>
<div class="row">
            <div class="col-lg-3">
</div>
<div class="col-lg-3">
                <label for="text_message">Message</label>
                <input class="form-control" id="text_message" placeholder="Text Message" type="text" />
            </div>
</div>
<div class="row">
            <div class="col-lg-3">
</div>
<div class="col-lg-4 btn-toolbar">
                <div class="btn-group">
                    <button class="btn btn-success" id="btn_submit" type="button">Submit    <span class="glyphicon glyphicon-check"></span></button>
                    <button class="btn btn-danger" id="btn_clear" type="button">Clear   <span class="glyphicon glyphicon-remove"></span></button>
                </div>
</div>
</div>
<div class="row">
            <div class="col-lg-3">
</div>
<div class="col-lg-3">
                <h2 class="label-info">
メッセージコンテナ</h2>
<div class="col-lg-12" id="container_message">
                </div>
</div>
</div>
</body>
</html>

2015年8月31日月曜日

JFreeChartで横軸の値を縦書きにする

JFreeChartでグラフを作るときに悩ましいのが、
横軸のラベル(って言えばいいのでしょうか?)の管理。
横軸ラベルの文字列が長くなると本来の値が
...に置換されてしまい残念な結果になってしまいます。
一応の対応策としては、ラベルを縦書きにすることで
問題を解消できます。
こんな感じで、修正可能です。
JFreeChart chart = ChartFactory.createBarChart("サンプルグラフ", "横軸", "縦軸", dataset);
chart.setAntiAlias(true);
CategoryPlot plot = chart.getCategoryPlot();
CategoryAxis axis = plot.getDomainAxis();
axis.setCategoryLabelPositions(CategoryLabelPositions.UP_90);

JFreeChartから上記処理に基づいて
CategoryAxisを取得しsetCategoryLabelPositionsメソッドで
向きを変更することができます。

2015年7月15日水曜日

pdfファイルにJFreeChartのグラフを出力

JFreeChartで出力したグラフをiTextを使ってpdfファイルに張り込む。

全体的な流れとしては、

  1. JFreeChartでグラフを生成
  2. 1.からBufferedImageを生成
  3. ChatUtilityを使ってPNG形式でエンコードしたものをbyteの配列として取得
  4. iTextのDocumentクラスをインスタンス化
  5. byteの配列からImageクラスを生成
  6. Imageのpdfファイル上の貼り付け場所を決める
  7. PdfWriterを生成する
  8. Documentをオープンする
  9. PdfContentByteを取得してimageを張り付ける
  10. Documentをクローズする
いつも通り品質は保証しません。


package variouslibraries.javalearning.jfree;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;


public class JFreeChartToPDF {
    public static void main(String[] args) {
        
 //グラフを作る
 String series1 = "Kyoto";
 String series2 = "Hyogo";
 String series3 = "Osaka";
 String category1 = "Category 1";
 String category2 = "Category 2";
 String category3 = "Category 3";
 String category4 = "Category 4";
 String category5 = "Category 5";
 String category6 = "Category 6";
 DefaultCategoryDataset dataset = new DefaultCategoryDataset();
 dataset.addValue(2.0, series1, category1);
 dataset.addValue(3.0, series1, category2);
 dataset.addValue(4.0, series1, category3);
 dataset.addValue(2.0, series1, category4);
 dataset.addValue(1.0, series1, category5);
 dataset.addValue(3.0, series1, category6);

 dataset.addValue(4.0, series2, category1);
 dataset.addValue(1.0, series2, category2);
 dataset.addValue(2.0, series2, category3);
 dataset.addValue(3.0, series2, category4);
 dataset.addValue(1.0, series2, category5);
 dataset.addValue(2.0, series2, category6);

 dataset.addValue(5.0, series3, category1);
 dataset.addValue(3.0, series3, category2);
 dataset.addValue(2.0, series3, category3);
 dataset.addValue(6.0, series3, category4);
 dataset.addValue(5.0, series3, category5);
 dataset.addValue(7.0, series3, category6);
        
      JFreeChart chart = ChartFactory.createLineChart("Sample Line Chart", "Category", "Value", dataset, PlotOrientation.VERTICAL, true, true, false);
 chart.setAntiAlias(true);   
        
        
        
        //byteの配列を変更する。
        float width = PageSize.A4.getWidth();
        float height = PageSize.A4.getHeight();
        BufferedImage bufImage = chart.createBufferedImage((int)width, (int) (height/2.0));
        byte[] byteArray = null;
        try {
            byteArray = ChartUtilities.encodeAsPNG(bufImage);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        //pdfファイルを作成する
        Document document = new Document(PageSize.A4);
        try {
            Image image = Image.getInstance(byteArray);
            image.setAbsolutePosition(0, document.getPageSize().getHeight() - bufImage.getHeight());
            PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream("PdfSample2.pdf"));
            document.open();
            PdfContentByte pdfContentByte = instance.getDirectContent();
            pdfContentByte.addImage(image);
        } catch (BadElementException | IOException ex) {
            ex.printStackTrace();
        } catch (DocumentException ex) {
            ex.printStackTrace();
        }
        document.close();
    }
}


2015年7月14日火曜日

JavaでXMLを読み込む(DOM版)

PowerShellでXMLを読み込む方法を書いたので、
今度はJavaで読み込む方法も書いてみた。
DOM使って読み込む。

まあ......手順としては理解しやすいけどめんどいね。
以下のファイルを読み込んでみた。


 

    ChildA
    ChildB
    ChildC


コードの全体の流れとしてはこんな感じ。

  1. Fileをインスタンス化
  2. DocumentBuilderFactoryをインスタンス化
  3. DocumentBuilderをインスタンス化
  4. DocumentBuilderを使って1をparseしてDocumentをインスタンス化
  5. 4.からElementにxml文書のルートノードを格納
  6. ElementからNodeListを取得
6はここでは、getElementsByTagIdメソッドを使っている。
getChildNodeでも同じ結果が得られると思って使ってみると、なんか
NodeListのgetLengthメソッドの結果が違う......
これは要調査。

package variouslibraries.javalearning.xml;

import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLReader {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        File file;
        file = new File("./SampleXML.xml");
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(file);
        
        Element root = document.getDocumentElement();
        System.out.println("Root要素のタグ名:"+root.getNodeName());
        
        System.out.println("子要素を取得して値を表示。");
        NodeList children = root.getElementsByTagName("Child");
        for(int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            System.out.println(node.getTextContent());
        }        
    }
}


実行結果

Root要素のタグ名:Parent
子要素を取得して値を表示。
ChildA
ChildB
ChildC

2015年7月13日月曜日

iTextを使ってpdfを出力する

ずっと食わず嫌いで触っていなかったので、今回こそ克服のために触る。


iTextってpdfライブラリを使ってHello world的なことをやってみた。


  1. Documentをインスタンス化
  2. PdfWriterインスタンス化時に1をFileOutputStreamと一緒に放り込む
  3. Documentをオープン(document.open());
  4. Documentに要素を追加(document.add());
  5. Documentをクローズ(document.close());

なんか1.でサイズを指定したり、4.で文字列以外も追加できる様子。
(まあ、当たり前ですが)

package variouslibraries.javalearning.log4j.itext;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author USER
 */
public class ITextPdfSample {
    public static void main(String[] args) {
        Document document = new Document();
        try {
            PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream("PdfSample.pdf"));
            document.open();
            document.add(new Paragraph("PDF Sample!"));
        } catch (FileNotFoundException | DocumentException ex) {
           ex.printStackTrace();
        }
        document.close();
    }
}
</pre>


はい、食わず嫌いしてて申し訳ありませんでした。

出来上がったファイルは以下。
完成品はかわいげもへったくれもないですね。
気が向いたらいろいろ試してみます。

古い記事ですが、
あたりに、いろいろ追加情報があったり、サーブレットからキックして
pdf出力させたい人にはいいかも。

他のライブラリが欲しいって人は
を参照すると幸せになれるかも。

JFreeChartでSVG出力(JFreeSVG利用)

JFreeChartもJFreeSVGもjfree.orgが開発しているんで、
相性はよかろうという安易な考えで書いてみた。

流れとしては、

  1. 適当にJFreeChartのグラフを作る
  2. SVGGraphics2D(キャンバスみたいなもん)を作成
  3. Rectangle2Dを作成
  4. SVGUtilsで出力
というながれ、2,3は出力先のキャンバスとキャンバス上に
どれくらいのサイズで出力するかを設定する感じ。
一先ず動きゃええの精神で作っているので品質は保証しません。


package variouslibraries.javalearning.jfree;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.graphics2d.svg.SVGGraphics2D;
import org.jfree.graphics2d.svg.SVGUtils;


public class JFreeChartSVGOutput {

 public static void main(String[] args) {
  // (1)データセットの作成
  String series1 = "First";
  String series2 = "Second";
  String series3 = "Third";
  // カテゴリーの設定
  String category1 = "Category 1";
  String category2 = "Category 2";
  String category3 = "Category 3";
  String category4 = "Category 4";
  String category5 = "Category 5";
  String category6 = "Category 6";
  DefaultCategoryDataset dataset = new DefaultCategoryDataset();
  dataset.addValue(3.0, series1, category1);
  dataset.addValue(2.0, series1, category2);
  dataset.addValue(4.0, series1, category3);
  dataset.addValue(4.0, series1, category4);
  dataset.addValue(4.0, series1, category5);
  dataset.addValue(6.0, series1, category6);

  dataset.addValue(5.0, series2, category1);
  dataset.addValue(3.0, series2, category2);
  dataset.addValue(6.0, series2, category3);
  dataset.addValue(5.0, series2, category4);
  dataset.addValue(6.0, series2, category5);
  dataset.addValue(5.0, series2, category6);

  dataset.addValue(6.0, series3, category1);
  dataset.addValue(7.0, series3, category2);
  dataset.addValue(7.0, series3, category3);
  dataset.addValue(6.0, series3, category4);
  dataset.addValue(5.0, series3, category5);
  dataset.addValue(7.0, series3, category6);

  // (2)JFreeChartオブジェクトの生成
  JFreeChart chart = ChartFactory.createLineChart("Sample Line Chart", "Category", "Value", dataset, PlotOrientation.VERTICAL, true, true, false);
  chart.setAntiAlias(true);
  // (3)グラフの出力

  SVGGraphics2D svg = new SVGGraphics2D(640, 480);
  Rectangle2D rectangle = new Rectangle(640, 480);
  chart.draw(svg, rectangle);

  try {
   SVGUtils.writeToSVG(new File("./SampleLineChart.svg"), svg.getSVGElement());
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

}
出力される画像は以下のような感じ。
実際のファイルだと拡大縮小してもスムーズな線のままです。
(したのファイルはpngにしているのでそうもいきません。)

Inkscapeやらで読み込むと一つ一つの線やら背景やらを
編集できるけど、使い道は知らない。

2015年1月8日木曜日

JAX-RSでJSONを出力してみた。

ほぼ自分用のメモ。
JAX-RSでJSONを出力してみました。

これを使えば、JAX-RS + AJAXの組み合わせで
ThinServerアーキテクチャライクなことができる...のか?


(手順)

  1. GlassFishでWebアプリケーションプロジェクトを作成。
  2. パターンからのRESTful Webサービスを作成する。
  3. 単純なルート・リソースを作成
  4. パスを指定(今回はSampleを設定)。* MIME-TYPEには application/jsonを指定。
  5. getJSONメソッド内でJSONを作り文字列にして返す。

* http://localhost:8080/アプリケーション名/webresources/パス がアクセスパスになる。
  RESTful Webサービスディレクトリ配下にあるクラス名を右クリックして
 テスト・リソースURIを選択すると、実行できる。(GlassFishをあらかじめ起動しておく必要がある)


以下、サンプルコードです。

SampleResourde.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package sample;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObjectBuilder;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;

/**
 * REST Web Service
 *
 * @author USER
 */
@Path("Sample")
public class SampleResource {

    @Context
    private UriInfo context;

    /**
     * Creates a new instance of SampleResource
     */
    public SampleResource() {
    }

    /**
     * Retrieves representation of an instance of sample.SampleResource
     * @return an instance of java.lang.String
     */
    @GET
    @Produces("application/json")
    public String getJson() {
        String json;
        JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
        JsonObjectBuilder objBuilder = Json.createObjectBuilder();
        
        objBuilder.add("time", "2015/01/23 14:30:25");
        objBuilder.add("value", 45.5);
        arrayBuilder.add(objBuilder);
        
        objBuilder.add("time", "2015/01/23 14:30:25");
        objBuilder.add("value", 45.5);
        arrayBuilder.add(objBuilder);
        
        JsonArray jsonArray = arrayBuilder.build();
        json = jsonArray.toString();
        
        return json;
    }

    /**
     * PUT method for updating or creating an instance of SampleResource
     * @param content representation for the resource
     * @return an HTTP response with content of the updated or created resource.
     */
    @PUT
    @Consumes("application/json")
    public void putJson(String content) {
    }
}

出力はこんな感じになります。
(適宜改行入れてます。)

http://localhost:8080/アプリケーション名/webresources/Sample にアクセス。

[
    {
     "time":"2015/01/23 14:30:25",
     "value":45.5
    },{
     "time":"2015/01/23 14:30:25",
     "value":45.5
    }
]