forget for get

覚えるために忘れる

エクセルからMySQLに接続

MySQL ODBCドライバをインストール

https://dev.mysql.com/downloads/connector/odbc/

 

使うエクセルが2007(32bit)だったので、8.0を選択。

 

ODBCデータソースの設定

コントロールパネルのODBCデータソースアドミニストレータ(32ビット)を使用して、MySQLの接続情報を設定

MySQLサーバーのIPアドレス、データベース名、ユーザー名、パスワードを入力

 

MySQL権限設定

VirtualBoxMySQLに接続しようとしたけどエラー。

権限を設定しないといけない。

CREATE USER 'remoteuser'@'%' IDENTIFIED BY 'password';

GRANT SELECT, INSERT, UPDATE, DELETE ON lightwill.* TO 'remoteuser'@'%';

FLUSH PRIVILEGES;

外部からアクセスできるユーザを作成。

SELECT, INSERT, UPDATE, DELETE の権限を付与。

反映。

 

エクセルマクロ(VBA

Sub AccessMySQL()
    Dim conn As Object
    Dim rs As Object
    Dim strSql As String
    Dim strConn As String
    
    ' MySQLへの接続情報を設定
    strConn = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=192.168.33.10;Database=lightwill;Uid=remoteuser;Pwd=password;"
    
    ' ADO Connectionオブジェクトを作成
    Set conn = CreateObject("ADODB.Connection")
    
    ' 接続を開く
    conn.Open strConn
    
     ' SQLクエリを作成
    strSql = "SELECT * FROM dp_comments order by id desc LIMIT 0, 30;"
    
    ' ADO Recordsetオブジェクトを作成
    Set rs = CreateObject("ADODB.Recordset")
    
    ' RecordsetにSQLクエリの結果を格納
    rs.Open sql, conn
    
    ' データをExcelに貼り付け
    Sheet1.Range("A1").CopyFromRecordset rs
    
    ' 接続を閉じる
    rs.Close
    conn.Close
    
    ' オブジェクトの解放
    Set rs = Nothing
    Set conn = Nothing
End Sub

 

 

 

 

SpringBoot入門:DBから値を取得

気軽に試せるH2データベースを使えるようにする

src/main/resources/
application.properties

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

spring.sql.init.encoding=UTF-8
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:schema.sql
spring.sql.init.data-locations=classpath:data.sql

spring.h2.console.enabled=true

 

スキーマとテストデータのSQL

schema.sql

create table if not exists employee(
  id varchar(50) primary key,
  name varchar(50),
  age int
);

 

data.sql

insert into employee(id, name, age)
values('1', 'Tom', 30);

Model、Repository、Service、Controller、Viewを作成、修正

src/main/java/com.example.demo/hello
Employee.java

@Data
public class Employee {
	private String employeeId;
	private String employeeName;
	private int employeeAge;
}

HelloRepository.java

@Repository
public class HelloRepository {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	public Map<String, Object> findById(String id) {
		String query = "select *"
				+ " from employee"
				+ " where id=?";		
		Map<String, Object> employee = jdbcTemplate.queryForMap(query, id);		
		return employee;
	}
}

HelloService.java

@Service
public class HelloService {
	@Autowired
	private HelloRepository repository;
	
	public Employee getEmployee(String id) {
		Map<String, Object> map = repository.findById(id);
		
		String employeeId = (String) map.get("id");
		String name = (String) map.get("name");
		int age = (Integer) map.get("age");
		
		Employee employee = new Employee();
		employee.setEmployeeId(employeeId);
		employee.setEmployeeName(name);
		employee.setEmployeeAge(age);
		
		return employee;
	}
}

HelloController.javaに追記

	@Autowired
	private HelloService service;
	
	@PostMapping("/hello/db")
	public String postDbRequest(@RequestParam("eid") String id, Model model) {
		Employee employee = service.getEmployee(id);
		model.addAttribute("employee", employee);
		return "hello/db";
	}

src/main/resources/templates
db.htmlを作成

        <p th:text="${employee.employeeId}"></p>
        <p th:text="${employee.employeeName}"></p>
        <p th:text="${employee.employeeAge}"></p>

 

hello.htmlに追記

        <form method="post" action="/hello/db">
            <input type="text" name="eid" th:value="${eid_value}">
            <button>送信</button>
        </form>

 

H2データベースのコンソール
http://localhost:8080/h2-console
JDBC URL: jdbc:h2:mem:testdb

 

 

 

 

SpringBoot入門:環境構築

参考書はこちらを選択(Kindle Unlimitedで無料で読めるので)
Spring 解体新書

 

環境構築


IDE
Spring Tools 4 for Eclipse
https://spring.io/tools/
windows版をダウンロード、任意の場所に配置して「java -jar spring-tool-suite-xxx.jar」
sts-x.x.x.RELEASEの中のSpringToolSuite4.exeが本体

 

Pleiadesの日本語化プラグイン
https://willbrains.jp/
Pleiades プラグイン・ダウンロードからWindowsをダウンロード
解凍してsetup.exe
先ほどのSpringToolSuite4.exeを選択して日本語化

 

Lombokインストール
https://projectlombok.org/download
java -jar lombok.jar
SpringToolSuite4.exeを選択してインストール

 

Spring Tools 4の設定
コード補完の設定
ウィンドウ→設定→Java→エディタ→コンテンツアシスタント
Javaの自動有効化トリガー
.abcdefghijkemnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_
※デフォルトだと.を入力した時しか補完されない
「Enter以外の挿入トリガーを使用不可にする」にチェック

Ctrl + Shift + Fでコード整形

 

新規Springスタータープロジェクトの作成
追加ライブラリ
Spring Boot DevTools, Lombok, JDBC API, Spring Data JDBC, H2 Database, Thymeleaf, Spring Web

 

src/main/resources/templates
hello.htmlを作成

<html xmlns:th="http://www.thymeleaf.org">
    <body>
        Hello World
    </body>
</html>

 

src/main/java/com.example.demo/hello
HelloController.javaを作成

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
	@GetMapping("/hello")
	public String getHello() {
		return "hello";
	}
}

プロジェクトを右クリック→実行→SpringBootアプリケーション
http://localhost:8080/hello

Java入門

筆者はPHPを習得しているので環境構築くらいしか書くことがない。

(言語の違いで気づいたことがあれば追記していく)

 

JavaDriveでJava入門
https://www.javadrive.jp/start/

 

JDKのインストール
https://jdk.java.net/
Ready for use: JDK XXをクリック
BuildsからWindowsのzipをダウンロード
任意のディレクトリに展開

 

環境変数の設定
検索窓に「環境変数」と入力して環境変数Windowを開く
ユーザー環境変数かシステム環境変数に「JAVA_HOME」を追加
変数値には先ほど配置したパスを指定「C:\xxx\jdk-xx.x.x」
「Path」の編集で、新規→「%JAVA_HOME%\bin」を追加
コマンドプロンプトで「javac -version」で確認

 

公式ドキュメント
https://www.oracle.com/jp/java/technologies/documentation.html
該当バージョンのリンク日本語→左メニューのAPIドキュメント

 

Hello, World
Hello.java

class Hello {
  public static void main(String[] args) {
    System.out.println("Hello");
  }
}

 

コンパイル
javac Hello.java
実行
java Hello

 

サンプルプログラム

import java.time.LocalDate;

class Sample {
  public static void main(String[] args) {
  	final int MAX_LEVEL = 100;
  	
  	System.out.println(MAX_LEVEL);
  	
  	LocalDate ld = LocalDate.now();
    System.out.println(ld);
  	
  	//配列
  	int[] nums = new int[3];
  	nums[0] = 1;
  	nums[1] = 2;
  	nums[2] = 3;
  	
  	for (int i = 0; i < 3; i++) {
  		System.out.println(nums[i]);
  	}
  	
  	//こうも書ける
  	int[] nums2 = {1, 2, 3};
  	for (int num : nums2) {
        System.out.println(num);
    }
  	
  	//String型や配列型は参照型なので、代入すると同じものを参照する
  	int[] others = nums2;
  	nums2[0] = 4;
  	// 同じものを参照しているので、4になる
    System.out.println(others[0]);
  	
  	int[] others2 = nums2.clone();
  	nums2[0] = 5;
  	// cloneだと別オブジェクトになるので5にならない
    System.out.println(others2[0]);
  }
}

 

 

Compositeパターン

容器と中身の同一視。
ファイルシステムでは、ディレクトリとファイルが入れ子になっている。
ディレクトリとファイルは異なるものですが、「ディレクトリに入るもの」とみなしている。

Leaf(葉):MyFile
中身
Composite(複合体):MyDirectory
容器
Component:Entry
LeafとCompositeを同一視するためのスーパークラス
Client(依頼者):Main

他にも複数と単数の同一視など。

Entry.php

abstract class Entry {
  abstract function getName();
  abstract function getSize();
  function add(Entry $entry) {
    throw new Exception("FileTreatmentException");
  }
  abstract function printList($prefix=null);
  function toString() {
    return $this->getName() . "(" . $this->getSize() . ")";
  }
}

MyFile.php

class MyFile extends Entry {
    private $name;
    private $size;
    function __construct(String $name, int $size) {
        $this->name = $name;
        $this->size = $size;
    }
    function getName() {
        return $this->name;
    }
    function getSize() {
        return $this->size;
    }
    function printList($prefix=null) {
        echo $prefix . "/" . $this->toString() . "\n";
    }
}

MyDirectory.php

class MyDirectory extends Entry {
    private $name;
    private $directory = [];
    function __construct(String $name) {
        $this->name = $name;
    }
    function getName() {
        return $this->name;
    }
    function getSize() {
        $size = 0;
        foreach ($this->directory as $entry) {
            $size += $entry->getSize();
        }
        return $size;
    }
    function add(Entry $entry) {
        $this->directory[] = $entry;
        return $this;
    }
    function printList($prefix=null) {
        echo $prefix . "/" . $this->toString() . "\n";
        foreach ($this->directory as $entry) {
            $entry->printList($prefix . "/" . $this->name);
        }
    }
}

Main.php

require "../autoload.php";
echo "Making root entries...\n";
$rootdir = new MyDirectory("root");
$bindir = new MyDirectory("bin");
$tmpdir = new MyDirectory("tmp");
$usrdir = new MyDirectory("usr");
$rootdir->getName();
$rootdir->add($bindir);
$rootdir->add($tmpdir);
$rootdir->add($usrdir);
$bindir->add(new MyFile("vi", 10000));
$bindir->add(new MyFile("latex", 20000));
$rootdir->printList();

 

Mementoパターン

状態を保存しておいて、復元できるようにしておく。
undo,redo,history,snapshot

復元するためにインスタンスの内部情報を公開すると、カプセル化の破壊になるので、
インタフェースを使い分ける。

Originator(作成者):Gamer
自分の現在の状態を保存したいときにMementoをつくる。
以前のMementoを渡されると、その状態に戻る。
Memento(記念品):Memento
Originatorの情報を持っているが、誰にでも公開はしない。
広いインタフェース→オブジェクトを元に戻すために内部情報を得られるメソッド。Originatorだけが使える。
狭いインタフェース→Caretakerに見せるもの。
Caretaker(世話をする人):Main
Originatorの状態を保存したいときに、Originatorに伝える。
OriginatorはMementoをCaretakerに渡す。
CaretakerはMementoの狭いインタフェースしか使えないので、Mementoの内部情報をいじることはできない。

Memento.php

class Memento {
    private $money;
    private $fruits = [];
    function __construct($money) {
        $this->money = $money;
    }
    function getMoney() {
        return $this->money;
    }
    function addFruit($fruit) {
        $this->fruits[] = $fruit;
    }
    function getFruits() {
        return $this->fruits;
    }
}

Gamer.php

class Gamer {
    private $money;
    private $fruits = [];
    private $fruitNames = ["夕張メロン","すいか","もも","なし"];
    function __construct($money) {
        $this->money = $money;
    }
    function getMoney() {
        return $this->money;
    }
    function bet() {
        $dice = rand(1, 6);
        if ($dice == 1) {
            $this->money += 100;
            echo "所持金が増えました\n";
        } else if ($dice == 2) {
            $this->money /= 2;
            echo "所持金が半分になりました\n";
        } else if ($dice == 6) {
            $f = $this->getFruit();
            echo "フルーツ(" . $f . ")をもらいました\n";
            $this->fruits[] = $f;
        } else {
            echo "何も起こりませんでした\n";
        }
    }
    function createMemento() {
        $m = new Memento($this->money);
        foreach ($this->fruits as $f) {
            if (strpos($f, "おいしい") !== false) {
                $m->addFruit($f);
            }
        }
        return $m;
    }
    function restoreMemento(Memento $memento) {
        $this->money = $memento->getMoney();
        $this->fruits = $memento->getFruits();
    }
    function toString() {
        return "[money = " . $this->money 
        . ", fruits = " . implode(",", $this->fruits) . "]";
    }
    private function getFruit() {
        $prefix = rand(0, 1) ? "おいしい" : "";
        return $prefix . $this->fruitNames[rand(0, count($this->fruitNames) - 1)];
    }
}

Main.php

require "../autoload.php";
$gamer = new Gamer(100);
$memento = $gamer->createMemento();
for ($i=1;$i<=100;$i++) {
    echo $i . ":" . $gamer->toString() . "\n";
    $gamer->bet();
    echo "所持金:" . $gamer->getMoney() . "\n";
    if ($gamer->getMoney() > $memento->getMoney()) {
        echo " (保存)\n";
        $memento = $gamer->createMemento();
    } else if ($gamer->getMoney() < $memento->getMoney() / 2) {
        echo " (復元)\n";
        $gamer->restoreMemento($memento);
    }
    sleep(1);
}

 

 

Strategyパターン

アルゴリズムをごっそり切り替える

Strategy(戦略):Strategy
インタフェースを規定
ConcreteStrategy(具体的戦略):WinningStrategy、ProbStrategy
Context(文脈):Player
Strategyを利用。ConcreteStrategyのインスタンスを保持。

Hand.php

class Hand {
  const GUU = 0;
  const CHO = 1;
  const PAA = 2;
  static $hand = [];
  static private $name = ["グー","チョキ","パー"];
  private $handvalue;
  static function initialize() {
    self::$hand = [new Hand(self::GUU), new Hand(self::CHO), new Hand(self::PAA)];
  }
  function __construct($handvalue) {
    $this->handvalue = $handvalue;
  }
  static function getHand($handvalue) {
    return self::$hand[$handvalue];
  }
  function isStrongerThan(Hand $h) {
    return $this->fight($h) == 1;
  }
  function isWeekerThan(Hand $h) {
    return $this->fight($h) == -1;
  }
  private function fight(Hand $h) {
    if ($this == $h) return 0;
    if (($this->handvalue + 1) % 3 == $h->handvalue) return 1;
    return -1;
  }
  function toString() {
    return self::$name[$this->handvalue];
  }
}

Strategy.php

interface Strategy {
  function nextHand(): Hand;
  function study(bool $win);
}

WinningStrategy.php

// 勝ったら同じ手を出す戦略
class WinningStrategy implements Strategy {
  private $won = false;
  private $prevHand;
  function nextHand(): Hand {
    if (!$this->won) $this->prevHand = Hand::getHand(rand(0, 2));
    return $this->prevHand;
  }
  function study(bool $win) {
    $this->won = $win;
  }
}

ProbStrategy.php

// 勝敗履歴から確率を計算する戦略
class ProbStrategy implements Strategy {
  private $prevHandValue = 0;
  private $currentHandValue = 0;
  private $history = [[1,1,1], [1,1,1], [1,1,1]];
  function nextHand(): Hand {
    $bet = rand(0, $this->getSum($this->currentHandValue));
    $handvalue = 0;
    if ($bet < $this->history[$this->currentHandValue][0]) {
      $handvalue = 0;
    } else if ($bet < $this->history[$this->currentHandValue][0] + $this->history[$this->currentHandValue][1]) {
      $handvalue = 1;
    } else {
      $handvalue = 2;
    }
    $this->prevHandValue = $this->currentHandValue;
    $this->currentHandValue = $handvalue;
    return Hand::getHand($handvalue);
  }
  private function getSum($hv) {
    $sum = 0;
    for ($i=0;$i<3;$i++) {
      $sum += $this->history[$hv][$i];
    }
    return $sum;
  }
  function study($win) {
    if ($win) {
      $this->history[$this->prevHandValue][$this->currentHandValue]++;
    } else {
      $this->history[$this->prevHandValue][($this->currentHandValue + 1) % 3]++;
      $this->history[$this->prevHandValue][($this->currentHandValue + 2) % 3]++;
    }
  }
}

Player.php

class Player {
  private $name;
  private $strategy;
  private $wincount = 0;
  private $losecount = 0;
  private $gamecount = 0;
  function __construct($name, $strategy) {
    $this->name = $name;
    $this->strategy = $strategy;
  }
  function nextHand() {
    return $this->strategy->nextHand();
  }
  function win() {
    $this->strategy->study(true);
    $this->wincount++;
    $this->gamecount++;
  }
  function lose() {
    $this->strategy->study(false);
    $this->losecount++;
    $this->gamecount++;
  }
  function even() {
    $this->gamecount++;
  }
  function toString() {
    return "[" . $this->name . ":" . $this->gamecount . " games, " . $this->wincount . " win, " . $this->losecount . " lose]";
  }
}

Main.php

require "../autoload.php";
Hand::initialize();
$player1 = new Player("Taro", new WinningStrategy());
$player2 = new Player("Jiro", new ProbStrategy());
for ($i=0;$i<10;$i++) {
  $nextHand1 = $player1->nextHand();
  $nextHand2 = $player2->nextHand();
  if ($nextHand1->isStrongerThan($nextHand2)) {
    echo "Winner:" . $player1->toString() . "\n";
    $player1->win();
    $player2->lose();
  } else if ($nextHand2->isStrongerThan($nextHand1)) {
    echo "Winner:" . $player2->toString() . "\n";
    $player2->win();
    $player1->lose();
  } else {
    echo "Even...\n";
    $player1->even();
    $player2->even();
  }
}
echo "Total result:\n";
echo $player1->toString() . "\n";
echo $player2->toString() . "\n";