티스토리 뷰
Domain
TeamWinning.java
package com.springmvc.domain;
import java.io.Serializable;
public class TeamWinning implements Serializable{
private static final long serialVersionUID = -3281574142158274296L;
private String winningId; //구단성적아이디
private String teamId; //팀아이디
private int matches; //경기수
private double rate; //승룰
private String recent; //최근결과
private String date; //경기날짜
private String result; //경기결과
public TeamWinning() {
super();
// TODO Auto-generated constructor stub
}
public String getRecentMatchesResult() {
return recent;
}
public void setRecentMatchesResult(String recent) {
this.recent=recent;
}
// countRecentWins 메서드를 구현하지 않고, 서비스 레이어에서 처리하는 것이 좋을 것 같습니다.
// 메서드를 호출하는 측에서 필요한 로직을 구현하도록 유도합니다.
public String getWinningId() {
return winningId;
}
public void setWinningId(String winningId) {
this.winningId = winningId;
}
public String getTeamId() {
return teamId;
}
public void setTeamId(String teamId) {
this.teamId = teamId;
}
public int getMatches() {
return matches;
}
public void setMatches(int matches) {
this.matches = matches;
}
public double getRate() {
return rate;
}
public void setRate(double rate) {
this.rate = rate;
}
public String getRecent() {
return recent;
}
public void setRecent(String recent) {
this.recent = recent;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
}
Controller
TeamWinningController.java
package com.springmvc.controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.springmvc.domain.Team;
import com.springmvc.domain.TeamWinning;
import com.springmvc.service.TeamService;
import com.springmvc.service.TeamWinningService;
@Controller
@RequestMapping("team/result")
public class TeamWinningController {
@Autowired
private TeamWinningService teamWinningService;
@GetMapping
public String requestWinningList(Model model) {
List<TeamWinning> list =teamWinningService.readAllWinningList();
model.addAttribute("winningList",list);
return "/Team/winnings";
}
@GetMapping("/all")
public String requestAllWInningList(@RequestParam("id") String winningId, Model model) {
List<TeamWinning> list = teamWinningService.readAllWinningList();
return "/Team/winnings";
}
// @GetMapping("/winning")
// public String requestWinningById(@RequestParam("id") String winningId, Model model) {
// TeamWinning winningById = teamWinningService.readWinningById(winningId);
// model.addAttribute("winning",winningById);
// return"/Team/winning";
// }
@GetMapping("/winning")
public String requestWinningDetails(@RequestParam("id") String teamId, Model model) {
// Get recent matches result, total wins, total losses, and winning rate from service
String recentMatchesResult = teamWinningService.getRecentMatchesResult(teamId);
int totalWins = teamWinningService.totalWins(teamId);
int totalTies = teamWinningService.totalTie(teamId);
int totalLosses = teamWinningService.totalLose(teamId);
double winningRate = teamWinningService.calculateWinningRate(teamId);
int totalGames = teamWinningService.totalGames(teamId);
// Add these attributes to the model
model.addAttribute("recentMatchesResult", recentMatchesResult);
model.addAttribute("totalWins", totalWins);
model.addAttribute("totalTies",totalTies);
model.addAttribute("totalLosses", totalLosses);
model.addAttribute("winningRate", winningRate);
model.addAttribute("totalGames",totalGames);
return "/Team/winning";
}
@GetMapping("/recent")
public String getRecentMatchesResult(@RequestParam("id") String teamId, Model model) {
String recentMatchesResult=teamWinningService.getRecentMatchesResult(teamId);
model.addAttribute("recent",recentMatchesResult);
System.out.println("recent도착");
return "/Team/recent";
}
//create
@GetMapping("/add")
public String requestAddWinningForm(@ModelAttribute("addWinning")TeamWinning teamWinning) {
return "/Team/radd";
}
@PostMapping("/add")
public String submitAddNewWinning(@ModelAttribute("addWinning")TeamWinning teamWinning, HttpServletRequest request){
teamWinningService.setNewWinning(teamWinning);
return "redirect:/team/result";
}
@GetMapping("/update")
public String getUpdateWinningForm(@ModelAttribute("updateWinning") TeamWinning teamWinning, @RequestParam("id")String winningId, Model model) {
TeamWinning winningById = teamWinningService.readWinningById(winningId);
model.addAttribute("winning",winningById);
return "rupdateForm";
}
@PostMapping("/update")
public String submitUpdateWinningForm(@ModelAttribute("updateWinning") TeamWinning teamWinning ) {
teamWinningService.setUpdateWinning(teamWinning);
return "redirect:/winning";
}
@GetMapping(value="/delete")
public String getDeleteForm(Model Model, String winningId) {
teamWinningService.setDeleteWinning(winningId);
return "redirect:/team/result";
}
@GetMapping("/rate")
public String getTeamRate(@RequestParam("id") String teamId, Model model) {
double winningRate = teamWinningService.calculateWinningRate(teamId);
model.addAttribute("winningRate", winningRate);
return "/Team/rate"; // 뷰 페이지의 경로에 맞게 수정
}
}
Repository
TeamWinningRepository.java
package com.springmvc.repository;
import java.util.List;
import com.springmvc.domain.TeamWinning;
public interface TeamWinningRepository {
List<TeamWinning> readAllWinningList();
TeamWinning readWinningById(String teamId);
List<TeamWinning> getRecentMatchesResults(String teamId);
int totalWins(String teamId);
int totalTie(String teamId);
int totalLose(String teamId);
int totalGames(String teamId);
double calculateWinningRate(String teamId);
void setNewWinning(TeamWinning teamWinning);
void setUpdateWinning(TeamWinning teamWinning);
void setDeleteWinning(String winningId);
}
//이 클래스는 주로 데이터베이스에서 조회된 특정 팀의 성적 정보를 담는 데 사용되며,
//객체 간의 데이터 전송이나 저장에 용이합니다.
//JPA(Entity)로 사용되기 위해서 @Entity 어노테이션이 추가되면 특정 데이터베이스 테이블과 매핑할 수 있습니다.
TeamWinningRepositoryImpl.java
package com.springmvc.repository;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.springmvc.domain.TeamWinning;
@Repository
public class TeamWinningRepositoryImpl implements TeamWinningRepository{
private JdbcTemplate template;
@Autowired
public void setJdbcTemplate(DataSource dataSource) {
this.template=new JdbcTemplate(dataSource);
}
@Override
public List<TeamWinning> readAllWinningList() {
String SQL = "SELECT * FROM t_score";
List<TeamWinning> listOfWinnings = template.query(SQL, new TeamWinningRowMapper());
return listOfWinnings;
}
@Override
public TeamWinning readWinningById(String teamId) {
TeamWinning winningInfo = null;
String SQL = "SELECT COUNT(*) FROM t_score WHERE ts_id=?";
int rowCount = template.queryForObject(SQL, Integer.class, teamId);
if(rowCount !=0) {
SQL="SELECT * FROM t_score WHERE ts_id=?";
winningInfo = template.queryForObject(SQL, new Object[] {teamId}, new TeamWinningRowMapper());
}
if(winningInfo == null) {
throw new IllegalArgumentException("일치하는 결과가 없습니다.");
}
return winningInfo;
}
//최근10경기보여주기
@Override
public List<TeamWinning> getRecentMatchesResults(String teamId) {
String SQL = "SELECT * FROM t_score WHERE teamId=? ORDER BY ts_date desc limit 10";
List<TeamWinning> listOfRecent = template.query(SQL, new TeamWinningRowMapper(), teamId);
return listOfRecent;
}
//create
@Override
public void setNewWinning(TeamWinning teamWinning) {
String SQL = "INSERT INTO t_score (ts_id, teamid, ts_matches, ts_result, ts_date)"+"VALUES(?, ?, ?, ?, ?)";
template.update(SQL,teamWinning.getWinningId(),teamWinning.getTeamId(),teamWinning.getMatches(),teamWinning.getResult(),teamWinning.getDate());
}
@Override
public void setUpdateWinning(TeamWinning teamWinning) {
String SQL = "UPDATE t_score SET teamid=?, ts_matches=?, ts_result=?, ts_date=? WHERE ts_id=?";
template.update(SQL,teamWinning.getTeamId(),teamWinning.getMatches(),teamWinning.getResult(),teamWinning.getDate(),teamWinning.getWinningId());
}
@Override
public void setDeleteWinning(String winningId) {
String SQL = "DELETE FROM t_score WHERE ts_id=?";
this.template.update(SQL, winningId);
}
public void setTemplate(JdbcTemplate template) {
this.template = template;
}
@Override
public int totalWins(String teamId) {
String SQL = "SELECT COUNT(*) AS totalWins FROM t_score WHERE teamId=? AND ts_result='Win'";
return template.queryForObject(SQL, Integer.class, teamId);
}
@Override
public int totalTie(String teamId) {
String SQL = "SELECT COUNT(*) AS totalTie FROM t_score WHERE teamId=? AND ts_result='Tie'";
return template.queryForObject(SQL, Integer.class, teamId);
}
@Override
public int totalLose(String teamId) {
String SQL = "SELECT COUNT(*) AS totalLose FROM t_score WHERE teamId=? AND ts_result='Lose'";
return template.queryForObject(SQL, Integer.class, teamId);
}
@Override
public double calculateWinningRate(String teamId) {
String SQL = "SELECT COUNT(*) FROM t_score WHERE teamId=? AND ts_result='Win'";
int totalWins = template.queryForObject(SQL, Integer.class, teamId);
String totalGamesSQL = "SELECT COUNT(*) FROM t_score WHERE teamId=?";
int totalGames = template.queryForObject(totalGamesSQL, Integer.class, teamId);
if(totalGames>0) {
double winningRate = ((double) totalWins / totalGames) * 100;
return Math.round(winningRate * 1000.0) / 1000.0;
}
else {
return 0.0;
}
}
@Override
public int totalGames(String teamId) {
String SQL = "SELECT COUNT(*) FROM t_score WHERE teamId=?";
return template.queryForObject(SQL, Integer.class, teamId);
}
}
TeamWinningRowMapper.java
package com.springmvc.repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import com.springmvc.domain.TeamWinning;
public class TeamWinningRowMapper implements RowMapper<TeamWinning> {
@Override
public TeamWinning mapRow(ResultSet rs, int rowNum) throws SQLException {
TeamWinning teamWinning = new TeamWinning();
teamWinning.setWinningId(rs.getString(1));
teamWinning.setTeamId(rs.getString(2));
teamWinning.setMatches(rs.getInt(3));
teamWinning.setResult(rs.getString(4));
teamWinning.setDate(rs.getString(5));
return teamWinning;
}
}
Service
TeamWinningService.java
package com.springmvc.service;
import java.util.List;
import com.springmvc.domain.TeamWinning;
public interface TeamWinningService {
List<TeamWinning> readAllWinningList();
TeamWinning readWinningById(String winningId);
String getRecentMatchesResult(String teamId);
int totalWins(String teamId);
int totalTie(String teamId);
int totalLose(String teamId);
int totalGames(String teamId);
void setNewWinning(TeamWinning teamWinning);
void setUpdateWinning(TeamWinning teamWinning);
void setDeleteWinning(String winningId);
double calculateWinningRate(String teamId);
}
TeamWinningServiceImpl.java
package com.springmvc.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.springmvc.domain.TeamWinning;
import com.springmvc.repository.TeamWinningRepository;
@Service
public class TeamWinningServiceImpl implements TeamWinningService {
@Autowired
private TeamWinningRepository teamWinningRepository;
@Override
public List<TeamWinning> readAllWinningList() {
return teamWinningRepository.readAllWinningList();
}
@Override
public TeamWinning readWinningById(String teamId) {
TeamWinning teamById = teamWinningRepository.readWinningById(teamId);
return teamById;
}
//최근10경기
@Override
public String getRecentMatchesResult(String teamId) {
List<TeamWinning> recentMatchesResults = teamWinningRepository.getRecentMatchesResults(teamId);
return calculateRecentMatchesResult(recentMatchesResults);
}
private String calculateRecentMatchesResult(List<TeamWinning> recentMatchesResults) {
int recentWins=0;
int recentTies=0;
int recentLosses=0;
for(TeamWinning result : recentMatchesResults) {
if("Win".equals(result.getResult())) {
recentWins++;
}
else if("Lose".equals(result.getResult())) {
recentLosses++;
}
else if("Tie".equals(result.getResult())) {
recentTies++;
}
}
return recentWins + "승" + recentTies + "무" +recentLosses+"패";
}
@Override
public void setNewWinning(TeamWinning teamWinning) {
teamWinningRepository.setNewWinning(teamWinning);
}
@Override
public void setUpdateWinning(TeamWinning teamWinning) {
teamWinningRepository.setUpdateWinning(teamWinning);
}
@Override
public void setDeleteWinning(String winningId) {
teamWinningRepository.setDeleteWinning(winningId);
}
@Override
public int totalWins(String teamId) {
// TODO Auto-generated method stub
return teamWinningRepository.totalWins(teamId);
}
@Override
public int totalTie(String teamId) {
// TODO Auto-generated method stub
return teamWinningRepository.totalTie(teamId);
}
@Override
public int totalLose(String teamId) {
// TODO Auto-generated method stub
return teamWinningRepository.totalLose(teamId);
}
@Override
public double calculateWinningRate(String teamId) {
// TODO Auto-generated method stub
return teamWinningRepository.calculateWinningRate(teamId);
}
@Override
public int totalGames(String teamId) {
// TODO Auto-generated method stub
return teamWinningRepository.totalGames(teamId);
}
}
SQL
-- 경기결과 테이블
drop table t_score;
create table if not exists t_score(
ts_id char(30) NOT NULL primary key,
teamid char(30) NOT NULL, -- 팀아이디
ts_matches int, -- 경기수
ts_result varchar(10), -- 최근경기
ts_date date
)default charset=utf8;
Views / Team
결과 등록
radd.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="<c:url value="/resources/css/bootstrap.min.css"/>"rel="stylesheet" />
<title>결과 등록</title>
</head>
<body>
<nav class="navbar navbar-expand navbar-dark bg-dark">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="./home">Home</a>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="container">
<h1 class="display-3">결과 등록</h1>
</div>
</div>
<div class="container">
<form:form modelAttribute="addWinning" enctype="multipart/form-data" class="form-horizontal">
<fieldset>
<div class="form-group row">
<label class="col-sm-2 control-label">결과ID</label>
<div class="col-sm-3">
<form:input path="winningId" class="form-control" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">구단ID</label>
<div class="col-sm-3">
<form:input path="teamId" class="form-control" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">경기날짜</label>
<div class="col-sm-7">
<form:input path="date" type="date" class="form-control" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">경기수</label>
<div class="col-sm-3">
<form:input path="matches" class="form-control" />
</div>
</div>
<div class="form-group row">
<label class="col-sm-2 control-label">결과</label>
<div class="col-sm-3">
<form:radiobutton path="result" value="Win" class="form-control" />승리
<form:radiobutton path="result" value="Tie" class="form-control" />무승부
<form:radiobutton path="result" value="Lose" class="form-control" />패배
</div>
</div>
<div class="form-group row">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" class="btn btn-primary" value="등록하기" />
<input type="reset" class="btn btn-primary" value="다시쓰기" />
</div>
</div>
</fieldset>
</form:form>
<hr>
<footer>
<p>© Result</p>
</footer>
</div>
</body>
</html>
결과 수정
rupdate.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>수정</title>
</head>
<body>
<h3>결과 수정 페이지</h3>
<form:form modelAttribute="updateWinning" action="./update?id=${winning.teamId}" class="form-horizontal" enctype="multipart/form-data">
<p>승리정보 ID: <form:input path="winningId" value="${winning.winningId}"/></p>
<p>구단 ID : <form:input path="teamId" value="${winning.teamId}"/></p>
<p>날짜 : <form:input path="date" value="${winning.date}"/></p>
<div class="form-group row">
<label class="col-sm-2 control-label">결과</label>
<div class="col-sm-3">
<form:radiobutton path="result" value="Win" class="form-control" />승리
<form:radiobutton path="result" value="Tie" class="form-control" />무승부
<form:radiobutton path="result" value="Lose" class="form-control" />패배
</div>
</div>
<div class="form-group row">
<input type="submit" class="btn btn-primary" value="수정"/>
<a href="<c:url value='/team/result'/>" class="btn btn-primary">취소</a>
</div>
</form:form>
</body>
</html>
경기 결과 목록
winnings.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- form 사용을 위한 선언 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="<c:url value="/resources/css/bootstrap.min.css"/>"rel="stylesheet" />
<script src="${pageContext.request.contextPath }/resources/js/controllers.js"></script>
<!-- 스크립트 사용을 위해 선언 -->
<title>구단 승리 정보</title>
</head>
<body>
<h2>구단 승리 목록</h2>
<c:forEach var="winning" items="${winningList}">
<div>
<p>승리정보 ID: ${winning.winningId}</p>
<p>구단 ID: ${winning.teamId}</p>
<p>최근10경기결과 : ${recent.recent}</p>
<p>날짜 : ${winning.date}</p>
<p><a href="<c:url value="/team/result/winning?id=${winning.teamId}"/>"class="btn btn-secondary" role="button">상세정보 »</a>
<p><a href="<c:url value='/team/result'/>" class="btn btn-secondary" role="button">목록 »</a></p>
<a href='<c:url value="/team/result/update?id=${winning.winningId}"/>' class="btn btn-success">수정»</a>
</div>
<hr>
</c:forEach>
</body>
</html>
경기 결과 상세보기
winning.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!-- form 사용을 위한 선언 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="<c:url value="/resources/css/bootstrap.min.css"/>"rel="stylesheet" />
<script src="${pageContext.request.contextPath }/resources/js/controllers.js"></script>
<!-- 스크립트 사용을 위해 선언 -->
<title>구단 승리 정보</title>
</head>
<body>
<h2>최근 경기 결과</h2>
<h2>경기 횟수</h2>
<p>총 경기 횟수 : ${totalGames}</p>
<p>최근 10경기 승패 결과: ${recentMatchesResult}</p>
<h2>승리 횟수</h2>
<p>총 승리 횟수: ${totalWins}</p>
<h2>무승부 횟수</h2>
<p>총 패배 횟수: ${totalTies}</p>
<h2>패배 횟수</h2>
<p>총 패배 횟수: ${totalLosses}</p>
<h2>승률</h2>
<p>팀의 승률: ${winningRate}%</p>
<p><a href="<c:url value="/Team/result/update?id=${winning.winningId}"/>"class="btn btn-secondary" role="button">수정 »</a>
<p><a href="<c:url value='/team/result'/>" class="btn btn-secondary" role="button">목록 »</a></p>
<p><a href="<c:url value="/Team/result/winning?id=${winning.winningId}"/>"class="btn btn-secondary" role="button">상세정보 »</a>
</body>
</html>
최근 경기 출력
recent.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>최근 10경기 승패 결과</title>
</head>
<body>
<h1>최근 10경기 승패 결과</h1>
<p>팀의 최근 10경기 승패 결과: ${recent}</p>
</body>
</html>
위의 DB를 조회했을때 A125는 11 경기를 했다.
컨트롤러에서 작성한 코드를 보았을 때 date를 desc하여 limit10을 하여 최근 10 경기만 조회하도록 작성했다.
그러므로 아래와 같이 최근 10경기에 대한 승패 결과만 출력되는 것을 볼 수 있다.
team.jsp
a태그를 활용하여 클릭하여 클릭 하면 결과 페이지로 이동하도록 연결 작업해주었다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>팀 정보</h2>
<c:if test="${not empty tb}">
<div class="col-md-4">
<c:choose>
<c:when test="${tb.getTeamImage() == null}">
<img src="<c:url value='/resources/images/${tb.fileName}'/>" style="width: 50%"/>
</c:when>
<c:otherwise>
<img src="<c:url value='/resources/images/${tb.fileName}'/>" style="width: 50%"/>
</c:otherwise>
</c:choose>
</div>
<div>
<p>팀 ID: ${tb.teamId}</p>
<p>팀 이름: ${tb.teamName}</p>
<form:form name="addForm" method="put">
<a href='<c:url value="/team/result/recent?id=${tb.teamId}"/>' class="btn btn-success">최근경기결과»</a>
<a href='<c:url value="/team/result/winning?id=${tb.teamId}"/>' class="btn btn-success">경기결과»</a>
<a href='<c:url value="/team/update?id=${tb.teamId}"/>' class="btn btn-success">수정»</a>
<a href="<c:url value='/team/delete?id=${tb.teamId}'/>" class="btn btn-danger" onclick="return deleteConfirm('${tb.teamId}')">삭제 »</a>
</form:form>
</div>
<hr>
</c:if>
</body>
</html>
'코딩 > spring' 카테고리의 다른 글
queryForObject() 메서드와 query() 메서드 (RowMapper) (0) | 2024.02.20 |
---|---|
[20주 2일차] 프로젝트 - 강의 리뷰 관리 (0) | 2024.02.20 |
[19주 5일차] 프로젝트 - 병원관리(CRUD) (0) | 2024.02.16 |
[19주 3일차] 메서드의 파라미터를 바인딩하기 위한 주요 애노테이션 (0) | 2024.02.14 |
[18주 1일차] 데이터베이스 연동 : 도서 목록 CRUD 처리하기 (1) | 2024.02.05 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday