- 投稿日:2019-02-09T23:20:53+09:00
JavaMailでPDF添付ファイル付きのメールを送る
概要
JavaMailとpdfboxを使ってPDF添付ファイル付きのメールを送信します。
PDFファイルの作成方法と、メール送信方法について説明します。環境
- Java JDK 1.8.0_171
- Windows10
- JavaMail 1.4.7
- pdfbox 2.0.13
- SMTPサーバー: FakeSMTP
PDFファイルを作成
pdfbox を使ってPDFファイルを作ります
準備
まずはmavenでpdfboxを利用できるようにします。
pom.xml<dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.13</version> </dependency>PDFファイル作成コード
ではPDFファイルを作成します。
実ファイルを利用する場合、InputStreamを利用する場合と紹介します。
今回は実ファイルを生成せずにメール送信を行いたいため、ByteArrayInputStreamを返すメソッドで書きます。public ByteArrayInputStream createDocument() { PDDocument document = null; TrueTypeCollection collection = null; ByteArrayInputStream inputStream; try { // PDFのベースを作成。今回はA4で。 document = new PDDocument(); PDPage page = new PDPage(PDRectangle.A4); document.addPage(page); // 日本語はフォントを読み込まないと使えないので読み込みます。 // Macはパスが違います。 PDFont font = PDType1Font.TIMES_BOLD; File file = new File("C:/Windows/Fonts/msmincho.ttc"); collection = new TrueTypeCollection(file); PDFont font2 = PDType0Font.load(document, collection.getFontByName("MS-Mincho"), true); // ページの中身を作成 PDPageContentStream contentStream = new PDPageContentStream(document, page); // フォントや位置を指定して一つのテキストを作成します。 // ページは左下がベース(0, 0)になります。 contentStream.beginText(); contentStream.newLineAtOffset(0, PDRectangle.A4.getHeight() - 12f); contentStream.setFont(font, 12); contentStream.showText("firstText"); contentStream.endText(); contentStream.beginText(); contentStream.newLine(); contentStream.setFont(font2, 15); contentStream.showText("secondText"); contentStream.endText(); contentStream.close(); // PDFファイルを作成します。 ByteArrayOutputStream out = new ByteArrayOutputStream(); document.save(out); inputStream = new ByteArrayInputStream(out.toByteArray()); // ---- 実ファイルを作成する場合 ---- // document.save("sample.pdf"); // -------------------------------- } catch (Exception e) { e.printStackTrace(); } finally { if (document != null) { try { document.close(); } catch (Exception e) { e.printStackTrace(); } } if (collection != null) { try { collection.close(); } catch (Exception e) { e.printStackTrace(); } } } return inputStream; }「実ファイルを実行する場合」のコードを記載した場合はこの段階でPDFファイルが生成されます。
メール送信
次に JavaMail を使ってメールを送信します。
準備
こちらもmavenで利用できるように記述を足します。
pom.xml<dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4.7</version> </dependency>FakeSMTP をインストール
今回開発用のSMTPサーバーとして FakeSMTP を使います。
利用方法は リンク先 を参照してください。ちなみにGmailはセキュリティを下げないとローカル環境から認証できなかったため使うのをやめました。
メール送信コード
ではメール送信を行うコードを書いていきます。
先程作成したPDFのInputStreamを引数で受け取って利用します。public void sendRawMail(final String subject, ByteArrayInputStream attachement) { // プロパティの設定 Properties properties = System.getProperties(); // ホスト properties.put("mail.smtp.host", HOST); // 認証 properties.put("mail.smtp.auth", "true"); // ポート指定(サブミッションポート) properties.put("mail.smtp.port", "25"); // STARTTLSによる暗号化 properties.put("mail.smtp.starttls.enable", "true"); properties.put("mail.smtp.starttls.enable", "false"); properties.put("mail.smtp.debug", "true"); // タイムアウト properties.put("mail.smtp.connectiontimeout", "10000"); properties.put("mail.smtp.timeout", "10000"); try { // セッションの作成。 final Session session = Session.getInstance(properties , new javax.mail.Authenticator(){ protected PasswordAuthentication getPasswordAuthentication(){ // Gmailなどを使う場合はユーザ名とパスワードを引数に指定。 return new PasswordAuthentication("", ""); } }); final Message message = new MimeMessage(session); // 基本情報 message.setFrom(new InternetAddress("送信元メールアドレス")); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("送信先メールアドレス", false)); // タイトル message.setSubject(subject); // 本文 final MimeMultipart multipart = new MimeMultipart("mixed"); // 本文テキスト final MimeBodyPart textPart = new MimeBodyPart(); textPart.setText("本文テキスト", "UTF-8"); // 添付ファイル final MimeBodyPart attPart = new MimeBodyPart(); // 実ファイルを利用する場合は実ファイルでDataSourceを作成 final DataSource dataSource = new ByteArrayDataSource(attachement, "application/pdf"); attPart.setDataHandler(new DataHandler(dataSource)); attPart.setFileName("test.pdf"); multipart.addBodyPart(textPart); multipart.addBodyPart(attPart); message.setContent(multipart); // 送信 Transport.send(message); } catch (Exception e) { e.printStackTrace(); throw new InternalServerErrorException(e); } }メソッド実行でPDFが添付されたメールが送信されます。
- 投稿日:2019-02-09T17:20:24+09:00
Spring Boot の学習【はじめ】
仕事でJavaは少しくらいは触っているけど、流行りのフレームワークには触れる機会がなく過ごしていますが何となくSpring Bootを見ていると、もしかしたら今度こそこれがスタンダードのフレームワークとして定着するんじゃないかなぁ?覚えて損はない。と思い立って、触ってみる事にしました。
【スターター・プロジェクト】
はじめてのSpring Bootプロジェクト作成ですが、他に選択が無いので定番かもしれませんがここからスタートします。
1.プロジェクト設定1
Gradleというのがどうも筆者は設定が見やすいので、これにします。
パッケージは、jarはまだよくわからないのでwarとします。2.プロジェクト設定2
とりあえずは、動かしてみたいだけなのでテンプレートエンジンとwebだけを選択
たぶん後で追加はできるはず。
4.コントローラーの作成
Controllerは主にWebページ用のコントローラで使用する。
RestControllerはJsonやXML等を返すWebAPI用のコントローラで使用する。
との事ですが、どっちも試してみたいと思います。
まずは、RestControllerから作ります。TestRest.javapackage com.example.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestRest { @RequestMapping("/Rest") public String Rest() { return "これはRest"; } }5.実行してみる
実行で「Spring Bootアプリケーション」を選択する
6.ブラウザーからアクセスしてみる
どうもTomcatは動いているが、肝心の作成したコントローラが見つからない?
いったいどういうこと?
7.RestControllerをSpringBootApplicationが置いてあるパッケージに移動させてみる
8.再度ブラウザーからアクセス
なぜか、動いた!という事は、SpringApplicationが置いてある配下しかコントローラは作れないってこと?
9.試しにSpringApplicationの配下にパッケージを作ってみます。
TestRest.javapackage com.example.demo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestRest { @RequestMapping("/Rest") public String Rest() { return "これはRest。demo配下のパッケージより"; } }やっぱりそうか、そうなのね。
まぁともかくちょっと理解が進んだ。
RestControllerはこれくらいでいいだろう。
次に進みます。Controllerを使って、テンプレートエンジンを使ってみます。10.Controllerを作ってみる。
「templates」フォルダにindex.htmlを作成します。
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>初めてのThymeleaf</title> </head> <body> <h1 th:text="${message}"></h1> </body> </html>com.example.demo.controllerに「TestController.java」を作成。
TestController.javapackage com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class TestController { @RequestMapping("/") public String index(Model model) { model.addAttribute("message", "Thymeleaf動きました!"); return "index"; } }11.実行してtemplatesの動作確認
ちゃんと動きました!めでたしめでたし。
文字コードは何も意識しないで文字化けもせず、すんなりとここまで来れるんですね。
Spring Bootなかなかよさそうですね。次はフォームを作って見よう。
- 投稿日:2019-02-09T14:22:27+09:00
GoogleCloudPrintに使ってPDFを印刷する。(GoogleAPI)
Google Cloud Print とは
Googleアカウントに端末に設定しているプリンタを登録して、クラウド経由で別端末から印刷ができるサービス。
- 印刷に必要な設定
- Googleアカウントの取得
- Chromeブラウザのインストール
- プリンタの登録
- GoogleAPIから呼び出す為に必要な設定
- GoogleAPIの認証キーの取得
処理の流れ
- リフレッシュトークンの取得(一度取得していれば不要)
- アクセストークンの取得
- GoogleCloudPrintの操作(プリンタ一覧の取得,プリンタID指定で印刷実行)
事前準備
GoogleCloudPrintのプリンタ登録は、以下を参考に実施。
https://www.google.com/cloudprint/learn/GoogleAPIのクライアントIDとシークレット取得
GoogleCloudPratformにアクセスして、認証情報を登録する。
https://console.cloud.google.com/
[APIとサービス]→[認証情報]→[認証情報を作成]→[OAuthクライアントID]の順番に選択
クライアントID
とクライアントシークレット
を取得(あとで使います。)
GoogleCloudPrintへのアクセス許可と、アプリケーションに設定するコードを取得
取得した
クライアントID
をURL設定して、ブラウザに直接アクセス
https://accounts.google.com/o/oauth2/auth?redirect_uri=oob&response_type=code&client_id=<ここに上記で取得したクライアントIDを指定>&scope=https://www.googleapis.com/auth/cloudprintGoogleAPIで自動印刷
今回は、JavaのUnirestを使って、実行してみる。
重要な処理だけをピックアップして記載getRefreshTokenHttpResponse<JsonNode> res = Unirest.post("https://www.googleapis.com/oauth2/v3/token") .field("code", code) // 事前準備で取得したコードを設定 .field("client_id", client_id) // 事前準備で取得したクライアントIDを設定 .field("client_secret", client_secret) // 事前準備で取得したクライアントシークレットを設定 .field("grant_type", "authorization_code") .field("redirect_uri", "oob") .asJson();リフレッシュトークンを取得する。
コードは一回使うと、もう使えなくなるのでリフレッシュトークンがわからなくなったら事前準備のコード取得から行う必要あり。getAccessTokenHttpResponse<JsonNode> res = Unirest.post("https://www.googleapis.com/oauth2/v3/token") .field("client_id", client_id) // 事前準備で取得したクライアントIDを設定 .field("client_secret", client_secret) // 事前準備で取得したクライアントシークレットを設定 .field("grant_type", "refresh_token") .field("refresh_token", refresh_token) // getRefreshTokenで取得したリフレッシュトークンを設定 .asJson();アクセストークンを取得する。
リフレッシュトークンから都度アクセストークンを取得する。
プリンタにアクセスする度に、アクセストークンを取得するように構成する。getPrintersHttpResponse<JsonNode> res = Unirest.get("https://www.google.com/cloudprint/search") .header("Authorization", token_type + " " + access_token) .asJson();GoogleCloudPrintに設定されているプリンタ一覧を取得する。
submitFileHttpResponse<JsonNode> res = Unirest.post("https://www.google.com/cloudprint/submit") .header("Authorization", token_type + " " + access_token) .field("printerid", printerid) // プリンタIDを設定:デフォルトのGoogleDriveは[__google__docs]です。 .field("title", file.getName()) .field("ticket", gson.toJson(new TicketBean())) .field("content", file) .asJson();GoogleCloudPrintにローカルPDFファイルの印刷要求を行う。
fileには、java.io.File型です。これらの処理を順番に行うことで印刷できます。
最後に
例えば、サーバ側に動的なPDF作成処理を実装し、複数クライアント側のプリンタに対して印刷を行うなど。
簡単に実現できる仕組みとなる。今はアカウントにプリンタを登録する必要があるので難しいが
いずれ、Faxがいらなくなる日が来るかもしれない。
- 投稿日:2019-02-09T14:22:27+09:00
GoogleCloudPrintに使ってPDFを印刷する。(GoogleAPIで自動印刷)
Google Cloud Print とは
Googleアカウントに端末に設定しているプリンタを登録して、クラウド経由で別端末から印刷ができるサービス。
- 印刷に必要な設定
- Googleアカウントの取得
- Chromeブラウザのインストール
- プリンタの登録
- GoogleAPIから呼び出す為に必要な設定
- GoogleAPIの認証キーの取得
処理の流れ
- リフレッシュトークンの取得(一度取得していれば不要)
- アクセストークンの取得
- GoogleCloudPrintの操作(プリンタ一覧の取得,プリンタID指定で印刷実行)
事前準備
GoogleCloudPrintのプリンタ登録は、以下を参考に実施。
https://www.google.com/cloudprint/learn/GoogleAPIのクライアントIDとシークレット取得
GoogleCloudPratformにアクセスして、認証情報を登録する。
https://console.cloud.google.com/
[APIとサービス]→[認証情報]→[認証情報を作成]→[OAuthクライアントID]の順番に選択
クライアントID
とクライアントシークレット
を取得(あとで使います。)
GoogleCloudPrintへのアクセス許可と、アプリケーションに設定するコードを取得
取得した
クライアントID
をURL設定して、ブラウザに直接アクセス
https://accounts.google.com/o/oauth2/auth?redirect_uri=oob&response_type=code&client_id=<ここに上記で取得したクライアントIDを指定>&scope=https://www.googleapis.com/auth/cloudprintGoogleAPIで自動印刷
今回は、JavaのUnirestを使って、実行してみる。
重要な処理だけをピックアップして記載getRefreshTokenHttpResponse<JsonNode> res = Unirest.post("https://www.googleapis.com/oauth2/v3/token") .field("code", code) // 事前準備で取得したコードを設定 .field("client_id", client_id) // 事前準備で取得したクライアントIDを設定 .field("client_secret", client_secret) // 事前準備で取得したクライアントシークレットを設定 .field("grant_type", "authorization_code") .field("redirect_uri", "oob") .asJson();リフレッシュトークンを取得する。
コードは一回使うと、もう使えなくなるのでリフレッシュトークンがわからなくなったら事前準備のコード取得から行う必要あり。getAccessTokenHttpResponse<JsonNode> res = Unirest.post("https://www.googleapis.com/oauth2/v3/token") .field("client_id", client_id) // 事前準備で取得したクライアントIDを設定 .field("client_secret", client_secret) // 事前準備で取得したクライアントシークレットを設定 .field("grant_type", "refresh_token") .field("refresh_token", refresh_token) // getRefreshTokenで取得したリフレッシュトークンを設定 .asJson();アクセストークンを取得する。
リフレッシュトークンから都度アクセストークンを取得する。
プリンタにアクセスする度に、アクセストークンを取得するように構成する。getPrintersHttpResponse<JsonNode> res = Unirest.get("https://www.google.com/cloudprint/search") .header("Authorization", token_type + " " + access_token) .asJson();GoogleCloudPrintに設定されているプリンタ一覧を取得する。
submitFileHttpResponse<JsonNode> res = Unirest.post("https://www.google.com/cloudprint/submit") .header("Authorization", token_type + " " + access_token) .field("printerid", printerid) // プリンタIDを設定:デフォルトのGoogleDriveは[__google__docs]です。 .field("title", file.getName()) .field("ticket", gson.toJson(new TicketBean())) .field("content", file) .asJson();GoogleCloudPrintにローカルPDFファイルの印刷要求を行う。
fileには、java.io.File型です。これらの処理を順番に行うことで印刷できます。
最後に
例えば、サーバ側に動的なPDF作成処理を実装し、複数クライアント側のプリンタに対して印刷を行うなど。
簡単に実現できる仕組みとなる。今はアカウントにプリンタを登録する必要があるので難しいが
いずれ、Faxがいらなくなる日が来るかもしれない。
- 投稿日:2019-02-09T10:32:17+09:00
【Java】ネストクラスに付与できる修飾子まとめ【Gold】
みなさんこんにちは!
Java Gold 取得に向けて勉強中の ひろき ppoi ( @HrkPPOI ) です。
先日 1 度目の受験で Fail してしまい,細かいところまで丁寧に学習する必要性を痛感しました。
…… と思いつつもやる気が起きず,勉強をズルズルと後回しにしていました。
Qiita に投稿する(=他人を理解させられるレベルで理解する)ことで「細かいところまで丁寧に学習する」モチベーションになるでしょうし,今後 Java Gold を学習するみなさんのお役にも立てると思い,記事を書きます。
※ 説明に誤りや過不足がありましたらぜひコメントにてご指摘ください。学習の目的で読ませていただいた上で,この記事の本旨にかなう範囲で記事を修正します!
対象読者
Java Gold に向けて勉強中で,一通りは勉強したので試験対策的な内容が読みたい
高度な Java クラスの設計 -> ネストクラス
の項目で情報の多さに戸惑い「整理してくれよ!」と憤っている
紫本の記載の簡素さに苛立っている解説に登場するクラス一覧
『オラクル認定資格教科書 Javaプログラマ Gold SE 8』
の p.63 表を参考に,ネストクラスにまつわるクラスをまとめました。概念同士の包含関係を表すためになんちゃってクラス図も描きました。
- ネストクラス
- クラス定義の中で定義されたクラス一般をそう呼ぶ
static
修飾子の有無で static クラス / インナークラス に分かれる- static クラス
- ネストクラスのうち,クラス定義部に
static
修飾子の付されて いる もの- 外側のクラスの関連に対して関連を持つ(※)
- インナークラス
- ネストクラスのうち,クラス定義部に
static
修飾子の付されて いない もの- 外側のクラスのインスタンスの関連に対して関連を持つ(※)
- ローカルクラス
- インナークラスのうち,特に,外側のクラスのメソッド内で定義されたもの
- 外側のクラスのメソッドに対して関連を持つ(※)
- 匿名クラス
- ローカルクラスのうち,特に,クラス名を指定せずに,クラス定義とインスタンス化を 1 つの式として記述したもの
※ は,こちら の記事の記述を参考にしました。簡にして要を得た言い回しだと思います?
修飾子の付与可否まとめ
Java には様々な修飾子があり,クラスの種類が増えてくると「この修飾子はこのクラスに付与できるんだっけ…?」と混乱しがちです。
理想論を言うならば,理解していれば混乱するわけがなく,問題は理解していないことであり,表にまとめて整理することは不要 です。
「まとめ」というのはいかにも試験対策的で,茶番感があるかもしれません。
しかし
各クラスの意味を理解していれば当然に修飾子の付与可否を判断できる
というのはいささか強者の理論に過ぎると思いますし,まとめてみる(比較する)ことで理解が進むこともあるでしょう。というわけで表にまとめてみました。
なんだかイケそうな気がしてきましたね…!
テキストではネストクラスの種類ごとに記載されていますから,ここでは
ふつうのクラス
( = ネストクラスでないクラス) との比較しながら, 修飾子ごと に考えていこうと思います。
abstract
修飾子
abstract
修飾子は,クラスに付与した場合,そのクラスが抽象クラスであることを示します。ネストクラスのうち,匿名クラスは
abstract
修飾子を付与することができません。そもそも匿名クラスにはクラス定義部分が存在しないため,
abstract
に限らず修飾子を付与できません。また,匿名クラスはクラス定義とインスタンス化を 1 つの式として記述しており,そのインスタンスが代入された参照変数を通してのみクラス情報を参照することを予定しています。抽象クラスは継承によってそのサブクラスから参照されることを予定していますから,
abstract
修飾子は匿名クラスの性質になじまず,匿名クラスに対してabstract
修飾子を付与することができないのでしょう。
static
修飾子static 修飾子は,付与された属性や操作が,インスタンスに属するものではなくクラスに属することを示す修飾子です。通常はメンバ変数(→ static が付与された結果,スタティック変数)やメソッドに付与されるものであって,クラスに付与されることはありません。
これに対してネストクラスの場合,
static クラス
に限っては,クラス定義に対して static 修飾子を付与することができます。この点は, static 修飾子の付与されたネストクラスを static クラスと言う のですから,言葉の定義から考えて当然でしょう,という感じですね。
protected
/private
修飾子の項目でも言及していますが,ぼくは, static クラスは 外側のクラスの属性( statice 変数)のようなもの だと理解しています。
final
修飾子
final
修飾子は,クラス定義に付与された場合,そのクラスを継承することができないことを示します。ネストクラスのうち,匿名クラスは
final
修飾子を付与することができません。これはabstract
修飾子と同様に考えることができます。
public
修飾子
public
修飾子は,クラス定義に付与された場合,そのクラスがすべてのクラスから参照できることを示します。また,属性や操作に付与された場合,その属性や操作がすべてのクラスから参照できることを示します。ネストクラスのうち,ローカルクラス / 匿名クラスでは
public
修飾子を付与することができません。ローカルクラス / 匿名クラスは,外側のクラスの,とあるメソッドの中でのみ利用されることを予定しているためです。
これは,メソッドの内部で宣言された変数が,最大でもそのメソッドの内部でのみ参照できることと同じように考えることができます。
protected
/private
修飾子
protected
/private
修飾子は,付与された属性 / 操作を参照できるクラスが限定されていることを示す修飾子です。あくまでも属性 / 操作に付与する修飾子であり,ふつうのクラスに付与することはできません。これに対して,
static クラス
・インナークラス
に対してはprotected
/private
修飾子を付与することができます。この点について,ぼくは以下のように理解しています。
- static クラス / インナークラスは,クラスを,あたかも外側のクラスの属性であるかのように扱う ものである
- そのため,属性に付与できる修飾子はすべて付与することができる
- static 修飾子を付与するともできるが,付与の有無によってそのネストクラスの呼びかた自体が変わる
- ローカルクラス・匿名クラスは,クラスを, あたかも外側のクラスのローカル変数であるかのように扱う ものである
- ローカル変数なので,アクセス修飾子は付与できない
おわり
というわけで,ネストクラスの種類ごとに,付与できる修飾子をまとめてみました。
インスタンス化やメソッド呼び出しなどもこんがらがりがち&出題されがちなので,別な投稿にまとめたいと思います!
- 投稿日:2019-02-09T01:54:20+09:00
[Java]Amazon Corretto8のインストール
はじめに
AWSが先日2月4日にAmazon Corretto 8(独自OpenJDK)を正式リリースしたという記事を読みまして、試しにインストールしてみることにしました。
前提
Macで実施します。
手順
ダウンロード
まずこちらのAWSのサイトからJDKをダウンロードしてきます。
私の場合はMacなのでmacOS x64の「amazon-corretto-8.202.08.2-macosx-x64.pkg」を選びました。各自のOSに合わせたものをDLします。
インストール
DLしたpkgファイルをダブルクリックしてウィザードに従ってインストールします。以下のような画面が出ますが、とりえあず特殊なことをしたい場合を除き、何もカスタマイズせず続けて完了させます。
設定
モノは/Library/Java/JavaVirtualMachines/に入りますが、最後にターミナルで以下のコマンドを打ってインストールを完了させます。また、JAVA_HOMEを設定したい場合は結果に表示されたパスをexportコマンドで指定してあげます。#コマンド $ /usr/libexec/java_home --verbose #結果出力 $ Matching Java Virtual Machines (2): 1.8.0_202, x86_64: "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home #(任意)JAVA_HOME設定 export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home以上です。
上記はAWSのサイトに書かれている手順なので一応間違ってはいないかと思います。
(JAVA_HOMEの設定はプロファイルとかに書くべきですかね)私は普段Eclipseを使っているので、一応適当なプロジェクトでこのJDKを指定して、(当たり前ですが)きちんと動くことを確認しました。
終わりに
正式リリースとしてはまだJava8だけのようですが、そのうち11もリリースされるようです。サポート期限の違いはあれどAdoptOpenJDKという選択肢もありますね。いずれにしても、これでJavaもまだまだ生き続けるかなと。
- 投稿日:2019-02-09T00:55:24+09:00
【用語】静的と動的
静的と動的
基本的にサーバー側とやり取りするのが動的Webプロジェクト
クライアント側で完結するのが静的Webプロジェクト例1)静的Webプロジェクト
企業サイトのように画面の情報が切り替わらないのが静的Webプロジェクト(※下記例外あり)例2)動的Webプロジェクト
ログイン画面でログインした後、「ようこそ XXXX さん」となるのが動的Webプロジェクト例外)広告バナーのようにJavaScriptを使用して画像を切り替えるなるクライアントサイドで操作するものでも静的Webプロジェクトと呼ばれる
例外があるので、動的/静的を区別する場合、以下の技術を使用しているかで判断すると分かり易い
※JavaScriptの技術を動的と捉える方もいるので、注意が必要①静的Webプロジェクト
・クライアントサイド
・HTML/CSS/JavaScript
・ブラウザ(IE/Google Chrome/Safari)だけで動作するもの②動的Webプロジェクト
・サーバーサイド
・Java/C#/PHPのようにサーバーとやり取りする場合
- 投稿日:2019-02-09T00:42:29+09:00
DateFormatはスレッドセーフじゃない
下記のようにDateFormatのインスタンスをメンバ変数として保持して使いまわしていたところ、Fabricにクラッシュレポートが上がってきました。
class Util { companion object { private val sDateFormat = SimpleDateFormat("yyyy/MM/dd") fun convert(date: Date): String { return sDateFormat.format(date) } } }調査したところ複数スレッドから呼ばれる実装になっており、ドキュメントにもあるように毎度インスタンスを生成するように変更して対応しました。
class Util { companion object { fun convert(date: Date): String { return SimpleDateFormat("yyyy/MM/dd").format(date) } } }