m_shige1979のときどきITブログ

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

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

https://github.com/mshige1979

JavaからDLLを呼び出してみる3

タイトルあんまり名前が繋がってない

まあ、意味は伝わるはず

やりたいこと

C++で作成したクラスをJavaで呼び出したい
でもできない(やりかたがわからない)ので関数でラップして使用する。

C++のクラス用DLLを作成

MathFuncsDll.h
// MathFuncsDll.h

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

namespace MathFuncs
{
	// This class is exported from the MathFuncsDll.dll
	class MyMathFuncs
	{
	public:
		// Returns a + b
		static MATHFUNCSDLL_API double Add(double a, double b);

		// Returns a - b
		static MATHFUNCSDLL_API double Subtract(double a, double b);

		// Returns a * b
		static MATHFUNCSDLL_API double Multiply(double a, double b);

		// Returns a / b
		// Throws const std::invalid_argument& if b is 0
		static MATHFUNCSDLL_API double Divide(double a, double b);
	};
}
MathFuncsDll.cpp
// MathFuncsDll.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "MathFuncsDll.h"
#include <stdexcept>

using namespace std;

namespace MathFuncs
{
	double MyMathFuncs::Add(double a, double b)
	{
		return a + b;
	}

	double MyMathFuncs::Subtract(double a, double b)
	{
		return a - b;
	}

	double MyMathFuncs::Multiply(double a, double b)
	{
		return a * b;
	}

	double MyMathFuncs::Divide(double a, double b)
	{
		if (b == 0)
		{
			throw invalid_argument("b cannot be zero!");
		}

		return a / b;
	}
}

ラッパー用

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

#include "stdafx.h"

#include "./MathFuncsDll.h"

double MyMathFuncs_Add(double a, double b) {
	return MathFuncs::MyMathFuncs::Add(a, b);
}
SampleDllWrapper.def
LIBRARY SampleDllWrapper
EXPORTS
  MyMathFuncs_Add @1

※DLLを参照して、ヘッダーファイルを指定する

Java

Sample02.java
package sample02;

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

interface HelloLib extends Library {
  HelloLib INSTANCE = (HelloLib) Native.loadLibrary("SampleDllWrapper.dll", HelloLib.class);

  // Cの関数名と一致させる
  double MyMathFuncs_Add(double s1, double s2);
}


public class Sample02 {

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

		double a = 100;
		double b = 1200;
	    System.out.println(hello.MyMathFuncs_Add(a, b));
	}

}

1300.0

※データ型がうまくあわないとエラーになりました(´・ω・`)

わかったこと

DLLを静的に読み込んでいるのでヘッダーファイルなどが必要。
最終的にはDLLだけでやりたいのでヘッダーファイルなしのバージョンも知りたい
難しいなあ(´・ω・`)

Windowsで作成したDLLをJavaで動かす2

関数を1つしか定義していなかったので

複数定義した場合のパターンをやってみる

SampleDll.cpp

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

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

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

int GetHelloString(char *data)
{
	printf("%s", data);
	return 0;
}

int GetHelloAdd(int data1, int data2)
{
	return data1 + data2;
}

SampleDll.def

LIBRARY SampleDll
EXPORTS
  GetHello @1
  GetHelloString @2
  GetHelloAdd @3

※この@1とかって引数のやつと思ったけど違うようです。
DEF ファイルを使った DLL からのエクスポート

エクスポート関数を確認

Dump of file SampleDll.dll

File Type: DLL

  Section contains the following exports for SampleDll.dll

    00000000 characteristics
    5857D09C time date stamp Mon Dec 19 21:20:44 2016
        0.00 version
           1 ordinal base
           3 number of functions
           3 number of names

    ordinal hint RVA      name

          1    0 0001102D GetHello = @ILT+40(?GetHello@@YAHH@Z)
          3    1 00011190 GetHelloAdd = @ILT+395(?GetHelloAdd@@YAHHH@Z)
          2    2 0001121C GetHelloString = @ILT+535(?GetHelloString@@YAHPEAD@Z)

  Summary

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

Javaで実装

Sample01.java
package sample01;

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

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

  // Cの関数名と一致させる
  int GetHello(int s);
  int GetHelloString(String s);
  int GetHelloAdd(int s1, int s2);
}


public class Sample01 {

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

	    hello.GetHello(100);
	    hello.GetHelloString("hoge");
	    System.out.println(hello.GetHelloAdd(600, 1200));
	}

}

1800
100hoge

※system.out.printlnのほうが先に出力していますね、なんで?

わかったこと

・char *で定義したら Stringで一致する。
・byte[]のやつは一部文字化けらしき問題を起こすらしい
・結果の出力は前後する場合がある

所感

C++とかほとんど知らないけどなんかJavaから呼び出せるようになるとちょっとおもしろい

Spring Bootでアップロードファイルを受け取る

FormとかBeanとかいうクラスを使用することで受け取ることが可能になりました。

ファイルってどうするのかな?

MultipartFileとかいうクラス

があれば受け取れます(^^)

フォーム系

SendDataForm.java
package com.example.form;

import java.io.Serializable;

import org.springframework.web.multipart.MultipartFile;

public class SendDataForm implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String id;
	private String text;
	private String item_id;
	private MultipartFile upload_file;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public String getItem_id() {
		return item_id;
	}
	public void setItem_id(String item_id) {
		this.item_id = item_id;
	}
	public MultipartFile getUpload_file() {
		return upload_file;
	}
	public void setUpload_file(MultipartFile upload_file) {
		this.upload_file = upload_file;
	}
	
	public String toString(){
		String str = "";
		
		str += "id = " + this.id + "\n";
		str += "text = " + this.text + "\n";
		str += "item_id = " + this.item_id + "\n";
		
		if(null !=  this.upload_file){
			str += "upload_file = " + this.upload_file.getOriginalFilename() + " size = " + this.upload_file.getSize() + "\n";
		}
		
		return str;
	}
	
}
Item.java
package com.example.form;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Item implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String id;
	private String text;
	private String item_id;
	private String upload_file;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public String getItem_id() {
		return item_id;
	}
	public void setItem_id(String item_id) {
		this.item_id = item_id;
	}
	public String getUpload_file() {
		return upload_file;
	}
	public void setUpload_file(String upload_file) {
		this.upload_file = upload_file;
	}
	
}

受信用コントローラー

SampleController.java
package com.example.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.example.form.Item;
import com.example.form.SendDataForm;

@RestController
@RequestMapping("/sample")
public class SampleController {
	
	@RequestMapping(value = "/upload", method = {RequestMethod.POST})
	public Item upload(SendDataForm form){
		
		Item item = new Item();
		item.setId(form.getId());
		item.setText(form.getText());
		item.setItem_id(form.getItem_id());
		item.setUpload_file(form.getUpload_file().getOriginalFilename());
		
		return item;
	}
	
}

実験

$ curl -X POST http://localhost:8080/sample/upload \
>     -F "id=100" \
>     -F "text=hogehoge" \
>     -F "item_id=12345678" \
>     -F "upload_file=@work/file/image.jpg"
{"id":"100","text":"hogehoge","item_id":"12345678","upload_file":"image.jpg"}

curlってこういうとき簡単に試せるから便利(^^)

MultipartFileの中でファイルの名前やサイズ、データも管理できるみたいなので結構便利な感じ
フォームで送信する形式になるのでヘッダーにjsonとかは設定できないんですね…なんかその辺まだ良くわかっていない(´・ω・`)
まあ、json形式で返却できるみたいなので大丈夫かな?

参考

Spring Bootでファイルをアップロードする - かずきのBlog@hatena


終わり
今回はここまで
(そろそろ認証まわり調べてみたい…)

Spring Bootでjson文字列を受信してクラスに割り当てる

BeanとかFormとか呼ばれているもので画面とかの項目が設定されるやつ

前の時代などではパラメータを指定して取り込んでいたけどjsonで送った場合なども対応したクラスに割り当てたい場合等に対応
json形式で送った際きちんとクラスに設定されるか検証する

やること

受付用のクラスを作成
@RequestBodyアノテーションを使用
@RequestMappingで受け付けるデータを指定

受付用クラス

ItemForm.java
package com.example.form;

import java.io.Serializable;

public class ItemForm implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String name;
	private String date;
	private String price;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public String getPrice() {
		return price;
	}
	public void setPrice(String price) {
		this.price = price;
	}
	
	public String toString(){
		return "name = " + this.name + " date = " + this.date + " price = " + this.price;
	}
	
}
ItemsForm.java
package com.example.form;

import java.io.Serializable;
import java.util.List;

public class ItemsForm implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String count;
	private List<ItemForm> items;
	
	public String getCount() {
		return count;
	}
	public void setCount(String count) {
		this.count = count;
	}
	public List<ItemForm> getItems() {
		return items;
	}
	public void setItems(List<ItemForm> items) {
		this.items = items;
	}
	
	public String toString(){
		
		String str = "";
		
		str = "count = " + this.count + "\n";
		str += "";
		for(ItemForm item : this.items) {
			str += item.toString() + "\n";
		}
		
		return str;
	}
	
}

コントローラー設定

SampleController.java
package com.example.web;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.form.ItemForm;
import com.example.form.ItemsForm;

@RestController
@RequestMapping("/sample")
public class SampleController {
	
	@RequestMapping(value = "/test1", method = {RequestMethod.POST}, consumes = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public String item(@RequestBody ItemForm form){
		return form.toString();
	}
	
	@RequestMapping(value = "/test2", method = {RequestMethod.POST}, consumes = MediaType.APPLICATION_JSON_VALUE)
	@ResponseBody
	public String items(@RequestBody ItemsForm form){
		return form.toString();
	}
	
}

実行結果

・/sample/test1

$ curl -X POST \
>     -H 'Content-Type:application/json' \
>     -d '{
>         "name": "hogehoge",
>         "date": "20151028",
>         "price": "12000"
>     }' http://localhost:8080/sample/test1
name = hogehoge date = 20151028 price = 12000

・/sample/test2

$ curl -X POST \
>     -H 'Content-Type:application/json' \
>     -d '{
>         "count": "10",
>         "items": [
>             {
>                 "name": "foo1",
>                 "date": "20160112",
>                 "price": "1200"
>             },
>             {
>                 "name": "foo2",
>                 "date": "20160212",
>                 "price": "4300"
>             },
>             {
>                 "name": "foo3",
>                 "date": "20160217",
>                 "price": "2500"
>             },
>             {
>                 "name": "foo4",
>                 "date": "20160519",
>                 "price": "2000"
>             },
>             {
>                 "name": "foo5",
>                 "date": "20160630",
>                 "price": "1500"
>             }
>         ]
>     }' http://localhost:8080/sample/test2
count = 10
name = foo1 date = 20160112 price = 1200
name = foo2 date = 20160212 price = 4300
name = foo3 date = 20160217 price = 2500
name = foo4 date = 20160519 price = 2000
name = foo5 date = 20160630 price = 1500
$


クラスを階層構造を内部に持つことでネスト構造の場合も対応できる感じ
ファイルとかできるかはわからない
送り込むjsonのキーが存在しなくてもクラスの方はnullになるだけでエラーを起こすわけではない

所感

フレームワークも新しくなることでいままで手動でゴリゴリやっていた部分が結構簡単に対応できるようになった感じ、
ただ、会社では簡単に新しいフレームワークを試せないのでちょっともったいない気がする。
とりあえず、新しい技術に取り残されないように勉強はしておかないと…

Spring BootでXMLやJSONを返す

忙しいです…

(´・ω・`)

Spring BootでRest APIを作成する場合には

・コントローラー用のクラスに"@RestController"アノテーションを付ける
・クラスを任意で用意して返却することで基本、json形式で返却できる
XMLを返したい場合は返却用のクラスに"@XmlRootElement"を付与する必要があります

返却用のクラス

Item.java
package com.example.entity;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Item implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private String name;
	private String date;
	
	public Item(){
	}
	public Item(String name, String date){
		this.name = name;
		this.date = date;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	
	
}

コントローラー

Sample1Controller.java
package com.example.web;

import java.util.List;
import java.util.ArrayList;

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.bind.annotation.RestController;

import com.example.entity.Item;

@RestController
@RequestMapping("/sample1")
public class Sample1Controller {
	
	private List<Item> items = new ArrayList<Item>();
	
	Sample1Controller(){
		items.add(new Item("hoeg1", "20131122"));
		items.add(new Item("hoeg2", "20131130"));
		items.add(new Item("hoeg3", "20131205"));
		items.add(new Item("hoeg4", "20131210"));
		items.add(new Item("hoeg5", "20131225"));
		items.add(new Item("hoeg6", "20141012"));
		items.add(new Item("hoeg7", "20141014"));
		items.add(new Item("hoeg8", "20141024"));
	}
	
	@RequestMapping(value = "/", method = { RequestMethod.GET })
	public String index(){
		return "/sample/index";
	}
	
	@RequestMapping(value = "/test1", method = { RequestMethod.GET })
	public String test1(){
		return "/sample/test1";
	}
	
	@RequestMapping(value = "/items", method = { RequestMethod.GET })
	public List<Item> items(){
		return this.items;
	}
	
	@RequestMapping(value = "/item/{id}", method = { RequestMethod.GET })
	public Item item(@PathVariable int id){
		return this.items.get(id);
	}
	
}

内容

・/sample1
→ "/sample/index"を返す

$ curl -i -H "Accept: application/json" \
>        http://localhost:8080/sample1/
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Content-Length: 13
Date: Sat, 17 Dec 2016 04:10:47 GMT

/sample/index

・/sample1/test1
→ "/sample/test1"を返す

$ curl -i -H "Accept: application/json" \
>        http://localhost:8080/sample1/test1
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Content-Length: 13
Date: Sat, 17 Dec 2016 04:11:29 GMT

/sample/test1

・/sample1/items
→ itemクラスのjson一覧を返す

$ curl -i -H "Accept: application/json" \
>        http://localhost:8080/sample1/items
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 17 Dec 2016 04:11:56 GMT

[{"name":"hoeg1","date":"20131122"},{"name":"hoeg2","date":"20131130"},{"name":"hoeg3","date":"20131205"},{"name":"hoeg4","date":"20131210"},{"name":"hoeg5","date":"20131225"},{"name":"hoeg6","date":"20141012"},{"name":"hoeg7","date":"20141014"},{"name":"hoeg8","date":"20141024"}]

・/sample1/item{id}
→ itemクラスのjsonを返す

$ curl -i -H "Accept: application/json" \
>        http://localhost:8080/sample1/item/5
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sat, 17 Dec 2016 04:12:21 GMT

{"name":"hoeg6","date":"20141012"}

所感

XMLは工夫が必要ですが基本的にはjsonで返す。
json時は特に何もしなくてもクラスを返すだけでいいので楽そう。

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を指定する必要がある。
  • パッケージ名も保存されるので他のパッケージの同じ名前のクラスはエラーとなる
  • 結構めんどくさい(´・ω・`)

です