20191024のJavaに関する記事は11件です。

Javaでアプリケーションを作る11月中に

//メモ

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

51歳からのプログラミング 備忘 FusedLocationProviderClientを常駐させる

FusedLocationProviderClientをForegroundSeriviceで常駐させる

androidDeveloperとgoogleApi様を参照してます。
あと、nyan様のサイトも、いっつも参照しています。ありがとうございます。


以下のサンプルコードは、androidのビルドバージョンはapi26以上です。

Manifest gradleの確認

Manifest
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application
    ...
    >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>
builed.gradle
dependencies {
    ...
    implementation 'com.google.android.gms:play-services-location:17.0.0'

Code

MainActivity
public class MainActivity extends AppCompatActivity {

    static TextView textView;
    static MainActivity mainActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Serviceで使うオブジェクトを取得してるよ
        textView = findViewById(R.id.textView);
        mainActivity = MainActivity.this;

        Intent intent = new Intent(this,MyService.class);
        startForegroundService(intent);
    }
}
MyService
public class MyService extends Service {

    TextView textView;
    FusedLocationProviderClient fusedLocationClient;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();

        // 位置情報を取り扱う時に使うオブジェクト を取得してるよ
        textView = MainActivity.textView;
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    }

    public int onStartCommand(Intent intent, int flags, int startId){
        // アプリを常駐させるためにForegorundServiseで通知処理をしまーす!
        // まずは、通知コンテンツ、チャンネル、重要度の作成ね!
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        Intent intentPending = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intentPending,0);
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("sampleApi")
                              .setContentText("sample")
                              .setContentIntent(pendingIntent)
                              .build();
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel("id","name",importance);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
        // ここまでが、通知コンテンツ、チャンネル、重要度の設定でした

        // 5秒以内に startForeground! 急げ!!
        startForeground(2,notification);

        locationManager();
        return START_STICKY;
    }

    private void locationManager(){
        // 定時的に位置を測定する、ていう設定ね
        LocationRequest request = LocationRequest.create();
            request.setInterval(1000*3);
            request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // ACCESS_FIN_LOCATION は、ユーザーにとって危険のある設定なので
        // 許可を得るコードが必須です!
        // では許可チェックをしましょう
      if(ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            // 許可がなければ許可を求めてみます
            ActivityCompat.requestPermissions(MainActivity.mainActivity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);
        }else{
            // 許可があるようなので、位置情報を取得していきます!
            fusedLocationClient.requestLocationUpdates(request,new LocationCallback(){
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    super.onLocationResult(locationResult);
                    // 例示的にlatitudeを表示します
                    String str = String.valueOf(locationResult.getLastLocation().getLatitude());
                    textView.setText(str);
                }
            }, Looper.getMainLooper());
        }
    }

    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults) {
        if (requestCode == 100) {
            // 省略
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

今回も、かなり時間を掛けました。位置情報を常駐的に取得するのって、僕にはハードル高すぎました。このコードを作るまでに約2週間。行ったり来たりを繰り返して、やっとでした~。

今回も亀の歩みですね。

亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!

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

51歳からのプログラミング 備忘 FusedLocationProviderClientをForegroundServiceで常駐させる

FusedLocationProviderClientをForegroundSeriviceで常駐させる

androidDeveloperとgoogleApi様を参照してます。
あと、nyan様のサイトも、いっつも参照しています。ありがとうございます。


以下のサンプルコードは、androidのビルドバージョンはapi26以上です。

Manifest gradleの確認

Manifest
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

builed.gradle
dependencies {
    ...
    implementation 'com.google.android.gms:play-services-location:17.0.0'

NotificationしないクラッシュCode

Notificationするとコードが長くなるので、まずはシンプルに動作確認するためのコードです。
起動すると位置情報を取得し始め、ボタンプッシュでサービスと位置情報取得を破棄。
5秒経つとクラッシュ

MainActivity
public class MainActivity extends AppCompatActivity {

    static MainActivity activity;
    static TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity = MainActivity.this;
        textView = findViewById(R.id.textView);
        Button button = findViewById(R.id.button);

        final Intent intent = new Intent(this,MyService.class);
        startForegroundService(intent);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });
    }
}

MyService
public class MyService extends Service {

    MainActivity activity;
    TextView textView;
    FusedLocationProviderClient fusedLocationClient;
    LocationCallback myCallback;

    @Override
    public void onCreate() {
        super.onCreate();
        activity = MainActivity.activity;
        textView = MainActivity.textView;
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity);
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        // 本当ならここでNotificationを設定してstartForeground
        // でも見辛くなるので今回は省略
        myCallback = new myCallback(); // LocationCallback()インスタンス
        myCheckPermission();           // ActivityCompat.checkSelfPermission()
        myGetLocation();               // FusedLocationProviderClient.requestLocationUpdates(); 
        return START_STICKY;
    }

    // Manifestで設定したpermissonの ACCESS_FINE_LOCATIONってば
    // ユーザーデンジャラス なので、permissionの許諾が必要!
    public void myCheckPermission(){
        if(ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);
            // requestPermissions()で確認した内容は
            // 本当ならonRequestPermissionsResult()で処理するのですが省略です
        }else{
            return;
        }
    }

    public void myGetLocation(){
        // fusedLocationProviderClientの動作を設定
        LocationRequest locationRequest = LocationRequest.create();
            locationRequest.setInterval(1000*3);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

        // では!位置情報を取得するよ!取得した情報はCallback()関数で扱います!
        fusedLocationClient.requestLocationUpdates(locationRequest,myCallback,null);
    }

    // MainActivityで、ストップボタンを押すと、Serviceが破棄されるようにしたので
    // その時に、onDestroyが呼ばれます
    // onDestroy()でfusedLocationProviderClientを破棄するよ!
    @Override
    public void onDestroy() {
        super.onDestroy();
        fusedLocationClient.removeLocationUpdates(myCallback);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    // LocationCallback()です。
    // 取得した位置情報を扱うのはこのクラス!
    class myCallback extends LocationCallback{
          @Override
          public void onLocationResult(LocationResult locationResult){
              super.onLocationResult(locationResult);
              // locationResultに位置情報があるので、それを使おう!
              double latitude = locationResult.getLastLocation().getLatitude();
              String strLatitude = String.valueOf(latitude);
              textView.setText(strLatitude);
        }
    }
}

常駐させ、緯度経度高度を取得するCode

Startボタンで位置情報取得と表示を常駐させます。
Stopボタンでサービスと位置情報取得を破棄します。
レッツゴー!

MainActivity
public class MainActivity extends AppCompatActivity {

    // Serviceから参照するUI部品をstaticに
    static MainActivity activity;
    static TextView textAlutitude;
    static TextView textLatitude;
    static TextView textLongitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // オブジェクトを取得!
        activity = MainActivity.this;
        textAlutitude = findViewById(R.id.textAltitude);
        textLatitude = findViewById(R.id.textLatitude);
        textLongitude = findViewById(R.id.textLongitude);
        Button btnStart= findViewById(R.id.btnStart);
        Button btnStop = findViewById(R.id.btnStop);


        // StartボタンでForagroundServiceスタート
        // StopボタンでForegroundServiceストップ
        //    ForegroundServiceストップでMyService.onDestroy()でFusedLocationProviderClientも破棄
        final Intent intent = new Intent(activity,MyService.class);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startForegroundService(intent);
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopService(intent);
            }
        });

    }
}

MyService
public class MyService extends Service {

    // オブジェクトをグローバルに
    MainActivity activity;
    TextView textAltitude;
    TextView textLatitude;
    TextView textLongitude;
    FusedLocationProviderClient fusedLocationClient;
    LocationRequest locationRequest;
    LocationCallback locationCallback;

    @Override
    public void onCreate() {
        super.onCreate();

        // FusedLocationProviderClient は onCreate()で生成するみたい
        // オブジェクトを取得!
        activity = MainActivity.activity;
        textAltitude = MainActivity.textAlutitude;
        textLatitude = MainActivity.textLatitude;
        textLongitude = MainActivity.textLongitude;
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);

        // LocationRequestを設定しときます
        // 5秒ごとに詳細な位置情報を取得するように設定
        locationRequest = LocationRequest.create();
            locationRequest.setInterval(1000*5);
            locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    public int onStartCommand(Intent intent, int flags, int startId){
        // 常駐させたいので通知を出します

        // 通知コンテンツ、重要度、チャンネルを設定
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        Intent pIntent = new Intent(this,MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,pIntent,0);
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("NotificationTitle")
                              .setContentText("NotificationText")
                              .setContentIntent(pendingIntent)
                              .build();
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel("id","name",importance);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);

        // 5秒以内に startForeground !! 急げ!
        startForeground(1,notification);


        // LocationCallback()は、requestLocation,Update,removeで使うので、ここで作成しとく
        locationCallback = new LocationCallback(){
            @Override
            public void onLocationResult(LocationResult locationResult){
                super.onLocationResult(locationResult);
                String alti = String.valueOf(locationResult.getLastLocation().getAltitude());
                String lati = String.valueOf(locationResult.getLastLocation().getLatitude());
                String longi = String.valueOf(locationResult.getLastLocation().getLongitude());
                textAltitude.setText(alti);
                textLatitude.setText(lati);
                textLongitude.setText(longi);
            }
        };

        checkLocationPermission();
        return START_STICKY;
    }

    // 位置情報を取得
    private void locationUpdate(){
        fusedLocationClient.requestLocationUpdates(locationRequest,locationCallback,null);
    }

    // permission ACCESS_FINE_LOCATION はユーザーデンジャラスな設定なので許可を確認します
    public void checkLocationPermission(){
        if(ActivityCompat.checkSelfPermission(activity,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            // ACCESS_FINE_LOCATIONの許可がなければダイアログでユーザーに確認
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},100);
        }else{
            locationUpdate();
        }
    }

    // checkLocationPermission()のrequestPermissionsでユーザに確認した内容を処理します
    public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){
        if(requestCode == 100){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                // 許可が得られたら
                locationUpdate();
            }else{
                // 許可が得られなかったら
                textAltitude.setText("No permission");
            }
        }
    }

    // Serviceが破棄されるときに、FusedLocationProviderClientも破棄
    @Override
    public void onDestroy() {
        super.onDestroy();
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

今回も、かなり時間を掛けました。位置情報を常駐的に取得するのって、僕にはハードル高すぎました。このコードを作るまでに約2週間。行ったり来たりを繰り返して、やっとでした~。

今回も亀の歩みですね。

亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!

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

JavaのExecutorServiceでサクッとタイムアウト処理

他人のコードを眺めていたらExecutorServiceを使った良い感じのタイムアウト実装を発見したので備忘録的に書き留めておく.

import java.util.concurrent.*;

...

// メソッド内
final Runnable runnable = () -> {
  // ここにしたい処理を書く
};

final ExecutorService service = Executors.newSingleThreadExecutor();
final Future<?> future = service.submit(runnable);

try {
  // ここで処理が行われる
  // 第一引数はタイムアウトまでの時間
  // 第二引数は単位時間(秒,時間,日,etc.)
  future.get(10, TimeUnit.SECONDS);
} catch (final TimeOutException e) {
  future.cancel(true);
  e.printStackTrace();
} catch (final InterruptedException | ExecutionException e) {
  e.printStackTrace();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Kotlin】NotNull(NonNull)/NullableアノテーションでJavaのフィールドをKotlinからNull安全に扱う【Java】

前書き

org.jetbrains.annotations内のNotNull/Nullableや、org.springframework.lang内のNonNull/Nullableアノテーションを用いることで、JavaのフィールドをKotlinからKotlinっぽく扱えるようになります。

同様に利用可能なアノテーションは他にも有りますので、以下をご覧下さい(ちなみにですが、org.springframework.langに関してはどこにも記述が有りませんでしたが同様に動きました)。

これらのアノテーションはゲッターに振るのが良さげです。

やり方

以下のように付与するだけで大丈夫です。
例ではorg.jetbrains.annotationsのものを使っていますが、org.springframework.langのものでも同様にできました。

import org.jetbrains.annotations.NotNull;

public class Sample {
    private String field;

    @NotNull
    public String getField() {
        return field;
    }

    public void setField(String field) {
        this.field = field;
    }
}

付与するとどうなるか

Kotlinから見ると、付与前は以下の画像のようにString!型(Platform型)で扱われています。
スクリーンショット 2019-10-24 21.30.17.png

付与後はString型で扱われていることが分かります。
スクリーンショット 2019-10-24 21.31.27.png

以下のように、アノテーションをNullableに変更するとことで、String?型として扱うこともできます。

Nullableへの変更
- import org.jetbrains.annotations.NotNull;
+ import org.jetbrains.annotations.Nullable;
- @NotNull
+ @Nullable
public String getField() {

スクリーンショット 2019-10-24 21.35.39.png

「ゲッターに振るのが良さげ」なのは何故か

画像の通り、フィールドに振ってしまうと「初期化しろ」と怒られるためです。
スクリーンショット 2019-10-24 22.00.55.png

意義

JavaプロジェクトにKotlinを導入したり、KotlinからJavaのフレームワークを使う場合、しばしば「値無しコンストラクタでオブジェクト初期化 -> セッターで各値を注入」的な挙動をされる場合が有ります。

このような場合、対象オブジェクトをKotlinで書こうとすると結構な工夫をする必要があり、「これKotlinで書く意味有るんだっけ」となれます。
既存のJavaオブジェクトがあり、それを一々全て書き換える必要があるなら、労力もバカになりません。
初めからDataクラスにマッピングできるようにユーティリティを作るというのも手ですが、書き換え以上に初期コストは掛かるでしょう。

そんなことをする位なら、ゲッターにアノテーションを振るだけで済ませた方がスマートなんじゃないかなと思います(無論何が何でもフルKotlinにしたいという場合は別ですが、実現できる挙動が同等であれば別にJavaで書いていいんじゃないかとは思います)。

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

Spring boot コントローラメソッド メモ

Spring MVCのコントローラメソッドは、画面で入力されたパラメータ以外に、様々な情報を引数として受け取ることができる。

@Secured

@Secured アノテーションを付けることで、URLに関する権限を指定する事が出来る。

@Controller
@RequestMapping("/sbadmin2/")
@Secured("IS_AUTHENTICATED_FULLY")
public class SbAdmin2Controller {

    @RequestMapping("/index.html")
    public ModelAndView index() {
        return new ModelAndView("SbAdmin2Controller/index");
    }

    @Secured("ROLE_STAFF")
    @RequestMapping("/forms.html")
    public ModelAndView forms() {
        return new ModelAndView("SbAdmin2Controller/forms");
    }
}
// /sbadmin2/index.html はログインしていればアクセス可能
// /sbadmin2/forms.html はログインして ROLE_STAFFの権限を割り当てられていればアクセス可能

@RequestParam

@RequestParam アノテーションを指定すると、URLに含まれるクエリパラメータや、メッセージボディーに含まれるポストパラメータを受け取ることができる。

@GetMapping("/hello")
public String hello(@RequestParam("name") String name) {}
// /hello?name=string

@RequestPart

@RequestParam アノテーションを指定すると、画像・動画ファイルやJSONを受け取ることができる。

@GetMapping("/hello")
public String hello(@RequestPart("data") String data) {}
const data = new FormData()
data.append('file', file)
data.append('jsonValue', new Blob([JSON.stringify(sampleObject)], {type : 'application/json'}))

axios.get('/hello', data)

@PathVariable

@PathVariable アノテーションを指定すると、URLに含まれる動的なパラメータを受け取ることができる。

@GetMapping("/hello/{userId}")
public String hello(@PathVariable("userId") Integer userId) {

@RequestHeader

@RequestHeader アノテーションを指定すると、リクエストヘッダに含まれている各項目を受け取ることができる。

@GetMapping("/hello")
public String hello(@RequestHeader("User-Agent") String userAgent) {
RequestHeader
GET /hello?userId=10 HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json
X-XSRF-TOKEN: 00000-000-0000-0000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/hello?userId=10
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Cookie: mailaddress=hoge@hoge.com;
JSESSIONID=sfdgfhgjh;
XSRF-TOKEN=00000-000-0000-0000

@RequestBody

@RequestBody アノテーションを指定すると、リクエストボディーの内容をそのまま取得することができる。

@PostMapping("/hello")
public String hello(@RequestBody String body) {
POST /hello HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 22
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://localhost:8080/hello
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.8,en;q=0.6

user=scott&password=tiger

※リクエストヘッダの後に一行、空行が入り、その後POSTで送信したクエリが、リクエストボディとしてクライアントからサーバへと送信されてくる
※仕様上、get時の body は null に設定される

@DateTimeFormat

@DateTimeFormat アノテーションを指定して、受け取る日時の文字列表現の形式を指定する。

@GetMapping("/hello/{date}")
public String hello(@PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) java.util.Date date) {}

@Autowired

付与されたフィールドの型と合うBeanを自動的にInjectionしてくれる。
型と会うBeanが複数ある場合は、@Qualifierアノテーションを使用することで一意に識別できる。

参考: @Autowired、@Inject、@Resourceの違いについての検証

@Validated

@Validated アノテーションを指定して、バリデーションを有効化する。

 @PostMapping("/hello")
    public String hello(@RequestBody @Validated String name)

@AuthenticationPrincipal

@AuthenticationPrincipal アノテーションを指定して、その引数に認証したユーザ情報が自動的に渡されるようにする。

@RequestMapping("/hello")
    public String hello(@AuthenticationPrincipal AppUserDetail userDetail) {
        log.info("debug: {}", userDetail);

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

【Java】Dateの時刻を00:00:00にする方法

概要

  • チェックする対象の日付が今日より前か後か当日かを調べたい
  • ただしチェックする対象の日付は時刻が00:00:00なので日付だけ比較したい
  • new Date()で生成した今日の日付は時刻まで入っている
    • 比較すると日付が一緒でも時刻が違うと当日判定にならない

実現方法

使うメソッド

  • java.util.Dateのメソッドを使って前後比較をします
  • 言わずと知れたorg.apache.commons.lang3DateUtilsを使います
UseMethod
java.util.Date.equals(Object obj)
java.util.Date.before(Date when)
java.util.Date.after(Date when)

org.apache.commons.lang3.time.DateUtils.truncate(Date date, int field)

サンプル

DateUtilService.java
public void printDate(Date targetDate) {

    // 今日の00:00:00を取得
    Date today = DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH);

    if (targetDate.equals(today)) {
        System.out.println("今日です。");
    } else if (targetDate.after(today)) {
        System.out.println("今日より後の日付です。");
    } else if (targetDate.before(today)) {
        System.out.println("今日より前の日付です。");
    }
}

解説

  1. DateUtils.truncateの第1引数にはゼロ埋めしたい日付を入れる
  2. 第2引数にCalendar.DAY_OF_MONTHを渡す
  3. todayの時刻が00:00:00になるから、targetDateとフォーマットが揃う
  4. あとはequals、after、beforeで前後関係を調べる

ちなみに

DateUtils.isSameDayを使う方法

当日かどうかだけならDateUtils.isSameDayを使えば、truncateで00:00:00にしなくても日付だけ比較してbooleanを返してくれます。
※今回はbeforeとafterを使いたかったのでゼロ埋めしました

ゼロにする位置を変える場合

DateUtils.truncateの第2引数に渡す変数次第でゼロにする位置を変えられます。

int field ゼロになる位置
Calendar.DAY_OF_MONTH 00:00:00
Calendar.HOUR_OF_DAY XX:00:00
Calendar.MONTH 1日の00:00:00
Calendar.YEAR 1/1の00:00:00

参考

【Java】Dateの時分秒を切り捨てる方法
Class DateUtils|org.apache.commons.lang3.time

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

【Java 】サーブレット(tomcat)&MySQL&Java でコネクションプールを使用して接続してみた

参考サイト

※ めちゃくちゃ参考になった!!!
Java で MySQL に 接続する 方法
https://garafu.blogspot.com/2016/05/how-to-connect-mysql.html#con-svlt1

JDBS ドライバ導入

  1. 公式サイトからmysql-connector-java-8.0.18.zipダウンロード
  2. 解凍するしてmysql-connector-java-5.1.48-bin.jarを取り出す
  3. /WebContent/WEB-INF/lib/mysql-connector-java-5.1.48-bin.jarに入れる

context.xml を作成する

/WebContent/META-INF/context.xmlに作成する

context.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Context>
    <Resource name = "jdbc/book"
              auth = "Container"
              type = "javax.sql.DataSource"
              driverClassName = "com.mysql.jdbc.Driver"
              url      = "jdbc:mysql://localhost/book"
              username = "namari"
              password = "password">
    </Resource>
</Context>

サーブレット

/Sample/webapps/book/WEB-INF/src/chapter14/All.javaに作成する

All.java
package chapter14;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.*;

/**
 * Servlet implementation class All
 */
@WebServlet("/All")
public class All extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public All() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        PrintWriter out = response.getWriter();

        try {
            // コネクション取得
            InitialContext ic = new InitialContext();
            DataSource ds = (DataSource) ic.lookup("java:/comp/env/jdbc/book");
            Connection con = ds.getConnection();

            // SQL文送信
            PreparedStatement st = con.prepareStatement("select * from product");
            // 実行&結果受け取り
            ResultSet rs = st.executeQuery();

            // データの表示
            while (rs.next()) {
                out.println(rs.getInt("id") + ":" + rs.getString("name") + ":" + rs.getInt("price"));
            }

            // データベース切断
            st.close();
            con.close();

        } catch (Exception e) {
            // 接続・SQL文エラー
            e.printStackTrace(out);

        } // try
    }

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

Cognos AnalyticsでJConsoleを使う手順

Cognos AnalyticsでJConsoleを使う手順

Cognos AnalyticsでJConsoleを使う手順をメモ変わりに投稿しておきます。
CognosのJavaプロセスで使用しているメモリー量、CPU、GCの発生状況、スレッド数などを見るのに役に立ちます。

マニュアル上の情報はこちらです。
Using logging to diagnose a problem for a specific user
https://www.ibm.com/support/knowledgecenter/SSEP7J_11.1.0/com.ibm.swg.ba.cognos.ug_cra.doc/t_disableipfuser.html#DisableIPFUser

基本的にリモートのPCからでも出来る説明なのですが、実際にやってみると一部情報しか見えなかったので、Cognosサーバー上で以下の手順で行いました。
環境は、Cognos Analytics 11.1.3 @ Redhat 7 です。

Cognos Configurationの設定
Cognos Configurationを起動し、赤枠の「外部JMXポート」を任意の値に、「外部JMX資格情報」でユーザーIDとパスワードを任意のものに指定し、保存後Cognosを再起動します。
012.PNG

IBM Java SDK 8の導入
こちらからJDK 8 をダウンロードして、Cognosサーバーノードにインストールします。
https://developer.ibm.com/javasdk/downloads/sdk8/

※Oracle Javaでも大丈夫という事です。試してはいないです。

JConsoleの起動
以下のコマンドで、JConsoleを起動します。
008.PNG

プロセスに接続
リモート・プロセスで接続すると、後述のイメージで「Mbeans」のタブの情報しか見えなかったので、「ローカル・プロセス」を指定し、プロセスとして赤枠のどちらかを選択します。
dataset-service = Query Serviceのプロセス
cognosserver = CognosのWebSphere Liberty本体
009.PNG

※リモート・プロセス接続の場合は、以下の指定。monitoring_serverはモニターしたいJavaプロセスが動作しているノード
service:jmx:rmi://Content_Manager_server/jndi/rmi://monitoring_server:8181/proxyserver

「不安定な接続」で。
011.PNG

各タブの紹介
「概説」タブ
001.PNG

「メモリー」タブ
002.PNG

「スレッド数」タブ
003.PNG

「クラス」タブ
004.PNG

「VMの要約」タブ
005.PNG

「MBeans」タブ
006.PNG

どこかで役に立つ事もあると思うので、覚えておいて頂ければと。

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

処理をどこまで分けるのが正解か

比較しました

FUnction.java
package mk42;

import java.util.List;
import java.util.function.Function;
import java.util.function.UnaryOperator;

/**
 * All method has the same process.
 *
 * @author
 *
 */
public class NotStaticProcessingTest {
    /**
     * This method contains all process to need.
     * @param list
     */
    public void streamTest1(List<String> list) {
        list.stream().map(v -> v + "3").mapToInt(Integer::parseInt).sum();
    }
    /**
     * This method has 2 functions.
     * @param list
     */
    public void streamTest2(List<String> list) {
        list.stream().map(add3.andThen(convertInt)).mapToInt(v -> v).sum();
    }
    /**
     * This method has 1 functions.
     * @param list
     */
    public void streamTest3(List<String> list) {
        list.stream().map(all).mapToInt(v -> v).sum();
    }
    /**
     * This method has 1 function.
     * The function has all process.
     * @param list
     */
    public void streamTest4(List<String> list) {
        this.sum.apply(list);
    }
    /**
     * This method has methos instead of function.
     * @param list
     */
    public void streamTest5(List<String> list) {
        this.sum(list);
    }

    /** Add 3 */
    private UnaryOperator<String> add3 = v -> v + "3";
    /** Convert to Integer */
    private Function<Object, Integer> convertInt = v -> Integer.parseInt(String.valueOf(v));
    /** all */
    private Function<String, Integer> all = v -> Integer.parseInt(v + "3");
    /** all of them function */
    private Function<List<String>, Integer> sum = v -> v.stream().mapToInt(x -> Integer.parseInt(x + "3")).sum();
    /** all of them method */
    private Integer sum(List<String> list) {
        return list.stream().mapToInt(v -> Integer.parseInt(v + "3")).sum();
    }
}

Mk42.echoはsysoutです、別で用意してあります.

処理速度検証.java
package mk42;

import java.util.Arrays;
import java.util.List;

public class StreamProcessingTest {

    /** constant list */
    private static final List<String> list = Arrays.asList("1", "2", "3");

    /**
     * main
     * @param args
     */
    public static void main(String[] args) {

        // instance
        NotStaticProcessingTest no = new NotStaticProcessingTest();

        /** ----------test1---------- */
        Mk42.echo.accept("stream test 1");
        Long start1 = System.nanoTime();
        no.streamTest1(list);
        Long end1 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end1 - start1) + "ns");

        /** ----------test2---------- */
        Mk42.echo.accept("stream test 2");
        Long start2 = System.nanoTime();
        no.streamTest2(list);
        Long end2 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end2 - start2) + "ns");

        /** ----------test3---------- */
        Mk42.echo.accept("stream test 3");
        Long start3 = System.nanoTime();
        no.streamTest3(list);
        Long end3 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end3 - start3) + "ns");

        /** ----------test4---------- */
        Mk42.echo.accept("stream test 4");
        Long start4 = System.nanoTime();
        no.streamTest4(list);
        Long end4 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end4 - start4) + "ns");

        /** ----------test5---------- */
        Mk42.echo.accept("stream test 5");
        Long start5 = System.nanoTime();
        no.streamTest5(list);
        Long end5 = System.nanoTime();
        Mk42.echo.accept("Processing TIme : " + (end5 - start5) + "ns");
    }
    /**
     * As a result.
     *
     * stream test 1
     * Processing TIme : 3630700ns
     *
     * stream test 2
     * Processing TIme : 632701ns
     *
     * stream test 3
     * Processing TIme : 195400ns
     *
     * stream test 4
     * Processing TIme : 151499ns
     *
     * stream test 5
     * Processing TIme : 143600ns
     */
}

結果

stream test 1
Processing TIme : 3630700ns
stream test 2
Processing TIme : 632701ns
stream test 3
Processing TIme : 195400ns
stream test 4
Processing TIme : 151499ns
stream test 5
Processing TIme : 143600ns

理由

処理をどこで分割するとかでなく
Integer呼んでるから1が最低速
中間操作でandThen使ってるから2が3より遅い

4と5はメソッドかFunctionかの差ですけど

メソッド.java
    public void streamTest4(List<String> list) {
        this.sum.apply(list);
    }

    public void streamTest5(List<String> list) {
        this.sum(list);
    }
stream test 4
Processing TIme : 151499ns
stream test 5
Processing TIme : 143600ns

ということで大差ないけどメソッドのが少しはやいかも…?


    以下をすると遅くなりますね
  • FunctionをandThenでつなげまくる
  • メソッドを細かく分けまくって呼びまくる
  • streamの中間操作が増える
  • CollectersやStringなどを呼ぶ

メソッドとFunctionでたいして速度変わらないなら、Functionはstreamの中間操作のために生まれたのか...?

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

【Java】src/main/resourcesにあるファイルを読み込む

Javaでsrc/main/resourcesにあるファイルを読み込むのに少し手間取ったので備忘録です。

1. ルートからの絶対パスで取得

src/main/resources/sample1.txt
sample1
src/main/java/Foo.java
public void sample1() {
    String path = "src/main/resources/sample1.txt";
    try (BufferedReader br = Files.newBufferedReader(Paths.get(path))) {

        System.out.println(br.readLine());

    } catch (IOException e) {
        e.printStackTrace();
    }
}
実行結果
sample1

2. クラスパスからの相対パスで取得

src/main/resources/sample2.txt
sample2
src/main/java/Foo.java
public void sample2() {
    String path = "/sample2.txt";
    // staticメソッドの場合はFoo.class.getResourceAsStreamのように書く(Fooはクラス名)
    try (InputStream is = getClass().getResourceAsStream(path);
        BufferedReader br = new BufferedReader(new InputStreamReader(is))) {

        System.out.println(br.readLine());

    } catch (IOException e) {
        e.printStackTrace();
    }
}
実行結果
sample2

注意点

1.と2.では、テストの際、src/test/resourcesに同名ファイルが有るときの動きが異なります。

src/test/resources/sample1.txt
test1
src/test/resources/sample2.txt
test2
src/test/java/FooTest.java
public class FooTest {
  @Test
  public void testInput() throws Exception {
    Foo foo = new Foo();
    foo.sample1();  // src/main/resources/sample1.txtを読み込む
    foo.sample2();  // src/test/resources/sample2.txtを読み込む
  }
}
実行結果
sample1
test2

1.の場合は、パスを直書きしているので当たり前ですが、src/main/resourcesディレクトリ下のsample1.txtを読み込みます。
2.の場合は、src/main/resourcesに優先してsrc/test/resourcesディレクトリ下のsample2.txtを読み込んでいます。

なお、src/test/resourcesディレクトリにsample2.txtがなければ、そのままsrc/main/resourcesディレクトリ下のsample2.txtが読み込まれます。

まとめ

とりあえずClass#getResourceAsStreamを使っておけば良いかと。
何か問題があれば教えていただけると助かります。

参考:
リソースの取得
【Java】クラスパス上のファイルを取得する方法の違いについて

余談

Class#getResourceAsStreamではなく、Class#getResource経由で絶対パスを取得し、Paths#getに渡したところ java.nio.file.InvalidPathExceptionとなりました。

String filename= "/sample2.txt";
String filepath = getClass().getResource(filename).getPath();
Path path = Paths.get(filepath); // java.nio.file.InvalidPathException

どうもWindows環境ではドライブレター部分のエスケープが必要なようで、以下のように置換したところ取得できました。

String filename= "/sample2.txt";
String filepath = getClass().getResource(filename).getPath();
Path path = Paths.get(filepath .replaceFirst("^/(.:/)", "$1")); // OK

参考: create Java NIO ファイル・パスの問題



最後までお読み頂きありがとうございました。質問や不備についてはコメント欄かTwitter(@ka2_kamaboko)までお願いします。

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