20200107のJavaに関する記事は9件です。

Arthas Java 診断ツール

Arthasとは何でしょう?

Arthas(読み方:アーサス)はAlibabaがオープンソースとして公開したJava診断ツールです。
開発環境、試験環境、本番環境で、JVMの状態をモニターしたり、障害が発生した時に、JVMを落とさず簡単に診断ができる。jconsole jmap jstackなどJDKツールより強力で、使いやすくできている。

どういう問題を解決できるのか?

・このクラスはどのJarからロードされているか確認したい!なぜ例外が発生したか?
・私がコミットしたコードが実行されてなかった気がするけど。。。コミットし忘れ?もしかしてブランチを間違った?
・オンラインでデバッグできないので、ログを仕込んで再配備するしかない?
・本番のあるユーザのデータ処理に問題あったが、本番ではデバッグできないし、ローカルでは再現しない!どうしよう?
・今JVMってどういう状況なの?
・リアルタイムでJVMの状況を把握したい!
・FlameGraphを描画してボトルネックを見つけたい!
など様々なシーンで活用できると思います。

ライセンス

Apache-2.0

環境

JDK 6以上
Linux/Mac/Windows

インストールと実行

Linux環境:
wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar

実行中のJavaプロセスが存在する場合、起動できる。
特定のJavaプロセスを監視したい場合は
jpsで現在実行中プロセスを確認し、そのPIDをパラメータとして渡せばいい。
例:

jps
341 Bootstrap

java -jar arthas-boot.jar 341

以下のような画面が表示され、シェルのようにarthasの各種コマンドを実行することができます。

p1.jpg

オフィシャルサイトでは以下のコマンドで現在のパスにインストールし、実行ファイルas.shも自動で生成するらしい。普段診断ツールとして使うならこちらがおすすめです。

curl -L https://alibaba.github.io/arthas/install.sh | sh
./as.sh

Arthasコマンド

dashboard

dashboard.png

シェル環境でこんな画面が表示できちゃうと正直すこし感動しますね。
上は現在JVMインスタンス内のスレッド一覧、真ん中の左側はメモリ状況、その右側はGC情報、一番下はOS、JVMのバージョン情報など。Tomcatの場合は性能の概要が見えます。

thread

現在のJVMプロセス内のスレッド一覧とそれぞれの状態を表示できます。

thread.png

さらにスレッド番号指定するとスタックトレースが表示できていまどこのメソッドで止まっているか見えます。

thread1.png

jad

現在実行中のクラスに対してデコンパイルができます。バグ対応のため、コードを修正したが、本当に修正版が動いているかどうか確認することができます。また、ミスって同じJarモジュールの異なるバージョンを両方ともクラスパスに入っちゃった場合、どれが実際ロードされているか確認できます。

jad1.jpg
p2.jpg

redefine

外部の.classフアイルを読み込み、現在実行中のJVM内のクラスを差し替えることができる。
制限:クラスのフィールドの新規、メソッドの新規はできない。変更は可能。
JVMを再起動せず、Tomcatの場合は、再起動、再ロードせず、クラスのロジックを変更することが来ます。おお~

redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class

sc

現在JVMにロードされたクラスの情報を表示。

sc.png

stack

スタックトトレースの確認

以下test.arthas.TestStack#doGetのスタックトレースを確認する場合

stack.jpg

trace

どのメソッドが遅いか。ボトルネック、性能調査で使えそうですね。

trace.jpg

その他

web console機能があってWebでarthasのコマンドを実行できるので、複数サーバを診断するときに使えそうですね。
他にもいろいろ使えそうなコマンドがたくさんありますので、詳しくは
こちらを参考してください。
https://github.com/alibaba/arthas

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Selenium InvalidSelectorExceptionエラーの対処法

Seleniumを使っていて、InvalidSelectorException エラーが出た場合の対処法

エラーの原因の1つにクラス名にスペースが入っている状態で要素取得しようとする場合に出ます。
例えば、クラス名が"class name"となっている要素の取得をしようと下記のように記述したとします。

driver.findElements(By.className("class name"));

Seleniumでは、クラスやidなどの属性値にスペースが入っているため
このままだとエラーになるので、
少し記述方法を変えることで要素が取得できるようになります。

driver.findElement(By.cssSelector("div[class='class name']"));

というように、cssSelectorを使ってタグ名と属性名、属性値を記述すれば要素を取得できます。

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring BootでFeatureToggleを実現するライブラリff4jの紹介

Feature Toggleとは

※ 基本的な話なのでご存知の方はすっ飛ばしてください
FeatureToggleとは、簡単に言えばある機能をオンにしたりオフにしたりする条件分岐のことです。FeatureFlagと呼ばれたりもします。

例えば下記のように、ある新しいアルゴリズムを使うためにuseNewAlgorithmというboolean変数を用意し、useNewAlgorithmのtrue/falseに応じて新アルゴリズムと旧アルゴリズムを使い分けるような場面で使います。

  function reticulateSplines(){
    var useNewAlgorithm = false;
    // useNewAlgorithm = true; // UNCOMMENT IF YOU ARE WORKING ON THE NEW SR ALGORITHM

    if( useNewAlgorithm ){
      return enhancedSplineReticulation();
    }else{
      return oldFashionedSplineReticulation();
    }
  }

  function oldFashionedSplineReticulation(){
    // current implementation lives here
  }

  function enhancedSplineReticulation(){
    // TODO: implement better SR algorithm
  }

FeatureFlagはリリースタイミングが決まっている新機能の提供時やカナリアリリース、A/Bテストなどでよく使われます。

FF4J

https://ff4j.github.io/
スクリーンショット 2020-01-07 22.29.42.png

FF4jとはFeatureToggleを簡単に実現できるJavaライブラリになります。

  • Web Console, REST APIによるリアルタイムなToggle切り替え
  • 多様なストレージを利用した状態の永続化
  • Featureの利用状況のモニタリング

といった様々な機能が提供されています。

導入手順

プロジェクトの作成

みんな大好きSpring InitializrからSpring Reactive Web, lombokだけを選んでプロジェクトを作成します。

FF4jの導入

pom.xmlに依存関係を追加します。

pom.xml
<dependency>
    <groupId>org.ff4j</groupId>
    <artifactId>ff4j-spring-boot-starter</artifactId>
    <version>1.8</version>
</dependency>

FF4jのBean定義 & Featureの作成を行います。

FF4JConfiguration.java
import org.ff4j.FF4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FF4JConfiguration {
    @Bean
    public FF4j ff4j() {
        FF4j ff4j = new FF4j()
                .createFeature(awesomeFeature())
                .createFeature(greatFeature())
                .createFeature(excellentFeature());
        return ff4j;
    }

    private Feature awesomeFeature() {
        return new Feature("AwesomeFeature", true);
    }

    private Feature greatFeature() {
        return new Feature("GreatFeature", false);
    }

    private Feature excellentFeature() {
        return new Feature("ExcellentFeature", false);
    }
}

今回はAwesomeFeature, GreatFeature, ExcellentFeatureの3つのFeatureを定義し、AwesomeFeatureだけオンにしています。

FF4jを利用したControllerを実装します。単純なメッセージだけを返すControllerで、定義した3つのFeatureがオンになっている場合そのFeatureに応じてメッセージに追記しています。

GreetingController.java
@RestController
@RequiredArgsConstructor
public class GreetingController {

    // コンストラクタインジェクション
    private final FF4j ff4j;

    @GetMapping
    public String greeting() {
        List<String> features = new ArrayList<>();
        addFeatures(features);
        String greeting = String.format("Hello, %s World!!", String.join(" ", features));

        return greeting;
    }

    // 各Featureの処理
    private void addFeatures(List<String> features) {
        if(ff4j.check("AwesomeFeature")) {
            features.add("Awesome");
        }

        if(ff4j.check("GreatFeature")) {
            features.add("Great");
        }

        if(ff4j.check("ExcellentFeature")) {
            features.add("Excellent");
        }
    }
}

アプリケーションを起動し、http://localhost:8080 にアクセスします。
スクリーンショット 2019-11-28 0.13.29.png

デフォルトではAwesomeFeatureが有効になっているため、メッセージはHello, Awesome World!と表示されます。

WebConsoleの導入

続いて、FF4jの管理コンソールを導入します。さきほどまでの状態だとソースコード上でFeatureのオン/オフを切り替える必要がありましたが、WebConsoleを利用することでアプリケーションの起動中にFeatureのオン/オフを切り替えることが可能となります。

pom.xmlに依存関係を追加します。

<dependency>
    <groupId>org.ff4j</groupId>
    <artifactId>ff4j-web</artifactId>
    <version>1.8</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>2.1.4.RELEASE</version>
</dependency>

新たにBean定義を追加します。

@Configuration
@ConditionalOnClass({ConsoleServlet.class, FF4jDispatcherServlet.class})
@AutoConfigureAfter(FF4JConfiguration.class)
public class FF4JWebConfiguration extends SpringBootServletInitializer {

    @Bean
    public ServletRegistrationBean<FF4jDispatcherServlet> ff4jDispatcherServletRegistrationBean(FF4jDispatcherServlet ff4jDispatcherServlet)
    {
        ServletRegistrationBean<FF4jDispatcherServlet> bean = new ServletRegistrationBean<>(ff4jDispatcherServlet, "/ff4j-web-console/*");
        bean.setName("ff4j-console");
        bean.setLoadOnStartup(1);
        return bean;
    }

    @Bean
    @ConditionalOnMissingBean
    public FF4jDispatcherServlet getFF4jDispatcherServlet(FF4j ff4j) {
        FF4jDispatcherServlet ff4jDispatcherServlet = new FF4jDispatcherServlet();
        ff4jDispatcherServlet.setFf4j(ff4j);
        return ff4jDispatcherServlet;
    }

}

起動して http://localhost:8080/ff4j-web-consoleにアクセスします。
スクリーンショット 2019-11-28 0.15.49.png

「Features」メニューで現在定義されているFeatureを確認することができ、
トグルをオン/オフするのに連動してFeatureがオン/オフになります。

スクリーンショット 2019-11-28 0.17.32.png

GIFアニメーションデモ

上記で説明した内容をGIFアニメーションで撮ったデモも貼っておきます。ご参考程度に。
ff4j-demo.gif

まとめ

FF4jの簡単な紹介をしました。Feature Toggleは強力なテクニックですが運用方針を定めないとカオスなコードベースが生まれてしまうので気をつけて運用したいです。ProfileごとにDIするFeatureをわける、コーディング規約とレビューポイントを定めるといった枠組みが必要になります。

参考

martinFowler.com - FeatureToggle: https://martinfowler.com/articles/feature-toggles.html
FF4j: https://ff4j.github.io/
今回使ったリポジトリ:https://github.com/IshinFUKUOKA/ff4j-demo

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【新年】すべてのプログラマの皆様へ新年のご挨拶【ちょっとした小ネタ】

ただの小ネタです。今年はまだ簡単です。
手元で、さくっと動作確認できた言語だけになっています。
ちなみに、BOMは入っていません。

C#とか

byte[] utf8Bytes = { 0xe4, 0xbb, 0x8a, 0xe5, 0xb9, 0xb4, 0xe3, 0x82, 0x82, 0x31, 0xe5, 0xb9, 0xb4, 0xe3, 0x81, 0x8a, 0xe4, 0xba, 0x92, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0xab, 0xe3, 0x80, 0x81, 0xe6, 0x99, 0x82, 0xe3, 0x81, 0xab, 0xe3, 0x81, 0xaf, 0xe8, 0x8b, 0xa6, 0xe3, 0x81, 0x97, 0xe3, 0x81, 0xbf, 0xe3, 0x81, 0xaa, 0xe3, 0x81, 0x8c, 0xe3, 0x82, 0x89, 0xe3, 0x82, 0x82, 0xe3, 0x80, 0x81, 0xe6, 0xa5, 0xbd, 0xe3, 0x81, 0x97, 0xe3, 0x82, 0x93, 0xe3, 0x81, 0xa7, 0xe3, 0x82, 0xb3, 0xe3, 0x83, 0xbc, 0xe3, 0x83, 0x87, 0xe3, 0x82, 0xa3, 0xe3, 0x83, 0xb3, 0xe3, 0x82, 0xb0, 0xe3, 0x81, 0x97, 0xe3, 0x81, 0xbe, 0xe3, 0x81, 0x97, 0xe3, 0x82, 0x87, 0xe3, 0x81, 0x86, 0xef, 0xbc, 0x81 };

Javaとか

byte[] utf8Bytes = { (byte)0xe4, (byte)0xbb, (byte)0x8a, (byte)0xe5, (byte)0xb9, (byte)0xb4, (byte)0xe3, (byte)0x82, (byte)0x82, (byte)0x31, (byte)0xe5, (byte)0xb9, (byte)0xb4, (byte)0xe3, (byte)0x81, (byte)0x8a, (byte)0xe4, (byte)0xba, (byte)0x92, (byte)0xe3, (byte)0x81, (byte)0x84, (byte)0xe3, (byte)0x81, (byte)0xab, (byte)0xe3, (byte)0x80, (byte)0x81, (byte)0xe6, (byte)0x99, (byte)0x82, (byte)0xe3, (byte)0x81, (byte)0xab, (byte)0xe3, (byte)0x81, (byte)0xaf, (byte)0xe8, (byte)0x8b, (byte)0xa6, (byte)0xe3, (byte)0x81, (byte)0x97, (byte)0xe3, (byte)0x81, (byte)0xbf, (byte)0xe3, (byte)0x81, (byte)0xaa, (byte)0xe3, (byte)0x81, (byte)0x8c, (byte)0xe3, (byte)0x82, (byte)0x89, (byte)0xe3, (byte)0x82, (byte)0x82, (byte)0xe3, (byte)0x80, (byte)0x81, (byte)0xe6, (byte)0xa5, (byte)0xbd, (byte)0xe3, (byte)0x81, (byte)0x97, (byte)0xe3, (byte)0x82, (byte)0x93, (byte)0xe3, (byte)0x81, (byte)0xa7, (byte)0xe3, (byte)0x82, (byte)0xb3, (byte)0xe3, (byte)0x83, (byte)0xbc, (byte)0xe3, (byte)0x83, (byte)0x87, (byte)0xe3, (byte)0x82, (byte)0xa3, (byte)0xe3, (byte)0x83, (byte)0xb3, (byte)0xe3, (byte)0x82, (byte)0xb0, (byte)0xe3, (byte)0x81, (byte)0x97, (byte)0xe3, (byte)0x81, (byte)0xbe, (byte)0xe3, (byte)0x81, (byte)0x97, (byte)0xe3, (byte)0x82, (byte)0x87, (byte)0xe3, (byte)0x81, (byte)0x86, (byte)0xef, (byte)0xbc, (byte)0x81 };

C/C++とか

const char utf8Bytes[] = { (char)0xe4, (char)0xbb, (char)0x8a, (char)0xe5, (char)0xb9, (char)0xb4, (char)0xe3, (char)0x82, (char)0x82, (char)0x31, (char)0xe5, (char)0xb9, (char)0xb4, (char)0xe3, (char)0x81, (char)0x8a, (char)0xe4, (char)0xba, (char)0x92, (char)0xe3, (char)0x81, (char)0x84, (char)0xe3, (char)0x81, (char)0xab, (char)0xe3, (char)0x80, (char)0x81, (char)0xe6, (char)0x99, (char)0x82, (char)0xe3, (char)0x81, (char)0xab, (char)0xe3, (char)0x81, (char)0xaf, (char)0xe8, (char)0x8b, (char)0xa6, (char)0xe3, (char)0x81, (char)0x97, (char)0xe3, (char)0x81, (char)0xbf, (char)0xe3, (char)0x81, (char)0xaa, (char)0xe3, (char)0x81, (char)0x8c, (char)0xe3, (char)0x82, (char)0x89, (char)0xe3, (char)0x82, (char)0x82, (char)0xe3, (char)0x80, (char)0x81, (char)0xe6, (char)0xa5, (char)0xbd, (char)0xe3, (char)0x81, (char)0x97, (char)0xe3, (char)0x82, (char)0x93, (char)0xe3, (char)0x81, (char)0xa7, (char)0xe3, (char)0x82, (char)0xb3, (char)0xe3, (char)0x83, (char)0xbc, (char)0xe3, (char)0x83, (char)0x87, (char)0xe3, (char)0x82, (char)0xa3, (char)0xe3, (char)0x83, (char)0xb3, (char)0xe3, (char)0x82, (char)0xb0, (char)0xe3, (char)0x81, (char)0x97, (char)0xe3, (char)0x81, (char)0xbe, (char)0xe3, (char)0x81, (char)0x97, (char)0xe3, (char)0x82, (char)0x87, (char)0xe3, (char)0x81, (char)0x86, (char)0xef, (char)0xbc, (char)0x81 };

Pythonとか

utf8_bytes = [ 0xe4, 0xbb, 0x8a, 0xe5, 0xb9, 0xb4, 0xe3, 0x82, 0x82, 0x31, 0xe5, 0xb9, 0xb4, 0xe3, 0x81, 0x8a, 0xe4, 0xba, 0x92, 0xe3, 0x81, 0x84, 0xe3, 0x81, 0xab, 0xe3, 0x80, 0x81, 0xe6, 0x99, 0x82, 0xe3, 0x81, 0xab, 0xe3, 0x81, 0xaf, 0xe8, 0x8b, 0xa6, 0xe3, 0x81, 0x97, 0xe3, 0x81, 0xbf, 0xe3, 0x81, 0xaa, 0xe3, 0x81, 0x8c, 0xe3, 0x82, 0x89, 0xe3, 0x82, 0x82, 0xe3, 0x80, 0x81, 0xe6, 0xa5, 0xbd, 0xe3, 0x81, 0x97, 0xe3, 0x82, 0x93, 0xe3, 0x81, 0xa7, 0xe3, 0x82, 0xb3, 0xe3, 0x83, 0xbc, 0xe3, 0x83, 0x87, 0xe3, 0x82, 0xa3, 0xe3, 0x83, 0xb3, 0xe3, 0x82, 0xb0, 0xe3, 0x81, 0x97, 0xe3, 0x81, 0xbe, 0xe3, 0x81, 0x97, 0xe3, 0x82, 0x87, 0xe3, 0x81, 0x86, 0xef, 0xbc, 0x81 ]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaでファイルをコピーするプログラムをbatファイルから動かして毎日やる作業を少しだけ効率化する話

まえがき

社内日誌を毎日提出することになりました。
毎日ファイルをコピーして、今日の日付を入れて、とするのは正直大変。クリック下手だし。

というわけでできるだけ自動化しました。

具体的にはダブルクリック1回でファイル名に日付が入ったコピーが生成されるように。
xlsファイルの中身は弄ってません。それができるライブラリもあるらしいけど、今回は見送り。

使ったのはJavaとbatchファイル。

やりたかったことは一通りできて勉強になったのでよし。

以下説明。

Java

とりあえずプログラム本体から。

プログラム

copyReport.java
package copyReport;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

 public class CopyReport {
    public static void main(String[] args) {
        //デスクトップにフォルダを置いてもらうようにする
        String desktopPath = "C:\\Users\\"+System.getProperty("user.name")+"\\Desktop";
        String folderPath = desktopPath+"\\copyreport";

        //プログラムフォルダ内のファイル名を配列で取得
        File[] files = new File(folderPath).listFiles();

        //コピー元ファイル名を取得。自分の名前に変えられるようにした。
        String baseFileName = "";
        for(File f:files) {
            if(f.getName().matches(".*日報_.*\\.(xls|xlsx|ods)")) {
                baseFileName = f.getName();
            }
        }

        //コピー元ファイルの有無をチェック
        if(baseFileName.isEmpty()) {
            System.out.println("copyreport下にコピー元ファイルが見つかりませんでした。");
            return;
        }
        File baseFile = new File(folderPath,baseFileName);
        if(!baseFile.exists()) {
            System.out.println("コピー元ファイルが見つかりませんでした。");
            return;
        }

        //日付から今日のぶんのファイル名を生成
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("YYYYMMdd"));
        String outFileName = today + baseFileName.substring(baseFileName.lastIndexOf("日報_"));
        System.out.println(outFileName + "としてコピーします。");

        //既にあるかチェックする
        File outFile = new File(desktopPath,outFileName);
        if(outFile.exists()) {
            System.out.println("コピー先ファイルがすでに存在します。");
            return;
        }

        //メッセージを出力
        System.out.println("ファイルをコピーします。");
        System.out.println("コピー元フォルダ名;"+folderPath);
        System.out.println("コピー元ファイル名:"+baseFile.getName());
        System.out.println();
        System.out.println("コピー先フォルダ名;"+desktopPath);
        System.out.println("コピー先ファイル名:"+outFile.getName());

        try {
            //コピー元・コピー先のFileインスタンスからstreamを作成
            FileInputStream fis = new FileInputStream(baseFile);
            FileOutputStream fos = new FileOutputStream(outFile);

            //バッファと読み込みバイト数を管理
            byte[] buf = new byte[256];
            int len=0;
            //ファイルの終わりまでbufずつstreamを読み込んで書き出す
            while((len = fis.read(buf)) != -1) {
                fos.write(buf,0,len);
            }

            //書きそびれの部分を書き出す
            fos.flush();

            //ファイルへのアクセスを終わる
            fos.close();
            fis.close();

            //メッセージ
            System.out.println("ファイルのコピーに成功しました。");

        } catch (FileNotFoundException e) {
            System.out.println("ファイルのコピーに失敗しました。");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("ファイルのコピーに失敗しました。");
            e.printStackTrace();
        }

    }

}

プログラムの説明

広く公開するツールではないので、「デスクトップに直接フォルダを置いて実行させる」つもりで組んであります。

デスクトップの場所

使ってるWindows10のデスクトップの場所はC:\user\(USER名)\Desktopで人によって違うので、それをSystem.getproperty(username)でもらってきて入れる。

File配列

プログラム、コピー元ファイル、実行用batファイルを入れるためのフォルダなので、全体の名前を取得→コピー元ファイルの名前を取得の2段構成。

match条件

(任意の日付項目)日報_(任意の名前).(xlsかxlsxかods)
の正規表現。これに一致したファイルをコピー元ファイル名として取得する。
こうすることで、元のファイル名に自分の名前が入っていればそのままコピーしてくれるようになった。

コピー元の有無チェック

過剰な気がしないでもないが、抜けがあったときのほうが面倒なため。

日付からファイル名を生成

今日の日付を8桁の数字列として取得する。
それをコピー元ファイル名の前半に入れる形でコピー先のファイル名を作る。

コピー先チェック

一度内容を書いた日報が上書きされたら困る(そもそも上書きしなかった気がするけど)ので一応チェック。

ファイルのコピー

今回はFileInputStreamとFileOutoutStreamを使うことにした。
FileInputStreamからlenバイトずつ読み込んだ中身であるbufをFileOutputStreamに流して~、ということらしい。調べたらどの資料にも同じように書いてあったけれど、そのせいでサンプルが少なく仕組みが理解しづらくなっていた。

finally処理

流し切らなかった部分を手動で流したりアクセス終了しておしまい。
Java8以降だとアクセス終了処理とかはやってくれるらしい。

 

というわけでjavaのプログラミングはここまで。あとはEclipseからエクスポートしたりjarをダブルクリックで実行できるようにしたり。

Eclipseでのエクスポート

ファイル→エクスポート→実行可能jarファイル、で流れるままにやる。jarファイル名とプロジェクト名とかメインクラス名とかってどこまで揃えるべきなんでしたっけね。
デスクトップあたりにjarファイルが生成していれば完了。

Java実行環境の構築

JREと呼ばれるやつ。Java Runtime Environmentだったかな。
コマンドプロンプトからjavaを実行(javaコマンド、javacコマンド)するのに必要。

Eclipseがあるなら話が早くて、画面→設定→Java→実行環境からパスを持ってきて、それをPCの環境変数に入れる。
直接java.exeやjavac.exeを指定してもいいらしいけど、今回はそれらが直下にあるフォルダを指定。
一度入れたら入れっぱなしにするものなので、入れることをすっかり忘れていて焦った。

実行の確認

コマンドプロンプトで.jarファイルのあるフォルダから「java -jar copyReport.jar」を動かして動作確認。ファイル名はEclipseからエクスポートした時のもの。

batファイルを作る

適当な名前をつけた.batファイルを作ってメモ帳で編集。
中身こんな感じ

copy.bat
@echo off
cd ./copyreport
java -jar copyReport.jar
timeout 5 

説明

1行目

以降のコマンド入力内容は映さなくていいよ(echo off) の命令を映さなくていいよ(@)

2行目

コンソールの現在位置を起動したフォルダの直下にあるcopyreportフォルダに移動するコマンド。
失敗しても落ちたりしないので安心して実行できる。copyreportフォルダ内にcopyreportって名前のフォルダ失敗するとこの先が動かなくなるってデメリットがあるけど。

3行目

指定したjava系のファイルをjarとしてjavaで実行してくれ

4行目

5秒後にこの画面を閉じるように。
メッセージが出るけど消したい場合は後ろに 「> nul」をつけるらしい。
これの意味は「メッセージの出力先はnulにしてくれ」だそうな。

学習したこと

ファイル操作の復習がてら書いたけどほぼ丸一日かかってしまった。
FileInputStream#readが複雑で、オーバーロードするメソッドしだいでbufとlenの内容がコロコロ化けるらしく、正直とても困った。
実行環境まわりのことはコロコロPCを変えるわけでもないぶん余計に忘れがちなので意識的に気を付けておきたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画面部品の配置

初学者ですが、個人的な勉強の為まとめました

画面部品の配置

Androidアプリの画面は、Android SDKで用意された画面部品を配置することで作成する。これが、.xmlファイルに画面部品タグを記述することである
画面部品については、大きくビューグループビューの2つがある

ビューグループ

ビューグループは、各画面の配置を決めるもので、レイアウト部品とも呼ばれる。以下は、主なレイアウト部品である
 ①<LinearLayout>・・・一番扱いやすいレイアウトで、画面部品を縦/横方向に並べて配置
 ②<TableLayout>・・・表形式で画面部品配置
 ③<GridLayout>・・・グリッド形式で画面部品を配置
 ④<FrameLayout>・・・画面部品を重ねて配置
 ⑤<RelativeLayout>・・・画面部品を相対的に配置
 ⑥<ConstraintLauout>・・・RelativeLayout同様に、画面部品を相対的に配置

 ※RelativeLayoutは、Android2.2まで、プロジェクトを作成した際に生成されるレイアウトXMLの最初に記述されていたものだが、2.3以降はより扱いやすくしたレイアウト部品としてConstraintLayoutが導入され、これが基本レイアウトとなった

ビュー

ビューは、画面部品そのもので、ウィジェットとも呼ぶ
・以下は、代表的なビュー
 ①<TextView>・・・文字列の表示
 ②<EditText>・・・テキストボックス
 ③<Button>・・・ボタン
 ④<RadioButton>・・・ラジオボタン
 ⑤<CheckBox>・・・チェックボックス
 ⑥<Spinner>・・・ドロップダウンリスト
 ⑦<ListView>・・・リスト表示
 ⑧<SeekBar>・・・スライダー
 ⑨<RatingBar>・・・☆でレート値を表現
 ⑩<Switch>・・・ON/OFFが表現できるスイッチ

タグの組み合わせ

・Android画面では、レイアウト部品とビュー部品を階層的に組み合わせて使う
・レイアウト部品は、画面部品の配置を決めるものなので、その配下に画面部品を含んで使う
 例)

activity_view_sample.xml
     <LinearLayout>
         <TextView/>
     </LinearLayout>

・レイアウト部品のような子要素を持つタグは開始タグと終了タグで囲み、ビュー部品は子要素を持たないものが多いので、終了タグを書かず、タグの右カッコの前にスラッシュを入れる、属性のみのタグが基本

よく使われる属性

①android:id

・画面部品のidの設定
・アクティビティ(Javaプログラム)内でこの部品を扱う場合にはIDを記述
@+id/・・・のように記述し、「・・・」の名前で部品にアクセスできる
 例)

activity_view_sample.xml
<TextView
       android:id="@+id/tvLabelInput"

②android:text

・画面部品が表示されるときの文字列を設定
・表示文字列は直接記述せずにstring.xmlに記述するので、string.xmlに記述された文字列と画面部品とを紐付ける方法が@string/・・・である
 例)

activity_view_sample.xml
<TextView
        android:text="@string/tv_msg"/>
string.xml
<string name="tv_msg">お名前を入力してください。</string>

③android:layout-width/height

・widthが部品の幅、heightが高さを表す
・すべての画面部品に記述する必要がある
・~dpのような数値、もしくはwrap_contentmatch_contentなどを使う
・wrap_contentは、必要なサイズに自動調整する
・match_contentは、親部品のサイズいっぱいまで拡張する

④android:margin/padding

・margin/paddingともに余白を表す
・marginは画面外側の余白、paddingは部品の内側の余白

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Project作成ウィザード

初学者ですが、個人的な勉強の為まとめました

Project作成ウィザード

AndoridStudioプロジェクトの作成には、プロジェクト作成ウィザードを使う
以下が、このウィザードを構成する4つの画面

①Create Android Project画面

・以下の、3つの入力欄がある

 1.Application name

 ・アプリ名の入力欄だが、アプリ名というより、プロジェクト名と理解したほうが良い

 2.Project location

 ・プロジェクトファイルを格納するフォルダ
 ・デフォルトでは、<ユーザーのホームフォルダ>¥AndroidStudioProjects配下にプロジェクト名と同名のフォルダが作られる

 3.Company domain

 ・入力内容に応じて自動でPackag nameが記述される
 ・ドメインを逆順にしたものを起点とし、そこにプロジェクト名を加えたものがルートパッケージになる
  例えば、ドメインが「hogehoge.com」,プロジェクト名が「HelloAndroid」の場合は、

com.hogehoge.・・・helloandroid

②Target Android Devices画面

・どの端末向けのアプリを開発するかを選択する画面

③Add an Activity to Mobile画面

・ある程度ソースコードが記述された13種類のテンプレートから適当なものを選択する画面

④Configure Activity画面

・Androidアプリ開発では、処理をJavaクラス(.Javaファイル)画面構成をXML(XMLファイル)に記述し、このペアで一つの画面が作られる
・Javaクラスのことをアクティビティと呼び、Activityクラス(または、その子クラス)を継承して作る
・XMLファイルはレイアウトファイルと呼ぶ
・アクティビティと、レイアウトファイルのペアで一つの画面が作られ、このことから通常、関連した名前を付ける
 例えば、アクティビティ名が、MainActivityなら、レイアウトファイル名は、activity_main.xmlとなり、これらを自動化してくれるのが、Configure Activity画面

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Androidビュー

初学者ですが、個人的な勉強の為まとめました

Androidビュー

Projectツールウィンドウの見え方は変更でき、デフォルトではAndroidビューである
Androidビューでは、開発に必要なファイルのみ表示するようになっており、必要に応じてはProjectビューなど他のビューに切り替える
※Projectビューは、より実際のファイルなどに近い構成になっている

Androidビューのファイル構成

・大きく、manifestsjavaresの3フォルダに分かれる

①manifests

AndroidManifest.xmlファイルが格納されている
・AndroidManifest.xmlファイルは、アプリの実行に必要な設定が記述されている

②java

・名前の通り、javaファイルが格納されている
・パッケージ右側に(androidTest),(test)と記述されているのは、Androidアプリをテストするための.Javaファイルの格納先

③res

・.xmlファイルや、アプリで使われる画像ファイルなどを格納する
・resフォルダには、以下のサブフォルダがある
 ①drawable・・・画像を格納
 ②layout・・・画面構成に関わる.xmlファイルを格納
 ③mipmap・・・アプリのアイコンを格納
 ④values・・・アプリで格納する固定文字列(String.xml)、画面のスタイル(styles.xml)、色構成(colors.xml)を表す.xmlファイルなどを格納

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Excel挿入と画像抽出

Spire.XLSは豊富な画像処理機能をサポートしています。添加、回転、抽出、削除などです。本論文では、Spire.XLS for Javaを使って、Excelドキュメントに画像を挿入して抽出する方法を紹介します。

使用ツール:Free Spire.XLS for Java (無料版)
https://www.e-iceblue.com/Introduce/free-xls-for-java.html

Jarファイルの取得と導入:

Method 1:ホームページを通じてjarファイルのカバンをダウンロードします。ダウンロード後、ファイルを解凍して、libフォルダの下のSpire.xls.jarファイルをJavaプログラムに導入します。
https://www.e-iceblue.com/Download/xls-for-java-free.html

Method 2:maven倉庫設置による導入。

https://www.e-iceblue.com/Tutorials/Licensing/How-to-install-Spire.PDF-for-Java-from-Maven-Repository.html

画像をExcelに挿入します

import com.spire.xls.ExcelPicture;
import com.spire.xls.ExcelVersion;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;

public class InsertImage {
    public static void main(String[] args){
        // Excelドキュメントを読み込む
        Workbook workbook = new Workbook();
        workbook.loadFromFile("Input.xlsx");

        //1番目のシートを取得
        Worksheet sheet = workbook.getWorksheets().get(0);

        //シートの指定位置に画像を追加します
        ExcelPicture pic = sheet.getPictures().add(4, 1,"image.jpg");
        // 画像の幅と高さを設定します
        pic.setWidth(500);
        pic.setHeight(300);

        //文書を保存
        workbook.saveToFile("InsertImage.xlsx", ExcelVersion.Version2013);
    }
}

Insert Image to Excel.png

画像を抽出

import com.spire.xls.ExcelPicture;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ReadImage {
    public static void main(String[] args) throws IOException {
          //Excelドキュメントを読み込む
        Workbook workbook = new Workbook();
        workbook.loadFromFile("InsertImage.xlsx");

        //1番目のシートを取得
        Worksheet sheet = workbook.getWorksheets().get(0);

        //シートの最初の画像を取得し、指定されたパスに保存します
        ExcelPicture pic = sheet.getPictures().get(0);
        BufferedImage loImage = pic.getPicture();
        ImageIO.write(loImage,"jpg",new File("output/ReadImage.jpg"));
    }
}

Extract Image from Excel.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む