JAVA クラス指定デバッグ出力メソッド

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

[ 出力例 ]

===============================
Class : vesselsch.Polygon
——————————-
lats : [D@de31cc6
lons : [D@2cdf0ade
polynm : null
latsList : null
lonsList : null
id_poly : 0
nm_poly : 謎の海域ふな
cd_unlo : JPFNB
tp_poly : OT
nm_route :
cnt_corner : 0
latmid : 0.0
lonmid : 0.0
m_depth : 0.0
===============================

配列型がとれてないので、改良予定

[ クラス例 ]


package vesselsch;

import java.util.ArrayList;
import java.util.Arrays;


/**
 * GoogleMap 多角形型
 * @author 田中尚
 */
public class Polygon {
  
  private double[] lats;      // 座標緯度
  private double[] lons;      // 座標経度
  private String polynm;
  
  private ArrayList<Double> latsList = null;    // 未使用
  private ArrayList<Double> lonsList = null;    // 未使用
  
  private int id_poly;
  private String nm_poly;
  private String cd_unlo;
  private String tp_poly;
  private String nm_route;
  
  private short cnt_corner;
  private double latmid;
  private double lonmid;
  
  private float m_depth;       // 水深

[ 埋め込み例 ]

JSONリクエストのセット状況


    // JSONデコードはリフレクションで行う // 
    PolygonDtl POD = new PolygonDtl();
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    Type type = new TypeToken<PolygonDtl>() {
    }.getType();
    POD = gson.fromJson(jsn, type);

    // Javascriptで"が消せないので //
    //POD.setCd_facil(POD.getCd_facil().replaceAll("\"", ""));
    if (POD.getCd_facil() != null) {
      if (POD.getCd_facil().equals("")) {
        POD.setCd_facil("ZZZZZ");
      }
      else {
        POD.setCd_facil(POD.getCd_facil().substring(0, 5));
      }
    }

    // -- debug
    MyBatisParent mb = new MyBatisParent();
    mb.printFieldValueList(POD);

Tomcat 他ユーザー所有のディレクトリにファイルが書き込めない時の対応

Tomcat9 からTomcatが他ユーザーのディレクトリにデフォルトでファイル書込み出来なくなってるので、startup.shを変更してます。
書込みパーミッションのマスクを外す


export UMASK="0022"

Linux ファイル権限について : https://qiita.com/shisama/items/5f4c4fa768642aad9e06

Tomcat ヒープメモリの設定

 

 

setenv.sh に記述

[root@???? ????]# lv setenv.sh

#JAVA_OPTS="-Xms4096m -Xmx8192m -XX:MaxPermSize=4096m -verbose:gc -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true"
CATALINA_OPTS="-Xms6144m -Xmx6144m -XX:PermSize=2048m -XX:MaxPermSize=4096m -XX:-UseGCOverheadLimit -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true"

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

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

楽天で購入

 

 

JAVA jps jstat の利用と応用

1) jps コマンドで、今動いてるJAVAのプロセスを確認

2) jstat で Javaのメモリ使用状況を確認

3) メモリ使用状況のログ追加と、警告メール配信

[ ログテーブルのスキーマ ]


sqlite> .schema log_jstat
CREATE TABLE log_jstat (
tm timestamp not null,
pid integer not null,
pnm text not null,
S0C real not null, 
S1C real not null,
S0U real not null,
S1U real not null,

EC real not null,
EU real not null,
OC real not null,
OU real not null,
ttlCapM integer not null default 0, 
ttlUseM integer not null default 0,
ttlRT   integer not null default 0);
CREATE INDEX log_jstat_tm on log_jstat (tm);
CREATE TRIGGER log_jstat_ai after insert on log_jstat for each row
begin
update log_jstat
set
ttlCapM = cast((S0C + S1C + EC + OC) / 1024 as int),
ttlUseM = cast((S0U + S1U + EU + OU) / 1024 as int),
ttlRT = cast((S0U + S1U + EU + OU) / (S0C + S1C + EC + OC) * 100 as int)
where
tm > current_date || ' 00:00:00';
end;
sqlite> 

[ Shellコードサンプル ]


#! /bin/bash

# --------------------const ------------------------ #

TMP_OUT_FILENAME_JPS=/home/sqlite/sql/jps.txt
TMP_OUT_FILENAME_JSTL=/home/sqlite/sql/jstl.txt

SQL_OUT_FILENAME=/home/sqlite/sql/tmp_jstl_add.sql
DBNAME=/home/sqlite/logs
INSERT_DML="insert into log_jstat (tm, pid, pnm, S0C,S1C,S0U, S1U, EC, EU, OC, OU) values (datetime('now','localtime'), "
echo $INSERT_DML

LAST_URATIO_SQL="SELECT mount, uratio FROM log_df ORDER BY tm DESC LIMIT 0, 3;"
LAST_URATIO_SQL_FILENAME=/home/sqlite/sql/lastgcratio.sql

GC_OUT_TEXTFILENAME=/home/ApacheDoc/APIStatus/tmpgcres.txt

LAST_URATIO_RES_FILENAME=/home/sqlite/sql/lastdf.txt
LAST_URATIO_RES_FILENAME2=/home/sqlite/sql/lastdf2.txt

WARN_TEMPLATE_FILENAME=/home/ssmtptxt/dfwarn.txt
WARN_TMP_FILENAME=/home/ssmtptxt/tmp_dfwarn.txt
WARN_TMP_FILENAME2=/home/ssmtptxt/tmp_dfwarn2.txt

MAX_ALLOWED=89

# ---------------------------------------------------- #

fmtnow=`date +%Y-%m-%d' '%H:%M:%S -d today`
echo "------------------- "$fmtnow" -------------------"

/usr/bin/jps | grep Bootstrap > ${TMP_OUT_FILENAME_JPS}
cat ${TMP_OUT_FILENAME_JPS}

#exit 0

# Write temporaly SQL file ##

echo -n > ${SQL_OUT_FILENAME}

pid=""
pnm=""
jstatres=""
inssql=""
cat ${TMP_OUT_FILENAME_JPS} | while read line
do
  pid=`echo ${line} | gawk '{print $1}'`
  pnm=`echo ${line} | gawk '{print $2}' | sed -e 's/^/"/' -e 's/$/"/'`
  echo ${pid} ${pnm} 

  jstatres=`jstat -gc ${pid} | grep -v S0C | gawk '{print $1","$2","$3","$4","$5","$6","$7","$8}'`
  #echo ${jstatres} 
  inssql=${INSERT_DML}${pid}","${pnm}","${jstatres}");"


  echo ${inssql} >> ${SQL_OUT_FILENAME}
done

cat ${SQL_OUT_FILENAME}
#exit 0


# Write sqlite database #
/usr/bin/sqlite3 ${DBNAME} < ${SQL_OUT_FILENAME}


# Output last res by sqlite (uratio updated by trigger) #
/usr/bin/sqlite3 $DBNAME < ${LAST_URATIO_SQL_FILENAME} > ${GC_OUT_TEXTFILENAME}

exit 0

echo "--- each uratio ---"
#cat ${LAST_URATIO_RES_FILENAME}
#cat ${LAST_URATIO_RES_FILENAME} | sed -e 's/|/;/g'  > ${LAST_URATIO_RES_FILENAME2}
#exit 0

# Loop and send a mail #
tmpmp=""
tmprt=0
wrntxt=""
wrncnt=0
while read line
do
  #echo ${line}

  tmpmp=`echo ${line} | gawk -F"|"  '{print $1}'`
  tmprt=`echo ${line} | gawk  -F"|" '{print $2}'`
  echo ${tmpmp}":"${tmprt}

  if [ ${tmprt} -gt ${MAX_ALLOWED} ]; then
    wrntxt=${wrntxt}${tmpmp}":"${tmprt}"%zzzzz"
    #wrntxt=`echo -e ${wrntxt}${tmpmp}" : "${tmprt}"%  \n"`
    #wrntxt=`echo ""${wrntxt}`
    let wrncnt++
  fi

done < ${LAST_URATIO_RES_FILENAME}

# send a mail by ssmtp #
if [ $[wrncnt] -gt 0 ]; then
  cp ${WARN_TEMPLATE_FILENAME} ${WARN_TMP_FILENAME}
  echo ${wrntxt} >> ${WARN_TMP_FILENAME}
  cat ${WARN_TMP_FILENAME} | sed 's/zzzzz/\n/g' > ${WARN_TMP_FILENAME2}

  echo "" >> ${WARN_TMP_FILENAME}
  echo "Issued Time : "`date`  >> ${WARN_TMP_FILENAME}

  /usr/sbin/ssmtp -t < ${WARN_TMP_FILENAME2}
fi

echo "------------------------------------------------"



4) cronにセットしてスケジュール実行


## Intervaled jstat log add ##
1,21,41 * * * * root /home/sh/jstatcheck.sh >> /home/Log/last_jstatlogadd.log 2>&1

5) メモリ使用状況ログをページで表示

POI が激遅くTomcat が停止した時の改修

レコード数、列数の多いPOIでのエクセル出力は、どうしても遅くなりがちですが、Javaのヒープ上限を超えて、エラーで出力不能となったことがあり、直しました。

[ コードサンプル ]
org.apache.poi.xssf 以下に替えて、org.apache.poi.ss 以下のAPIをインポート


import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;
import org.apache.poi.ss.usermodel.WorkbookFactory;

テンプレート読込


  /**
   * テンプレート読込
   *
   * @throws IOException ファイル読込みエラー
   */
  public void readTemplate() throws IOException {

    try {
      InputStream fi = new FileInputStream(new File(exTmplFName));
      this.wb = WorkbookFactory.create(fi);
    }
    catch (Exception e) {
      e.printStackTrace();
    }

  }

エクセルオブジェクト



    private Workbook wb = null;

    Sheet sheet = null;
    Cell cell = null;

    sheet = this.wb.getSheetAt(0);
    Row row = sheet.getRow(1);

MyBatis 大量連続更新時のパフォーマンス向上策

 

 

 

sqlSessionFactory.openSession の引数に ExecutorType.BATCH を入れてます。

[ コードサンプル ]


  /**
   * MyBatisセッションファクトリー
   */
  protected SqlSessionFactory sqlSessionFactory = null;

  /**
   * マルチ選択用ファイル分類一時テーブル削除追加
   */
  protected void delinsFileTmpTable() {

    try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
      // -- ファイル分類一時テーブル更新 -- //
      // 削除 //
      session.delete("delTmpFileList", this);
      // 追加 //
      for (String nmf : this.fileextList) {
        this.nmFile = nmf;
        session.insert("insATmpFileList", this);
      }
      session.commit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }

  }

 

Tomcat 管理ツールは probe 一択

Tomcat9系 でも使えてます。

よく使う機能

1) アプリケーション単位での停止、起動 (Tomcat再起動しなくても一瞬でできる)

2) データソースの確認と接続チェック

3) 接続セッションの確認、切断

4) 配備後のJSPの全コンパイル

5) ヒープメモリ使用量のチェックとガベージコレクションの実行

JAVA 本番環境リリース時変更をなくす (プロキシサーバー)

開発環境がプロキシなし, 実行環境がプロキシありの場合、そのままでは動かないので、違う設定する必要ありますが、最小限に済ます方法です。
プロキシの設定は、httpclient, seleniumのconnect, jsoupのconnect, curlのシェル実行とかで多用するので、どこに居ても開発がはかどります。

1) web.xmlに使うか使わないかを設定


   <!-- Use proxy or not for curl command -->
  <context-param>
    <param-name>IsUseProxy</param-name> <param-value>0</param-value>
  </context-param>

2) 判別と、使う場合のcurlコマンドに使う引数を、静的設定用クラスに定義


  /**
   * プロキシ利用フラグ
   */
  public static boolean isUseProxy = false;
  /**
   * curl用プロキシ引数
   */
  public static final String ARG_PROXY_CURL = "--proxy http://10.70.1.80:8080";

3) JSPでの利用例


  // クレジットバランス用 //
  ServletContext cntxt = getServletContext();
  String crblcURL = cntxt.getInitParameter("CreditBalanceURL");
 
  crblc.setIsUseProxy(DBini.isUseProxy);

  crblc.setUrl(crblcURL);
  String crrest = crblc.getCreditBalance();
  pageContext.setAttribute("crrest", crrest);

        // == ツールバー == //
        var htmlds = 'From ' + "${dtpcsumsel}" +
                '<span style="margin-left:12px;">' + '${crrest}' + '</span>';
        $('#t_pcsum').prepend(htmlds); // 後でリフレッシュボタンを付けてるのでprepend

  /**
   * curlでクレジットバランス取得
   *
   * @return 文字列
   */
  public String getCreditBalance() {

    int res = 0;
    String proxy = this.isUseProxy ? DBini.ARG_PROXY_CURL: "";

    // コマンド文字列作成 //
    String curcmd = "curl -k --connect-timeout 5 " + proxy + " " + url;
    System.out.println(curcmd);

    String restxt = "";
    try {

      Runtime runtime = Runtime.getRuntime();
      Process p = runtime.exec(curcmd);
      InputStream is = p.getInputStream();

      // レスポンス取得 //
      int nread;
      byte[] rbuf = new byte[500];
      while ((nread = is.read(rbuf)) > 0) {
      }
      restxt = new String(rbuf, "US-ASCII");

    }
    catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println(restxt);

    String blctxt = "";
    if (restxt != null) {
      int crblcstpos = restxt.indexOf("CREDIT_BALANCE=\"");
      int lastchgpos = restxt.indexOf("\" LAST_CHARGED");
      if (crblcstpos != -1 && lastchgpos != -1) {
        blctxt = restxt.substring(crblcstpos + 16, lastchgpos);
      }
      if (blctxt.indexOf("Connection timed out") > -1) {
        blctxt = "TimedOut";
      }
      if (blctxt.equals("")) {
        blctxt = "No Response";
      }
      return blctxt;
    }
    // エラー //
    else {     
      return "Error";
    }
  }

4) Servletでの利用例


    // コマンド //
    String curlcmd = "curl -k " + (DBini.isUseProxy ? DBini.ARG_PROXY_CURL: "")
            + (isSimple ? DBini.vesselPositionURLSimple : DBini.vesselPositionURL) + imo;
    System.out.println(curlcmd);

    // 開始時間取得 //
    long startTime = System.currentTimeMillis();

    VesselPosition vsp = new VesselPosition(DBini.tmNowFmt());

    String restxt = "";
    try {

      Runtime runtime = Runtime.getRuntime();
      Process p = runtime.exec(curlcmd);
      InputStream is = p.getInputStream();

      // レスポンス取得 //
      int nread;
      byte[] rbuf = new byte[2048];
      while ((nread = is.read(rbuf)) > 0) {
      }
      restxt = new String(rbuf, "US-ASCII");

    }
    catch (Exception e) {
      e.printStackTrace();
      vsp.setResmsg(this.FAIL_MESSAFE);
    }

JAVA 本番環境リリース時変更をなくす (ファイルアップロード)

開発環境がWindows, 実行環境がLinuxの場合、そのままでは動かないので、違う設定する必要ありますが、最小限に済ます方法です。

1) web.xmlの記述で、URIを違えた2種類の設定を入れる (アノテーションでも出来ると思うが慣れてないので)


  <!-- ***** Excel Goods master upload **** -->
  <!-- Windows -->
  <servlet>
    <servlet-name>ExcelCheckWin</servlet-name>
    <servlet-class>dnksg.svlt.mstupld.ExcelCheck</servlet-class>
    <multipart-config>
      <max-file-size>-1</max-file-size>
      <max-request-size>-1</max-request-size>
      <file-size-threshold>0</file-size-threshold>
      <location>D:\\#NBTest\\dnksgDocumentTmp</location>
    </multipart-config>
    <init-param>
      <param-name>UploadPath</param-name>
      <param-value>D:\\#NBTest\\dnksgDocumentTmp\\</param-value>
    </init-param>
  </servlet>
  
  <!-- Linux -->
  <servlet>
    <servlet-name>ExcelCheckLin</servlet-name>
    <servlet-class>dnksg.svlt.mstupld.ExcelCheck</servlet-class>
    <multipart-config>
      <max-file-size>-1</max-file-size>
      <max-request-size>-1</max-request-size>
      <file-size-threshold>0</file-size-threshold>
      <location>/home/dnksgDocumentTmp</location>
    </multipart-config>
    <init-param>
      <param-name>UploadPath</param-name>
      <param-value>/home/dnksgDocumentTmp/</param-value>
    </init-param>
  </servlet> 
  
  <!-- Windows -->
  <servlet-mapping>
    <servlet-name>ExcelCheckWin</servlet-name>
    <url-pattern>/ExcelCheckWin</url-pattern>
  </servlet-mapping>
  
  <!-- Linux -->    
  <servlet-mapping>  
    <servlet-name>ExcelCheckLin</servlet-name>
    <url-pattern>/ExcelCheckLin</url-pattern>
  </servlet-mapping>  

2) JSPでファイルセパレータからWindows or Linuxを判別して、pageContextにセット


// Linux or Windows //
  boolean isLin = System.getProperty("file.separator").equals("/");
  pageContext.setAttribute("LW", isLin ? "Lin" : "Win");

3) 2)をJavascriptのconstな変数にセット


    <script type="text/javascript">

      const LW = '${LW}';

4) dropzone.js の 送信先URL末尾で 3)を使う


 // 送信先URL //
  const UPLOAD_URLS = ['ImageUpload', 'FileUploadMulti', 'FileUploadMulti', 'AmazonDocUpload'];
$('#' + itm).dropzone({
      url: UPLOAD_URLS[j] + LW + "?dropzone=1&userid=" + ID_USER + UPLOAD_KIND_PARAMS[j],
[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

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

JAVA 本番環境リリース時変更をなくす (MyBatis Datasource)

開発環境がWindows, 実行環境がLinuxの場合、そのままでは動かないので、違う設定する必要ありますが、最小限に済ます方法です。

1)  環境設定用xmlは、UNPOOLED (Windows開発環境) と JNDI (Linux本番環境)の2種類を用意。

開発用


    <environment id="ocean">
      <transactionManager type="JDBC"/>
      <dataSource type="UNPOOLED">
        <property name="driver" value="${msdriver}"/>
        <property name="url" value="${msurl}"/>
        <property name="username" value="${msusername}"/>
        <property name="password" value="${mspassword}"/>
      </dataSource>
    </environment>

本番用


    <environment id="ocean">
      <transactionManager type="JDBC"/>
      <dataSource type="JNDI">
        <property name="data_source" value="java:comp/env/jdbc/ocean2"/>
      </dataSource>
    </environment>

2) web.xml の context に判別できる記述をしておく


  <!-- Datasource JNDI pooled or Unpooled -->
  <context-param>
    <param-name>IsDSJNDI</param-name>
    <param-value>0</param-value>
  </context-param>

3) Startupのサーブレットで、2)を読み、public static な変数に入れておく
静的設定クラス


  /**
   * Mybatis設定
   */
  public static final String MB_RESOURCE = "vesselsch/mybatis/SqlMapConfigLocal.xml";       // 開発用、DRバックアップ用
  public static final String MB_RESOURCE_JNDI = "vesselsch/mybatis/SqlMapConfigJNDI.xml";   // サービス用
  public static boolean isDSJNDI = false;

Startup


ServletContext cntxt = getServletContext();
// データソースがJNDIかどうか //
DBini.isDSJNDI = cntxt.getInitParameter("IsDSJNDI").equals("1");

4) sqlSessionFactory の生成にあたって、リソース読込で 3)を使う


 /**
   * MyBatis SQLセッションファクトリ
   */
  protected SqlSessionFactory sqlSessionFactory = null;
  /*
  コンストラクタ
  */
  public MyBatisParent() {

    // MyBatis //
    try {
      // 開発環境 or サービス環境で違える UNPOOLED or JNDI //
      InputStream inputStream = Resources.getResourceAsStream(DBini.isDSJNDI ? DBini.MB_RESOURCE_JNDI : DBini.MB_RESOURCE);
      sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    catch (IOException ie) {
      ie.printStackTrace();
    }

  }

5) 4) は親クラスのコンストラクタで行い、継承された子クラスでの個別設定はなくす
利用例


  public ArrayList<ExRate> selectExRateSheet() {

    List list = null;
    try (SqlSession session = sqlSessionFactory.openSession()) {
      list = session.selectList("selExRate", this);
      System.out.println("selectExRateSheet:" + list.size());
    }
    catch (Exception se) {
      se.printStackTrace();
    }
    return new ArrayList(list);

  }

6) 結果、2)のフラグ記述の変更だけで本番で動く