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

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

新規登録して質問してみよう
ただいま回答率
85.49%
Hibernate

HibernateとはJava言語のobject-relational mapping (ORM)ライブラリであり、Object/Relational Mappingよりはるか多くの方法でアプリケーションをPOJOで機能付けることができます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

1回答

1897閲覧

CreateNativequeryのエラー回避のやり方について

Pocchi

総合スコア3

Hibernate

HibernateとはJava言語のobject-relational mapping (ORM)ライブラリであり、Object/Relational Mappingよりはるか多くの方法でアプリケーションをPOJOで機能付けることができます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2023/02/06 08:24

編集2023/02/08 06:30

実現したいこと

JavaでWebサイトのログイン画面を開発を学習中です。
CreateNativequeryのエラー回避のやり方を教えて頂けないでしょうか?
<処理の内容>

  • ログイン画面に社員番号とパスワードを入力し、DBで社員番号の照合を行う。
  • 社員番号でDBを検索し、登録があれば正常ケースとして、index.jspに遷移
  • 社員番号がDBに登録がなければ、loginnerro.jspに遷移

(質問内容の詳細)
ログイン画面にデータ未登録の社員番号を入力し、エラー動作の確認を行ったところ、
「IllegalArgumentException」や「NoResultException」などのエラーが出ました。
CreateNativequeryメソッドを使用する場合、データがない場合や検索コードの誤りなど
エラーが起こる場合の対処方法を教えて頂けないでしょうか?
※サイト画面の入力チェックはバリデーションとして実装済です。

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

タイプ 例外報告

メッセージ No entity found for query

説明 サーバーは予期しない条件に遭遇しました。それはリクエストの実行を妨げます。

例外

javax.persistence.NoResultException: No entity found for query
org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1643)
controllers.LoginServlet.doPost(LoginServlet.java:78)

タイプ 例外報告

メッセージ No query defined for that name [select * from employees where code =:code]

説明 サーバーは予期しない条件に遭遇しました。それはリクエストの実行を妨げます。

例外

java.lang.IllegalArgumentException: No query defined for that name [select * from employees where code =:code]

該当のソースコード

package controllers;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import models.Employees;
import utils.DBUtil;

/**

  • Servlet implementation class LoginServlet

*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

/** * @see HttpServlet#HttpServlet() */ public LoginServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/layout/login.jsp"); rd.forward(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, NoResultException{ // TODO Auto-generated method stub System.out.println("LoginservletPost"); EntityManager em = DBUtil.createEntityManager(); String code = request.getParameter("emp_number"); String password = request.getParameter("emp_pass"); System.out.println("emp_number" + code); System.out.println("password" + password); List<String> errors = new ArrayList<String>(); //社員番号のブランクチェック if (code == null || code.equals("")) { errors.add("社員番号を入力してください"); } //パスワードのブランクチェック if (password == null || password.equals("")) { errors.add("パスワードを入力してください"); } //入力内容にエラーがあるかどうか if (errors.size() > 0) { //エラーありログインエラー System.out.println("ログイン入力エラー"); request.setAttribute("loginError", "true"); request.setAttribute("errors", errors); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } else { //エラーなしログイン成功 try { Employees employees = (Employees) em .createNativeQuery("select * from employees where code =:code",Employees.class) .setParameter("code", code) .getSingleResult(); System.out.println("ログイン成功"); request.setAttribute("employees", employees); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/layout/index.jsp"); rd.forward(request, response); } catch (ServletException e) { e.printStackTrace(); } catch (NoResultException e) { System.out.println("ログイン社員番号未登録エラー"); errors.add("社員番号が登録されていません"); e.printStackTrace(); } } }

}

言語

Java

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2023/02/06 08:28

バリデーションに引っかかってもDBアクセスされてますが、それは要件通りですか?
Pocchi

2023/02/06 10:40

ご指摘の通りです。 現状、バリデーション通過後もDBアクセスしておりますが、ここは一旦要件通りとして見逃してください。
jimbe

2023/02/06 15:59

>try-catchしてNoResultExceptionをcatchするようにしたのですが、 >Employeesクラスの初期化がうまくいかず、エラーが解消されませんでした。 どのように入れてどこで(初期化がうまくいかずに)問題になったのでしょうか。 具体的なコード・結果を試したこととしてご提示ください。
Pocchi

2023/02/08 02:49

ありがとうございます。 試したことを提示いたします。 ※DBに登録されていないCodeでログイン画面にアクセスし、ログインエラー画面に遷移するか、のテストを実施しています。 希望する動きは、CreateNativeQueryメソッドを実行後、NoResultExceptionでもコンソールや画面で異常終了せず、ログインエラー画面に遷移する動きを希望しています。 ①今のソースの状態で実行する →NoResultExceptionが出て異常終了する ②CreateNativeQueryメソッドの箇所にtry-catchを入れて「NoResultException」を例外処理する //Employeeデータベースから社員番号索引 Employees employees; try { employees = (Employees) em .createNativeQuery("select * from employees where code =:code", Employees.class) .setParameter("code", code) .getSingleResult(); System.out.println("employeescode" + employees.getCode()); System.out.println("code" + code); } catch (NoResultException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } employeesがtryの中で代入されているため、try-catchから出た後のemployeesの変数が使用できなくなり、コンパイルエラーとなる ③doPostのメソッド内全体にtry-catchを入れる * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, NoResultException{ // TODO Auto-generated method stub try { System.out.println("LoginservletPost"); EntityManager em = DBUtil.createEntityManager(); String code = request.getParameter("emp_number"); String password = request.getParameter("emp_pass"); System.out.println("emp_number" + code); System.out.println("password" + password); List<String> errors = new ArrayList<String>(); //社員番号のブランクチェック if (code == null || code.equals("")) { errors.add("社員番号を入力してください"); } //パスワードのブランクチェック if (password == null || password.equals("")) { errors.add("パスワードを入力してください"); } //Employeeデータベースから社員番号索引 Employees employees = (Employees) em .createNativeQuery("select * from employees where code =:code", Employees.class) .setParameter("code", code) .getSingleResult(); System.out.println("employeescode" + employees.getCode()); System.out.println("code" + code); //入力内容にエラーがあるかどうか if (errors.size() > 0) { //エラーありログインエラー System.out.println("loginError"); request.setAttribute("loginError", "true"); request.setAttribute("errors", errors); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } else { //エラーなしログイン成功 request.setAttribute("employees", employees); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/layout/index.jsp"); rd.forward(request, response); } } catch (ServletException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (NoResultException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } } 上記のソースで、画面上からDBに登録されていないケースでログインすると、 異常終了は解消されるが、コンソール上でエラーが出ており、Queryの箇所でエラーになっており、 想定通り処理しません。 こちらが希望する動きは、DBにないコードの場合、 後続のエラー画面に遷移する、という動きですが、CreateNativeQueryでエラーになっているため 後続処理に進んでいない、という状況です。 Hibernate: alter table employees add constraint UK_3um79qgwg340lpaw7phtwudtc unique (code) javax.persistence.NoResultException: No entity found for query at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1643)
m.ts10806

2023/02/08 03:05

質問は編集できますので追加を。 ただ、やはり if (errors.size() > 0) { の位置を移動するだけなので、バリデーションOKのときのみDBアクセス実行するようにした方が問題の切り分けにもなりますし、無駄なDBアクセスを減らせます。
Pocchi

2023/02/08 04:35

ありがとうございます。 ご指摘の通り、バリデーション後に判定条件をいれる事で修正しました。 すると、エラー内容が変わりました。 修正した結果、追加で質問させて頂く事をお許しください。 ①if(errors.size())の位置 バリデーション後にif(errors.size())を入れました。 しかし、そうすると、CreateNativeQueryメソッドの結果、データが見つからないエラーの場合、 errors.addに「社員番号が未登録です」というエラー文を追加し、エラー画面に遷移させたいのですが、 今の位置ではエラー画面へのRedirect処理を2回する必要があると思います。 バリデーションとDBのデータが見つからないケースのエラーを判断後、エラー画面に遷移する、というロジックにしたいのですが、どういった書き方が適切か、助言を頂けないでしょうか? ②新たなエラー:IllegalArgumentExceptionについて ソース修正後、未登録社員番号を画面入力し、処理を確認したところ、 .IllegalArgumentExceptionと新たなエラーが出ました。 「不適切な引数」エラーということなのですが、何にせよCreateNativeQueryのエラー回避のやり方が理解できていないのだと考えます。 通常、CreateNativeQueryを使用される場合、「不正な引数」「データが見つからない」などのエラー回避に対して、どのように回避されているか教えて頂けないでしょうか? <ソース> protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, NoResultException{ // TODO Auto-generated method stub System.out.println("LoginservletPost"); EntityManager em = DBUtil.createEntityManager(); String code = request.getParameter("emp_number"); String password = request.getParameter("emp_pass"); System.out.println("emp_number" + code); System.out.println("password" + password); List<String> errors = new ArrayList<String>(); //社員番号のブランクチェック if (code == null || code.equals("")) { errors.add("社員番号を入力してください"); } //パスワードのブランクチェック if (password == null || password.equals("")) { errors.add("パスワードを入力してください"); } //入力内容にエラーがあるかどうか if (errors.size() > 0) { //エラーありログインエラー System.out.println("ログイン入力エラー"); request.setAttribute("loginError", "true"); request.setAttribute("errors", errors); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } else { //エラーなしログイン成功 try { Employees employees = (Employees) em .createNamedQuery("select * from employees where code =:code",Employees.class) .setParameter("code", code) .getSingleResult(); System.out.println("ログイン成功"); request.setAttribute("employees", employees); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/layout/index.jsp"); rd.forward(request, response); } catch (ServletException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (NoResultException e) { System.out.println("ログイン社員番号未登録エラー"); // TODO 自動生成された catch ブロック errors.add("社員番号が登録されていません"); e.printStackTrace(); }
m.ts10806

2023/02/08 04:37

質問は編集できますので追加を。
Pocchi

2023/02/08 05:12

大変失礼しました。 バリデーション箇所を変更後、エラー内容が変わったため 質問題材から変更させて頂きました。 CreateNativequeryメソッドを使用時のエラー回避方法を教えて頂きたい、という事が私が聞きたいことでした。
jimbe

2023/02/08 06:20 編集

teratail のコンテンツは、後の人が同じ問題に遭遇した時の参考・解決に役立てることを目的としており、長く残されます。 ですのでタイトルからコメントまでを含めて状況の変化が追えなくなるような改変には注意が必要です。 エラーメッセージやコード等、パソコンの画面に表示される(/された)モノは、コードのマークダウン(```)で囲うようにされると、フォントが変わり、変にフォーマットされずにすみます。その際コードはファイル毎に分けるようにしてください。 全くの蛇足ですが、「// TODO Auto-generated constructor stub」とか「// TODO 自動生成された catch ブロック」とかの意味の無いコメントは削除されたほうが良いです。コードの品質が疑われます。
jimbe

2023/02/08 06:40 編集

そもそもの発端は getSingleResult() は必ず 1 件が返される場合にのみ使用する(そうで無かったらシステム障害として例外処理する)べき所を 0 件の場合もシステム的には正常ルートとするつもりでコードが書かれていたことであって、ログイン項目が空かどうかでクエリを実行しなければ全て解決することでは無いと思います。 (社員番号やパスワードが空ならクエリを行わないのは、クエリを実行しても 0 件になるのが分かっているので無駄に処理をしないということであって、両方入力されていても存在しない社員番号やパスワードが一致しないで 0 件となることは防げません。) また蛇足になりますが、社員番号とパスワードを入力してログインする際に、("社員番号が登録されていません"のように)何が問題だったのかを表示してはいけません。 不正ログインを試みるものに対して情報を与えることになります。
Pocchi

2023/02/08 06:40

> getSingleResult() は必ず 1 件が返される場合にのみ使用する(そうで無かったらシステム障害として例外処理する)べき所を 0 件の場合もシステム的には正常ルートとするつもりでコードが書かれていたこと ありがとうございます。 ログイン画面は必ず件が返される場合ではないと考えております。(社員番号未登録や社員番号間違いなど) そのため、0件の場合でもシステム的に正常ルートとするつもりでコードを書いていました。 今回の場合、getSingleResult()を使用した場合、NoResultExceptionを例外にして0件の場合もシステム的には正常ルートをする、方法でコーディングしましたが、他の方々の場合は、もっと別のコーディングのやり方をされるのでしょうか? 良ければその手法を教えて頂けると幸いです。 -- 不要なコメントは削除しました。 teratailに投稿する事が慣れておらず、質問内容や中身を改変してしまいました。 せっかくコメントして頂いているにも関わらず、失礼いたしました。
jimbe

2023/02/08 06:53 編集

getSingleResult() に拘るかどうかと思います。 その場合は仰るように NoResultException をキャッチして正常ルートとすることになるでしょうし、うろ覚えですが確か getResultList() とかで 0 ~ 複数件を普通に得られたと思いますので、 1 件ならログイン成功、 0 件なら失敗、 2 件以上ならシステム障害として処理することも可能かと思います。 変数を try-catch の中で宣言しているからコンパイルエラーになってうんぬんはデータベースとは全く関係無く java のコーディングの問題ですので、それによって解決出来ないとなれば質問の内容は全く違うことになるでしょう。 コメント等での指摘は最終的には書いた側が「そうしてほしい」とか「そう思っている」というだけで、何ら強制する(される)ものではありません。 より良い方法等があればそうして頂くのが良いです。
Pocchi

2023/02/08 07:10

ありがとうございます。 頂いたコメントで解決いたしました。 getSingleResult()と、getResultList()と両方の手法でコーディングしてみて、 望む結果が得れるか検証を重ねたいと思います。 ありがとうございました。
guest

回答1

0

自己解決

jimbeさん、m.ts10806さん、ありがとうございます。
頂いたコメントを元に考えた結果、getSingleResult()などのデータ検索時のエラーで悩んでいたといきつく事が出来ました。
結果、私はgetSingleResult()を使用して、NoResultExceptionとNonUniqueResultExceptionのクエリ使用時に発生する例外をtry-catchで回避する方法でコーディングしました。
結果、想定通りにデータ0件時も2件以上ある場合でも正常終了し、エラー画面に遷移する事を確認できました。
ありがとうございました。

最終ソースは以下の通りになります。
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, NoResultException {

String code = request.getParameter("emp_number"); String password = request.getParameter("emp_pass"); String error = ""; EntityManager em = DBUtil.createEntityManager(); //入力エラーチェック if (code == null || code.equals("")) { //社員番号ブランクエラーによるエラー画面遷移 error = "社員番号がブランクです"; request.setAttribute("error", error); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } else if (password == null || password.equals("")) { //パスワードブランクエラーによるエラー画面遷移 error = "パスワードがブランクです"; request.setAttribute("error", error); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } else { //入力バリデーションクリア try { Employees employees = (Employees) em .createNativeQuery("select * from employees where code =:code", Employees.class) .setParameter("code", code) .getSingleResult(); request.setAttribute("employees", employees); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/layout/index.jsp"); rd.forward(request, response); } catch (NoResultException e) { //検索データ0件 e.printStackTrace(); error = "社員番号未登録です"; request.setAttribute("error", error); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } catch (NonUniqueResultException e) { //検索データが複数件 e.printStackTrace(); error = "社員番号が複数あります"; request.setAttribute("error", error); RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/views/error/loginerrors.jsp"); rd.forward(request, response); } } }

}

投稿2023/02/08 08:42

Pocchi

総合スコア3

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問