BLOB型とはBinary Large Objectの略で、バイナリーデータを保存できる。
最大は4GBから1を引いたバイト数にデータベース・ブロック・サイズを掛けた値
画像をBLOBカラムに格納する
Oracleだけでなく、MySQLでもある
あまり見ない印象だが、画像データそのものをデータベースに保存することなんてあるんだ。。。
随机应变 ABCD: Always Be Coding and … : хороший
BLOB型とはBinary Large Objectの略で、バイナリーデータを保存できる。
最大は4GBから1を引いたバイト数にデータベース・ブロック・サイズを掛けた値
画像をBLOBカラムに格納する
Oracleだけでなく、MySQLでもある
あまり見ない印象だが、画像データそのものをデータベースに保存することなんてあるんだ。。。
STSで開発したプログラムをvagrantにデプロイしたい
-> Spring Boot Mavenプラグインを追加することで、実行可能なファイルとしてパッケージ化することができる。
-> pom.xmlに追加する
<packaging>jar</packaging> // 省略 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
run as -> maven install

targetフォルダに demo-0.0.1-SNAPSHOT.jar が生成された

vagrantに.jarファイルを配置します

$ java -version
openjdk version “1.8.0_265”
OpenJDK Runtime Environment (build 1.8.0_265-b01)
OpenJDK 64-Bit Server VM (build 25.265-b01, mixed mode)
$ wget https://d3pxv6yz143wms.cloudfront.net/11.0.2.9.3/java-11-amazon-corretto-devel-11.0.2.9-3.x86_64.rpm
$ sudo yum localinstall java-11-amazon-corretto-devel-11.0.2.9-3.x86_64.rpm
$ java -version
openjdk version “11.0.2” 2019-01-15 LTS
OpenJDK Runtime Environment Corretto-11.0.2.9.3 (build 11.0.2+9-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.2.9.3 (build 11.0.2+9-LTS, mixed mode)
$ rm -rf java-11-amazon-corretto-devel-11.0.2.9-3.x86_64.rpm
$ java -jar demo-0.0.1-SNAPSHOT.jar
http://192.168.33.10:8080/view/what-time-is-it

うお、何これ?
サーバにJavaさえ入ってれば動くやん
Sugeeeeeeeeeeeeee
マジでビビった。
まず、postgres側でテーブルを作ってデータを入れます。
create table weather ( id serial primary key, location_id int, name varchar(20), temperature int, humidity int, date_time timestamp );
test=> insert into weather (location_id, name, temperature, humidity, date_time) values
(1, ‘東京’, 15, 55, ‘2021-02-02 09:00:00’),
(1, ‘東京’, 16, 53, ‘2021-02-02 10:00:00’),
(1, ‘東京’, 17, 40, ‘2021-02-02 11:00:00’),
(2, ‘那覇’, 20, 65, ‘2021-02-02 09:00:00’),
(2, ‘那覇’, 22, 67, ‘2021-02-02 10:00:00’),
(2, ‘那覇’, 25, 69, ‘2021-02-02 11:00:00’);
INSERT 0 6
test=> select * from weather;
id | location_id | name | temperature | humidity | date_time
—-+————-+——+————-+———-+———————
1 | 1 | 東京 | 15 | 55 | 2021-02-02 09:00:00
2 | 1 | 東京 | 16 | 53 | 2021-02-02 10:00:00
3 | 1 | 東京 | 17 | 40 | 2021-02-02 11:00:00
4 | 2 | 那覇 | 20 | 65 | 2021-02-02 09:00:00
5 | 2 | 那覇 | 22 | 67 | 2021-02-02 10:00:00
6 | 2 | 那覇 | 25 | 69 | 2021-02-02 11:00:00
application.properties
server.port=8080 spring.jpa.database=POSTGRESQL spring.datasource.url=jdbc:postgresql://localhost:5432/test spring.datasource.username=postgres spring.datasource.password=
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>
model
Weather.java
package com.example.demo.model;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="weather")
public class Weather {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private Integer location_id;
private String name;
private Integer temperature;
private Integer humidity;
private Timestamp date_time;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getLocation_id() {
return location_id;
}
public void setLocation_id(Integer location_id) {
this.location_id = location_id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getTemperature() {
return temperature;
}
public void setTemperature(Integer temperature) {
this.temperature = temperature;
}
public Integer getHumidity() {
return humidity;
}
public void setHumidity(Integer humidity) {
this.humidity = humidity;
}
public Timestamp getDate_time() {
return date_time;
}
public void setDate_time(Timestamp date_time) {
this.date_time = date_time;
}
}
repository/WeatherRepository.java
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Weather;
@Repository
public interface WeatherRepository extends JpaRepository<Weather, Integer>{}
service/WeatherService.java
package com.example.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.model.Weather;
import com.example.demo.repository.WeatherRepository;
@Service
@Transactional
public class WeatherService {
@Autowired
WeatherRepository weatherRepository;
public List<Weather> findAllWeatherData(){
return weatherRepository.findAll();
}
}
HelloController.java
package com.example.demo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.model.Weather;
import com.example.demo.service.WeatherService;
@Controller
public class HelloController {
@Autowired
WeatherService weatherService;
@RequestMapping("/hello")
public String hello(Model model) {
model.addAttribute("hello", "Hello World!");
List<Weather> weatherDataList = weatherService.findAllWeatherData();
model.addAttribute("weatherDataList", weatherDataList);
return "hello";
}
}
hello.html
<!Doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="UTF-8">
<!-- <link th:href="@{/css/common.css}" rel="stylesheet"></link>
<script th:src="@{/js/common.js}"></script> -->
</head>
<body>
<p>
<span th:text="${hello}">Hello World!</span>
</p>
<div>
<table>
<tr th:each="data: ${weatherDataList}" th:object="${data}">
<td th:text="*{id}"></td>
<td th:text="*{location_id}"></td>
<td th:text="*{name}"></td>
<td th:text="*{temperature}"></td>
<td th:text="*{humidity}"></td>
<td th:text="*{date_time}"></td>
</tr>
</table>
</div>
</body>
</html>
lsof -i:8080
Run As -> SpringBoot app
http://localhost:8080/hello

Hello World!
1 1 東京 15 55 2021-02-02 09:00:00.0
2 1 東京 16 53 2021-02-02 10:00:00.0
3 1 東京 17 40 2021-02-02 11:00:00.0
4 2 那覇 20 65 2021-02-02 09:00:00.0
5 2 那覇 22 67 2021-02-02 10:00:00.0
6 2 那覇 25 69 2021-02-02 11:00:00.0
うおおおおおおおおおおおおお
マジか。。。
これ、Javaでアプリ作れんじゃん。
### create table
$ psql -l
$ psql -U root test
test=> create table mybook(
id integer,
name varchar(10)
);
CREATE TABLE
### テーブル一覧
test=> \d
List of relations
Schema | Name | Type | Owner
——–+——–+——-+——-
public | mybook | table | root
(1 row)
### カラムの確認
test=> \d mybook;
Table “public.mybook”
Column | Type | Collation | Nullable | Default
——–+———————–+———–+———-+———
id | integer | | |
name | character varying(10) | | |
### テーブル削除
test=> drop table mybook;
DROP TABLE
primary keyは、create tableの際に、name varchar(10) primary key,
mysqlでいうauto_incrementは、generated always as identity とする。
id integer generated always as identity,
Postgres放置してたけど、SpringBootやるなら必須じゃんか。
### データの挿入
test=> CREATE TABLE products (
product_no integer,
name text,
price numeric
);
CREATE TABLE
test=> INSERT INTO products (product_no, name, price) VALUES (1, ‘melon’, 9.99);
INSERT 0 1
test=> select * from products;
product_no | name | price
————+——-+——-
1 | melon | 9.99
(1 row)
### データの更新
test=> UPDATE products SET price = 12.0 where product_no = 1;
UPDATE 1
test=> select * from products;
product_no | name | price
————+——-+——-
1 | melon | 12.0
(1 row)
### データの削除
test=> delete from products where product_no = 1;
DELETE 1
test=> select * from products;
product_no | name | price
————+——+——-
(0 rows)
PostgresのCRUDは一通りマスターした。
後はこれをSpringBootから操作するところをやる
SpringBootのサポートするテンプレートエンジン
– Groovy, Thymeleaf, FreeMaker, Mustache
Tymeleaf利点
– 独自タグなし、ブラウザ表示
src/main/resources/templates/index.html
<!Doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="UTF-8">
<style type="text/css">
form {
border-style: solid;
border-color: black;
border-width: 1px;
margin: 5px;
padding: 10px;
}
</style>
</head>
<body>
<h1 th:text="'これはTypeleafですか?'">html-見出し1</h1>
Spring bootで推奨されています。
</body>
</html>
Run As -> SpringBoot app
http://localhost:8080/

WhatTimeIsItController.java
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("view/what-time-is-it")
@Controller
public class WhatTimeIsItController {
}
– @RequestMappingを設定
– Controllerで動的な値を生成
– 設定した動的な値をThymeleafのviewで参照
what time is it
package com.example.demo;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.ui.Model;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("view/what-time-is-it")
@Controller
public class WhatTimeIsItController {
@GetMapping()
public String view(Model model) {
String now = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
model.addAttribute("datetime", now);
return "wtii"; // viewを返す
}
}
Run As -> SpringBoot app

やべ、だいぶわかってきた。
ちょっと理解すると、アプリ作りたい衝動が抑えられなくなってくる
MVC:ControllerがMVC:Viewにデータを渡すのにui:Modelを使用する
model.addAttribute(“”,)で値を設定している
SpEL(Spring Expression Language)とうい方式を使っている
${変数式}、*{選択変数式}、#{メッセージ式}、@{リンク式} などがある
pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
WebApiController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.apache.commons.text.StringEscapeUtils;
@RestController
@RequestMapping("/api")
public class WebApiController {
@RequestMapping(value="weather/tokyo"
, produces=MediaType.APPLICATION_JSON_VALUE
, method=RequestMethod.GET)
private String call() {
RestTemplate rest = new RestTemplate();
final String cityCode = "130010";
final String endpoint = "http://weather.livedoor.com/forecast/webservice/json/v1";
final String url = endpoint + "?city=" + cityCode;
ResponseEntity<String> response = rest.getForEntity(url, String.class);
String json = response.getBody();
return decode(json);
}
private static String decode(String string) {
return StringEscapeUtils.unescapeJava(string);
}
}

うお、Jsonとして機能してないが、やりたいことやpom.xmlの使い方、importの意味などはわかってきた。
早くデータアクセスに行きたい。
String以外の戻り値にしてみる
java beanはデータを出し入れする倉庫
@RestController
@RequestMapping("/api")
public class WebApiController {
private static final Logger log = LoggerFactory.getLogger(WebApiController.class);
public static class HogeMogeBean {
public HogeMogeBean(String string, int i) {
// TODO Auto-generated constructor stub
}
}
@RequestMapping("hogemoge")
public HogeMogeBean hogemoge() {
return new HogeMogeBean( "ほげ", 1234 );
}
}
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sun Jan 31 19:21:10 JST 2021
There was an unexpected error (type=Internal Server Error, status=500).
$ curl localhost:8080/api/hogemoge
{“timestamp”:”2021-01-31T10:23:31.543+00:00″,”status”:500,”error”:”Internal Server Error”,”message”:””,”path”:”/api/hogemoge”}
なんやこれは。。
いきなりよくわからん。
まず、Spring Starter Projectでプロジェクトを作ったら、packageを作ります。
com.example.demo.controller

WebApiController.java
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
@RequestMapping("api")
public class WebApiController {
@RequestMapping("hello")
private String hello() {
return "SpringBoot!";
}
}
あれ、さっきgradleで作った時はRestControllerではなくRequestMethodだったけど、今回はRestControllerか。。ん、requestMappingってパスの事か。
application.properties
server.port=8080
Run As -> SpringBoot app
http://localhost:8080/api/hello

ほう、なるほど
パスパラメータ
-> requestMappingで仕込んで使用する
@RequestMapping("/hello/{param}")
private String hello(@PathVariable("hoge") String param) {
return "SpringBoot!";
}
package com.example.demo.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sample/api")
public class WebApiController {
private static final Logger log = LoggerFactory.getLogger(WebApiController.class);
@RequestMapping("/test/{param}")
private String testPathVariable(@PathVariable String param) {
log.info(param);
return "受け取ったパラメータ:" + param;
}
@RequestMapping("/test")
private String testRequestParam(@RequestParam() String param) {
log.info(param);
return "受け取ったパラメータ:" + param;
}
@RequestMapping(value = "/test", method = RequestMethod.POST)
private String testRequestBody(@RequestBody String body) {
log.info(body);
return "受け取ったbody:" + body;
}
}
$ lsof -i:8080
$ kill hoge
Run As -> SpringBoot app
http://localhost:8080/sample/api/test/firstparam

なにこれ? GetParameter実装するの凄い簡単なのに、こんなにコード書かなきゃいけないの。。。
New Spring Starter Project

次の画面で、TymeleafとWebを選択


# MarvenとGradle
### Marven
– POM (Project Od Model) の考え方に基づく。
– ビルドファイルは、pom.xml
– プラグインによる拡張が可能
### Gradle
– AndroidStudioデフォルト
– 依存関係はGroovyに書いている
Run As -> SpringBoot app
. ____ _ __ _ _
/\\ / ___’_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | ‘_ | ‘_| | ‘_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
‘ |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.2)
### HTMLの作成
hello-world/src/main/resources/templates
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <h1>Hello SpringBoot Sample</h1> </body> </html>
### Controllerの作成

HelloController.java
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HelloController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model) {
return "index";
}
}
Run As -> SpringBoot app

やべえ、なんか出来てる….
Laravel8.x + Mailgun + お名前.com + Route53
まず、Mailgunでカスタムドメインを設定する必要がある
そうすると、DNSに、TXT、MX、CNAMEを登録しろ、と出てくる

なるほど、これをお名前.comに登録すれば良いのね、ということで、お名前.comのDNS設定で追加して、Verify DNS Settingsを押しても一向にverifyされない。。。
何故だ? 24時間くらい待った方が良いの? 常識的にそんな訳ないよね。。お名前に問い合わせしようかな。。と考えていたが、
TXT、MX、CNAMは、お名前側ではなく、Route53のHosted zonesのcreate recordで設定して上手くいった。
設定内容は、record nameと”Enter This Value”をvalueに入れていく。

mxレコードの場合は、valueに”10 mxa.mailgun.org”と入れる。
これで、再度Verify DNS Settingsを押すと、verifyされる。
で、設定したドメインのSMTP credentialのページに行き、ログインの箇所とReset Passwordでパスワードを取得して、この内容をlaravelのenvに記載する

laravel .env
L maildriverはsmtpのままで大丈夫
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@${domain name}
MAIL_PASSWORD=${domain password}
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME=""
これでOK
送信テストを行う
まあ、Amazon SESの申請が降りたから、mailgun使わなくて良いんだけど、SESの申請が落ちた時はこちらを使う。
取り敢えず、MailgunのTXT、MX、CNAMEはお名前.comではなく、Route53側で設定するということ。
mailstrapで開発してて、さあSTG、商用環境にデプロイしよか、って時にメール送信できないとか、恐怖でしかないわ、ホンマに。