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) ヒープメモリ使用量のチェックとガベージコレクションの実行

CentOS7系 6系より便利なところ

基本的に設定ファイルをいじる方式から、コマンドで設定を変更する方式に変わってきてる。

1)  systemd で起動、終了、自動起動、ステータスがわかりやすい。自作サービスも作りやすい

2) firewalld でファイアウォールの設定がやりやすい

3) nmtui, nmcui のネットワーク設定が便利

詳しくはこちらのリク: https://qiita.com/sion_cojp/items/115e1671fcbc8f214aee 

https://liginc.co.jp/343687

 

HttpFox を使い続ける

FireFoxの定番プラグインのHttpFoxを長年使ってましたが、Ver60以降、Quantamになってから、使えなくなったので、WaterFoxをNetBeansのデフォルトブラウザにして使い続けてます。

レスポンスボディ、Postパラメータのチェックとか、JSON, AJaxを使ってると頻繁に行う必要あり、開発ツールに比べ、シンプルで見やすいです。

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)のフラグ記述の変更だけで本番で動く