コード全文
package com.example.demo.controller;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.Message;
@RestController
@RequestMapping("/chat")
public class ChatController {
private static final Queue<Message> messages = new ConcurrentLinkedQueue<>();
@GetMapping
public List<Message> getMessages() {
return new ArrayList<>(messages);
}
@PostMapping
public void postMessage(@RequestParam("user") String user,
@RequestParam("message") String message) {
messages.add(new Message(user, message));
}
}
package com.example.demo.model;
public class Message {
private String user;
private String content;
public Message() {} // JSON変換用
public Message(String user, String content) {
this.user = user;
this.content = content;
}
public String getUser() {
return user;
}
public String getContent() {
return content;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>LINE風複数人チャット</title>
<style>
body {
font-family: sans-serif;
background-color: #e5ddd5;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
height: 100vh;
}
#chatBox {
flex: 1;
padding: 10px;
overflow-y: auto;
background-color: #f7f7f7;
}
.message {
max-width: 70%;
padding: 8px 12px;
margin: 6px 0;
border-radius: 15px;
clear: both;
}
.sent {
background-color: #dcf8c6;
float: right;
text-align: right;
}
.received {
background-color: #fff;
float: left;
text-align: left;
}
#inputArea {
display: flex;
padding: 10px;
background-color: #fff;
border-top: 1px solid #ccc;
}
#message, #username {
padding: 8px;
font-size: 1em;
border: 1px solid #ccc;
border-radius: 20px;
margin-right: 10px;
}
#message {
flex: 1;
}
#sendMessage {
padding: 8px 20px;
border: none;
background-color: #34b7f1;
color: white;
border-radius: 20px;
font-weight: bold;
cursor: pointer;
}
.username-label {
font-size: 0.75em;
color: #555;
display: block;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
</style>
</head>
<body>
<div id="chatBox"></div>
<div id="inputArea">
<input type="text" id="username" placeholder="名前" />
<input type="text" id="message" placeholder="メッセージ" />
<button id="sendMessage">送信</button>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
const chatBox = document.getElementById("chatBox");
const username = document.getElementById("username");
const messageInput = document.getElementById("message");
const sendButton = document.getElementById("sendMessage");
function renderMessages(messages) {
chatBox.innerHTML = '';
messages.forEach(msg => {
const div = document.createElement('div');
const nameLabel = document.createElement('span');
nameLabel.className = "username-label";
nameLabel.textContent = msg.user;
div.className = "message clearfix " +
(msg.user === username.value.trim() ? "sent" : "received");
div.appendChild(nameLabel);
div.appendChild(document.createTextNode(msg.content));
chatBox.appendChild(div);
});
chatBox.scrollTop = chatBox.scrollHeight;
}
sendButton.addEventListener("click", function () {
const user = username.value.trim();
const message = messageInput.value.trim();
if (!user || !message) return;
fetch("/chat", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: `user=${encodeURIComponent(user)}&message=${encodeURIComponent(message)}`
}).then(() => {
messageInput.value = "";
});
});
setInterval(() => {
fetch("/chat")
.then(res => res.json())
.then(data => renderMessages(data));
}, 1500);
});
</script>
</body>
</html>
JavaでAND条件・OR条件に対応した動的検索DAOの作り方
今回は、検索条件を動的に変更できるDAOの作り方を、Javaと研修中に説明したSuperDao
クラスを使って詳しく解説します。
しかも今回は、「AND条件」だけでなく「OR条件」にも対応できる柔軟な実装方法を紹介します!
たとえばこんな検索、やりたくなったことはありませんか?
- 「年齢が30歳以上かつ性別が女性」
- 「名前が『田中』または『佐藤』」
- 「部署が『営業部』か『企画部』かつ年齢が40歳以下」
こうした複雑な条件を自由に組み立てる方法を、例えを交えながら丁寧に説明します。
AND/OR条件に対応した検索DAOの設計
ここでは社員情報を検索するEmployeeDao
クラスの例で、AND・OR両方に対応する方法を解説します。
どう実現する?
検索条件を格納するために、以下のような構造を使います。
public class SearchCondition {
public enum Operator { AND, OR }
private String field;
private String operator; // 例: =, >=, LIKEなど
private Object value;
private Operator logic; // ANDかOR
// コンストラクタやgetter/setterは省略
}
これを使えば、複数の条件をANDやORでつなぐことができます。
実装コード例(EmployeeDao)
public class EmployeeDao extends SuperDao {
public List<Employee> searchEmployees(List<SearchCondition> conditions) {
List<Employee> resultList = new ArrayList<>();
connect();
StringBuilder sql = new StringBuilder("SELECT * FROM employee WHERE ");
List<Object> params = new ArrayList<>();
for (int i = 0; i < conditions.size(); i++) {
SearchCondition cond = conditions.get(i);
if (i > 0) {
sql.append(" ").append(cond.getLogic().name()).append(" ");
}
sql.append(cond.getField()).append(" ").append(cond.getOperator()).append(" ?");
// 値の加工(LIKE用の%追加など)
if ("LIKE".equalsIgnoreCase(cond.getOperator())) {
params.add("%" + cond.getValue() + "%");
} else {
params.add(cond.getValue());
}
}
try (PreparedStatement stmt = con.prepareStatement(sql.toString())) {
for (int i = 0; i < params.size(); i++) {
stmt.setObject(i + 1, params.get(i));
}
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setAge(rs.getInt("age"));
emp.setGender(rs.getString("gender"));
resultList.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return resultList;
}
}
利用例 – ANDとORを組み合わせる
List<SearchCondition> conditions = new ArrayList<>();
conditions.add(new SearchCondition("name", "LIKE", "田中", SearchCondition.Operator.OR));
conditions.add(new SearchCondition("name", "LIKE", "佐藤", SearchCondition.Operator.OR));
conditions.add(new SearchCondition("age", ">=", 30, SearchCondition.Operator.AND));
EmployeeDao dao = new EmployeeDao();
List<Employee> employees = dao.searchEmployees(conditions);
この例では次のようなSQLが実行されます:
SELECT * FROM employee WHERE name LIKE ? OR name LIKE ? AND age >= ?
ちなみにこれは次のように解釈されます:
(名前が「田中」に類似 または 名前が「佐藤」に類似) かつ 年齢が30歳以上
AND/OR条件の整理(表で理解)
条件 | SQLの書き方 | 説明 |
---|---|---|
AND | 条件1 AND 条件2 | すべての条件を満たす |
OR | 条件1 OR 条件2 | いずれかの条件を満たす |
グループ化 | (条件1 OR 条件2) AND 条件3 | 複数条件をまとめてAND/ORで比較 |
メリットとデメリット
項目 | 内容 |
---|---|
メリット | 複雑な検索条件に柔軟に対応可能 |
デメリット | SQLが長くなりやすく、括弧の使い方に注意が必要 |
まとめ
動的にAND/OR条件を組み合わせて検索できるDAOを作ることで、非常に高機能で汎用的な検索処理が実現できます。
「たくさんの検索項目を自由に組み合わせて探したい!」
というニーズにこたえる柔軟なシステムが作れるようになりますよ。
ぜひトライしてみてください!