- 投稿日:2021-01-23T23:03:28+09:00
MyBatis+SpringBootでCRUDアプリを作る ※余計なものはナシ※ 2/2
前回の記事の続きです。
次はクラスを作っていきます。
前回までの分はこちら
https://qiita.com/sumichan/items/bdc2a0e909416ae551623-1.Model.java
今回使うのはidとtask(やること)だけです。
@NotBlank
はvalidationでblank入力を禁止します。
@Data
はlombokがセッティングさせていれば使用できますが、されていなければgetter,setterを自分で書いてください。@Data //lombokが入っていればこれでgetter,setter生成完了 public class Todo { private Long id; @NotBlank private String task; }3-2.TodoMapper.java
個人的にmapperから書いていくとわかりやすいです。
必要なSQLを書いていきます。今回だとこの5つを使います。
mapperクラスにはinterfaceのクラスにして、@Mapper
を付けます。@Mapper public interface TodoMapper { //全件取得 @Select("select * from todo") List<Todo> selectAll(); //idが一致した1件を取得 @Select("select * from todo where id = #{id}") Todo selectOne(Long id); //登録 @Options(useGeneratedKeys = true) //自動で連番のidを取得する @Insert("insert into todo (task) values (#{task})") void insert(Todo todo); //更新 @Update("update todo set task = #{task} where id = #{id}") int update(Todo todo); //削除 @Delete("delete from todo where id = #{id}") void delete(Long id); }3-3.TodoService.java
サービスクラスには
@Service
を付けます。
mapperへ何を取ってくるのか指示しています。@Service public class TodoService { @Autowired private TodoMapper todoMapper; //全件取得 @Transactional public List<Todo> selectAll() { return todoMapper.selectAll(); } //一件取得 @Transactional public Todo selectOne(Long id) { return todoMapper.selectOne(id); } //登録 @Transactional public void insert(Todo todo) { todoMapper.insert(todo); } //更新 @Transactional public int update(Todo todo) { return todoMapper.update(todo); } //削除 @Transactional public void delete(Long id) { todoMapper.delete(id); } }3-4.TodoController.java
controlleは実行した結果のSQLを画面に渡しています。
あとは画面遷移の指示をしています。@Controller @RequestMapping("/todos") public class TodoController { @Autowired private TodoService todoService; //全件取得したtodoを、todoに入れておき、top.htmlで表示する。 @GetMapping("") public String top(Model model) { //全件取得 model.addAttribute("todo", todoService.selectAll()); //todoにselectAll()の結果を入れて、top.htmlで表示する return "todos/top";//画面はtopへ移り、todoを表示する } @GetMapping("new") //top→newボタン public String newTodo(Model model, @ModelAttribute Todo todo) { //newボタンがtopで押されるとここを通る return "todos/new"; } @PostMapping("new") //formから作成された画面 public String create(@Validated @ModelAttribute Todo todo,BindingResult result) { if (result.hasErrors()) { return "todos/new"; } todoService.insert(todo);//バリデーションに引っかからなければinsert実行 return "redirect:/todos";//一覧表に戻る } @GetMapping("{id}") //1件分のデータの中身を確認する public String show(@PathVariable Long id, Model model) { model.addAttribute("todo", todoService.selectOne(id));//urlのidを使ってsql実行 return "todos/show"; } @GetMapping("{id}/change") //編集画面に行くまでの画面 public String change(@PathVariable Long id, Model model) { model.addAttribute("todo", todoService.selectOne(id)); return "todos/change";//取得したidを使って、change画面へ } @PutMapping("put/{id}") //更新画面 public String update(Todo todo) { todoService.update(todo); return "redirect:/todos"; } @DeleteMapping("{id}/delete") //消去画面 public String dast(@PathVariable Long id) { todoService.delete(id); return "redirect:/todos"; } }if (result.hasErrors()
バリデーションチェックに引っかかった場合(今回はtaskがブランクだった場合)は、new.htmlに戻るように指示されています。
バリデーションチェックを使用する場合は@Validated
を付けて、BindingResultを使います。
@PathVariable
でURLの値を使うことができます。4.
http://localhost:8080/todos
を実行する設定を8080にしていなければ変えてください。
無事にCRUDができたら完成です!
お疲れ様でした!ソースコード
https://github.com/IwaiSumire/trial/tree/main/Qiita210121
参考
https://qiita.com/ozaki25/items/fe5fc876bd55a9d7daa9
大変お世話になりました。
ありがとうございます。最後に
このアプリができればMyBatisを使ったCRUDの流れが掴めると思います。
応用して色々試してみてください!最後まで読んでいただきありがとうございました。
- 投稿日:2021-01-23T23:02:48+09:00
MyBatis+SpringBootでCRUDアプリを作る ※余計なものはナシ※ 1/2
MyBatisを使ったToDoリストを作成します。
目標物はこれ↓
- やることを登録(blankは登録できない)
- やることを見る
- やることを変更
- やることを消去
以上ができる単純なアプリです。作成した経緯
SpringBootのCRUDができる書籍はありますが、MyBatisを使ったものは少ないです。(ほぼJPAかJDBC)
また、BootstrapやJSが混ざったもの、HTMLが複雑なものも多く、私が理解しづらかったため、わかりやすくシンプルなものにしてみました。対象者
- Controller、Service、Repositoryが何をしている何となくわかる人。
- CRUDが何かわかる人。
- JPAやJDBCがなんとなくわかる人。
- MyBatisを初めて使う人。
使っている環境
■OS : Windows10
■IDE : Eclipse
■Maven
■SpringBoot
■DB : MySQL8.0.22MyBatisとは
簡単に言えばDBに接続してSQL文を実行してくれるものです。(O/Rマッパー)
JDBCより簡単で、JSPより細かいSQL文が実行できます。
今まではおそらくRepositoryクラスで作成されていたものが、今回はMapperクラスとなります。
XMLに書くこともできるのですが、今回は分かりやすいのでアノテーションに書いていきます。
(こっちの方が新しい書き方のようです)1-1.pom.xml
今回DBはMySQL、O/RマッパーにMyBatis、バリデーション機能を使うので3つをapplicationに追加します。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>1-2.application.properties
MySQLへの接続をします。
#MySQLのDBのURL spring.datasource.url=jdbc:mysql://localhost:3306/xxxxxxx?serverTimezone=JST #name、password指定。 spring.datasource.username=root spring.datasource.password=xxxxxxxx #SpringBootを起動したときに実行したいSQL文を記述したパス #schemaにはテーブルを作るSQLを入れておく spring.datasource.schema=classpath:schema.sql #これがないとputやdeleteでエラーになる spring.mvc.hiddenmethod.filter.enabled=trueご自身のMySQLの環境に合わせてください。
spring.mvc.hiddenmethod.filter.enabled=true がないとエラーになります。
ここで私はハマりましたww
htmlのhttpメソッドでdeleteとputを使っているので必要になります。
getとpostで書けば不要となります。
その場合はControllerのアノテーションも@GetMapping
に揃えてください。
↓こちらを参考にさせていただきました。
https://qiita.com/kazuhiro1982/items/b8b9965fddf9c55075171-3.MySQLでテーブルを作る
CREATE TABLE IF NOT EXISTS todo ( id bigint(20) NOT NULL AUTO_INCREMENT, task varchar(255) DEFAULT NULL, PRIMARY KEY (id) );特に難しいSQLではないですが
NOT EXISTSはもうテーブルが存在するなら、再度作らない。
AUTO_INCREMENTは連続した番号を付ける。2-1.top.html(最初の画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>ToDOリスト</title> </head> <body> <h1>ToDoリスト</h1> <a th:href="@{/todos/new}"> <button>ToDo作成【NEW】</button> </a> <div th:if="!${todo.size()}"> <p>該当の検索結果がありません!</p> </div> <table th:if="${todo.size()}" border="1"> <thead> <tr> <th>ID#</th> <th>やること</th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> <tr th:each="todo:${todo}" th:object="${todo}"> <!-- each;DBの情報をすべて出すまで繰り返す --> <td th:text="*{id}"></td> <td th:text="*{task}"></td> <td><a th:href="@{/todos/{id}(id=*{id})}"> <button>詳細</button> </a></td> <td><a th:href="@{/todos/{id}/change(id=*{id})}"><button>変更</button></a></td> <td> <form th:action="@{/todos/{id}/delete(id=*{id})}" th:method="delete"> <button>消去</button> </form> </td> </tr> </tbody> </table> </body> </html>th:if="${todo.size()
todoが何も登録していないときは「該当の検索結果がありません!」と表示
th:each="todo:${todo}" th:object="${todo}
todoが全部終わるまで、todoの中身を表示
th:text="{id}" th:text="{task}"
todoの中身のidとtaskを表示
th:method="delete"
Controllerの
@DeleteMapping
に対応します。
get、post以外にも出てくるんです。2-2.new.html(登録画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>新規ToDo</title> </head> <body> <h2>新規ToDo作成</h2> <form method="post" th:action="@{/todos/new}" th:object="${todo}"> <ul> <li><label>やること</label> <br> <input type="text" id="task" name="task" th:field="*{task}" /> </li> </ul> <button >新規作成</button> </form> </body> </html>th:action="@{/todos/new}" th:object="${todo}" th:field="*{task}"
objectのtodoの中に、taskを詰めて、controllerのtodos/newに渡します。
2-3.show.html(確認画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>todo</title> </head> <body> <h2>登録内容確認</h2> <div th:object="${todo}"> <table border="1"> <tr> <th>id</th> <td><div th:text="*{id}"></div></td> </tr> <tr> <th>やること</th> <td><div ><div th:text="*{task}"></div></div></td> </tr> </table> </div> </body> </html>todoの中身のidとtaskを表示します。
2-4.change.html(変更画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>ToDo変更</title> </head> <body> <h2>ToDo変更</h2> <form th:action="@{/todos/put/{id}(id=*{id})}" th:method="put" th:object="${todo}"> <!-- 入力したやつをtodoの中にいれて使える --> <ul> <li><label>やること</label> <br> <input type="text" id="todo" name="todo" th:field="*{task}" /> <!-- fieldはramen.shopとかにしてHTMLで使える --> </ul> <button>更新</button> </form> </body> </html>todoの中身を入れ替えます。ほぼnew.htmlと同様です。
th:action="@{/todos/put/{id}(id=*{id})}" th:method="put" th:object="${todo}"
taskを詰め直したtodoをcontrollerの/todos/put/{id}(id={id})に渡します。
URLが該当のidになるようにしているので、{id}(id={id}となっています。
deleteと同じく、Controllerの@@PutMapping
に対応します。残りは次の記事へ
https://qiita.com/sumichan/items/a53e223c2a727cae26a4
- 投稿日:2021-01-23T23:02:48+09:00
MyBatis+SpringBootでCRUDアプリを作る ※一番単純※ 1/2
MyBatisを使ったToDoリストを作成します。
目標物はこれ↓
- やることを登録(blankは登録できない)
- やることを見る
- やることを変更
- やることを消去
以上ができる単純なアプリです。作成した経緯
SpringBootのCRUDができる書籍はありますが、MyBatisを使ったものは少ないです。(ほぼJPAかJDBC)
また、BootstrapやJSが混ざったもの、HTMLが複雑なものも多く、私が理解しづらかったため、わかりやすくシンプルなものにしてみました。対象者
- Controller、Service、Repositoryが何をしている何となくわかる人。
- CRUDが何かわかる人。
- JPAやJDBCがなんとなくわかる人。
- MyBatisを初めて使う人。
使っている環境
■OS : Windows10
■IDE : Eclipse
■Maven
■SpringBoot
■DB : MySQL8.0.22MyBatisとは
簡単に言えばDBに接続してSQL文を実行してくれるものです。(O/Rマッパー)
JDBCより簡単で、JSPより細かいSQL文が実行できます。
今まではおそらくrepositoryクラスで作成されていたものが、今回はMapperクラスとなります。
XMLに書くこともできるのですが、今回は分かりやすいのでアノテーションに書いていきます。
(こっちの方が新しい書き方のようです)1-1.pom.xml
今回DBはMySQL、O/RマッパーにMyBatis、バリデーション機能を使うので3つをapplicationに追加します。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>1-2.application.properties
MySQLへの接続をします。
#MySQLのDBのURL spring.datasource.url=jdbc:mysql://localhost:3306/xxxxxxx?serverTimezone=JST #name、password指定。 spring.datasource.username=root spring.datasource.password=xxxxxxxx #SpringBootを起動したときに実行したいSQL文を記述したパス #schemaにはテーブルを作るSQLを入れておく spring.datasource.schema=classpath:schema.sql #これがないとputやdeleteでエラーになる spring.mvc.hiddenmethod.filter.enabled=trueご自身のMySQLの環境に合わせてください。
spring.mvc.hiddenmethod.filter.enabled=true がないとエラーになります。
ここで私はハマりましたww
1-3.MySQLでテーブルを作る
CREATE TABLE IF NOT EXISTS todo ( id bigint(20) NOT NULL AUTO_INCREMENT, task varchar(255) DEFAULT NULL, PRIMARY KEY (id) );特に難しいSQLではないですが
NOT EXISTSはもうテーブルが存在するなら、再度作らない。
AUTO_INCREMENTは連続した番号を付ける。2-1.top.html(最初の画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>ToDOリスト</title> </head> <body> <h1>ToDoリスト</h1> <a th:href="@{/todos/new}"> <button>ToDo作成【NEW】</button> </a> <div th:if="!${todo.size()}"> <p>該当の検索結果がありません!</p> </div> <table th:if="${todo.size()}" border="1"> <thead> <tr> <th>ID#</th> <th>やること</th> <th></th> <th></th> <th></th> </tr> </thead> <tbody> <tr th:each="todo:${todo}" th:object="${todo}"> <!-- each;DBの情報をすべて出すまで繰り返す --> <td th:text="*{id}"></td> <td th:text="*{task}"></td> <td><a th:href="@{/todos/{id}(id=*{id})}"> <button>詳細</button> </a></td> <td><a th:href="@{/todos/{id}/change(id=*{id})}"><button>変更</button></a></td> <td> <form th:action="@{/todos/{id}/delete(id=*{id})}" th:method="delete"> <button>消去</button> </form> </td> </tr> </tbody> </table> </body> </html>th:if="${todo.size()
todoが何も登録していないときは「該当の検索結果がありません!」と表示
th:each="todo:${todo}" th:object="${todo}
todoが全部終わるまで、todoの中身を表示
th:text="{id}" th:text="{task}"
todoの中身のidとtaskを表示
th:method="delete"
Controllerの
@DeleteMapping
に対応します。
get、post以外にも出てくるんです。2-2.new.html(登録画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>新規ToDo</title> </head> <body> <h2>新規ToDo作成</h2> <form method="post" th:action="@{/todos/new}" th:object="${todo}"> <ul> <li><label>やること</label> <br> <input type="text" id="task" name="task" th:field="*{task}" /> </li> </ul> <button >新規作成</button> </form> </body> </html>th:action="@{/todos/new}" th:object="${todo}" th:field="*{task}"
objectのtodoの中に、taskを詰めて、controllerのtodos/newに渡します。
2-3.show.html(確認画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>todo</title> </head> <body> <h2>登録内容確認</h2> <div th:object="${todo}"> <table border="1"> <tr> <th>id</th> <td><div th:text="*{id}"></div></td> </tr> <tr> <th>やること</th> <td><div ><div th:text="*{task}"></div></div></td> </tr> </table> </div> </body> </html>todoの中身のidとtaskを表示します。
2-4.change.html(変更画面)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="layout"> <meta charset="UTF-8"> <title>ToDo変更</title> </head> <body> <h2>ToDo変更</h2> <form th:action="@{/todos/put/{id}(id=*{id})}" th:method="put" th:object="${todo}"> <!-- 入力したやつをtodoの中にいれて使える --> <ul> <li><label>やること</label> <br> <input type="text" id="todo" name="todo" th:field="*{task}" /> <!-- fieldはramen.shopとかにしてHTMLで使える --> </ul> <button>更新</button> </form> </body> </html>todoの中身を入れ替えます。ほぼnew.htmlと同様です。
th:action="@{/todos/put/{id}(id=*{id})}" th:method="put" th:object="${todo}"
taskを詰め直したtodoをcontrollerの/todos/put/{id}(id={id})に渡します。
URLが該当のidになるようにしているので、{id}(id={id}となっています。
deleteと同じく、Controllerの@@PutMapping
に対応します。残りは次の記事へ
https://qiita.com/sumichan/items/a53e223c2a727cae26a4
- 投稿日:2021-01-23T22:00:41+09:00
【Java】java.lang.NullPointerExceptionを避ける方法
プログラミング勉強日記
2021年1月23日
Javaでコードを書いているときに、よく出てくるNullPointerExcptionの意味と、NullPointerExcptionにならないようにする方法をまとめる。java.lang.NullPointerExceptionRequest processing failed; nested exception is java.lang.NullPointerExceptionNullPointerExceptionとは
参照型の変数の値にnullが格納されているとき、それを参照しようとしたときには発生する例外である。
NullPointerException(ナル・ポインタ・エクセプション、ヌル-)は、プログラミング言語Javaにおける例外の一つである。
null値(定義されていない値)の参照型変数を参照しようとした時に発生する。NullPointerExceptionは実行時例外と呼ばれるjava.lang.RuntimeException クラスのサブクラスであるため、try-catch節による例外処理を書かなくてもコンパイルエラーは発生しない。
(引用:https://ja.wikipedia.org/wiki/NullPointerException)なので、以下のようなコードだとNullPointerExcptionが発生する。
class Sample{ public static void main(String[] args) { Integer i = null; i.toString(); } }NullPointerExcptionを避ける方法
基本的には、参照型変数がnullかどうか判定すればいい。
先ほどのコードではNullPointerExcptionが発生したが、参照型変数がnullの場合は処理をしないというコードに書きかえることでNullPointerExcptionをなくせる。class Sample{ public static void main(String[] args) { Integer i = null; // i がnullの場合、処理をしない if(i == null) { return; } i.toString(); } }しかし、コード量が増えるほど判定は大変になるので対策方法を示す。
- null以外の値で変数を初期化する
- 配列は空で初期化する
- 戻り値にnullを返さない
この3つを意識することで、NullPointerExcptionあ発生しにくくなると思う。
参考文献
- 投稿日:2021-01-23T17:50:17+09:00
VSCodeのターミナルから実行
はじめに
VSCodeのTerminalからコマンドラインでコンパイル&実行する方法についての備忘。
文字コードの設定オプションが必要。Terminal表示
コンパイル/実行
ディレクトリ移動
dir cd srcコンパイル/実行
日本語が文字化けしてしまう。
javac HelloWorld.java java HelloWorldコンパイル/実行(エンコードUTF-8指定)
エンコードの指定をしてコンパイル/実行すると正しく表示された。
javac HelloWorld.java -encoding UTF-8 java -Dfile.encoding=UTF-8 HelloWorld
- 投稿日:2021-01-23T17:50:17+09:00
VSCodeのターミナルからコンパイル/実行
はじめに
VSCodeのTerminalからコマンドラインでコンパイル&実行する方法についての備忘。
日本語でコーディングや出力をする場合文字コードのコンパイルオプションが必要。
毎回オプション指定するのがめんどくさい場合は、設定ファイルの編集方法参照。Terminal表示
コンパイル/実行
ディレクトリ移動
dir cd srcコンパイル/実行
日本語が文字化けしてしまう。
javac HelloWorld.java java HelloWorldコマンドオプション
コンパイル/実行(エンコードUTF-8指定)
エンコードの指定をしてコンパイル/実行すると正しく表示された。
javac HelloWorld.java -encoding UTF-8 java -Dfile.encoding=UTF-8 HelloWorld設定ファイル変更
設定ファイルの変更で対応する場合はsettings.jsonに以下の2つの設定の追加が必要。
1.コンパイルオプションの文字コード(UTF-8)指定
2.Terminalの文字コード(UTF-8)指定
編集後はVSCodeを再起動。1.ファイルの文字コード変更
以下の設定をsettings.jsonに追記
"java.jdt.ls.vmargs": "-Dfile.encoding=UTF-8"2.Terminalの文字コード変更
以下の設定をsettings.jsonに追記
"terminal.integrated.shellArgs.windows": [ "-NoExit", "-Command", "/k", "chcp", "65001" ]おまけ settings.jsonの開き方
左下の[設定]から[Settings]を押下
- 投稿日:2021-01-23T17:39:33+09:00
【Java】UTF-8同士のファイルの入出力をおこなう(文字化けさせない)
こんばんは。関東では今日夜から雪が降るそうです。
風邪をひかないようにあったかくして休みましょう。今日は文字化けの話です。
1.読んでいただきたい方
・Java初心者の方
・出力ファイルの文字化けに苦しんでいる方
・特にデフォルトエンコーディングがMS932の方は、僕の環境と同じなので共感できるかも知れません(調べ方は下記参照)2.はじめに
前回の記事でも書いたのですが、僕はもともとvbscriptでファイルの読み書きをしていましたが、windows10から文字コードがUTF-8になり、文法も変わったのをきっかけにJavaで入出力のプログラムを作る事にしました。
どっこいこれが大苦戦・・。
自分なりにポイントをまとめておこうと思います。3.ポイント
・自分の開発環境のデフォルトエンコーディングを理解する
・入力・出力の文字コードをきちんと指定する4.本日の作品
このようなプログラムを作成しました(utftest.java)。
デフォルトエンコーディングがMS932の方も、
以下のプログラムを実行すると、UTF-8→UTF-8のファイル入出力ができます!!javautftest.javaimport java.io.File; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.OutputStreamWriter; import java.io.BufferedWriter; import java.io.FileOutputStream; public class utftest{ public static void main(String args[]) throws IOException{ try{ File file = new File("K0040d.txt"); //BufferedReader br = new BufferedReader(new FileReader(file)); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8")); //FileOutputStreamで文字コード・改行コードを指定(UTF-8,\n) PrintWriter fw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test.txt"),"UTF-8"))); String str = br.readLine(); while(str != null){ System.out.println(str); fw.print(str + "\n"); str = br.readLine(); } br.close(); fw.close(); }catch(FileNotFoundException e){ System.out.println(e); }catch(IOException e){ System.out.println(e); } } }インプットデータ(K0040d.txt)は以下。
2020/03/20 xxx -100 あいうえお5.対応したこと
5-1.自分の開発環境のデフォルトエンコーディングを理解する
以下を参照にしてみてください。
https://www.javadrive.jp/start/encoding/index1.html
MS932:Shift-Jis
UTF-8の場合は、UTF-8と出力されるようです。
ここで、多くの方がMS932になるようですが、この場合、UTF-8で出力する場合は、明確にUTF-8であることをプログラムに指定する必要が出てきます。5-2.入力・出力の文字コードをきちんと指定する
(1).入力処理
入力で使用したBufferedReaderクラスは、文字コードを指定できます。
(修正前)BufferedReader br = new BufferedReader(new FileReader(file));(修正後)
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));UTF-8→Shift-Jisにすれば、Shift-Jis型のファイルも読み込み可能です。
(2).出力処理
最初は、出力にfileWriterを使用していました。
javaでファイル出力、とgoogle検索して出てきた方法です。こんな具合ですね。FileWriter fw = new FileWriter("test.txt",true);しかし、FileWriterでは、出力先の文字コードを決める事ができない事が分かりました。
(https://docs.oracle.com/javase/jp/8/docs/api/java/io/FileWriter.html)
「文字ファイルを書き込むための簡易クラスです。このクラスのコンストラクタは、デフォルトの文字エンコーディングとデフォルトのbyteバッファのサイズが許容できることを前提としています。」とありました。
つまりデフォルトエンコーディングがShift-Jisの場合、出力にはUTF-8を使うことができない事になるという事と理解して、FileOutputStreamを使うようにしました。//FileOutputStreamで文字コード・改行コードを指定(UTF-8,\n) PrintWriter fw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream("test.txt"),"UTF-8")));6.感想
正直、ここまでファイル入出力でハマるとは思いませんでしたが、前進して嬉しいです。
汎用的なクラスでできること、できないことを把握しておいた方が良いことも分かりました。これで色々遊べるぞ・・。
ではまた。
- 投稿日:2021-01-23T17:32:14+09:00
spring-kafkaのconsumerでjson deserialize型変換エラーをスキップ
spring-kafkaでjsonの型変換などの処理続行不可能なメッセージをskipしたい場合がある。以下はその場合に使えるかもしれない設定例。
build.gradleplugins { id 'org.springframework.boot' version '2.4.2' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '15' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.kafka:spring-kafka' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.kafka:spring-kafka-test' implementation 'com.fasterxml.jackson.core:jackson-databind' } test { useJUnitPlatform() }まずプロパティでconsumerのdeserializerに
org.springframework.kafka.support.serializer.ErrorHandlingDeserializer
を設定し、そのdelete先をspring.kafka.properties.spring.deserializer.value.delegate.class
プロパティで指定する。これはjson変換クラスを指定する。こうするとjson変換エラーは単にスキップされる。application.propertiesspring.kafka.bootstrap-servers=localhost:19092 spring.kafka.consumer.group-id=myGroup spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.ErrorHandlingDeserializer spring.kafka.consumer.properties.spring.json.trusted.packages=* spring.kafka.properties.spring.deserializer.value.delegate.class=org.springframework.kafka.support.serializer.JsonDeserializer以下は動作検証用の適当なconsumer.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class KafkaSampleApplication { public static void main(String[] args) { SpringApplication.run(KafkaSampleApplication.class, args); } }import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class SampleData { String id; int value; }import org.springframework.kafka.annotation.KafkaListener; import org.springframework.stereotype.Component; @Component public class JsonConsumer { @KafkaListener(topics = "mytopic") public void processMessage(SampleData content) { System.out.println("content" + content); } }とはいえ、実際にはログ出したいとかエラー発生時に特殊な処理したいとか色々あるので、もうちょい細かい設定が色々必要になる。
- 投稿日:2021-01-23T15:24:19+09:00
プロエンジニアの教え方を未経験がメモっておく
この記事を書いた経緯
私は現在エンジニアスクールに通っています。
プロエンジニア講師に個別で補習をしてもらい、何週間も悩んだ機能がやっと実装できました。
動いたときの喜びが今でも忘れられません。
答えをすぐに教えるような教え方ではなかったため2時間かかりましたが、とても丁寧に実装まで導いてくださいました。(気が早いですが)自分がいつか誰かに指導する立場になったとき、この記事を見返そうと思い、投稿させていただきます。
事前準備
- コードをもらっておき、予め何が問題だったか予想しておく。
質問した人
- 自分のできる限りググりつくしている。
- 今回の質問は(Java)SpringSecurityについて。登録済のId,Passを入力してもloginできない状態だった。
講師の教え方
- 何がしたいのか、自分の言葉で全体のコード説明させる。
- 最後まで喋らせる。口を挟まない。
- 何が問題だと思うのか、自分の言葉で説明させる。
- 何でそう思うのか根拠を聞く。
- デバック等で確認したか聞く。
- 気になるポイントがあれば、どんな意図でそうしたのか聞く。
- 実際に動かしてみて、動かないことを一緒に見る。
- どこまで動いていると思うか聞く。
- デバックを一緒にしてみた上で、またどこまで動いていると思うかまた聞く。
- どこまで値が渡させているか場所が判明したら、解決方法を探る。
- 質問者が解決する上で分かりずらいものを付けていたら一旦外す。(今回だと独自のlogin画面。一旦設定をデフォルトにしておく。)
- 必要なところまで値が届くように、細かくデバック&実行していく。
- エラー、例外が出たら何だと思うか読ませる。
- 自分で調べさせて、予想を言わせてから解説する。
- 調べさせても予想が出ない場合は、ヒントを出してみる。
- あとは少しずつひも解いていく。
- 4で外したコードを戻して、実装してみる。
- 実装できたら「いえーい!」と一緒に喜んであげる。
- 最後に「こうしてもいいよ」「こうしたらもっといいかも」を伝える。他に理解できなかったことはないか聞く。
人に教える上で大切なこと
- 一緒に喜んであげる。
- 焦らせない、せかさない、ゆったりする。
- 「おしい」と言ってあげる。(全然見当違いじゃないと伝えると安心してもらえる)
- 自分の考えを言わせる、調べさせる、また考えを言わせる。
- 付属する知識も一緒に伝える。
最後に
今回私は悩んで調べまくってもできなかった機能が実装できて、本当に嬉しくて、またプログラミングの勉強を頑張ろうと思いました。
そう思ったのは、自分の力で実装までできるように丁寧に導いて下さったからだと思います。
実務で2時間丁寧に教えて頂けることはそうそうないと思います。
解決までのプロセスが学べるので、未経験、新人に一度だけでもいいので、こんな体験に付き合ってあげるのは良いのではないでしょうか。ちなみにSpringSecurityでログインできなかった原因
- 独自のuserを作っていなかった。(作る意味が分かっていなかった)
- 独自のlogin.htmlがタイムリーフになっていなかったので、入力した値を渡せていなかった。
最後まで読んでいただきまして、ありがとうございました。
- 投稿日:2021-01-23T15:24:19+09:00
プロエンジニアの教え方を未来の私の為にメモっておく
この記事を書いた経緯
私は現在エンジニアスクールに通っています。
プロエンジニア講師に個別で補習をしてもらい、何週間も悩んだ機能がやっと実装できました。
動いたときの喜びが今でも忘れられません。
答えをすぐに教えるような教え方ではなかったため2時間かかりましたが、とても丁寧に実装まで導いてくださいました。(気が早いですが)自分がいつか誰かに指導する立場になったとき、この記事を見返そうと思い、投稿させていただきます。
質問した人
- 自分のできる限りググりつくしている。
- 今回の質問は(Java)SpringSecurityについて。登録済のId,Passを入力してもloginできない状態だった。
事前準備
- コードをもらっておき、予め何が問題だったか予想しておく。
講師の教え方
1. 何がしたいのか、自分の言葉で全体のコード説明させる。
- 最後まで喋らせる。口を挟まない。
2. 何が問題だと思うのか、自分の言葉で説明させる。
- 何でそう思うのか根拠を聞く。
- デバック等で確認したか聞く。
- 気になるポイントがあれば、どんな意図でそうしたのか聞く。
3. 実際に動かしてみて、動かないことを一緒に見る。
- どこまで動いていると思うか聞く。
- デバックを一緒にしてみた上で、またどこまで動いていると思うかまた聞く。
4. どこまで値が渡させているか場所が判明したら、解決方法を探る。
- 質問者が解決する上で分かりずらいものを付けていたら一旦外す。(今回だと独自のlogin画面。一旦設定をデフォルトにしておく。)
- 必要なところまで値が届くように、細かくデバック&実行していく。
- エラー、例外が出たら何だと思うか読ませる。
- 自分で調べさせて、予想を言わせてから解説する。
- 調べさせても予想が出ない場合は、ヒントを出してみる。
5. あとは少しずつひも解いていく。
6. 4で外したコードを戻して、実装してみる。
7. 実装できたら「いえーい!」と一緒に喜んであげる。
8. 最後に「こうしてもいいよ」「こうしたらもっといいかも」を伝える。他に理解できなかったことはないか聞く。
まとめ
- 一緒に喜んであげる。
- 焦らせない、せかさない、ゆったりする。
- 「おしい」と言ってあげる。(全然見当違いじゃないと伝えると安心してもらえる)
- 自分の考えを言わせる、調べさせる、また考えを言わせる。
- 付属する知識も一緒に伝える。
最後に
今回私は悩んで調べまくってもできなかった機能が実装できて、本当に嬉しくて、またプログラミングの勉強を頑張ろうと思いました。
そう思ったのは、自分の力で実装までできるように丁寧に導いて下さったからだと思います。
実務で2時間丁寧に教えて頂けることはそうそうないと思います。
解決までのプロセスが学べるので、未経験、新人に一度だけでもいいので、こんな体験に付き合ってあげるのは良いのではないでしょうか。因みにSpringSecurityでログインできなかった原因
- 独自のuserを作っていなかった。(作る意味が分かっていなかった)
- 独自のlogin.htmlがタイムリーフになっていなかったので、入力した値を渡せていなかった。
最後まで読んでいただきまして、ありがとうございました。
- 投稿日:2021-01-23T12:46:53+09:00
STSで行うカバレッジ測定
- 投稿日:2021-01-23T10:52:47+09:00
Mapについて【Java】
目次
- 特徴
- 初期化① put(key, value)
- 初期化② put(key, value)
- 要素数を返す size()
- キーを指定して値を取得する get(key)
- KeyとValueをセットで取得する entrySet()
- Keyのみを取得する keySet()
- Valueのみを取得する values()
- keyを指定して削除する remove(key)
- マップの要素を全て削除する clear()
特徴
java.util.HashMap
● 順番が保証されない
● nullのキーを許容するjava.util.LinkedHashMap
● 追加した順java.util.TreeMap
● 昇順初期化① put(key, value)
Main.javapackage com.test; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> animalsMap = new HashMap<>(); animalsMap.put(1, "dog"); animalsMap.put(2, "cat"); animalsMap.put(3, "pig"); System.out.println(animalsMap); // {1=dog, 2=cat, 3=pig} } }初期化② put(key, value)
Main.javapackage com.test; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<Integer, String> animalsMap = new HashMap<Integer, String>() { { put(1, "dog"); put(2, "cat"); put(3, "pig"); } }; System.out.println(animalsMap); // {1=dog, 2=cat, 3=pig} } }要素数を返す size()
System.out.println(animalsMap.size()); // 3キーを指定して値を取得する get(key)
for (int i = 1; i <= animalsMap.size(); i++) { System.out.print(animalsMap.get(i) + ","); // dog,cat,pig, }KeyとValueをセットで取得する entrySet()
System.out.println(animalsMap.entrySet()); // [1=dog, 2=cat, 3=pig]Keyのみを取得する keySet()
System.out.println(animalsMap.keySet()); // [1, 2, 3]Valueのみを取得する values()
System.out.println(animalsMap.values()); // [dog, cat, pig]keyを指定して削除する remove(key)
animalsMap.remove(2); System.out.println(animalsMap); // {1=dog, 3=pig}マップの要素を全て削除する clear()
animalsMap.clear(); System.out.println(animalsMap); // {}参考