Java・ツイッタークローン・タスク管理システム⑤編集機能をつける

##はじめに
Javaを使って初めてアプリケーションを作成する人にむけて記事を書いてみようと思います。
ポートフォリオや、会社の研修課題作成の参考にしていただければ幸いです。
今回は、タスクマネージャーを作成します。
これを応用することで、ツイッタークローンの作成にも活かすことができます。

アプリケーションの機能ごとに記事を投稿していきます。
1.データベース作成
2.ログイン機能
3.タスクの登録機能
4.一覧表示
　　-ソート機能
　　-検索機能
5.編集機能
6.削除機能
7.排他制御について

＊詳しい説明はコード内に書いてありますので、コピペする人は消して使ってください

##実行環境
eclipse4.16.0
Tomcat9
Java11
Mysql5.7

目次
1.viewの作成
2.DAOの作成
3.サーブレット作成
4.次回予告

#viewの作成
今回は、編集ページを作っていきます。以前記事にしたタスク登録画面に大変似ているので、簡単に確認してください。
タスク編集は、ログインユーザなら自分が投稿した物以外も編集することができるようになっております。

```task-update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>タスク編集</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/task-insert.css">
</head>
<body>
<jsp:include page="header.jsp"/>
<jsp:useBean id="task" scope="session" class="model.entity.TaskBean"/>

	<div class="contain">
		<h3>タスク登録</h3>
		<form action="task-update-servlet" method="post">
			<table class="form-table" border="1">
	    		<tbody>
		    		<tr>
					    <th>タスク名</th>
					        <td>
					        <div class="input-key">
								<input type="text" class="form-control" name="task_name" value="<jsp:getProperty property="task_name" name="task"/>">
							</div>
					    </td>
				   	</tr>
			       	<tr>
			        	<th>カテゴリー</th>
			        	<td>
					        <div class="input-key">
					      		<select class="form-control" name="category_id">
        							<option value="<jsp:getProperty property="category_id" name="task"/>">変更なし</option>
        							<option value="1">新商品A：開発プロジェクト</option>
        							<option value="2">既存商品B:改良プロジェクト</option>
      							</select>
						    </div>
					    </td>
				    </tr>
				    <tr>
					    <th>期限</th>
					        <td>
					        <div class="input-key">
								<input type="date" name="limit_date" class="form-control" value="<jsp:getProperty property="limit_date" name="task"/>">
							</div>
					    </td>
				   	</tr>
			        <tr>
					    <th>ステータス</th>
				        <td>
					        <div class="input-key">
				      			<select class="form-control" name="status_code">
       								<option value="<jsp:getProperty property="status_code" name="task"/>">変更なし</option>
       								<option value="00">未着手</option>
       								<option value="50">着手</option>
       								<option value="99">完了</option>
    		 					</select>
				    		</div>
				        </td>
			        </tr>
			        <tr>
					    <th>メモ</th>
					        <td>
					        <div class="input-key">
								<input type="text" class="form-control" name="memo" value="<jsp:getProperty property="memo" name="task"/>">
							</div>
					    </td>
				   	</tr>
				    <tr>
				        <th>作成日</th>
				        <td><jsp:getProperty property="create_datetime" name="task"/><input type="hidden" name="create_datetime" value="<jsp:getProperty property="create_datetime" name="task"/>"></td>
			        </tr>
			        <tr>
				        <th>
				        	<input type="hidden" name="task_id" value="<jsp:getProperty property="task_id" name="task"/>">
			        		<input type="hidden" name="version" value='<jsp:getProperty property="version" name="task"/>'>
			        		<input type="submit" value="更新する" class="input-submit"></th>
				        <td></td>
			        </tr>
			    </tbody>
			</table>
	    </form>
	</div>
</body>
</html>
```

さらに編集に成功した時の画面も用意します。
こちらには、編集した内容が表示されるようになっている。

```task-update-comp.java
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="model.entity.TaskBean"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>更新完了</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/task-edit-failure.css">
</head>
<body>
<jsp:useBean id="task" class="model.entity.TaskBean" scope="session"/>
<%
String category_name = (String)request.getAttribute("category_name");
String status_name = (String)request.getAttribute("status_name");
%>
	<jsp:include page="header.jsp"/>
	<div class="contain">
		<div class="box">
		  	<h3>タスクの更新が完了しました</h3>
		  	<p>以下の内容で更新しました</p>
		  	<hr>
		 	<p>
			  	タスク名：<jsp:getProperty property="task_name" name="task"/><br>
			  	カテゴリー：<jsp:getProperty property="category_id" name="task"/>：<%=category_name %><br>
			  	期限：<jsp:getProperty property="limit_date" name="task"/><br>
		 	 	ステータス：<jsp:getProperty property="status_code" name="task"/>：<%=status_name %><br>
		 	 	メモ：<jsp:getProperty property="memo" name="task"/><br>
		 	 </p>
	 	 </div>
	</div>
</body>
</html>
```

さらに失敗した時の画面も用意する
失敗理由も表示するようにする

```task-update-failure
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.List"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>タスク更新失敗</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/task-edit-failure.css">
</head>
<body>
<%
List<String> error = (List<String>)request.getAttribute("error");
%>
	<jsp:include page="header.jsp"/>
	<div class="contain">
		<div class="box">
			<h3>タスクの更新に失敗しました</h3>
			<hr>
			<p>*下記の原因が考えられます</p>
		    <ul>
<%for(String er : error){ %>
		  		<li><%=er %></li>
<%} %>
		  	</ul>
		</div>
	</div>
</body>
</html>
```

#DAOの作成
タスクの更新用メソッドと指定したタスクを取得するメソッドの作成


```model.dao.TaskDAO.java
 /**
	  * タスク更新用メソッド
	  * @param task
	  * @return sum
	  * @throws SQLException
	  * @throws ClassNotFoundException
	  */
	 public int updateTask(TaskBean task) throws SQLException, ClassNotFoundException {
		 String sql = "update t_task set task_name = ?, category_id = ?, limit_date = ?, status_code = ?, memo = ?, version = version + 1 where task_id = ? and version = ?";
		 int sum = 0;
		 try(Connection con = ConnectionManager.getConnection();
				 PreparedStatement pstmt = con.prepareStatement(sql)){
			 pstmt.setString(1, task.getTask_name());
			 pstmt.setInt(2, task.getCategory_id());
			 pstmt.setDate(3, task.getLimit_date());
			 pstmt.setString(4, task.getStatus_code());
			 pstmt.setString(5, task.getMemo());
			 pstmt.setInt(6, task.getTask_id());
			 pstmt.setInt(7, task.getVersion());
			 sum = pstmt.executeUpdate();
		 }
		 return sum;
	 }

/**
	 * task_idを引数に特定のタスクを取得する
	 * @param task_id
	 * @return
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public TaskBean getSpecificTask(int task_id) throws SQLException, ClassNotFoundException {
		 TaskBean task = new TaskBean();
		 String sql = "select * from t_task where task_id = ?";
		 try(Connection con = ConnectionManager.getConnection();
				 PreparedStatement pstmt = con.prepareStatement(sql);){
			 pstmt.setInt(1, task_id);
			 ResultSet res = pstmt.executeQuery();
			 //taskオブジェクトへカラム情報を格納していく
			 while(res.next()) {
				task.setTask_id(task_id);
				task.setTask_name(res.getString("task_name"));
				task.setCategory_id(res.getInt("category_id"));
				task.setLimit_date(res.getDate("limit_date"));
				task.setUser_id(res.getString("user_id"));
				task.setStatus_code(res.getString("status_code"));
				task.setMemo(res.getString("memo"));
				task.setCreate_datetime(res.getTimestamp("create_datetime"));
				task.setUpdate_datetime(res.getTimestamp("update_datetime"));
				task.setVersion(res.getInt("version"));
			 }
		 }
		 return task;
	 }
```



#サーブレットの作成
一覧画面から選択したタスクの情報をセッションスコープへ保存して転送先（task-update.java）で表示・編集する

```servlet.TaskUpdateDetailServlet.java
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//リクエストパラメータの取得
		request.setCharacterEncoding("UTF-8");
		int task_id = Integer.parseInt(request.getParameter("task_id"));

		TaskDAO dao = new TaskDAO();
		TaskBean task = new TaskBean();

		try {
			//指定したタスクをsessionスコープへ保存
			task = dao.getSpecificTask(task_id);
			HttpSession session = request.getSession();
			session.setAttribute("task", task);
			RequestDispatcher rd = request.getRequestDispatcher("task-update.jsp");
			rd.forward(request, response);
		}catch(SQLException | ClassNotFoundException e) {
			e.printStackTrace();
		}
```
編集後に下記のサーブレットにてDBの処理と画面遷移を行う


```servlet.TaskUpdateServket.java
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub

		TaskDAO taskdao = new TaskDAO();
		CategoryDAO categorydao = new CategoryDAO();
		StatusDAO statusdao = new StatusDAO();

		//リクエストパラメータ取得
		request.setCharacterEncoding("UTF-8");
		int task_id = Integer.parseInt(request.getParameter("task_id"));
		String task_name = request.getParameter("task_name");
		String category_id_str = request.getParameter("category_id");
		String limit_date_check = request.getParameter("limit_date");
		String status_code = request.getParameter("status_code");
		String memo = request.getParameter("memo");
		int version = Integer.parseInt(request.getParameter("version"));

		//error表示を保存するリスト生成
		List<String> error = new ArrayList<String>();

		//sessionチェック
		HttpSession session = request.getSession();
		boolean sessioncheck = (boolean)session.getAttribute("login");
		if(!sessioncheck) {
			error.add("ログインしてからタスク登録をしてください");
		}

		//入力漏れをチェック
		if(task_name.equals("")) {
			error.add("タスク名が空欄です");
		}
		boolean limit_check;
		limit_date_check = limit_date_check.replace('-', '/');
	    DateFormat format = DateFormat.getDateInstance();
		format.setLenient(false);
		try {
			format.parse(limit_date_check);
			 limit_check = true;
		} catch(Exception e) {
			limit_check = false;
		}
		if(!limit_check) {
			error.add("期限には日付を入力してください");
		}

		request.setAttribute("error", error);

		if(task_name != "") {
			try {
				//パラメータ通りに受け取れないもの、つまりカテゴリーと期限（String型でないもの）を変換
				int category_id = Integer.parseInt(category_id_str);
				Date limit_date = Date.valueOf(request.getParameter("limit_date"));

				//現在のversionとレコード取得時のversionを照合
				int current_version = taskdao.getVersion(task_id);
				if(current_version != version) {
					error.add("このタスクは他の人によって改編されています");
					request.setAttribute("error", error);
					RequestDispatcher rd = request.getRequestDispatcher("task-update-failure.jsp");
					rd.forward(request, response);
				}

				//タスクオブジェクトへ値を設定
				TaskBean task = new TaskBean();
				task.setTask_name(task_name);
				task.setCategory_id(category_id);
				task.setLimit_date(limit_date);
				task.setStatus_code(status_code);
				task.setMemo(memo);
				task.setTask_id(task_id);
				task.setVersion(version);

				//updateメソッドによりデータベース処理
				taskdao.updateTask(task);

				//sessionスコープへtaskを保存
				session.setAttribute("task", task);

				//リクエストスコープへカテゴリ名とステータス名を保存
				String category_name = categorydao.getCategoryName(task.getCategory_id());
				String status_name = statusdao.getStatusName(task.getStatus_code());
				request.setAttribute("category_name", category_name);
				request.setAttribute("status_name", status_name);

				RequestDispatcher rd = request.getRequestDispatcher("task-update-comp.jsp");
				rd.forward(request, response);
			} catch(SQLException | ClassNotFoundException | IllegalArgumentException e) {
				RequestDispatcher rd = request.getRequestDispatcher("task-update-failure.jsp");
				rd.forward(request, response);
			}
		}else {
			RequestDispatcher rd = request.getRequestDispatcher("task-update-failure.jsp");
			rd.forward(request, response);
			}
	}
```


#次回予告
今回は、タスクの編集機能を実装しました。
次回はタスクの削除機能を実装します。