Tomcat9 JNDIデータソースの設定

プーリングコネクションするJNDIの設定を、server.xml に記述します。

[ 設定例 MySQL ]


      <Resource 
      driverClassName="com.mysql.jdbc.Driver" 
      maxActive="300" 
      maxIdle="100" 
      maxWait="5000" 
      name="jdbc/DATABASE_NAME" 
      password="??????" 
      type="javax.sql.DataSource" 
      url="jdbc:mysql://localhost:3306/DATABASE_NAME?characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false" 
      username="??????" 
      
      validationQuery="select 1"
      testOnBorrow="true"
      testWhileIdle="true"
      timeBetweenEvictionRunsMillis="60000"
      />

5.7系にバージョンアップした時、はまったのですが、非リモートサーバーのデータベースの場合、urlに useSSL=false を入れる必要あります。(ないと劇遅)
Oracleの中の人に教えてもらったのですが、同一ホスト内の場合、127.0.0.1 より localhost が速いそうです。

[ 設定例 Firebird ]


    <Resource
      name="jdbc/DATABASE_NAME"
      type="javax.sql.DataSource"
      driverClassName="org.firebirdsql.jdbc.FBDriver"
      password="????????"
      maxIdle="40"
      maxWait="5000"
      username="????????"
      url="jdbc:firebirdsql:localhost/3050:DATABASE_NAME?lc_ctype=SJIS_0208"
      maxActive="100"
      
    />

[ 設定例 Oracle ]


    <Resource
      name="jdbc/SID_NAME"
      type="javax.sql.DataSource"
      driverClassName="oracle.jdbc.driver.OracleDriver"
      password="SID_NAME"
      maxIdle="40"
      maxWait="5000"
      username="????????"
      url="jdbc:oracle:thin:@???.???.???.???:1521:SID_NAME"
      maxActive="100"/>

[ 設定例 PostgreSQL ]


    <Resource
      name="jdbc/DBNAME"
      type="javax.sql.DataSource"
      driverClassName="org.postgresql.Driver"
      password="???????"
      maxIdle="40"
      maxWait="5000"
      username="??????"
      url="jdbc:postgresql://127.0.0.1/DBNAME"
      maxActive="100"/>

[ 設定例 SQLServer ]


     <Resource
      name="jdbc/DBNAME"
      type="javax.sql.DataSource"
      driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
      password="??????"
      maxIdle="40"
      maxWait="5000"
      username="??????"
      url="jdbc:sqlserver://???.????.???.???:1433;DatabaseName=DBNAME"
      maxActive="100" />

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Tomcatハンドブック
価格:5170円(税込、送料無料) (2023/1/11時点)

Apache2.4 <=> Tomcat 連携

/etc/httpd/conf.d/ の中にインクルードする設定ファイルを作り、以下のような記述を入れます。
8009 はデフォルトのTomcatの server.xml に設定されたポート番号なので、変えた場合、変える必要あります。

<Location /tomcat_sitename>
  ProxyPass ajp://127.0.0.1:8009/tomcat_sitename
</Location>

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Tomcatハンドブック
価格:5170円(税込、送料無料) (2023/1/11時点)

jQuery-ui テーマの動的変更

1)  JSPの自作カスタムタグを使った select を使う


<%@ taglib uri="/WEB-INF/htmythema.tld" prefix="MyThema" %>

2) 1) を使いたいところに配置


// マイテーマ選択用 //
      var themasel = "<MyThema:mythema realdir='' themaval='<%=cfg.getSeltheme()%>' />";

          // == 生成完了した時 == //
          gridComplete: function () {

      var THEMA_DIV = "<div style='float:right' id='mythemadiv'></div>";    

            // マイテーマ選択用 //
            $("#t_others").append(THEMA_DIV);
            $('#mythemadiv').html("MyTheme " + themasel);
            // テーマ変更 => リロード //
            $('#themasel').on('change', function () {
              $('#thmnm').val($(this).val());
              $('#thmchgform').submit();
            });

    <%-- テーマ変更用 --%>
    <%--<MyThema:mythema realdir="" themaval="<%=cfg.getSeltheme()%>"/>--%>
    <form id="thmchgform" method="post" action="export.jsp">
      <input type="hidden" name="thmchg" value="yes" />
      <input type="hidden" name="thmnm" id="thmnm" value="" />
    </form> 

3) 変更リクエストのactionは自ページで、変更内容はクッキーとセッションにセット (どっち使っても良いが、実際はセッションを使ってる)


  // テーマ変更で来た場合 //
  if (request.getParameter("thmchg") != null) {

    //  セッションに格納 //
    String thmnm = request.getParameter("thmnm");
    cfg.setSeltheme(thmnm);

    // クッキーに保存 //
    Cookie cookie = new Cookie("thema", thmnm);
    cookie.setMaxAge(60 * 24 * 60 * 60); //有効期間を60日間に設定
    response.addCookie(cookie);

  }

[ 画面例 ]

多言語化の方法

[ 基本的方法 ]

  1. データベースにマスタを用意
  2. JSPでデータベースのデータを読込、Javascriptの連想配列になった文字列を、pageContext に格納
  3. pageContext の連想配列を const した変数に格納
  4. 3. を jQuery の text, html に入れて表示。jqGridの場合は、constな変数に格納して使う
  5. 2.により、言語変更は、コード簡潔化の為、ページの再読込を必要とする

MultipleSelect 使い方 (4) Java

大まかな流れとしては、

  1. サーブレットで各マルチセレクト条件値CSVテキストをリクエストパラメータで受信
  2. サーブレットで、1.がnullであるか判別してフラグにして、操作用クラスにセットする
  3. マルチセレクト条件値CSVテキストは、リストにして操作用クラスにセットする
  4. 操作用クラスの検索処理メソッドで、最初にセットされた項目別フラグがtrueの場合、一時テーブルの削除追加を行う
  5. MyBatisの指定idの検索SQLを実行する際に、フラグがtrueの場合、一時テーブルをジョインしたSQL、falseの場合ジョインしないSQLを実行

となります。

MultipleSelect 使い方 (3) MyBatis SQL

検索条件を各項目の一時テーブルに入れて、ジョインするかしないかは、パラメータで指示してます。

[ SQL例 ]


 <!-- 船スペックマスタリスト --> 
 <!-- 使用 -->
  <select id="selVesselSpecList2" parameterType="ParamVesselSpec" resultType="VesselSpec">
    select * from (
		select
			v.ukfld as id, v.ukfld as imo,
			
			v.Name as vessel, 
      coalesce(fc_acc6m(v.Name), '') as acc6m,
    
			coalesce(en.cnt_en, 0) as cnt_en, 
      coalesce(`in`.cnt_in, 0) as cnt_in,     
			coalesce(eo.cnt_eo, 0) as cnt_eo, 			
			coalesce(io.cnt_io, 0) as cnt_io, 
      coalesce(ua.cnt_ua, 0) as cnt_ua, 
			
			v.TEU, v.`Year`, v.Speed, v.GrossT, v.DeadW, v.`call`, v.Cntry,  
		
			v.tm_add, v.tm_updt, 
			greatest(v.tm_add, v.tm_updt, coalesce(mt.TM_ADD, '2000-01-01 00:00:00')) as tm_lastupdt,
		
			v.is_manadd,
    
      coalesce(mt.LENGTH_OVERALL, 0) as `length`,
			coalesce(mt.BREADTH_EXTREME, 0) as width,
			coalesce(mt.DRAUGHT, 0) as draught,
    
      coalesce(round(mt.LENGTH_OVERALL, 0), 0) as `length_int`,
			coalesce(round(mt.BREADTH_EXTREME, 0), 0) as width_int,
			coalesce(round(mt.DRAUGHT, 0), 0) as draught_int,
    
			COALESCE(mt.LIQUID_OIL, 0) AS liquid_oil,
			COALESCE(mt.FUEL_CONSUMPTION, '') AS fuel_consumption,
			COALESCE(mt.OWNER, '') AS owner,			
			COALESCE(mt.MANAGER, '') AS manager,
			COALESCE(mt.MANAGER_OWNER, '') AS manager_owner    
			
			
		from 
			vessel2 v
    
      left outer join vessel_mt mt on (v.ukfld = mt.IMO) 
    
      <if test="!isTEUselAll">
        inner join tmp_imo_teu tt on (
        v.ukfld = tt.IMO and tt.ID_SESSION = #{idSession} and tt.NM_GRID = 'specs' 
        )
      </if>
      <if test="!isYearselAll">
        inner join tmp_imo_year yt on (
        v.ukfld = yt.IMO and yt.ID_SESSION = #{idSession} and yt.NM_GRID = 'specs' 
        )        
      </if>
      <if test="!isSpeedselAll">
        inner join tmp_imo_speed st on (
        v.ukfld = st.IMO and st.ID_SESSION = #{idSession} and st.NM_GRID = 'specs' 
        )        
      </if>
      
      <if test="!isLengthselAll">
        inner join tmp_imo_length lg on (
        mt.IMO = lg.IMO and lg.ID_SESSION = #{idSession} and lg.NM_GRID = 'specs' 
        )        
      </if>
      <if test="!isWidthselAll">
        inner join tmp_imo_width wd on (
        mt.IMO = wd.IMO and wd.ID_SESSION = #{idSession} and wd.NM_GRID = 'specs' 
        )        
      </if>
      <if test="!isDraughtselAll">
        inner join tmp_imo_draught dr on (
        mt.IMO = dr.IMO and dr.ID_SESSION = #{idSession} and dr.NM_GRID = 'specs' 
        )        
      </if>
      
    
			left outer join (
			select imo, count(*) as cnt_en from sch_export_source group by imo
			) en 
			on (v.ukfld = en.imo)
			
			left outer join (
			select imo, count(*) as cnt_in from sch_import_source group by imo
			) `in` 
			on (v.ukfld = `in`.imo)
		      
      left outer join (
			select imo, count(*) as cnt_eo from sch_export_source_old group by imo
			) eo 
			on (v.ukfld = eo.imo)
      
      left outer join (
			select imo, count(*) as cnt_io from sch_import_source_old group by imo
			) io 
			on (v.ukfld = io.imo)    
      
			left outer join (
			select u.vessel, count(u.id) as cnt_ua from sch_useradd u group by vessel
			) ua on (v.Name = ua.vessel)             
      
    where 
      1 = 1 and v.Name like concat('%', #{vsllk}, '%') and
      ukfld like concat('%', #{imolk}, '%')
      <if test="isModOnly">
        and is_manadd = 1
      </if>
    ) a
    order by
      ${sidx} ${sord}  
    limit ${skip}, ${pgrec}  
  </select>

[ 使っているテーブル ]

船マスタ


CREATE TABLE `vessel2` (
	`Name` VARCHAR(36) NOT NULL DEFAULT '' COMMENT '船名',
	`call` VARCHAR(9) NOT NULL DEFAULT '' COMMENT '無線局呼出符号',
	`Year` SMALLINT(6) NOT NULL DEFAULT '0' COMMENT '建造年',
	`Speed` FLOAT NOT NULL DEFAULT '0' COMMENT '速力',
	`TEU` SMALLINT(6) NOT NULL DEFAULT '0' COMMENT '積載TEU',
	`GrossT` INT(11) NOT NULL DEFAULT '0' COMMENT 'グロス重量',
	`DeadW` INT(11) NOT NULL DEFAULT '0' COMMENT '重量重量',
	`Cntry` VARCHAR(2) NOT NULL DEFAULT '' COMMENT '船籍国コード',
	`ukfld` INT(11) NOT NULL DEFAULT '0' COMMENT 'IMOコード',
	`tm_add` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '追加時刻',
	`tm_updt` DATETIME NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '最終更新時刻',
	`is_manadd` TINYINT(4) NOT NULL DEFAULT '0' COMMENT 'ユーザー更新フラグ',
	`ChgName` VARCHAR(36) NOT NULL DEFAULT '0' COMMENT '参照結合用変換船名',
	PRIMARY KEY (`ukfld`),
	INDEX `vessel2_Name` (`Name`),
	INDEX `vessel2_ChgName` (`ChgName`)
)
COMMENT='船マスタ (利用)'
COLLATE='utf8_general_ci'
ENGINE=MyISAM

一時テーブル (一部)

・ID_SESSION はTomcatのセッションIDでユーザー別
・ほっておくと肥大するので、夜中に全レコード削除


CREATE TABLE `tmp_imo_teu` (
	`ID` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'シーケンス番号',
	`ID_SESSION` VARCHAR(70) NOT NULL DEFAULT '' COMMENT 'WEBサーバーセッションID',
	`NM_GRID` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'jqGridグリッドID',
	`IMO` INT(11) NOT NULL DEFAULT '0' COMMENT 'IMOコード',
	`TM_ADD` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '追加時刻',
	PRIMARY KEY (`ID`),
	INDEX `tmp_imo_ID_SESSION` (`ID_SESSION`),
	INDEX `tmp_imo_NM_GRID` (`NM_GRID`),
	INDEX `tmp_imo_IMO` (`IMO`)
)
COMMENT='船スペック検索用IMO一時テーブル'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5627
;

CREATE TABLE `tmp_imo_year` (
	`ID` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'シーケンス番号',
	`ID_SESSION` VARCHAR(70) NOT NULL DEFAULT '' COMMENT 'WEBサーバーセッションID',
	`NM_GRID` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'jqGridグリッドID',
	`IMO` INT(11) NOT NULL DEFAULT '0' COMMENT 'IMOコード',
	`TM_ADD` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '追加時刻',
	PRIMARY KEY (`ID`),
	INDEX `tmp_imo_ID_SESSION` (`ID_SESSION`),
	INDEX `tmp_imo_NM_GRID` (`NM_GRID`),
	INDEX `tmp_imo_IMO` (`IMO`)
)
COMMENT='船スペック検索用IMO一時テーブル'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;

[ 一時テーブル削除追加用SQL ]

・テーブル名を ${tmptbl} のパラメータで渡すことで、まとめてます。


 <!-- マルチセレクト用一時テーブル更新 -->
 <!-- 削除 -->
 <delete id="delIMOTmpAll" parameterType="MyBatisParent">
   delete from ${tmptbl} where ID_SESSION = #{idSession} and NM_GRID = #{nmGrid}
 </delete>
 <!-- 追加 -->
 <insert id="insAIMOTmp" parameterType="MyBatisParent">
   insert into ${tmptbl}
   (ID_SESSION, NM_GRID, IMO)
   select #{idSession}, #{nmGrid}, 
   ukfld
   from ${vslmsttbl}
   where ${vslColumn} between #{insMinVal} and #{insMaxVal}
 </insert>
 <insert id="insAIMOTmpmt" parameterType="MyBatisParent">
   insert into ${tmptbl}
   (ID_SESSION, NM_GRID, IMO)
   select #{idSession}, #{nmGrid}, IMO
   from ${vslmsttbl}
   where ${vslColumn} between #{insMinVal} and #{insMaxVal}
 </insert>

jqGrid フッター、ヘッダーに集計値表示

[ フッター配置例 ]

[ ヘッダー配置例 ]

[ jqGrid コード例 ]

デフォルトはフッター
footerrow, userDataOnFooter を true にする


footerrow: true,
userDataOnFooter: true,

ヘッダーにしたい時は、gridComplete で DOM操作して明細行と合計行の位置を入れ替える


  // フッター合計を上にする, 境界線スタイルを変える //
  var dtlobj = $('#gview_asivlist').children('div').eq(3);   // 明細行
  var fttlobj = $('#gview_asivlist').children('div').eq(4);  // 合計行
  $(fttlobj).css({
    "border-bottom-style": "solid",
    "border-bottom-color": '#008600',
    "border-bottom-width": "2px"
  }).insertBefore($(dtlobj));

[ Servlet コード例 ]

集計値用マップ


    // +++ 結果メッセージ用 +++ //
    HashMap<String, String> usrdata = new HashMap<String, String>();

検索後、集計値を格納


  /**
   * テーブルスキーマ情報取得
   *
   * @param usrdata 合計値マップ
   * @return テーブルスキーマ型リスト
   */
  public ArrayList<TableSchema> getTableSchemaList(HashMap<String, String> usrdata) {

    List list = null;
    try (SqlSession session = sqlSessionFactory.openSession()) {

      list = session.selectList("selTableSchemaList", this);
      System.out.println("getTableSchemaList ():" + list.size());

      // フッター用 //
      // ストリームで合計を格納 //
      ArrayList<TableSchema> slist = new ArrayList(list);
      int cntRow = (int)slist.stream().count();    // 件数 long なので intにキャスト     
      int colTotal = slist.stream().mapToInt(v -> v.getCntCol()).sum();     // 列数
      int rowTotal = slist.stream().mapToInt(v -> v.getCntRow()).sum();     // 行数
      int totalTotal = slist.stream().mapToInt(v -> v.getLenTotal()).sum(); // 合計サイズ
      int dataTotal = slist.stream().mapToInt(v -> v.getLenData()).sum();   // データサイズ
      int indexTotal = slist.stream().mapToInt(v -> v.getLenIndex()).sum(); // インデックスサイズ
      
      // HashMapに追加 //
      usrdata.put("cntCol", String.valueOf(colTotal));
      usrdata.put("cntRow", String.valueOf(rowTotal));
      usrdata.put("lenTotal", String.valueOf(totalTotal));
      usrdata.put("lenData", String.valueOf(dataTotal));
      usrdata.put("lenIndex", String.valueOf(indexTotal));
      usrdata.put("comment", "    Total " + String.valueOf(cntRow) + " Tables" );
      
    }
    catch (Exception se) {
      se.printStackTrace();
    }
    return new ArrayList(list);

  }

応答JSONのセット


    // +++ 結果返却用 +++ //
    JSONResultGrid loggrid = new JSONResultGrid();
    loggrid.setPage(1);
    loggrid.setTotal(1);
    loggrid.setRows(loglist);
    loggrid.setUserdata(usrdata);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String gsonstr = gson.toJson(loggrid);

応答データ


  "userdata": {
    "cntRow": "27494440",
    "lenTotal": "4135942",
    "cntCol": "1689",
    "lenData": "2479938",
    "comment": "    Total 173 Tables",
    "lenIndex": "1656004",
    "sidx": "1"
  }

ケータイ用インドネシア語辞書

昔、インドネシア語を勉強してた時期があり、ふさわしい電子辞書がないので、自作しました。
国内でインドネシア語を勉強してる人、日本人インドネシア駐在員の方々、在日インドネシア人の人達にご好評で、一時期、多数のアクセスがありましたが、最近はガラケー利用者が少ないのか、時代遅れなのか、過疎な状態です。

URL : 2020年3月リニューアルしました

特徴としては、

1) 印 => 日 検索で、ローマ字が出る
2) 日 => 印 検索で、ひらがな、ローマ字が使える
3) 検索結果を一時的に記憶して、一覧で見れる

だけです。

上画面例訳語を見て、初めて知った言葉、polisi tidur は、警察 : 睡眠 が日本語訳になり、面白い表現で少し笑えます。

辞書データは下サイトの運営者作成のを、使わせて頂いてます。

http://www.geocities.jp/indo_ka/bahasa/id_soft.htm

JAVA 改良版 クラス指定デバッグ出力メソッド (JSON)

デバッグする時、NetBeansのデバッグで止めてチェックしたりするのが、じゃまくさく、時間かかるので、止めてみて終了させる必要ない場合用に、System.out.println() で見れるようにしてます。

昔作った、obj.getClass().getDeclaredFields()でのループ型で配列がとれない欠点があり、JSON出力にしてます。
null, getterのないフィールドがとれない欠点がありますが、PHPの var_dump() みたいなこと出来て便利です。

[ 出力例 ]


===============================
Time : 2019-01-08 19:16:29.204
Class : vesselsch.Polygon
Comment : ポリゴン追加
-------------------------------
{
  "lats": [
    35.68114829375634,
    35.680799702175534,
    35.6783595184685,
    35.67561015535696,
    35.67561015535696,
    35.67700460322533,
    35.677771539167104,
    35.678956789306746,
    35.679026509354955,
    35.68114829375634,
    35.68114829375634
  ],
  "lons": [
    139.97815035776364,
    139.98261355356442,
    139.98287104562985,
    139.98201273874508,
    139.9794378180908,
    139.97892283395993,
    139.9801244635986,
    139.9801244635986,
    139.97840784982907,
    139.97815035776364,
    139.97815035776364
  ],
  "id_poly": 0,
  "nm_poly": "1916",
  "cd_unlo": "JPFNB",
  "tp_poly": "CY",
  "nm_route": "",
  "cnt_corner": 0,
  "latmid": 0.0,
  "lonmid": 0.0,
  "m_depth": 0.0
}

[ コード例 ]


      // JSONデコードはリフレクションで行う //  
      Polygon PL = new Polygon();
      Gson gson = new GsonBuilder().setPrettyPrinting().create();
      Type type = new TypeToken<Polygon>() {
      }.getType();
      PL = gson.fromJson(jsn, type);
      // デバッグ出力 //
      FieldValuePrint fvp = new FieldValuePrint(PL, "ポリゴン追加");

[ 出力用クラス ]


package vesselsch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang.time.DateFormatUtils;

/**
 * 指定クラスJSON出力
 * @author 田中尚
 */
public class FieldValuePrint {
  
  private Object obj;
  private String comment;
  
  /**
   * 引数付コンストラクタ
   * @param obj クラスオブジェクト 
   */
  public FieldValuePrint(Object obj) {  
    this.obj = obj;
    this.printToJSON();
  }
  
  /**
   * 引数付コンストラクタ
   * @param obj クラスオブジェクト
   * @param comment コメント
   */
  public FieldValuePrint(Object obj, String comment) {  
    this.obj = obj;
    this.comment = comment;
    this.printToJSON();
  }
  
  /**
   * クラスのフィールド名、フィールド値一覧チェック出力
   *
   */
  public void printToJSON() {

    // JSON出力 //
    Gson gsondbg = new GsonBuilder().setPrettyPrinting().create();
    System.out.println("===============================");
    System.out.println("Time : " + DateFormatUtils.format(new java.util.Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
    System.out.println("Class : " + this.obj.getClass().getCanonicalName());
    if (this.comment != null) {
      System.out.println("Comment : " + this.comment);
    }
    System.out.println("-------------------------------");
    System.out.println(gsondbg.toJson(this.obj));

  }

}

[ 送信データ画面例 ]