m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

Windowsで作成したDLLをJavaより呼び出して使用する

C言語で作成すると

超速いというのは知っていますが、そもそも他の言語で作成できるのかな?
と思ったので簡単なプログラムを作成して試してみる。

環境

f:id:m_shige1979:20161210152446p:plain

Windows64系のVC++でDLLを作成し、それをeclipseで実行する。

DLL作成

プロジェクトの作成でC++Win32のコンソールアプリケーションを選択

f:id:m_shige1979:20161210153121p:plain

ウィザードが立ち上がるのでそのまま次へを選択

f:id:m_shige1979:20161210153257p:plain

アプリケーションの種類を「DLL」を選択

f:id:m_shige1979:20161210153546p:plain

こうなります

f:id:m_shige1979:20161210153929p:plain

SampleDll.cpp
// SampleDll.cpp : DLL アプリケーション用にエクスポートされる関数を定義します。
//

#include "stdafx.h"
#include "stdio.h"

int GetHello(int data)
{
	printf("%d", data);
	return 0;
}

※簡単な処理を作成する

SampleDll.def
LIBRARY SampleDll
EXPORTS
  GetHello @1

※公開設定としてdefファイルを追加して以下を記載する

64bitでビルドし、エクスポート関数を確認する
>"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\dumpbin.exe" /exports SampleDll.dll
Microsoft (R) COFF/PE Dumper Version 14.00.24215.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file SampleDll.dll

File Type: DLL

  Section contains the following exports for SampleDll.dll

    00000000 characteristics
    584B9C0D time date stamp Sat Dec 10 15:09:17 2016
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 0001102D GetHello = @ILT+40(?GetHello@@YAHH@Z)

  Summary

        1000 .00cfg
        1000 .data
        1000 .gfids
        1000 .idata
        3000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        8000 .text
       10000 .textbss

>

Javaで実装

JNA用のパッケージが必要

GitHub - java-native-access/jna: Java Native Access
上のサイトよりjna.jarをダウンロードしてライブラリとして登録する。

Sample01.java
package sample01;

import com.sun.jna.Library;
import com.sun.jna.Native;

interface HelloLib extends Library {
  // loadLibrary
  HelloLib INSTANCE = (HelloLib) Native.loadLibrary("C:/hogehoge/SampleDll.dll", HelloLib.class);

  // Cの関数名と一致させる
  int GetHello(int s);
}


public class Sample01 {

	public static void main(String[] args) {
		HelloLib hello = HelloLib.INSTANCE;

	    hello.GetHello(100);
	}

}

100

詰みかけたところ

Windows64bitでJNAでJavaからC++コード呼び出そうとしてハマった話 - きしだのはてな
→ 32bitで作成したのを64bitで実行しようとしてエラーになった(´・ω・`)

java - Invalid memory access - Stack Overflow
→ データ型が良くないので合わせる

所感

C++はわかりませんけどとりあえずは動かすことができました。
関数を実行することはできたけどクラス作ったやつのアクセスとかできるかもやってみたい。
同じような感じでいいのかな?

JavaでクラスをシリアライズしてDBへ保存

まあ、なんかの役に立つかもしれない

クラスをデータ化して保存する

環境

MySQL
Java8

テーブル定義

mysql> create table obj_data(
    ->   id integer not null auto_increment,
    ->   data blob,
    ->   create_at datetime,
    ->   update_at datetime,
    ->   primary key(id)
    -> );
Query OK, 0 rows affected (0.02 sec)

対象オブジェクト

package sample_mysql03;

import java.io.Serializable;

public class Item implements Serializable{
	
	private static final long serialVersionUID = 1L;
	private String name;
	private String price;
	private String remarks;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	public String getRemarks() {
		return remarks;
	}
	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
}

※Serializableが必要です。

追加処理

package sample_mysql03;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;

public class Sample01 {

	// 接続情報
	private static final String URL = "jdbc:mysql://192.168.33.10/myapp?useSSL=false";
	private static final String USER = "app";
	private static final String PASS = "Password123@";
	
	public static void main(String[] args) throws IOException {
		
		System.out.println("start");
		
		try (
				Connection con = DriverManager.getConnection(URL, USER, PASS);
				Statement st = con.createStatement();
				){
			
			// オブジェクト生成
			Item item = new Item();
			item.setName("hoge");
			item.setPrice("hoge");
			item.setName("bikoaaaaaaaa");
			
			String sql = null;
			PreparedStatement pstmt = null;
			int result;
			
			// プリペアードステートメント
			sql = "insert into obj_data(data, create_at) values(?, ?);";
			pstmt = con.prepareStatement(sql);
			
			// オブジェクトを出力するストリームをくみ上げる
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(item);
			
			ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
		    
			// ステートメントにパラメータを入れる
			pstmt.setBinaryStream(1, bais, baos.toByteArray().length);
			pstmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
			result = pstmt.executeUpdate();
			System.out.println("処理結果=" + result);
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("end");

	}

}

mysql> select * from obj_data;                                                                                        +----+-------------------------------------------------------------------------------------------------------------------------+---------------------+-----------+
| id | data                                                                                                                    | create_at           | update_at |
+----+-------------------------------------------------------------------------------------------------------------------------+---------------------+-----------+
|  1 | �� sr sample_mysql03.Item        L namet Ljava/lang/String;L priceq ~ L remarksq ~ xpt
                                                                                              bikoaaaaaaaat hogep   | 2016-12-04 16:27:06 | NULL      |
+----+-------------------------------------------------------------------------------------------------------------------------+---------------------+-----------+
1 row in set (0.00 sec)

mysql>

なんかそれっぽいデータが入っている。

読み込み

package sample_mysql04;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import sample_mysql03.Item;

public class Sample02 {

	// 接続情報
	private static final String URL = "jdbc:mysql://192.168.33.10/myapp?useSSL=false";
	private static final String USER = "app";
	private static final String PASS = "Password123@";
	
	public static void main(String[] args) throws IOException, ClassNotFoundException {
		
		System.out.println("start");
		
		try (
				Connection con = DriverManager.getConnection(URL, USER, PASS);
				Statement st = con.createStatement();
				){
			
			
			String sql = null;
			PreparedStatement pstmt = null;
			
			// プリペアードステートメント
			sql = "select * from obj_data where id = ?";
			pstmt = con.prepareStatement(sql);
			
			// パラメータ指定
			pstmt.setInt(1 , 2);
			
			Item item;
			
			// 実行
			ResultSet rs = pstmt.executeQuery();
			while(rs.next()){
				InputStream is = rs.getBinaryStream("data");
				ObjectInputStream obis = new ObjectInputStream(is);
				item = (Item) obis.readObject();
				
				System.out.println(item.getName() + "" + item.getPrice() + "" + item.getRemarks());
			}
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("end");

	}

}

start
name1price222bikobikobiko
end

できました(^^)

わかったこと

  • 対象のクラス(オブジェクト)にはSerializableを指定する必要がある。
  • パッケージ名も保存されるので他のパッケージの同じ名前のクラスはエラーとなる
  • 結構めんどくさい(´・ω・`)

です

JavaからMySQLに接続

スケジュールって基本できる時間で組むべきで

理想で組むべきじゃないと思う
残業した時点で既に破綻していることになっているから…

MySQLで接続

Java 1.8
MySQL

MySQL用のJarを取得する

https://dev.mysql.com/downloads/connector/j/へアクセス

f:id:m_shige1979:20161204103242p:plain
Oracleアカウントへのサインアップが必要です。

プロジェクトに追加する

f:id:m_shige1979:20161204103651p:plain

データベース構成

テーブル
mysql> create table item(
    ->   id integer not null auto_increment,
    ->   name varchar(50) not null,
    ->   price int not null,
    ->   create_at datetime,
    ->   update_at datetime,
    ->   primary key(id)
    -> );
サンプルデータ追加
mysql> insert into item(name, price, create_at) values('test1', 100, current_timestamp);
Query OK, 1 row affected (0.00 sec)

mysql> insert into item(name, price, create_at) values('test2', 150, current_timestamp);
Query OK, 1 row affected (0.00 sec)

mysql> insert into item(name, price, create_at) values('test2', 3000, current_timestamp);
Query OK, 1 row affected (0.00 sec)

mysql> insert into item(name, price, create_at) values('test4', 10000, current_timestamp);
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> select * from item;
+----+-------+-------+---------------------+-----------+
| id | name  | price | create_at           | update_at |
+----+-------+-------+---------------------+-----------+
|  1 | test1 |   100 | 2016-12-04 02:40:59 | NULL      |
|  2 | test2 |   150 | 2016-12-04 02:41:08 | NULL      |
|  3 | test2 |  3000 | 2016-12-04 02:41:13 | NULL      |
|  4 | test4 | 10000 | 2016-12-04 02:41:25 | NULL      |
+----+-------+-------+---------------------+-----------+
4 rows in set (0.00 sec)

実装

取得
package sample_mysql01;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Sample01 {
	
	// 接続情報
	private static final String URL = "jdbc:mysql://192.168.33.10/myapp?useSSL=false";
	private static final String USER = "app";
	private static final String PASS = "Password123@";
	
	public static void main(String[] args) {
		System.out.println("start");
		
		try (
				Connection con = DriverManager.getConnection(URL, USER, PASS);
				Statement st = con.createStatement();
				){
			
			String sql = null;
			ResultSet rs = null;
			PreparedStatement pstmt = null;
			
			// 単純なSQL
			sql = "select * from item;";
			rs = st.executeQuery(sql);
			while(rs.next()){
				int id = rs.getInt("id");
				String name = rs.getString("name");
				int price = rs.getInt("price");
				System.out.println("id=" + id + " name=" + name + " price=" + price);
			}
			rs.close();
			System.out.println();
			
			// プリペアードステートメント
			sql = "select * from item where price >= ?;";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, 300);
			rs = pstmt.executeQuery();
			while(rs.next()){
				int id = rs.getInt("id");
				String name = rs.getString("name");
				int price = rs.getInt("price");
				System.out.println("id=" + id + " name=" + name + " price=" + price);
			}
			rs.close();
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("end");
	}

}

start
id=1 name=test1 price=100
id=2 name=test2 price=150
id=3 name=test2 price=3000
id=4 name=test4 price=10000

id=3 name=test2 price=3000
id=4 name=test4 price=10000
end

実装

更新
package sample_mysql02;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;

public class Sample02 {
	
	// 接続情報
	private static final String URL = "jdbc:mysql://192.168.33.10/myapp?useSSL=false";
	private static final String USER = "app";
	private static final String PASS = "Password123@";
	
	public static void main(String[] args) {
		System.out.println("start");
		
		try (
				Connection con = DriverManager.getConnection(URL, USER, PASS);
				Statement st = con.createStatement();
				){
			
			String sql = null;
			ResultSet rs = null;
			PreparedStatement pstmt = null;
			int result;
			
			// プリペアードステートメント
			sql = "insert into item(name, price, create_at) values(?, ?, ?);";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, "hoge");
			pstmt.setInt(2, 500);
			pstmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
			result = pstmt.executeUpdate();
			
			// プリペアードステートメント
			sql = "update item set name = ?, update_at = ? where name = ?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, "foo");
			pstmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
			pstmt.setString(3, "hoge");
			result = pstmt.executeUpdate();
			
			// プリペアードステートメント
			sql = "select * from item where price >= ?;";
			pstmt = con.prepareStatement(sql);
			pstmt.setInt(1, 300);
			rs = pstmt.executeQuery();
			while(rs.next()){
				int id = rs.getInt("id");
				String name = rs.getString("name");
				int price = rs.getInt("price");
				System.out.println("id=" + id + " name=" + name + " price=" + price);
			}
			rs.close();
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("end");
	}

}

SE7以降は毎回閉じなくてもいい感じ…

本当は閉じたほうが良いかもしれないけど、try-catchでファイルとかは自動で開放してくれるようになったので
ちょっと楽な感じ

SQLはプログラムでは今後はプリペアしか使わない…

一応サンプルとして使って見たけどセキュリティの問題もあるので使わないようにする

BlumixのCFアプリのJavaサーブレットでLINE APIのボットサンプルを作成

Javaはクラスを基準に制御する

のでjson変換するのはjacksonを使用してみた。

LINE API

メッセージを送受信できるAPI
大抵のことはPHPでやっていたけどJavaでやっておく

・署名
json解析
・LINE送信

Jasksonを使うと簡単に解析できる

クラスやクラス内のネスト情報も取得できる

こんな画面

f:id:m_shige1979:20161203210414p:plain

pom.xmlの追加部分

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-core</artifactId>
		    <version>2.8.5</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-annotations</artifactId>
		    <version>2.8.5</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
		<dependency>
		    <groupId>com.fasterxml.jackson.core</groupId>
		    <artifactId>jackson-databind</artifactId>
		    <version>2.8.5</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
		<dependency>
		    <groupId>org.apache.httpcomponents</groupId>
		    <artifactId>httpclient</artifactId>
		    <version>4.5.2</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
		<dependency>
		    <groupId>org.apache.httpcomponents</groupId>
		    <artifactId>httpcore</artifactId>
		    <version>4.4.5</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
		<dependency>
		    <groupId>commons-codec</groupId>
		    <artifactId>commons-codec</artifactId>
		    <version>1.10</version>
		</dependency>

サンプルソース

package wasdev.sample.servlet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

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.servlet.ServletContext;
import java.io.BufferedReader;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

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

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, JsonParseException, JsonMappingException {
    	
    	ServletContext sc = getServletContext();
    	String num = (String)sc.getAttribute("count");
    	if(null == num){
    		num = "1";
    	} else {
    		num = String.valueOf((Integer.parseInt(num) + 1));
    	}
    	sc.setAttribute("count", num);
    	
    	String body = (String)sc.getAttribute("body");
    	String token = (String)sc.getAttribute("token");
    	String signature = (String)sc.getAttribute("signature");
    	
    	response.setContentType("text/html; charset=UTF-8");
        response.getWriter().print(num);
        response.getWriter().print(body);
        response.getWriter().print(token);
        response.getWriter().print(signature);
    }
    
    @Override    
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
    	
    	ServletContext sc = getServletContext();
    	String num = (String)sc.getAttribute("count");
    	if(null == num){
    		num = "1";
    	} else {
    		num = String.valueOf((Integer.parseInt(num) + 1));
    	}
    	sc.setAttribute("count", num);
    	
    	// 受信
    	BufferedReader bufferReaderBody = new BufferedReader(request.getReader());
		String body = bufferReaderBody.readLine();
		sc.setAttribute("body", body);
		
		// 署名
		try{
			String channel_secret = "シークレットキー";
			String signature = request.getHeader("X-Line-Signature");
			SecretKeySpec key = new SecretKeySpec(channel_secret.getBytes(), "HmacSHA256");
			Mac mac = Mac.getInstance("HmacSHA256");
			mac.init(key);
	        byte[] source = body.getBytes(StandardCharsets.UTF_8);
	        String createdSignature = Base64.encodeBase64String(mac.doFinal(source));
	        if (!signature.equals(createdSignature)) {
		    	sc.setAttribute("signature", "ng");
	        	response.setStatus(200);
	            return;
	        }else{
		    	sc.setAttribute("signature", "ok");
	        }
		}catch(NoSuchAlgorithmException e){
		}catch(InvalidKeyException e){
		}
		
		// json->オブジェクト変換
		ObjectMapper mapper = new ObjectMapper();
        LineBotResponse result = mapper.readValue(body, LineBotResponse.class);
        
        // イベントデータ取得
        Event event = result.get(0);
            System.out.println(event.replyToken);
    	sc.setAttribute("token", event.replyToken);
    	
    	// 送信データを作成
    	LineBotRequest lineReq = null;
        String json = null ;
        lineReq = new LineBotRequest();
        lineReq.replyToken = event.replyToken;
        lineReq.messages.add(new SendMessageText("hogehoge"));
        json = mapper.writeValueAsString(lineReq);
        
        // 送信処理
        String access_token = "シークレットアクセスキー";
        HttpPost httpPost = new HttpPost("https://api.line.me/v2/bot/message/reply");    
        httpPost.setHeader("Content-Type", "application/json");
       	httpPost.setHeader("Authorization", "Bearer " + access_token);
        StringEntity params = new StringEntity(json, StandardCharsets.UTF_8);
        httpPost.setEntity(params);
        
        try (CloseableHttpClient client = HttpClients.createDefault();
                CloseableHttpResponse resp = client.execute(httpPost);
                BufferedReader br = new BufferedReader(new InputStreamReader(resp.getEntity().getContent(), StandardCharsets.UTF_8))) {
            
            int statusCode = resp.getStatusLine().getStatusCode();
            switch (statusCode) {
            case 200:
                // ↓これは空のJSON({})が返るはず
                br.readLine();
                break;
            default:
            }
        } catch (final ClientProtocolException e) {
        } catch (final IOException e) {
        }
    	
    }

}

Macにtomcatをインストール

外部に配置したいんだけどね…

eclipseとかで開発する場合はないと動かない見ないだし(´・ω・`)

環境

mac
Java 1.8系

Tomcatインストール

http://tomcat.apache.org/よりダウンロード

f:id:m_shige1979:20161130065557p:plain

f:id:m_shige1979:20161130065738p:plain

解凍、移動
tar zxf apache-tomcat-8.5.8.tar.gz
sudo mv apache-tomcat-8.5.8 /usr/local/tomcat
起動
$ sh /usr/local/tomcat/bin/startup.sh
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.
$
localhost:8080で確認

f:id:m_shige1979:20161130070333p:plain

停止
$ sh /usr/local/tomcat/bin/shutdown.sh
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
$

ポート変更

/usr/local/tomcat/conf/server.xml
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

    <Connector port="8100" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

※ポート番号を変更

起動して確認

f:id:m_shige1979:20161130071117p:plain

所感

正直、macに入れたくはなかった。設定をシンプルにしているので消すのはそんなに困らないと思うけど
まあポート番号を変更できたのでなんとかこれで対応する。
仕事で使うかもしれないのでちょっと勉強してみる。

Javaによるnio2での簡単なファイル読み書き

NIO2?

JavaのSE7から出てきたファイル制御が少し簡単になるライブラリです。
ファイルを閉じるときに意味不明なtry-catch文の対応と一緒に組み込まれたのかな?

昔のやつ

Sample02.java
package sample02;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Sample02 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        FileWriter fw;
        BufferedWriter bw;
        PrintWriter pw;
        
        FileReader fr;
        BufferedReader br;
        
        try{
            File f = new File("/tmp/bbb.txt");
            
            // ファイル書き込み
            fw = new FileWriter(f, true);
            bw = new BufferedWriter(fw);
            pw = new PrintWriter(bw);
            
            pw.write("bbb\n");
            pw.close();
            
            // ファイル読み込み
            fr = new FileReader(f);
            br = new BufferedReader(fr);
            String s;
            String s2 = "";
            while((s = br.readLine()) != null){
                s2 += s + "\n";
            }
            System.out.println(s2);
            
        }catch(IOException e){
            e.printStackTrace();
        }
        
    }
    
}

新しいやつ

Sample01.java
package sample01;

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;


public class Sample01 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        // 初期設定
        FileSystem fs = FileSystems.getDefault();
        
        // パスを指定
        Path path1 = fs.getPath("/tmp", "aaa1.txt");
        
        try {
            // 簡易書き込み
            Path write;
            write = Files.write(
                    path1, 
                    "aaa\n".getBytes(), 
                    StandardOpenOption.CREATE, 
                    StandardOpenOption.APPEND);
            
            // 簡易読み込み
            byte[] readAllBytes = Files.readAllBytes(path1);
            System.out.println(new String(readAllBytes, "utf-8"));
            
        } catch (IOException ex) {
            Logger.getLogger(Sample01.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
}

aaa
aaa
aaa
aaa

所感

Stringそのまま出力したいんですけど(´・ω・`)
昔の2つ3つのオブジェクトを使用しなくなったのは良かったと思います。
まだ、気になる点は多いですがファイルのオープン、クローズに手間書けないようなことは嬉しい。

Spring Bootでデータベースに接続

そろそろDB

Javaって他の言語より導入が面倒な部分が感じられるのでなかなか進まない

環境

Spring Boot 1.4
MySQL 5.x
MySQLvagrantに配置して接続してみる

DB設定

DDL作成
create table if not exists memo (
  id int not null auto_increment,
  name varchar(30) not null,
  memo varchar(128),
  create_at datetime not null default current_timestamp,
  update_at datetime not null default current_timestamp on update current_timestamp,
  primary key (id)
) engine = INNODB;
テストデータを作成
insert into `memo`(name, memo) values('test01', 'hogehoge01');
insert into `memo`(name, memo) values('test02', 'hogehoge02');
insert into `memo`(name, memo) values('test03', 'hogehoge03');
insert into `memo`(name, memo) values('test04', 'hogehoge04');
insert into `memo`(name, memo) values('test05', 'hogehoge05');
insert into `memo`(name, memo) values('test06', 'hogehoge06');
insert into `memo`(name, memo) values('test07', 'hogehoge07');
insert into `memo`(name, memo) values('test08', 'hogehoge08');
insert into `memo`(name, memo) values('test09', 'hogehoge09');
insert into `memo`(name, memo) values('test10', 'hogehoge10');

maven設定

pom.xml
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		
	</dependencies>

jpaMySQLの情報を追加

application.yml
server:
  port: 7777
spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.33.10/myapp?useSSL=false
    username: app
    password: Password123@
  jpa:
    hibernate:
      show-sql: true
      ddl-auto: update
    database-platform: org.hibernate.dialect.MySQLDialect

MySQLの接続設定を追加

画面用(ホントはいらないかも…)

MemoForm.java
package com.example.beans;

import java.io.Serializable;
import java.sql.Timestamp;

public class MemoForm implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -3570891756024535003L;

	private Integer id;
	private String name;
	private String memo;
	private Timestamp createAt;
	private Timestamp updateAt;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public Timestamp getCreateAt() {
		return createAt;
	}

	public void setCreateAt(Timestamp createAt) {
		this.createAt = createAt;
	}

	public Timestamp getUpdateAt() {
		return updateAt;
	}

	public void setUpdateAt(Timestamp updateAt) {
		this.updateAt = updateAt;
	}
	
}

エンティティ準備

Memo.java
package com.example.entities;

import java.io.Serializable;
import java.sql.Timestamp;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "memo")
public class Memo implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -3570891756024535003L;

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Integer id;
	
	@Column(name="name")
	private String name;
	
	@Column(name="memo")
	private String memo;
	
	@Column(name="create_at")
	private Timestamp createAt;

	@Column(name="update_at")
	private Timestamp updateAt;
	
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public Timestamp getCreateAt() {
		return createAt;
	}

	public void setCreateAt(Timestamp createAt) {
		this.createAt = createAt;
	}

	public Timestamp getUpdateAt() {
		return updateAt;
	}

	public void setUpdateAt(Timestamp updateAt) {
		this.updateAt = updateAt;
	}
	
}

リポジトリ

MemoRepository.java
package com.example.repositories;

import org.springframework.data.jpa.repository.JpaRepository;

import com.example.entities.Memo;

public interface MemoRepository extends JpaRepository<Memo, Long>{
	public Memo findById(Integer id);
}

サービス

MemoService.java
package com.example.services;

import java.sql.Timestamp;
import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.beans.MemoForm;
import com.example.entities.Memo;
import com.example.repositories.MemoRepository;

@Service
@Transactional
public class MemoService {
	@Autowired
	MemoRepository repository;
	
	/**
	 * 全件取得
	 * @return
	 */
	public List<Memo> getAllList() {
		return repository.findAll();
	}
	
	/**
	 * 1件取得
	 * @return
	 */
	public MemoForm getMemo(Integer id) {
		Memo newMemo = repository.findById(id);
		
		MemoForm form = new MemoForm();
		form.setId(newMemo.getId());
		form.setName(newMemo.getName());
		form.setMemo(newMemo.getMemo());
		form.setCreateAt(newMemo.getCreateAt());
		form.setUpdateAt(newMemo.getUpdateAt());
		
		return form;
	}
	
	/**
	 * 追加
	 * @param memo
	 * @return
	 */
	public Memo regist(MemoForm form) {
		
		// 新しく作成して値を設定
		Memo memo = new Memo();
		memo.setName(form.getName());
		memo.setMemo(form.getMemo());
		memo.setCreateAt(new Timestamp(System.currentTimeMillis()));
		memo.setUpdateAt(new Timestamp(System.currentTimeMillis()));
		
		// 登録
		return repository.save(memo);
	}
	
	/**
	 * 追加
	 * @param memo
	 * @return
	 */
	public Memo update(MemoForm form) {
		
		// 新しく作成して値を設定
		Memo memo = new Memo();
		memo.setId(form.getId());
		memo.setName(form.getName());
		memo.setMemo(form.getMemo());
		memo.setCreateAt(form.getCreateAt());
		memo.setUpdateAt(new Timestamp(System.currentTimeMillis()));
		
		// 更新
		return repository.save(memo);
	}
	
	/**
	 * 削除
	 * @param id
	 */
	public void remove(Integer id) {
		Memo memo = new Memo();
		memo.setId(id);
		repository.delete(memo);
	}
}

コントローラー

MemoController.java
package com.example.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.example.beans.MemoForm;
import com.example.entities.Memo;
import com.example.services.MemoService;

@Controller
@RequestMapping("memo")
public class MemoController {
	
	@Autowired
	private MemoService memoService;
	
	/**
	 * 一覧表示
	 * @return
	 */
	@RequestMapping(method = {RequestMethod.GET})
	public ModelAndView index() {
		
		// 一覧を取得
		List<Memo> list = memoService.getAllList();
		
		// Modelを生成
		ModelAndView mv = new ModelAndView();
		
		// 取得したデータを画面へ割当
		mv.addObject("list", list);
		
		// 使用するビューを指定
		mv.setViewName("memo/index");
		
		// view
		return mv;
	}
	
	/**
	 * 新規画面
	 * @return
	 */
	@RequestMapping(value = {"new"}, method = {RequestMethod.GET})
	public ModelAndView _new(@ModelAttribute MemoForm form) {
		
		// Modelを生成
		ModelAndView mv = new ModelAndView();
				
		// 使用するビューを指定
		mv.setViewName("memo/new");
		
		// formを設定する
		mv.addObject("form", form);
		
		// view
		return mv;
	}
	
	/**
	 * 登録処理
	 * @return
	 */
	@RequestMapping(value = {"regist"}, method = {RequestMethod.POST})
	public String regist(@ModelAttribute MemoForm form) {
		
		// 追加処理
		memoService.regist(form);
		
		// view
		return "redirect:/memo";
	}
	
	/**
	 * 編集画面
	 * @param id
	 * @return
	 */
	@RequestMapping(value = {"edit/{id}"}, method = {RequestMethod.GET})
	public ModelAndView edit(@PathVariable("id") String id) {
		
		MemoForm form = memoService.getMemo(Integer.parseInt(id));
		
		// Modelを生成
		ModelAndView mv = new ModelAndView();
						
		// 使用するビューを指定
		mv.setViewName("memo/edit");
			
		// formを設定する
		mv.addObject("form", form);
				
		// view
		return mv;
	}
	
	/**
	 * 更新処理
	 * @return
	 */
	@RequestMapping(value = {"update"}, method = {RequestMethod.POST})
	public String update(@ModelAttribute MemoForm form) {
		
		// 更新処理
		memoService.update(form);
		
		// view
		return "redirect:/memo";
	}
	
	/**
	 * 削除実施
	 * @param id
	 * @return
	 */
	@RequestMapping(value = {"remove/{id}"}, method = {RequestMethod.GET})
	public String remove(@PathVariable("id") String id) {
		
		// 削除実行
		memoService.remove(Integer.parseInt(id));
		
		// 一覧へリダイレクトする
		return "redirect:/memo";
	}
	
}

ビュー

memo/index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Spring Sample Memo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Memo Sample</h1>
	<div>
		<a href="/memo/new">new</a>
    	<table>
    		<tbody th:if="${list} != null">
    			<tr th:each="memo: ${list}">
    				<td th:text="${memo.id}"><br /></td>
    				<td th:text="${memo.name}"><br /></td>
    				<td th:text="${memo.memo}"><br /></td>
    				<td th:text="${memo.createAt}"><br /></td>
    				<td th:text="${memo.updateAt}"><br /></td>
    				<td>
    					<a th:href="@{/memo/edit/{id}(id=${memo.id})}">edit</a>
    				</td>
    				<td>
    					<a th:href="@{/memo/remove/{id}(id=${memo.id})}">remove</a>
    				</td>
    			</tr>
    		</tbody>
    	</table>
	</div>
</body>
</html>
memo/new.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Spring Sample Memo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Memo Sample</h1>
	<div>
    	<form th:action="@{/memo/regist}" method="post">
    		<table>
    			<tr>
    				<th>name</th>
    				<td>
    					<input type="text" name="name" />
    				</td>
    			</tr>
    			<tr>
    				<th>memo</th>
    				<td>
    					<input type="text" name="memo" />
    				</td>
    			</tr>
    		</table>
    		<input type="submit" value="登録する" />
    	</form>
	</div>
</body>
</html>
memo/edit.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Spring Sample Memo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<h1>Memo Sample</h1>
	<div>
    	<form th:action="@{/memo/update}"  method="post">
    		<input type="hidden" name="id" th:field="${form.id}" />
    		<input type="hidden" name="createAt" th:field="${form.createAt}" />
    		<table>
    			<tr>
    				<th>name</th>
    				<td>
    					<input type="text" name="name" th:field="${form.name}" />
    				</td>
    			</tr>
    			<tr>
    				<th>memo</th>
    				<td>
    					<input type="text" name="memo" th:field="${form.memo}" />
    				</td>
    			</tr>
    		</table>
    		<input type="submit" value="更新する" />
    	</form>
	</div>
</body>
</html>

実行

所感

さわりさわりなのでまだ違和感がある。
なんとかここまでこぎつけた。まだ、認証とかバリデーションとかあるのでそのあたりも調べないといけない
結構やること多いです(´・ω・`)