m_shige1979のときどきITブログ

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

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

https://github.com/mshige1979

doma2によるデータの抽出を試す

この前は自動生成しかしていないので

自動生成なしで準備して見る

環境

Mac
eclipse

ライブラリ

doma2
mysql

準備

Javaプロジェクトを準備し、ライブラリを設定しておく

f:id:m_shige1979:20161224014909p:plain

プロジェクトのプロパティより注釈処理を有効にしておく

f:id:m_shige1979:20161224015143p:plain

ファクトリーパスにdoma2のjarを設定する

f:id:m_shige1979:20161224015313p:plain

※これらの設定を行わないとdoma2のアノテーションでDaoの実装クラスを生成できない

プロジェクト構成

.
├── bin
│   ├── META-INF
│   │   └── com
│   │       └── example
│   │           └── dao
│   │               └── ItemDao
│   │                   └── findAll.sql
│   ├── com
│   │   └── example
│   │       ├── Sample01$1.class
│   │       ├── Sample01.class
│   │       ├── config
│   │       │   └── AppConfig.class
│   │       ├── dao
│   │       │   ├── ItemDao.class
│   │       │   └── ItemDaoImpl.class
│   │       └── entity
│   │           ├── Item.class
│   │           └── _Item.class
│   ├── doma-2.0.1.jar
│   └── mysql-connector-java-5.1.40.jar
├── lib
│   ├── doma-2.0.1.jar
│   └── mysql-connector-java-5.1.40.jar
└── src
    ├── META-INF
    │   └── com
    │       └── example
    │           └── dao
    │               └── ItemDao
    │                   └── findAll.sql
    └── com
        └── example
            ├── Sample01.java
            ├── config
            │   └── AppConfig.java
            ├── dao
            │   └── ItemDao.java
            └── entity
                └── Item.java

設定情報クラス

AppConfig
package com.example.config;

import javax.sql.DataSource;

import org.seasar.doma.SingletonConfig;
import org.seasar.doma.jdbc.Config;
import org.seasar.doma.jdbc.dialect.Dialect;
import org.seasar.doma.jdbc.dialect.MysqlDialect;
import org.seasar.doma.jdbc.tx.LocalTransactionDataSource;
import org.seasar.doma.jdbc.tx.LocalTransactionManager;
import org.seasar.doma.jdbc.tx.TransactionManager;

@SingletonConfig
public class AppConfig implements Config {
	
	private static final AppConfig INSTANCE = new AppConfig();

    private final Dialect dialect;
    private final LocalTransactionDataSource dataSource;
    private final TransactionManager transactionManager;

    private AppConfig() {
        dialect = new MysqlDialect();
        dataSource = new LocalTransactionDataSource("jdbc:mysql://192.168.33.10:3306/myapp?useSSL=false", "app", "Password123@");
        transactionManager = new LocalTransactionManager(dataSource.getLocalTransaction(getJdbcLogger()));
    }
	
	@Override
	public DataSource getDataSource() {
		// TODO Auto-generated method stub
		return dataSource;
	}

	@Override
	public Dialect getDialect() {
		// TODO Auto-generated method stub
		return dialect;
	}
	
	@Override
    public TransactionManager getTransactionManager() {
        return transactionManager;
    }

    public static AppConfig singleton() {
        return INSTANCE;
    }

}

エンティティ

Item
package com.example.entity;

import java.time.LocalDateTime;

import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

@Entity
@Table(name = "item")
public class Item {
	
	@Id
	private Integer id;
	
	@Column(name = "name")
	private String name;
	
	@Column(name = "price")
	private Integer price;
	
	@Column(name = "create_at")
	private LocalDateTime createAt;
	
	@Column(name = "update_at")
	private LocalDateTime 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 Integer getPrice() {
		return price;
	}

	public void setPrice(Integer price) {
		this.price = price;
	}

	public LocalDateTime getCreateAt() {
		return createAt;
	}

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

	public LocalDateTime getUpdateAt() {
		return updateAt;
	}

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

Dao

ItemDao
package com.example.dao;

import java.util.List;

import org.seasar.doma.Dao;
import org.seasar.doma.Select;

import com.example.config.AppConfig;
import com.example.entity.Item;

@Dao(config = AppConfig.class)
public interface ItemDao {
	
	@Select
    List<Item> findAll();
	
}
findAll.sql
select
    /*%expand*/*
from
    item
order by 
	id asc

実行用クラス

Sample01.java
package com.example;

import java.util.List;

import org.seasar.doma.jdbc.tx.TransactionManager;

import com.example.config.AppConfig;
import com.example.dao.ItemDao;
import com.example.dao.ItemDaoImpl;
import com.example.entity.Item;

public class Sample01 {

	public static void main(String[] args) {
		
		TransactionManager tm = AppConfig.singleton().getTransactionManager();
		tm.required(new Runnable(){

			@Override
			public void run() {
				// TODO Auto-generated method stub
				ItemDao dao = new ItemDaoImpl();
				List<Item> list = dao.findAll();
				
				System.out.println(list.size());
			}
			
		});
		
		

	}

}

実行結果

12 24, 2016 1:40:25 午前 org.seasar.doma.jdbc.tx.LocalTransaction begin
情報: [DOMA2063] ローカルトランザクション[1190654826]を開始しました。
12 24, 2016 1:40:25 午前 com.example.dao.ItemDaoImpl findAll
情報: [DOMA2220] ENTER  : クラス=[com.example.dao.ItemDaoImpl], メソッド=[findAll]
12 24, 2016 1:40:25 午前 com.example.dao.ItemDaoImpl findAll
情報: [DOMA2076] SQLログ : SQLファイル=[META-INF/com/example/dao/ItemDao/findAll.sql],
select
    id, name, price, create_at, update_at
from
    item
order by 
	id asc
12 24, 2016 1:40:25 午前 com.example.dao.ItemDaoImpl findAll
情報: [DOMA2221] EXIT   : クラス=[com.example.dao.ItemDaoImpl], メソッド=[findAll]
6
12 24, 2016 1:40:25 午前 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2067] ローカルトランザクション[1190654826]をコミットしました。
12 24, 2016 1:40:25 午前 org.seasar.doma.jdbc.tx.LocalTransaction commit
情報: [DOMA2064] ローカルトランザクション[1190654826]を終了しました。

動きました(^^)
ログにsqlを表示する?

所感

たいていはフレームワーク内で使用されているような記載がほとんどで単体で動かすサンプルが少なかったので助かりました。
sqlを記載できるのでSQLが好きな人には使えるような感じ…
動的な条件をどのような感じで設定できるか試していないのでちょっとやってみる。

Doma2のgenで自動生成を行う

Doma2

ORマッパーらしい
SQLファイルとか書いてなんかできるらしいよ

今回やること

Doma2でDBを参照していい感じのエンティティとかを作成できるらしいので準備して見る。

環境

eclipse
mysql

ライブラリ

doma2
doma2-gen
freemarker
mysl

設定

プロジェクトを作成する

f:id:m_shige1979:20161221001145p:plain

ライブラリを指定の場所へ配置しておく

f:id:m_shige1979:20161221001243p:plain

設定ファイル編集

doma-gen-build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="doma-gen-example" default="gen" basedir=".">
	<!-- javaDestDir -->
	<property name="javaDestDir" value="src"/>
	
	<!-- sqlDestDir -->
	<property name="sqlDestDir" value="src"/>
	
	<!-- dialectName -->
	<property name="dialectName" value="mysql"/>
	
	<!-- driverClassName -->
	<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	<property name="url" value="jdbc:mysql://192.168.33.10:3306/myapp"/>
	<property name="user" value="app"/>
	<property name="password" value="Password123@"/>
	
	<!-- package -->
	<property name="entityPackageName" value="com.example.mshige1979.server.db.entity"/>
	<property name="daoPackageName" value="com.example.mshige1979.server.db.dao"/>
	
	
	<property name="configClassName" value="com.example.mshige1979.server.db.config.AppConfig"/>
	<property name="sqlTestClassName" value="com.example.mshige1979.server.db.SqlTest"/>
	<property name="sqlFilePattern" value="META-INF/**/*.sql"/>
	
	<path id="classpath">
		<fileset dir="WEB-INF/lib" includes="*.jar"/>
	</path>

	<taskdef name="gen" classname="org.seasar.doma.extension.gen.task.Gen" classpathref="classpath" loaderref="loader"/>
	<typedef name="entityConfig" classname="org.seasar.doma.extension.gen.task.EntityConfig" loaderref="loader"/>
	<typedef name="daoConfig" classname="org.seasar.doma.extension.gen.task.DaoConfig" loaderref="loader"/>
	<typedef name="sqlConfig" classname="org.seasar.doma.extension.gen.task.SqlConfig" loaderref="loader"/>
	
	<target name="gen">
		<gen
			dialectName="${dialectName}"
			driverClassName="${driverClassName}"
			url="${url}"
			user="${user}"
			password="${password}">
			<entityConfig
				destdir="${javaDestDir}"
				packageName="${entityPackageName}"
			/>
			<daoConfig
				destdir="${javaDestDir}"
				packageName="${daoPackageName}"
				configClassName="${configClassName}"
			/>
			<sqlConfig
				destdir="${sqlDestDir}"
			/>
		</gen>
	</target>

	<target name="genTest">
		<genTest
			dialectName="${dialectName}"
			driverClassName="${driverClassName}"
			url="${url}"
			user="${user}"
			password="${password}">
			<sqlTestConfig
				destdir="${javaDestDir}"
				testClassName="${sqlTestClassName}">
				<fileset dir="${sqlDestDir}">
					<include name="${sqlFilePattern}"/>
				</fileset>
			</sqlTestConfig>
		</genTest>
	</target>

</project>

実行する

f:id:m_shige1979:20161221001657p:plain

Buildfile: sample_spring_doma2a/doma-gen-build.xml
gen:
      [gen] [DOMAGEN0017] 方言にはクラス[org.seasar.doma.extension.gen.dialect.MysqlGenDialect]が使用されます。
      [gen] Wed Dec 21 00:17:40 JST 2016 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/com/example/mshige1979/server/db/entity/Item.java
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/META-INF/com/example/mshige1979/server/db/dao/ItemDao/selectById.sql
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/com/example/mshige1979/server/db/entity/Memo.java
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/META-INF/com/example/mshige1979/server/db/dao/MemoDao/selectById.sql
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/com/example/mshige1979/server/db/entity/ObjData.java
      [gen] [DOMAGEN0020] ファイルを上書きしました。/Users/matsumotoshigeharu/Documents/workspace/sample_spring_doma2a/src/META-INF/com/example/mshige1979/server/db/dao/ObjDataDao/selectById.sql
BUILD SUCCESSFUL
Total time: 1 second

できたもの(一部)

ItemDao.java
package com.example.mshige1979.server.db.dao;

import com.example.mshige1979.server.db.config.AppConfig;
import com.example.mshige1979.server.db.entity.Item;
import org.seasar.doma.Dao;
import org.seasar.doma.Delete;
import org.seasar.doma.Insert;
import org.seasar.doma.Select;
import org.seasar.doma.Update;

/**
 */
@Dao(config = AppConfig.class)
public interface ItemDao {

    /**
     * @param id
     * @return the Item entity
     */
    @Select
    Item selectById(Integer id);

    /**
     * @param entity
     * @return affected rows
     */
    @Insert
    int insert(Item entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Update
    int update(Item entity);

    /**
     * @param entity
     * @return affected rows
     */
    @Delete
    int delete(Item entity);
}
Item.java
package com.example.mshige1979.server.db.entity;

import java.time.LocalDateTime;
import org.seasar.doma.Column;
import org.seasar.doma.Entity;
import org.seasar.doma.GeneratedValue;
import org.seasar.doma.GenerationType;
import org.seasar.doma.Id;
import org.seasar.doma.Table;

/**
 * 
 */
@Entity(listener = ItemListener.class)
@Table(name = "item")
public class Item {

    /**  */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    Integer id;

    /**  */
    @Column(name = "name")
    String name;

    /**  */
    @Column(name = "price")
    Integer price;

    /**  */
    @Column(name = "create_at")
    LocalDateTime createAt;

    /**  */
    @Column(name = "update_at")
    LocalDateTime updateAt;

    /** 
     * Returns the id.
     * 
     * @return the id
     */
    public Integer getId() {
        return id;
    }

    /** 
     * Sets the id.
     * 
     * @param id the id
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /** 
     * Returns the name.
     * 
     * @return the name
     */
    public String getName() {
        return name;
    }

    /** 
     * Sets the name.
     * 
     * @param name the name
     */
    public void setName(String name) {
        this.name = name;
    }

    /** 
     * Returns the price.
     * 
     * @return the price
     */
    public Integer getPrice() {
        return price;
    }

    /** 
     * Sets the price.
     * 
     * @param price the price
     */
    public void setPrice(Integer price) {
        this.price = price;
    }

    /** 
     * Returns the createAt.
     * 
     * @return the createAt
     */
    public LocalDateTime getCreateAt() {
        return createAt;
    }

    /** 
     * Sets the createAt.
     * 
     * @param createAt the createAt
     */
    public void setCreateAt(LocalDateTime createAt) {
        this.createAt = createAt;
    }

    /** 
     * Returns the updateAt.
     * 
     * @return the updateAt
     */
    public LocalDateTime getUpdateAt() {
        return updateAt;
    }

    /** 
     * Sets the updateAt.
     * 
     * @param updateAt the updateAt
     */
    public void setUpdateAt(LocalDateTime updateAt) {
        this.updateAt = updateAt;
    }
}
selectById.sql
select
  /*%expand*/*
from
  item
where
  id = /* id */1

今回はここまで
おわりです

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時は特に何もしなくてもクラスを返すだけでいいので楽そう。