Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/main/java/lobby/controller/CreateRoomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)
roomPlayerDAO.enterIfAbsent(roomResult.getId(), hostUserId);

LobbyWebSocket.broadcastRoomList();

session.setAttribute("ROOM_AUTH_" + roomId, true);

response.sendRedirect(
request.getContextPath() + "/room?roomId=" + URLEncoder.encode(roomId, StandardCharsets.UTF_8)
request.getContextPath() + "/room/enter?roomId=" + URLEncoder.encode(roomId, StandardCharsets.UTF_8)
+ "&playType=" + URLEncoder.encode(playType, StandardCharsets.UTF_8));

} catch (Exception e) {
e.printStackTrace();
throw new ServletException("방 생성 실패", e);
Expand Down
37 changes: 36 additions & 1 deletion src/main/java/room/controller/EnterRoomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import javax.servlet.http.HttpSession;

import lobby.ws.LobbyWebSocket;
import room.dao.RoomDAO;
import room.dao.RoomDAOImpl;
import room.dao.RoomPlayerDAO;
import room.dao.RoomPlayerDAOImpl;

Expand All @@ -20,28 +22,61 @@ public class EnterRoomController extends HttpServlet {
private static final long serialVersionUID = 1L;

private final RoomPlayerDAO roomPlayerDao = new RoomPlayerDAOImpl();
private final RoomDAO roomDAO = new RoomDAOImpl();

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
handler(request, response);
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
handler(request, response);
}

protected void handler(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String ctx = request.getContextPath();

try {
String roomId = request.getParameter("roomId");
String playType = request.getParameter("playType");
String roomPwd = request.getParameter("roomPwd");

if (roomId == null || roomId.isBlank() || playType == null || playType.isBlank()) {
response.sendRedirect(ctx + "/lobby?error=missing_room_id");
response.sendRedirect(ctx + "/lobby?error=missing_room_info");
return;
}
Comment thread
gaeunnlee marked this conversation as resolved.

boolean isPrivate = roomDAO.isPrivateRoom(roomId);
String hostUserId = roomDAO.findHostUserIdByRoomId(roomId);
Comment thread
gaeunnlee marked this conversation as resolved.

HttpSession session = request.getSession(false);
String userId = (session == null) ? null : (String)session.getAttribute("loginUserId");

if (userId == null || userId.isBlank()) {
response.sendRedirect(ctx + "/lobby?error=enter_failed");
return;
}

boolean isHost = userId.equals(hostUserId);

if (isPrivate && !isHost) {
if (roomPwd == null || roomPwd.isBlank()) {
response.sendRedirect(ctx + "/lobby?error=need_password");
return;
}

if (!roomDAO.matchRoomPassword(roomId, roomPwd)) {
response.sendRedirect(ctx + "/lobby?error=wrong_password");
return;
}
session.setAttribute("ROOM_AUTH_" + roomId, true);
}
Comment thread
gaeunnlee marked this conversation as resolved.

roomPlayerDao.enterIfAbsent(roomId, userId);

System.out.println("[ENTER] ctx=" + request.getContextPath() + " roomId=" + roomId + " userId=" + userId);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/room/controller/ExitRoomController.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response)

try {
roomService.exitAndHandleHost(roomId, userId);
session.removeAttribute("ROOM_AUTH_" + roomId);
System.out.println("[EXIT] ctx=" + request.getContextPath() + " roomId=" + roomId + " userId=" + userId);
LobbyWebSocket.broadcastRoomList();
response.sendRedirect(ctx + "/lobby");
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/room/controller/ViewRoomController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package room.controller;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
Expand All @@ -21,13 +23,24 @@ public class ViewRoomController extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String ctx = request.getContextPath();

try {
String roomId = request.getParameter("roomId");
String playType = request.getParameter("playType");
HttpSession session = request.getSession(false);

if (playType == null || roomId == null || session == null) {
response.sendRedirect("/lobby");
response.sendRedirect(ctx + "/lobby");
return;
}

boolean isPrivate = roomDAO.isPrivateRoom(roomId);
Boolean isRoomAuthed = (Boolean)session.getAttribute("ROOM_AUTH_" + roomId);

if (isPrivate && (isRoomAuthed == null || !isRoomAuthed)) {
response.sendRedirect(ctx + "/room/enter?roomId=" + URLEncoder.encode(roomId, StandardCharsets.UTF_8)
+ "&playType=" + URLEncoder.encode(playType, StandardCharsets.UTF_8));
return;
}

Expand All @@ -38,7 +51,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response)
String hostUserId = roomDAO.findHostUserIdByRoomId(roomId);

if (hostUserId == null) {
response.sendRedirect("/lobby?error=host_not_found");
response.sendRedirect(ctx + "/lobby?error=host_not_found");
return;
}

Expand Down
22 changes: 22 additions & 0 deletions src/main/java/room/dao/RoomDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,26 @@ RoomDTO createRoom(
*/
String findHostUserIdByRoomId(String roomId) throws Exception;

/**
* 비공개 방 비밀번호 검증
*
* @param roomId 방 ID
* @param inputPwd 사용자가 입력한 비밀번호 (평문)
*
* @return true - 비밀번호 일치
* false - 비밀번호 불일치 또는 존재하지 않는 방
*
* 동작 규칙
* - 공개방(isPublic="0")은 호출 대상이 아님
* - 비공개방(isPublic="1")에 대해서만 room_pwd와 비교
*/
boolean matchRoomPassword(String roomId, String inputPwd) throws Exception;

/**
* 방이 비공개방(비밀번호가 설정된 방)인지 여부 조회
*
* @param roomId 조회할 방 ID
*/
boolean isPrivateRoom(String roomId) throws Exception;

}
46 changes: 46 additions & 0 deletions src/main/java/room/dao/RoomDAOImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,52 @@ public String findHostUserIdByRoomId(String roomId) throws Exception {
}
}

public boolean matchRoomPassword(String roomId, String inputPwd) throws Exception {
final String query = """
SELECT COUNT(*)
FROM room
WHERE id = ?
AND is_public = '1'
AND room_pwd = ?
""";

try (Connection conn = DB.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query)) {

pstmt.setString(1, roomId);
pstmt.setString(2, inputPwd);

try (ResultSet rs = pstmt.executeQuery()) {
rs.next();
return rs.getInt(1) == 1;
}
}
}

@Override
public boolean isPrivateRoom(String roomId) throws Exception {

String query = """
SELECT COUNT(*)
FROM room
WHERE id = ?
AND room_pwd IS NOT NULL
""";

try (Connection conn = DB.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query)) {

pstmt.setString(1, roomId);

try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next()) {
return rs.getInt(1) > 0;
}
return false;
}
}
}

private RoomDTO mapToRoom(ResultSet rs) throws SQLException {
return RoomDTO.builder()
.id(rs.getString("id"))
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/WEB-INF/views/room/create.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@
<div class="row">
<label>공개 여부</label>
<label>
<input type="radio" name="isPublic" value="1" checked onclick="togglePwd(false)" />
<input type="radio" name="isPublic" value="0" checked onclick="togglePwd(false)" />
공개
</label>
<label>
<input type="radio" name="isPublic" value="0" onclick="togglePwd(true)" />
<input type="radio" name="isPublic" value="1" onclick="togglePwd(true)" />
비공개 🔒
</label>
</div>
Expand Down
39 changes: 38 additions & 1 deletion src/main/webapp/static/lobby/lobby.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@
function toRowHtml(r) {
const roomId = r.id ?? "";
const roomName = r.roomName ?? "-";
const isPublic = (String(r.isPublic) === "1") ? "공개" : "비공개 🔒";
const isPublic = (String(r.isPublic) === "0") ? "공개" : "비공개 🔒";
const playType = (String(r.playType) === "0") ? "개인전" : "팀전";
const current = r.currentUserCnt ?? 0;
const total = r.totalUserCnt ?? 0;
const isPublicId = (String(r.isPublic) === "0") ? "public" : "private";


const disabledAttr = IS_LOGIN ? "" : "disabled";
Expand All @@ -98,12 +99,48 @@
<form class="enter-room-form" action="${CTX}/room/enter"" method="post">
<input type="hidden" name="playType" value="${escapeHtml(r.playType)}" />
<input type="hidden" name="roomId" value="${escapeHtml(roomId)}" />
<input type="hidden" name="isPublic" value="${escapeHtml(isPublicId)}" />
<button type="submit" ${disabledAttr} ${titleAttr}>입장</button>
</form>
</td>
</tr>
`;
}

document.addEventListener("submit", function (e) {
const form = e.target;

if (!(form instanceof HTMLFormElement)) return;
if (!form.classList.contains("enter-room-form")) return;

const isPublicEl = form.querySelector("input[name='isPublic']");
const isPublic = isPublicEl ? isPublicEl.value : "public";

if (isPublic === "public") return;

e.preventDefault();

const pwd = prompt("비밀번호를 입력하세요");
if (pwd === null) return; // 취소

const trimmed = pwd.trim();
if (!trimmed) {
alert("비밀번호를 입력해주세요.");
return;
}

let pwdInput = form.querySelector("input[name='roomPwd']");
if (!pwdInput) {
pwdInput = document.createElement("input");
pwdInput.type = "hidden";
pwdInput.name = "roomPwd";
form.appendChild(pwdInput);
}
pwdInput.value = trimmed;

form.submit();
});


function escapeHtml(str) {
return String(str)
Expand Down