Windowsで作成したDLLをJavaより呼び出して使用する
C言語で作成すると
超速いというのは知っていますが、そもそも他の言語で作成できるのかな?
と思ったので簡単なプログラムを作成して試してみる。
DLL作成
ウィザードが立ち上がるのでそのまま次へを選択
アプリケーションの種類を「DLL」を選択
こうなります
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
→ データ型が良くないので合わせる
参考
http://blue-red.ddo.jp/~ao/wiki/wiki.cgi?page=JNI%A1%A2JNA%A4%CE%BB%C8%A4%A4%CA%FD
JavaからCの処理を呼ぶ方法(JNI/JNA/SWIG) - Qiita
GitHub - java-native-access/jna: Java Native Access
javaでwindowsのdllを利用する | Tech-Sketch
Visual Studio 2015でDLLを作成して動的読み込みしてみる。 - 小さい頃はエラ呼吸
所感
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
できました(^^)
参考
(・ω・)Serendipity ::: Light in Moment - 14
4. ラージオブジェクト | TECHSCORE(テックスコア)
備忘録的なblog: OracleのBLOBにJavaオブジェクトを保存
わかったこと
- 対象のクラス(オブジェクト)にはSerializableを指定する必要がある。
- パッケージ名も保存されるので他のパッケージの同じ名前のクラスはエラーとなる
- 結構めんどくさい(´・ω・`)
です
JavaからMySQLに接続
スケジュールって基本できる時間で組むべきで
理想で組むべきじゃないと思う
残業した時点で既に破綻していることになっているから…
MySQL用のJarを取得する
https://dev.mysql.com/downloads/connector/j/へアクセス
※Oracleアカウントへのサインアップが必要です。
プロジェクトに追加する
データベース構成
テーブル
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のボットサンプルを作成
Jasksonを使うと簡単に解析できる
クラスやクラス内のネスト情報も取得できる
こんな画面
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をインストール
Tomcatインストール
http://tomcat.apache.org/よりダウンロード
↓
解凍、移動
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で確認
停止
$ 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" />
※ポート番号を変更
起動して確認
所感
正直、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
参考
NIO2を使ったファイルの読み書きメモ - xykの日記
Java技術最前線 - Java SE 7徹底理解 第4回 New I/O 2の新しいファイルシステムインタフェース その1:ITpro
java.nio.file.Filesのメソッドを一通り使ってみた - kagamihogeの日記
所感
Stringそのまま出力したいんですけど(´・ω・`)
昔の2つ3つのオブジェクトを使用しなくなったのは良かったと思います。
まだ、気になる点は多いですがファイルのオープン、クローズに手間書けないようなことは嬉しい。
Spring Bootでデータベースに接続
そろそろDB
Javaって他の言語より導入が面倒な部分が感じられるのでなかなか進まない
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>
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>
実行
参考
Spring Boot/第五回 Spring Bootで Web (一覧表示) - なべ’s blog
Spring BootでToDoアプリを作ってみた - かずきのBlog@hatena
Spring Bootでデータベースに接続 | Developers.IO
Spring Bootでデータベースに接続する - Qiita
Thymeleaf version 2.1.4の機能メモ - Qiita
Spring Data JPAによるデータ登録・更新・削除 その1 · dorakucommitter/assign Wiki · GitHub
Spring Data JPA でのクエリー実装方法まとめ - Qiita
※途中からこんがらがったよwww
所感
さわりさわりなのでまだ違和感がある。
なんとかここまでこぎつけた。まだ、認証とかバリデーションとかあるのでそのあたりも調べないといけない
結構やること多いです(´・ω・`)