20210509のJavaに関する記事は16件です。

Jakarta EE 9 の dependency 一覧

Jakarta EE 9 の各仕様の dependency を一覧にした。 Jakarta EE Platform <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>9.0.0</version> </dependency> implementation 'jakarta.platform:jakarta.jakartaee-api:9.0.0' Jakarta EE Web Platform <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-web-api</artifactId> <version>9.0.0</version> </dependency> implementation 'jakarta.platform:jakarta.jakartaee-web-api:9.0.0' Jakarta Activation <dependency> <groupId>jakarta.activation</groupId> <artifactId>jakarta.activation-api</artifactId> <version>2.0.1</version> </dependency> implementation 'jakarta.activation:jakarta.activation-api:2.0.1' Jakarta Annotations <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.annotation:jakarta.annotation-api:2.0.0' Jakarta Authentication <dependency> <groupId>jakarta.authentication</groupId> <artifactId>jakarta.authentication-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.authentication:jakarta.authentication-api:2.0.0' Jakarta Authorization <dependency> <groupId>jakarta.authorization</groupId> <artifactId>jakarta.authorization-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.authorization:jakarta.authorization-api:2.0.0' Jakarta Batch <dependency> <groupId>jakarta.batch</groupId> <artifactId>jakarta.batch-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.batch:jakarta.batch-api:2.0.0' Jakarta Bean Validation <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.validation:jakarta.validation-api:3.0.0' Jakarta Concurrency <dependency> <groupId>jakarta.enterprise.concurrent</groupId> <artifactId>jakarta.enterprise.concurrent-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.enterprise.concurrent:jakarta.enterprise.concurrent-api:2.0.0' Jakarta Connectors <dependency> <groupId>jakarta.resource</groupId> <artifactId>jakarta.resource-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.resource:jakarta.resource-api:2.0.0' Jakarta Contexts and Dependency Injection <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.enterprise:jakarta.enterprise.cdi-api:3.0.0' Jakarta Dependency Injection <dependency> <groupId>jakarta.inject</groupId> <artifactId>jakarta.inject-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.inject:jakarta.inject-api:2.0.0' Jakarta Enterprise Beans <dependency> <groupId>jakarta.ejb</groupId> <artifactId>jakarta.ejb-api</artifactId> <version>4.0.0</version> </dependency> implementation 'jakarta.ejb:jakarta.ejb-api:4.0.0' Jakarta Expression Language <dependency> <groupId>jakarta.el</groupId> <artifactId>jakarta.el-api</artifactId> <version>4.0.0</version> </dependency> implementation 'jakarta.el:jakarta.el-api:4.0.0' Jakarta Interceptors <dependency> <groupId>jakarta.interceptor</groupId> <artifactId>jakarta.interceptor-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.interceptor:jakarta.interceptor-api:2.0.0' Jakarta JSON Binding <dependency> <groupId>jakarta.json.bind</groupId> <artifactId>jakarta.json.bind-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.json.bind:jakarta.json.bind-api:2.0.0' Jakarta JSON Processing <dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> <version>2.0.1</version> </dependency> implementation 'jakarta.json:jakarta.json-api:2.0.1' Jakarta Mail <dependency> <groupId>jakarta.mail</groupId> <artifactId>jakarta.mail-api</artifactId> <version>2.0.1</version> </dependency> implementation 'jakarta.mail:jakarta.mail-api:2.0.1' Jakarta Messaging <dependency> <groupId>jakarta.jms</groupId> <artifactId>jakarta.jms-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.jms:jakarta.jms-api:3.0.0' Jakarta Persistence <dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.persistence:jakarta.persistence-api:3.0.0' Jakarta RESTful Web Services <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.0.0' Jakarta Security <dependency> <groupId>jakarta.security.enterprise</groupId> <artifactId>jakarta.security.enterprise-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.security.enterprise:jakarta.security.enterprise-api:2.0.0' Jakarta Server Faces <dependency> <groupId>jakarta.faces</groupId> <artifactId>jakarta.faces-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.faces:jakarta.faces-api:3.0.0' Jakarta Server Pages <dependency> <groupId>jakarta.servlet.jsp</groupId> <artifactId>jakarta.servlet.jsp-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.0.0' Jakarta Servlet <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>5.0.0</version> </dependency> implementation 'jakarta.servlet:jakarta.servlet-api:5.0.0' Jakarta SOAP Attachments <dependency> <groupId>jakarta.xml.soap</groupId> <artifactId>jakarta.xml.soap-api</artifactId> <version>2.0.1</version> </dependency> implementation 'jakarta.xml.soap:jakarta.xml.soap-api:2.0.1' Jakarta Standard Tag Library <dependency> <groupId>jakarta.servlet.jsp.jstl</groupId> <artifactId>jakarta.servlet.jsp.jstl-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:2.0.0' Jakarta Transactions <dependency> <groupId>jakarta.transaction</groupId> <artifactId>jakarta.transaction-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.transaction:jakarta.transaction-api:2.0.0' Jakarta Web Services Metadata <dependency> <groupId>jakarta.jws</groupId> <artifactId>jakarta.jws-api</artifactId> <version>3.0.0</version> </dependency> implementation 'jakarta.jws:jakarta.jws-api:3.0.0' Jakarta WebSocket <dependency> <groupId>jakarta.websocket</groupId> <artifactId>jakarta.websocket-api</artifactId> <version>2.0.0</version> </dependency> implementation 'jakarta.websocket:jakarta.websocket-api:2.0.0' Jakarta XML Binding <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>3.0.1</version> </dependency> implementation 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1' Jakarta XML Web Services Specification <dependency> <groupId>jakarta.xml.ws</groupId> <artifactId>jakarta.xml.ws-api</artifactId> <version>3.0.1</version> </dependency> implementation 'jakarta.xml.ws:jakarta.xml.ws-api:3.0.1'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Microsoft Graph API を利用した Azure AD B2C のユーザー操作(削除編)

Microsoft Azure 上でクラウドネイティブなシステムを作る際は、ユーザー情報管理や認証処理を Azure AD B2C を利用して実現することが一般的です。 本記事では、Microsoft Graph API を利用して Azure AD B2C 上のユーザー情報を作成、更新、削除する方法を紹介します。 前提条件 Azure AD B2C テナントが作成済みであること Azure AD B2C テナントに Azure AD B2C 用ユーザーが作成されていること Microsoft Graph アプリケーションを登録されていること クライアント側は Spring-Boot ベースの Java アプリケーション pom.xml 作成編を参考にしてください。 Azure AD B2C ユーザーの ObjectId を確認する Azure AD B2C ユーザーの削除は、対象ユーザーの ObjectId が必要になります。 ObjectId は、ユーザーのプロファイル画面から確認できます。 Azure AD B2C ユーザーの削除 TestGraphApi.java @Test void deleteUser() { /** * Azure AD B2C 上にユーザーを削除 */ createIGraphServiceClient( CLIENT_ID, CLIENT_SECRET, DOMAIN_NAME).users(OBJECT_ID_FOR_DELETE) .buildRequest().delete(); // (*1) (*2) } (*1) IGraphServiceClient オブジェクトの users メソッドの引数は、削除対象ユーザーの ObjectId になります。 (*2) ユーザー作成時は post メソッドでしたが、ユーザー削除時は、delete メソッドになります。 削除時の Exception について 指定した ObjectId のユーザーが Azure AD B2C 上に存在しない場合は、以下の Excepiton が発生します。 重大: Throwable detail: com.microsoft.graph.http.GraphServiceException: Error code: Request_ResourceNotFound エラーハンドリング処理の記述を忘れないように気をつけてください。 実行結果 上記を実行すると、Azure AD B2C 上の指定した ObjectId のユーザーが削除されていることが確認できます。 以上で「Microsoft Graph API を利用した Azure AD B2C のユーザー操作」の記事は終わりになります。 本記事の前段で、ユーザー作成と更新の方法を紹介していますので、良ければご覧ください。 ユーザー作成編 ユーザー更新編 Azure AD B2C では、MFA 認証もサポートしており、ユーザー作成と一緒に、2 要素認証用電話番号の操作(作成、更新)を実施したい場合もあるかもしれません。 現時点( 2021/4 現在)で Graph API は、2 要素認証用電話番号の操作を Beta 版でサポートしています。 別の記事で、2 要素認証用電話番号 を Graph API で操作する方法について、ご紹介します。 読んで頂きありがとうございました。 検証コード Graph API リファレンス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring復習

背景  Springの機能を確認したかった。 やって見て・・・ 今ままで学んだことも忘れているが・・・そこはToDoリストを自分で作ったり、 今までの記載を確認したり、公式を確認したりしようと思う。 リソース Spring Boot 2 入門: 基礎から実演まで 原田 けいと https://www.amazon.co.jp/dp/B0893LQ5KY/ref=cm_sw_r_tw_dp_BV9D710FBKGWDJJJ3NF9 TakeAway ちゃんと想定通りのJavaバージョンになっているか。 Javaの環境設定 コンパイラー lombokの設定 1.サイトからlombok.jarをダウンロードする。 2.⁨⁨/Applications/SpringToolSuite4.app/Contents/Eclipse/へlombok.jarを配置する。 3./Applications/SpringToolSuite4.app/Contents/Eclipse/SpringToolSuite4.iniへ下記を追記する。 -javaagent:/Applications/SpringToolSuite4.app/Contents/Eclipse/lombok.jar 4.STSを再起動する Testのやり方 @SpringBootTest・・・SpringBootの機能を有効にします。 @Transactional・・・テスト開始から終了までを、トランザクション処理にします。これを付けると、各テスト後に、データが初期化(ロールバック)されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Springのapplication.propertiesから値を取得する例

application.properties accesskey=hoge Sample.java final String RESOURCE_NAME = "application"; ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_NAME); //ここで値がhogeになる final String accessKey = rb.getString("accesskey");
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SpringBootで日付計算処理アプリ

日付計算処理を行うアプリケーションを作成しましたので自分用のアウトプットとして投稿させていただきます。 記載が稚拙だったり誤っている箇所等あるかもしれませんがご容赦ください。 誤りについてはご指摘いただけますと大変幸いですm(_ _)m。 制作物イメージ ・ログイン機能がある(SpringSecurityを使用した超簡潔なもので、おまけ程度のものです) ・HTMLで表示した画面に入力した日付に対して、DBに登録した計算式から計算処理を行う 環境 macOS Big Sur Java 11 Spring Boot 2.4.5 SpringToolSuite4 gradle MySQL MyBatis ディレクトリ構成(一部抜粋) . ├src/main/java/com/example/demo/ │                 ├config / SecurityConfig.java │                 ├controller / DateCalcController.java │                 ├model / DateCalc.java │                 ├repository / DateCalcMapper.java │                 └service / DateCalcService.java └ src/main/resources/          ├templates          │  ├register.html          │  ├top.html          │  └update.html          ├static / css / style.css          ├application.properties          ├data.sql          └schema.sql 各ソースコード application.properties spring.datasource.url=jdbc:mysql://localhost:3306/[任意のDB名を記載してください]?serverTimezone=Asia/Tokyo spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=[MySQLのパスワードを記載してください] spring.datasource.sql-script-encoding=UTF-8 spring.datasource.initialization-mode=always spring.datasource.schema=classpath:schema.sql spring.datasource.data=classpath:data.sql #Log Level logging.level.com.example=debug MySQLの利用に必要な記載と、アプリ実行時に自動起動させるSQLファイルの記載です。 当記事ではxmlファイルでなくMapper.javaファイルにSQL文を記載するため、 xmlファイルのパス指定は書いておりません。 #LogLevel…コンソールにSQLの処理を出力してくれます(無くてもOKです)。 schema.sql CREATE TABLE IF NOT EXISTS DateCalc ( id INT(50) PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), plusyear INT(50), plusmonth INT(50), plusday INT(50) ) AUTO_INCREMENT = 1; 作成するテーブルの内容を記載します。 AUTO_INCREMENTによりIDは自動連番としています。 計算結果の値をMap型に格納するために重要です。 AUTO_INCREMENT=1により、初期値を1としています(デフォルトの初期値は0です)。 data.sql INSERT IGNORE INTO DateCalc (id, name, plusyear, plusmonth, plusday) VALUES (1, 'A', 1, 1, 1); INSERT IGNORE INTO DateCalc (id, name, plusyear, plusmonth, plusday) VALUES (2, 'B', 2, 2, 2); INSERT IGNORE INTO DateCalc (id, name, plusyear, plusmonth, plusday) VALUES (3, 'C', 3, 3, 3); DateCalcテーブルに予めINSERTしておくユーザー情報を記載します。 IGNOREにより、もし無ければ追加するようにしています。 SecurityConfig.java package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { //パスワードのハッシュ化 @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } /* BCryptPasswordEncoder * bcryptアルゴリズムを使用したエンコーダーにより * パスワードのハッシュ化を提供しているクラス */ @Override protected void configure(HttpSecurity http) throws Exception { http //認証リクエストの設定 authorize=認可リクエスト 認証→認可の流れ .authorizeRequests() //認証の必要があるよう設定 .anyRequest()//いかなるリクエストも .authenticated()//認証が必要 //フォームベースの設定 .and().formLogin(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth //インメモリ認証を設定 インメモリorDB認証のどちらか .inMemoryAuthentication() //"user"を追加 .withUser("user") //"password"をBCryptで暗号化 .password(passwordEncoder().encode("1")) //権限=ロールを設定 .authorities("ROLE_USER"); } } 書籍等を参考に、ただ実装しただけのログイン機能です。 SpringSecurityに用意されているログイン画面を表示させているので、htmlファイルはありません。 ユーザー名とパスワードは以下のように設定しています。 ユーザー名:user パスワード:1 top.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>日付計算アプリtop</title> </head> <body> <h1>日付を入力してください(top.html)</h1> <form method="post" th:action="@{/calc}"> <label>基準となる日付:<input type="date" name="inputdate" value="2020-01-01" max="9999-12-31"required></label><br> <button>計算実行</button><br> </form> </label> <a th:href="@{/register}"> <button>計算式の新規登録へ</button> </a> <!-- ↓↓下記の通りregister用のボタンを生成しても一応動く↓↓ <form method="get" th:action="@{/register}"> <button>計算式の新規登録へ</button><br> </form> --> <p th:if="${inputdate} == null">(日付を入力したらここに表示されます)</span></p> <p th:unless="${inputdate} == null">(入力した日付は<span th:text="${inputdate}"></span>)</p> <table border=1 align="left"> <thead> <tr> <th>計算式ID</th> <th>計算式名</th> <th>加減年</th> <th>加減月</th> <th>加減日</th> <th>計算結果(map)</th> <th>更新ボタン</th> <th>削除ボタン</th> </tr> </thead> <tbody th:each="dateCalc:${dateCalc}" th:object="${dateCalc}"> <tr> <td th:text="*{id}"></td> <td th:text="*{name}"></td> <td th:text="*{plusyear}"></td> <td th:text="*{plusmonth}"></td> <td th:text="*{plusday}"></td> <td th:text="${resultdateMap.get(__*{id}__)}"></td> <td><a th:href="@{/update/id={id}(id=*{id})}"><button>更新</button></a></td> <td><form method="post" th:action="@{/delete/id={id}(id=*{id})}"><button>削除</button></form></td> </tr> </tbody> </table> <table border=1> <thead> <tr> <th>計算結果(配列)</th> </tr> </thead> <tbody th:each="resultdateArray:${resultdateArray}"> <tr> <td th:text="${resultdateArray}"></td> </tr> </tbody> </table> </body> </html> ログイン後に表示されるトップ画面です。 日付入力欄はinputタグのtype="date"により、日付以外入力できないようにしています。 またデフォルトだとなぜか年に6桁まで入力できるため、max="9999-12-31"により疑似バリデーションしています。 計算結果の表示を、JavaのMap型と配列の2通りで行っています。 それぞれ一長一短であり、改善策を模索中です。 Map型  計算式IDをキーとして、一つのテーブルで表示できます。  しかし、delete処理などにより計算式IDが連番でなくなると、上手く結果が表示されなくなります。 配列  計算式IDが連番でなくても、順番に計算結果を表示してくれます。  しかし、配列の表示のために「th:each」を用いる必要があり、一つのテーブルで表示できません。 register.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>日付計算アプリregister</title> <link th:href="@{/css/style.css}" rel="stylesheet" type="text/css"> </head> <body> <h1>新規登録する加減算式を入力してください(register.html)</h1> <form method="post" th:action="@{/register}" th:object="${dateCalc}"> <table border=1> <thead> <tr> <th>計算式名</th> <th>加減年</th> <th>加減月</th> <th>加減日</th> </tr> </thead> <tbody> <tr> <td><input type="text" th:field="*{name}" placeholder="任意の文字"><br> <span class="form-error" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span></td> <td><input type="text" th:field="*{plusyear}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusyear')}">入力値エラー</span></td> <td><input type="text" th:field="*{plusmonth}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusmonth')}">入力値エラー</span></td> <td><input type="text" th:field="*{plusday}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusday')}">入力値エラー</span></td> </tr> </tbody> </table> <button>新規登録</button> </form> <form> </body> </html> th:if="${#fields.hasErrors()}により、特定の値以外が入力された際にエラーが表示されるようにしています。 「計算式名」はth:errorsにより、Entityクラスに@NotBlankで設定したエラーメッセージを表示しています。 それ以外は、「入力値エラー」と表示しています。 エラー分を赤字表示するため、class="form-error"を作成し、cssファイルで設定しています。 ↓エラーメッセージ表示はこんな感じです↓ update.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>日付計算アプリupdate</title> <link th:href="@{/css/style.css}" rel="stylesheet" type="text/css"> </head> <body> <h1>更新後の加減算式を入力してください(update.html)</h1> <form method="post" th:action="@{/update/id={id}(id=*{id})}" th:object="${dateCalc}"> <table border=1> <thead> <tr> <th>計算式ID</th> <th>計算式名</th> <th>加減年</th> <th>加減月</th> <th>加減日</th> </tr> </thead> <tbody> <tr> <td><p>計算式ID:<span border="1" th:text="*{id}"></span></p></td> <td><input type="text" th:field="*{name}" placeholder="任意の文字"><br> <span class="form-error" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span></td> <td><input type="text" th:field="*{plusyear}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusyear')}">入力値エラー</span></td> <td><input type="text" th:field="*{plusmonth}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusmonth')}">入力値エラー</span></td> <td><input type="text" th:field="*{plusday}" placeholder="半角数字"><br> <span class="form-error" th:if="${#fields.hasErrors('plusday')}">入力値エラー</span></td> </tr> </tbody> </table> <button>更新</button> </form> <form> </body> </html> register.htmlとほとんど同じ構成です。 違いとして、formタグ内のth:actionで指定するURL内で、更新対象の計算式のIDを動的処理により表示しています。 style.css .form-error { color:red; } エラーメッセージを赤字にしているだけです\(^o^)/ DateCalc.java package com.example.demo.entity; import javax.validation.constraints.Max; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import lombok.Data; @Data public class DateCalc { private int id; @NotBlank(message = "(Entityクラスに設定したオリジナルメッセージ):入力してください") private String name; @NotNull private int plusyear; @NotNull private int plusmonth; @NotNull private int plusday; } DBのデータを格納するためのEntityクラスです。 それぞれのフィールドにアノテーションでバリデーション処理を実装しています。 @NotNullの場合は(message = "")でエラーメッセージを変更できませんでした。(そういう仕様…?) DateCalc.Mapper.java package com.example.demo.repository; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Options; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.example.demo.entity.DateCalc; @Mapper public interface DateCalcMapper { //select全件 @Select("select * from DateCalc") public List<DateCalc> selectAll(); //select1件 @Select("SELECT * FROM DateCalc where id = #{id}") public DateCalc selectOne(int id); //新規登録 @Insert("insert into DateCalc (name, plusyear, plusmonth, plusday) values (#{name}, #{plusyear}, #{plusmonth}, #{plusday})") public void insertOne(DateCalc dateCalc); //更新 @Update("update DateCalc set name = #{name}, plusyear = #{plusyear}, plusmonth = #{plusmonth}, plusday = #{plusday} where id = #{id}") public void updateOne(DateCalc dateCalc); //削除 @Delete("delete from DateCalc where id = #{id}") public void deleteOne(DateCalc dateCalc); } MyBatisにおいてSQL文を記載しているファイルです。 SQL文が複雑だったり数が多い訳ではないので、今回は別途xmlファイルを作成せずMapperファイルに書くことにしました。 DateCalcService.java package com.example.demo.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.example.demo.entity.DateCalc; import com.example.demo.repository.DateCalcMapper; @Service public class DateCalcService { @Autowired DateCalcMapper mapper; //select全件 public List<DateCalc> selectAll() { return mapper.selectAll(); } //select1件 public DateCalc selectOne(int id) { return mapper.selectOne(id); } //insert public void insertOne(DateCalc dateCalc) { mapper.insertOne(dateCalc); } //update public void updateOne(DateCalc dateCalc) { mapper.updateOne(dateCalc); } //delete public void deleteOne(DateCalc dateCalc) { mapper.deleteOne(dateCalc); } } DateCalcController.java package com.example.demo.controller; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import com.example.demo.entity.DateCalc; import com.example.demo.service.DateCalcService; @Controller public class DateCalcController { @Autowired DateCalcService service; //top.html表示 @GetMapping("/") public String loginSuccess(Model model) { List<DateCalc> dateCalc = service.selectAll(); LocalDate[] resultdateArray = new LocalDate[0]; Map<Integer, LocalDate> resultdateMap = new HashMap<>(); model.addAttribute("dateCalc", dateCalc); model.addAttribute("resultdateArray", resultdateArray); model.addAttribute("resultdateMap", resultdateMap); return "top"; } //計算結果をtop.htmlに表示 @PostMapping("/calc") public String calc(Model model, @ModelAttribute("inputdate") String inputdateHTML) {//@ModelAttributeでhtml画面に入力された値を受けっ取っている List<DateCalc> dateCalc = service.selectAll();//DBから全データをselectしDateCalc型のListに格納 LocalDate inputdate = LocalDate.parse((inputdateHTML), DateTimeFormatter.ofPattern("yyyy-MM-dd"));//htmlファイルに入力された数値をデータ型に変換 //確認用 // System.out.println("inputdateは " + inputdate); // System.out.println("End"); //加減年・月・日格納用の配列を作成 int[] plusyear = new int[dateCalc.size()]; int[] plusmonth = new int[dateCalc.size()]; int[] plusday = new int[dateCalc.size()]; //計算結果格納用のLocalDate型の配列を作成 LocalDate[] resultdateArray = new LocalDate[dateCalc.size()]; //上記の配列を用いて、DB内の値の数だけ繰り返し処理し、各計算式に対する計算結果resultdateを作成 for(int i = 0; i < dateCalc.size(); i++) { plusyear[i] = dateCalc.get(i).getPlusyear(); plusmonth[i] = dateCalc.get(i).getPlusmonth(); plusday[i] = dateCalc.get(i).getPlusday(); resultdateArray[i] = inputdate.plusYears(plusyear[i]).plusMonths(plusmonth[i]).plusDays(plusday[i]); } //確認用 // System.out.println("計算結果日は↓"); // for(LocalDate value : resultdateArray) { // System.out.println(value); // } // System.out.println("End"); // System.out.println("resultdateArray[0]は:" + resultdateArray[0]); //Mapに格納 Map<Integer, LocalDate> resultdateMap = new HashMap<>(); for(int i = 0; i < dateCalc.size(); i++) { resultdateMap.put(i+1, resultdateArray[i]); } //確認用 // System.out.println("resultdateMap確認用"); // for(Integer key : resultdateMap.keySet()) { // LocalDate value = resultdateMap.get(key); // System.out.println("idが" + key + "のresultdateは" + value); // } // System.out.println("id1のresultdateMapは" + resultdateMap.get(1)); // System.out.println("End"); //Thymeleafへファイルへ各値を渡す model.addAttribute("dateCalc", dateCalc); model.addAttribute("inputdate", inputdate); model.addAttribute("resultdateArray", resultdateArray); model.addAttribute("resultdateMap", resultdateMap); //top.htmlを表示 return "top"; } //新規登録 @GetMapping("/register") public String displayRegister(@ModelAttribute DateCalc dateCalc, Model model) { model.addAttribute("dateCalc", dateCalc); return "register"; } @PostMapping("/register") public String runRegister(Model model, @Validated @ModelAttribute DateCalc dateCalc, BindingResult bindingresult) { if(bindingresult.hasErrors()) { System.out.println("エラー発生!BindingResult内容↓↓↓"); System.out.println(bindingresult); System.out.println("エラー発生!BindingResult内容↑↑↑"); model.addAttribute("dateCalc", dateCalc); return "/register"; } service.insertOne(dateCalc); return "redirect:/"; } //更新 @GetMapping("/update/id={id}") public String displayUpdate(Model model, @PathVariable("id") int id) { model.addAttribute("dateCalc", service.selectOne(id)); return "update"; } @PostMapping("/update/id={id}") public String runUpdate(Model model, @Validated @ModelAttribute DateCalc dateCalc, BindingResult bindingresult) { if(bindingresult.hasErrors()) { System.out.println("エラー発生!BindingResult内容↓↓↓"); System.out.println(bindingresult); System.out.println("エラー発生!BindingResult内容↑↑↑"); model.addAttribute("dateCalc", dateCalc); return "/update"; } service.updateOne(dateCalc); return "redirect:/"; } //削除 @PostMapping("delete/id={id}") public String deleteOne(@ModelAttribute DateCalc dateCalc) { service.deleteOne(dateCalc); return "redirect:/"; } } ところどころ、コンソールで確認するための記載はコメントアウトしています。 計算結果の日付について、配列はresultdateArray、Map型はresultdateMapへ格納しています。 バリデーション処理実装時に最も詰まったのが「Controllerクラスにおいて変数名をどう設定するか」です。 当初はHTMLファイル内のth:if="${#fields.hasErrors('')}が常にfalseとなりエラーメッセージが表示されませんでした。 原因は、DateCalcの変数名を「dc」と設定していたためです。 BindingResultのエラーメッセージを見ると分かるのですが、BindingResultは以下のような形式で自動的にEntityクラスの名前を生成しエラーを探しているようです。  例)DateCalc → dateCalc よって、「dateCalc」という変数名を設定しHTMLファイルに渡す必要があります。 以下のteratailを参考にさせていただきました。ありがとうございました! https://teratail.com/questions/171010 あとはブラウザに( http://www.localhost:8080/ ) と入力すればログインページが表示されるはずです。 お読みいただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】MapでforEachメソッドを使い方法

はじめに 本記事では、Java8で追加されたListやMapなどを巡回(Iterate)するためのforEachメソッドについてアウトプットします。 以下ではMapを巡回するための方法について書きます。 ①Lambdaを使用する場合 Map<String, String> capitalsMap = new LinkedHashMap<>(); capitalsMap.put("Paris", "France"); capitalsMap.put("Beijin", "China"); capitalsMap.put("Berlin", "Germany"); capitalsMap.put("Canberra", "Australia"); capitalsMap.forEach((k, v) -> { System.out.println("key: " + k + ", value: " + v); }); 出力 key: Paris, value: France key: Beijin, value: China key: Berlin, value: Germany key: Canberra, value: Australia ②entrySetを使用する場合 Map<String, String> capitalsMap = new LinkedHashMap<>(); capitalsMap.put("Paris", "France"); capitalsMap.put("Beijin", "China"); capitalsMap.put("Berlin", "Germany"); capitalsMap.put("Canberra", "Australia"); capitalsMap.entrySet().forEach(entry -> { System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue()); }); 出力 key: Paris, value: France key: Beijin, value: China key: Berlin, value: Germany key: Canberra, value: Australia まとめ 個人的にはentrySetを使った方が分かりやすいですが、 Lambdaを使った方がコードがスッキリして良いと思いました。 参照 Java Platform SE8 #Map
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】正規表現及びその具体例のまとめ

正規表現(Regular expression)まとめ 正規表現: ・文字列のパターンをまとめたもの ・不正な文字列がないかの入力チェックを容易に行える 正規表現の数は膨大だが、よく使うものを次節以降にまとめる。 *正規表現すべての一覧はjava.util.regex.PatternクラスのAPIドキュメントに載っている https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/regex/Pattern.html パターンの例⓵ パターン文字 意味 xyz xyzという文字列 [xyz] x,y,zのどれか一文字 [^xyz] x,y,z以外のどれか一文字 [a-z] a-z(小文字アルファベット)のどれか一文字 [a-z][A-Z] 小文字アルファベットまたは大文字アルファベットのどれか一文字 [a-zA-Z] ↑に同じ パターンの例②(数量子) 数量子…任意の数の文字を表現する パターン文字 意味 x? xが0または1回(例:"ax?z" -> "az" or "axz") x* xが0回以上(例:"ax*z" -> "az", "axxxxxz" etc) x+ xが1回以上(例:"ax+z" -> "axz", "axxxxxz" etc) x{n} xがn回(例:"ax{3}z" -> "axxxz") x{n,} xがn回以上(例:"ax{3,}z" -> "axxxz", "axxxxxz" etc) x{n,m} xがn回以上m回以下(例:"ax{3,4}z" -> "axxxz" or "axxxxz") パターンの例⓷(定義済み文字列) 定義済み文字列…[a-z]や[0-9]といった文字集合を省略して表記 パターン文字 意味 . 任意の文字 \d 数字[0-9] \D 数字以外[^0-9] \s 空白文字[\t\n\x0B\f\r] \S 空白文字以外[^\s] \w 単語構成文字[a-zA-Z_0-9] \W 単語構成文字以外[^\w] Javaで正規表現を用いる具体例 具体的なメソッドの例 クラスPatternのメソッド static Pattern compile(String regex) 指定された正規表現をPatternにコンパイルする クラスMatcherのメソッド public boolean find() 入力シーケンスからこのパターンとマッチする次の部分シーケンスを検索する public String group() 前回のマッチで一致した入力部分シーケンスを返す Stringクラスのメソッド public String replaceAll​(String regex, String replacement) 指定された文字列(あるいは正規表現)に一致する各部分文字列に対し、指定された置換を行う public String[] split​(String regex) 文字列を指定された正規表現に一致する位置で分割する public boolean matches​(String regex) 文字列が指定された正規表現と一致するかどうかを判定する 具体例⓵ 電話番号をハイフンで分割 public class ApiSample { public static void main(String[] args) { String str = "000-0000-0000"; String[] str2 = str.split("-"); for(String s :str2) { System.out.println(s); } } } 実行結果 000 0000 0000 具体例② 文字のみを取り出したい public class ApiSample { public static void main(String[] args) { String str = "a. b. c. b. e"; String[] str2 = str.split("\\.\\s"); for(String s :str2) { System.out.println(s); } } } 実行結果 a b c d e 具体例⓷ アルファベット以外の文字で分割 public class ApiSample { public static void main(String[] args) { String str = "abc$de@fgh0ijk^lmn"; String[] str2 = str.split("[^a-zA-Z]"); for(String s :str2) { System.out.println(s); } } } 実行結果 abc de fgh ijk lmn おわりに 参考書籍:Java SE8 Silver 黒本
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodigGameのゲームAI対戦環境をローカルで動かす 〜Kotlin編〜

パラメータ調整用にCodingameのローカルテスト環境を作った際のメモです。 主な対象はKotlinですが、Javaでもほぼ同じ方法で動かすことができます。 CodinGameとは? ゲームを通してプログラミングを学んで遊べるWebベースのプラットフォームです。 自作のゲームAIを戦わせるオリジナルゲームが非常に良く練られていてまたサイトの完成度も高く、数あるプログラミングサイトの中でもトップクラスの面白さだと思います。 より詳しくは以下が参考になるかと思います。 - https://qiita.com/javacommons/items/b178c924199d1a6d524d なぜローカルの実行環境を作るのか CodinGameではエディタでコードを書いてビルドして対戦させるまでがサイト上で完結するようになっており、ブラウザ1つあれば遊べるようになっています。 ですが新しい戦略を試したりパラメータ調整を行う際にはブラウザ上でポチポチ操作するより手元で自動実行したほうが楽で効率も良いため、ローカルの実行環境を作っておくことがオススメです。 ローカル実行環境の構築 実行コードの取得・ビルドの準備 ゲームの実行環境はGitHubで公開されており、それをCloneすればコードの取得は完了です。 ゲームのルールのページ等にリンクがあるかと思います。(今回のSpringChallenge2021は https://github.com/CodinGame/SpringChallenge2021 にありました。) 実行環境のビルドシステムにはMavenが使われており、環境を用意してCLIからビルドしても良いですが今回はIntellij IDEAを使いました。 "Project from existing source..." からCloneしてきたソースのルートを指定し、 "Import Project" でMavenを選択すればあとはIDEがよしなにやってくれると思います。 ゲームの実行 いよいよ手元でゲームを動かします。 ゲーム実行環境は先程のソースの src/test/java/Spring2021.java にあります。(他のゲームでもゲーム名かMain.javaのような名前になっているようです。) ゲーム実行の本体は MultiplayerGameRunner クラスでこれにリーグレベル(レベルによってルールが変わります)、乱数のシード、そして自分で作成したゲームAIクラスを ”Agent” として登録します。 今回はKotlinで "Agent1.kt" と "Agent2.kt" に作成したものを登録します。 Spring2021.java public static void main(String[] args) throws IOException, InterruptedException { launchGame(); } public static void launchGame() throws IOException, InterruptedException { MultiplayerGameRunner gameRunner = new MultiplayerGameRunner(); gameRunner.setLeagueLevel(3); Properties gameParameters = new Properties(); gameRunner.setGameParameters(gameParameters); gameRunner.addAgent( Agent1Kt.class, "Tororo", "https://static.codingame.com/servlet/fileservlet?id=61910307869345" ); gameRunner.addAgent( Agent2Kt.class, "Ghilbib", "https://static.codingame.com/servlet/fileservlet?id=61910289640958" ); gameRunner.setSeed(7308340236785320085L); gameRunner.start(8888); } Agent1.kt の中身は基本的にはCodinGameのWeb上で動かすものと同じです。 ただし Agent1.kt と Agent2.kt に同名のルートレベル関数などがあるとまずいので、それぞれのクラスなりに入れておく必要があります。 またCodinGameの仕様(?)なのか入出力のストリームはファイル直下の main で取ったものを使う必要があるようです。 まとめると以下のようになります。 Agent1.kt fun main(){ Agent1.solve(Scanner(System.`in`), System.`out`) } object Agent1{ fun solve(input: Scanner, output: PrintStream) { // Game AI } } これにて準備は完了です。実行(IntelliJならSpring2021.javaのmainの横の実行ボタンを押すだけです)すると対戦が行われ、結果のアニメーションをローカルホスト(http://localhost:8888/test.html)から見ることができます。 アニメーションの省略と結果の取得 まとめてローカルで対戦を実行する場合、アニメーションは不要な場合が多いかと思います。 その場合 MultiplayerGameRunner.start() に変わって MultiplayerGameRunner.simulate() を用いることでアニメーション生成を省略して実行することができ、対戦結果データを GameResult クラスで取得することができます。 例えば両者のスコアを取得したい場合は以下のようになります。 Spring2021.java public static void launchGame() throws IOException, InterruptedException { // (略) gameRunner.setSeed(7308340236785320085L); GameResult result = gameRunner.simulate(); System.out.println("Agent1: " + result.scores.get(0) + ", Agent2: " + result.scores.get(1)); // Agent1: 70, Agent2: 69 } 参考 https://tech.io/playgrounds/25775/codingame-sdk-documentation/game-runner
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Effective Java(第3版) 項目9 try-finally よりも try-with-resources を選ぶ

クローズしなければならない資源に対しては、Java7で導入された try-with-resources を使用するべき、という内容です。 記載内容 結論としては、クローズが必要な資源を使用する場合、try-with-resourcesを使用するべき。 try-finally の欠点 Java6以前は、資源の適切なクローズを保証するだったが、以下の欠点がある 間違えやすい(2007時点でJavaライブラリ内の3分の2が間違えているほど) finally内で発生した例外が最初に発生した例外を隠してしまう try-with-resources の利点 try-finally の問題が一挙に解決している。 * 資源はAutoCloseableインタフェースを実装する必要が有る * closeで例外が発生しても、最初の例外が優先される。getSuppressedメソッドで、closeで発生した例外も取得可能 * catch節を記載することも可能 考察 既に try-with-resources のメリットが広く認識されており、特に問題ないと思います。 著者が間違えたというJava puzzlersのコードは以下の様なものです。 InputStream in = null; OutputStream out = null; try { in = new FileInputStream(src); out = new FileOutputStream(dest); byte[] buf = new byte[1024]; int n; while ((n = in.read(buf)) > 0) out.write(buf, 0, n); } finally { if (in != null) { try { in.close(); } catch (IOException e) {} // クローズエラーに対して出来ることはない } if (out != null) { try { out.close(); } catch (IOException e) {} // クローズエラーに対して出来ることはない } } 何を間違えているか明示されていませんので確実ではないですが、 メインのIO処理で例外が発生せず、クローズで例外が出た場合、 その例外が握りつぶされることが問題なのかと思います。 確かに、try-with-resourcesなしで、これを綺麗に書くのは難しいですね・・・
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

一目で思い出せるJavaのArrayDequeのキュー/スタックとしての使い方

Javaでキューやスタックの処理を行いたい 競技プログラミングなどで、キューやスタックの処理を行いたいことがよくあります。キューの処理については大概の場合優先度をつけて実行するPriorityQueueを使用することが多いですが、純粋にキューの処理を行いたい場合や、スタックの処理を行いたい場合はArrayDequeクラスを使用することができます。 このクラスは両端キュークラスなので、先入れ先出し(FIFO)のキューとしても、後入れ先出し(LIFO)のスタックとしても使用することができるのですが、似たような名前のメソッドが多くよく混乱するので、使い方を整理しておきます。 図解+基本的な使い方 大概の場合は以下の図のメソッドを使えば処理できると思います。poll系のメソッドを使うと取り出した要素は削除されます。キューとスタックで違うのは、取り出すときに使うメソッドだけです。 キュー(先入れ先出し=FIFO) ArrayDeque<Integer> queue = new ArrayDeque<>(); for ( int i = 0 ; i < 5 ; i++ ) queue.add(i); while ( queue.size() > 0 ) { System.out.print(queue.poll() + " "); } 実行結果 0 1 2 3 4 スタック(後入れ先出し=FIFO) ArrayDeque<Integer> stack = new ArrayDeque<>(); for ( int i = 0 ; i < 5 ; i++ ) stack.add(i); while ( stack.size() > 0 ) { System.out.print(stack.pollLast() + " "); } 実行結果 4 3 2 1 0 性能 競技プログラミングで使う場合は性能が気になると思います。要素を100個追加して100個取り出す、というのを100万回繰り返して(つまり合計1億回の追加・取り出し)所要時間を測定してみました。 所要時間(計1億回の追加・取り出し) キュー 651ms スタック 586ms キューとして使ってもスタックとして使っても、このクラスが原因で性能問題が起きるようなものではなさそうです。 なお、測定に使用したコードと環境は以下の通りです。 static void timeCount() { long time = 0; for ( int i = 0 ; i < 100 ; i++ ) { time += exec(1000000, 100); } System.out.println(String.format("time: %d[ms]", time / 100)); } static long exec(int N, int K) { ArrayDeque<Integer> queue = new ArrayDeque<>(); long a = 0; long start = System.currentTimeMillis(); for ( int i = 0 ; i < N ; i++ ) { for ( int j = 0 ; j < K ; j++ ) { queue.add(i); } while ( queue.size() > 0 ) { a += queue.poll(); // スタックの場合はpollLast() } } long end = System.currentTimeMillis(); return end - start; } 測定マシン:Mac mini(2018) CPU: 3.6 GHz クアッドコアIntel Core i3 メモリ: 16GB 実行環境 Java 8 メソッドの整理 ついでなので、その他のメソッドについても整理してみました。基本的にはDequeインターフェースのドキュメントにまとめられていますが、機能・位置・特殊値の取り扱いで整理すると見通しが良くなると思います。 メソッド 機能 位置 特殊値 addFirst(e) 追加 先頭 NullPointerException addLast(e), add(e) 追加 末尾 NullPointerException offerFirst(e) 追加 先頭 NullPointerException(※) offerLast(e), offer(e) 追加 末尾 NullPointerException(※) removeFirst(), remove() 取得&削除 先頭 NoSuchElementException removeLast() 取得&削除 末尾 NoSuchElementException pollFirst(), poll() 取得&削除 先頭 null pollLast() 取得&削除 末尾 null getFirst(), element() 取得 先頭 NoSuchElementException getLast() 取得 末尾 NoSuchElementException peekFirst(), peek() 取得 先頭 null peekLast() 取得 末尾 null 「特殊値」の列は追加系は追加する値がnullだった場合、取得(+削除)系は取得すべき値が存在しない場合を表しています。混乱しがちなポイントを以下に整理しておきます。 offer系で、null値を追加しようとした場合、Dequeのドキュメント上はfalseを返してきそうな雰囲気があるが、ArrayDequeのドキュメントをきちんと読むとわかるように例外となる(「※」を付けた部分) したがって、add系とoffer系は同じ動作 First, Lastがつかないメソッドは、追加系はLast, 取得系はFirstとして動作(FIFOのキューの振る舞い) getだけは省略系がelement() 結論 結論としては、通常使用する範囲では以下を覚えておけば良いと思います。 キュー(FIFO)として使用する場合 追加:add(e) 取得&削除:poll() 取得:peek() スタック(LIFO)として使用する場合 追加:add(e) 取得&削除:pollLast() 取得:peekLast()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]ES256アルゴリズムを用いたJWT生成方法 メモ

Sign in with Apple 用クライアントシークレットをES256を用いたJWT形式で生成する必要があったため、Javaでその生成方法を検証した。その際のメモを残す。 JWTとは JSON Web Tokenの略称。 電子署名による改竄検知機能を持ったトークン。 認証用途などで用いられる。 ピリオド(".")区切りのHeader部、Payload部、Signature部から構成される。 Header.Payload.Signature Header部:JWTの検証に必要な情報から構成される。署名に使用するアルゴリズム(alg)や署名に使用する鍵(公開鍵/秘密鍵)を識別する値(kid)などが含まれる。 Payload部:JWTに関する属性情報から構成される。JWTの発行者(aud)や発行日時(iat)などの情報が含まれる。 Signature部:Header部とPayload部を合わせた文字列に署名した値。Header部に指定したアルゴリズムと秘密鍵を使用して署名を行う。 各部位はBase64URLエンコードされる。 署名アルゴリズムには、ES256やRSA-SHA256などが用いられる。 ES256:「P-256 および SHA-256 を使⽤した ECDSA」の別称。 ECDSA:Elliptic Curve Digital Signature Algorithm, 楕円曲線デジタル署名アルゴリズム P-256:使⽤されるアルゴリズムのバージョン。 サンプルコード Sign in with Apple のJWT例を構成情報とした生成コード。 デベロッパーコンソールから取得した鍵は使用せず、自前で生成した鍵を使用して署名を行う。 エラーハンドリングなどは省略。 package jwt_test; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.SignatureException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.codec.binary.Base64; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; public class JWTTest { private static ECPublicKey PUBLIC_KEY; private static ECPrivateKey PRIVATE_KEY; public static void main(String[] args) { try { String jwt = generateJWT(); verifyJWT(jwt, PUBLIC_KEY); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); } } // JWT生成 private static String generateJWT() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, SignatureException, InvalidKeyException, JsonProcessingException { // 署名鍵生成 // ※Sign in with Appleの場合は、コンソールから生成した秘密鍵を利用する。https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC"); keyPairGenerator.initialize(new ECGenParameterSpec("secp256r1")); final KeyPair keyPair = keyPairGenerator.generateKeyPair(); PUBLIC_KEY = (ECPublicKey) keyPair.getPublic(); PRIVATE_KEY = (ECPrivateKey) keyPair.getPrivate(); byte[] publicKeyEncodedBytes = Base64.encodeBase64(PUBLIC_KEY.getEncoded()); byte[] privateKeyEncodedBytes = Base64.encodeBase64(PRIVATE_KEY.getEncoded()); System.out.println("ES256 Public Key:" + new String(publicKeyEncodedBytes)); System.out.println("ES256 Private Key:" + new String(privateKeyEncodedBytes)); // ヘッダー部設定 final ObjectMapper objectMapper = new ObjectMapper(); final Map<String, Object> jwtHeader = new LinkedHashMap(); jwtHeader.put("kid", "ABC123DEFG"); jwtHeader.put("alg", "ES256"); String jwtHeaderStr = Base64.encodeBase64URLSafeString(objectMapper.writeValueAsBytes(jwtHeader)); // ペイロード部設定 final Map<String, Object> jwtPayload = new LinkedHashMap(); jwtPayload.put("iss", "DEF123GHIJ"); jwtPayload.put("iat", 1437179036); jwtPayload.put("exp", 1493298100); jwtPayload.put("aud", "https://appleid.apple.com"); jwtPayload.put("sub", "com.mytest.app"); String jwtPayloadStr = Base64.encodeBase64URLSafeString(objectMapper.writeValueAsBytes(jwtPayload)); // 署名設定 final Signature jwtSignature = Signature.getInstance("SHA256withECDSAinP1363Format"); jwtSignature.initSign(PRIVATE_KEY); jwtSignature.update((jwtHeaderStr + "." + jwtPayloadStr).getBytes()); byte[] jwtSignatureBytes = jwtSignature.sign(); final String jwtSignatureStr = Base64.encodeBase64URLSafeString(jwtSignatureBytes); final String jwt = jwtHeaderStr + "." + jwtPayloadStr + "." + jwtSignatureStr; System.out.println("jwt:" + jwt); return jwt; } // 署名検証 public static void verifyJWT(String jwt, ECPublicKey publicKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final String[] splitJwt = jwt.split("\\."); final String jwtHeaderStr = splitJwt[0]; final String jwtPayloadStr = splitJwt[1]; final String jwtSignatureStr = splitJwt[2]; final Signature jwtSignature = Signature.getInstance("SHA256withECDSAinP1363Format"); jwtSignature.initVerify(publicKey); jwtSignature.update((jwtHeaderStr + "." + jwtPayloadStr).getBytes()); if( jwtSignature.verify(Base64.decodeBase64(jwtSignatureStr))) { System.out.println("Verifying Signature Success"); }else { System.out.println("Verifying Signature Failure"); } } } 動作確認 ES256 Public Key:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaGzLv1quqEfO2YfyeMKJ5y72hVYP+NgH2tSqyKtW3MoxZShcY/p3aSw9af+N4bDwutbrTtLmEn4I6GbV71/bcQ== ES256 Private Key:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCBS+5M9cXf4BPwM8g8JTR4Dma26Etno8lAXg7EgsWht4A== jwt:eyJraWQiOiJBQkMxMjNERUZHIiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJERUYxMjNHSElKIiwiaWF0IjoxNDM3MTc5MDM2LCJleHAiOjE0OTMyOTgxMDAsImF1ZCI6Imh0dHBzOi8vYXBwbGVpZC5hcHBsZS5jb20iLCJzdWIiOiJjb20ubXl0ZXN0LmFwcCJ9.WxE4w1JSf1dxcHJiDaFdRHstMveiwfqn0ZcwW_7PEJji0kRuJWCczt_AM3-RW6lgp8CDREfTnQTMRegnHohRKg Verifying Signature Success ※生成されたjwtの中身をjwt.ioで確認した結果 Header部 { "kid": "ABC123DEFG", "alg": "ES256" } Payload部 { "iss": "DEF123GHIJ", "iat": 1437179036, "exp": 1493298100, "aud": "https://appleid.apple.com", "sub": "com.mytest.app" } 参考情報 JWT(JSON Web Token)の紹介 What the Heck is Sign In with Apple? Generate and Validate Tokens
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者Webエンジニア備忘録

Qiitaはじめました こんにちは。 グチコと申します。 自分のインプットした情報をアウトプットし、身に付けるためにQiitaを始めました。 勉強した内容をアウトプットの場としてブログのような形で発信していきたいと思います! 自己紹介 2021年4月からWeb言語の勉強を始めました。 文系の大学卒でITとは関係ない仕事をしておりましたが、 Webエンジニアに興味を持ち独学で勉強を始めました。 現在、24歳で販売業からWebエンジニアを目指し独学で勉強中です。 趣味 セルフでジェルネイルをすること NETFLIX・youtubeを見ること おいしいものを食べること 性格 最後まであきらめずやり抜く 相手を理解しようとする 誰かのためにという強い気持ちを持っている 自己紹介は以上になります♪ 仕事終わりや、休日に勉強する時間を設け少しずつ進めています。 わからないことも多いですが、自分のスキルアップのためにコツコツ頑張ります! 現在学んでいること HTML CSS Java 学んでいるツール Progate udemy 2のサイトを活用し、3言語を学んでいます。 これからやっていくこと 学んだ言語を基にホームページを作っていきたいと思います。 経過をQiitaに更新していこうと思います。 最後に はじめての投稿は以上で終わります。 これから勉強を進めて、スキルアップに努めていきます! 不定期の更新になりますが、よろしくお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者Webエンジニアの自己紹介

Qiitaはじめました こんにちは。 グチコと申します。 自分のインプットした情報をアウトプットし、身に付けるためにQiitaを始めました。 勉強した内容をアウトプットの場としてブログのような形で発信していきたいと思います! 自己紹介 2021年4月からWeb言語の勉強を始めました。 文系の大学卒でITとは関係ない仕事をしておりましたが、 Webエンジニアに興味を持ち独学で勉強を始めました。 現在、24歳で販売業からWebエンジニアを目指し独学で勉強中です。 趣味 セルフでジェルネイルをすること NETFLIX・youtubeを見ること おいしいものを食べること 性格 最後まであきらめずやり抜く 相手を理解しようとする 誰かのためにという強い気持ちを持っている 自己紹介は以上になります♪ 仕事終わりや、休日に勉強する時間を設け少しずつ進めています。 わからないことも多いですが、自分のスキルアップのためにコツコツ頑張ります! 現在学んでいること HTML CSS Java 学んでいるツール Progate udemy 2のサイトを活用し、3言語を学んでいます。 これからやっていくこと 学んだ言語を基にホームページを作っていきたいと思います。 経過をQiitaに更新していこうと思います。 最後に はじめての投稿は以上で終わります。 これから勉強を進めて、スキルアップに努めていきます! 不定期の更新になりますが、よろしくお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初心者が最初に学習すべき言語

初投稿です。プログラミング初心者が最初に学ぶべき言語は何?って100人のプログラマーに聞いたら20以上の言語が返ってくると思います。そんな答えの無い論争に終止符を打ちます。 結論 processing https://processing.org/ processing is 何 processing、聞きなれない言語だと思います。簡単に言うと、クリエイティブコーディングを掲げたAltJavaです。processingで書かれたコードはjavaに埋め込まれて動きます。 環境構築 公式サイトからダウンロードしてインストールするだけで環境構築終わり。エディタを起動したらもうコーディングできます。 クリエイティブコーディングとは 「楽に、楽しく書こう」という概念です。一行のコードでウィンドウを作ったり、図形を書いたりできます。コード例を挙げるのでクリエイティブコーディングがどんなものか感じ取ってください。これをそのままprocessingにコピペすれば動きます。 400×400のウィンドウを出す。 size(400,400); 画面の中心に半径50の円を描画する。 size(400,300); ellipse(height/2,width/2,100,100); 右に移動する円を描画する。 void setup(){ //最初に一度だけ実行 size(400, 400); } void draw() { //描画のたびに実行 background(0,0,0);//背景を塗りつぶす ellipse(frameCount, width/2, 100, 100); } 正直プログラミング既修者からしたらいろいろ突っ込みたくなるような仕様だと思います。それもこれもjavaのコードに埋め込んでいる="実質マクロ"だから起こることですが、書く量を極限まで減らしているのは事実です。 そもそも初心者向け言語に必要な物とは 結論から話したので、今度は理由を話します。独断と偏見が多分に含まれているので異論は認めます。 環境構築が簡単 プログラミング初心者は9割パソコン初心者なので、パスを通すとかコマンドプロントを操作するとか、あるいは複数のソフトを正しくインストールするとか、そういうことはできません。そこが難しくて萎えてしまうと、どの言語が~とか以前の問題です。 楽しい HelloWorldとコンソールに表示できても、殆どの人は「だから何?」っていう感じだと思います。初心者でパソコンが自分の命令の通りに動くことに快感を覚える人は異常です。 そこで、図形を表示したりアニメーションを作ったりすると、楽しいと感じてくれる可能性が高いのです。 おまじないが少ない 書く量が多いと、タイピング速度が遅いのでストレスが溜まるし、覚えることも多いので、萎える確率が上がる。出来るだけ書く量が少ない方がいい。 if式やfor inがあると、参考演算子やfor(;;)などを使わなくて済むのでそういうのも重要。 乗り換えやすい そもそもプログラミング言語は何をしたいかによって選ぶものなので、乗換前提で考えるべき。Cベースの記法がベター。 情報量 ググって解決しないのは萎える原因になる。 エラーチェック 基本的にはコンパイラが全部エラーを教えてくれるのが理想。そう考えると静的型付け言語の方が良い。 これらを満たす言語とは 表にしました 情報量 言語仕様 環境構築 楽しさ 総合点 Processing 〇 △ 〇 〇 3.5 P5.js 〇 △ 〇 〇 3.5 TypeScript 〇 〇 △ △ 3 JavaScript 〇 △ 〇 △ 3 C++ 〇 〇 △ △ 3 Kotlin △ 〇 × 〇 2.5 C# △ △ △ △ 2 Python 〇 × × △ 1.5 Java 〇 × × △ 1.5 Rust × 〇 × × 1 言語仕様は、おまじない、直感的な記法、コンパイラチェック、乗り換えやすさを総合的に考慮して採点。 楽しさは、初心者が楽しく学習できる環境があるかどうかで採点。Kotlinが〇なのはOPENrndr、C++が△なのはDXlibraryというライブラリの存在を考慮してのこと。 P5.jsっていうのは聞きなれない言語かもしれないけど、JavaScript版Processingだと思ってくれれば良い。 というわけでProcessingかP5.jsが優勝候補なんだけど、どっちにも弱点がある。共通の弱点として、埋め込みで動いているので、ブラックボックスになっている。Processingは中身がJavaなので直感的で便利な記法が全くと言って良いほど使えない。一方でP5.jsは中身がJSなので動的型付けである。 自分は動的型付けが大嫌いなので僅差でProcessingの優勝。 こんなクソみたいな言語使ってられるか!!! その通り。あくまでも初心者が最初に学ぶべき言語としては良いけれど、ある程度プログラミングのことが分かっている人にとってはクソ言語である。 だからこそある程度プログラミングのことが分かってきたら他の言語に乗り換えてほしい。乗り換え先は何をしたいかによって選ぶことになるけれど、おすすめ乗り換え先を挙げておく。 Rust +最速 +パソコンの低レイヤにも触れる -情報量とライブラリが少ない C# +Unityが使える +クロスプラットフォーム開発が超簡単 +CやC++のライブラリが使用可能 -欲しい情報が古い情報に埋もれてる Kotlin +最高に書きやすい +Javaのライブラリが使用可能 +OPENrndr(Processingより高機能なクリエイティブコーディングライブラリ) Typescript +ブラウザで動く Python +最高の資産(機械学習など) ---最低最悪の言語仕様 終わり 初心者には乗換前提でProcessingをお勧めしてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初心者に最初に学習させるべき言語

初投稿です。プログラミング初心者が最初に学ぶべき言語は何?って100人のプログラマーに聞いたら20以上の言語が返ってくると思います。そんな答えの無い論争に終止符を打ちます。 結論 processing https://processing.org/ processing is 何 processing、聞きなれない言語だと思います。簡単に言うと、クリエイティブコーディングを掲げたAltJavaです。processingで書かれたコードはjavaに埋め込まれて動きます。 公式サイトからダウンロードしてインストールするだけで環境構築終わり。エディタとセットになっているのでエディタを起動したらもうコーディングできます。 クリエイティブコーディングとは 「楽に、楽しく書こう」という概念です。一行のコードでウィンドウを作ったり、図形を書いたりできます。コード例を挙げるのでクリエイティブコーディングがどんなものか感じ取ってください。これをそのままprocessingにコピペすれば動きます。 400×400のウィンドウを出す。 size(400,400); 画面の中心に半径50の円を描画する。 size(400,300); ellipse(height/2,width/2,100,100); 右に移動する円を描画する。 void setup(){ //最初に一度だけ実行 size(400, 400); } void draw() { //描画のたびに実行 background(0,0,0);//背景を塗りつぶす ellipse(frameCount, width/2, 100, 100); } 正直プログラミング既修者からしたらいろいろ突っ込みたくなるような仕様だと思います。それもこれもjavaのコードに埋め込んでいる="実質マクロ"だから起こることですが、書く量を極限まで減らしているのは事実です。 そもそも初心者向け言語に必要な条件とは 結論から話したので、今度は理由を話します。独断と偏見が多分に含まれているので異論は認めます。以下のような条件が、初心者が最初に学ぶべきプログラミング言語の条件だと思います。 環境構築が簡単 プログラミング初心者は9割パソコン初心者なので、パスを通すとかコマンドプロントを操作するとか、あるいは複数のソフトを正しくインストールするとか、そういうことはできません。そこが難しくて萎えてしまうと、どの言語が~とか以前の問題です。 楽しい HelloWorldとコンソールに表示できても、殆どの人は「だから何?」っていう感じだと思います。初心者でパソコンが自分の命令の通りに動くことに快感を覚える人は異常です。 そこで、図形を表示したりアニメーションを作ったりすると、楽しいと感じてくれる可能性が高いのです。 おまじないが少ない 書く量が多いと、タイピング速度が遅いのでストレスが溜まるし、覚えることも多いので、萎える確率が上がる。出来るだけ書く量が少ない方がいい。 if式やfor inがあると、三項演算子やfor(;;)などを使わなくて済むのでそういうのも重要。 乗り換えやすい そもそもプログラミング言語は何をしたいかによって選ぶものなので、乗換前提で考えるべき。Cベースの記法がベター。 情報量 ググって解決しないのは萎える原因になる。 エラーチェック 基本的にはコンパイラが全部エラーを教えてくれるのが理想。そう考えると静的型付け言語の方が良い。 これらを満たす言語とは 表にしました 情報量 言語仕様 環境構築 楽しさ 総合点 Processing 〇 △ 〇 〇 3.5 P5.js 〇 △ 〇 〇 3.5 TypeScript 〇 〇 △ △ 3 JavaScript 〇 △ 〇 △ 3 C++ 〇 〇 △ △ 3 Kotlin △ 〇 × 〇 2.5 C# △ △ △ △ 2 Python 〇 × × △ 1.5 Java 〇 × × △ 1.5 Rust × 〇 × × 1 言語仕様は、おまじない、直感的な記法、コンパイラチェック、乗り換えやすさを総合的に考慮して採点。 楽しさは、初心者が楽しく学習できる環境があるかどうかで採点。Kotlinが〇なのはOPENrndr、C++が△なのはDXlibraryというライブラリの存在を考慮してのこと。 P5.jsっていうのは聞きなれない言語かもしれないけど、JavaScript版Processingだと思ってくれれば良い。 というわけでProcessingかP5.jsが優勝候補なんだけど、どっちにも弱点がある。共通の弱点として、埋め込みで動いているので、外側がブラックボックスになっている。 Processingは中身がJavaなので直感的で便利な記法が全くと言って良いほど使えない。一方でP5.jsは中身がJSなので動的型付けである。 自分は動的型付けが大嫌いなので僅差でProcessingの優勝。 こんなクソみたいな言語使ってられるか!!! その通り。あくまでも初心者が最初に学ぶべき言語としては良いけれど、ある程度プログラミングのことが分かっている人にとってはクソ言語である。 だからこそある程度プログラミングのことが分かってきたら他の言語に乗り換えてほしい。乗り換え先は何をしたいかによって選ぶことになるけれど、おすすめの言語を挙げておく。 Rust +最速 +パソコンの低レイヤにも触れる -情報量とライブラリが少ない C# +Unityが使える +クロスプラットフォーム開発が超簡単 +CやC++のライブラリが使用可能 -欲しい情報が古い情報に埋もれてる Kotlin +最高に書きやすい +Javaのライブラリが使用可能 +OPENrndr(Processingより高機能なクリエイティブコーディングライブラリ) Typescript +ブラウザで動く Python +最高の資産(機械学習など) ---最低最悪の言語仕様 終わり 初心者には乗換前提でProcessingをお勧めしてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

カプセル化とは

■ カプセル化とは 「隠蔽し、不正な操作や変更を防ぐ、また修正が必要になった場合にも原因箇所を特定しやすくなる」 具体的には、アクセス修飾子を用いて、クラス外からのフィールドへの読み書きやメソッドの呼び出しを制限する ■ アクセス修飾子とは フィールドやメソッドを宣言する際に、先頭に記述する「public」などで、4つのアクセス制御レベルに分かれる ・private:クラス内でのみアクセスが可能、クラス外からのアクセスを制限 ・指定なし (package privateと呼ばれることもある):同じパッケージ内のクラスのみアクセスが可能 ・protected:同じパッケージのクラスとサブクラス(自分を継承した子クラス)からアクセス可能 ・public:すべてのクラスからアクセス可能 クラスに指定できるアクセス修飾子は「public」か「指定なし」 public class hello { class hello { フィールドやメソッドにはすべてのアクセス修飾子が指定できる private String name; public int age; public void introduce() { void greet() { 基本的にフィールドはすべて「private」 メソッドは「public」にするのがセオリー ■ 制限したフィールドの利用方法( getter / setter ) privateなどでアクセスを制限したフィールドは、メソッドを経由してアクセスし使用することが可能 使用するメソッドは「 getter / setter 」 ■ getter getter は制限されたフィールド値を取り出すことができるメソッド Characterクラス public class Character { public String name; private int age; public int getAge() { return this.age; } void greet() { System.out.println("hello"); } } mainメソッドのクラス public class Tameshi { public static void main(String[] args) { Character c = new Character(); c.name = "Tanaka"; int age = c.getAge(); System.out.println(c.name + ":" + age + "歳"); System.out.println(c.name + ":" + c.getAge() + "歳"); } } Characterクラスのフィールドは name は public なのでmainメソッドのクラスでインスタンス化した後に名前を代入できるが、 age は private なため、name のようには代入できず、取り出すこともできない name と同じように c.age = 25; とすると 「フィールドc.ageは不可視です」とコンパイルエラーが出る 上記のCharacterクラスのようにget + フィールド名のメソッドを作成し、return this.○○(フィールド)、つまりメソッドを呼び出すと、このクラスの○○フィールドを返しますよ、という記述をすることで、mainメソッドのクラスで getter メソッドで指定したフィールドの値が取得できる 上記の場合は値が設定されていないため、そのままだとデフォルトの 0 のみ取得される ■ setter setter は制限されたフィールドに値を設定することができるメソッド getter が値を取得するだけのメソッドであるのに対し、setter は値を設定するだけのメソッドであり、両方あわせて使用する また getter のみ記述すればクラス外から取得はできるが書き換えはできない(Read Only)のフィールドにすることもできる Characterクラス public class Character { public String name; private int age; private int number; public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } void greet() { System.out.println("hello"); } } mainメソッドのクラス public class Tameshi { public static void main(String[] args) { Character c = new Character(); c.name = "Tanaka"; c.setAge(25); int age = c.getAge(); System.out.println(c.name + ":" + age + "歳"); System.out.println(c.name + ":" + c.getAge() + "歳"); } } setAge(int age) メソッドで引数を受けて呼び出し this.age = age; this.age(フィールド)に値を代入する setAgeメソッド経由で private なフィールドに値を代入し、設定するのみ ■ setter によって修正箇所を少なくできる  また setter を使用することで、例えばフィールド名を変更しようとした際に、フィールドが public な状態と、 private な状態では 【 public 】 name ⇒ empName public class Character { public String name; //name ⇒ empName } public static void main(String[] args) { Character c = new Character(); c.name = "Tanaka"; //① c.name ⇒ c.empName System.out.println(c.name); //② c.name ⇒ c.empName } } 上記のようにクラス外での修正箇所が多く発生してしまうが、private の場合 【 private 】 name ⇒ empName public class Character { private name; // name ⇒ empName public void getName() { return this.name; //this.name ⇒ this.empName } public void setName(String name) { this.name = name; //this.name ⇒ this.empName } } public static void main(String[] args) { Character c = new Character(); c.setName = "Tanaka"; system.out.println(c.getName()); } 上記の場合は、mainメソッド内のsetNameメソッドで渡す先の仮引数 name は、フィールドを name から emoName に変更したこととは関係がないため、クラス外での修正をせず、変更するフィールドが定義されているクラス内のみの修正で済む ■ フィールドに設定されている値が妥当かどうかを確認できる 「クラス外からフィールドの値を書き換えることを制限する」ということを利用して、setter で値が設定される際に、その値が妥当かどうかを確認するための条件式を設定し、不当な値が設定されないようにもできる private String password; public void setPassword (String password) { if(password == null) { throw new IllegalArgumentException ("パスワードが入力されていません。"); } if(password.length() <= 3) { throw new IllegalArgumentException ("パスワードが短すぎます。") ; } if(password.length() >8) { throw new IllegalArgumentException ("パスワードが長すぎます。"); } this.password = password; System.out.println("パスワードを設定しました。"); } public static void main(String[] args) { Character c = new Character(); c.setPassword("aiueo"); c.setPassword("ai"); } } 上記のコードでは、条件式で null、または3文字以下、8文字より多い場合にはエラー(throw ~ で強制終了するメソッド)を出すようにし、妥当な文字列の入力が行われた場合には this.password = password で設定している mainクラスの1つ目の文字列、"aiueo" は妥当だが、2つ目の"ai" は3文字以下のため、エラーが発生する ■ クラスに対するアクセス修飾子( public / 指定なし< package private>) クラスに対する修飾子は、ほかの全てのクラスから使用できる「public」と、そのパッケージ内でのみ利用が許されている「package private:指定なし」があり、package privateにした場合は、他のパッケージに属するクラスからのアクセスが制限される、つまり、あるクラスのフィールドやメソッドが public 指定されていたとしても、パッケージが package private であればそのフィールド、メソッドにはアクセスできない package private のクラスの特徴は 1.ファイル名と名前が同一でなくてよい 2.1つのファイル内に複数クラスを宣言できる 「クラス名とファイル名が同じでなければならない」、および「1つのソースファイル内に宣言できるクラスは1つだけ」というルールは puclic なクラスの場合であり、package private なクラスは複数宣言でき、そのファイル内にpublic なクラスがなくても構わない、その場合はファイル名は何でもよいということになる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む