- 投稿日:2019-10-24T22:55:57+09:00
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.gradledependencies { ... implementation 'com.google.android.gms:play-services-location:17.0.0'Code
MainActivitypublic 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); } }MyServicepublic 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週間。行ったり来たりを繰り返して、やっとでした~。
今回も亀の歩みですね。
亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!
- 投稿日:2019-10-24T22:55:57+09:00
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.gradledependencies { ... implementation 'com.google.android.gms:play-services-location:17.0.0'NotificationしないクラッシュCode
Notificationするとコードが長くなるので、まずはシンプルに動作確認するためのコードです。
起動すると位置情報を取得し始め、ボタンプッシュでサービスと位置情報取得を破棄。
5秒経つとクラッシュMainActivitypublic 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); } }); } }MyServicepublic 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ボタンでサービスと位置情報取得を破棄します。
レッツゴー!MainActivitypublic 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); } }); } }MyServicepublic 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週間。行ったり来たりを繰り返して、やっとでした~。
今回も亀の歩みですね。
亀の歩みでも、諦めないでもがき続けると、前進できるんだなって感じたよ。
無理かな無理かなと思っても、前進できるんだね。
まだまだ全然実力不足なんだけれど、面白い。すごく楽しい!
- 投稿日:2019-10-24T22:11:00+09:00
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(); }
- 投稿日:2019-10-24T22:08:43+09:00
【Kotlin】NotNull(NonNull)/NullableアノテーションでJavaのフィールドをKotlinからNull安全に扱う【Java】
前書き
org.jetbrains.annotations
内のNotNull
/Nullable
や、org.springframework.lang
内のNonNull
/Nullable
アノテーションを用いることで、Java
のフィールドをKotlin
からKotlin
っぽく扱えるようになります。同様に利用可能なアノテーションは他にも有りますので、以下をご覧下さい(ちなみにですが、
org.springframework.lang
に関してはどこにも記述が有りませんでしたが同様に動きました)。
- Calling Java from Kotlin - Kotlin Programming Language
- kotlin/JvmAnnotationNames.kt at master · JetBrains/kotlin
これらのアノテーションはゲッターに振るのが良さげです。
やり方
以下のように付与するだけで大丈夫です。
例では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型)で扱われています。
以下のように、アノテーションを
Nullable
に変更するとことで、String?
型として扱うこともできます。Nullableへの変更- import org.jetbrains.annotations.NotNull; + import org.jetbrains.annotations.Nullable; - @NotNull + @Nullable public String getField() {「ゲッターに振るのが良さげ」なのは何故か
画像の通り、フィールドに振ってしまうと「初期化しろ」と怒られるためです。
意義
Java
プロジェクトにKotlin
を導入したり、Kotlin
からJava
のフレームワークを使う場合、しばしば「値無しコンストラクタでオブジェクト初期化 -> セッターで各値を注入」的な挙動をされる場合が有ります。このような場合、対象オブジェクトを
Kotlin
で書こうとすると結構な工夫をする必要があり、「これKotlin
で書く意味有るんだっけ」となれます。
既存のJava
オブジェクトがあり、それを一々全て書き換える必要があるなら、労力もバカになりません。
初めからData
クラスにマッピングできるようにユーティリティを作るというのも手ですが、書き換え以上に初期コストは掛かるでしょう。そんなことをする位なら、ゲッターにアノテーションを振るだけで済ませた方がスマートなんじゃないかなと思います(無論何が何でもフル
Kotlin
にしたいという場合は別ですが、実現できる挙動が同等であれば別にJava
で書いていいんじゃないかとは思います)。
- 投稿日:2019-10-24T19:10:28+09:00
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) {RequestHeaderGET /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"; }
- 投稿日:2019-10-24T15:45:10+09:00
【Java】Dateの時刻を00:00:00にする方法
概要
- チェックする対象の日付が今日より前か後か当日かを調べたい
- ただしチェックする対象の日付は時刻が00:00:00なので日付だけ比較したい
new Date()
で生成した今日の日付は時刻まで入っている
- 比較すると日付が一緒でも時刻が違うと当日判定にならない
実現方法
使うメソッド
java.util.Date
のメソッドを使って前後比較をします- 言わずと知れた
org.apache.commons.lang3
のDateUtils
を使いますUseMethodjava.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.javapublic 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("今日より前の日付です。"); } }解説
DateUtils.truncate
の第1引数にはゼロ埋めしたい日付を入れる- 第2引数に
Calendar.DAY_OF_MONTH
を渡す- todayの時刻が00:00:00になるから、targetDateとフォーマットが揃う
- あとは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
- 投稿日:2019-10-24T14:46:23+09:00
【Java 】サーブレット(tomcat)&MySQL&Java でコネクションプールを使用して接続してみた
参考サイト
※ めちゃくちゃ参考になった!!!
Java で MySQL に 接続する 方法
https://garafu.blogspot.com/2016/05/how-to-connect-mysql.html#con-svlt1JDBS ドライバ導入
- 公式サイトから
mysql-connector-java-8.0.18.zip
をダウンロード- 解凍するして
mysql-connector-java-5.1.48-bin.jar
を取り出す/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.javapackage 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 } }
- 投稿日:2019-10-24T14:32:20+09:00
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を再起動します。
IBM Java SDK 8の導入
こちらからJDK 8 をダウンロードして、Cognosサーバーノードにインストールします。
https://developer.ibm.com/javasdk/downloads/sdk8/※Oracle Javaでも大丈夫という事です。試してはいないです。
JConsoleの起動
以下のコマンドで、JConsoleを起動します。
プロセスに接続
リモート・プロセスで接続すると、後述のイメージで「Mbeans」のタブの情報しか見えなかったので、「ローカル・プロセス」を指定し、プロセスとして赤枠のどちらかを選択します。
dataset-service = Query Serviceのプロセス
cognosserver = CognosのWebSphere Liberty本体
※リモート・プロセス接続の場合は、以下の指定。monitoring_serverはモニターしたいJavaプロセスが動作しているノード
service:jmx:rmi://Content_Manager_server/jndi/rmi://monitoring_server:8181/proxyserverどこかで役に立つ事もあると思うので、覚えておいて頂ければと。
- 投稿日:2019-10-24T14:01:54+09:00
処理をどこまで分けるのが正解か
比較しました
FUnction.javapackage 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です、別で用意してあります.
処理速度検証.javapackage 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かの差ですけど
メソッド.javapublic 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の中間操作のために生まれたのか...?
- 投稿日:2019-10-24T00:01:40+09:00
【Java】src/main/resourcesにあるファイルを読み込む
Javaで
src/main/resources
にあるファイルを読み込むのに少し手間取ったので備忘録です。1. ルートからの絶対パスで取得
src/main/resources/sample1.txtsample1src/main/java/Foo.javapublic 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(); } }実行結果sample12. クラスパスからの相対パスで取得
src/main/resources/sample2.txtsample2src/main/java/Foo.javapublic 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.txttest1src/test/resources/sample2.txttest2src/test/java/FooTest.javapublic 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 test21.の場合は、パスを直書きしているので当たり前ですが、
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)までお願いします。