06 JSP(자바 서버 페이지)
p109 - src/main/java/boot/domain/Users
public class Users {
private Long userIdx;
private String userId;
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Long getUserIdx() {
return userIdx;
}
public void setUserIdx(Long userIdx) {
this.userIdx = userIdx;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
p111 - src/main/java/boot/start/repository/UsersRepository
public class UsersRepository {
private void createUsers() {
Users user1 = new Users();
user1.setUserIdx(1L);
user1.setUserId("user1");
user1.setUserName("John Doe");
Users user2 = new Users();
user2.setUserIdx(2L);
user2.setUserId("user2");
user2.setUserName("Jane Smith");
Users user3 = new Users();
user3.setUserIdx(3L);
user3.setUserId("user3");
user3.setUserName("Alice Johnson");
usersMap.put(user1.getUserIdx(), user1);
usersMap.put(user2.getUserIdx(), user2);
usersMap.put(user3.getUserIdx(), user3);
}
// ConcurrentHashMap을 이용한 데이터 저장소
private final ConcurrentMap<Long, Users> usersMap = new ConcurrentHashMap<>();
private static Long userIndex = 3L;
// 기본 유저 등록
public UsersRepository() {
createUsers();
}
// CREATE: User 객체 저장
public Users save(Users user) {
user.setUserIdx(++userIndex);
usersMap.put(user.getUserIdx(), user);
return user;
}
// READ: user_idx로 검색
public Optional<Users> findByUserIdx(Long user_idx) {
return Optional.ofNullable(usersMap.get(user_idx));
}
// READ: user_id로 검색
public Optional<Users> findByUserId(String user_id) {
return usersMap.values().stream()
.filter(user -> user.getUserId().equals(user_id))
.findAny();
}
// READ: user_name으로 검색
public List<Users> findByUserName(String user_name) {
return usersMap.values().stream()
.filter(user -> user.getUserName().equals(user_name))
.collect(Collectors.toList());
}
// READ: 모든 데이터 찾기
public List<Users> findAll() {
return new ArrayList<>(usersMap.values());
}
// UPDATE: 특정 User 업데이트
public Optional<Users> update(Long user_idx, Users updatedUser) {
if (usersMap.containsKey(user_idx)) {
updatedUser.setUserIdx(user_idx); // 기존 user_idx 유지
usersMap.put(user_idx, updatedUser);
return Optional.of(updatedUser);
}
return Optional.empty();
}
// DELETE: 특정 User 삭제
public boolean delete(Long user_idx) {
return usersMap.remove(user_idx) != null;
}
}
p112,113 - src/test/java/repository/UsersRepositoryTest
class UsersRepositoryTest {
private UsersRepository usersRepository;
@BeforeEach
void setUp() {
usersRepository = new UsersRepository();
}
@AfterEach
void tearDown() {
usersRepository = null;
}
@Test
void save() {
Users newUser = new Users();
newUser.setUserId("newUser");
newUser.setUserName("New User");
Users savedUser = usersRepository.save(newUser);
assertNotNull(savedUser.getUserIdx());
assertEquals("newUser", savedUser.getUserId());
assertEquals("New User", savedUser.getUserName());
}
@Test
void findByUserIdx() {
Optional<Users> user = usersRepository.findByUserIdx(1L);
assertTrue(user.isPresent());
assertEquals(1L, user.get().getUserIdx());
assertEquals("user1", user.get().getUserId());
assertEquals("John Doe", user.get().getUserName());
}
}
p115, p117 - src/test/java/util/ConcurrentTest
public class ConcurrentTest {
// 첫 번째 테스트: ConcurrentHashMap 동작 테스트
@Test
public void testConcurrentHashMap() {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// 데이터를 안전하게 추가
concurrentMap.put("apple", 10);
concurrentMap.put("banana", 20);
// 데이터 읽기 확인
Integer appleCount = concurrentMap.get("apple");
assertEquals(10, appleCount);
assertEquals(20, concurrentMap.get("banana"));
// 동시 접근 중에도 안전한 수정
concurrentMap.compute("apple", (key, value) -> value == null ? 1 : value + 1);
// apple의 값이 11로 변경되어야 함
assertEquals(11, concurrentMap.get("apple"));
}
// 두 번째 테스트: ConcurrentMap 동작 테스트
@Test
public void testConcurrentMap() {
ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
// 값이 없을 때만 추가
map.putIfAbsent("name", "John");
assertEquals("John", map.get("name"));
// 값이 있을 때만 제거
boolean removed = map.remove("name", "John");
assertTrue(removed); // 제거 성공
// 제거 후 값이 null이어야 함
assertNull(map.get("name"));
// 값을 다시 추가
map.put("name", "John");
// 기존 값이 "John"일 때만 "Doe"로 교체
boolean replaced = map.replace("name", "John", "Doe");
assertTrue(replaced); // 교체 성공
// 새로운 값 "Doe" 확인
assertEquals("Doe", map.get("name"));
}
}
p120~124 - src/test/util/OptionalTest
public class OptionalTest {
@Test
public void testEmpty() {
// Optional.empty()는 값이 없는 빈 Optional을 생성
Optional<String> emptyOptional = Optional.empty();
// emptyOptional에는 값이 없으므로 isPresent는 false
assertFalse(emptyOptional.isPresent());
// 값이 없으므로 기본값을 반환하는 orElse 사용
String defaultValue = emptyOptional.orElse("Default");
assertEquals("Default", defaultValue);
}
@Test
public void testOf() {
// Optional.of()는 null이 아닌 값을 감싸는 Optional을 생성
Optional<String> optional = Optional.of("Hello");
// 값이 있으므로 isPresent는 true
assertTrue(optional.isPresent());
// 값이 있으므로 그 값을 반환
String value = optional.get();
assertEquals("Hello", value);
}
@Test
public void testOfThrowsExceptionForNull() {
// Optional.of()는 null을 허용하지 않으므로 NullPointerException이 발생해야 함
assertThrows(NullPointerException.class, () -> {
Optional.of(null);
});
}
@Test
public void testOfNullable() {
// Optional.ofNullable()는 값이 null일 수 있는 상황에서 안전하게 Optional을 생성
Optional<String> optionalWithNull = Optional.ofNullable(null);
// 값이 없으므로 isPresent는 false
assertFalse(optionalWithNull.isPresent());
// 값이 null일 경우 대체값을 반환
String defaultValue = optionalWithNull.orElse("Fallback");
assertEquals("Fallback", defaultValue);
}
@Test
public void testIsPresent() {
Optional<Integer> optional = Optional.of(10);
// 값이 있으므로 isPresent는 true
assertTrue(optional.isPresent());
Optional<Integer> emptyOptional = Optional.empty();
// 값이 없으므로 isPresent는 false
assertFalse(emptyOptional.isPresent());
}
@Test
public void testIfPresent() {
Optional<String> optional = Optional.of("Hello");
// 값이 있을 때만 동작 수행 (여기서는 람다식으로 값을 전달받아 출력)
optional.ifPresent(value -> assertEquals("Hello", value));
// 값이 없는 경우는 아무 동작도 하지 않음
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(value -> fail("This should not be executed"));
}
@Test
public void testOrElse() {
Optional<String> optionalWithValue = Optional.of("Hello");
// 값이 있으므로 그 값을 반환
String result = optionalWithValue.orElse("Default");
assertEquals("Hello", result);
Optional<String> emptyOptional = Optional.empty();
// 값이 없으므로 대체값을 반환
result = emptyOptional.orElse("Default");
assertEquals("Default", result);
}
@Test
public void testOrElseGet() {
Optional<String> optionalWithValue = Optional.of("Hello");
// 값이 있으므로 그 값을 반환
String result = optionalWithValue.orElseGet(() -> "Fallback");
assertEquals("Hello", result);
Optional<String> emptyOptional = Optional.empty();
// 값이 없으므로 Supplier가 제공한 대체값을 반환
result = emptyOptional.orElseGet(() -> "Fallback");
assertEquals("Fallback", result);
}
@Test
public void testOrElseVsOrElseGet() {
Optional<String> emptyOptional = Optional.empty();
// orElse는 항상 대체값을 계산 (심지어 값이 있더라도)
String result = emptyOptional.orElse("Fallback");
assertEquals("Fallback", result);
// orElseGet은 값이 없을 때만 Supplier를 호출
result = emptyOptional.orElseGet(() -> "Generated");
assertEquals("Generated", result);
}
}
p130 - src/test/java/util/SynchronousTest
public class SynchronousTest {
@Test
void synchronousTest() {
System.out.println("동기 작업 시작");
String result = performSynchronousTask();
System.out.println("동기 작업 완료");
// 결과가 예상대로 나왔는지 확인
assertEquals("동기 작업 결과", result);
}
// 동기 작업을 수행하는 메서드
private String performSynchronousTask() {
try {
// 2초간 대기하는 동기 작업 시뮬레이션
Thread.sleep(2000);
System.out.println("작업 중...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "동기 작업 결과";
}
}
p132 - src/test/java/util/AsynchronousTest
public class AsynchronousTest {
@Test
void asynchronousTest() throws ExecutionException, InterruptedException {
System.out.println("비동기 작업 시작");
// 비동기 작업 실행 (논블로킹)
CompletableFuture<String> futureResult = performAsynchronousTask();
System.out.println("다른 작업 수행 중...");
// 비동기 작업이 완료될 때까지 기다리고 결과 확인
String result = futureResult.get(); // `get()`을 사용해 결과를 기다림
System.out.println("비동기 작업 완료");
// 비동기 작업 결과가 예상대로 나왔는지 확인
assertEquals("비동기 작업 결과", result);
}
// 비동기 작업을 수행하는 메서드
private CompletableFuture<String> performAsynchronousTask() {
return CompletableFuture.supplyAsync(() -> {
try {
// 2초간 대기하는 비동기 작업 시뮬레이션
Thread.sleep(2000);
System.out.println("비동기 작업 중...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "비동기 작업 결과";
});
}
}
p134, 138, 139 - src/main/java/boot/start/servlet/UserServlet
@WebServlet(name = "userServlet", urlPatterns = {"/users", "/users/list"})
public class UserServlet extends HttpServlet {
private UsersRepository usersRepository = new UsersRepository();
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getServletPath();
System.out.println("path = " + path);
if ("/users/list".equals(path)) {
handleApiList(req, resp);
} else {
handleUserForm(req, resp);
}
}
private void handleUserForm(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 응답의 Content-Type을 설정
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
// 사용자 등록 폼을 HTML 형식으로 작성
PrintWriter out = resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>User Registration</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Register New User</h1>");
out.println("<form action='/users' method='post'>");
out.println(" <label for='userId'>User ID:</label><br>");
out.println(" <input type='text' id='userId' name='userId'><br><br>");
out.println(" <label for='userName'>User Name:</label><br>");
out.println(" <input type='text' id='userName' name='userName'><br><br>");
out.println(" <input type='submit' value='Register'>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
private void handleApiList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 모든 사용자 목록을 JSON 형식으로 반환
List<Users> usersList = usersRepository.findAll();
String result = objectMapper.writeValueAsString(usersList);
// JSON 형식으로 응답
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println(result);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("UserServlet.doPost");
// 폼 데이터에서 사용자 ID와 이름을 가져옴
String userId = req.getParameter("userId");
String userName = req.getParameter("userName");
// 새로운 사용자 객체를 생성하고 값 설정
Users user = new Users();
user.setUserId(userId);
user.setUserName(userName);
// 사용자 객체를 저장소에 저장
Users savedUser = usersRepository.save(user);
// 응답의 Content-Type을 설정
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
// 저장된 사용자 정보를 포함한 HTML 문서를 생성하고 반환
PrintWriter writer = resp.getWriter();
writer.println("<!DOCTYPE html>");
writer.println("<html>");
writer.println("<head>");
writer.println("<title>User Registered</title>");
writer.println("</head>");
writer.println("<body>");
writer.println("<h1>User Registered Successfully</h1>");
writer.println("<p>User ID: " + savedUser.getUserId() + "</p>");
writer.println("<p>User Name: " + savedUser.getUserName() + "</p>");
writer.println("<a href='/users'>Register another user</a>");
writer.println("</body>");
writer.println("</html>");
}
}
p144
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.2.8'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'education'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api'
implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
implementation 'jakarta.servlet:jakarta.servlet-api'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
p147, 148은 이미지 보면서 설명
p149 - src/main/webapp/jsp/register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>User Registration</title>
</head>
<body>
<h1>Register New User</h1>
<form action="/jsp/registered.jsp" method="post">
<label for="userId">User ID:</label><br>
<input type="text" id="userId" name="userId"><br><br>
<label for="userName">User Name:</label><br>
<input type="text" id="userName" name="userName"><br><br>
<input type="submit" value="Register">
</form>
</body>
</html>
p150 - src/main/webapp/jsp/registered.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="boot.start.repository.UsersRepository" %>
<%@ page import="boot.start.domain.Users" %>
<%@ page import="boot.start.repository.UsersRepositorySingleton" %>
<%
UsersRepository usersRepository = UsersRepositorySingleton.getInstance();
System.out.println("JspClass.jsp_service_method");
String userId = request.getParameter("userId");
String userName = request.getParameter("userName");
Users user = new Users();
user.setUserId(userId);
user.setUserName(userName);
usersRepository.save(user);
%>
<!DOCTYPE html>
<html>
<head>
<title>User Registered</title>
</head>
<body>
<h1>User Registered Successfully</h1>
<p>User ID: <%=user.getUserId()%></p>
<p>User Name: <%=user.getUserName()%></p>
<!-- 리스트 페이지로 이동하는 버튼 -->
<form action="/jsp/list.jsp" method="post">
<input type="submit" value="Go to User List">
</form>
</body>
</html>
p152 - src/main/java/boot/start/repository/UsersRepositorySingleton
public class UsersRepositorySingleton {
// ConcurrentHashMap을 이용한 데이터 저장소
private final ConcurrentMap<Long, Users> usersMap = new ConcurrentHashMap<>();
private static Long userIndex = 3L;
// 싱글톤 인스턴스를 위한 static 변수
private static final UsersRepository instance = new UsersRepository();
// 유일한 인스턴스를 반환하는 메서드
public static UsersRepository getInstance() {
return instance;
}
// private 생성자 - 외부에서 인스턴스 생성 불가
private UsersRepositorySingleton() {
createUsers();
}
private void createUsers() {
Users user1 = new Users();
user1.setUserIdx(1L);
user1.setUserId("user1");
user1.setUserName("John Doe");
Users user2 = new Users();
user2.setUserIdx(2L);
user2.setUserId("user2");
user2.setUserName("Jane Smith");
Users user3 = new Users();
user3.setUserIdx(3L);
user3.setUserId("user3");
user3.setUserName("Alice Johnson");
usersMap.put(user1.getUserIdx(), user1);
usersMap.put(user2.getUserIdx(), user2);
usersMap.put(user3.getUserIdx(), user3);
}
// CREATE: User 객체 저장
public Users save(Users user) {
user.setUserIdx(++userIndex);
usersMap.put(user.getUserIdx(), user);
return user;
}
// READ: user_idx로 검색
public Optional<Users> findByUserIdx(Long user_idx) {
return Optional.ofNullable(usersMap.get(user_idx));
}
// READ: user_id로 검색
public Optional<Users> findByUserId(String user_id) {
return usersMap.values().stream()
.filter(user -> user.getUserId().equals(user_id))
.findAny();
}
// READ: user_name으로 검색
public List<Users> findByUserName(String user_name) {
return usersMap.values().stream()
.filter(user -> user.getUserName().equals(user_name))
.collect(Collectors.toList());
}
// READ: 모든 데이터 찾기
public List<Users> findAll() {
return new ArrayList<>(usersMap.values());
}
// UPDATE: 특정 User 업데이트
public Optional<Users> update(Long user_idx, Users updatedUser) {
if (usersMap.containsKey(user_idx)) {
updatedUser.setUserIdx(user_idx); // 기존 user_idx 유지
usersMap.put(user_idx, updatedUser);
return Optional.of(updatedUser);
}
return Optional.empty();
}
// DELETE: 특정 User 삭제
public boolean delete(Long user_idx) {
return usersMap.remove(user_idx) != null;
}
}
p154 - src/main/webapp/jsp/list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="boot.start.domain.Users" %>
<%@ page import="java.util.List" %>
<%@ page import="boot.start.repository.UsersRepository" %>
<%@ page import="boot.start.repository.UsersRepositorySingleton" %>
<%
UsersRepository usersRepository = UsersRepositorySingleton.getInstance();
// request 객체에서 유저 리스트를 가져오기
List<Users> usersList = usersRepository.findAll();
%>
<!DOCTYPE html>
<html>
<head>
<title>User List</title>
<style>
table {
width: 50%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 10px;
text-align: left;
}
</style>
</head>
<body>
<h1>User List</h1>
<table>
<thead>
<tr>
<th>User Index</th>
<th>User ID</th>
<th>User Name</th>
</tr>
</thead>
<tbody>
<%
if (usersList != null) {
for (Users user : usersList) {
%>
<tr>
<td><%= user.getUserIdx() %></td>
<td><%= user.getUserId() %></td>
<td><%= user.getUserName() %></td>
</tr>
<%
}
} else {
%>
<tr>
<td colspan="3">No users found.</td>
</tr>
<%
}
%>
</tbody>
</table>
</body>
</html>
Last updated