2008年12月26日金曜日

Flexでパンくずを作ってみる

Flexでパンくずを作ってみました。
もちろん改良の余地はあります。なんせ0.0.0ですから。

まだSVNのみの公開です。
http://code.google.com/p/breadcrumbs-flex/


んーんGoogleCodeナウいですな。

HibernateでClobを生成

OracleのCLOB型などを使用すると
String型から変換してClob型などに変更する必要があります。


Clob clob = Hibernate.createClob(textData);


SQLServer2000でMicrosoftのJDBCを利用すると
TEXT型がCLOB型になるのですがどうもうまく返してくれません。
※Microsoftによると仕様みたいです。

なのでjTDSのドライバを使ったことがあります。

HibernateでOracleのシーケンスを使う

Oracle でのシーケンス指定を行います。
するとHibernateでは以下のように指定します。


<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">tblTree_id</param>
</generator>
</id>

Oracleで通番を設定

Oracleで指定しないで通番を指定するには


create table tbl_tree (
id number,
name varchar2(255) not null,
treeXML XMLType,
create_dt_d timestamp,
update_dt_d timestamp,
primary key ( id )
);

create sequence tblTree_id start with 1 increment by 1;

select tbltree_id.nextval from dual;


という風に「tblTree_id」のような変数を作って
指定する必要があります。

SQLではtblTree_id.nextvalみたいな設定が必要です。

HTTPServiceに引数を渡す

Objectを単純にnewして作成します。

その後、オブジェクトのプロパティ名を
Webに対する引数と同じにして設定します。

POSTの仕方は以下です。(GETでも良い)
でsend()メソッドの引数に渡すと


var argObj:Object = new Object();

var targetId:String = String(treeGrid.selectedItem.id);
argObj.targetId = targetId;

srvTreeView.method = URLRequestMethod.POST;
srvTreeView.send(argObj);



サービスに対して渡すことができます。

Webにアクセスしてデータグリッドを表示

Webにアクセスして、データグリッドの一覧に表示する方法です。


<mx:HTTPService id="srvDataView" url="http://localhost:8080/selectView.do"
useProxy="false" result="showResult(event)"/>


というタグを作ります。

XMLを返してくれるHTTPにアクセスします。
上記URLは下記XMLを返すRESTサイトです。


<treeView>
<forms>
<treeViewList>
<data>
<name>テスト名称</name>
<id>5</id>
</data>
<data>
<name>XMLデータだよー</name>
<id>6</id>
</data>
<data>
<name>一応ね</name>
<id>7</id>
</data>
</treeViewList>
</forms>
</treeView>


これに対して
データグリッドを準備して

<mx:DataGrid id="treeGrid">
<mx:columns>
<mx:Array>
<mx:DataGridColumn headerText="ID" dataField="id"/>
<mx:DataGridColumn headerText="Name" dataField="name" />
</mx:Array>
</mx:columns>
</mx:DataGrid>


ActionScript上に戻り値のイベントを利用して
その値を設定します。


public function showResult(event:Event):void {
treeGrid.dataProvider = srvDataView.lastResult.treeView.forms.treeViewList.data;
}


これで変更してくれます。

2008年12月14日日曜日

Flexのコンポーネントの初期化

ActionScriptでコントロールを作成して、

//オブジェクトを生成
var waitWindow:WaitWindow =new WaitWindow();
//ラベルを設定
waitWindow.setLabel(objFile.name);


という風に処理を行い
newしたコンポーネントに対して処理を行う場合、
newされた側にあるコンポーネントの値にアクセスすると
nullオブジェクトにアクセスする場合があります。

そんなときは


private var myLabel:String = "";

public function setLabel(aLabelText:String):void {
myLabel = aLabelText;
callLater(setTitle);
}

private function setTitle():void {
displayLabel.text = myLabel;
}


として処理を遅らせます。
newしただけでは中にあるDisplayObjectが初期化が行われないのでしょう。
callLater()は表示を再描画時に処理を行うそうなので
処理を遅らせて処理をすることが可能になります。

何度も処理を行うような時に使用するかは。。。わかりませんが
これで初期化はOKです。

2008年12月6日土曜日

Flexで日付変換

まずタグを用意します。


<!-- 日付フォーマットオブジェクト -->
<mx:DateFormatter id="dateFormatter" formatString="YYYY/MM/DD JJ:NN:SS" />


でスクリプト上で


//日付型へ変換
var showDate:Date = new Date(item.pubDate);
return dateFormatter.format(showDate);


と指定してやるとOKです。

Webアプリの再起動

「conf/tomcat-users.xml」
のmanagerロールで管理されていますので


<user name    ="アカウント" 
      password="パスワード"
      role    ="manager"/>


を設定しておきます。

その後、 
http://ドメイン/manager/reload?path=/Webアプリのパス
にアクセスすると
追加してあるユーザをBASIC認証してきます。
そこにユーザ名とパスワードを設定してください。

アプリケーションが再起動します。
(ポートも指定してください)

Web+APでコネクトして隠したとしても
私みたいに全通ししているとアクセス可能です。
よって攻めないでください。
(外部からも再起動可能って事です)

Javaのサーバモード

起動方式を変更します。

以前仕事で(その時はWindowsサーバ)で
デフォルトで結合試験を通り、いざシステムテストの負荷テストを
行ったら、でかいクエリを10発連続で飛ばしたら止まりました。。。

はてさてなんでだろう。。。とやっていて、
コネクション数、セッション継続時間、ソケット有効とかも変更しましたが
一応以下の文面も追加しました。

メモリを変更しないと動かない時が多かったので
これがわかりやすい問題の1つでした。
調べると難しい話しも多いのですが、
システム搭載の物理メモリの半分ぐらい使って良いのではないでしょうか?

アウトオブメモリに陥ったらどうぞお試しあれ。
※実装を直す暇があれば、適切かどうかを試すのが賢明かも。

環境変数に


CATALINA_OPTS=-Xmx256M -Xms256M -Xss256K -server


を追加します。
そうすると起動時に環境変数として盛り込まれます。

但し、Windowsのサービス起動(Tomcat.exe)だと、
この変数の影響がでない現象がありました。
何やらサービスの起動はレジストリからVMの値を
決定しているらしい。。。という結論に至りました。

Tomcatエラーページの指定

サーバ上でエラーとなった場合、エラーページを指定する事ができます。

<error-page>
  <error-code>404</error-code>
  <location>/error/notfound.html</localtion>
</error-page>

と指定するとNotFoundを自分の好きなページで表示する事ができます。
400:不正なリクエスト

401:無許可
403:禁止されている
408:サーバが応答しない
500:サーバ側で何らかの問題発生

となります。
BASIC認証時は401を指定していると
いきなりエラーページにとんだことがあります。
これはBASIC認証を勉強すれば、わかります。

Javaの例外を捕まえたい場合は

<error-page>
  <exception-type>java.io.FileNotFoundException</exception-type>
  <location>/error/filenotfound.html</localtion>
</error-page>

とできるようです。
。。。。Struts等を使いたい場合、
例外はtry処理等した方が良いと思いますが。。。

Tomcatで認証

「認証情報がなければ、FORMページへリダイレクト」といった
アプリケーションはしばしば見受けられますが、
Tomcat(他を知りませんが)はweb.xmlの編集で認証を
フォルダ、ファイル単位でかけることが可能になります。


それではPostgreSQLのテーブルを使って認証してみましょう。

データベース作成はPostgreSQLの項にありますので見てみてください。
Tomcat5だと./common/libに
JDBCドライバが存在する事が条件です。
Tomcat6では./libになります。

server.xml内にある200行目位です。

 <Realm className="org.apache.catalina.realm.JDBCRealm" debug="99"
        driverName="org.postgresql.Driver" 
          connectionURL="jdbc:postgresql://サーバ名/データベース名?
          user=ユーザ&password=パスワード"
        userTable="users"
        userNameCol="user_name"
        userCredCol="user_pass"
        userRoleTable="user_roles"
        roleNameCol="role_name"/>

って感じで編集します。

その後、アプリケーションのweb.xmlにおいて以下を追加します。


  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Volunteer Manager ID</web-resource-name>
      <url-pattern>/manage/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
      <role-name>design</role-name>
    </auth-constraint>
  </security-constraint>
  
  <login-config>
    <auth-method>DIGEST</auth-method>
    <realm-name>Volunteer Manager ID</realm-name>
  </login-config>

  <security-role>
    <role-name>admin</role-name>
    <role-name>design</role-name>
  </security-role>


これで指定したパスはセキュリティがかかります。

サーブレットでエンコード

すべてのレスポンスを統一したコードに変換する方式は
web.xmlに以下を記述します。


 <filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>filter.EncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>UTF-8</param-value>
  </init-param>
 </filter>

 <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <servlet-name>action</servlet-name>
 </filter-mapping>


まぁこれはStruts用なのでservlet-nameはactionになっていますが、
それぞれの名称にあわせてください。

このクラスに


/**
 * Tomcatコード変換フィルター
 */
public class EncodingFilter implements Filter {

  String encName;

  /**
   * 初期化処理<br>
   * エンコード名を取得
   */
  public void init(FilterConfig config) throws ServletException {
    // TODO 自動生成されたメソッド・スタブ
    encName = config.getInitParameter("encoding");
  }

  /**
   * 実行処理
   */
  public void doFilter(ServletRequest request,
                       ServletResponse response,
                       FilterChain chain) 
                      throws IOException, ServletException {
    request.setCharacterEncoding(encName);
    chain.doFilter(request, response);
  }
}


としておけばOKです。
initでコード名を取ってきていますが、
実装に依存させても大丈夫です。

2008年12月4日木曜日

DataGridのカラムに対して処理を行う

データグリッドの文字列をXMLから設定して、
それで処理をやりたいですよね。

・・・ってDataGridの表示を説明してない。。。

ActionScriptに

//データの日付処理
private function changeDate(item:Object, column:DataGridColumn):String {
//item.pubDateって感じでデータにアクセス
//戻す文字列で表示されます。
return "test";
}

って感じのメソッドを作成します。
引数、戻り値はこれで決まってます。

でDataGridColumnにメソッドをlabelFunctionで指定してあげます。
・・・dataFieldには指定しなくても良いのかな?


<mx:DataGridColumn width="250" headerText="日付" dataField="pubDate" labelFunction="changeDate"/>


これでchangeDate()が呼び出されます。
XMLで日付を出してたんですけど、書式を変えたかったのでやってみました。

FlexでTreeを表示


Flexでのツリーの初期化を行います。
myXMLという変数にディレクトリを表現したXMLを記述します。

Treeコンポーネントを用意して


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApp();">
<mx:Script>
<![CDATA[
private var myXML:XML =
<dir name="Yahooトピックス" url="http://dailynews.yahoo.co.jp/fc/rss.xml">
<dir name="国内" url="http://dailynews.yahoo.co.jp/fc/domestic/rss.xml"/>
<dir name="地域" url="http://dailynews.yahoo.co.jp/fc/local/rss.xml"/>
<dir name="経済" url="http://dailynews.yahoo.co.jp/fc/economy/rss.xml"/>
<dir name="海外" url="http://dailynews.yahoo.co.jp/fc/world/rss.xml"/>
<dir name="エンターテイメント" url="http://dailynews.yahoo.co.jp/fc/entertainment/rss.xml"/>
<dir name="スポーツ" url="http://dailynews.yahoo.co.jp/fc/sports/rss.xml"/>
<dir name="サイエンス" url="http://dailynews.yahoo.co.jp/fc/science/rss.xml"/>
<dir name="コンピュータ" url="http://dailynews.yahoo.co.jp/fc/computer/rss.xml"/>
</dir>

//アプリケーション初期化
public function initApp():void{
//ツリーの初期化
rssTree.dataProvider = myXML;
}
]]>
</mx:Script>

<mx:Tree x="10" y="80" width="219" height="308" id="rssTree"
labelField="@name"
defaultLeafIcon="@Embed(source='Assets.swf', symbol='TreeFolderClosed')"/>

</mx:Application>


idを入れてアプリケーション初期化のメソッドにdataProviderを指定させます。
これでツリーが表示されるはずです。

Flexで初期化

Flexでの初期化の方法です。


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="initApp();">
<mx:Script>
<![CDATA[
//アプリケーション初期化
public function initApp():void{
}
]]>
</mx:Script>
</mx:Application>


Appricationタグに「creationComplete」でメソッドを指定して
ActionScriptでメソッドを記述します。
これでこのメソッドが初期化処理として呼び出されます。

2008年12月1日月曜日

日付変換を行う

Date型から固定文字列への変換には
SimpleDateFormatを使用して以下のようにします。

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
String date = sdf.format(new Date());

また文字列で取得したデータからDate型への変換は

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
Date date = sdf.parse(str);

とします。
無論文字列のフォーマットが合ってないとダメです。
※例外を発生します。

正規表現を使う

色々チェックする時には、String.matches()を使用します。
例えば以下は簡単なメールアドレスチェックです。

aValue.matches("[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+");

マップのキー取得

STLを知らないプログラマも増えてきて
何度言ってもListとMapの違いまでしかわかってくれません。
何がListで何がArrayかもわからんのです。。。

まぁそれはさておき、良くマップのキー取得を行う際に
忘れてしまうので覚え書きしておきましょう。


//HashMapオブジェクト生成
Map map = new HashMap();

//Mapにオブジェクトを追加
map.put("1","ライコネン");
map.put("2","アロンソ");
map.put("3","ミヒャエル");
map.put("4","バトン");
map.put("5","ハイドフェルド");

//「キー」の一覧をSetで取得
Set set = map.keySet();

//イテレータ取得
Iterator iterator = set.iterator();

Object object;
//データ数回取得
while(iterator.hasNext()){
  object = iterator.next();
  System.out.println(map.get(object));
}

文字列の変換

「http://ーーー」と指定された文字列をAタグに変換かけたいような時は
正規表現を使用して以下のように行います。

String atag = value.replaceAll("(http://|https://){1}
                     [\w\.\-/:]+","<a href=$#39;$0$#39;>$0</a>");

valueの値はどんな文字列でも変換されます。
Stringの関数ですのでかなり手軽に行う事ができます。
無論リンクの名前を変更したいような時は後ろの$0を変更します。

認証ユーザ名を拾ってみる

BASIC認証等行なった際は

String user = request.getRemoteUser();

とすれば認証されたユーザ名が取得できます。
当然の事ですが、パスワードは取れません。(取る必要がない?)

また、ユーザのロール確認には


request.isUserInRole("test")

として、ロール名に認証されたユーザが入っているかを確認できます。

また、

request.getAuthType()

を行うと認証方式を取得する事もできます。。。。使うか?

ログアウト

Webアプリでログインしている状態を終了します。
但し、単純にセッションを切るだけです。(Form認証の際)

    HttpSession session = request.getSession(false);
    if (session!=null) {
      session.invalidate();
    }

BASIC認証はブラウザにデータを埋め込んで処理をしますので、
ブラウザを終了したりしないと認証は起こりません。

Javaでグラフを表示

さて、グラフを出してみましょう。JFreeChartを使ってみます。
http://www.jfree.org/
に行ってみてください。

解凍したファイルから

java -jar jfreechart-0.9.21-demo.jar

を実行してみましょう。

をーかっこいいのは何個かありますね。
Gantt Chart辺りを使えばプロジェクト管理なんかもできそう!!
あちゃ。。。アボートした。。。

Barでアクセス数、 Timeで日毎アクセス数、Pieで使用OS、ブラウザ
これでアクセスログ解析ができるでしょう。
しかもこれをWebアプリ等に簡単に適用して、
サービスに展開する事も可狽ゥな。。。。

よし!!簡単なアプリケーションを作ってみましょう。
jfreechatはもちろんjcommonもクラスパスに追加しましょう。 

public class ChartTest extends JFrame  implements WindowListner
  public ChartTest() throws HeadlessException {
    super();
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent ev) {
        System.exit(0);
      }
    });

    JPanel pane = new JPanel(new BorderLayout());
    setContentPane(pane);

    JFreeChart chart = createChart();
    ChartPanel cpane = new ChartPanel(chart);
    pane.add(cpane);
  }

  private JFreeChart createChart() {
    DefaultPieDataset pie = new DefaultPieDataset();
    pie.setValue("FireFox",37);
    pie.setValue("Opera",25);
    pie.setValue("IE",21);
    pie.setValue("Other",17);
    JFreeChart rtnChart = 
        ChartFactory.createPieChart("てすとです",pie,true,true,true);
    return rtnChart;
  }

  public static void main(String[] args) {
    ChartTest chart = new ChartTest();
    chart.setBounds(0,0,300,300);
    chart.show();
  }
}

おーこれで円グラフが書けました!!
ChartUtilities等を使えばファイルに保存もできます。

※一応言っておきますが、一部インプリメントしてません。

ログファイル出力

ログは以下のように出力できます。

  //ロガーを取得
  Logger logger = Logger.getLogger("java.util.logging");
  //ファイル名を指定
  FileHandler fh = new FileHandler("/tmp/ziro.txt");
  //出力フォーマットの設定
  fh.setFormatter(new SimpleFormatter());
  logger.addHandler(fh);
  //出力レベルの設定
  logger.setLevel(Level.INFO);
  //出力
  logger.log(Level.INFO,"出力します。");

とします。
これで出力指定したファイルにログファイルを出力します。