20210123のJavaに関する記事は12件です。

MyBatis+SpringBootでCRUDアプリを作る ※余計なものはナシ※ 2/2

前回の記事の続きです。
次はクラスを作っていきます。
前回までの分はこちら
https://qiita.com/sumichan/items/bdc2a0e909416ae55162

3-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の流れが掴めると思います。
応用して色々試してみてください!

最後まで読んでいただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MyBatis+SpringBootでCRUDアプリを作る ※余計なものはナシ※ 1/2

MyBatisを使ったToDoリストを作成します。
目標物はこれ↓
ezgif.com-gif-maker.gif

  • やることを登録(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.22

MyBatisとは

簡単に言えば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
qiita.png

htmlのhttpメソッドでdeleteとputを使っているので必要になります。
getとpostで書けば不要となります。
その場合はControllerのアノテーションも@GetMappingに揃えてください。
↓こちらを参考にさせていただきました。
https://qiita.com/kazuhiro1982/items/b8b9965fddf9c5507517

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MyBatis+SpringBootでCRUDアプリを作る ※一番単純※ 1/2

MyBatisを使ったToDoリストを作成します。
目標物はこれ↓
ezgif.com-gif-maker.gif

  • やることを登録(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.22

MyBatisとは

簡単に言えば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
qiita.png

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

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】java.lang.NullPointerExceptionを避ける方法

プログラミング勉強日記

2021年1月23日
Javaでコードを書いているときに、よく出てくるNullPointerExcptionの意味と、NullPointerExcptionにならないようにする方法をまとめる。

java.lang.NullPointerException
Request processing failed; nested exception is java.lang.NullPointerException

NullPointerExceptionとは

 参照型の変数の値に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();
    }
}

 しかし、コード量が増えるほど判定は大変になるので対策方法を示す。

  1. null以外の値で変数を初期化する
  2. 配列は空で初期化する
  3. 戻り値にnullを返さない

 この3つを意識することで、NullPointerExcptionあ発生しにくくなると思う。

参考文献

【Java】java.lang.NullPointerException

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeのターミナルから実行

はじめに

VSCodeのTerminalからコマンドラインでコンパイル&実行する方法についての備忘。
文字コードの設定オプションが必要。

Terminal表示

[View]タブから[Terminal]を押下
image1.png

Terminalが表示されました。
image1.png

コンパイル/実行

ディレクトリ移動

dir
cd src

image3.png

コンパイル/実行

日本語が文字化けしてしまう。

javac HelloWorld.java
java HelloWorld

image4.png

コンパイル/実行(エンコードUTF-8指定)

エンコードの指定をしてコンパイル/実行すると正しく表示された。

javac HelloWorld.java -encoding UTF-8
java -Dfile.encoding=UTF-8 HelloWorld

image5.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeのターミナルからコンパイル/実行

はじめに

VSCodeのTerminalからコマンドラインでコンパイル&実行する方法についての備忘。
日本語でコーディングや出力をする場合文字コードのコンパイルオプションが必要。
毎回オプション指定するのがめんどくさい場合は、設定ファイルの編集方法参照。

Terminal表示

[View]タブから[Terminal]を押下
image1.png

Terminalが表示されました。
image1.png

コンパイル/実行

ディレクトリ移動

dir
cd src

image3.png

コンパイル/実行

日本語が文字化けしてしまう。

javac HelloWorld.java
java HelloWorld

image4.png

コマンドオプション

コンパイル/実行(エンコードUTF-8指定)

エンコードの指定をしてコンパイル/実行すると正しく表示された。

javac HelloWorld.java -encoding UTF-8
java -Dfile.encoding=UTF-8 HelloWorld

image5.png

設定ファイル変更

設定ファイルの変更で対応する場合は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"
    ]

image3.png

おまけ settings.jsonの開き方

左下の[設定]から[Settings]を押下

image1.png

コマンドパレットで"settings.json"を入力し、[Edit in settings.json]を押下
image2.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】UTF-8同士のファイルの入出力をおこなう(文字化けさせない)

こんばんは。関東では今日夜から雪が降るそうです。
風邪をひかないようにあったかくして休みましょう。

今日は文字化けの話です。

1.読んでいただきたい方

・Java初心者の方
・出力ファイルの文字化けに苦しんでいる方
・特にデフォルトエンコーディングがMS932の方は、僕の環境と同じなので共感できるかも知れません(調べ方は下記参照)

2.はじめに

前回の記事でも書いたのですが、僕はもともとvbscriptでファイルの読み書きをしていましたが、windows10から文字コードがUTF-8になり、文法も変わったのをきっかけにJavaで入出力のプログラムを作る事にしました。

どっこいこれが大苦戦・・。
自分なりにポイントをまとめておこうと思います。

3.ポイント

・自分の開発環境のデフォルトエンコーディングを理解する
・入力・出力の文字コードをきちんと指定する

4.本日の作品

このようなプログラムを作成しました(utftest.java)。
デフォルトエンコーディングがMS932の方も、
以下のプログラムを実行すると、UTF-8→UTF-8のファイル入出力ができます!!

javautftest.java
import 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.感想

正直、ここまでファイル入出力でハマるとは思いませんでしたが、前進して嬉しいです。
汎用的なクラスでできること、できないことを把握しておいた方が良いことも分かりました。

これで色々遊べるぞ・・。

ではまた。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

spring-kafkaのconsumerでjson deserialize型変換エラーをスキップ

spring-kafkaでjsonの型変換などの処理続行不可能なメッセージをskipしたい場合がある。以下はその場合に使えるかもしれない設定例。

build.gradle
plugins {
  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.properties
spring.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);
    }
}

とはいえ、実際にはログ出したいとかエラー発生時に特殊な処理したいとか色々あるので、もうちょい細かい設定が色々必要になる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロエンジニアの教え方を未経験がメモっておく

この記事を書いた経緯

私は現在エンジニアスクールに通っています。
プロエンジニア講師に個別で補習をしてもらい、何週間も悩んだ機能がやっと実装できました。
動いたときの喜びが今でも忘れられません。
答えをすぐに教えるような教え方ではなかったため2時間かかりましたが、とても丁寧に実装まで導いてくださいました。

(気が早いですが)自分がいつか誰かに指導する立場になったとき、この記事を見返そうと思い、投稿させていただきます。

事前準備

  • コードをもらっておき、予め何が問題だったか予想しておく。

質問した人

  • 自分のできる限りググりつくしている。
  • 今回の質問は(Java)SpringSecurityについて。登録済のId,Passを入力してもloginできない状態だった。

講師の教え方

  1. 何がしたいのか、自分の言葉で全体のコード説明させる。
    • 最後まで喋らせる。口を挟まない。
  2. 何が問題だと思うのか、自分の言葉で説明させる。
    • 何でそう思うのか根拠を聞く。
    • デバック等で確認したか聞く。
    • 気になるポイントがあれば、どんな意図でそうしたのか聞く。
  3. 実際に動かしてみて、動かないことを一緒に見る。
    • どこまで動いていると思うか聞く。
    • デバックを一緒にしてみた上で、またどこまで動いていると思うかまた聞く。
  4. どこまで値が渡させているか場所が判明したら、解決方法を探る。
    • 質問者が解決する上で分かりずらいものを付けていたら一旦外す。(今回だと独自のlogin画面。一旦設定をデフォルトにしておく。)
    • 必要なところまで値が届くように、細かくデバック&実行していく。
    • エラー、例外が出たら何だと思うか読ませる。
    • 自分で調べさせて、予想を言わせてから解説する。
      • 調べさせても予想が出ない場合は、ヒントを出してみる。
  5. あとは少しずつひも解いていく。
  6. 4で外したコードを戻して、実装してみる。
  7. 実装できたら「いえーい!」と一緒に喜んであげる。
  8. 最後に「こうしてもいいよ」「こうしたらもっといいかも」を伝える。他に理解できなかったことはないか聞く。

人に教える上で大切なこと

  • 一緒に喜んであげる。
  • 焦らせない、せかさない、ゆったりする。
  • 「おしい」と言ってあげる。(全然見当違いじゃないと伝えると安心してもらえる)
  • 自分の考えを言わせる、調べさせる、また考えを言わせる。
  • 付属する知識も一緒に伝える。

最後に

今回私は悩んで調べまくってもできなかった機能が実装できて、本当に嬉しくて、またプログラミングの勉強を頑張ろうと思いました。
そう思ったのは、自分の力で実装までできるように丁寧に導いて下さったからだと思います。
実務で2時間丁寧に教えて頂けることはそうそうないと思います。
解決までのプロセスが学べるので、未経験、新人に一度だけでもいいので、こんな体験に付き合ってあげるのは良いのではないでしょうか。

ちなみにSpringSecurityでログインできなかった原因

  • 独自のuserを作っていなかった。(作る意味が分かっていなかった)
  • 独自のlogin.htmlがタイムリーフになっていなかったので、入力した値を渡せていなかった。

  
最後まで読んでいただきまして、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プロエンジニアの教え方を未来の私の為にメモっておく

この記事を書いた経緯

私は現在エンジニアスクールに通っています。
プロエンジニア講師に個別で補習をしてもらい、何週間も悩んだ機能がやっと実装できました。
動いたときの喜びが今でも忘れられません。
答えをすぐに教えるような教え方ではなかったため2時間かかりましたが、とても丁寧に実装まで導いてくださいました。

(気が早いですが)自分がいつか誰かに指導する立場になったとき、この記事を見返そうと思い、投稿させていただきます。

質問した人

  • 自分のできる限りググりつくしている。
  • 今回の質問は(Java)SpringSecurityについて。登録済のId,Passを入力してもloginできない状態だった。

事前準備

  • コードをもらっておき、予め何が問題だったか予想しておく。

講師の教え方

1. 何がしたいのか、自分の言葉で全体のコード説明させる。
  • 最後まで喋らせる。口を挟まない。
2. 何が問題だと思うのか、自分の言葉で説明させる。
  • 何でそう思うのか根拠を聞く。
  • デバック等で確認したか聞く。
  • 気になるポイントがあれば、どんな意図でそうしたのか聞く。
3. 実際に動かしてみて、動かないことを一緒に見る。
  • どこまで動いていると思うか聞く。
  • デバックを一緒にしてみた上で、またどこまで動いていると思うかまた聞く。
4. どこまで値が渡させているか場所が判明したら、解決方法を探る。
  • 質問者が解決する上で分かりずらいものを付けていたら一旦外す。(今回だと独自のlogin画面。一旦設定をデフォルトにしておく。)
  • 必要なところまで値が届くように、細かくデバック&実行していく。
  • エラー、例外が出たら何だと思うか読ませる。
  • 自分で調べさせて、予想を言わせてから解説する。
    • 調べさせても予想が出ない場合は、ヒントを出してみる。
5. あとは少しずつひも解いていく。
6. 4で外したコードを戻して、実装してみる。
7. 実装できたら「いえーい!」と一緒に喜んであげる。
8. 最後に「こうしてもいいよ」「こうしたらもっといいかも」を伝える。他に理解できなかったことはないか聞く。

まとめ

  • 一緒に喜んであげる。
  • 焦らせない、せかさない、ゆったりする。
  • 「おしい」と言ってあげる。(全然見当違いじゃないと伝えると安心してもらえる)
  • 自分の考えを言わせる、調べさせる、また考えを言わせる。
  • 付属する知識も一緒に伝える。

最後に

今回私は悩んで調べまくってもできなかった機能が実装できて、本当に嬉しくて、またプログラミングの勉強を頑張ろうと思いました。
そう思ったのは、自分の力で実装までできるように丁寧に導いて下さったからだと思います。
実務で2時間丁寧に教えて頂けることはそうそうないと思います。
解決までのプロセスが学べるので、未経験、新人に一度だけでもいいので、こんな体験に付き合ってあげるのは良いのではないでしょうか。

因みにSpringSecurityでログインできなかった原因

  • 独自のuserを作っていなかった。(作る意味が分かっていなかった)
  • 独自のlogin.htmlがタイムリーフになっていなかったので、入力した値を渡せていなかった。

  
最後まで読んでいただきまして、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

STSで行うカバレッジ測定

  1. Eclipseマーケットプレイスで「EclEmma Java Code Coverage」をインストールし、再起動する

スクリーンショット 2021-01-23 12.39.00.png

スクリーンショット 2021-01-23 12.38.42.png

2. 「src/test.java」を右クリックで画像のようにJUnitを選択して実行
スクリーンショット 2021-01-23 12.40.36.png

3. 以下の画面のように、ソースコードに背景色がつく。
  緑:OK 黄色:分岐の片方しか通っていない 赤:通っていない。これを全て緑にすると、「カバレッジ100%」
スクリーンショット 2021-01-23 12.43.06.png
全体のカバレッジのパーセントは「カバレッジ」のビューで確認できる
スクリーンショット 2021-01-23 12.45.39.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Mapについて【Java】

目次

特徴

java.util.HashMap
  ● 順番が保証されない
  ● nullのキーを許容する

java.util.LinkedHashMap
  ● 追加した順

java.util.TreeMap
  ● 昇順

初期化① put(key, value)

Main.java
package 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.java
package 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); // {}

参考

https://style.potepan.com/articles/16280.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む