#03:メッセージの投稿機能の実装
このチャプターでは、メッセージの投稿機能を実装します。
【PostInsertServlet】package jp.paiza.servlet;
import java.io.*;
import java.sql.*;
import javax.sql.*;
import jakarta.annotation.*;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import jp.paiza.bean.*;
import jp.paiza.model.*;
@WebServlet("/post-insert")
public class PostInsertServlet extends HttpServlet {
@Resource(name = "jdbc/datasource")
private DataSource ds;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
}
}
【post-input.jsp】<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新規投稿</title>
<link rel="stylesheet" href="css/style.css" type="text/css">
</head>
<body>
<jsp:include page="header.jsp" />
<div class="page-background">
<div class="form-container">
<form action="/learning/post-insert" method="post">
<div class="user-info"><c:out value="${account.userId}" /></div>
<textarea
id="post-content"
name="content"
rows="4"
placeholder="いまどうしてる?"></textarea>
<div class="form-actions">
<button type="submit">投稿する</button>
</div>
</form>
</div>
</div>
</body>
</html>
【style.css】textarea {
width: 100%;
padding: 0;
border: none;
resize: vertical;
font-size: 1.125rem;
line-height: 1.6;
box-sizing: border-box;
background-color: transparent;
}
textarea:focus {
outline: none;
}
【PostModel.insert()】 public void insert(PostBean post) throws SQLException {
String sql = "insert into posts (account_id, content) VALUES (?, ?)";
}
【PostInsertServlet.doPost()】 @Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
try (Connection con = ds.getConnection()) {
RequestDispatcher d =
req.getRequestDispatcher("/posts");
d.forward(req, res);
} catch (SQLException e) {
e.printStackTrace();
throw new ServletException(e);
}
}
【PostModel】package jp.paiza.model;
import java.util.*;
import java.time.*;
import jp.paiza.bean.*;
import java.sql.*;
import jp.paiza.bean.AccountBean;
public class PostModel {
private Connection con;
public PostModel(Connection con) {
this.con = con;
}
public List<PostBean> findAll() throws SQLException {
String sql = "select posts.id, posts.account_id, accounts.user_id, posts.content, posts.created_at, posts.updated_at from posts inner join accounts on posts.account_id = accounts.id order by posts.id desc";
ArrayList<PostBean> l = new ArrayList<>();
try (PreparedStatement query = con.prepareStatement(sql)) {
ResultSet rs = query.executeQuery();
while (rs.next()) {
PostBean post = new PostBean();
post.setId(rs.getInt("id"));
post.setAccountId(rs.getInt("account_id"));
post.setUserId(rs.getString("user_id"));
post.setContent(rs.getString("content"));
post.setCreatedAt(rs.getTimestamp("created_at"));
post.setUpdatedAt(rs.getTimestamp("updated_at"));
l.add(post);
}
}
return l;
}
public void insert(PostBean post) throws SQLException {
String sql = "insert into posts (account_id, content) VALUES (?, ?)";
try (PreparedStatement query = con.prepareStatement(sql)) {
query.setInt(1, post.getAccountId());
query.setString(2, post.getContent());
query.executeUpdate();
}
}
}
【PostInsertServlet】package jp.paiza.servlet;
import java.io.*;
import java.sql.*;
import javax.sql.*;
import jakarta.annotation.*;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
import jp.paiza.bean.*;
import jp.paiza.model.*;
@WebServlet("/post-insert")
public class PostInsertServlet extends HttpServlet {
@Resource(name = "jdbc/datasource")
private DataSource ds;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
RequestDispatcher d =
req.getRequestDispatcher("/WEB-INF/jsp/post-input.jsp");
d.forward(req, res);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
try (Connection con = ds.getConnection()) {
String content = req.getParameter("content");
AccountBean account = (AccountBean) req.getSession().getAttribute("account");
PostBean post = new PostBean();
post.setContent(content);
post.setAccountId(account.getId());
PostModel m = new PostModel(con);
m.insert(post);
RequestDispatcher d =
req.getRequestDispatcher("/posts");
d.forward(req, res);
} catch (SQLException e) {
e.printStackTrace();
throw new ServletException(e);
}
}
}
【style.css】@charset "utf-8";
body {
margin: 0;
background-color: #f9fafb;
font-family: sans-serif;
}
.page-background {
display: flex;
justify-content: center;
padding: 2rem 1rem;
box-sizing: border-box;
}
.form-container {
width: 100%;
max-width: 512px;
background-color: white;
border-radius: 0.75rem;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
padding: 1.5rem;
}
h1 {
font-size: 1.5rem;
font-weight: bold;
text-align: center;
margin-top: 0;
margin-bottom: 2rem;
}
.input-group {
margin-bottom: 1.5rem;
}
label {
display: block;
font-size: 0.875rem;
color: #374151;
margin-bottom: 0.5rem;
font-weight: 500;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 0.75rem 1rem;
border: 1px solid #d1d5db;
border-radius: 0.5rem;
box-sizing: border-box;
font-size: 1rem;
transition: border-color 0.2s, box-shadow 0.2s;
}
input[type="text"]:focus,
input[type="password"]:focus {
outline: none;
border-color: #3b82f6;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.4);
}
button {
background-color: #3b82f6;
color: white;
font-weight: bold;
padding: 0.5rem 1.5rem;
border: none;
border-radius: 9999px;
cursor: pointer;
transition: background-color 0.2s;
}
button:hover {
background-color: #2563eb;
}
.form-actions {
display: flex;
justify-content: flex-end;
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #f3f4f6;
}
header {
background-color: white;
padding: 0 2rem;
height: 64px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
width: 100%;
box-sizing: border-box;
}
header .site-title {
font-size: 1.5rem;
font-weight: bold;
color: #111827;
}
header nav ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
gap: 1.5rem;
}
header nav a {
text-decoration: none;
color: #4b5563;
font-weight: 500;
transition: color 0.2s;
}
header nav a:hover {
color: #3b82f6;
}
.content-container {
width: 100%;
max-width: 800px;
background-color: white;
border-radius: 0.75rem;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
padding: 2rem;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
table th, table td {
padding: 0.75rem 1rem;
text-align: left;
border-bottom: 1px solid #e5e7eb;
white-space: nowrap;
}
table td:last-child {
white-space: normal;
}
table thead th {
background-color: #f9fafb;
font-weight: 600;
color: #6b7280;
font-size: 0.8rem;
text-transform: uppercase;
}
table tbody tr:hover {
background-color: #f9fafb;
}
.user-info {
font-weight: bold;
color: #111827;
margin-bottom: 0.75rem;
}
textarea {
width: 100%;
padding: 0;
border: none;
resize: vertical;
font-size: 1.125rem;
line-height: 1.6;
box-sizing: border-box;
background-color: transparent;
}
textarea:focus {
outline: none;
}
新・Java入門編27: 例外について学習しよう
https://paiza.jp/works/java/new-primer/java-new-primer-27
新・SQL入門編6: INSERT文を理解しよう
https://paiza.jp/works/sql/new-primer/sql-new-primer-6
インタフェースConnection
https://docs.oracle.com/javase/jp/17/docs/api/java.sql/java/sql/Connection.html
インタフェースPreparedStatement
https://docs.oracle.com/javase/jp/17/docs/api/java.sql/java/sql/PreparedStatement.html
インタフェースResultSet
https://docs.oracle.com/javase/jp/17/docs/api/java.sql/java/sql/ResultSet.html
クラスSQLException
https://docs.oracle.com/javase/jp/17/docs/api/java.sql/java/sql/SQLException.html
Class HttpServlet
https://jakarta.ee/specifications/servlet/6.1/apidocs/jakarta.servlet/jakarta/servlet/http/httpservlet
Interface HttpServletRequest
https://jakarta.ee/specifications/servlet/6.1/apidocs/jakarta.servlet/jakarta/servlet/http/httpservletrequest
Interface HttpServletResponse
https://jakarta.ee/specifications/servlet/6.1/apidocs/jakarta.servlet/jakarta/servlet/http/httpservletresponse
Interface HttpSession
https://jakarta.ee/specifications/servlet/6.1/apidocs/jakarta.servlet/jakarta/servlet/http/httpsession