しんさんの出張所 はてな編 このページをアンテナに追加 RSSフィード

   
カレンダー
2007 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 |

2013-05-03

[][]続・JavaでさくさくWebアプリ開発

JavaでさくさくWebアプリ開発の続き

たぶん前回のエントリ見た人の半分は気がついてると思うけどクラスパスとかいろいろとスキャンしたりするようなApplicationを継承したクラスはいくつも用意されている。


探し方

Application app = new

と入力した状態でCTRL+SPACEを押すとApplicationを継承したクラスがいくつも出てくるのでそれであたりをつける。


単純な置き換え系

HogeApplication app = new HogeApplication(Hoge.class);

ClassNamesResourceConfig app = new ClassNamesResourceConfig(Hoge.class);

にかえてもよい。こちらはClass引数に取るほかにもクラスの名前を文字列で渡したりすることもできる。

いちいち自分で作ることもないのだ。

クラスパスから検索

ClasspathResourceConfig app = new ClasspathResourceConfig();

ただし、なにもしぼらないとクラスパスすべて見に行くため起動に時間がかかるようになる。

ライブラリが増えれば増えるほど遅くなる。

実測でこれ以外はすべて650msくらいで起動するが、これだけはなんと1.1秒に!全然さくさくじゃない!

パッケージ指定

たぶんこれが一番使いやすい。

PackagesResourceConfig app = new PackagesResourceConfig("");

からの文字列でも十分高速で速度は全然変わらなかった。

これによってサーバーの起動時間はかわらない。

パッケージは省略できるけど、ファイルが増えてきたらできるだけ絞ったほうがいいのかもね。起動が1秒を超えるかもしれないし。



というわけで、1つだけ1秒切ることはなかったけど、忍耐力が高い人ならたぶん大丈夫。

2013-04-29

[][]JavaでさくさくWebアプリ開発

かなり久々の技術エントリ。

運用はお堅い重いサーバーを使ったとしても開発は軽いほうがいい。当たり前ですね。

というわけでさくさく開発する方法を書いてみる。DIコンテナCDIGuice、Springなど好きなものでよいが、今回は省く。軽いこともあって開発中はGuiceを使うことをお勧めしたい。注入は@Injectを使うため、開発中と運用中でコードが変わるってのは少ないはずだ。

まずはJAX-RS

まず、アクションベースのWebアプリJAX-RSを使うこと。これが基本。サーブレットAPIを使わずに開発することについては今までも書いてきた。サーブレットAPIを触らないことにより開発効率とテストのしやすさを両立できる。

こんな感じ。

@Path("/")
public class Hoge {
    @GET
    @Path("add/{a}/{b}")
    public Response add(@PathParam("a")int a, @PathParam("b")int b){
        String text = a + "+" + b + "=" + (a+b);
        return Response.ok(text , "text/plain").build();
    }
}

okはわざわざこんなことやらなくてもいいけど、JavaJAX-RSよくわからん人でもなんとなく動きはわかるようにしてみた。これがJAX-RS

書き方は結構自由なので、同じ動きをいろんなかきかたができる。いろんなかきかたができるといってもわかりにくいということではなく、柔軟にstatusコードとかmimeとか数値や文字列だったり定数クラスだったり指定することができる。

        return Response.ok(entity , "text/plain").build();
        return Response.ok().entity(text).type("text/plain").build();
        return Response.ok(text).type("text/plain").build();
        return Response.status(200).entity(text).type("text/plain").build();
        return Response.status(Response.Status.OK).entity(text).type(MediaType.TEXT_PLAIN_TYPE).build();

もちろんOK以外もいくつかメソッドで用意されている。こんな感じ。

        return Response.seeOther(new URI("http://example.com")).build();
        return Response.serverError().entity("ごめんちゃい").build();

すでに枯れた標準APIなのでJava使いなら大抵誰でも知ってるはず。もうすぐ次のバージョンが出るけど、互換性があって基本部分に変更はないので大丈夫。あくまでもさらに便利になるフィルタクライアント(今までは実装依存だった)の標準化をしたに過ぎない。

POJOなのでこういうテストを書いてもいい。

    @Test
    public void testAdd() {
        System.out.println("add");
        int a = 12;
        int b = 3;
        Hoge instance = new Hoge();
        Response result = instance.add(a, b);
        
        assertEquals(200, result.getStatus());
        assertEquals("12+3=15", result.getEntity().toString());
    }

そのほか実際にスタンドアロンサーバーで通信するテストを書いてもいい。サーブレットコンテナはいらないのでJavaSEで開発ができる。さくさくである。この場合テンプレートJSPは利用できないので他のテンプレートエンジンを利用することになる。基本クライアントサイドで組み立てたほうがいいと思うけどね。サーバーとはデータのみやり取りするように。

jax-rsライブラリはRIのjerseyから落としてくるとよい。

https://jersey.java.net/nonav/documentation/latest/chapter_deps.html

このあたりを。


それでもサーブレットコンテナがほしい

それでも特定のサーブレットJSPを利用したいこともあるかもしれない。自分のアプリの都合ではなく、ライブラリなどの都合でフィルターが使いたいとかで。完全新規ならフィルターはJerseyのフィルタを使えばいいがそうではない場合もあるだろう。そうなるとTomcatなどが必要になってきて開発はどんどん重くなる。

軽いコンテナは?と聞いたらすぐに帰ってくるのがJetty

そう、Jettyのembeddedを利用する。

jetty-all-[version].jarというのをクラスパスに追加する。servlet-api-3.0.jarもいれておく。

jetty-allはこのへんから。

http://mvnrepository.com/artifact/org.eclipse.jetty.aggregate

servlet-api-3.0.jarjetty-distribution-[version].zipとかをjettyの公式サイトのトップから落としてそこから拾うとよい。

public class ServerMain {

    public static void main(String[] args) throws Exception {
        
        //サーバー起動
        Server server = new Server(8080);
        server.start();
    }
}

これで起動する。サーバーが起動しているかどうかブラウザで404がかえるのを確認する。

JerseyServletを設定する

リソースを列挙するクラスを用意。コンストラクタで列挙できるようにしてある。

public class HogeApplication extends Application{
    final Set<Class<?>> classes = new HashSet<>();

    public HogeApplication(Class<?>... classArray) {
        classes.addAll(Arrays.asList(classArray));
    }
    
    @Override
    public Set<Class<?>> getClasses() {
        return classes;
    }

}

クラスパスとかをスキャンしたりして自動登録してもいい。


    public static void main(String[] args) throws Exception {
        ServletContextHandler ctx = new ServletContextHandler();
        ctx.setContextPath("/test");

        //Jersey設定
        //リソースクラスの一覧を列挙
        HogeApplication app = new HogeApplication(Hoge.class);
        ServletContainer sc = new ServletContainer(app);
        ctx.addServlet(new ServletHolder(sc), "/res/*");
        
        //サーバー起動
        Server server = new Server(8080);
        server.setHandler(ctx);
        server.start();
    }

これで以下のURLで動くようになった。

http://localhost:8080/test/res/add/12/3

でもこれではスタンドアロンサーバーの状態のままに近い。一応サーブレットとして動いているので好きなようにフィルタ付けたりいろいろとできることはできるけど、JSPとかは動かない。

JSPとか動かす

ライブラリが足りないのでJSPを動かすのに必要なライブラリをクラスパスに通す。

jetty-distribution-[version]からlib/jsp以下のjarをもってくる。

mainクラスは以下のように修正。


    public static void main(String[] args) throws Exception {
        ServletContextHandler ctx = new ServletContextHandler(ServletContextHandler.SESSIONS);
        ctx.setClassLoader(Thread.currentThread().getContextClassLoader());
        ctx.setSessionHandler(new SessionHandler());
        ctx.setContextPath("/test");

        //Jersey設定
        //リソースクラスの一覧を列挙
        HogeApplication app = new HogeApplication(Hoge.class);
        ServletContainer sc = new ServletContainer(app);
        ctx.addServlet(new ServletHolder(sc), "/res/*");
        
        //JSP設定
        ctx.setResourceBase("webapp");
        ctx.addServlet(DefaultServlet.class, "/");
        ServletHolder jsp = ctx.addServlet(JspServlet.class, "*.jsp");
        jsp.setInitParameter("classpath", ctx.getClassPath());
        
        //サーバー起動
        Server server = new Server(8080);
        server.setHandler(ctx);
        server.start();

これで準備完了。

カレントディレクトリにwebappというディレクトリを作ってJSPを置いて動作確認しよう。

一瞬でサーバーが起動して動作が確認できるだろう。

JSPが動くということはViewableが動くということ。ViewableはJSPフォワードしてくれる仕組み。

先ほどのリソースクラスに追加してみる。

@Path("/")
public class Hoge {
    @GET
    @Path("add/{a}/{b}")
    public Response add(@PathParam("a")int a, @PathParam("b")int b){
        String text = a + "+" + b + "=" + (a+b);
        return Response.ok(text , "text/plain").build();
    }
    //---------------------------------------------------------------
    //ここから下が追加分
    @GET
    public Viewable get(@QueryParam("a")int a, @QueryParam("b")int b ){
        HashMap<String, Object> params = new HashMap<>();
        params.put("a", a);
        params.put("b", b);
        params.put("c", a + b);
        return new Viewable("/hoge.jsp", params);
    }
}

JSPitという名前でアクセスすることができる。たとえばこんな感じ。

<%@page pageEncoding="UTF-8" contentType="text/plain" %>
${it.a} + ${it.b} = ${it.c}

以下のURLブラウザで確認するとよいだろう。

http://localhost:8080/test/res/?a=12&b=3

これで1秒で起動するJSP等も動くサーバーの出来上がり。



続きかいた

2012-04-25

[][][]NetBeans 7.2の新機能 TestNGと履歴の強化

NetBeans 7.1までは「JUnit」というカテゴリが存在していたが、それが「Unit Tests」という項目になっている。つまり、単体テストJUnitだけではないということだ。具体的にはTestNGが追加された。

http://shin.cside.com/diary/2012/0425-01.png

もちろん、頻繁に使うこちらのダイアログ(CTRL+SHIFT+U)でも選択肢が追加されていた。

http://shin.cside.com/diary/2012/0425-02.png

ただ、TestNGの動作はまだ完成していないようでうまく動かなかった。ライブラリ等は設定されてはいたが。

今後他のテストフレームワークが追加されるのかもしれない。


続いて履歴。

以前紹介したのはローカル履歴だけだったが、バージョン管理システムを有効にしている場合はこうなる。今回はMercurialで。

http://shin.cside.com/diary/2012/0425-03.png

つまり、ローカルだろうが、どっかのリポジトリだろうが関係なく横断的に検索ということが可能になる。もちろん、フィルタでどっちかだけとか絞ることも可能ではあるが、これはなかなか面白い。


・・・だけど、今のところMercurialの比較動作にバグがある模様。デフォルトキャラクタセットを利用しようとする。デフォルトのキャラクタセットを使ってよいか?とわざわざダイアログで表示しているのに、キャンセルをすると表示すらされない。

このバグは6.x系に長く存在していた。今回もエンバグしたようだ。マルチバイト系のバグは放置される癖があるので直らないかもしれない。

2012-04-24

[][]NetBeans 7.2の強化されたJPAサポート

NetBeans 7.2紹介シリーズ第3弾。

NetBeansはもともと古くからJPAをいち早くサポートしていたがさらに強化された。まぁ今回紹介するのは微妙なところだけど。


名前付クエリで補間がきくようになった。

http://shin.cside.com/diary/2012/0424-01.png


構文がおかしいと知らせてくれる。

http://shin.cside.com/diary/2012/0424-02.png


これはベタ書きした場合でも有効。ただし、いったん変数に入れたりすると有効ではないのであんまり意味がないけど。作成後利ファクタする、って感じがいいのかな。

http://shin.cside.com/diary/2012/0424-03.png


名前付クエリ名の補間とそのJPQL表示が見ることが出来るってのが一番いいところなのかな。これも別の変数に入れるとダメだけど。

http://shin.cside.com/diary/2012/0424-04.png


JPARDBを利用する場合、いまやJavaでもっともスタンダードなO/Rマッパだ。

他の代替肢はなくなったというくらい駆逐され、圧倒的なシェアをもつ。実装としてHibernate(EntityManager)を利用することは多いとは思うが、基本的にJPAで行える範囲内はJPAで実装、足りない部分を実装固有のものを利用するというのが一般的だ。最初からHibernateAPIというのもだいぶなくなったと思う。

というわけで、JPAをどんどん使おう。DIコンテナやWebフレームワークと違い圧倒的な一強で、新しく出来たライブラリ等でも違う点を説明する際にもJPAと比較、拡張しているのがほとんどのため一般教養に等しい存在になっている。どのDIコンテナ、どのWebフレームワークを利用してもDBアクセスはみんなJPAなのだ。現代のJDBCといってよい。

2012-04-21

[][]NetBeans 7.2ではじめるAmazonのクラウド

NetBeans 7.2の新機能紹介シリーズ。

おや、サービスウインドウに見慣れないものがあるぞ。

http://shin.cside.com/diary/2012/0421-01.png


クラウドの選択・・・だと?

http://shin.cside.com/diary/2012/0421-02.png


AWSの接続情報を入力する。

http://shin.cside.com/diary/2012/0421-03.png


追加された。

http://shin.cside.com/diary/2012/0421-04.png


次にプロジェクトの新規作成で、Webプロジェクトを作る。

その際にTomcatやGlassfishなど選択できるが、そこでサーバーの新規追加を選ぶと…やつ(Beanstalk)が選択できる。

http://shin.cside.com/diary/2012/0421-05.png


コンテナタイプを選択できる。PHPも選べるが、PHPプロジェクトも対応しているかはわからない。テンプレートという項目もあるが選べない模様。

http://shin.cside.com/diary/2012/0421-06.png


追加された。

http://shin.cside.com/diary/2012/0421-07.png


AWSの管理ツールを開くとこの時点でデプロイされているのがわかる。

http://shin.cside.com/diary/2012/0421-08.png


リンクをクリックすると確かにデフォルトで起動していた。

http://shin.cside.com/diary/2012/0421-09.png


こういうwarファイルらしい。

http://shin.cside.com/diary/2012/0421-10.png


で、F6を押してプロジェクトの実行。F6をオスとメインプロジェクトのコンパイル、warアーカイブ、デプロイ、ブラウザ起動と順に実行される。そして表示された。これはNetBeansのWebプロジェクトの新規作成をスルト標準ではいっているJSPファイルだ。

http://shin.cside.com/diary/2012/0421-11.png


バージョン管理されているのがわかる。このwarファイルはS3に作られる。

http://shin.cside.com/diary/2012/0421-12.png


と、このようにTomcatやGlassfishなどと同じようにAWSのクラウド(Beanstalk)にデプロイできる。

ただ、現状基本的な動きは問題はないものの、細かいところでバグはあるようで、コンボボックスの選択がおかしかったり、追加したサーバーの情報が消せなかったりする。現時点でここまで動いているので、リリースまでは問題なく実装されそうだ。


Beanstalkで起動されるインスタンスはマイクロインスタンス。マイクロでも500MBはメモリ確保できると思うのであんまり問題にはならないとは思うが、変えたいときはAWSの管理コンソール画面で修正するのがいいのだろう。

BanstalkのJava版はLinux + JavaSE 6 + Tomcat 6/7で実装されているため、Javaのコードを書いてwarをアップロードするだけで、バージョン管理されてサーバーが完成する。好きなバージョンに戻すことも可能だ。ロードバランサも設定され、デフォルトでは1インスタンス、負荷が増えるとインスタンス数が自動で増えて最大4つまで生成されるようになっている。つまり、サーバーの管理はしたくない、アプリだけ作ってあとは全部おまかせができるということだ。

GoogleのクラウドであるAppEngine/Javaとの違いは普通のWebアプリがデプロイできるというところだ。GAEはJavaSEのかなりの部分が実行できないようになっているため、Javaの一般的なWebアプリで利用する既存のライブラリ等がほとんど動かないと思ってよい。

そのため、何もしなくてもそのまま動く、AWSのBeanstalkはクラウド入門によい。そしてNetBeans 7.2はそのためのアクセスを標準で用意した。JavaEE 7ではクラウドがキーワードとなっているため、今後こういった方向は大事になっていくのだろう。今後に期待である。