質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.65%

queryForListがうまくいきません。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 752

usako

score 25

前提・実現したいこと

Eclipse,Springを使ってJAVAの勉強をしている(超)初心者です。
元々、受講していた通信教育の課題がDBを使用しておらず、
内部にテーブルを保持している構造だったので、それを
MySQL,jDBCで外部化しようとしています。
一覧表示、更新、参照機能だけのシンプルな画面です。
まずは一覧機能を実装しようとしたところ、NULL例外で以下のメッセージが
発生しました。エラーの原因個所は特定できました。
List<Map<String, Object>> list1 = jdbcTemplate.queryForList("select * from unit02.addressbook");
ただ、この記述のどこに問題があってNULLが発生しているのかがわかりません。
DBにはデータも存在します。
どなたか、ご教授いただけないでしょうか。

発生している問題・エラーメッセージ

HTTPステータス 500 - Request processing failed; nested exception is java.lang.NullPointerException

type 例外レポート

メッセージ Request processing failed; nested exception is java.lang.NullPointerException

説明 The server encountered an internal error that prevented it from fulfilling this request.

The server encountered an internal error that prevented it from fulfilling this request.

該当のソースコード

package jp.practice.address;

import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**e n d*/

@Controller
@RequestMapping(value = "/book")
public class AddressBookController {
    private static final String INIT   = "init";
    private static final String REFER  = "refer";
    private static final String UPDATE = "update";
    private static final String LIST   = "list";
    private static final String INIMSG = "従業員番号を入力してください";
    private static final String REFMSG = "情報が取得できました";
    private static final String UPDMSG = "情報を更新してください";
    private static final String ERRMSG = "該当するデータはありません";
/**start ****/
//    @Autowired
//  private JdbcTemplate jdbcTemplate;
/**e n d*/
    @RequestMapping(value = "/start")
    public String init(AddressBookForm form, Model model) {
/**start ****/
//      List<Map<String, Object>> list = jdbcTemplate.queryForList("select * from unit02.addressbook");
//      for (int idx1 = 0; idx1 < 13; idx1++){
//          System.out.print(idx1);
//          model.addAttribute("id",      list.get(idx1).get("id") );
//          model.addAttribute("name",    list.get(idx1).get("name") );
//          model.addAttribute("tel",     list.get(idx1).get("tel") );
//          model.addAttribute("address", list.get(idx1).get("address") );
//      }
/**e n d*/
        model.addAttribute("message", INIMSG);
        return INIT;
    }

    @RequestMapping(params = "reference")
    public String refer(AddressBookForm form, Model model) {
        Employee employee = RecordManager.selectEmployee(form.getId());
        if (employee != null) {
            form.setName(employee.getName());
            form.setPhone(employee.getPhone());
            form.setAddress(employee.getAddress());
            model.addAttribute("message", REFMSG);
            return REFER;
        } else {
            model.addAttribute("message", ERRMSG);
            return INIT;
        }
    }

    @RequestMapping(params = "toInit")
    public String toInit(AddressBookForm form, Model model) {
        model.addAttribute("message", INIMSG);
        return INIT;
    }

    @RequestMapping(params = "update")
    public String update(AddressBookForm form, Model model) {
        Employee employee = RecordManager.selectEmployee(form.getId());
        if (employee != null) {
            form.setName(employee.getName());
            form.setPhone(employee.getPhone());
            form.setAddress(employee.getAddress());
            model.addAttribute("message", UPDMSG);
            return UPDATE;
        } else {
            model.addAttribute("message", ERRMSG);
            return INIT;
        }
    }

    @RequestMapping(params = "reflection")
    public String reflection(AddressBookForm form, Model model) {
        Employee employee = new Employee(form.getId(), form.getName(), form.getPhone(), form.getAddress());
        RecordManager.updateEmployee(employee);
        model.addAttribute("message", INIMSG);
        return INIT;
    }

    @RequestMapping(params = "list")
    public String list(Model model) {
        List<Map<String, Object>> employeeList = RecordManager.getEmployeeList();
        model.addAttribute("employeeList", employeeList);
        model.addAttribute("employeeCount", employeeList.size());
        return LIST;
    }
package jp.practice.address;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
/**e n d*/

public class RecordManager {
/**start ****/
    @Autowired
    private static JdbcTemplate jdbcTemplate;
/**e n d*/
//    /** 初期値データ */
    private static List<Employee> list = new ArrayList<>();
    static {
//        list.add(new Employee("200101", "佐藤一郎", "0569-000-1111", "尾張県愛知市舟船町596"));
//        list.dd(new Employee("200102", "鈴木次男", "0242-000-2222", "三河県三河市海池2727"));
//        list.add(new Employee("200103", "田中信三郎", "0722-000-3333", "和泉県泉市浜川55"));
//        list.add(new Employee("200104", "高橋四郎", "0729-000-4444", "摂津府兵庫市沼地11"));
//        list.add(new Employee("200105", "渡辺五郎", "0982-000-5555", "筑紫県筑後市泉町2"));
//        list.add(new Employee("200106", "伊藤六次", "0562-000-6666", "信濃県信州市泊町333"));
//        list.add(new Employee("200107", "山本七三", "086-000-7777", "土佐県四国市港町4"));
//        list.add(new Employee("200108", "中村八吉", "0489-000-8888", "薩摩県種島市潮見55"));
//        list.add(new Employee("200109", "小林九兵", "0827-000-9999", "周防県周防市川原66"));
//        list.add(new Employee("200110", "加藤十重", "048-000-1010", "武蔵県北むさし市河岸777"));
//        list.add(new Employee("200111", "ジャック", "0273-000-1111", "相模県相模市堤5"));
//        list.add(new Employee("200112", "山田十二", "075-000-1212", "駿河県南駿河市河口35"));
    }

    private RecordManager() {
    }

    /**
     * 指定したID のレコードを取得
     *
     * @param id
     *            従業員番号
     * @return Employee
     */

    public static Employee selectEmployee(String id) {
        int index = list.indexOf(new Employee(id, "", "", ""));
        if (index < 0) {
            return null;
        }
        return list.get(index);
    }
    /**
     * 指定した従業員情報を反映
     *
     * @param emp
     *            従業員情報
     */
    public static void updateEmployee(Employee emp) {
        int index = list.indexOf(emp);
        list.set(index, emp);
    }
/**start ****/
    public static List<Map<String, Object>> getEmployeeList() {
    List<Map<String, Object>> list1 = jdbcTemplate.queryForList("select * from unit02.addressbook");

    return list1;
/**e n d*/
    }
<%@ page session="false" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.time.LocalDate"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css"
    href="/address/resources/css/common.css" />
<title>住所録(初期画面)</title>
</head>
<body>
    <form:form modelAttribute="addressBookForm" action="/address/book">
        <div class="header">
            <span class="titleName">住所録</span>
            <div class="date"><%=LocalDate.now()%></div>
        </div>
        <div class="main">
            <div class="message">
                <c:out value="${message}" />
            </div>
            <div>
                <span class="itemName">従業員番号:</span>
                <form:input path="id" size="31" />
            </div>
        </div>
        <div class="footer">
            <div>
                <input type="submit" name="reference" value="参照" />
            </div>
            <div>
                <input type="submit" name="update" value="更新" />
            </div>
            <div>
                <input type="submit" name="list" value="一覧" />
            </div>
        </div>
    <!-- start -->
     <!-- <p>  DB's id: ${id} name: ${name} tel: ${tel} address: ${address} . </p> -->
    <!-- end -->
    </form:form>
</body>
</html>
<%@ page session="false" language="java"
    contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.time.LocalDate"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css"
    href="/address/resources/css/common.css" />
<title>住所録(一覧画面)</title>
</head>
<body>
    <form:form modelAttribute="addressBookForm" action="/address/book">
        <div class="header">
            <span class="titleName">住所録</span>
            <div class="date"><%=LocalDate.now()%></div>
        </div>
        <div>
            社員数 :
            <c:out value="${employeeCount}"></c:out></div>
        <table>
            <tr>
                <th>従業員番号</th>
                <th>名前</th>
                <th>電話番号</th>
                <th>住所</th>
            </tr>
            <c:forEach items="${employeeList}" var="employee" varStatus="status">
                <c:choose>
                    <c:when test="${status.count % 2 == 0}">
                        <tr class="even">
                            <td>${employee.id}</td>
                            <td>${employee.name}</td>
                            <td>${employee.phone}</td>
                            <td>${employee.address}</td>
                        </tr>
                    </c:when>
                    <c:otherwise>
                        <tr>
                            <td>${employee.id}</td>
                            <td>${employee.name}</td>
                            <td>${employee.phone}</td>
                            <td>${employee.address}</td>
                        </tr>
                    </c:otherwise>
                </c:choose>
            </c:forEach>
        </table>
        <div class="listFooter">
            <input type="submit" name="toInit" value="戻る" />
        </div>
    </form:form>
</body>
</html>

試したこと

AddressBookController.javaの@Controller直下だと、エラーにならずDBの内容を表示できます。
(現在はコメント化しています)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • rubytomato

    2019/05/28 22:23

    @Autowired
    private static JdbcTemplate jdbcTemplate;
    の箇所でJdbcTemplateのインスタンスがセットされていないのではないでしょうか?

    getEmployeeListメソッドで、jdbcTemplate.queryForListを使う直前にjdbcTemplateがnullかどうか確認して結果をお知らせください。
    たとえば
    if (jdbcTemplate == null) {
    System.out.println("jdbcTemplate is null");
    }
    など。

    キャンセル

  • usako

    2019/05/29 08:59 編集

    ご教授いただいたように、if文をいれたところ、"jdbcTemplate is null"と表示されました。
    本来であれば何が入っているはずなのでしょうか。
    また、何が原因でnullが入ってしまうのか、ご教授いただけないでしょうか。

    キャンセル

回答 3

checkベストアンサー

+1

ご確認ありがとうございます。

if文をいれたところ、"jdbcTemplate is null"と表示されました。
本来であれば何が入っているはずなのでしょうか。
また、何が原因でnullが入ってしまうのか、ご教授いただけないでしょうか。

本来であればJdbcTemplateクラスのインスタンスが注入されているはずですが、nullになってしまう原因は下記のようにjdbcTemplateフィールドがstaticだからのようです。

@Autowired
private static JdbcTemplate jdbcTemplate;

過去にも同じような質問がありましたのでご確認ください。

リンク先のページではstaticフィールドにautowiredする方法が紹介されていますが、staticを使わなくても解決できる方法もありますので、ここではその方法を記述します。なお、staticを使うか使わないかは設計の問題になると思いますので、どちらが正しい/間違っているという風には決められません(と思っていますが、私自身はなるべくstaticフィールドにならないようにしています)。

それでは下記にstaticを使わない方法の改修について説明します。改修点は大きく分けて2つあります。
1つ目がRecordManagerクラスの改修です。改修箇所にコメントを付けていますのでご確認ください。

// (1) Componentアノテーションを追加、これでSpring DIコンテナの管理下に入ります。
@Component
public class RecordManager {

  // (2) Autowiredアノテーションとstaticを削除しました。
  private JdbcTemplate jdbcTemplate;

  // (3) コンストラクタインジェクションという方法でJdbcTemplateを注入(autowired)します。
  public RecordManager(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }

  // (4) staticを削除しました。
  public List<Map<String, Object>> getEmployeeList() {
    List<Map<String, Object>> list1 = jdbcTemplate.queryForList("select * from unit02.addressbook");
    return list1;
  }

}

2つ目がRecordManagerクラスのインスタンスを利用するAddressBookControllerクラスの改修です。

@Controller
@RequestMapping(value = "/book")
public class AddressBookController {

  // (1) JdbcTemplateの代わりにRecordManagerを使用します。
  private RecordManager recordManager;

  // (2) コンストラクタインジェクションです。
  // RecordManagerはSpringの管理下にあるので注入してもらえます。
  public AddressBookController(RecordManager recordManager) {
    this.recordManager = recordManager;
  }

  @RequestMapping(value = "/start")
  public String init(AddressBookForm form, Model model) {
    // (3) RecordManagerのインスタンスを使ってDBアクセスを行います。
    List<Map<String, Object>> list = recordManager.getEmployeeList();
    for (int idx1 = 0; idx1 < 13; idx1++){
          System.out.print(idx1);
    }
    model.addAttribute("message", INIMSG);
    return INIT;
  }

}

なお、コンストラクタインジェクションの部分ですが、従来通りフィールドにAutowiredアノテーションを付けて注入するという方法でも問題ありません。

@Autowired
private RecordManager recordManager;

上記の内容で動作すると思うのですが、実際に環境を構築して動かした訳ではないので保証はできません。このコードを参考にして動かしたときに別の新しいエラーがでましたら、質問内容に追記ください。

2019/06/01追記

①RecordManage.java(1)において、@Componentを記載することnewせずともRecordManageというインスタンスが生成されるという理解で合っておりますでしょうか。

そのご理解で問題ないと思いますが、すこし補足しますとRecordManagerのインスタンスを使うには、誰かがnewしなければなりません。
その誰かを、Componentアノテーションを付加することでSpringに任せています。

Springは、アプリケーション起動時にComponentアノテーションが付加されたクラスを探し出しインスタンスを生成し管理します。
なお、Componentアノテーション以外にも下記のアノテーションが付加されたクラスが同様にインスタンス生成されます。
(他にもありますが、ここでは省略します。)

@Controller
@Service
@Repository

Controllerアノテーションは、コントローラクラスに付加されているのをご覧になっていると思いますが、コントローラクラスのインスタンス生成もSpringが行っています。

@Controller
@RequestMapping(value = "/book")
public class AddressBookController {

//...省略...

}

Springは自分が生成したインスタンスを管理していて、そのインスタンスが必要な場面がくるとそこへ注入(Injection)します。
必要な場所とは、ご存知の通りAutowiredアノテーションが付いているフィールドやメソッドなどです。

Springがサポートする注入の方法は3つあります。

  1. フィールドインジェクション

フィールドインジェクションを呼ばれる注入方法です。記述するコード量が少なくて済むのでこの書き方が多いように思います。

@Autowired
private JdbcTemplate jdbcTemplate;
  1. セッターインジェクション

クラスを作成したときにフィールドにゲッター(getXXXX)/セッター(setXXXX)メソッドを書いたことがあるかと思いますが、このセッターメソッドを使う方法です。
Autowiredはセッターメソッドに付けます。
なお、私の経験上ですがセッターインジェクションが使われているコードはあまり見たことがありません。

private JdbcTemplate jdbcTemplate;

@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
  this.jdbcTemplate = jdbcTemplate
}
  1. コンストラクタインジェクション

名前の通りクラスのコンストラクタを使った注入方法です。
コンストラクタが1つだけの場合はAutowiredアノテーションを省略することができます。が、書いてもエラーではありません。

private JdbcTemplate jdbcTemplate;

// @Autowired 付けなくてもよい
public RecordManager(JdbcTemplate jdbcTemplate) {
  this.jdbcTemplate = jdbcTemplate;
}

上記のとおり、Component(やController,Service, Repository)とAutowiredアノテーションを利用することで、インスタンスの生成と注入を任せることができますが、1点気を付けなければならない点があります。
それは、Springは自身が生成したインスタンスに対してのみインスタンスの注入を行うということです。
このご質問のRecordManagerクラスのJdbcTemplateフィールドがnullになってしまう理由は、RecordManagerのインスタンス生成をSpringが担当していなかったからということになります。

ざっくりとした説明になりましたが、この機能はSpring Frameworkの重要な機能の1つでDI (Dependency Injection) / "依存性の注入"と呼ばれています。ネットで検索すれば詳しい記事がたくさんみつかるとおもいますので探して読んでみてください。
あるいは書籍で知識を仕入れるのも最初のころはいいかもしれません。

②RecordManage.java(3)において、コンストラクタインジェクションにする意図。jdbcTemplateを動的に注入して・・・ということだと考えていますが、コンストラクタインジェクションを行わない場合、どのようなことが起こりえるのでしょうか。(テストのしやすさとかの問題だけ?)

こちらの意味は、コンストラクタインジェクションとフィールドインジェクションの違い(メリット/デメリット)は何か?という風に解釈しましたが、その前提で進めます。

上記で触れていますが、注入(Injection)方法には3つあります。これらは場面によって使い分けるものと私自身は考えていますが、Springの開発チームは
”つねにコンストラクタインジェクションを使う”ことをお勧めする(Recommend)というメッセージを出しています。

このようなメッセージを出す背景には、コンストラクタインジェクションのメリットが大きいからだと思いますが、テストコードが書きやすくなるのもその1つだと思います。
他にもありますが、私自身上手くご説明できないので、"spring コンストラクタインジェクション フィールドインジェクション"などのキーワードで探してみてください。すぐに詳しく解説してくれているページがすぐに見つかると思います。

もし探したページをいくつか読んでも腑に落ちないということであれば、Spring Frameworkはかなり大きなプロジェクトなので前提となる知識が不足しているのかもしれません。
そんなときは先にJavaでコードを書く時のベストプラクティスを習得するという方向に向かうのもいいと思います。(並行して簡単なSpringを使ったアプリケーションを書き続けるのもなお効果があるとおもいます)

③AddressBookController.java(2)において、コンストラクタを追加していますがこれはRecordManage.java(3)で作成したコンストラクタを受け取るためのものという理解で合っておりますでしょうか。

RecordManage.java(3)で作成したコンストラクタを受け取るためのもの

ここの”コンストラクタを受け取る”とはどういう意味なのかちょっと分かりませんが、AddressBookControllerクラスにコンストラクタを追加したのは、SpringにRecordManagerのインスタンスを注入してもらうためです。(コンストラクタインジェクションを使って)
上記で触れていますが、RecordManagerクラスにComponentアノテーションを付加したことによりSpringがインスタンスを生成、管理してくれています。

2019/06/04 追記

質問の意図としては、jdbcTemplateがRecordManagerクラスに注入され、更にrecordManagerがAddressBookControllerクラスに注入されるという具合に値(オブジェクト?)が引き継がれていくのでしょうか、ということでした。

"引き継がれていくのでしょうか"という表現は多少違和感(聞きなれない表現なので)がありますが、概ねそのような理解で良いかと思います。

コンストラクラインジェクションと普通の引数ありのコンストラクタの見極めはどのように行うのでしょうか。(記述方法としては同じになると思うのですが・・・)
デフォルトコンストラクタが見当たらないのもなぜなのかわかりません。これもSpringが勝手にやってくれているということなのでしょうか。

クラスにコンストラクタを1つも定義しなかった場合、暗黙的に引数無し、処理なしのコンストラクタが定義されます。これがいわゆるデフォルトコンストラクタと呼ばれるものです。
この動きはJavaの言語仕様でSpringは関係ありません。

以下の1)と2)は同じコードと言えます。コンストラクタを1つも定義しなかった場合、1)には2)のような引数無し、処理なしのコンストラクタが(ソースコード上は見えませんが)追加されます。

1)

@Controller
public class AddressBookController {

  // コンストラクタを明示的に定義しなかった場合、ソースコード上には見えないが
  // 引数無し、処理なしのデフォルトコンストラクタが暗黙的に定義される

}

2)

@Controller
public class AddressBookController {

  // デフォルトコンストラクタ
  public AddressBookController() {
  }

}

ただし、3)のようにクラスに明示的にコンストラクタを追加すると、引数無し、処理なしのデフォルトコンストラクタは追加されません。これもJavaの言語仕様です。
コンストラクタが1つだけの場合、Springはそのコンストラクタを使ってコントローラクラスのインスタンスを生成します。

3)

@Controller
public class AddressBookController {

  private RecordManager recordManager;

  // RecordManagerがSpringの管理下にある場合、管理しているインスタンスを引数に渡す
  public AddressBookController(RecordManager recordManager) {
    this.recordManager = recordManager;
  }

}

次に明示的にデフォルトコンストラクタを定義し、コンストラクタを2つにした場合どうなるかというと
Springはデフォルトコンストラクタを使用してコントローラクラスのインスタンスを生成するので、4)の例で言えばrecordManagerフィールドはnullになります。

4)

@Controller
public class AddressBookController {

  private RecordManager recordManager;

  public AddressBookController() {
  }

  public AddressBookController(RecordManager recordManager) {
    this.recordManager = recordManager;
  }

}

引数有りのコンストラクタを使ってほしい場合は以下のようにコンストラクタにAutowiredアノテーションを付加します。
SpringはAutowiredアノテーションが付いたコンストラクタを使ってコントローラクラスのインスタンスを生成、その際にRecordManagerのインスタンスを引数に与えます。

5)

@Controller
public class AddressBookController {

  private RecordManager recordManager;

  public AddressBookController() {
  }

  @Autowired
  public AddressBookController(RecordManager recordManager) {
    this.recordManager = recordManager;
  }

}

引数の数が違うコンストラクタを定義し、そこにもAutowiredアノテーションを付加した場合どうなるかですが
コンストラクタにつけられるAutowiredアノテーションは1つまでなのでエラーになります。

6)

@Controller
public class AddressBookController {

  private RecordManager recordManager;

  public AddressBookController() {
  }

  // これはエラー
  @Autowired
  public AddressBookController(RecordManager recordManager) {
    this.recordManager = recordManager;
  }

  // これもエラー
  @Autowired
  public AddressBookController(RecordManager recordManager, String dummyParam) {
    this.recordManager = recordManager;
  }

}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/30 10:58

    rubytomato様、丁寧な回答ありがとうございます!この通りにプログラムを修正したら、正常に動作するようになりました。ただ、修正の意図がわからない個所があります。(主にコンストラクタインジェクション)ネットや本でも調べてみたのですが、いまいち理解が及びません。お時間のある時で結構ですので、ご教授いただけないでしょうか。
    ①RecordManage.java(1)において、@Componentを記載することnewせずともRecordManageというインスタンスが生成されるという理解で合っておりますでしょうか。
    ②RecordManage.java(3)において、コンストラクタインジェクションにする意図。jdbcTemplateを動的に注入して・・・ということだと考えていますが、コンストラクタインジェクションを行わない場合、どのようなことが起こりえるのでしょうか。(テストのしやすさとかの問題だけ?)
    ③AddressBookController.java(2)において、コンストラクタを追加していますがこれはRecordManage.java(3)で作成したコンストラクタを受け取るためのものという理解で合っておりますでしょうか。

    キャンセル

  • 2019/06/04 10:23 編集

    rubytomato様、丁寧な説明、本当に感謝です。
    回答を咀嚼するのに時間がかかりお礼が遅くなりました。

    > ③AddressBookController.java(2)において、コンストラクタを追加して
    >いますがこれはRecordManage.java(3)で作成したコンストラクタを受け
    >取るためのものという理解で合っておりますでしょうか。

    とんちんかんな質問で失礼しました(汗)質問の意図としては、jdbcTemplateがRecordManagerクラスに注入され、更にrecordManagerがAddressBookControllerクラスに注入されるという具合に値(オブジェクト?)が引き継がれていくのでしょうか、ということでした。
    (この質問の仕方も???だったら申訳ないです)

    あと、基本的なことかもしれませんが、コンストラクラインジェクションと普通の引数ありのコンストラクタの見極めはどのように行うのでしょうか。(記述方法としては同じになると思うのですが・・・)
    またこの場合、デフォルトコンストラクタが見当たらないのもなぜなのかわかりません。これもSpringが勝手にやってくれているということなのでしょうか。

    キャンセル

  • 2019/06/05 13:51 編集

    rubytomato様、何度も返信してくださってありがとうございます。
    お陰でコンストラクタインジェクションのことが少し理解できたような気がします。(自身で一から書けるようになるのはまだ先のことかもしれませんが・・・)
    まずはソースを読めるように精進したいと思っております。
    本当にありがとうございました。
    ↓とんちんかんな質問して申訳ありませんでした・・・

    >デフォルトコンストラクタが見当たらないのもなぜなのかわかりません。
    >これもSpringが勝手にやってくれているということなのでしょうか。

    キャンセル

0

https://teratail.com/questions/68121

上記が参考になると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/29 13:15 編集

    アドバイスありがとうございます。
    この記事も調べていて同じようにしてみたつもりなのですが、エラーが解除されませんでした。
    具体的には、AddressBookController.javaとRecordManager.javaを@Serviceを使って以下のように修正してみましたが、やはりNullPointerExceptionが起きてしまいます。記述が悪いのでしょうか。
    ↓-----------------------------------------------
    package jp.practice.address;

    import java.util.List;
    import java.util.Map;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    @Controller
    @RequestMapping(value = "/book")
    public class AddressBookController {
    private static final String INIT = "init";
    private static final String REFER = "refer";
    private static final String UPDATE = "update";
    private static final String LIST = "list";
    private static final String INIMSG = "従業員番号を入力してください";
    private static final String REFMSG = "情報が取得できました";
    private static final String UPDMSG = "情報を更新してください";
    private static final String ERRMSG = "該当するデータはありません";

    @RequestMapping(value = "/start")
    public String init(AddressBookForm form, Model model) {
    model.addAttribute("message", INIMSG);
    return INIT;
    }
    -----割愛-----
    @RequestMapping(params = "list")
    public String list(Model model) {
    //*start ***
    List<Map<String, Object>> employeeList = service.getEmployeeList();
    // List<Map<String, Object>> employeeList = RecordManager.getEmployeeList();
    //*e n d
    model.addAttribute("employeeList", employeeList);
    model.addAttribute("employeeCount", employeeList.size());
    return LIST;
    }
    //*start ***
    @Autowired
    RecordManager service;
    //*e n d
    }

    ↓ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
    package jp.practice.address;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Service;
    /**start ****/
    @Service
    /**e n d*/
    public class RecordManager {
    @Autowired
    private static JdbcTemplate jdbcTemplate;
    -----割愛-------
    public static List<Map<String, Object>> getEmployeeList() {
    if (jdbcTemplate == null) {
    System.out.println("jdbcTemplate is null");
    }
    List<Map<String, Object>> list1 = jdbcTemplate.queryForList("select * from unit02.addressbook order by id");
    return list1;
    }

    キャンセル

0

上記の回答ですが、自分は、@Controller 以外から
呼び出すには、@Service を経由する必要があると理解しました。

提示されたソースでは、@Service の文字は存在していないので、
サービス経由で使用していないのではと思いました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/29 13:59 編集

    アドバイスありがとうございます。kamimaze.cappa様のご指摘もあり、
    AddressBookController.javaとRecordManager.javaを@Serviceを使って以下のように修正してみましたが、やはりNullPointerExceptionが起きてしまいます。記述が悪いのでしょうか。
    ↓-----------------------------------------------
    package jp.practice.address;

    import java.util.List;
    import java.util.Map;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    @Controller
    @RequestMapping(value = "/book")
    public class AddressBookController {
    private static final String INIT = "init";
    private static final String REFER = "refer";
    private static final String UPDATE = "update";
    private static final String LIST = "list";
    private static final String INIMSG = "従業員番号を入力してください";
    private static final String REFMSG = "情報が取得できました";
    private static final String UPDMSG = "情報を更新してください";
    private static final String ERRMSG = "該当するデータはありません";

    @RequestMapping(value = "/start")
    public String init(AddressBookForm form, Model model) {
    model.addAttribute("message", INIMSG);
    return INIT;
    }
    -----割愛-----
    @RequestMapping(params = "list")
    public String list(Model model) {
    //*start ***
    List<Map<String, Object>> employeeList = service.getEmployeeList();
    // List<Map<String, Object>> employeeList = RecordManager.getEmployeeList();
    //*e n d
    model.addAttribute("employeeList", employeeList);
    model.addAttribute("employeeCount", employeeList.size());
    return LIST;
    }
    //*start ***
    @Autowired
    RecordManager service;
    //*e n d
    }

    ↓ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
    package jp.practice.address;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Service;
    /**start ****/
    @Service
    /**e n d*/
    public class RecordManager {
    @Autowired
    private static JdbcTemplate jdbcTemplate;
    -----割愛-------
    public static List<Map<String, Object>> getEmployeeList() {
    if (jdbcTemplate == null) {
    System.out.println("jdbcTemplate is null");
    }
    List<Map<String, Object>> list1 = jdbcTemplate.queryForList("select * from unit02.addressbook order by id");
    return list1;
    }

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる